mirror of
https://github.com/drakkan/sftpgo.git
synced 2024-11-25 00:50:31 +00:00
fix a potential race condition for pre-login and ext auth
hooks doing something like this: err = provider.updateUser(u) ... return provider.userExists(username) could be racy if another update happen before provider.userExists(username) also pass a pointer to updateUser so if the user is modified inside "validateUser" we can just return the modified user without do a new query
This commit is contained in:
parent
72b2c83392
commit
daac90c4e1
26 changed files with 167 additions and 163 deletions
|
@ -96,7 +96,7 @@ Command-line flags should be specified in the Subsystem declaration.
|
|||
if user.HomeDir != filepath.Clean(homedir) && !preserveHomeDir {
|
||||
// update the user
|
||||
user.HomeDir = filepath.Clean(homedir)
|
||||
err = dataprovider.UpdateUser(user)
|
||||
err = dataprovider.UpdateUser(&user)
|
||||
if err != nil {
|
||||
logger.Error(logSender, connectionID, "unable to update user %#v: %v", username, err)
|
||||
os.Exit(1)
|
||||
|
@ -113,7 +113,7 @@ Command-line flags should be specified in the Subsystem declaration.
|
|||
user.Password = connectionID
|
||||
user.Permissions = make(map[string][]string)
|
||||
user.Permissions["/"] = []string{dataprovider.PermAny}
|
||||
err = dataprovider.AddUser(user)
|
||||
err = dataprovider.AddUser(&user)
|
||||
if err != nil {
|
||||
logger.Error(logSender, connectionID, "unable to add user %#v: %v", username, err)
|
||||
os.Exit(1)
|
||||
|
|
|
@ -364,7 +364,7 @@ func (c *Configuration) GetProxyListener(listener net.Listener) (*proxyproto.Lis
|
|||
|
||||
// ExecutePostConnectHook executes the post connect hook if defined
|
||||
func (c *Configuration) ExecutePostConnectHook(ipAddr, protocol string) error {
|
||||
if len(c.PostConnectHook) == 0 {
|
||||
if c.PostConnectHook == "" {
|
||||
return nil
|
||||
}
|
||||
if strings.HasPrefix(c.PostConnectHook, "http") {
|
||||
|
@ -594,7 +594,7 @@ func (conns *ActiveConnections) checkIdles() {
|
|||
|
||||
for _, c := range conns.connections {
|
||||
idleTime := time.Since(c.GetLastActivity())
|
||||
isUnauthenticatedFTPUser := (c.GetProtocol() == ProtocolFTP && len(c.GetUsername()) == 0)
|
||||
isUnauthenticatedFTPUser := (c.GetProtocol() == ProtocolFTP && c.GetUsername() == "")
|
||||
|
||||
if idleTime > Config.idleTimeoutAsDuration || (isUnauthenticatedFTPUser && idleTime > Config.idleLoginTimeout) {
|
||||
defer func(conn ActiveConnection, isFTPNoAuth bool) {
|
||||
|
|
|
@ -1031,7 +1031,7 @@ func TestHasSpace(t *testing.T) {
|
|||
|
||||
user.VirtualFolders[0].QuotaFiles = 0
|
||||
user.VirtualFolders[0].QuotaSize = 0
|
||||
err = dataprovider.AddUser(user)
|
||||
err = dataprovider.AddUser(&user)
|
||||
assert.NoError(t, err)
|
||||
user, err = dataprovider.UserExists(user.Username)
|
||||
assert.NoError(t, err)
|
||||
|
@ -1041,7 +1041,7 @@ func TestHasSpace(t *testing.T) {
|
|||
|
||||
user.VirtualFolders[0].QuotaFiles = 10
|
||||
user.VirtualFolders[0].QuotaSize = 1048576
|
||||
err = dataprovider.UpdateUser(user)
|
||||
err = dataprovider.UpdateUser(&user)
|
||||
assert.NoError(t, err)
|
||||
c.User = user
|
||||
quotaResult = c.HasSpace(true, "/vdir/file1")
|
||||
|
@ -1057,10 +1057,10 @@ func TestHasSpace(t *testing.T) {
|
|||
quotaResult = c.HasSpace(true, "/vdir/file1")
|
||||
assert.False(t, quotaResult.HasSpace)
|
||||
|
||||
err = dataprovider.DeleteUser(user)
|
||||
err = dataprovider.DeleteUser(&user)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = dataprovider.DeleteFolder(folder)
|
||||
err = dataprovider.DeleteFolder(&folder)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
|
@ -1091,7 +1091,7 @@ func TestUpdateQuotaMoveVFolders(t *testing.T) {
|
|||
QuotaFiles: -1,
|
||||
QuotaSize: -1,
|
||||
})
|
||||
err := dataprovider.AddUser(user)
|
||||
err := dataprovider.AddUser(&user)
|
||||
assert.NoError(t, err)
|
||||
user, err = dataprovider.UserExists(user.Username)
|
||||
assert.NoError(t, err)
|
||||
|
@ -1148,11 +1148,11 @@ func TestUpdateQuotaMoveVFolders(t *testing.T) {
|
|||
assert.Equal(t, 1, user.UsedQuotaFiles)
|
||||
assert.Equal(t, int64(100), user.UsedQuotaSize)
|
||||
|
||||
err = dataprovider.DeleteUser(user)
|
||||
err = dataprovider.DeleteUser(&user)
|
||||
assert.NoError(t, err)
|
||||
err = dataprovider.DeleteFolder(folder1)
|
||||
err = dataprovider.DeleteFolder(&folder1)
|
||||
assert.NoError(t, err)
|
||||
err = dataprovider.DeleteFolder(folder2)
|
||||
err = dataprovider.DeleteFolder(&folder2)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
|
|
|
@ -171,19 +171,15 @@ func (m *CertManager) LoadRootCAs() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// SetCACertificates sets the root CA authorities file paths
|
||||
// SetCACertificates sets the root CA authorities file paths.
|
||||
// This should not be changed at runtime
|
||||
func (m *CertManager) SetCACertificates(caCertificates []string) {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
m.caCertificates = caCertificates
|
||||
}
|
||||
|
||||
// SetCARevocationLists sets the CA revocation lists file paths
|
||||
// SetCARevocationLists sets the CA revocation lists file paths.
|
||||
// This should not be changed at runtime
|
||||
func (m *CertManager) SetCARevocationLists(caRevocationLists []string) {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
m.caRevocationLists = caRevocationLists
|
||||
}
|
||||
|
||||
|
|
|
@ -101,7 +101,7 @@ func (p BoltProvider) checkAvailability() error {
|
|||
|
||||
func (p BoltProvider) validateUserAndPass(username, password, ip, protocol string) (User, error) {
|
||||
var user User
|
||||
if len(password) == 0 {
|
||||
if password == "" {
|
||||
return user, errors.New("Credentials cannot be null or empty")
|
||||
}
|
||||
user, err := p.userExists(username)
|
||||
|
@ -246,8 +246,8 @@ func (p BoltProvider) userExists(username string) (User, error) {
|
|||
return user, err
|
||||
}
|
||||
|
||||
func (p BoltProvider) addUser(user User) error {
|
||||
err := validateUser(&user)
|
||||
func (p BoltProvider) addUser(user *User) error {
|
||||
err := validateUser(user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -291,8 +291,8 @@ func (p BoltProvider) addUser(user User) error {
|
|||
})
|
||||
}
|
||||
|
||||
func (p BoltProvider) updateUser(user User) error {
|
||||
err := validateUser(&user)
|
||||
func (p BoltProvider) updateUser(user *User) error {
|
||||
err := validateUser(user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -315,7 +315,7 @@ func (p BoltProvider) updateUser(user User) error {
|
|||
return err
|
||||
}
|
||||
for _, folder := range oldUser.VirtualFolders {
|
||||
err = removeUserFromFolderMapping(folder, oldUser, folderBucket)
|
||||
err = removeUserFromFolderMapping(folder, &oldUser, folderBucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -339,7 +339,7 @@ func (p BoltProvider) updateUser(user User) error {
|
|||
})
|
||||
}
|
||||
|
||||
func (p BoltProvider) deleteUser(user User) error {
|
||||
func (p BoltProvider) deleteUser(user *User) error {
|
||||
return p.dbHandle.Update(func(tx *bolt.Tx) error {
|
||||
bucket, idxBucket, err := getBuckets(tx)
|
||||
if err != nil {
|
||||
|
@ -567,8 +567,8 @@ func (p BoltProvider) getFolderByPath(name string) (vfs.BaseVirtualFolder, error
|
|||
return folder, err
|
||||
}
|
||||
|
||||
func (p BoltProvider) addFolder(folder vfs.BaseVirtualFolder) error {
|
||||
err := validateFolder(&folder)
|
||||
func (p BoltProvider) addFolder(folder *vfs.BaseVirtualFolder) error {
|
||||
err := validateFolder(folder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -580,12 +580,12 @@ func (p BoltProvider) addFolder(folder vfs.BaseVirtualFolder) error {
|
|||
if f := bucket.Get([]byte(folder.MappedPath)); f != nil {
|
||||
return fmt.Errorf("folder %v already exists", folder.MappedPath)
|
||||
}
|
||||
_, err = addFolderInternal(folder, bucket)
|
||||
_, err = addFolderInternal(*folder, bucket)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func (p BoltProvider) deleteFolder(folder vfs.BaseVirtualFolder) error {
|
||||
func (p BoltProvider) deleteFolder(folder *vfs.BaseVirtualFolder) error {
|
||||
return p.dbHandle.Update(func(tx *bolt.Tx) error {
|
||||
bucket, err := getFolderBucket(tx)
|
||||
if err != nil {
|
||||
|
@ -816,7 +816,7 @@ func addFolderInternal(folder vfs.BaseVirtualFolder, bucket *bolt.Bucket) (vfs.B
|
|||
return folder, err
|
||||
}
|
||||
|
||||
func addUserToFolderMapping(folder vfs.VirtualFolder, user User, bucket *bolt.Bucket) error {
|
||||
func addUserToFolderMapping(folder vfs.VirtualFolder, user *User, bucket *bolt.Bucket) error {
|
||||
var baseFolder vfs.BaseVirtualFolder
|
||||
var err error
|
||||
if f := bucket.Get([]byte(folder.MappedPath)); f == nil {
|
||||
|
@ -842,7 +842,7 @@ func addUserToFolderMapping(folder vfs.VirtualFolder, user User, bucket *bolt.Bu
|
|||
return err
|
||||
}
|
||||
|
||||
func removeUserFromFolderMapping(folder vfs.VirtualFolder, user User, bucket *bolt.Bucket) error {
|
||||
func removeUserFromFolderMapping(folder vfs.VirtualFolder, user *User, bucket *bolt.Bucket) error {
|
||||
var f []byte
|
||||
if f = bucket.Get([]byte(folder.MappedPath)); f == nil {
|
||||
// the folder does not exists so there is no associated user
|
||||
|
@ -940,7 +940,7 @@ func updateDatabaseFrom1To2(dbHandle *bolt.DB) error {
|
|||
return err
|
||||
}
|
||||
user.Status = 1
|
||||
err = provider.updateUser(user)
|
||||
err = provider.updateUser(&user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -994,7 +994,8 @@ func updateDatabaseFrom2To3(dbHandle *bolt.DB) error {
|
|||
}
|
||||
|
||||
for _, user := range users {
|
||||
err = provider.updateUser(user)
|
||||
user := user
|
||||
err = provider.updateUser(&user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1053,7 +1054,7 @@ func updateDatabaseFrom3To4(dbHandle *bolt.DB) error {
|
|||
}
|
||||
}
|
||||
user.VirtualFolders = folders
|
||||
err = provider.updateUser(user)
|
||||
err = provider.updateUser(&user)
|
||||
providerLog(logger.LevelInfo, "number of virtual folders to restore %v, user %#v, error: %v", len(user.VirtualFolders),
|
||||
user.Username, err)
|
||||
if err != nil {
|
||||
|
|
|
@ -367,17 +367,17 @@ type Provider interface {
|
|||
updateQuota(username string, filesAdd int, sizeAdd int64, reset bool) error
|
||||
getUsedQuota(username string) (int, int64, error)
|
||||
userExists(username string) (User, error)
|
||||
addUser(user User) error
|
||||
updateUser(user User) error
|
||||
deleteUser(user User) error
|
||||
addUser(user *User) error
|
||||
updateUser(user *User) error
|
||||
deleteUser(user *User) error
|
||||
getUsers(limit int, offset int, order string, username string) ([]User, error)
|
||||
dumpUsers() ([]User, error)
|
||||
getUserByID(ID int64) (User, error)
|
||||
updateLastLogin(username string) error
|
||||
getFolders(limit, offset int, order, folderPath string) ([]vfs.BaseVirtualFolder, error)
|
||||
getFolderByPath(mappedPath string) (vfs.BaseVirtualFolder, error)
|
||||
addFolder(folder vfs.BaseVirtualFolder) error
|
||||
deleteFolder(folder vfs.BaseVirtualFolder) error
|
||||
addFolder(folder *vfs.BaseVirtualFolder) error
|
||||
deleteFolder(folder *vfs.BaseVirtualFolder) error
|
||||
updateFolderQuota(mappedPath string, filesAdd int, sizeAdd int64, reset bool) error
|
||||
getUsedFolderQuota(mappedPath string) (int, int64, error)
|
||||
dumpFolders() ([]vfs.BaseVirtualFolder, error)
|
||||
|
@ -439,16 +439,16 @@ func Initialize(cnf Config, basePath string) error {
|
|||
|
||||
func validateHooks() error {
|
||||
var hooks []string
|
||||
if len(config.PreLoginHook) > 0 && !strings.HasPrefix(config.PreLoginHook, "http") {
|
||||
if config.PreLoginHook != "" && !strings.HasPrefix(config.PreLoginHook, "http") {
|
||||
hooks = append(hooks, config.PreLoginHook)
|
||||
}
|
||||
if len(config.ExternalAuthHook) > 0 && !strings.HasPrefix(config.ExternalAuthHook, "http") {
|
||||
if config.ExternalAuthHook != "" && !strings.HasPrefix(config.ExternalAuthHook, "http") {
|
||||
hooks = append(hooks, config.ExternalAuthHook)
|
||||
}
|
||||
if len(config.PostLoginHook) > 0 && !strings.HasPrefix(config.PostLoginHook, "http") {
|
||||
if config.PostLoginHook != "" && !strings.HasPrefix(config.PostLoginHook, "http") {
|
||||
hooks = append(hooks, config.PostLoginHook)
|
||||
}
|
||||
if len(config.CheckPasswordHook) > 0 && !strings.HasPrefix(config.CheckPasswordHook, "http") {
|
||||
if config.CheckPasswordHook != "" && !strings.HasPrefix(config.CheckPasswordHook, "http") {
|
||||
hooks = append(hooks, config.CheckPasswordHook)
|
||||
}
|
||||
|
||||
|
@ -527,14 +527,14 @@ func RevertDatabase(cnf Config, basePath string, targetVersion int) error {
|
|||
|
||||
// CheckUserAndPass retrieves the SFTP user with the given username and password if a match is found or an error
|
||||
func CheckUserAndPass(username, password, ip, protocol string) (User, error) {
|
||||
if len(config.ExternalAuthHook) > 0 && (config.ExternalAuthScope == 0 || config.ExternalAuthScope&1 != 0) {
|
||||
if config.ExternalAuthHook != "" && (config.ExternalAuthScope == 0 || config.ExternalAuthScope&1 != 0) {
|
||||
user, err := doExternalAuth(username, password, nil, "", ip, protocol)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
return checkUserAndPass(user, password, ip, protocol)
|
||||
}
|
||||
if len(config.PreLoginHook) > 0 {
|
||||
if config.PreLoginHook != "" {
|
||||
user, err := executePreLoginHook(username, LoginMethodPassword, ip, protocol)
|
||||
if err != nil {
|
||||
return user, err
|
||||
|
@ -546,14 +546,14 @@ func CheckUserAndPass(username, password, ip, protocol string) (User, error) {
|
|||
|
||||
// CheckUserAndPubKey retrieves the SFTP user with the given username and public key if a match is found or an error
|
||||
func CheckUserAndPubKey(username string, pubKey []byte, ip, protocol string) (User, string, error) {
|
||||
if len(config.ExternalAuthHook) > 0 && (config.ExternalAuthScope == 0 || config.ExternalAuthScope&2 != 0) {
|
||||
if config.ExternalAuthHook != "" && (config.ExternalAuthScope == 0 || config.ExternalAuthScope&2 != 0) {
|
||||
user, err := doExternalAuth(username, "", pubKey, "", ip, protocol)
|
||||
if err != nil {
|
||||
return user, "", err
|
||||
}
|
||||
return checkUserAndPubKey(user, pubKey)
|
||||
}
|
||||
if len(config.PreLoginHook) > 0 {
|
||||
if config.PreLoginHook != "" {
|
||||
user, err := executePreLoginHook(username, SSHLoginMethodPublicKey, ip, protocol)
|
||||
if err != nil {
|
||||
return user, "", err
|
||||
|
@ -568,9 +568,9 @@ func CheckUserAndPubKey(username string, pubKey []byte, ip, protocol string) (Us
|
|||
func CheckKeyboardInteractiveAuth(username, authHook string, client ssh.KeyboardInteractiveChallenge, ip, protocol string) (User, error) {
|
||||
var user User
|
||||
var err error
|
||||
if len(config.ExternalAuthHook) > 0 && (config.ExternalAuthScope == 0 || config.ExternalAuthScope&4 != 0) {
|
||||
if config.ExternalAuthHook != "" && (config.ExternalAuthScope == 0 || config.ExternalAuthScope&4 != 0) {
|
||||
user, err = doExternalAuth(username, "", nil, "1", ip, protocol)
|
||||
} else if len(config.PreLoginHook) > 0 {
|
||||
} else if config.PreLoginHook != "" {
|
||||
user, err = executePreLoginHook(username, SSHLoginMethodKeyboardInteractive, ip, protocol)
|
||||
} else {
|
||||
user, err = provider.userExists(username)
|
||||
|
@ -653,41 +653,41 @@ func UserExists(username string) (User, error) {
|
|||
|
||||
// AddUser adds a new SFTPGo user.
|
||||
// ManageUsers configuration must be set to 1 to enable this method
|
||||
func AddUser(user User) error {
|
||||
func AddUser(user *User) error {
|
||||
if config.ManageUsers == 0 {
|
||||
return &MethodDisabledError{err: manageUsersDisabledError}
|
||||
}
|
||||
err := provider.addUser(user)
|
||||
if err == nil {
|
||||
go executeAction(operationAdd, user)
|
||||
go executeAction(operationAdd, *user)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateUser updates an existing SFTPGo user.
|
||||
// ManageUsers configuration must be set to 1 to enable this method
|
||||
func UpdateUser(user User) error {
|
||||
func UpdateUser(user *User) error {
|
||||
if config.ManageUsers == 0 {
|
||||
return &MethodDisabledError{err: manageUsersDisabledError}
|
||||
}
|
||||
err := provider.updateUser(user)
|
||||
if err == nil {
|
||||
RemoveCachedWebDAVUser(user.Username)
|
||||
go executeAction(operationUpdate, user)
|
||||
go executeAction(operationUpdate, *user)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteUser deletes an existing SFTPGo user.
|
||||
// ManageUsers configuration must be set to 1 to enable this method
|
||||
func DeleteUser(user User) error {
|
||||
func DeleteUser(user *User) error {
|
||||
if config.ManageUsers == 0 {
|
||||
return &MethodDisabledError{err: manageUsersDisabledError}
|
||||
}
|
||||
err := provider.deleteUser(user)
|
||||
if err == nil {
|
||||
RemoveCachedWebDAVUser(user.Username)
|
||||
go executeAction(operationDelete, user)
|
||||
go executeAction(operationDelete, *user)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -711,7 +711,7 @@ func GetUserByID(ID int64) (User, error) {
|
|||
|
||||
// AddFolder adds a new virtual folder.
|
||||
// ManageUsers configuration must be set to 1 to enable this method
|
||||
func AddFolder(folder vfs.BaseVirtualFolder) error {
|
||||
func AddFolder(folder *vfs.BaseVirtualFolder) error {
|
||||
if config.ManageUsers == 0 {
|
||||
return &MethodDisabledError{err: manageUsersDisabledError}
|
||||
}
|
||||
|
@ -720,7 +720,7 @@ func AddFolder(folder vfs.BaseVirtualFolder) error {
|
|||
|
||||
// DeleteFolder deletes an existing folder.
|
||||
// ManageUsers configuration must be set to 1 to enable this method
|
||||
func DeleteFolder(folder vfs.BaseVirtualFolder) error {
|
||||
func DeleteFolder(folder *vfs.BaseVirtualFolder) error {
|
||||
if config.ManageUsers == 0 {
|
||||
return &MethodDisabledError{err: manageUsersDisabledError}
|
||||
}
|
||||
|
@ -1303,7 +1303,7 @@ func validateUser(user *User) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func checkLoginConditions(user User) error {
|
||||
func checkLoginConditions(user *User) error {
|
||||
if user.Status < 1 {
|
||||
return fmt.Errorf("user %#v is disabled", user.Username)
|
||||
}
|
||||
|
@ -1344,11 +1344,11 @@ func isPasswordOK(user *User, password string) (bool, error) {
|
|||
}
|
||||
|
||||
func checkUserAndPass(user User, password, ip, protocol string) (User, error) {
|
||||
err := checkLoginConditions(user)
|
||||
err := checkLoginConditions(&user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
if len(user.Password) == 0 {
|
||||
if user.Password == "" {
|
||||
return user, errors.New("Credentials cannot be null or empty")
|
||||
}
|
||||
hookResponse, err := executeCheckPasswordHook(user.Username, password, ip, protocol)
|
||||
|
@ -1378,7 +1378,7 @@ func checkUserAndPass(user User, password, ip, protocol string) (User, error) {
|
|||
}
|
||||
|
||||
func checkUserAndPubKey(user User, pubKey []byte) (User, string, error) {
|
||||
err := checkLoginConditions(user)
|
||||
err := checkLoginConditions(&user)
|
||||
if err != nil {
|
||||
return user, "", err
|
||||
}
|
||||
|
@ -1731,7 +1731,7 @@ func doKeyboardInteractiveAuth(user User, authHook string, client ssh.KeyboardIn
|
|||
if authResult != 1 {
|
||||
return user, fmt.Errorf("keyboard interactive auth failed, result: %v", authResult)
|
||||
}
|
||||
err = checkLoginConditions(user)
|
||||
err = checkLoginConditions(&user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
@ -1739,7 +1739,7 @@ func doKeyboardInteractiveAuth(user User, authHook string, client ssh.KeyboardIn
|
|||
}
|
||||
|
||||
func isCheckPasswordHookDefined(protocol string) bool {
|
||||
if len(config.CheckPasswordHook) == 0 {
|
||||
if config.CheckPasswordHook == "" {
|
||||
return false
|
||||
}
|
||||
if config.CheckPasswordScope == 0 {
|
||||
|
@ -1900,20 +1900,23 @@ func executePreLoginHook(username, loginMethod, ip, protocol string) (User, erro
|
|||
u.LastQuotaUpdate = userLastQuotaUpdate
|
||||
u.LastLogin = userLastLogin
|
||||
if userID == 0 {
|
||||
err = provider.addUser(u)
|
||||
err = provider.addUser(&u)
|
||||
} else {
|
||||
err = provider.updateUser(u)
|
||||
err = provider.updateUser(&u)
|
||||
}
|
||||
if err != nil {
|
||||
return u, err
|
||||
}
|
||||
providerLog(logger.LevelDebug, "user %#v added/updated from pre-login hook response, id: %v", username, userID)
|
||||
return provider.userExists(username)
|
||||
if userID == 0 {
|
||||
return provider.userExists(username)
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// ExecutePostLoginHook executes the post login hook if defined
|
||||
func ExecutePostLoginHook(username, loginMethod, ip, protocol string, err error) {
|
||||
if len(config.PostLoginHook) == 0 {
|
||||
if config.PostLoginHook == "" {
|
||||
return
|
||||
}
|
||||
if config.PostLoginScope == 1 && err == nil {
|
||||
|
@ -2047,7 +2050,7 @@ func doExternalAuth(username, password string, pubKey []byte, keyboardInteractiv
|
|||
if len(pkey) > 0 && !utils.IsStringPrefixInSlice(pkey, user.PublicKeys) {
|
||||
user.PublicKeys = append(user.PublicKeys, pkey)
|
||||
}
|
||||
// some users want to map multiple login usernames with a single SGTPGo account
|
||||
// some users want to map multiple login usernames with a single SFTPGo account
|
||||
// for example an SFTP user logins using "user1" or "user2" and the external auth
|
||||
// returns "user" in both cases, so we use the username returned from
|
||||
// external auth and not the one used to login
|
||||
|
@ -2058,10 +2061,10 @@ func doExternalAuth(username, password string, pubKey []byte, keyboardInteractiv
|
|||
user.UsedQuotaFiles = u.UsedQuotaFiles
|
||||
user.LastQuotaUpdate = u.LastQuotaUpdate
|
||||
user.LastLogin = u.LastLogin
|
||||
err = provider.updateUser(user)
|
||||
} else {
|
||||
err = provider.addUser(user)
|
||||
err = provider.updateUser(&user)
|
||||
return user, err
|
||||
}
|
||||
err = provider.addUser(&user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
@ -2174,7 +2177,7 @@ func CacheWebDAVUser(cachedUser *CachedUser, maxSize int) {
|
|||
|
||||
webDAVUsersCache.Range(func(k, v interface{}) bool {
|
||||
cacheSize++
|
||||
if len(userToRemove) == 0 {
|
||||
if userToRemove == "" {
|
||||
userToRemove = k.(string)
|
||||
expirationTime = v.(*CachedUser).Expiration
|
||||
return true
|
||||
|
|
|
@ -88,7 +88,7 @@ func (p MemoryProvider) close() error {
|
|||
|
||||
func (p MemoryProvider) validateUserAndPass(username, password, ip, protocol string) (User, error) {
|
||||
var user User
|
||||
if len(password) == 0 {
|
||||
if password == "" {
|
||||
return user, errors.New("Credentials cannot be null or empty")
|
||||
}
|
||||
user, err := p.userExists(username)
|
||||
|
@ -178,13 +178,13 @@ func (p MemoryProvider) getUsedQuota(username string) (int, int64, error) {
|
|||
return user.UsedQuotaFiles, user.UsedQuotaSize, err
|
||||
}
|
||||
|
||||
func (p MemoryProvider) addUser(user User) error {
|
||||
func (p MemoryProvider) addUser(user *User) error {
|
||||
p.dbHandle.Lock()
|
||||
defer p.dbHandle.Unlock()
|
||||
if p.dbHandle.isClosed {
|
||||
return errMemoryProviderClosed
|
||||
}
|
||||
err := validateUser(&user)
|
||||
err := validateUser(user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -198,20 +198,20 @@ func (p MemoryProvider) addUser(user User) error {
|
|||
user.UsedQuotaFiles = 0
|
||||
user.LastLogin = 0
|
||||
user.VirtualFolders = p.joinVirtualFoldersFields(user)
|
||||
p.dbHandle.users[user.Username] = user
|
||||
p.dbHandle.users[user.Username] = user.getACopy()
|
||||
p.dbHandle.usersIdx[user.ID] = user.Username
|
||||
p.dbHandle.usernames = append(p.dbHandle.usernames, user.Username)
|
||||
sort.Strings(p.dbHandle.usernames)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p MemoryProvider) updateUser(user User) error {
|
||||
func (p MemoryProvider) updateUser(user *User) error {
|
||||
p.dbHandle.Lock()
|
||||
defer p.dbHandle.Unlock()
|
||||
if p.dbHandle.isClosed {
|
||||
return errMemoryProviderClosed
|
||||
}
|
||||
err := validateUser(&user)
|
||||
err := validateUser(user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -227,11 +227,12 @@ func (p MemoryProvider) updateUser(user User) error {
|
|||
user.UsedQuotaSize = u.UsedQuotaSize
|
||||
user.UsedQuotaFiles = u.UsedQuotaFiles
|
||||
user.LastLogin = u.LastLogin
|
||||
p.dbHandle.users[user.Username] = user
|
||||
// pre-login and external auth hook will use the passed *user so save a copy
|
||||
p.dbHandle.users[user.Username] = user.getACopy()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p MemoryProvider) deleteUser(user User) error {
|
||||
func (p MemoryProvider) deleteUser(user *User) error {
|
||||
p.dbHandle.Lock()
|
||||
defer p.dbHandle.Unlock()
|
||||
if p.dbHandle.isClosed {
|
||||
|
@ -247,7 +248,7 @@ func (p MemoryProvider) deleteUser(user User) error {
|
|||
delete(p.dbHandle.users, user.Username)
|
||||
delete(p.dbHandle.usersIdx, user.ID)
|
||||
// this could be more efficient
|
||||
p.dbHandle.usernames = []string{}
|
||||
p.dbHandle.usernames = make([]string, 0, len(p.dbHandle.users))
|
||||
for username := range p.dbHandle.users {
|
||||
p.dbHandle.usernames = append(p.dbHandle.usernames, username)
|
||||
}
|
||||
|
@ -396,7 +397,7 @@ func (p MemoryProvider) getUsedFolderQuota(mappedPath string) (int, int64, error
|
|||
return folder.UsedQuotaFiles, folder.UsedQuotaSize, err
|
||||
}
|
||||
|
||||
func (p MemoryProvider) joinVirtualFoldersFields(user User) []vfs.VirtualFolder {
|
||||
func (p MemoryProvider) joinVirtualFoldersFields(user *User) []vfs.VirtualFolder {
|
||||
var folders []vfs.VirtualFolder
|
||||
for _, folder := range user.VirtualFolders {
|
||||
f, err := p.addOrGetFolderInternal(folder.MappedPath, user.Username, folder.UsedQuotaSize, folder.UsedQuotaFiles,
|
||||
|
@ -522,13 +523,13 @@ func (p MemoryProvider) getFolderByPath(mappedPath string) (vfs.BaseVirtualFolde
|
|||
return p.folderExistsInternal(mappedPath)
|
||||
}
|
||||
|
||||
func (p MemoryProvider) addFolder(folder vfs.BaseVirtualFolder) error {
|
||||
func (p MemoryProvider) addFolder(folder *vfs.BaseVirtualFolder) error {
|
||||
p.dbHandle.Lock()
|
||||
defer p.dbHandle.Unlock()
|
||||
if p.dbHandle.isClosed {
|
||||
return errMemoryProviderClosed
|
||||
}
|
||||
err := validateFolder(&folder)
|
||||
err := validateFolder(folder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -537,13 +538,13 @@ func (p MemoryProvider) addFolder(folder vfs.BaseVirtualFolder) error {
|
|||
return fmt.Errorf("folder %#v already exists", folder.MappedPath)
|
||||
}
|
||||
folder.ID = p.getNextFolderID()
|
||||
p.dbHandle.vfolders[folder.MappedPath] = folder
|
||||
p.dbHandle.vfolders[folder.MappedPath] = *folder
|
||||
p.dbHandle.vfoldersPaths = append(p.dbHandle.vfoldersPaths, folder.MappedPath)
|
||||
sort.Strings(p.dbHandle.vfoldersPaths)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p MemoryProvider) deleteFolder(folder vfs.BaseVirtualFolder) error {
|
||||
func (p MemoryProvider) deleteFolder(folder *vfs.BaseVirtualFolder) error {
|
||||
p.dbHandle.Lock()
|
||||
defer p.dbHandle.Unlock()
|
||||
if p.dbHandle.isClosed {
|
||||
|
@ -644,8 +645,9 @@ func (p MemoryProvider) reloadConfig() error {
|
|||
logger.Debug(logSender, "", "folder %#v already exists, restore not needed", folder.MappedPath)
|
||||
continue
|
||||
}
|
||||
folder := folder // pin
|
||||
folder.Users = nil
|
||||
err = p.addFolder(folder)
|
||||
err = p.addFolder(&folder)
|
||||
if err != nil {
|
||||
providerLog(logger.LevelWarn, "error adding folder %#v: %v", folder.MappedPath, err)
|
||||
return err
|
||||
|
@ -653,15 +655,16 @@ func (p MemoryProvider) reloadConfig() error {
|
|||
}
|
||||
for _, user := range dump.Users {
|
||||
u, err := p.userExists(user.Username)
|
||||
user := user // pin
|
||||
if err == nil {
|
||||
user.ID = u.ID
|
||||
err = p.updateUser(user)
|
||||
err = p.updateUser(&user)
|
||||
if err != nil {
|
||||
providerLog(logger.LevelWarn, "error updating user %#v: %v", user.Username, err)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err = p.addUser(user)
|
||||
err = p.addUser(&user)
|
||||
if err != nil {
|
||||
providerLog(logger.LevelWarn, "error adding user %#v: %v", user.Username, err)
|
||||
return err
|
||||
|
|
|
@ -74,7 +74,7 @@ func initializeMySQLProvider() error {
|
|||
}
|
||||
func getMySQLConnectionString(redactedPwd bool) string {
|
||||
var connectionString string
|
||||
if len(config.ConnectionString) == 0 {
|
||||
if config.ConnectionString == "" {
|
||||
password := config.Password
|
||||
if redactedPwd {
|
||||
password = "[redacted]"
|
||||
|
@ -119,15 +119,15 @@ func (p MySQLProvider) userExists(username string) (User, error) {
|
|||
return sqlCommonCheckUserExists(username, p.dbHandle)
|
||||
}
|
||||
|
||||
func (p MySQLProvider) addUser(user User) error {
|
||||
func (p MySQLProvider) addUser(user *User) error {
|
||||
return sqlCommonAddUser(user, p.dbHandle)
|
||||
}
|
||||
|
||||
func (p MySQLProvider) updateUser(user User) error {
|
||||
func (p MySQLProvider) updateUser(user *User) error {
|
||||
return sqlCommonUpdateUser(user, p.dbHandle)
|
||||
}
|
||||
|
||||
func (p MySQLProvider) deleteUser(user User) error {
|
||||
func (p MySQLProvider) deleteUser(user *User) error {
|
||||
return sqlCommonDeleteUser(user, p.dbHandle)
|
||||
}
|
||||
|
||||
|
@ -153,11 +153,11 @@ func (p MySQLProvider) getFolderByPath(mappedPath string) (vfs.BaseVirtualFolder
|
|||
return sqlCommonCheckFolderExists(ctx, mappedPath, p.dbHandle)
|
||||
}
|
||||
|
||||
func (p MySQLProvider) addFolder(folder vfs.BaseVirtualFolder) error {
|
||||
func (p MySQLProvider) addFolder(folder *vfs.BaseVirtualFolder) error {
|
||||
return sqlCommonAddFolder(folder, p.dbHandle)
|
||||
}
|
||||
|
||||
func (p MySQLProvider) deleteFolder(folder vfs.BaseVirtualFolder) error {
|
||||
func (p MySQLProvider) deleteFolder(folder *vfs.BaseVirtualFolder) error {
|
||||
return sqlCommonDeleteFolder(folder, p.dbHandle)
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ func initializePGSQLProvider() error {
|
|||
|
||||
func getPGSQLConnectionString(redactedPwd bool) string {
|
||||
var connectionString string
|
||||
if len(config.ConnectionString) == 0 {
|
||||
if config.ConnectionString == "" {
|
||||
password := config.Password
|
||||
if redactedPwd {
|
||||
password = "[redacted]"
|
||||
|
@ -120,15 +120,15 @@ func (p PGSQLProvider) userExists(username string) (User, error) {
|
|||
return sqlCommonCheckUserExists(username, p.dbHandle)
|
||||
}
|
||||
|
||||
func (p PGSQLProvider) addUser(user User) error {
|
||||
func (p PGSQLProvider) addUser(user *User) error {
|
||||
return sqlCommonAddUser(user, p.dbHandle)
|
||||
}
|
||||
|
||||
func (p PGSQLProvider) updateUser(user User) error {
|
||||
func (p PGSQLProvider) updateUser(user *User) error {
|
||||
return sqlCommonUpdateUser(user, p.dbHandle)
|
||||
}
|
||||
|
||||
func (p PGSQLProvider) deleteUser(user User) error {
|
||||
func (p PGSQLProvider) deleteUser(user *User) error {
|
||||
return sqlCommonDeleteUser(user, p.dbHandle)
|
||||
}
|
||||
|
||||
|
@ -154,11 +154,11 @@ func (p PGSQLProvider) getFolderByPath(mappedPath string) (vfs.BaseVirtualFolder
|
|||
return sqlCommonCheckFolderExists(ctx, mappedPath, p.dbHandle)
|
||||
}
|
||||
|
||||
func (p PGSQLProvider) addFolder(folder vfs.BaseVirtualFolder) error {
|
||||
func (p PGSQLProvider) addFolder(folder *vfs.BaseVirtualFolder) error {
|
||||
return sqlCommonAddFolder(folder, p.dbHandle)
|
||||
}
|
||||
|
||||
func (p PGSQLProvider) deleteFolder(folder vfs.BaseVirtualFolder) error {
|
||||
func (p PGSQLProvider) deleteFolder(folder *vfs.BaseVirtualFolder) error {
|
||||
return sqlCommonDeleteFolder(folder, p.dbHandle)
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ func getUserByUsername(username string, dbHandle sqlQuerier) (User, error) {
|
|||
|
||||
func sqlCommonValidateUserAndPass(username, password, ip, protocol string, dbHandle *sql.DB) (User, error) {
|
||||
var user User
|
||||
if len(password) == 0 {
|
||||
if password == "" {
|
||||
return user, errors.New("Credentials cannot be null or empty")
|
||||
}
|
||||
user, err := getUserByUsername(username, dbHandle)
|
||||
|
@ -177,8 +177,8 @@ func sqlCommonCheckUserExists(username string, dbHandle *sql.DB) (User, error) {
|
|||
return getUserWithVirtualFolders(user, dbHandle)
|
||||
}
|
||||
|
||||
func sqlCommonAddUser(user User, dbHandle *sql.DB) error {
|
||||
err := validateUser(&user)
|
||||
func sqlCommonAddUser(user *User, dbHandle *sql.DB) error {
|
||||
err := validateUser(user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -231,8 +231,8 @@ func sqlCommonAddUser(user User, dbHandle *sql.DB) error {
|
|||
return tx.Commit()
|
||||
}
|
||||
|
||||
func sqlCommonUpdateUser(user User, dbHandle *sql.DB) error {
|
||||
err := validateUser(&user)
|
||||
func sqlCommonUpdateUser(user *User, dbHandle *sql.DB) error {
|
||||
err := validateUser(user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -285,7 +285,7 @@ func sqlCommonUpdateUser(user User, dbHandle *sql.DB) error {
|
|||
return tx.Commit()
|
||||
}
|
||||
|
||||
func sqlCommonDeleteUser(user User, dbHandle *sql.DB) error {
|
||||
func sqlCommonDeleteUser(user *User, dbHandle *sql.DB) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultSQLQueryTimeout)
|
||||
defer cancel()
|
||||
q := getDeleteUserQuery()
|
||||
|
@ -470,7 +470,7 @@ func sqlCommonCheckFolderExists(ctx context.Context, name string, dbHandle sqlQu
|
|||
func sqlCommonAddOrGetFolder(ctx context.Context, name string, usedQuotaSize int64, usedQuotaFiles int, lastQuotaUpdate int64, dbHandle sqlQuerier) (vfs.BaseVirtualFolder, error) {
|
||||
folder, err := sqlCommonCheckFolderExists(ctx, name, dbHandle)
|
||||
if _, ok := err.(*RecordNotFoundError); ok {
|
||||
f := vfs.BaseVirtualFolder{
|
||||
f := &vfs.BaseVirtualFolder{
|
||||
MappedPath: name,
|
||||
UsedQuotaSize: usedQuotaSize,
|
||||
UsedQuotaFiles: usedQuotaFiles,
|
||||
|
@ -485,8 +485,8 @@ func sqlCommonAddOrGetFolder(ctx context.Context, name string, usedQuotaSize int
|
|||
return folder, err
|
||||
}
|
||||
|
||||
func sqlCommonAddFolder(folder vfs.BaseVirtualFolder, dbHandle sqlQuerier) error {
|
||||
err := validateFolder(&folder)
|
||||
func sqlCommonAddFolder(folder *vfs.BaseVirtualFolder, dbHandle sqlQuerier) error {
|
||||
err := validateFolder(folder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -503,7 +503,7 @@ func sqlCommonAddFolder(folder vfs.BaseVirtualFolder, dbHandle sqlQuerier) error
|
|||
return err
|
||||
}
|
||||
|
||||
func sqlCommonDeleteFolder(folder vfs.BaseVirtualFolder, dbHandle sqlQuerier) error {
|
||||
func sqlCommonDeleteFolder(folder *vfs.BaseVirtualFolder, dbHandle sqlQuerier) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultSQLQueryTimeout)
|
||||
defer cancel()
|
||||
q := getDeleteFolderQuery()
|
||||
|
@ -585,7 +585,7 @@ func sqlCommonGetFolders(limit, offset int, order, folderPath string, dbHandle s
|
|||
return getVirtualFoldersWithUsers(folders, dbHandle)
|
||||
}
|
||||
|
||||
func sqlCommonClearFolderMapping(ctx context.Context, user User, dbHandle sqlQuerier) error {
|
||||
func sqlCommonClearFolderMapping(ctx context.Context, user *User, dbHandle sqlQuerier) error {
|
||||
q := getClearFolderMappingQuery()
|
||||
stmt, err := dbHandle.PrepareContext(ctx, q)
|
||||
if err != nil {
|
||||
|
@ -597,7 +597,7 @@ func sqlCommonClearFolderMapping(ctx context.Context, user User, dbHandle sqlQue
|
|||
return err
|
||||
}
|
||||
|
||||
func sqlCommonAddFolderMapping(ctx context.Context, user User, folder vfs.VirtualFolder, dbHandle sqlQuerier) error {
|
||||
func sqlCommonAddFolderMapping(ctx context.Context, user *User, folder vfs.VirtualFolder, dbHandle sqlQuerier) error {
|
||||
q := getAddFolderMappingQuery()
|
||||
stmt, err := dbHandle.PrepareContext(ctx, q)
|
||||
if err != nil {
|
||||
|
@ -609,7 +609,7 @@ func sqlCommonAddFolderMapping(ctx context.Context, user User, folder vfs.Virtua
|
|||
return err
|
||||
}
|
||||
|
||||
func generateVirtualFoldersMapping(ctx context.Context, user User, dbHandle sqlQuerier) error {
|
||||
func generateVirtualFoldersMapping(ctx context.Context, user *User, dbHandle sqlQuerier) error {
|
||||
err := sqlCommonClearFolderMapping(ctx, user, dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -813,7 +813,7 @@ func sqlCommonExecSQLAndUpdateDBVersion(dbHandle *sql.DB, sql []string, newVersi
|
|||
return err
|
||||
}
|
||||
for _, q := range sql {
|
||||
if len(strings.TrimSpace(q)) == 0 {
|
||||
if strings.TrimSpace(q) == "" {
|
||||
continue
|
||||
}
|
||||
_, err = tx.ExecContext(ctx, q)
|
||||
|
@ -892,7 +892,7 @@ func sqlCommonRestoreCompatVirtualFolders(ctx context.Context, users []userCompa
|
|||
QuotaSize: quotaSize,
|
||||
QuotaFiles: quotaFiles,
|
||||
}
|
||||
err = sqlCommonAddFolderMapping(ctx, u, f, dbHandle)
|
||||
err = sqlCommonAddFolderMapping(ctx, &u, f, dbHandle)
|
||||
if err != nil {
|
||||
providerLog(logger.LevelWarn, "error adding virtual folder mapping for user %#v: %v", user.Username, err)
|
||||
return foldersToScan, err
|
||||
|
@ -923,7 +923,7 @@ func sqlCommonUpdateDatabaseFrom3To4(sqlV4 string, dbHandle *sql.DB) error {
|
|||
return err
|
||||
}
|
||||
for _, q := range strings.Split(sql, ";") {
|
||||
if len(strings.TrimSpace(q)) == 0 {
|
||||
if strings.TrimSpace(q) == "" {
|
||||
continue
|
||||
}
|
||||
_, err = tx.ExecContext(ctx, q)
|
||||
|
|
|
@ -93,7 +93,7 @@ func initializeSQLiteProvider(basePath string) error {
|
|||
var err error
|
||||
var connectionString string
|
||||
logSender = fmt.Sprintf("dataprovider_%v", SQLiteDataProviderName)
|
||||
if len(config.ConnectionString) == 0 {
|
||||
if config.ConnectionString == "" {
|
||||
dbPath := config.Name
|
||||
if !utils.IsFileInputValid(dbPath) {
|
||||
return fmt.Errorf("Invalid database path: %#v", dbPath)
|
||||
|
@ -149,15 +149,15 @@ func (p SQLiteProvider) userExists(username string) (User, error) {
|
|||
return sqlCommonCheckUserExists(username, p.dbHandle)
|
||||
}
|
||||
|
||||
func (p SQLiteProvider) addUser(user User) error {
|
||||
func (p SQLiteProvider) addUser(user *User) error {
|
||||
return sqlCommonAddUser(user, p.dbHandle)
|
||||
}
|
||||
|
||||
func (p SQLiteProvider) updateUser(user User) error {
|
||||
func (p SQLiteProvider) updateUser(user *User) error {
|
||||
return sqlCommonUpdateUser(user, p.dbHandle)
|
||||
}
|
||||
|
||||
func (p SQLiteProvider) deleteUser(user User) error {
|
||||
func (p SQLiteProvider) deleteUser(user *User) error {
|
||||
return sqlCommonDeleteUser(user, p.dbHandle)
|
||||
}
|
||||
|
||||
|
@ -183,11 +183,11 @@ func (p SQLiteProvider) getFolderByPath(mappedPath string) (vfs.BaseVirtualFolde
|
|||
return sqlCommonCheckFolderExists(ctx, mappedPath, p.dbHandle)
|
||||
}
|
||||
|
||||
func (p SQLiteProvider) addFolder(folder vfs.BaseVirtualFolder) error {
|
||||
func (p SQLiteProvider) addFolder(folder *vfs.BaseVirtualFolder) error {
|
||||
return sqlCommonAddFolder(folder, p.dbHandle)
|
||||
}
|
||||
|
||||
func (p SQLiteProvider) deleteFolder(folder vfs.BaseVirtualFolder) error {
|
||||
func (p SQLiteProvider) deleteFolder(folder *vfs.BaseVirtualFolder) error {
|
||||
return sqlCommonDeleteFolder(folder, p.dbHandle)
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ func addFolder(w http.ResponseWriter, r *http.Request) {
|
|||
sendAPIResponse(w, r, err, "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
err = dataprovider.AddFolder(folder)
|
||||
err = dataprovider.AddFolder(&folder)
|
||||
if err == nil {
|
||||
folder, err = dataprovider.GetFolderByPath(folder.MappedPath)
|
||||
if err == nil {
|
||||
|
@ -81,7 +81,7 @@ func deleteFolderByPath(w http.ResponseWriter, r *http.Request) {
|
|||
if _, ok := r.URL.Query()["folder_path"]; ok {
|
||||
folderPath = r.URL.Query().Get("folder_path")
|
||||
}
|
||||
if len(folderPath) == 0 {
|
||||
if folderPath == "" {
|
||||
err := errors.New("a non-empty folder path is required")
|
||||
sendAPIResponse(w, r, err, "", http.StatusBadRequest)
|
||||
return
|
||||
|
@ -92,7 +92,7 @@ func deleteFolderByPath(w http.ResponseWriter, r *http.Request) {
|
|||
sendAPIResponse(w, r, err, "", getRespStatus(err))
|
||||
return
|
||||
}
|
||||
err = dataprovider.DeleteFolder(folder)
|
||||
err = dataprovider.DeleteFolder(&folder)
|
||||
if err != nil {
|
||||
sendAPIResponse(w, r, err, "", http.StatusInternalServerError)
|
||||
} else {
|
||||
|
|
|
@ -25,7 +25,7 @@ func dumpData(w http.ResponseWriter, r *http.Request) {
|
|||
if _, ok := r.URL.Query()["indent"]; ok {
|
||||
indent = strings.TrimSpace(r.URL.Query().Get("indent"))
|
||||
}
|
||||
if len(outputFile) == 0 {
|
||||
if outputFile == "" {
|
||||
sendAPIResponse(w, r, errors.New("Invalid or missing output_file"), "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
@ -147,8 +147,9 @@ func RestoreFolders(folders []vfs.BaseVirtualFolder, inputFile string, scanQuota
|
|||
logger.Debug(logSender, "", "folder %#v already exists, restore not needed", folder.MappedPath)
|
||||
continue
|
||||
}
|
||||
folder := folder // pin
|
||||
folder.Users = nil
|
||||
err = dataprovider.AddFolder(folder)
|
||||
err = dataprovider.AddFolder(&folder)
|
||||
logger.Debug(logSender, "", "adding new folder: %+v, dump file: %#v, error: %v", folder, inputFile, err)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -166,6 +167,7 @@ func RestoreFolders(folders []vfs.BaseVirtualFolder, inputFile string, scanQuota
|
|||
// RestoreUsers restores the specified users
|
||||
func RestoreUsers(users []dataprovider.User, inputFile string, mode, scanQuota int) error {
|
||||
for _, user := range users {
|
||||
user := user // pin
|
||||
u, err := dataprovider.UserExists(user.Username)
|
||||
if err == nil {
|
||||
if mode == 1 {
|
||||
|
@ -173,14 +175,14 @@ func RestoreUsers(users []dataprovider.User, inputFile string, mode, scanQuota i
|
|||
continue
|
||||
}
|
||||
user.ID = u.ID
|
||||
err = dataprovider.UpdateUser(user)
|
||||
err = dataprovider.UpdateUser(&user)
|
||||
user.Password = "[redacted]"
|
||||
logger.Debug(logSender, "", "restoring existing user: %+v, dump file: %#v, error: %v", user, inputFile, err)
|
||||
if mode == 2 && err == nil {
|
||||
disconnectUser(user.Username)
|
||||
}
|
||||
} else {
|
||||
err = dataprovider.AddUser(user)
|
||||
err = dataprovider.AddUser(&user)
|
||||
user.Password = "[redacted]"
|
||||
logger.Debug(logSender, "", "adding new user: %+v, dump file: %#v, error: %v", user, inputFile, err)
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ func addUser(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
}
|
||||
err = dataprovider.AddUser(user)
|
||||
err = dataprovider.AddUser(&user)
|
||||
if err == nil {
|
||||
user, err = dataprovider.UserExists(user.Username)
|
||||
if err == nil {
|
||||
|
@ -181,7 +181,7 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
|
|||
sendAPIResponse(w, r, err, "user ID in request body does not match user ID in path parameter", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
err = dataprovider.UpdateUser(user)
|
||||
err = dataprovider.UpdateUser(&user)
|
||||
if err != nil {
|
||||
sendAPIResponse(w, r, err, "", getRespStatus(err))
|
||||
} else {
|
||||
|
@ -204,7 +204,7 @@ func deleteUser(w http.ResponseWriter, r *http.Request) {
|
|||
sendAPIResponse(w, r, err, "", getRespStatus(err))
|
||||
return
|
||||
}
|
||||
err = dataprovider.DeleteUser(user)
|
||||
err = dataprovider.DeleteUser(&user)
|
||||
if err != nil {
|
||||
sendAPIResponse(w, r, err, "", http.StatusInternalServerError)
|
||||
} else {
|
||||
|
|
|
@ -129,10 +129,10 @@ func (c Conf) Initialize(configDir string) error {
|
|||
staticFilesPath := getConfigPath(c.StaticFilesPath, configDir)
|
||||
templatesPath := getConfigPath(c.TemplatesPath, configDir)
|
||||
enableWebAdmin := len(staticFilesPath) > 0 || len(templatesPath) > 0
|
||||
if len(backupsPath) == 0 {
|
||||
if backupsPath == "" {
|
||||
return fmt.Errorf("Required directory is invalid, backup path %#v", backupsPath)
|
||||
}
|
||||
if enableWebAdmin && (len(staticFilesPath) == 0 || len(templatesPath) == 0) {
|
||||
if enableWebAdmin && (staticFilesPath == "" || templatesPath == "") {
|
||||
return fmt.Errorf("Required directory is invalid, static file path: %#v template path: %#v",
|
||||
staticFilesPath, templatesPath)
|
||||
}
|
||||
|
|
|
@ -3430,7 +3430,7 @@ func TestRenderWebCloneUserMock(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
user.FsConfig.CryptConfig.Passphrase.SetStatus(kms.SecretStatusAWS)
|
||||
user.Password = defaultPassword
|
||||
err = dataprovider.UpdateUser(user)
|
||||
err = dataprovider.UpdateUser(&user)
|
||||
assert.NoError(t, err)
|
||||
|
||||
req, err = http.NewRequest(http.MethodGet, webUserPath+fmt.Sprintf("?cloneFromId=%v", user.ID), nil)
|
||||
|
|
|
@ -727,7 +727,7 @@ func handleWebAddUserPost(w http.ResponseWriter, r *http.Request) {
|
|||
renderAddUserPage(w, user, err.Error())
|
||||
return
|
||||
}
|
||||
err = dataprovider.AddUser(user)
|
||||
err = dataprovider.AddUser(&user)
|
||||
if err == nil {
|
||||
http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
|
||||
} else {
|
||||
|
@ -764,7 +764,7 @@ func handleWebUpdateUserPost(w http.ResponseWriter, r *http.Request) {
|
|||
user.FsConfig.GCSConfig.Credentials, user.FsConfig.CryptConfig.Passphrase, user.FsConfig.SFTPConfig.Password,
|
||||
user.FsConfig.SFTPConfig.PrivateKey)
|
||||
|
||||
err = dataprovider.UpdateUser(updatedUser)
|
||||
err = dataprovider.UpdateUser(&updatedUser)
|
||||
if err == nil {
|
||||
if len(r.Form.Get("disconnect")) > 0 {
|
||||
disconnectUser(user.Username)
|
||||
|
@ -806,7 +806,7 @@ func handleWebAddFolderPost(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
folder.MappedPath = r.Form.Get("mapped_path")
|
||||
|
||||
err = dataprovider.AddFolder(folder)
|
||||
err = dataprovider.AddFolder(&folder)
|
||||
if err == nil {
|
||||
http.Redirect(w, r, webFoldersPath, http.StatusSeeOther)
|
||||
} else {
|
||||
|
|
3
main.go
3
main.go
|
@ -1,6 +1,5 @@
|
|||
// Fully featured and highly configurable SFTP server with optional
|
||||
// FTP/S and WebDAV support. It can serve local filesystem, S3 or
|
||||
// Google Cloud Storage.
|
||||
// FTP/S and WebDAV support.
|
||||
// For more details about features, installation, configuration and usage
|
||||
// please refer to the README inside the source tree:
|
||||
// https://github.com/drakkan/sftpgo/blob/master/README.md
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/bash
|
||||
|
||||
NFPM_VERSION=2.2.1
|
||||
NFPM_VERSION=2.2.2
|
||||
NFPM_ARCH=${NFPM_ARCH:-amd64}
|
||||
if [ -z ${SFTPGO_VERSION} ]
|
||||
then
|
||||
|
|
|
@ -106,7 +106,7 @@ func (s *Service) Start() error {
|
|||
|
||||
if s.PortableMode == 1 {
|
||||
// create the user for portable mode
|
||||
err = dataprovider.AddUser(s.PortableUser)
|
||||
err = dataprovider.AddUser(&s.PortableUser)
|
||||
if err != nil {
|
||||
logger.ErrorToConsole("error adding portable user: %v", err)
|
||||
return err
|
||||
|
|
|
@ -245,7 +245,7 @@ func (s *Service) configurePortableUser() string {
|
|||
if len(s.PortableUser.Password) > 0 {
|
||||
printablePassword = "[redacted]"
|
||||
}
|
||||
if len(s.PortableUser.PublicKeys) == 0 && len(s.PortableUser.Password) == 0 {
|
||||
if len(s.PortableUser.PublicKeys) == 0 && s.PortableUser.Password == "" {
|
||||
var b strings.Builder
|
||||
for i := 0; i < 8; i++ {
|
||||
b.WriteRune(chars[rand.Intn(len(chars))])
|
||||
|
|
|
@ -668,7 +668,7 @@ func (c *scpCommand) parseUploadMessage(command string) (int64, string, error) {
|
|||
return size, name, err
|
||||
}
|
||||
name = parts[2]
|
||||
if len(name) == 0 {
|
||||
if name == "" {
|
||||
err = fmt.Errorf("error getting name from upload message, cannot be empty")
|
||||
c.connection.Log(logger.LevelWarn, "error: %v", err)
|
||||
c.sendErrorMessage(err)
|
||||
|
|
|
@ -323,7 +323,7 @@ func (c *Configuration) configureLoginBanner(serverConfig *ssh.ServerConfig, con
|
|||
}
|
||||
|
||||
func (c *Configuration) configureKeyboardInteractiveAuth(serverConfig *ssh.ServerConfig) {
|
||||
if len(c.KeyboardInteractiveHook) == 0 {
|
||||
if c.KeyboardInteractiveHook == "" {
|
||||
return
|
||||
}
|
||||
if !strings.HasPrefix(c.KeyboardInteractiveHook, "http") {
|
||||
|
|
|
@ -537,7 +537,7 @@ func (c *sshCommand) getCopyPaths() (string, string, error) {
|
|||
if strings.HasSuffix(sshDestPath, "/") {
|
||||
sshDestPath = path.Join(sshDestPath, path.Base(sshSourcePath))
|
||||
}
|
||||
if len(sshSourcePath) == 0 || len(sshDestPath) == 0 || len(c.args) != 2 {
|
||||
if sshSourcePath == "" || sshDestPath == "" || len(c.args) != 2 {
|
||||
err := errors.New("usage sftpgo-copy <source dir path> <destination dir path>")
|
||||
return "", "", err
|
||||
}
|
||||
|
@ -606,7 +606,7 @@ func (c *sshCommand) checkCopyPermissions(fsSourcePath, fsDestPath, sshSourcePat
|
|||
|
||||
func (c *sshCommand) getRemovePath() (string, error) {
|
||||
sshDestPath := c.getDestPath()
|
||||
if len(sshDestPath) == 0 || len(c.args) != 1 {
|
||||
if sshDestPath == "" || len(c.args) != 1 {
|
||||
err := errors.New("usage sftpgo-remove <destination path>")
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -896,7 +896,7 @@ func TestBasicUsersCache(t *testing.T) {
|
|||
}
|
||||
u.Permissions = make(map[string][]string)
|
||||
u.Permissions["/"] = []string{dataprovider.PermAny}
|
||||
err := dataprovider.AddUser(u)
|
||||
err := dataprovider.AddUser(&u)
|
||||
assert.NoError(t, err)
|
||||
user, err := dataprovider.UserExists(u.Username)
|
||||
assert.NoError(t, err)
|
||||
|
@ -969,7 +969,7 @@ func TestBasicUsersCache(t *testing.T) {
|
|||
assert.False(t, cachedUser.IsExpired())
|
||||
}
|
||||
// cache is invalidated after a user modification
|
||||
err = dataprovider.UpdateUser(user)
|
||||
err = dataprovider.UpdateUser(&user)
|
||||
assert.NoError(t, err)
|
||||
_, ok = dataprovider.GetCachedWebDAVUser(username)
|
||||
assert.False(t, ok)
|
||||
|
@ -980,7 +980,7 @@ func TestBasicUsersCache(t *testing.T) {
|
|||
_, ok = dataprovider.GetCachedWebDAVUser(username)
|
||||
assert.True(t, ok)
|
||||
// cache is invalidated after user deletion
|
||||
err = dataprovider.DeleteUser(user)
|
||||
err = dataprovider.DeleteUser(&user)
|
||||
assert.NoError(t, err)
|
||||
_, ok = dataprovider.GetCachedWebDAVUser(username)
|
||||
assert.False(t, ok)
|
||||
|
@ -1001,25 +1001,25 @@ func TestUsersCacheSizeAndExpiration(t *testing.T) {
|
|||
u.Password = password + "1"
|
||||
u.Permissions = make(map[string][]string)
|
||||
u.Permissions["/"] = []string{dataprovider.PermAny}
|
||||
err := dataprovider.AddUser(u)
|
||||
err := dataprovider.AddUser(&u)
|
||||
assert.NoError(t, err)
|
||||
user1, err := dataprovider.UserExists(u.Username)
|
||||
assert.NoError(t, err)
|
||||
u.Username = username + "2"
|
||||
u.Password = password + "2"
|
||||
err = dataprovider.AddUser(u)
|
||||
err = dataprovider.AddUser(&u)
|
||||
assert.NoError(t, err)
|
||||
user2, err := dataprovider.UserExists(u.Username)
|
||||
assert.NoError(t, err)
|
||||
u.Username = username + "3"
|
||||
u.Password = password + "3"
|
||||
err = dataprovider.AddUser(u)
|
||||
err = dataprovider.AddUser(&u)
|
||||
assert.NoError(t, err)
|
||||
user3, err := dataprovider.UserExists(u.Username)
|
||||
assert.NoError(t, err)
|
||||
u.Username = username + "4"
|
||||
u.Password = password + "4"
|
||||
err = dataprovider.AddUser(u)
|
||||
err = dataprovider.AddUser(&u)
|
||||
assert.NoError(t, err)
|
||||
user4, err := dataprovider.UserExists(u.Username)
|
||||
assert.NoError(t, err)
|
||||
|
@ -1137,7 +1137,7 @@ func TestUsersCacheSizeAndExpiration(t *testing.T) {
|
|||
assert.True(t, ok)
|
||||
|
||||
// now remove user1 after an update
|
||||
err = dataprovider.UpdateUser(user1)
|
||||
err = dataprovider.UpdateUser(&user1)
|
||||
assert.NoError(t, err)
|
||||
_, ok = dataprovider.GetCachedWebDAVUser(user1.Username)
|
||||
assert.False(t, ok)
|
||||
|
@ -1164,13 +1164,13 @@ func TestUsersCacheSizeAndExpiration(t *testing.T) {
|
|||
_, ok = dataprovider.GetCachedWebDAVUser(user4.Username)
|
||||
assert.True(t, ok)
|
||||
|
||||
err = dataprovider.DeleteUser(user1)
|
||||
err = dataprovider.DeleteUser(&user1)
|
||||
assert.NoError(t, err)
|
||||
err = dataprovider.DeleteUser(user2)
|
||||
err = dataprovider.DeleteUser(&user2)
|
||||
assert.NoError(t, err)
|
||||
err = dataprovider.DeleteUser(user3)
|
||||
err = dataprovider.DeleteUser(&user3)
|
||||
assert.NoError(t, err)
|
||||
err = dataprovider.DeleteUser(user4)
|
||||
err = dataprovider.DeleteUser(&user4)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = os.RemoveAll(u.GetHomeDir())
|
||||
|
|
|
@ -207,7 +207,7 @@ func (s *webDavServer) authenticate(r *http.Request, ip string) (dataprovider.Us
|
|||
if cachedUser.IsExpired() {
|
||||
dataprovider.RemoveCachedWebDAVUser(username)
|
||||
} else {
|
||||
if len(password) > 0 && cachedUser.Password == password {
|
||||
if password != "" && cachedUser.Password == password {
|
||||
return cachedUser.User, true, cachedUser.LockSystem, nil
|
||||
}
|
||||
updateLoginMetrics(username, ip, dataprovider.ErrInvalidCredentials)
|
||||
|
|
Loading…
Reference in a new issue