Home > Mobile >  What is the best way to deal with plain text passwords in Go
What is the best way to deal with plain text passwords in Go

Time:09-27

I'm creating a simple program to register my IP to OpenDNS when it changes. I know about the ddclient but I want to write my own just for learning purposes.

To be able to perform any operation on OpenDNS, I have to call the URL specifying my user and pass, so a curl example would be something like: curl -u user:password https://updates.opendns.com/nic/update?hostname=xxxx&myip=123.123.123.123

In Go I created the following function:

func registerNewIpToOpenDns(ip string) (int, error) {

    openDnsURL := "https://updates.opendns.com/nic/update?hostname=xxxx&myip="   ip
    req, err := http.NewRequest("GET", openDnsURL, nil)
    if err != nil {
        return 0, err
    }
    req.SetBasicAuth("USER", "PASS")

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        return 0, err
    }
    defer resp.Body.Close()

    return resp.StatusCode, nil
}

So how should I perform the input of the user/pass to this program? I will let this project 'Public' in Github.

I was thinking in creating a file something like "input" and add it to .gitignore. So if someone else wants to use the program, the person would just need to create it own "input" file and the program would read from it.

What do you think?

CodePudding user response:

Put the configuration data that wouldn't be true for everybody in environment variables.

Use os.Getenv() to retrieve the variables at runtime. Make sure they are set to something valid looking (at least not empty string) as part of your program's configuration.

You can then set the environment variables in a systemd configuration file if you're running this from systemd, or in the .bash_config for a user dedicated to this process, or wherever is the most convenient for where your program is executed.

Or, create a configuration file you can read from your program. I usually use Json encoding for configuration like this, but you could use anything. Reading secrets from configuration files might arguably be somewhat safer than environment variables which can often be introspected by system processes.

When I create a configuration file, I usually model my configuration with a struct,

type Config struct {
   Username string
   Password string
}

Then as part of my program's initialization, I'd do something like

const ConfigFileEnv "ConfigFile" // avoid typing errors 
var config Config
... 
if f, err := os.Open(os.Getenv(ConfigFileEnv); err != nil {
  panic(fmt.Errorf("Couldn't open config file %s: %w",
    os.Getenv(ConfigFileEnv),
    err,
  ))
} else if err := json.NewDecoder(f).Decode(&config); err != nil {
   panic(fmt.Errorf("Couldn't decode json from config file %s: %w", 
      os.Getenv(ConfigFileEnv),
      err
   )
}
// Now config file has been loaded into config
...
req.SetBasicAuth(config.Username, config.Password)

Working minimal example (without your logic): https://github.com/farrellit/stackoverflow/tree/main/69335827

  • Related