chore: OpenVPN user and password as nullable

- Username and password can be the empty string for custom provider
This commit is contained in:
Quentin McGaw
2022-08-13 16:44:38 +00:00
parent 8e101d49a1
commit 1ab74e6bb3
9 changed files with 50 additions and 46 deletions

View File

@@ -19,13 +19,15 @@ type OpenVPN struct {
// It can only be "2.4" or "2.5".
Version string
// User is the OpenVPN authentication username.
// It cannot be an empty string in the internal state
// if OpenVPN is used.
User string
// It cannot be nil in the internal state if OpenVPN is used.
// It is usually required but in some cases can be the empty string
// to indicate no user+password authentication is needed.
User *string
// Password is the OpenVPN authentication password.
// It cannot be an empty string in the internal state
// if OpenVPN is used.
Password string
// It cannot be nil in the internal state if OpenVPN is used.
// It is usually required but in some cases can be the empty string
// to indicate no user+password authentication is needed.
Password *string
// ConfFile is a custom OpenVPN configuration file path.
// It can be set to the empty string for it to be ignored.
// It cannot be nil in the internal state.
@@ -88,14 +90,14 @@ func (o OpenVPN) validate(vpnProvider string) (err error) {
isCustom := vpnProvider == providers.Custom
if !isCustom && o.User == "" {
if !isCustom && *o.User == "" {
return ErrOpenVPNUserIsEmpty
}
passwordRequired := !isCustom &&
(vpnProvider != providers.Ivpn || !ivpnAccountID.MatchString(o.User))
(vpnProvider != providers.Ivpn || !ivpnAccountID.MatchString(*o.User))
if passwordRequired && o.Password == "" {
if passwordRequired && *o.Password == "" {
return ErrOpenVPNPasswordIsEmpty
}
@@ -204,8 +206,8 @@ func validateOpenVPNClientKey(vpnProvider, clientKey string) (err error) {
func (o *OpenVPN) copy() (copied OpenVPN) {
return OpenVPN{
Version: o.Version,
User: o.User,
Password: o.Password,
User: helpers.CopyStringPtr(o.User),
Password: helpers.CopyStringPtr(o.Password),
ConfFile: helpers.CopyStringPtr(o.ConfFile),
Ciphers: helpers.CopyStringSlice(o.Ciphers),
Auth: helpers.CopyStringPtr(o.Auth),
@@ -225,8 +227,8 @@ func (o *OpenVPN) copy() (copied OpenVPN) {
// unset field of the receiver settings object.
func (o *OpenVPN) mergeWith(other OpenVPN) {
o.Version = helpers.MergeWithString(o.Version, other.Version)
o.User = helpers.MergeWithString(o.User, other.User)
o.Password = helpers.MergeWithString(o.Password, other.Password)
o.User = helpers.MergeWithStringPtr(o.User, other.User)
o.Password = helpers.MergeWithStringPtr(o.Password, other.Password)
o.ConfFile = helpers.MergeWithStringPtr(o.ConfFile, other.ConfFile)
o.Ciphers = helpers.MergeStringSlices(o.Ciphers, other.Ciphers)
o.Auth = helpers.MergeWithStringPtr(o.Auth, other.Auth)
@@ -246,8 +248,8 @@ func (o *OpenVPN) mergeWith(other OpenVPN) {
// settings.
func (o *OpenVPN) overrideWith(other OpenVPN) {
o.Version = helpers.OverrideWithString(o.Version, other.Version)
o.User = helpers.OverrideWithString(o.User, other.User)
o.Password = helpers.OverrideWithString(o.Password, other.Password)
o.User = helpers.OverrideWithStringPtr(o.User, other.User)
o.Password = helpers.OverrideWithStringPtr(o.Password, other.Password)
o.ConfFile = helpers.OverrideWithStringPtr(o.ConfFile, other.ConfFile)
o.Ciphers = helpers.OverrideWithStringSlice(o.Ciphers, other.Ciphers)
o.Auth = helpers.OverrideWithStringPtr(o.Auth, other.Auth)
@@ -264,8 +266,11 @@ func (o *OpenVPN) overrideWith(other OpenVPN) {
func (o *OpenVPN) setDefaults(vpnProvider string) {
o.Version = helpers.DefaultString(o.Version, openvpn.Openvpn25)
o.User = helpers.DefaultStringPtr(o.User, "")
if vpnProvider == providers.Mullvad {
o.Password = "m"
o.Password = helpers.DefaultStringPtr(o.Password, "m")
} else {
o.Password = helpers.DefaultStringPtr(o.Password, "")
}
o.ConfFile = helpers.DefaultStringPtr(o.ConfFile, "")
@@ -293,8 +298,8 @@ func (o OpenVPN) String() string {
func (o OpenVPN) toLinesNode() (node *gotree.Node) {
node = gotree.New("OpenVPN settings:")
node.Appendf("OpenVPN version: %s", o.Version)
node.Appendf("User: %s", helpers.ObfuscatePassword(o.User))
node.Appendf("Password: %s", helpers.ObfuscatePassword(o.Password))
node.Appendf("User: %s", helpers.ObfuscatePassword(*o.User))
node.Appendf("Password: %s", helpers.ObfuscatePassword(*o.Password))
if *o.ConfFile != "" {
node.Appendf("Custom configuration file: %s", *o.ConfFile)

View File

@@ -72,14 +72,25 @@ func (r *Reader) readOpenVPN() (
return openVPN, nil
}
func (r *Reader) readOpenVPNUser() (user string) {
_, user = r.getEnvWithRetro("OPENVPN_USER", "USER")
func (r *Reader) readOpenVPNUser() (user *string) {
user = new(string)
_, *user = r.getEnvWithRetro("OPENVPN_USER", "USER")
if *user == "" {
return nil
}
// Remove spaces in user ID to simplify user's life, thanks @JeordyR
return strings.ReplaceAll(user, " ", "")
*user = strings.ReplaceAll(*user, " ", "")
return user
}
func (r *Reader) readOpenVPNPassword() (password string) {
_, password = r.getEnvWithRetro("OPENVPN_PASSWORD", "PASSWORD")
func (r *Reader) readOpenVPNPassword() (password *string) {
password = new(string)
_, *password = r.getEnvWithRetro("OPENVPN_PASSWORD", "PASSWORD")
if *password == "" {
return nil
}
return password
}

View File

@@ -25,18 +25,3 @@ func readSecretFileAsStringPtr(secretPathEnvKey, defaultSecretPath string) (
}
return files.ReadFromFile(path)
}
func readSecretFileAsString(secretPathEnvKey, defaultSecretPath string) (
s string, err error) {
path := getCleanedEnv(secretPathEnvKey)
if path == "" {
path = defaultSecretPath
}
stringPtr, err := files.ReadFromFile(path)
if err != nil {
return "", err
} else if stringPtr == nil {
return "", nil
}
return *stringPtr, nil
}

View File

@@ -8,7 +8,7 @@ import (
func readOpenVPN() (
settings settings.OpenVPN, err error) {
settings.User, err = readSecretFileAsString(
settings.User, err = readSecretFileAsStringPtr(
"OPENVPN_USER_SECRETFILE",
"/run/secrets/openvpn_user",
)
@@ -16,7 +16,7 @@ func readOpenVPN() (
return settings, fmt.Errorf("cannot read user file: %w", err)
}
settings.Password, err = readSecretFileAsString(
settings.Password, err = readSecretFileAsStringPtr(
"OPENVPN_PASSWORD_SECRETFILE",
"/run/secrets/openvpn_password",
)

View File

@@ -74,7 +74,7 @@ func modifyConfig(lines []string, connection models.Connection,
modified = append(modified, "pull-filter ignore \"auth-token\"") // prevent auth failed loop
modified = append(modified, "auth-retry nointeract")
modified = append(modified, "suppress-timestamps")
if settings.User != "" {
if *settings.User != "" {
modified = append(modified, "auth-user-pass "+openvpn.AuthConf)
}
modified = append(modified, "verb "+strconv.Itoa(*settings.Verbosity))

View File

@@ -36,7 +36,7 @@ func Test_modifyConfig(t *testing.T) {
"auth bla",
},
settings: settings.OpenVPN{
User: "user",
User: stringPtr("user"),
Ciphers: []string{"cipher"},
Auth: stringPtr("auth"),
MSSFix: uint16Ptr(1000),

View File

@@ -0,0 +1,3 @@
package server
func stringPtr(s string) *string { return &s }

View File

@@ -94,8 +94,8 @@ func (h *openvpnHandler) setStatus(w http.ResponseWriter, r *http.Request) {
func (h *openvpnHandler) getSettings(w http.ResponseWriter) {
vpnSettings := h.looper.GetSettings()
settings := vpnSettings.OpenVPN
settings.User = "redacted"
settings.Password = "redacted"
settings.User = stringPtr("redacted")
settings.Password = stringPtr("redacted")
encoder := json.NewEncoder(w)
if err := encoder.Encode(settings); err != nil {
h.warner.Warn(err.Error())

View File

@@ -27,8 +27,8 @@ func setupOpenVPN(ctx context.Context, fw Firewall,
return nil, "", fmt.Errorf("failed writing configuration to file: %w", err)
}
if settings.OpenVPN.User != "" {
err := openvpnConf.WriteAuthFile(settings.OpenVPN.User, settings.OpenVPN.Password)
if *settings.OpenVPN.User != "" {
err := openvpnConf.WriteAuthFile(*settings.OpenVPN.User, *settings.OpenVPN.Password)
if err != nil {
return nil, "", fmt.Errorf("failed writing auth to file: %w", err)
}