1
0
Эх сурвалжийг харах

config: fix replace from env vars for some sub list

ensure to merge configuration from files with configuration from env

Signed-off-by: Nicola Murino <[email protected]>
Nicola Murino 3 жил өмнө
parent
commit
e244ba37b2
4 өөрчлөгдсөн 222 нэмэгдсэн , 55 устгасан
  1. 89 44
      config/config.go
  2. 123 1
      config/config_test.go
  3. 4 4
      go.mod
  4. 6 6
      go.sum

+ 89 - 44
config/config.go

@@ -957,9 +957,7 @@ func getPluginsFromEnv(idx int) {
 }
 
 func getSFTPDBindindFromEnv(idx int) {
-	binding := sftpd.Binding{
-		ApplyProxyConfig: true,
-	}
+	binding := defaultSFTPDBinding
 	if len(globalConf.SFTPD.Bindings) > idx {
 		binding = globalConf.SFTPD.Bindings[idx]
 	}
@@ -995,9 +993,17 @@ func getSFTPDBindindFromEnv(idx int) {
 
 func getFTPDPassiveIPOverridesFromEnv(idx int) []ftpd.PassiveIPOverride {
 	var overrides []ftpd.PassiveIPOverride
+	if len(globalConf.FTPD.Bindings) > idx {
+		overrides = globalConf.FTPD.Bindings[idx].PassiveIPOverrides
+	}
 
 	for subIdx := 0; subIdx < 10; subIdx++ {
 		var override ftpd.PassiveIPOverride
+		var replace bool
+		if len(globalConf.FTPD.Bindings) > idx && len(globalConf.FTPD.Bindings[idx].PassiveIPOverrides) > subIdx {
+			override = globalConf.FTPD.Bindings[idx].PassiveIPOverrides[subIdx]
+			replace = true
+		}
 
 		ip, ok := os.LookupEnv(fmt.Sprintf("SFTPGO_FTPD__BINDINGS__%v__PASSIVE_IP_OVERRIDES__%v__IP", idx, subIdx))
 		if ok {
@@ -1011,7 +1017,11 @@ func getFTPDPassiveIPOverridesFromEnv(idx int) []ftpd.PassiveIPOverride {
 		}
 
 		if len(override.Networks) > 0 {
-			overrides = append(overrides, override)
+			if replace {
+				overrides[subIdx] = override
+			} else {
+				overrides = append(overrides, override)
+			}
 		}
 	}
 
@@ -1019,10 +1029,7 @@ func getFTPDPassiveIPOverridesFromEnv(idx int) []ftpd.PassiveIPOverride {
 }
 
 func getDefaultFTPDBinding(idx int) ftpd.Binding {
-	binding := ftpd.Binding{
-		ApplyProxyConfig: true,
-		MinTLSVersion:    12,
-	}
+	binding := defaultFTPDBinding
 	if len(globalConf.FTPD.Bindings) > idx {
 		binding = globalConf.FTPD.Bindings[idx]
 	}
@@ -1155,9 +1162,7 @@ func getWebDAVDBindingProxyConfigsFromEnv(idx int, binding *webdavd.Binding) boo
 }
 
 func getWebDAVDBindingFromEnv(idx int) {
-	binding := webdavd.Binding{
-		MinTLSVersion: 12,
-	}
+	binding := defaultWebDAVDBinding
 	if len(globalConf.WebDAVD.Bindings) > idx {
 		binding = globalConf.WebDAVD.Bindings[idx]
 	}
@@ -1233,22 +1238,44 @@ func getWebDAVDBindingFromEnv(idx int) {
 
 func getHTTPDSecurityProxyHeadersFromEnv(idx int) []httpd.HTTPSProxyHeader {
 	var httpsProxyHeaders []httpd.HTTPSProxyHeader
+	if len(globalConf.HTTPDConfig.Bindings) > idx {
+		httpsProxyHeaders = globalConf.HTTPDConfig.Bindings[idx].Security.HTTPSProxyHeaders
+	}
 
 	for subIdx := 0; subIdx < 10; subIdx++ {
-		proxyKey, _ := os.LookupEnv(fmt.Sprintf("SFTPGO_HTTPD__BINDINGS__%v__SECURITY__HTTPS_PROXY_HEADERS__%v__KEY", idx, subIdx))
-		proxyVal, _ := os.LookupEnv(fmt.Sprintf("SFTPGO_HTTPD__BINDINGS__%v__SECURITY__HTTPS_PROXY_HEADERS__%v__VALUE", idx, subIdx))
-		if proxyKey != "" && proxyVal != "" {
-			httpsProxyHeaders = append(httpsProxyHeaders, httpd.HTTPSProxyHeader{
-				Key:   proxyKey,
-				Value: proxyVal,
-			})
+		var httpsProxyHeader httpd.HTTPSProxyHeader
+		var replace bool
+		if len(globalConf.HTTPDConfig.Bindings) > idx &&
+			len(globalConf.HTTPDConfig.Bindings[idx].Security.HTTPSProxyHeaders) > subIdx {
+			httpsProxyHeader = httpsProxyHeaders[subIdx]
+			replace = true
+		}
+		proxyKey, ok := os.LookupEnv(fmt.Sprintf("SFTPGO_HTTPD__BINDINGS__%v__SECURITY__HTTPS_PROXY_HEADERS__%v__KEY",
+			idx, subIdx))
+		if ok {
+			httpsProxyHeader.Key = proxyKey
+		}
+		proxyVal, ok := os.LookupEnv(fmt.Sprintf("SFTPGO_HTTPD__BINDINGS__%v__SECURITY__HTTPS_PROXY_HEADERS__%v__VALUE",
+			idx, subIdx))
+		if ok {
+			httpsProxyHeader.Value = proxyVal
+		}
+		if httpsProxyHeader.Key != "" && httpsProxyHeader.Value != "" {
+			if replace {
+				httpsProxyHeaders[subIdx] = httpsProxyHeader
+			} else {
+				httpsProxyHeaders = append(httpsProxyHeaders, httpsProxyHeader)
+			}
 		}
 	}
 	return httpsProxyHeaders
 }
 
 func getHTTPDSecurityConfFromEnv(idx int) (httpd.SecurityConf, bool) { //nolint:gocyclo
-	var result httpd.SecurityConf
+	result := defaultHTTPDBinding.Security
+	if len(globalConf.HTTPDConfig.Bindings) > idx {
+		result = globalConf.HTTPDConfig.Bindings[idx].Security
+	}
 	isSet := false
 
 	enabled, ok := lookupBoolFromEnv(fmt.Sprintf("SFTPGO_HTTPD__BINDINGS__%v__SECURITY__ENABLED", idx))
@@ -1296,6 +1323,7 @@ func getHTTPDSecurityConfFromEnv(idx int) (httpd.SecurityConf, bool) { //nolint:
 	stsSeconds, ok := lookupIntFromEnv(fmt.Sprintf("SFTPGO_HTTPD__BINDINGS__%v__SECURITY__STS_SECONDS", idx))
 	if ok {
 		result.STSSeconds = stsSeconds
+		isSet = true
 	}
 
 	stsIncludeSubDomains, ok := lookupBoolFromEnv(fmt.Sprintf("SFTPGO_HTTPD__BINDINGS__%v__SECURITY__STS_INCLUDE_SUBDOMAINS", idx))
@@ -1344,7 +1372,10 @@ func getHTTPDSecurityConfFromEnv(idx int) (httpd.SecurityConf, bool) { //nolint:
 }
 
 func getHTTPDOIDCFromEnv(idx int) (httpd.OIDC, bool) {
-	var result httpd.OIDC
+	result := defaultHTTPDBinding.OIDC
+	if len(globalConf.HTTPDConfig.Bindings) > idx {
+		result = globalConf.HTTPDConfig.Bindings[idx].OIDC
+	}
 	isSet := false
 
 	clientID, ok := os.LookupEnv(fmt.Sprintf("SFTPGO_HTTPD__BINDINGS__%v__OIDC__CLIENT_ID", idx))
@@ -1398,78 +1429,81 @@ func getHTTPDOIDCFromEnv(idx int) (httpd.OIDC, bool) {
 	return result, isSet
 }
 
-func getHTTPDUIBrandingFromEnv(prefix string) (httpd.UIBranding, bool) {
-	var result httpd.UIBranding
+func getHTTPDUIBrandingFromEnv(prefix string, branding httpd.UIBranding) (httpd.UIBranding, bool) {
 	isSet := false
 
 	name, ok := os.LookupEnv(fmt.Sprintf("%s__NAME", prefix))
 	if ok {
-		result.Name = name
+		branding.Name = name
 		isSet = true
 	}
 
 	shortName, ok := os.LookupEnv(fmt.Sprintf("%s__SHORT_NAME", prefix))
 	if ok {
-		result.ShortName = shortName
+		branding.ShortName = shortName
 		isSet = true
 	}
 
 	faviconPath, ok := os.LookupEnv(fmt.Sprintf("%s__FAVICON_PATH", prefix))
 	if ok {
-		result.FaviconPath = faviconPath
+		branding.FaviconPath = faviconPath
 		isSet = true
 	}
 
 	logoPath, ok := os.LookupEnv(fmt.Sprintf("%s__LOGO_PATH", prefix))
 	if ok {
-		result.LogoPath = logoPath
+		branding.LogoPath = logoPath
 		isSet = true
 	}
 
 	loginImagePath, ok := os.LookupEnv(fmt.Sprintf("%s__LOGIN_IMAGE_PATH", prefix))
 	if ok {
-		result.LoginImagePath = loginImagePath
+		branding.LoginImagePath = loginImagePath
 		isSet = true
 	}
 
 	disclaimerName, ok := os.LookupEnv(fmt.Sprintf("%s__DISCLAIMER_NAME", prefix))
 	if ok {
-		result.DisclaimerName = disclaimerName
+		branding.DisclaimerName = disclaimerName
 		isSet = true
 	}
 
 	disclaimerPath, ok := os.LookupEnv(fmt.Sprintf("%s__DISCLAIMER_PATH", prefix))
 	if ok {
-		result.DisclaimerPath = disclaimerPath
+		branding.DisclaimerPath = disclaimerPath
 		isSet = true
 	}
 
 	defaultCSSPath, ok := os.LookupEnv(fmt.Sprintf("%s__DEFAULT_CSS", prefix))
 	if ok {
-		result.DefaultCSS = defaultCSSPath
+		branding.DefaultCSS = defaultCSSPath
 		isSet = true
 	}
 
 	extraCSS, ok := lookupStringListFromEnv(fmt.Sprintf("%s__EXTRA_CSS", prefix))
 	if ok {
-		result.ExtraCSS = extraCSS
+		branding.ExtraCSS = extraCSS
 		isSet = true
 	}
-
-	return result, isSet
+	return branding, isSet
 }
 
 func getHTTPDBrandingFromEnv(idx int) (httpd.Branding, bool) {
-	var result httpd.Branding
+	result := defaultHTTPDBinding.Branding
+	if len(globalConf.HTTPDConfig.Bindings) > idx {
+		result = globalConf.HTTPDConfig.Bindings[idx].Branding
+	}
 	isSet := false
 
-	webAdmin, ok := getHTTPDUIBrandingFromEnv(fmt.Sprintf("SFTPGO_HTTPD__BINDINGS__%v__BRANDING__WEB_ADMIN", idx))
+	webAdmin, ok := getHTTPDUIBrandingFromEnv(fmt.Sprintf("SFTPGO_HTTPD__BINDINGS__%v__BRANDING__WEB_ADMIN", idx),
+		result.WebAdmin)
 	if ok {
 		result.WebAdmin = webAdmin
 		isSet = true
 	}
 
-	webClient, ok := getHTTPDUIBrandingFromEnv(fmt.Sprintf("SFTPGO_HTTPD__BINDINGS__%v__BRANDING__WEB_CLIENT", idx))
+	webClient, ok := getHTTPDUIBrandingFromEnv(fmt.Sprintf("SFTPGO_HTTPD__BINDINGS__%v__BRANDING__WEB_CLIENT", idx),
+		result.WebClient)
 	if ok {
 		result.WebClient = webClient
 		isSet = true
@@ -1480,9 +1514,18 @@ func getHTTPDBrandingFromEnv(idx int) (httpd.Branding, bool) {
 
 func getHTTPDWebClientIntegrationsFromEnv(idx int) []httpd.WebClientIntegration {
 	var integrations []httpd.WebClientIntegration
+	if len(globalConf.HTTPDConfig.Bindings) > idx {
+		integrations = globalConf.HTTPDConfig.Bindings[idx].WebClientIntegrations
+	}
 
 	for subIdx := 0; subIdx < 10; subIdx++ {
 		var integration httpd.WebClientIntegration
+		var replace bool
+		if len(globalConf.HTTPDConfig.Bindings) > idx &&
+			len(globalConf.HTTPDConfig.Bindings[idx].WebClientIntegrations) > subIdx {
+			integration = integrations[subIdx]
+			replace = true
+		}
 
 		url, ok := os.LookupEnv(fmt.Sprintf("SFTPGO_HTTPD__BINDINGS__%v__WEB_CLIENT_INTEGRATIONS__%v__URL", idx, subIdx))
 		if ok {
@@ -1495,8 +1538,12 @@ func getHTTPDWebClientIntegrationsFromEnv(idx int) []httpd.WebClientIntegration
 			integration.FileExtensions = extensions
 		}
 
-		if url != "" && len(extensions) > 0 {
-			integrations = append(integrations, integration)
+		if integration.URL != "" && len(integration.FileExtensions) > 0 {
+			if replace {
+				integrations[subIdx] = integration
+			} else {
+				integrations = append(integrations, integration)
+			}
 		}
 	}
 
@@ -1504,12 +1551,7 @@ func getHTTPDWebClientIntegrationsFromEnv(idx int) []httpd.WebClientIntegration
 }
 
 func getDefaultHTTPBinding(idx int) httpd.Binding {
-	binding := httpd.Binding{
-		EnableWebAdmin:  true,
-		EnableWebClient: true,
-		RenderOpenAPI:   true,
-		MinTLSVersion:   12,
-	}
+	binding := defaultHTTPDBinding
 	if len(globalConf.HTTPDConfig.Bindings) > idx {
 		binding = globalConf.HTTPDConfig.Bindings[idx]
 	}
@@ -1669,6 +1711,9 @@ func setHTTPDBinding(isSet bool, binding httpd.Binding, idx int) {
 
 func getHTTPClientCertificatesFromEnv(idx int) {
 	tlsCert := httpclient.TLSKeyPair{}
+	if len(globalConf.HTTPConfig.Certificates) > idx {
+		tlsCert = globalConf.HTTPConfig.Certificates[idx]
+	}
 
 	cert, ok := os.LookupEnv(fmt.Sprintf("SFTPGO_HTTP__CERTIFICATES__%v__CERT", idx))
 	if ok {

+ 123 - 1
config/config_test.go

@@ -485,6 +485,126 @@ func TestDisabledMFAConfig(t *testing.T) {
 	assert.NoError(t, err)
 }
 
+func TestFTPDOverridesFromEnv(t *testing.T) {
+	reset()
+
+	os.Setenv("SFTPGO_FTPD__BINDINGS__0__PASSIVE_IP_OVERRIDES__0__IP", "192.168.1.1")
+	os.Setenv("SFTPGO_FTPD__BINDINGS__0__PASSIVE_IP_OVERRIDES__0__NETWORKS", "192.168.1.0/24, 192.168.3.0/25")
+	os.Setenv("SFTPGO_FTPD__BINDINGS__0__PASSIVE_IP_OVERRIDES__1__IP", "192.168.2.1")
+	os.Setenv("SFTPGO_FTPD__BINDINGS__0__PASSIVE_IP_OVERRIDES__1__NETWORKS", "192.168.2.0/24")
+	cleanup := func() {
+		os.Unsetenv("SFTPGO_FTPD__BINDINGS__0__PASSIVE_IP_OVERRIDES__0__IP")
+		os.Unsetenv("SFTPGO_FTPD__BINDINGS__0__PASSIVE_IP_OVERRIDES__0__NETWORKS")
+		os.Unsetenv("SFTPGO_FTPD__BINDINGS__0__PASSIVE_IP_OVERRIDES__1__IP")
+		os.Unsetenv("SFTPGO_FTPD__BINDINGS__0__PASSIVE_IP_OVERRIDES__1__NETWORKS")
+	}
+	t.Cleanup(cleanup)
+
+	configDir := ".."
+	err := config.LoadConfig(configDir, "")
+	assert.NoError(t, err)
+	ftpdConf := config.GetFTPDConfig()
+	require.Len(t, ftpdConf.Bindings, 1)
+	require.Len(t, ftpdConf.Bindings[0].PassiveIPOverrides, 2)
+	require.Equal(t, "192.168.1.1", ftpdConf.Bindings[0].PassiveIPOverrides[0].IP)
+	require.Len(t, ftpdConf.Bindings[0].PassiveIPOverrides[0].Networks, 2)
+	require.Equal(t, "192.168.2.1", ftpdConf.Bindings[0].PassiveIPOverrides[1].IP)
+	require.Len(t, ftpdConf.Bindings[0].PassiveIPOverrides[1].Networks, 1)
+
+	cleanup()
+	cfg := make(map[string]any)
+	cfg["ftpd"] = ftpdConf
+	configAsJSON, err := json.Marshal(cfg)
+	require.NoError(t, err)
+	confName := tempConfigName + ".json"
+	configFilePath := filepath.Join(configDir, confName)
+	err = os.WriteFile(configFilePath, configAsJSON, os.ModePerm)
+	assert.NoError(t, err)
+	os.Setenv("SFTPGO_FTPD__BINDINGS__0__PASSIVE_IP_OVERRIDES__0__IP", "192.168.1.2")
+	os.Setenv("SFTPGO_FTPD__BINDINGS__0__PASSIVE_IP_OVERRIDES__1__NETWORKS", "192.168.2.0/24,192.168.4.0/25")
+	err = config.LoadConfig(configDir, confName)
+	assert.NoError(t, err)
+	ftpdConf = config.GetFTPDConfig()
+	require.Len(t, ftpdConf.Bindings, 1)
+	require.Len(t, ftpdConf.Bindings[0].PassiveIPOverrides, 2)
+	require.Equal(t, "192.168.1.2", ftpdConf.Bindings[0].PassiveIPOverrides[0].IP)
+	require.Len(t, ftpdConf.Bindings[0].PassiveIPOverrides[0].Networks, 2)
+	require.Equal(t, "192.168.2.1", ftpdConf.Bindings[0].PassiveIPOverrides[1].IP)
+	require.Len(t, ftpdConf.Bindings[0].PassiveIPOverrides[1].Networks, 2)
+
+	err = os.Remove(configFilePath)
+	assert.NoError(t, err)
+}
+
+func TestHTTPDSubObjectsFromEnv(t *testing.T) {
+	reset()
+
+	os.Setenv("SFTPGO_HTTPD__BINDINGS__0__SECURITY__HTTPS_PROXY_HEADERS__0__KEY", "X-Forwarded-Proto")
+	os.Setenv("SFTPGO_HTTPD__BINDINGS__0__SECURITY__HTTPS_PROXY_HEADERS__0__VALUE", "https")
+	os.Setenv("SFTPGO_HTTPD__BINDINGS__0__WEB_CLIENT_INTEGRATIONS__0__URL", "http://127.0.0.1/")
+	os.Setenv("SFTPGO_HTTPD__BINDINGS__0__WEB_CLIENT_INTEGRATIONS__0__FILE_EXTENSIONS", ".pdf, .txt")
+	os.Setenv("SFTPGO_HTTPD__BINDINGS__0__OIDC__CLIENT_ID", "client_id")
+	os.Setenv("SFTPGO_HTTPD__BINDINGS__0__OIDC__CLIENT_SECRET", "client_secret")
+	os.Setenv("SFTPGO_HTTPD__BINDINGS__0__OIDC__CONFIG_URL", "config_url")
+	os.Setenv("SFTPGO_HTTPD__BINDINGS__0__OIDC__REDIRECT_BASE_URL", "redirect_base_url")
+	os.Setenv("SFTPGO_HTTPD__BINDINGS__0__OIDC__USERNAME_FIELD", "email")
+	cleanup := func() {
+		os.Unsetenv("SFTPGO_HTTPD__BINDINGS__0__SECURITY__HTTPS_PROXY_HEADERS__0__KEY")
+		os.Unsetenv("SFTPGO_HTTPD__BINDINGS__0__SECURITY__HTTPS_PROXY_HEADERS__0__VALUE")
+		os.Unsetenv("SFTPGO_HTTPD__BINDINGS__0__WEB_CLIENT_INTEGRATIONS__0__URL")
+		os.Unsetenv("SFTPGO_HTTPD__BINDINGS__0__WEB_CLIENT_INTEGRATIONS__0__FILE_EXTENSIONS")
+		os.Unsetenv("SFTPGO_HTTPD__BINDINGS__0__OIDC__CLIENT_ID")
+		os.Unsetenv("SFTPGO_HTTPD__BINDINGS__0__OIDC__CLIENT_SECRET")
+		os.Unsetenv("SFTPGO_HTTPD__BINDINGS__0__OIDC__CONFIG_URL")
+		os.Unsetenv("SFTPGO_HTTPD__BINDINGS__0__OIDC__REDIRECT_BASE_URL")
+		os.Unsetenv("SFTPGO_HTTPD__BINDINGS__0__OIDC__USERNAME_FIELD")
+	}
+	t.Cleanup(cleanup)
+
+	configDir := ".."
+	err := config.LoadConfig(configDir, "")
+	assert.NoError(t, err)
+	httpdConf := config.GetHTTPDConfig()
+	require.Len(t, httpdConf.Bindings, 1)
+	require.Len(t, httpdConf.Bindings[0].Security.HTTPSProxyHeaders, 1)
+	require.Len(t, httpdConf.Bindings[0].WebClientIntegrations, 1)
+	require.Equal(t, "client_id", httpdConf.Bindings[0].OIDC.ClientID)
+	require.Equal(t, "client_secret", httpdConf.Bindings[0].OIDC.ClientSecret)
+	require.Equal(t, "config_url", httpdConf.Bindings[0].OIDC.ConfigURL)
+	require.Equal(t, "redirect_base_url", httpdConf.Bindings[0].OIDC.RedirectBaseURL)
+	require.Equal(t, "email", httpdConf.Bindings[0].OIDC.UsernameField)
+
+	cleanup()
+	cfg := make(map[string]any)
+	cfg["httpd"] = httpdConf
+	configAsJSON, err := json.Marshal(cfg)
+	require.NoError(t, err)
+	confName := tempConfigName + ".json"
+	configFilePath := filepath.Join(configDir, confName)
+	err = os.WriteFile(configFilePath, configAsJSON, os.ModePerm)
+	assert.NoError(t, err)
+
+	os.Setenv("SFTPGO_HTTPD__BINDINGS__0__SECURITY__HTTPS_PROXY_HEADERS__0__VALUE", "http")
+	os.Setenv("SFTPGO_HTTPD__BINDINGS__0__WEB_CLIENT_INTEGRATIONS__0__URL", "http://127.0.1.1/")
+	os.Setenv("SFTPGO_HTTPD__BINDINGS__0__OIDC__CLIENT_SECRET", "new_client_secret")
+	err = config.LoadConfig(configDir, confName)
+	assert.NoError(t, err)
+	httpdConf = config.GetHTTPDConfig()
+	require.Len(t, httpdConf.Bindings, 1)
+	require.Len(t, httpdConf.Bindings[0].Security.HTTPSProxyHeaders, 1)
+	require.Equal(t, "http", httpdConf.Bindings[0].Security.HTTPSProxyHeaders[0].Value)
+	require.Len(t, httpdConf.Bindings[0].WebClientIntegrations, 1)
+	require.Equal(t, "http://127.0.1.1/", httpdConf.Bindings[0].WebClientIntegrations[0].URL)
+	require.Equal(t, "client_id", httpdConf.Bindings[0].OIDC.ClientID)
+	require.Equal(t, "new_client_secret", httpdConf.Bindings[0].OIDC.ClientSecret)
+	require.Equal(t, "config_url", httpdConf.Bindings[0].OIDC.ConfigURL)
+	require.Equal(t, "redirect_base_url", httpdConf.Bindings[0].OIDC.RedirectBaseURL)
+	require.Equal(t, "email", httpdConf.Bindings[0].OIDC.UsernameField)
+
+	err = os.Remove(configFilePath)
+	assert.NoError(t, err)
+}
+
 func TestPluginsFromEnv(t *testing.T) {
 	reset()
 
@@ -545,7 +665,9 @@ func TestPluginsFromEnv(t *testing.T) {
 	require.Equal(t, kms.SecretStatusAWS, pluginConf.KMSOptions.EncryptedStatus)
 	require.Equal(t, 14, pluginConf.AuthOptions.Scope)
 
-	configAsJSON, err := json.Marshal(pluginsConf)
+	cfg := make(map[string]any)
+	cfg["plugins"] = pluginConf
+	configAsJSON, err := json.Marshal(cfg)
 	require.NoError(t, err)
 	confName := tempConfigName + ".json"
 	configFilePath := filepath.Join(configDir, confName)

+ 4 - 4
go.mod

@@ -66,9 +66,9 @@ require (
 	go.uber.org/automaxprocs v1.5.1
 	gocloud.dev v0.25.0
 	golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
-	golang.org/x/net v0.0.0-20220622184535-263ec571b305
+	golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e
 	golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2
-	golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664
+	golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b
 	golang.org/x/time v0.0.0-20220609170525-579cf78fd858
 	google.golang.org/api v0.85.0
 	gopkg.in/natefinch/lumberjack.v2 v2.0.0
@@ -155,7 +155,7 @@ require (
 	golang.org/x/tools v0.1.11 // indirect
 	golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
 	google.golang.org/appengine v1.6.7 // indirect
-	google.golang.org/genproto v0.0.0-20220623142657-077d458a5694 // indirect
+	google.golang.org/genproto v0.0.0-20220627200112-0a929928cb33 // indirect
 	google.golang.org/grpc v1.47.0 // indirect
 	google.golang.org/protobuf v1.28.0 // indirect
 	gopkg.in/ini.v1 v1.66.6 // indirect
@@ -167,5 +167,5 @@ require (
 replace (
 	github.com/jlaffaye/ftp => github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9
 	golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20220624102318-5fdf29404a2d
-	golang.org/x/net => github.com/drakkan/net v0.0.0-20220624102526-8a8f9741f842
+	golang.org/x/net => github.com/drakkan/net v0.0.0-20220628152131-9c7397602ad7
 )

+ 6 - 6
go.sum

@@ -261,8 +261,8 @@ github.com/drakkan/crypto v0.0.0-20220624102318-5fdf29404a2d h1:VLfi41ryCFZIcCC4
 github.com/drakkan/crypto v0.0.0-20220624102318-5fdf29404a2d/go.mod h1:SiM6ypd8Xu1xldObYtbDztuUU7xUzMnUULfphXFZmro=
 github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9 h1:LPH1dEblAOO/LoG7yHPMtBLXhQmjaga91/DDjWk9jWA=
 github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9/go.mod h1:2lmrmq866uF2tnje75wQHzmPXhmSWUt7Gyx2vgK1RCU=
-github.com/drakkan/net v0.0.0-20220624102526-8a8f9741f842 h1:EcMvw4c2tNRpHwQ4811Cz22vN07CE4oz3sKXTLjfWB8=
-github.com/drakkan/net v0.0.0-20220624102526-8a8f9741f842/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+github.com/drakkan/net v0.0.0-20220628152131-9c7397602ad7 h1:/KuSaF3lQkzeeNsXiTPhnI2w4PlH3hbxN6h8tfKAc5E=
+github.com/drakkan/net v0.0.0-20220628152131-9c7397602ad7/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 github.com/eikenb/pipeat v0.0.0-20210730190139-06b3e6902001 h1:/ZshrfQzayqRSBDodmp3rhNCHJCff+utvgBuWRbiqu4=
 github.com/eikenb/pipeat v0.0.0-20210730190139-06b3e6902001/go.mod h1:kltMsfRMTHSFdMbK66XdS8mfMW77+FZA1fGY1xYMF84=
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -966,8 +966,8 @@ golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664 h1:wEZYwx+kK+KlZ0hpvP2Ls1Xr4+RWnlzGFwPP0aiDjIU=
-golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b h1:2n253B2r0pYSmEV+UNCQoPfU/FiaizQEK5Gu4Bq4JE8=
+golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -1214,8 +1214,8 @@ google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP
 google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
 google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
 google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
-google.golang.org/genproto v0.0.0-20220623142657-077d458a5694 h1:itnFmgk4Ls5nT+mYO2ZK6F0DpKsGZLhB5BB9y5ZL2HA=
-google.golang.org/genproto v0.0.0-20220623142657-077d458a5694/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
+google.golang.org/genproto v0.0.0-20220627200112-0a929928cb33 h1:3L4edWcjDHPWGcMl1N0YH1NSoasyvfEcZCe2rUbxHfs=
+google.golang.org/genproto v0.0.0-20220627200112-0a929928cb33/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=