add more linters

test cases migration to testify is now complete.
Linters are enabled for test cases too
This commit is contained in:
Nicola Murino 2020-05-06 19:36:34 +02:00
parent e9534be1e6
commit f02e24437a
43 changed files with 2288 additions and 3762 deletions

View file

@ -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
.golangci.yml Normal file
View file

@ -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

View file

@ -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 (

View file

@ -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 (

View file

@ -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 (

View file

@ -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 (

View file

@ -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
} }

View file

@ -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 (

View file

@ -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 (

View file

@ -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 (

View file

@ -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 (

View file

@ -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 (

View file

@ -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
} }
} }

View file

@ -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.ExternalAuthProgram = "ext_auth_program" //nolint:staticcheck
providerConf.PreLoginProgram = "pre_login_program" 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)

View file

@ -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 (

View file

@ -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 (

View file

@ -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()

View file

@ -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) {

View file

@ -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) {

View file

@ -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 (

View file

@ -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 (

View file

@ -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 (

View file

@ -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) err = ioutil.WriteFile(certPath, []byte(httpsCert), 0666)
ioutil.WriteFile(keyPath, []byte(httpsKey), 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.Remove(logfilePath) //nolint:errcheck
os.RemoveAll(backupsPath) os.RemoveAll(backupsPath) //nolint:errcheck
os.RemoveAll(credentialsPath) os.RemoveAll(credentialsPath) //nolint:errcheck
os.Remove(certPath) os.Remove(certPath) //nolint:errcheck
os.Remove(keyPath) os.Remove(keyPath) //nolint:errcheck
os.Exit(exitCode) 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.StorageClass = "Standard" //nolint:goconst
u.FsConfig.S3Config.KeyPrefix = "/somedir/subdir/" 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.Bucket = "test" //nolint:goconst
user.FsConfig.S3Config.Region = "us-east-1" 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.Bucket = "test-bucket"
user.FsConfig.S3Config.Region = "us-east-1" 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) resp, err := client.Get("https://localhost:8443" + metricsPath)
assert.Error(t, err) if assert.Error(t, err) {
if !strings.Contains(err.Error(), "certificate is not valid") && if !strings.Contains(err.Error(), "certificate is not valid") &&
!strings.Contains(err.Error(), "certificate signed by unknown authority") { !strings.Contains(err.Error(), "certificate signed by unknown authority") {
assert.Fail(t, err.Error()) 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) { assert.True(t, utils.IsStringInSlice(dataprovider.PermListItems, val))
t.Error("permssions for /otherdir does not match") 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 = os.RemoveAll(credentialsPath)
err := dataprovider.Initialize(providerConf, configDir) 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 {

View file

@ -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 := req.ParseForm()
_, err := getFsConfigFromUserPostFields(req) 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)

View file

@ -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

View file

@ -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 (

View file

@ -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.

View file

@ -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() {

View file

@ -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 (

View file

@ -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 (

View file

@ -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/drakkan/sftpgo/vfs"
"github.com/pkg/sftp"
) )
// Connection details for an authenticated user // Connection details for an authenticated user

File diff suppressed because it is too large Load diff

View file

@ -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 { assert.Equal(t, uint32(1000), cmd.SysProcAttr.Credential.Uid)
t.Errorf("unexpected uid") assert.Equal(t, uint32(1001), cmd.SysProcAttr.Credential.Gid)
}
if cmd.SysProcAttr.Credential.Gid != 1001 {
t.Errorf("unexpected gid")
}
} }

View file

@ -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 (

View file

@ -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 Load diff

View file

@ -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"

View file

@ -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 (

View file

@ -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"

View file

@ -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 (

View file

@ -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 (

View file

@ -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

View file

@ -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