add more linters
test cases migration to testify is now complete. Linters are enabled for test cases too
This commit is contained in:
parent
e9534be1e6
commit
f02e24437a
43 changed files with 2288 additions and 3762 deletions
6
.github/workflows/quality.yml
vendored
6
.github/workflows/quality.yml
vendored
|
@ -15,14 +15,14 @@ jobs:
|
|||
- name: Set up Go 1.14
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.14'
|
||||
go-version: 1.14
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- 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
|
||||
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
42
.golangci.yml
Normal 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
|
|
@ -1,13 +1,14 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/drakkan/sftpgo/config"
|
||||
"github.com/drakkan/sftpgo/dataprovider"
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -4,9 +4,10 @@ import (
|
|||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/drakkan/sftpgo/service"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -9,11 +9,12 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/drakkan/sftpgo/dataprovider"
|
||||
"github.com/drakkan/sftpgo/service"
|
||||
"github.com/drakkan/sftpgo/sftpd"
|
||||
"github.com/drakkan/sftpgo/vfs"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -3,8 +3,9 @@ package cmd
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/drakkan/sftpgo/service"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/drakkan/sftpgo/service"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
41
cmd/root.go
41
cmd/root.go
|
@ -5,10 +5,11 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/drakkan/sftpgo/config"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/drakkan/sftpgo/config"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -77,71 +78,71 @@ func Execute() {
|
|||
|
||||
func addConfigFlags(cmd *cobra.Command) {
|
||||
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),
|
||||
"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, "+
|
||||
"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.BindEnv(configFileKey, "SFTPGO_CONFIG_FILE") //nolint: errcheck
|
||||
viper.BindEnv(configFileKey, "SFTPGO_CONFIG_FILE") //nolint:errcheck
|
||||
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 "+
|
||||
"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. "+
|
||||
"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) {
|
||||
addConfigFlags(cmd)
|
||||
|
||||
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),
|
||||
"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.")
|
||||
viper.BindPFlag(logFilePathKey, cmd.Flags().Lookup(logFilePathFlag)) //nolint: errcheck
|
||||
viper.BindPFlag(logFilePathKey, cmd.Flags().Lookup(logFilePathFlag)) //nolint:errcheck
|
||||
|
||||
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),
|
||||
"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.")
|
||||
viper.BindPFlag(logMaxSizeKey, cmd.Flags().Lookup(logMaxSizeFlag)) //nolint: errcheck
|
||||
viper.BindPFlag(logMaxSizeKey, cmd.Flags().Lookup(logMaxSizeFlag)) //nolint:errcheck
|
||||
|
||||
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),
|
||||
"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.")
|
||||
viper.BindPFlag(logMaxBackupKey, cmd.Flags().Lookup(logMaxBackupFlag)) //nolint: errcheck
|
||||
viper.BindPFlag(logMaxBackupKey, cmd.Flags().Lookup(logMaxBackupFlag)) //nolint:errcheck
|
||||
|
||||
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),
|
||||
"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.")
|
||||
viper.BindPFlag(logMaxAgeKey, cmd.Flags().Lookup(logMaxAgeFlag)) //nolint: errcheck
|
||||
viper.BindPFlag(logMaxAgeKey, cmd.Flags().Lookup(logMaxAgeFlag)) //nolint:errcheck
|
||||
|
||||
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 "+
|
||||
"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.")
|
||||
viper.BindPFlag(logCompressKey, cmd.Flags().Lookup(logCompressFlag)) //nolint: errcheck
|
||||
viper.BindPFlag(logCompressKey, cmd.Flags().Lookup(logCompressFlag)) //nolint:errcheck
|
||||
|
||||
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. "+
|
||||
"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.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. "+
|
||||
"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.")
|
||||
viper.BindPFlag(profilerKey, cmd.Flags().Lookup(profilerFlag)) //nolint: errcheck
|
||||
viper.BindPFlag(profilerKey, cmd.Flags().Lookup(profilerFlag)) //nolint:errcheck
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/drakkan/sftpgo/service"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -4,9 +4,10 @@ import (
|
|||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/drakkan/sftpgo/service"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -3,8 +3,9 @@ package cmd
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/drakkan/sftpgo/service"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/drakkan/sftpgo/service"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -3,8 +3,9 @@ package cmd
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/drakkan/sftpgo/service"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/drakkan/sftpgo/service"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -3,8 +3,9 @@ package cmd
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/drakkan/sftpgo/service"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/drakkan/sftpgo/service"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -9,13 +9,14 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/drakkan/sftpgo/dataprovider"
|
||||
"github.com/drakkan/sftpgo/httpclient"
|
||||
"github.com/drakkan/sftpgo/httpd"
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
"github.com/drakkan/sftpgo/sftpd"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -222,19 +223,19 @@ func LoadConfig(configDir, configName string) error {
|
|||
|
||||
func checkHooksCompatibility() {
|
||||
// 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.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.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.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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,12 +8,13 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/drakkan/sftpgo/config"
|
||||
"github.com/drakkan/sftpgo/dataprovider"
|
||||
"github.com/drakkan/sftpgo/httpclient"
|
||||
"github.com/drakkan/sftpgo/httpd"
|
||||
"github.com/drakkan/sftpgo/sftpd"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -173,8 +174,8 @@ func TestHookCompatibity(t *testing.T) {
|
|||
err := config.LoadConfig(configDir, configName)
|
||||
assert.NoError(t, err)
|
||||
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["data_provider"] = providerConf
|
||||
jsonConf, err := json.Marshal(c)
|
||||
|
@ -189,7 +190,7 @@ func TestHookCompatibity(t *testing.T) {
|
|||
err = os.Remove(configFilePath)
|
||||
assert.NoError(t, err)
|
||||
sftpdConf := config.GetSFTPDConfig()
|
||||
sftpdConf.KeyboardInteractiveProgram = "key_int_program"
|
||||
sftpdConf.KeyboardInteractiveProgram = "key_int_program" //nolint:staticcheck
|
||||
cnf := make(map[string]sftpd.Configuration)
|
||||
cnf["sftpd"] = sftpdConf
|
||||
jsonConf, err = json.Marshal(cnf)
|
||||
|
|
|
@ -8,9 +8,10 @@ import (
|
|||
"path/filepath"
|
||||
"time"
|
||||
|
||||
bolt "go.etcd.io/bbolt"
|
||||
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -33,6 +33,7 @@ import (
|
|||
|
||||
"github.com/alexedwards/argon2id"
|
||||
"github.com/go-chi/render"
|
||||
unixcrypt "github.com/nathanaelle/password/v2"
|
||||
"github.com/rs/xid"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
|
@ -43,7 +44,6 @@ import (
|
|||
"github.com/drakkan/sftpgo/metrics"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
"github.com/drakkan/sftpgo/vfs"
|
||||
unixcrypt "github.com/nathanaelle/password/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -271,9 +271,9 @@ func sqlCommonGetUsers(limit int, offset int, order string, username string, dbH
|
|||
defer stmt.Close()
|
||||
var rows *sql.Rows
|
||||
if len(username) > 0 {
|
||||
rows, err = stmt.Query(username, limit, offset)
|
||||
rows, err = stmt.Query(username, limit, offset) //nolint:rowserrcheck // err is checked
|
||||
} else {
|
||||
rows, err = stmt.Query(limit, offset)
|
||||
rows, err = stmt.Query(limit, offset) //nolint:rowserrcheck // err is checked
|
||||
}
|
||||
if err == nil {
|
||||
defer rows.Close()
|
||||
|
|
|
@ -3,10 +3,11 @@ package httpd
|
|||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/render"
|
||||
|
||||
"github.com/drakkan/sftpgo/dataprovider"
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
"github.com/drakkan/sftpgo/sftpd"
|
||||
"github.com/go-chi/render"
|
||||
)
|
||||
|
||||
func getQuotaScans(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
|
@ -5,10 +5,11 @@ import (
|
|||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/drakkan/sftpgo/dataprovider"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/go-chi/render"
|
||||
|
||||
"github.com/drakkan/sftpgo/dataprovider"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
)
|
||||
|
||||
func getUsers(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
|
@ -16,11 +16,12 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/go-chi/render"
|
||||
|
||||
"github.com/drakkan/sftpgo/dataprovider"
|
||||
"github.com/drakkan/sftpgo/httpclient"
|
||||
"github.com/drakkan/sftpgo/sftpd"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
"github.com/go-chi/render"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -9,10 +9,11 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
unixcrypt "github.com/nathanaelle/password/v2"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -13,10 +13,11 @@ import (
|
|||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
|
||||
"github.com/drakkan/sftpgo/dataprovider"
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
"github.com/go-chi/chi"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -46,9 +46,6 @@ const (
|
|||
activeConnectionsPath = "/api/v1/connection"
|
||||
quotaScanPath = "/api/v1/quota_scan"
|
||||
versionPath = "/api/v1/version"
|
||||
providerStatusPath = "/api/v1/providerstatus"
|
||||
dumpDataPath = "/api/v1/dumpdata"
|
||||
loadDataPath = "/api/v1/loaddata"
|
||||
metricsPath = "/metrics"
|
||||
pprofPath = "/debug/pprof/"
|
||||
webBasePath = "/web"
|
||||
|
@ -94,16 +91,20 @@ func TestMain(m *testing.M) {
|
|||
homeBasePath = os.TempDir()
|
||||
logfilePath := filepath.Join(configDir, "sftpgo_api_test.log")
|
||||
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()
|
||||
credentialsPath = filepath.Join(os.TempDir(), "test_credentials")
|
||||
providerConf.CredentialsPath = credentialsPath
|
||||
providerDriverName = providerConf.Driver
|
||||
os.RemoveAll(credentialsPath)
|
||||
os.RemoveAll(credentialsPath) //nolint:errcheck
|
||||
|
||||
err := dataprovider.Initialize(providerConf, configDir)
|
||||
err = dataprovider.Initialize(providerConf, configDir)
|
||||
if err != nil {
|
||||
logger.Warn(logSender, "", "error initializing data provider: %v", err)
|
||||
logger.WarnToConsole("error initializing data provider: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
@ -117,14 +118,18 @@ func TestMain(m *testing.M) {
|
|||
httpd.SetBaseURLAndCredentials("http://127.0.0.1:8081", "", "")
|
||||
backupsPath = filepath.Join(os.TempDir(), "test_backups")
|
||||
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)
|
||||
httpd.SetDataProvider(dataProvider)
|
||||
|
||||
go func() {
|
||||
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
|
||||
certPath := filepath.Join(os.TempDir(), "test.crt")
|
||||
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.CertificateFile = certPath
|
||||
httpdConf.CertificateKeyFile = keyPath
|
||||
|
@ -144,18 +157,18 @@ func TestMain(m *testing.M) {
|
|||
}
|
||||
}()
|
||||
waitTCPListening(fmt.Sprintf("%s:%d", httpdConf.BindAddress, httpdConf.BindPort))
|
||||
httpd.ReloadTLSCertificate()
|
||||
httpd.ReloadTLSCertificate() //nolint:errcheck
|
||||
|
||||
testServer = httptest.NewServer(httpd.GetHTTPRouter())
|
||||
defer testServer.Close()
|
||||
defer testServer.Close() //nolint:errcheck
|
||||
|
||||
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) {
|
||||
|
@ -163,7 +176,7 @@ func TestInitialization(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
httpdConf := config.GetHTTPDConfig()
|
||||
httpdConf.BackupsPath = "test_backups"
|
||||
httpdConf.AuthUserFile = "invalid file"
|
||||
httpdConf.AuthUserFile = "invalid_file"
|
||||
err = httpdConf.Initialize(configDir, true)
|
||||
assert.Error(t, err)
|
||||
httpdConf.BackupsPath = backupsPath
|
||||
|
@ -241,7 +254,7 @@ func TestAddUserNoHomeDir(t *testing.T) {
|
|||
|
||||
func TestAddUserInvalidHomeDir(t *testing.T) {
|
||||
u := getTestUser()
|
||||
u.HomeDir = "relative_path"
|
||||
u.HomeDir = "relative_path" //nolint:goconst
|
||||
_, _, err := httpd.AddUser(u, http.StatusBadRequest)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
@ -333,13 +346,13 @@ func TestAddUserInvalidFsConfig(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
err = os.MkdirAll(credentialsPath, 0700)
|
||||
assert.NoError(t, err)
|
||||
u.FsConfig.S3Config.Bucket = "test"
|
||||
u.FsConfig.S3Config.Bucket = "testbucket"
|
||||
u.FsConfig.S3Config.Region = "eu-west-1"
|
||||
u.FsConfig.S3Config.AccessKey = "access-key"
|
||||
u.FsConfig.S3Config.AccessSecret = "access-secret"
|
||||
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)
|
||||
assert.NoError(t, err)
|
||||
u.FsConfig.S3Config.KeyPrefix = ""
|
||||
|
@ -355,13 +368,13 @@ func TestAddUserInvalidFsConfig(t *testing.T) {
|
|||
u.FsConfig.GCSConfig.Bucket = ""
|
||||
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
||||
assert.NoError(t, err)
|
||||
u.FsConfig.GCSConfig.Bucket = "test"
|
||||
u.FsConfig.GCSConfig.Bucket = "abucket"
|
||||
u.FsConfig.GCSConfig.StorageClass = "Standard"
|
||||
u.FsConfig.GCSConfig.KeyPrefix = "/somedir/subdir/"
|
||||
u.FsConfig.GCSConfig.Credentials = base64.StdEncoding.EncodeToString([]byte("test"))
|
||||
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
||||
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.AutomaticCredentials = 0
|
||||
_, _, err = httpd.AddUser(u, http.StatusBadRequest)
|
||||
|
@ -542,8 +555,8 @@ func TestUserS3Config(t *testing.T) {
|
|||
user, _, err := httpd.AddUser(getTestUser(), http.StatusOK)
|
||||
assert.NoError(t, err)
|
||||
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.AccessSecret = "Server-Access-Secret"
|
||||
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)
|
||||
assert.NoError(t, err)
|
||||
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.Endpoint = "http://localhost:9000"
|
||||
user.FsConfig.S3Config.KeyPrefix = "somedir/subdir"
|
||||
user.FsConfig.S3Config.KeyPrefix = "somedir/subdir" //nolint:goconst
|
||||
user.FsConfig.S3Config.UploadConcurrency = 5
|
||||
user, _, err = httpd.UpdateUser(user, http.StatusOK)
|
||||
assert.NoError(t, err)
|
||||
|
@ -580,7 +593,7 @@ func TestUserS3Config(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
// test user without access key and access secret (shared config state)
|
||||
user.FsConfig.Provider = 1
|
||||
user.FsConfig.S3Config.Bucket = "test1"
|
||||
user.FsConfig.S3Config.Bucket = "testbucket"
|
||||
user.FsConfig.S3Config.Region = "us-east-1"
|
||||
user.FsConfig.S3Config.AccessKey = ""
|
||||
user.FsConfig.S3Config.AccessSecret = ""
|
||||
|
@ -820,7 +833,8 @@ func TestProviderErrors(t *testing.T) {
|
|||
backupData.Users = append(backupData.Users, user)
|
||||
backupContent, _ := json.Marshal(backupData)
|
||||
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)
|
||||
assert.NoError(t, err)
|
||||
err = os.Remove(backupFilePath)
|
||||
|
@ -978,11 +992,14 @@ func TestHTTPSConnection(t *testing.T) {
|
|||
client := &http.Client{
|
||||
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))
|
||||
rr = executeRequest(req)
|
||||
checkResponseCode(t, http.StatusConflict, rr.Code)
|
||||
sftpd.RemoveQuotaScan(user.Username)
|
||||
err = sftpd.RemoveQuotaScan(user.Username)
|
||||
assert.NoError(t, err)
|
||||
|
||||
userAsJSON = getUserAsJSON(t, user)
|
||||
req, _ = http.NewRequest(http.MethodPost, quotaScanPath, bytes.NewBuffer(userAsJSON))
|
||||
|
@ -1584,7 +1602,8 @@ func TestWebUserAddMock(t *testing.T) {
|
|||
rr = executeRequest(req)
|
||||
checkResponseCode(t, http.StatusOK, rr.Code)
|
||||
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))
|
||||
newUser := users[0]
|
||||
assert.Equal(t, user.UID, newUser.UID)
|
||||
|
@ -1650,7 +1669,8 @@ func TestWebUserUpdateMock(t *testing.T) {
|
|||
rr = executeRequest(req)
|
||||
checkResponseCode(t, http.StatusOK, rr.Code)
|
||||
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))
|
||||
updateUser := users[0]
|
||||
assert.Equal(t, user.HomeDir, updateUser.HomeDir)
|
||||
|
@ -1661,9 +1681,8 @@ func TestWebUserUpdateMock(t *testing.T) {
|
|||
assert.Equal(t, user.GID, updateUser.GID)
|
||||
|
||||
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 {
|
||||
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(".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)
|
||||
checkResponseCode(t, http.StatusOK, rr.Code)
|
||||
}
|
||||
|
@ -1827,7 +1847,8 @@ func TestWebUserGCSMock(t *testing.T) {
|
|||
rr = executeRequest(req)
|
||||
checkResponseCode(t, http.StatusOK, rr.Code)
|
||||
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))
|
||||
updateUser := users[0]
|
||||
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()))
|
||||
rr = executeRequest(req)
|
||||
checkResponseCode(t, http.StatusInternalServerError, rr.Code)
|
||||
config.LoadConfig(configDir, "")
|
||||
err := config.LoadConfig(configDir, "")
|
||||
assert.NoError(t, err)
|
||||
providerConf := config.GetProviderConf()
|
||||
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)
|
||||
httpd.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 {
|
||||
baseDir := filepath.Dir(path)
|
||||
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)
|
||||
if size > 0 {
|
||||
|
|
|
@ -14,12 +14,13 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/drakkan/sftpgo/dataprovider"
|
||||
"github.com/drakkan/sftpgo/sftpd"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
"github.com/drakkan/sftpgo/vfs"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -304,8 +305,9 @@ func TestGCSWebInvalidFormFile(t *testing.T) {
|
|||
form.Set("fs_provider", "2")
|
||||
req, _ := http.NewRequest(http.MethodPost, webUserPath, strings.NewReader(form.Encode()))
|
||||
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())
|
||||
}
|
||||
|
||||
|
@ -370,9 +372,10 @@ func TestBasicAuth(t *testing.T) {
|
|||
oldAuthPassword := authPassword
|
||||
authUserFile := filepath.Join(os.TempDir(), "http_users.txt")
|
||||
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)
|
||||
_, _, err := GetVersion(http.StatusUnauthorized)
|
||||
_, _, err = GetVersion(http.StatusUnauthorized)
|
||||
assert.NoError(t, err)
|
||||
SetBaseURLAndCredentials(httpBaseURL, "test1", "password1")
|
||||
_, _, err = GetVersion(http.StatusOK)
|
||||
|
@ -391,12 +394,14 @@ func TestBasicAuth(t *testing.T) {
|
|||
_, _, err = GetVersion(http.StatusOK)
|
||||
assert.Error(t, err)
|
||||
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")
|
||||
_, _, err = GetVersion(http.StatusUnauthorized)
|
||||
assert.NoError(t, err)
|
||||
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")
|
||||
_, _, err = GetVersion(http.StatusUnauthorized)
|
||||
assert.NoError(t, err)
|
||||
|
|
|
@ -4,14 +4,15 @@ import (
|
|||
"net/http"
|
||||
"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/middleware"
|
||||
"github.com/go-chi/render"
|
||||
"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
|
||||
|
|
|
@ -13,11 +13,12 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
|
||||
"github.com/drakkan/sftpgo/dataprovider"
|
||||
"github.com/drakkan/sftpgo/sftpd"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
"github.com/drakkan/sftpgo/vfs"
|
||||
"github.com/go-chi/chi"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -5,9 +5,10 @@ import (
|
|||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/drakkan/sftpgo/metrics"
|
||||
"github.com/go-chi/chi/middleware"
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
"github.com/drakkan/sftpgo/metrics"
|
||||
)
|
||||
|
||||
// StructuredLogger defines a simple wrapper around zerolog logger.
|
||||
|
|
3
main.go
3
main.go
|
@ -4,10 +4,11 @@
|
|||
package main // import "github.com/drakkan/sftpgo"
|
||||
|
||||
import (
|
||||
"github.com/drakkan/sftpgo/cmd"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/lib/pq"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
|
||||
"github.com/drakkan/sftpgo/cmd"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
|
|
@ -11,14 +11,15 @@ import (
|
|||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/grandcat/zeroconf"
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
"github.com/drakkan/sftpgo/config"
|
||||
"github.com/drakkan/sftpgo/dataprovider"
|
||||
"github.com/drakkan/sftpgo/httpd"
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
"github.com/drakkan/sftpgo/sftpd"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
"github.com/grandcat/zeroconf"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -7,13 +7,13 @@ import (
|
|||
"strings"
|
||||
"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/eventlog"
|
||||
"golang.org/x/sys/windows/svc/mgr"
|
||||
|
||||
"github.com/drakkan/sftpgo/dataprovider"
|
||||
"github.com/drakkan/sftpgo/httpd"
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -8,13 +8,12 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/drakkan/sftpgo/vfs"
|
||||
"github.com/pkg/sftp"
|
||||
"golang.org/x/crypto/ssh"
|
||||
|
||||
"github.com/drakkan/sftpgo/dataprovider"
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
|
||||
"github.com/pkg/sftp"
|
||||
"github.com/drakkan/sftpgo/vfs"
|
||||
)
|
||||
|
||||
// Connection details for an authenticated user
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -5,15 +5,13 @@ package sftpd
|
|||
import (
|
||||
"os/exec"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestWrapCmd(t *testing.T) {
|
||||
cmd := exec.Command("ls")
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -13,13 +13,14 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pires/go-proxyproto"
|
||||
"github.com/pkg/sftp"
|
||||
"golang.org/x/crypto/ssh"
|
||||
|
||||
"github.com/drakkan/sftpgo/dataprovider"
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
"github.com/drakkan/sftpgo/metrics"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
"github.com/pires/go-proxyproto"
|
||||
"github.com/pkg/sftp"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -49,7 +49,7 @@ const (
|
|||
)
|
||||
|
||||
const (
|
||||
uploadModeStandard = iota //nolint:varcheck,deadcode
|
||||
uploadModeStandard = iota
|
||||
uploadModeAtomic
|
||||
uploadModeAtomicWithResume
|
||||
)
|
||||
|
|
4640
sftpd/sftpd_test.go
4640
sftpd/sftpd_test.go
File diff suppressed because it is too large
Load diff
|
@ -15,13 +15,14 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/shlex"
|
||||
"golang.org/x/crypto/ssh"
|
||||
|
||||
"github.com/drakkan/sftpgo/dataprovider"
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
"github.com/drakkan/sftpgo/metrics"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
"github.com/drakkan/sftpgo/vfs"
|
||||
"github.com/google/shlex"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
const scpCmdName = "scp"
|
||||
|
|
|
@ -8,10 +8,11 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/eikenb/pipeat"
|
||||
|
||||
"github.com/drakkan/sftpgo/dataprovider"
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
"github.com/drakkan/sftpgo/metrics"
|
||||
"github.com/eikenb/pipeat"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -24,8 +24,9 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
"golang.org/x/crypto/ssh"
|
||||
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
)
|
||||
|
||||
const logSender = "utils"
|
||||
|
|
|
@ -12,12 +12,13 @@ import (
|
|||
"time"
|
||||
|
||||
"cloud.google.com/go/storage"
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
"github.com/drakkan/sftpgo/metrics"
|
||||
"github.com/eikenb/pipeat"
|
||||
"google.golang.org/api/googleapi"
|
||||
"google.golang.org/api/iterator"
|
||||
"google.golang.org/api/option"
|
||||
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
"github.com/drakkan/sftpgo/metrics"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -8,10 +8,11 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
"github.com/eikenb/pipeat"
|
||||
"github.com/rs/xid"
|
||||
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -15,10 +15,11 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
||||
"github.com/eikenb/pipeat"
|
||||
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
"github.com/drakkan/sftpgo/metrics"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
"github.com/eikenb/pipeat"
|
||||
)
|
||||
|
||||
// S3FsConfig defines the configuration for S3 based filesystem
|
||||
|
|
|
@ -10,9 +10,10 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
"github.com/eikenb/pipeat"
|
||||
"github.com/pkg/sftp"
|
||||
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
)
|
||||
|
||||
// Fs defines the interface for filesystem backends
|
||||
|
|
Loading…
Reference in a new issue