瀏覽代碼

add more linters

test cases migration to testify is now complete.
Linters are enabled for test cases too
Nicola Murino 5 年之前
父節點
當前提交
f02e24437a

+ 3 - 3
.github/workflows/quality.yml

@@ -15,14 +15,14 @@ jobs:
     - name: Set up Go 1.14
     - name: Set up Go 1.14
       uses: actions/setup-go@v2
       uses: actions/setup-go@v2
       with:
       with:
-        go-version: '1.14'
+        go-version: 1.14
       id: go
       id: go
 
 
     - name: Check out code into the Go module directory
     - name: Check out code into the Go module directory
       uses: actions/checkout@v2
       uses: actions/checkout@v2
 
 
     - name: Install golangci-lint
     - name: Install golangci-lint
-      run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.25.1
+      run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.26.0
 
 
     - name: Run golangci-lint
     - name: Run golangci-lint
-      run: golangci-lint run --timeout=3m --tests=false --enable=goconst,gofmt,goimports,golint,unconvert,unparam,bodyclose,gocyclo,misspell,maligned,whitespace,dupl,scopelint
+      run: golangci-lint run

+ 42 - 0
.golangci.yml

@@ -0,0 +1,42 @@
+run:
+  timeout: 5m
+  issues-exit-code: 1
+  tests: true
+
+
+linters-settings:
+  dupl:
+    threshold: 150
+  errcheck:
+    check-type-assertions: false
+    check-blank: false
+  goconst:
+    min-len: 3
+    min-occurrences: 3
+  gocyclo:
+    min-complexity: 15
+  gofmt:
+    simplify: true
+  goimports:
+    local-prefixes: github.com/drakkan/sftpgo
+  maligned:
+    suggest-new: true
+
+linters:
+  enable:
+    - goconst
+    - errcheck
+    - gofmt
+    - goimports
+    - golint
+    - unconvert
+    - unparam
+    - bodyclose
+    - gocyclo
+    - misspell
+    - maligned
+    - whitespace
+    - dupl
+    - scopelint
+    - rowserrcheck
+    - dogsled

+ 4 - 3
cmd/initprovider.go

@@ -1,13 +1,14 @@
 package cmd
 package cmd
 
 
 import (
 import (
+	"github.com/rs/zerolog"
+	"github.com/spf13/cobra"
+	"github.com/spf13/viper"
+
 	"github.com/drakkan/sftpgo/config"
 	"github.com/drakkan/sftpgo/config"
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/logger"
 	"github.com/drakkan/sftpgo/logger"
 	"github.com/drakkan/sftpgo/utils"
 	"github.com/drakkan/sftpgo/utils"
-	"github.com/rs/zerolog"
-	"github.com/spf13/cobra"
-	"github.com/spf13/viper"
 )
 )
 
 
 var (
 var (

+ 2 - 1
cmd/install_windows.go

@@ -4,9 +4,10 @@ import (
 	"fmt"
 	"fmt"
 	"strconv"
 	"strconv"
 
 
+	"github.com/spf13/cobra"
+
 	"github.com/drakkan/sftpgo/service"
 	"github.com/drakkan/sftpgo/service"
 	"github.com/drakkan/sftpgo/utils"
 	"github.com/drakkan/sftpgo/utils"
-	"github.com/spf13/cobra"
 )
 )
 
 
 var (
 var (

+ 2 - 1
cmd/portable.go

@@ -9,11 +9,12 @@ import (
 	"path/filepath"
 	"path/filepath"
 	"strings"
 	"strings"
 
 
+	"github.com/spf13/cobra"
+
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/service"
 	"github.com/drakkan/sftpgo/service"
 	"github.com/drakkan/sftpgo/sftpd"
 	"github.com/drakkan/sftpgo/sftpd"
 	"github.com/drakkan/sftpgo/vfs"
 	"github.com/drakkan/sftpgo/vfs"
-	"github.com/spf13/cobra"
 )
 )
 
 
 var (
 var (

+ 2 - 1
cmd/reload_windows.go

@@ -3,8 +3,9 @@ package cmd
 import (
 import (
 	"fmt"
 	"fmt"
 
 
-	"github.com/drakkan/sftpgo/service"
 	"github.com/spf13/cobra"
 	"github.com/spf13/cobra"
+
+	"github.com/drakkan/sftpgo/service"
 )
 )
 
 
 var (
 var (

+ 21 - 20
cmd/root.go

@@ -5,10 +5,11 @@ import (
 	"fmt"
 	"fmt"
 	"os"
 	"os"
 
 
-	"github.com/drakkan/sftpgo/config"
-	"github.com/drakkan/sftpgo/utils"
 	"github.com/spf13/cobra"
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
 	"github.com/spf13/viper"
+
+	"github.com/drakkan/sftpgo/config"
+	"github.com/drakkan/sftpgo/utils"
 )
 )
 
 
 const (
 const (
@@ -77,71 +78,71 @@ func Execute() {
 
 
 func addConfigFlags(cmd *cobra.Command) {
 func addConfigFlags(cmd *cobra.Command) {
 	viper.SetDefault(configDirKey, defaultConfigDir)
 	viper.SetDefault(configDirKey, defaultConfigDir)
-	viper.BindEnv(configDirKey, "SFTPGO_CONFIG_DIR") //nolint: errcheck // err is not nil only if the key to bind is missing
+	viper.BindEnv(configDirKey, "SFTPGO_CONFIG_DIR") //nolint:errcheck // err is not nil only if the key to bind is missing
 	cmd.Flags().StringVarP(&configDir, configDirFlag, "c", viper.GetString(configDirKey),
 	cmd.Flags().StringVarP(&configDir, configDirFlag, "c", viper.GetString(configDirKey),
 		"Location for SFTPGo config dir. This directory should contain the \"sftpgo\" configuration file or the configured "+
 		"Location for SFTPGo config dir. This directory should contain the \"sftpgo\" configuration file or the configured "+
 			"config-file and it is used as the base for files with a relative path (eg. the private keys for the SFTP server, "+
 			"config-file and it is used as the base for files with a relative path (eg. the private keys for the SFTP server, "+
 			"the SQLite database if you use SQLite as data provider). This flag can be set using SFTPGO_CONFIG_DIR env var too.")
 			"the SQLite database if you use SQLite as data provider). This flag can be set using SFTPGO_CONFIG_DIR env var too.")
-	viper.BindPFlag(configDirKey, cmd.Flags().Lookup(configDirFlag)) //nolint: errcheck
+	viper.BindPFlag(configDirKey, cmd.Flags().Lookup(configDirFlag)) //nolint:errcheck
 
 
 	viper.SetDefault(configFileKey, defaultConfigName)
 	viper.SetDefault(configFileKey, defaultConfigName)
-	viper.BindEnv(configFileKey, "SFTPGO_CONFIG_FILE") //nolint: errcheck
+	viper.BindEnv(configFileKey, "SFTPGO_CONFIG_FILE") //nolint:errcheck
 	cmd.Flags().StringVarP(&configFile, configFileFlag, "f", viper.GetString(configFileKey),
 	cmd.Flags().StringVarP(&configFile, configFileFlag, "f", viper.GetString(configFileKey),
 		"Name for SFTPGo configuration file. It must be the name of a file stored in config-dir not the absolute path to the "+
 		"Name for SFTPGo configuration file. It must be the name of a file stored in config-dir not the absolute path to the "+
 			"configuration file. The specified file name must have no extension we automatically load JSON, YAML, TOML, HCL and "+
 			"configuration file. The specified file name must have no extension we automatically load JSON, YAML, TOML, HCL and "+
 			"Java properties. Therefore if you set \"sftpgo\" then \"sftpgo.json\", \"sftpgo.yaml\" and so on are searched. "+
 			"Java properties. Therefore if you set \"sftpgo\" then \"sftpgo.json\", \"sftpgo.yaml\" and so on are searched. "+
 			"This flag can be set using SFTPGO_CONFIG_FILE env var too.")
 			"This flag can be set using SFTPGO_CONFIG_FILE env var too.")
-	viper.BindPFlag(configFileKey, cmd.Flags().Lookup(configFileFlag)) //nolint: errcheck
+	viper.BindPFlag(configFileKey, cmd.Flags().Lookup(configFileFlag)) //nolint:errcheck
 }
 }
 
 
 func addServeFlags(cmd *cobra.Command) {
 func addServeFlags(cmd *cobra.Command) {
 	addConfigFlags(cmd)
 	addConfigFlags(cmd)
 
 
 	viper.SetDefault(logFilePathKey, defaultLogFile)
 	viper.SetDefault(logFilePathKey, defaultLogFile)
-	viper.BindEnv(logFilePathKey, "SFTPGO_LOG_FILE_PATH") //nolint: errcheck
+	viper.BindEnv(logFilePathKey, "SFTPGO_LOG_FILE_PATH") //nolint:errcheck
 	cmd.Flags().StringVarP(&logFilePath, logFilePathFlag, "l", viper.GetString(logFilePathKey),
 	cmd.Flags().StringVarP(&logFilePath, logFilePathFlag, "l", viper.GetString(logFilePathKey),
 		"Location for the log file. Leave empty to write logs to the standard output. This flag can be set using SFTPGO_LOG_FILE_PATH "+
 		"Location for the log file. Leave empty to write logs to the standard output. This flag can be set using SFTPGO_LOG_FILE_PATH "+
 			"env var too.")
 			"env var too.")
-	viper.BindPFlag(logFilePathKey, cmd.Flags().Lookup(logFilePathFlag)) //nolint: errcheck
+	viper.BindPFlag(logFilePathKey, cmd.Flags().Lookup(logFilePathFlag)) //nolint:errcheck
 
 
 	viper.SetDefault(logMaxSizeKey, defaultLogMaxSize)
 	viper.SetDefault(logMaxSizeKey, defaultLogMaxSize)
-	viper.BindEnv(logMaxSizeKey, "SFTPGO_LOG_MAX_SIZE") //nolint: errcheck
+	viper.BindEnv(logMaxSizeKey, "SFTPGO_LOG_MAX_SIZE") //nolint:errcheck
 	cmd.Flags().IntVarP(&logMaxSize, logMaxSizeFlag, "s", viper.GetInt(logMaxSizeKey),
 	cmd.Flags().IntVarP(&logMaxSize, logMaxSizeFlag, "s", viper.GetInt(logMaxSizeKey),
 		"Maximum size in megabytes of the log file before it gets rotated. This flag can be set using SFTPGO_LOG_MAX_SIZE "+
 		"Maximum size in megabytes of the log file before it gets rotated. This flag can be set using SFTPGO_LOG_MAX_SIZE "+
 			"env var too. It is unused if log-file-path is empty.")
 			"env var too. It is unused if log-file-path is empty.")
-	viper.BindPFlag(logMaxSizeKey, cmd.Flags().Lookup(logMaxSizeFlag)) //nolint: errcheck
+	viper.BindPFlag(logMaxSizeKey, cmd.Flags().Lookup(logMaxSizeFlag)) //nolint:errcheck
 
 
 	viper.SetDefault(logMaxBackupKey, defaultLogMaxBackup)
 	viper.SetDefault(logMaxBackupKey, defaultLogMaxBackup)
-	viper.BindEnv(logMaxBackupKey, "SFTPGO_LOG_MAX_BACKUPS") //nolint: errcheck
+	viper.BindEnv(logMaxBackupKey, "SFTPGO_LOG_MAX_BACKUPS") //nolint:errcheck
 	cmd.Flags().IntVarP(&logMaxBackups, "log-max-backups", "b", viper.GetInt(logMaxBackupKey),
 	cmd.Flags().IntVarP(&logMaxBackups, "log-max-backups", "b", viper.GetInt(logMaxBackupKey),
 		"Maximum number of old log files to retain. This flag can be set using SFTPGO_LOG_MAX_BACKUPS env var too. "+
 		"Maximum number of old log files to retain. This flag can be set using SFTPGO_LOG_MAX_BACKUPS env var too. "+
 			"It is unused if log-file-path is empty.")
 			"It is unused if log-file-path is empty.")
-	viper.BindPFlag(logMaxBackupKey, cmd.Flags().Lookup(logMaxBackupFlag)) //nolint: errcheck
+	viper.BindPFlag(logMaxBackupKey, cmd.Flags().Lookup(logMaxBackupFlag)) //nolint:errcheck
 
 
 	viper.SetDefault(logMaxAgeKey, defaultLogMaxAge)
 	viper.SetDefault(logMaxAgeKey, defaultLogMaxAge)
-	viper.BindEnv(logMaxAgeKey, "SFTPGO_LOG_MAX_AGE") //nolint: errcheck
+	viper.BindEnv(logMaxAgeKey, "SFTPGO_LOG_MAX_AGE") //nolint:errcheck
 	cmd.Flags().IntVarP(&logMaxAge, "log-max-age", "a", viper.GetInt(logMaxAgeKey),
 	cmd.Flags().IntVarP(&logMaxAge, "log-max-age", "a", viper.GetInt(logMaxAgeKey),
 		"Maximum number of days to retain old log files. This flag can be set using SFTPGO_LOG_MAX_AGE env var too. "+
 		"Maximum number of days to retain old log files. This flag can be set using SFTPGO_LOG_MAX_AGE env var too. "+
 			"It is unused if log-file-path is empty.")
 			"It is unused if log-file-path is empty.")
-	viper.BindPFlag(logMaxAgeKey, cmd.Flags().Lookup(logMaxAgeFlag)) //nolint: errcheck
+	viper.BindPFlag(logMaxAgeKey, cmd.Flags().Lookup(logMaxAgeFlag)) //nolint:errcheck
 
 
 	viper.SetDefault(logCompressKey, defaultLogCompress)
 	viper.SetDefault(logCompressKey, defaultLogCompress)
-	viper.BindEnv(logCompressKey, "SFTPGO_LOG_COMPRESS") //nolint: errcheck
+	viper.BindEnv(logCompressKey, "SFTPGO_LOG_COMPRESS") //nolint:errcheck
 	cmd.Flags().BoolVarP(&logCompress, logCompressFlag, "z", viper.GetBool(logCompressKey), "Determine if the rotated "+
 	cmd.Flags().BoolVarP(&logCompress, logCompressFlag, "z", viper.GetBool(logCompressKey), "Determine if the rotated "+
 		"log files should be compressed using gzip. This flag can be set using SFTPGO_LOG_COMPRESS env var too. "+
 		"log files should be compressed using gzip. This flag can be set using SFTPGO_LOG_COMPRESS env var too. "+
 		"It is unused if log-file-path is empty.")
 		"It is unused if log-file-path is empty.")
-	viper.BindPFlag(logCompressKey, cmd.Flags().Lookup(logCompressFlag)) //nolint: errcheck
+	viper.BindPFlag(logCompressKey, cmd.Flags().Lookup(logCompressFlag)) //nolint:errcheck
 
 
 	viper.SetDefault(logVerboseKey, defaultLogVerbose)
 	viper.SetDefault(logVerboseKey, defaultLogVerbose)
-	viper.BindEnv(logVerboseKey, "SFTPGO_LOG_VERBOSE") //nolint: errcheck
+	viper.BindEnv(logVerboseKey, "SFTPGO_LOG_VERBOSE") //nolint:errcheck
 	cmd.Flags().BoolVarP(&logVerbose, logVerboseFlag, "v", viper.GetBool(logVerboseKey), "Enable verbose logs. "+
 	cmd.Flags().BoolVarP(&logVerbose, logVerboseFlag, "v", viper.GetBool(logVerboseKey), "Enable verbose logs. "+
 		"This flag can be set using SFTPGO_LOG_VERBOSE env var too.")
 		"This flag can be set using SFTPGO_LOG_VERBOSE env var too.")
-	viper.BindPFlag(logVerboseKey, cmd.Flags().Lookup(logVerboseFlag)) //nolint: errcheck
+	viper.BindPFlag(logVerboseKey, cmd.Flags().Lookup(logVerboseFlag)) //nolint:errcheck
 
 
 	viper.SetDefault(profilerKey, defaultProfiler)
 	viper.SetDefault(profilerKey, defaultProfiler)
-	viper.BindEnv(profilerKey, "SFTPGO_PROFILER") //nolint: errcheck
+	viper.BindEnv(profilerKey, "SFTPGO_PROFILER") //nolint:errcheck
 	cmd.Flags().BoolVarP(&profiler, profilerFlag, "p", viper.GetBool(profilerKey), "Enable the built-in profiler. "+
 	cmd.Flags().BoolVarP(&profiler, profilerFlag, "p", viper.GetBool(profilerKey), "Enable the built-in profiler. "+
 		"The profiler will be accessible via HTTP/HTTPS using the base URL \"/debug/pprof/\". "+
 		"The profiler will be accessible via HTTP/HTTPS using the base URL \"/debug/pprof/\". "+
 		"This flag can be set using SFTPGO_PROFILER env var too.")
 		"This flag can be set using SFTPGO_PROFILER env var too.")
-	viper.BindPFlag(profilerKey, cmd.Flags().Lookup(profilerFlag)) //nolint: errcheck
+	viper.BindPFlag(profilerKey, cmd.Flags().Lookup(profilerFlag)) //nolint:errcheck
 }
 }

+ 2 - 1
cmd/serve.go

@@ -1,9 +1,10 @@
 package cmd
 package cmd
 
 
 import (
 import (
+	"github.com/spf13/cobra"
+
 	"github.com/drakkan/sftpgo/service"
 	"github.com/drakkan/sftpgo/service"
 	"github.com/drakkan/sftpgo/utils"
 	"github.com/drakkan/sftpgo/utils"
-	"github.com/spf13/cobra"
 )
 )
 
 
 var (
 var (

+ 2 - 1
cmd/start_windows.go

@@ -4,9 +4,10 @@ import (
 	"fmt"
 	"fmt"
 	"path/filepath"
 	"path/filepath"
 
 
+	"github.com/spf13/cobra"
+
 	"github.com/drakkan/sftpgo/service"
 	"github.com/drakkan/sftpgo/service"
 	"github.com/drakkan/sftpgo/utils"
 	"github.com/drakkan/sftpgo/utils"
-	"github.com/spf13/cobra"
 )
 )
 
 
 var (
 var (

+ 2 - 1
cmd/status_windows.go

@@ -3,8 +3,9 @@ package cmd
 import (
 import (
 	"fmt"
 	"fmt"
 
 
-	"github.com/drakkan/sftpgo/service"
 	"github.com/spf13/cobra"
 	"github.com/spf13/cobra"
+
+	"github.com/drakkan/sftpgo/service"
 )
 )
 
 
 var (
 var (

+ 2 - 1
cmd/stop_windows.go

@@ -3,8 +3,9 @@ package cmd
 import (
 import (
 	"fmt"
 	"fmt"
 
 
-	"github.com/drakkan/sftpgo/service"
 	"github.com/spf13/cobra"
 	"github.com/spf13/cobra"
+
+	"github.com/drakkan/sftpgo/service"
 )
 )
 
 
 var (
 var (

+ 2 - 1
cmd/uninstall_windows.go

@@ -3,8 +3,9 @@ package cmd
 import (
 import (
 	"fmt"
 	"fmt"
 
 
-	"github.com/drakkan/sftpgo/service"
 	"github.com/spf13/cobra"
 	"github.com/spf13/cobra"
+
+	"github.com/drakkan/sftpgo/service"
 )
 )
 
 
 var (
 var (

+ 8 - 7
config/config.go

@@ -9,13 +9,14 @@ import (
 	"fmt"
 	"fmt"
 	"strings"
 	"strings"
 
 
+	"github.com/spf13/viper"
+
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/httpclient"
 	"github.com/drakkan/sftpgo/httpclient"
 	"github.com/drakkan/sftpgo/httpd"
 	"github.com/drakkan/sftpgo/httpd"
 	"github.com/drakkan/sftpgo/logger"
 	"github.com/drakkan/sftpgo/logger"
 	"github.com/drakkan/sftpgo/sftpd"
 	"github.com/drakkan/sftpgo/sftpd"
 	"github.com/drakkan/sftpgo/utils"
 	"github.com/drakkan/sftpgo/utils"
-	"github.com/spf13/viper"
 )
 )
 
 
 const (
 const (
@@ -222,19 +223,19 @@ func LoadConfig(configDir, configName string) error {
 
 
 func checkHooksCompatibility() {
 func checkHooksCompatibility() {
 	// we copy deprecated fields to new ones to keep backward compatibility so lint is disabled
 	// we copy deprecated fields to new ones to keep backward compatibility so lint is disabled
-	if len(globalConf.ProviderConf.ExternalAuthProgram) > 0 && len(globalConf.ProviderConf.ExternalAuthHook) == 0 { //nolint: staticcheck
+	if len(globalConf.ProviderConf.ExternalAuthProgram) > 0 && len(globalConf.ProviderConf.ExternalAuthHook) == 0 { //nolint:staticcheck
 		logger.Warn(logSender, "", "external_auth_program is deprecated, please use external_auth_hook")
 		logger.Warn(logSender, "", "external_auth_program is deprecated, please use external_auth_hook")
 		logger.WarnToConsole("external_auth_program is deprecated, please use external_auth_hook")
 		logger.WarnToConsole("external_auth_program is deprecated, please use external_auth_hook")
-		globalConf.ProviderConf.ExternalAuthHook = globalConf.ProviderConf.ExternalAuthProgram //nolint: staticcheck
+		globalConf.ProviderConf.ExternalAuthHook = globalConf.ProviderConf.ExternalAuthProgram //nolint:staticcheck
 	}
 	}
-	if len(globalConf.ProviderConf.PreLoginProgram) > 0 && len(globalConf.ProviderConf.PreLoginHook) == 0 { //nolint: staticcheck
+	if len(globalConf.ProviderConf.PreLoginProgram) > 0 && len(globalConf.ProviderConf.PreLoginHook) == 0 { //nolint:staticcheck
 		logger.Warn(logSender, "", "pre_login_program is deprecated, please use pre_login_hook")
 		logger.Warn(logSender, "", "pre_login_program is deprecated, please use pre_login_hook")
 		logger.WarnToConsole("pre_login_program is deprecated, please use pre_login_hook")
 		logger.WarnToConsole("pre_login_program is deprecated, please use pre_login_hook")
-		globalConf.ProviderConf.PreLoginHook = globalConf.ProviderConf.PreLoginProgram //nolint: staticcheck
+		globalConf.ProviderConf.PreLoginHook = globalConf.ProviderConf.PreLoginProgram //nolint:staticcheck
 	}
 	}
-	if len(globalConf.SFTPD.KeyboardInteractiveProgram) > 0 && len(globalConf.SFTPD.KeyboardInteractiveHook) == 0 { //nolint: staticcheck
+	if len(globalConf.SFTPD.KeyboardInteractiveProgram) > 0 && len(globalConf.SFTPD.KeyboardInteractiveHook) == 0 { //nolint:staticcheck
 		logger.Warn(logSender, "", "keyboard_interactive_auth_program is deprecated, please use keyboard_interactive_auth_hook")
 		logger.Warn(logSender, "", "keyboard_interactive_auth_program is deprecated, please use keyboard_interactive_auth_hook")
 		logger.WarnToConsole("keyboard_interactive_auth_program is deprecated, please use keyboard_interactive_auth_hook")
 		logger.WarnToConsole("keyboard_interactive_auth_program is deprecated, please use keyboard_interactive_auth_hook")
-		globalConf.SFTPD.KeyboardInteractiveHook = globalConf.SFTPD.KeyboardInteractiveProgram //nolint: staticcheck
+		globalConf.SFTPD.KeyboardInteractiveHook = globalConf.SFTPD.KeyboardInteractiveProgram //nolint:staticcheck
 	}
 	}
 }
 }

+ 5 - 4
config/config_test.go

@@ -8,12 +8,13 @@ import (
 	"strings"
 	"strings"
 	"testing"
 	"testing"
 
 
+	"github.com/stretchr/testify/assert"
+
 	"github.com/drakkan/sftpgo/config"
 	"github.com/drakkan/sftpgo/config"
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/httpclient"
 	"github.com/drakkan/sftpgo/httpclient"
 	"github.com/drakkan/sftpgo/httpd"
 	"github.com/drakkan/sftpgo/httpd"
 	"github.com/drakkan/sftpgo/sftpd"
 	"github.com/drakkan/sftpgo/sftpd"
-	"github.com/stretchr/testify/assert"
 )
 )
 
 
 const (
 const (
@@ -173,8 +174,8 @@ func TestHookCompatibity(t *testing.T) {
 	err := config.LoadConfig(configDir, configName)
 	err := config.LoadConfig(configDir, configName)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 	providerConf := config.GetProviderConf()
 	providerConf := config.GetProviderConf()
-	providerConf.ExternalAuthProgram = "ext_auth_program"
-	providerConf.PreLoginProgram = "pre_login_program"
+	providerConf.ExternalAuthProgram = "ext_auth_program" //nolint:staticcheck
+	providerConf.PreLoginProgram = "pre_login_program"    //nolint:staticcheck
 	c := make(map[string]dataprovider.Config)
 	c := make(map[string]dataprovider.Config)
 	c["data_provider"] = providerConf
 	c["data_provider"] = providerConf
 	jsonConf, err := json.Marshal(c)
 	jsonConf, err := json.Marshal(c)
@@ -189,7 +190,7 @@ func TestHookCompatibity(t *testing.T) {
 	err = os.Remove(configFilePath)
 	err = os.Remove(configFilePath)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 	sftpdConf := config.GetSFTPDConfig()
 	sftpdConf := config.GetSFTPDConfig()
-	sftpdConf.KeyboardInteractiveProgram = "key_int_program"
+	sftpdConf.KeyboardInteractiveProgram = "key_int_program" //nolint:staticcheck
 	cnf := make(map[string]sftpd.Configuration)
 	cnf := make(map[string]sftpd.Configuration)
 	cnf["sftpd"] = sftpdConf
 	cnf["sftpd"] = sftpdConf
 	jsonConf, err = json.Marshal(cnf)
 	jsonConf, err = json.Marshal(cnf)

+ 2 - 1
dataprovider/bolt.go

@@ -8,9 +8,10 @@ import (
 	"path/filepath"
 	"path/filepath"
 	"time"
 	"time"
 
 
+	bolt "go.etcd.io/bbolt"
+
 	"github.com/drakkan/sftpgo/logger"
 	"github.com/drakkan/sftpgo/logger"
 	"github.com/drakkan/sftpgo/utils"
 	"github.com/drakkan/sftpgo/utils"
-	bolt "go.etcd.io/bbolt"
 )
 )
 
 
 const (
 const (

+ 1 - 1
dataprovider/dataprovider.go

@@ -33,6 +33,7 @@ import (
 
 
 	"github.com/alexedwards/argon2id"
 	"github.com/alexedwards/argon2id"
 	"github.com/go-chi/render"
 	"github.com/go-chi/render"
+	unixcrypt "github.com/nathanaelle/password/v2"
 	"github.com/rs/xid"
 	"github.com/rs/xid"
 	"golang.org/x/crypto/bcrypt"
 	"golang.org/x/crypto/bcrypt"
 	"golang.org/x/crypto/pbkdf2"
 	"golang.org/x/crypto/pbkdf2"
@@ -43,7 +44,6 @@ import (
 	"github.com/drakkan/sftpgo/metrics"
 	"github.com/drakkan/sftpgo/metrics"
 	"github.com/drakkan/sftpgo/utils"
 	"github.com/drakkan/sftpgo/utils"
 	"github.com/drakkan/sftpgo/vfs"
 	"github.com/drakkan/sftpgo/vfs"
-	unixcrypt "github.com/nathanaelle/password/v2"
 )
 )
 
 
 const (
 const (

+ 2 - 2
dataprovider/sqlcommon.go

@@ -271,9 +271,9 @@ func sqlCommonGetUsers(limit int, offset int, order string, username string, dbH
 	defer stmt.Close()
 	defer stmt.Close()
 	var rows *sql.Rows
 	var rows *sql.Rows
 	if len(username) > 0 {
 	if len(username) > 0 {
-		rows, err = stmt.Query(username, limit, offset)
+		rows, err = stmt.Query(username, limit, offset) //nolint:rowserrcheck // err is checked
 	} else {
 	} else {
-		rows, err = stmt.Query(limit, offset)
+		rows, err = stmt.Query(limit, offset) //nolint:rowserrcheck // err is checked
 	}
 	}
 	if err == nil {
 	if err == nil {
 		defer rows.Close()
 		defer rows.Close()

+ 2 - 1
httpd/api_quota.go

@@ -3,10 +3,11 @@ package httpd
 import (
 import (
 	"net/http"
 	"net/http"
 
 
+	"github.com/go-chi/render"
+
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/logger"
 	"github.com/drakkan/sftpgo/logger"
 	"github.com/drakkan/sftpgo/sftpd"
 	"github.com/drakkan/sftpgo/sftpd"
-	"github.com/go-chi/render"
 )
 )
 
 
 func getQuotaScans(w http.ResponseWriter, r *http.Request) {
 func getQuotaScans(w http.ResponseWriter, r *http.Request) {

+ 3 - 2
httpd/api_user.go

@@ -5,10 +5,11 @@ import (
 	"net/http"
 	"net/http"
 	"strconv"
 	"strconv"
 
 
-	"github.com/drakkan/sftpgo/dataprovider"
-	"github.com/drakkan/sftpgo/utils"
 	"github.com/go-chi/chi"
 	"github.com/go-chi/chi"
 	"github.com/go-chi/render"
 	"github.com/go-chi/render"
+
+	"github.com/drakkan/sftpgo/dataprovider"
+	"github.com/drakkan/sftpgo/utils"
 )
 )
 
 
 func getUsers(w http.ResponseWriter, r *http.Request) {
 func getUsers(w http.ResponseWriter, r *http.Request) {

+ 2 - 1
httpd/api_utils.go

@@ -16,11 +16,12 @@ import (
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 
 
+	"github.com/go-chi/render"
+
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/httpclient"
 	"github.com/drakkan/sftpgo/httpclient"
 	"github.com/drakkan/sftpgo/sftpd"
 	"github.com/drakkan/sftpgo/sftpd"
 	"github.com/drakkan/sftpgo/utils"
 	"github.com/drakkan/sftpgo/utils"
-	"github.com/go-chi/render"
 )
 )
 
 
 var (
 var (

+ 3 - 2
httpd/auth.go

@@ -9,10 +9,11 @@ import (
 	"strings"
 	"strings"
 	"sync"
 	"sync"
 
 
-	"github.com/drakkan/sftpgo/logger"
-	"github.com/drakkan/sftpgo/utils"
 	unixcrypt "github.com/nathanaelle/password/v2"
 	unixcrypt "github.com/nathanaelle/password/v2"
 	"golang.org/x/crypto/bcrypt"
 	"golang.org/x/crypto/bcrypt"
+
+	"github.com/drakkan/sftpgo/logger"
+	"github.com/drakkan/sftpgo/utils"
 )
 )
 
 
 const (
 const (

+ 2 - 1
httpd/httpd.go

@@ -13,10 +13,11 @@ import (
 	"path/filepath"
 	"path/filepath"
 	"time"
 	"time"
 
 
+	"github.com/go-chi/chi"
+
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/logger"
 	"github.com/drakkan/sftpgo/logger"
 	"github.com/drakkan/sftpgo/utils"
 	"github.com/drakkan/sftpgo/utils"
-	"github.com/go-chi/chi"
 )
 )
 
 
 const (
 const (

+ 76 - 50
httpd/httpd_test.go

@@ -46,9 +46,6 @@ const (
 	activeConnectionsPath = "/api/v1/connection"
 	activeConnectionsPath = "/api/v1/connection"
 	quotaScanPath         = "/api/v1/quota_scan"
 	quotaScanPath         = "/api/v1/quota_scan"
 	versionPath           = "/api/v1/version"
 	versionPath           = "/api/v1/version"
-	providerStatusPath    = "/api/v1/providerstatus"
-	dumpDataPath          = "/api/v1/dumpdata"
-	loadDataPath          = "/api/v1/loaddata"
 	metricsPath           = "/metrics"
 	metricsPath           = "/metrics"
 	pprofPath             = "/debug/pprof/"
 	pprofPath             = "/debug/pprof/"
 	webBasePath           = "/web"
 	webBasePath           = "/web"
@@ -94,16 +91,20 @@ func TestMain(m *testing.M) {
 	homeBasePath = os.TempDir()
 	homeBasePath = os.TempDir()
 	logfilePath := filepath.Join(configDir, "sftpgo_api_test.log")
 	logfilePath := filepath.Join(configDir, "sftpgo_api_test.log")
 	logger.InitLogger(logfilePath, 5, 1, 28, false, zerolog.DebugLevel)
 	logger.InitLogger(logfilePath, 5, 1, 28, false, zerolog.DebugLevel)
-	config.LoadConfig(configDir, "")
+	err := config.LoadConfig(configDir, "")
+	if err != nil {
+		logger.WarnToConsole("error loading configuration: %v", err)
+		os.Exit(1)
+	}
 	providerConf := config.GetProviderConf()
 	providerConf := config.GetProviderConf()
 	credentialsPath = filepath.Join(os.TempDir(), "test_credentials")
 	credentialsPath = filepath.Join(os.TempDir(), "test_credentials")
 	providerConf.CredentialsPath = credentialsPath
 	providerConf.CredentialsPath = credentialsPath
 	providerDriverName = providerConf.Driver
 	providerDriverName = providerConf.Driver
-	os.RemoveAll(credentialsPath)
+	os.RemoveAll(credentialsPath) //nolint:errcheck
 
 
-	err := dataprovider.Initialize(providerConf, configDir)
+	err = dataprovider.Initialize(providerConf, configDir)
 	if err != nil {
 	if err != nil {
-		logger.Warn(logSender, "", "error initializing data provider: %v", err)
+		logger.WarnToConsole("error initializing data provider: %v", err)
 		os.Exit(1)
 		os.Exit(1)
 	}
 	}
 
 
@@ -117,14 +118,18 @@ func TestMain(m *testing.M) {
 	httpd.SetBaseURLAndCredentials("http://127.0.0.1:8081", "", "")
 	httpd.SetBaseURLAndCredentials("http://127.0.0.1:8081", "", "")
 	backupsPath = filepath.Join(os.TempDir(), "test_backups")
 	backupsPath = filepath.Join(os.TempDir(), "test_backups")
 	httpdConf.BackupsPath = backupsPath
 	httpdConf.BackupsPath = backupsPath
-	os.MkdirAll(backupsPath, 0777)
+	err = os.MkdirAll(backupsPath, 0777)
+	if err != nil {
+		logger.WarnToConsole("error creating backups path: %v", err)
+		os.Exit(1)
+	}
 
 
 	sftpd.SetDataProvider(dataProvider)
 	sftpd.SetDataProvider(dataProvider)
 	httpd.SetDataProvider(dataProvider)
 	httpd.SetDataProvider(dataProvider)
 
 
 	go func() {
 	go func() {
 		if err := httpdConf.Initialize(configDir, true); err != nil {
 		if err := httpdConf.Initialize(configDir, true); err != nil {
-			logger.Error(logSender, "", "could not start HTTP server: %v", err)
+			logger.ErrorToConsole("could not start HTTP server: %v", err)
 		}
 		}
 	}()
 	}()
 
 
@@ -132,8 +137,16 @@ func TestMain(m *testing.M) {
 	// now start an https server
 	// now start an https server
 	certPath := filepath.Join(os.TempDir(), "test.crt")
 	certPath := filepath.Join(os.TempDir(), "test.crt")
 	keyPath := filepath.Join(os.TempDir(), "test.key")
 	keyPath := filepath.Join(os.TempDir(), "test.key")
-	ioutil.WriteFile(certPath, []byte(httpsCert), 0666)
-	ioutil.WriteFile(keyPath, []byte(httpsKey), 0666)
+	err = ioutil.WriteFile(certPath, []byte(httpsCert), 0666)
+	if err != nil {
+		logger.WarnToConsole("error writing HTTPS certificate: %v", err)
+		os.Exit(1)
+	}
+	err = ioutil.WriteFile(keyPath, []byte(httpsKey), 0666)
+	if err != nil {
+		logger.WarnToConsole("error writing HTTPS private key: %v", err)
+		os.Exit(1)
+	}
 	httpdConf.BindPort = 8443
 	httpdConf.BindPort = 8443
 	httpdConf.CertificateFile = certPath
 	httpdConf.CertificateFile = certPath
 	httpdConf.CertificateKeyFile = keyPath
 	httpdConf.CertificateKeyFile = keyPath
@@ -144,18 +157,18 @@ func TestMain(m *testing.M) {
 		}
 		}
 	}()
 	}()
 	waitTCPListening(fmt.Sprintf("%s:%d", httpdConf.BindAddress, httpdConf.BindPort))
 	waitTCPListening(fmt.Sprintf("%s:%d", httpdConf.BindAddress, httpdConf.BindPort))
-	httpd.ReloadTLSCertificate()
+	httpd.ReloadTLSCertificate() //nolint:errcheck
 
 
 	testServer = httptest.NewServer(httpd.GetHTTPRouter())
 	testServer = httptest.NewServer(httpd.GetHTTPRouter())
-	defer testServer.Close()
+	defer testServer.Close() //nolint:errcheck
 
 
 	exitCode := m.Run()
 	exitCode := m.Run()
-	os.Remove(logfilePath)
-	os.RemoveAll(backupsPath)
-	os.RemoveAll(credentialsPath)
-	os.Remove(certPath)
-	os.Remove(keyPath)
-	os.Exit(exitCode)
+	os.Remove(logfilePath)        //nolint:errcheck
+	os.RemoveAll(backupsPath)     //nolint:errcheck
+	os.RemoveAll(credentialsPath) //nolint:errcheck
+	os.Remove(certPath)           //nolint:errcheck
+	os.Remove(keyPath)            //nolint:errcheck
+	os.Exit(exitCode)             //nolint:errcheck
 }
 }
 
 
 func TestInitialization(t *testing.T) {
 func TestInitialization(t *testing.T) {
@@ -163,7 +176,7 @@ func TestInitialization(t *testing.T) {
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 	httpdConf := config.GetHTTPDConfig()
 	httpdConf := config.GetHTTPDConfig()
 	httpdConf.BackupsPath = "test_backups"
 	httpdConf.BackupsPath = "test_backups"
-	httpdConf.AuthUserFile = "invalid file"
+	httpdConf.AuthUserFile = "invalid_file"
 	err = httpdConf.Initialize(configDir, true)
 	err = httpdConf.Initialize(configDir, true)
 	assert.Error(t, err)
 	assert.Error(t, err)
 	httpdConf.BackupsPath = backupsPath
 	httpdConf.BackupsPath = backupsPath
@@ -241,7 +254,7 @@ func TestAddUserNoHomeDir(t *testing.T) {
 
 
 func TestAddUserInvalidHomeDir(t *testing.T) {
 func TestAddUserInvalidHomeDir(t *testing.T) {
 	u := getTestUser()
 	u := getTestUser()
-	u.HomeDir = "relative_path"
+	u.HomeDir = "relative_path" //nolint:goconst
 	_, _, err := httpd.AddUser(u, http.StatusBadRequest)
 	_, _, err := httpd.AddUser(u, http.StatusBadRequest)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 }
 }
@@ -333,13 +346,13 @@ func TestAddUserInvalidFsConfig(t *testing.T) {
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 	err = os.MkdirAll(credentialsPath, 0700)
 	err = os.MkdirAll(credentialsPath, 0700)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
-	u.FsConfig.S3Config.Bucket = "test"
+	u.FsConfig.S3Config.Bucket = "testbucket"
 	u.FsConfig.S3Config.Region = "eu-west-1"
 	u.FsConfig.S3Config.Region = "eu-west-1"
 	u.FsConfig.S3Config.AccessKey = "access-key"
 	u.FsConfig.S3Config.AccessKey = "access-key"
 	u.FsConfig.S3Config.AccessSecret = "access-secret"
 	u.FsConfig.S3Config.AccessSecret = "access-secret"
 	u.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000/path?a=b"
 	u.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000/path?a=b"
-	u.FsConfig.S3Config.StorageClass = "Standard"
-	u.FsConfig.S3Config.KeyPrefix = "/somedir/subdir/"
+	u.FsConfig.S3Config.StorageClass = "Standard" //nolint:goconst
+	u.FsConfig.S3Config.KeyPrefix = "/adir/subdir/"
 	_, _, err = httpd.AddUser(u, http.StatusBadRequest)
 	_, _, err = httpd.AddUser(u, http.StatusBadRequest)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 	u.FsConfig.S3Config.KeyPrefix = ""
 	u.FsConfig.S3Config.KeyPrefix = ""
@@ -355,13 +368,13 @@ func TestAddUserInvalidFsConfig(t *testing.T) {
 	u.FsConfig.GCSConfig.Bucket = ""
 	u.FsConfig.GCSConfig.Bucket = ""
 	_, _, err = httpd.AddUser(u, http.StatusBadRequest)
 	_, _, err = httpd.AddUser(u, http.StatusBadRequest)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
-	u.FsConfig.GCSConfig.Bucket = "test"
+	u.FsConfig.GCSConfig.Bucket = "abucket"
 	u.FsConfig.GCSConfig.StorageClass = "Standard"
 	u.FsConfig.GCSConfig.StorageClass = "Standard"
 	u.FsConfig.GCSConfig.KeyPrefix = "/somedir/subdir/"
 	u.FsConfig.GCSConfig.KeyPrefix = "/somedir/subdir/"
 	u.FsConfig.GCSConfig.Credentials = base64.StdEncoding.EncodeToString([]byte("test"))
 	u.FsConfig.GCSConfig.Credentials = base64.StdEncoding.EncodeToString([]byte("test"))
 	_, _, err = httpd.AddUser(u, http.StatusBadRequest)
 	_, _, err = httpd.AddUser(u, http.StatusBadRequest)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
-	u.FsConfig.GCSConfig.KeyPrefix = "somedir/subdir/"
+	u.FsConfig.GCSConfig.KeyPrefix = "somedir/subdir/" //nolint:goconst
 	u.FsConfig.GCSConfig.Credentials = ""
 	u.FsConfig.GCSConfig.Credentials = ""
 	u.FsConfig.GCSConfig.AutomaticCredentials = 0
 	u.FsConfig.GCSConfig.AutomaticCredentials = 0
 	_, _, err = httpd.AddUser(u, http.StatusBadRequest)
 	_, _, err = httpd.AddUser(u, http.StatusBadRequest)
@@ -542,8 +555,8 @@ func TestUserS3Config(t *testing.T) {
 	user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
 	user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 	user.FsConfig.Provider = 1
 	user.FsConfig.Provider = 1
-	user.FsConfig.S3Config.Bucket = "test"
-	user.FsConfig.S3Config.Region = "us-east-1"
+	user.FsConfig.S3Config.Bucket = "test"      //nolint:goconst
+	user.FsConfig.S3Config.Region = "us-east-1" //nolint:goconst
 	user.FsConfig.S3Config.AccessKey = "Server-Access-Key"
 	user.FsConfig.S3Config.AccessKey = "Server-Access-Key"
 	user.FsConfig.S3Config.AccessSecret = "Server-Access-Secret"
 	user.FsConfig.S3Config.AccessSecret = "Server-Access-Secret"
 	user.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000"
 	user.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000"
@@ -559,11 +572,11 @@ func TestUserS3Config(t *testing.T) {
 	user, _, err = httpd.AddUser(user, http.StatusOK)
 	user, _, err = httpd.AddUser(user, http.StatusOK)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 	user.FsConfig.Provider = 1
 	user.FsConfig.Provider = 1
-	user.FsConfig.S3Config.Bucket = "test1"
-	user.FsConfig.S3Config.Region = "us-east-1"
+	user.FsConfig.S3Config.Bucket = "test-bucket"
+	user.FsConfig.S3Config.Region = "us-east-1" //nolint:goconst
 	user.FsConfig.S3Config.AccessKey = "Server-Access-Key1"
 	user.FsConfig.S3Config.AccessKey = "Server-Access-Key1"
 	user.FsConfig.S3Config.Endpoint = "http://localhost:9000"
 	user.FsConfig.S3Config.Endpoint = "http://localhost:9000"
-	user.FsConfig.S3Config.KeyPrefix = "somedir/subdir"
+	user.FsConfig.S3Config.KeyPrefix = "somedir/subdir" //nolint:goconst
 	user.FsConfig.S3Config.UploadConcurrency = 5
 	user.FsConfig.S3Config.UploadConcurrency = 5
 	user, _, err = httpd.UpdateUser(user, http.StatusOK)
 	user, _, err = httpd.UpdateUser(user, http.StatusOK)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
@@ -580,7 +593,7 @@ func TestUserS3Config(t *testing.T) {
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 	// test user without access key and access secret (shared config state)
 	// test user without access key and access secret (shared config state)
 	user.FsConfig.Provider = 1
 	user.FsConfig.Provider = 1
-	user.FsConfig.S3Config.Bucket = "test1"
+	user.FsConfig.S3Config.Bucket = "testbucket"
 	user.FsConfig.S3Config.Region = "us-east-1"
 	user.FsConfig.S3Config.Region = "us-east-1"
 	user.FsConfig.S3Config.AccessKey = ""
 	user.FsConfig.S3Config.AccessKey = ""
 	user.FsConfig.S3Config.AccessSecret = ""
 	user.FsConfig.S3Config.AccessSecret = ""
@@ -820,7 +833,8 @@ func TestProviderErrors(t *testing.T) {
 	backupData.Users = append(backupData.Users, user)
 	backupData.Users = append(backupData.Users, user)
 	backupContent, _ := json.Marshal(backupData)
 	backupContent, _ := json.Marshal(backupData)
 	backupFilePath := filepath.Join(backupsPath, "backup.json")
 	backupFilePath := filepath.Join(backupsPath, "backup.json")
-	ioutil.WriteFile(backupFilePath, backupContent, 0666)
+	err = ioutil.WriteFile(backupFilePath, backupContent, 0666)
+	assert.NoError(t, err)
 	_, _, err = httpd.Loaddata(backupFilePath, "", "", http.StatusInternalServerError)
 	_, _, err = httpd.Loaddata(backupFilePath, "", "", http.StatusInternalServerError)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 	err = os.Remove(backupFilePath)
 	err = os.Remove(backupFilePath)
@@ -978,11 +992,14 @@ func TestHTTPSConnection(t *testing.T) {
 	client := &http.Client{
 	client := &http.Client{
 		Timeout: 5 * time.Second,
 		Timeout: 5 * time.Second,
 	}
 	}
-	_, err := client.Get("https://localhost:8443" + metricsPath)
-	assert.Error(t, err)
-	if !strings.Contains(err.Error(), "certificate is not valid") &&
-		!strings.Contains(err.Error(), "certificate signed by unknown authority") {
-		assert.Fail(t, err.Error())
+	resp, err := client.Get("https://localhost:8443" + metricsPath)
+	if assert.Error(t, err) {
+		if !strings.Contains(err.Error(), "certificate is not valid") &&
+			!strings.Contains(err.Error(), "certificate signed by unknown authority") {
+			assert.Fail(t, err.Error())
+		}
+	} else {
+		resp.Body.Close()
 	}
 	}
 }
 }
 
 
@@ -1276,7 +1293,8 @@ func TestStartQuotaScanMock(t *testing.T) {
 	req, _ = http.NewRequest(http.MethodPost, quotaScanPath, bytes.NewBuffer(userAsJSON))
 	req, _ = http.NewRequest(http.MethodPost, quotaScanPath, bytes.NewBuffer(userAsJSON))
 	rr = executeRequest(req)
 	rr = executeRequest(req)
 	checkResponseCode(t, http.StatusConflict, rr.Code)
 	checkResponseCode(t, http.StatusConflict, rr.Code)
-	sftpd.RemoveQuotaScan(user.Username)
+	err = sftpd.RemoveQuotaScan(user.Username)
+	assert.NoError(t, err)
 
 
 	userAsJSON = getUserAsJSON(t, user)
 	userAsJSON = getUserAsJSON(t, user)
 	req, _ = http.NewRequest(http.MethodPost, quotaScanPath, bytes.NewBuffer(userAsJSON))
 	req, _ = http.NewRequest(http.MethodPost, quotaScanPath, bytes.NewBuffer(userAsJSON))
@@ -1584,7 +1602,8 @@ func TestWebUserAddMock(t *testing.T) {
 	rr = executeRequest(req)
 	rr = executeRequest(req)
 	checkResponseCode(t, http.StatusOK, rr.Code)
 	checkResponseCode(t, http.StatusOK, rr.Code)
 	var users []dataprovider.User
 	var users []dataprovider.User
-	render.DecodeJSON(rr.Body, &users)
+	err := render.DecodeJSON(rr.Body, &users)
+	assert.NoError(t, err)
 	assert.Equal(t, 1, len(users))
 	assert.Equal(t, 1, len(users))
 	newUser := users[0]
 	newUser := users[0]
 	assert.Equal(t, user.UID, newUser.UID)
 	assert.Equal(t, user.UID, newUser.UID)
@@ -1650,7 +1669,8 @@ func TestWebUserUpdateMock(t *testing.T) {
 	rr = executeRequest(req)
 	rr = executeRequest(req)
 	checkResponseCode(t, http.StatusOK, rr.Code)
 	checkResponseCode(t, http.StatusOK, rr.Code)
 	var users []dataprovider.User
 	var users []dataprovider.User
-	render.DecodeJSON(rr.Body, &users)
+	err = render.DecodeJSON(rr.Body, &users)
+	assert.NoError(t, err)
 	assert.Equal(t, 1, len(users))
 	assert.Equal(t, 1, len(users))
 	updateUser := users[0]
 	updateUser := users[0]
 	assert.Equal(t, user.HomeDir, updateUser.HomeDir)
 	assert.Equal(t, user.HomeDir, updateUser.HomeDir)
@@ -1661,9 +1681,8 @@ func TestWebUserUpdateMock(t *testing.T) {
 	assert.Equal(t, user.GID, updateUser.GID)
 	assert.Equal(t, user.GID, updateUser.GID)
 
 
 	if val, ok := updateUser.Permissions["/otherdir"]; ok {
 	if val, ok := updateUser.Permissions["/otherdir"]; ok {
-		if !utils.IsStringInSlice(dataprovider.PermListItems, val) || !utils.IsStringInSlice(dataprovider.PermUpload, val) {
-			t.Error("permssions for /otherdir does not match")
-		}
+		assert.True(t, utils.IsStringInSlice(dataprovider.PermListItems, val))
+		assert.True(t, utils.IsStringInSlice(dataprovider.PermUpload, val))
 	} else {
 	} else {
 		assert.Fail(t, "user permissions must contains /otherdir", "actual: %v", updateUser.Permissions)
 		assert.Fail(t, "user permissions must contains /otherdir", "actual: %v", updateUser.Permissions)
 	}
 	}
@@ -1672,7 +1691,8 @@ func TestWebUserUpdateMock(t *testing.T) {
 	assert.True(t, utils.IsStringInSlice(dataprovider.SSHLoginMethodKeyboardInteractive, updateUser.Filters.DeniedLoginMethods))
 	assert.True(t, utils.IsStringInSlice(dataprovider.SSHLoginMethodKeyboardInteractive, updateUser.Filters.DeniedLoginMethods))
 	assert.True(t, utils.IsStringInSlice(dataprovider.SSHLoginMethodKeyboardInteractive, updateUser.Filters.DeniedLoginMethods))
 	assert.True(t, utils.IsStringInSlice(dataprovider.SSHLoginMethodKeyboardInteractive, updateUser.Filters.DeniedLoginMethods))
 	assert.True(t, utils.IsStringInSlice(".zip", updateUser.Filters.FileExtensions[0].DeniedExtensions))
 	assert.True(t, utils.IsStringInSlice(".zip", updateUser.Filters.FileExtensions[0].DeniedExtensions))
-	req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
+	req, err = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
+	assert.NoError(t, err)
 	rr = executeRequest(req)
 	rr = executeRequest(req)
 	checkResponseCode(t, http.StatusOK, rr.Code)
 	checkResponseCode(t, http.StatusOK, rr.Code)
 }
 }
@@ -1827,7 +1847,8 @@ func TestWebUserGCSMock(t *testing.T) {
 	rr = executeRequest(req)
 	rr = executeRequest(req)
 	checkResponseCode(t, http.StatusOK, rr.Code)
 	checkResponseCode(t, http.StatusOK, rr.Code)
 	var users []dataprovider.User
 	var users []dataprovider.User
-	render.DecodeJSON(rr.Body, &users)
+	err = render.DecodeJSON(rr.Body, &users)
+	assert.NoError(t, err)
 	assert.Equal(t, 1, len(users))
 	assert.Equal(t, 1, len(users))
 	updateUser := users[0]
 	updateUser := users[0]
 	assert.Equal(t, int64(1577836800000), updateUser.ExpirationDate)
 	assert.Equal(t, int64(1577836800000), updateUser.ExpirationDate)
@@ -1871,11 +1892,13 @@ func TestProviderClosedMock(t *testing.T) {
 	req, _ = http.NewRequest(http.MethodPost, webUserPath+"/0", strings.NewReader(form.Encode()))
 	req, _ = http.NewRequest(http.MethodPost, webUserPath+"/0", strings.NewReader(form.Encode()))
 	rr = executeRequest(req)
 	rr = executeRequest(req)
 	checkResponseCode(t, http.StatusInternalServerError, rr.Code)
 	checkResponseCode(t, http.StatusInternalServerError, rr.Code)
-	config.LoadConfig(configDir, "")
+	err := config.LoadConfig(configDir, "")
+	assert.NoError(t, err)
 	providerConf := config.GetProviderConf()
 	providerConf := config.GetProviderConf()
 	providerConf.CredentialsPath = credentialsPath
 	providerConf.CredentialsPath = credentialsPath
-	os.RemoveAll(credentialsPath)
-	err := dataprovider.Initialize(providerConf, configDir)
+	err = os.RemoveAll(credentialsPath)
+	assert.NoError(t, err)
+	err = dataprovider.Initialize(providerConf, configDir)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 	httpd.SetDataProvider(dataprovider.GetProvider())
 	httpd.SetDataProvider(dataprovider.GetProvider())
 	sftpd.SetDataProvider(dataprovider.GetProvider())
 	sftpd.SetDataProvider(dataprovider.GetProvider())
@@ -1938,7 +1961,10 @@ func checkResponseCode(t *testing.T, expected, actual int) {
 func createTestFile(path string, size int64) error {
 func createTestFile(path string, size int64) error {
 	baseDir := filepath.Dir(path)
 	baseDir := filepath.Dir(path)
 	if _, err := os.Stat(baseDir); os.IsNotExist(err) {
 	if _, err := os.Stat(baseDir); os.IsNotExist(err) {
-		os.MkdirAll(baseDir, 0777)
+		err = os.MkdirAll(baseDir, 0777)
+		if err != nil {
+			return err
+		}
 	}
 	}
 	content := make([]byte, size)
 	content := make([]byte, size)
 	if size > 0 {
 	if size > 0 {

+ 13 - 8
httpd/internal_test.go

@@ -14,12 +14,13 @@ import (
 	"strings"
 	"strings"
 	"testing"
 	"testing"
 
 
+	"github.com/go-chi/chi"
+	"github.com/stretchr/testify/assert"
+
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/sftpd"
 	"github.com/drakkan/sftpgo/sftpd"
 	"github.com/drakkan/sftpgo/utils"
 	"github.com/drakkan/sftpgo/utils"
 	"github.com/drakkan/sftpgo/vfs"
 	"github.com/drakkan/sftpgo/vfs"
-	"github.com/go-chi/chi"
-	"github.com/stretchr/testify/assert"
 )
 )
 
 
 const (
 const (
@@ -304,8 +305,9 @@ func TestGCSWebInvalidFormFile(t *testing.T) {
 	form.Set("fs_provider", "2")
 	form.Set("fs_provider", "2")
 	req, _ := http.NewRequest(http.MethodPost, webUserPath, strings.NewReader(form.Encode()))
 	req, _ := http.NewRequest(http.MethodPost, webUserPath, strings.NewReader(form.Encode()))
 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
-	req.ParseForm()
-	_, err := getFsConfigFromUserPostFields(req)
+	err := req.ParseForm()
+	assert.NoError(t, err)
+	_, err = getFsConfigFromUserPostFields(req)
 	assert.EqualError(t, err, http.ErrNotMultipart.Error())
 	assert.EqualError(t, err, http.ErrNotMultipart.Error())
 }
 }
 
 
@@ -370,9 +372,10 @@ func TestBasicAuth(t *testing.T) {
 	oldAuthPassword := authPassword
 	oldAuthPassword := authPassword
 	authUserFile := filepath.Join(os.TempDir(), "http_users.txt")
 	authUserFile := filepath.Join(os.TempDir(), "http_users.txt")
 	authUserData := []byte("test1:$2y$05$bcHSED7aO1cfLto6ZdDBOOKzlwftslVhtpIkRhAtSa4GuLmk5mola\n")
 	authUserData := []byte("test1:$2y$05$bcHSED7aO1cfLto6ZdDBOOKzlwftslVhtpIkRhAtSa4GuLmk5mola\n")
-	ioutil.WriteFile(authUserFile, authUserData, 0666)
+	err := ioutil.WriteFile(authUserFile, authUserData, 0666)
+	assert.NoError(t, err)
 	httpAuth, _ = newBasicAuthProvider(authUserFile)
 	httpAuth, _ = newBasicAuthProvider(authUserFile)
-	_, _, err := GetVersion(http.StatusUnauthorized)
+	_, _, err = GetVersion(http.StatusUnauthorized)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 	SetBaseURLAndCredentials(httpBaseURL, "test1", "password1")
 	SetBaseURLAndCredentials(httpBaseURL, "test1", "password1")
 	_, _, err = GetVersion(http.StatusOK)
 	_, _, err = GetVersion(http.StatusOK)
@@ -391,12 +394,14 @@ func TestBasicAuth(t *testing.T) {
 	_, _, err = GetVersion(http.StatusOK)
 	_, _, err = GetVersion(http.StatusOK)
 	assert.Error(t, err)
 	assert.Error(t, err)
 	authUserData = append(authUserData, []byte("test3:$apr1$gLnIkRIf$Xr/6$aJfmIr$ihP4b2N2tcs/\n")...)
 	authUserData = append(authUserData, []byte("test3:$apr1$gLnIkRIf$Xr/6$aJfmIr$ihP4b2N2tcs/\n")...)
-	ioutil.WriteFile(authUserFile, authUserData, 0666)
+	err = ioutil.WriteFile(authUserFile, authUserData, 0666)
+	assert.NoError(t, err)
 	SetBaseURLAndCredentials(httpBaseURL, "test3", "wrong_password")
 	SetBaseURLAndCredentials(httpBaseURL, "test3", "wrong_password")
 	_, _, err = GetVersion(http.StatusUnauthorized)
 	_, _, err = GetVersion(http.StatusUnauthorized)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 	authUserData = append(authUserData, []byte("test4:$invalid$gLnIkRIf$Xr/6$aJfmIr$ihP4b2N2tcs/\n")...)
 	authUserData = append(authUserData, []byte("test4:$invalid$gLnIkRIf$Xr/6$aJfmIr$ihP4b2N2tcs/\n")...)
-	ioutil.WriteFile(authUserFile, authUserData, 0666)
+	err = ioutil.WriteFile(authUserFile, authUserData, 0666)
+	assert.NoError(t, err)
 	SetBaseURLAndCredentials(httpBaseURL, "test3", "password2")
 	SetBaseURLAndCredentials(httpBaseURL, "test3", "password2")
 	_, _, err = GetVersion(http.StatusUnauthorized)
 	_, _, err = GetVersion(http.StatusUnauthorized)
 	assert.NoError(t, err)
 	assert.NoError(t, err)

+ 5 - 4
httpd/router.go

@@ -4,14 +4,15 @@ import (
 	"net/http"
 	"net/http"
 	"strings"
 	"strings"
 
 
-	"github.com/drakkan/sftpgo/dataprovider"
-	"github.com/drakkan/sftpgo/logger"
-	"github.com/drakkan/sftpgo/sftpd"
-	"github.com/drakkan/sftpgo/utils"
 	"github.com/go-chi/chi"
 	"github.com/go-chi/chi"
 	"github.com/go-chi/chi/middleware"
 	"github.com/go-chi/chi/middleware"
 	"github.com/go-chi/render"
 	"github.com/go-chi/render"
 	"github.com/prometheus/client_golang/prometheus/promhttp"
 	"github.com/prometheus/client_golang/prometheus/promhttp"
+
+	"github.com/drakkan/sftpgo/dataprovider"
+	"github.com/drakkan/sftpgo/logger"
+	"github.com/drakkan/sftpgo/sftpd"
+	"github.com/drakkan/sftpgo/utils"
 )
 )
 
 
 // GetHTTPRouter returns the configured HTTP handler
 // GetHTTPRouter returns the configured HTTP handler

+ 2 - 1
httpd/web.go

@@ -13,11 +13,12 @@ import (
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
+	"github.com/go-chi/chi"
+
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/sftpd"
 	"github.com/drakkan/sftpgo/sftpd"
 	"github.com/drakkan/sftpgo/utils"
 	"github.com/drakkan/sftpgo/utils"
 	"github.com/drakkan/sftpgo/vfs"
 	"github.com/drakkan/sftpgo/vfs"
-	"github.com/go-chi/chi"
 )
 )
 
 
 const (
 const (

+ 2 - 1
logger/request_logger.go

@@ -5,9 +5,10 @@ import (
 	"net/http"
 	"net/http"
 	"time"
 	"time"
 
 
-	"github.com/drakkan/sftpgo/metrics"
 	"github.com/go-chi/chi/middleware"
 	"github.com/go-chi/chi/middleware"
 	"github.com/rs/zerolog"
 	"github.com/rs/zerolog"
+
+	"github.com/drakkan/sftpgo/metrics"
 )
 )
 
 
 // StructuredLogger defines a simple wrapper around zerolog logger.
 // StructuredLogger defines a simple wrapper around zerolog logger.

+ 2 - 1
main.go

@@ -4,10 +4,11 @@
 package main // import "github.com/drakkan/sftpgo"
 package main // import "github.com/drakkan/sftpgo"
 
 
 import (
 import (
-	"github.com/drakkan/sftpgo/cmd"
 	_ "github.com/go-sql-driver/mysql"
 	_ "github.com/go-sql-driver/mysql"
 	_ "github.com/lib/pq"
 	_ "github.com/lib/pq"
 	_ "github.com/mattn/go-sqlite3"
 	_ "github.com/mattn/go-sqlite3"
+
+	"github.com/drakkan/sftpgo/cmd"
 )
 )
 
 
 func main() {
 func main() {

+ 3 - 2
service/service.go

@@ -11,14 +11,15 @@ import (
 	"syscall"
 	"syscall"
 	"time"
 	"time"
 
 
+	"github.com/grandcat/zeroconf"
+	"github.com/rs/zerolog"
+
 	"github.com/drakkan/sftpgo/config"
 	"github.com/drakkan/sftpgo/config"
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/httpd"
 	"github.com/drakkan/sftpgo/httpd"
 	"github.com/drakkan/sftpgo/logger"
 	"github.com/drakkan/sftpgo/logger"
 	"github.com/drakkan/sftpgo/sftpd"
 	"github.com/drakkan/sftpgo/sftpd"
 	"github.com/drakkan/sftpgo/utils"
 	"github.com/drakkan/sftpgo/utils"
-	"github.com/grandcat/zeroconf"
-	"github.com/rs/zerolog"
 )
 )
 
 
 const (
 const (

+ 4 - 4
service/service_windows.go

@@ -7,13 +7,13 @@ import (
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
-	"github.com/drakkan/sftpgo/dataprovider"
-	"github.com/drakkan/sftpgo/httpd"
-	"github.com/drakkan/sftpgo/logger"
-
 	"golang.org/x/sys/windows/svc"
 	"golang.org/x/sys/windows/svc"
 	"golang.org/x/sys/windows/svc/eventlog"
 	"golang.org/x/sys/windows/svc/eventlog"
 	"golang.org/x/sys/windows/svc/mgr"
 	"golang.org/x/sys/windows/svc/mgr"
+
+	"github.com/drakkan/sftpgo/dataprovider"
+	"github.com/drakkan/sftpgo/httpd"
+	"github.com/drakkan/sftpgo/logger"
 )
 )
 
 
 const (
 const (

+ 2 - 3
sftpd/handler.go

@@ -8,13 +8,12 @@ import (
 	"sync"
 	"sync"
 	"time"
 	"time"
 
 
-	"github.com/drakkan/sftpgo/vfs"
+	"github.com/pkg/sftp"
 	"golang.org/x/crypto/ssh"
 	"golang.org/x/crypto/ssh"
 
 
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/logger"
 	"github.com/drakkan/sftpgo/logger"
-
-	"github.com/pkg/sftp"
+	"github.com/drakkan/sftpgo/vfs"
 )
 )
 
 
 // Connection details for an authenticated user
 // Connection details for an authenticated user

File diff suppressed because it is too large
+ 264 - 334
sftpd/internal_test.go


+ 4 - 6
sftpd/internal_unix_test.go

@@ -5,15 +5,13 @@ package sftpd
 import (
 import (
 	"os/exec"
 	"os/exec"
 	"testing"
 	"testing"
+
+	"github.com/stretchr/testify/assert"
 )
 )
 
 
 func TestWrapCmd(t *testing.T) {
 func TestWrapCmd(t *testing.T) {
 	cmd := exec.Command("ls")
 	cmd := exec.Command("ls")
 	cmd = wrapCmd(cmd, 1000, 1001)
 	cmd = wrapCmd(cmd, 1000, 1001)
-	if cmd.SysProcAttr.Credential.Uid != 1000 {
-		t.Errorf("unexpected uid")
-	}
-	if cmd.SysProcAttr.Credential.Gid != 1001 {
-		t.Errorf("unexpected gid")
-	}
+	assert.Equal(t, uint32(1000), cmd.SysProcAttr.Credential.Uid)
+	assert.Equal(t, uint32(1001), cmd.SysProcAttr.Credential.Gid)
 }
 }

+ 4 - 3
sftpd/server.go

@@ -13,13 +13,14 @@ import (
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
+	"github.com/pires/go-proxyproto"
+	"github.com/pkg/sftp"
+	"golang.org/x/crypto/ssh"
+
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/logger"
 	"github.com/drakkan/sftpgo/logger"
 	"github.com/drakkan/sftpgo/metrics"
 	"github.com/drakkan/sftpgo/metrics"
 	"github.com/drakkan/sftpgo/utils"
 	"github.com/drakkan/sftpgo/utils"
-	"github.com/pires/go-proxyproto"
-	"github.com/pkg/sftp"
-	"golang.org/x/crypto/ssh"
 )
 )
 
 
 const (
 const (

+ 1 - 1
sftpd/sftpd.go

@@ -49,7 +49,7 @@ const (
 )
 )
 
 
 const (
 const (
-	uploadModeStandard = iota //nolint:varcheck,deadcode
+	uploadModeStandard = iota
 	uploadModeAtomic
 	uploadModeAtomic
 	uploadModeAtomicWithResume
 	uploadModeAtomicWithResume
 )
 )

File diff suppressed because it is too large
+ 256 - 510
sftpd/sftpd_test.go


+ 3 - 2
sftpd/ssh_cmd.go

@@ -15,13 +15,14 @@ import (
 	"sync"
 	"sync"
 	"time"
 	"time"
 
 
+	"github.com/google/shlex"
+	"golang.org/x/crypto/ssh"
+
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/logger"
 	"github.com/drakkan/sftpgo/logger"
 	"github.com/drakkan/sftpgo/metrics"
 	"github.com/drakkan/sftpgo/metrics"
 	"github.com/drakkan/sftpgo/utils"
 	"github.com/drakkan/sftpgo/utils"
 	"github.com/drakkan/sftpgo/vfs"
 	"github.com/drakkan/sftpgo/vfs"
-	"github.com/google/shlex"
-	"golang.org/x/crypto/ssh"
 )
 )
 
 
 const scpCmdName = "scp"
 const scpCmdName = "scp"

+ 2 - 1
sftpd/transfer.go

@@ -8,10 +8,11 @@ import (
 	"sync"
 	"sync"
 	"time"
 	"time"
 
 
+	"github.com/eikenb/pipeat"
+
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/logger"
 	"github.com/drakkan/sftpgo/logger"
 	"github.com/drakkan/sftpgo/metrics"
 	"github.com/drakkan/sftpgo/metrics"
-	"github.com/eikenb/pipeat"
 )
 )
 
 
 const (
 const (

+ 2 - 1
utils/utils.go

@@ -24,8 +24,9 @@ import (
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
-	"github.com/drakkan/sftpgo/logger"
 	"golang.org/x/crypto/ssh"
 	"golang.org/x/crypto/ssh"
+
+	"github.com/drakkan/sftpgo/logger"
 )
 )
 
 
 const logSender = "utils"
 const logSender = "utils"

+ 3 - 2
vfs/gcsfs.go

@@ -12,12 +12,13 @@ import (
 	"time"
 	"time"
 
 
 	"cloud.google.com/go/storage"
 	"cloud.google.com/go/storage"
-	"github.com/drakkan/sftpgo/logger"
-	"github.com/drakkan/sftpgo/metrics"
 	"github.com/eikenb/pipeat"
 	"github.com/eikenb/pipeat"
 	"google.golang.org/api/googleapi"
 	"google.golang.org/api/googleapi"
 	"google.golang.org/api/iterator"
 	"google.golang.org/api/iterator"
 	"google.golang.org/api/option"
 	"google.golang.org/api/option"
+
+	"github.com/drakkan/sftpgo/logger"
+	"github.com/drakkan/sftpgo/metrics"
 )
 )
 
 
 var (
 var (

+ 3 - 2
vfs/osfs.go

@@ -8,10 +8,11 @@ import (
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
-	"github.com/drakkan/sftpgo/logger"
-	"github.com/drakkan/sftpgo/utils"
 	"github.com/eikenb/pipeat"
 	"github.com/eikenb/pipeat"
 	"github.com/rs/xid"
 	"github.com/rs/xid"
+
+	"github.com/drakkan/sftpgo/logger"
+	"github.com/drakkan/sftpgo/utils"
 )
 )
 
 
 const (
 const (

+ 2 - 1
vfs/s3fs.go

@@ -15,10 +15,11 @@ import (
 	"github.com/aws/aws-sdk-go/aws/session"
 	"github.com/aws/aws-sdk-go/aws/session"
 	"github.com/aws/aws-sdk-go/service/s3"
 	"github.com/aws/aws-sdk-go/service/s3"
 	"github.com/aws/aws-sdk-go/service/s3/s3manager"
 	"github.com/aws/aws-sdk-go/service/s3/s3manager"
+	"github.com/eikenb/pipeat"
+
 	"github.com/drakkan/sftpgo/logger"
 	"github.com/drakkan/sftpgo/logger"
 	"github.com/drakkan/sftpgo/metrics"
 	"github.com/drakkan/sftpgo/metrics"
 	"github.com/drakkan/sftpgo/utils"
 	"github.com/drakkan/sftpgo/utils"
-	"github.com/eikenb/pipeat"
 )
 )
 
 
 // S3FsConfig defines the configuration for S3 based filesystem
 // S3FsConfig defines the configuration for S3 based filesystem

+ 2 - 1
vfs/vfs.go

@@ -10,9 +10,10 @@ import (
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
-	"github.com/drakkan/sftpgo/logger"
 	"github.com/eikenb/pipeat"
 	"github.com/eikenb/pipeat"
 	"github.com/pkg/sftp"
 	"github.com/pkg/sftp"
+
+	"github.com/drakkan/sftpgo/logger"
 )
 )
 
 
 // Fs defines the interface for filesystem backends
 // Fs defines the interface for filesystem backends

Some files were not shown because too many files changed in this diff