allow to store temporary sessions within the data provider

so we can persist password reset codes, OIDC auth sessions and tokens.
These features will also work in multi-node setups without sicky
sessions now

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
Nicola Murino
2022-05-19 19:49:51 +02:00
parent a87aa9b98e
commit 796ea1dde9
68 changed files with 1501 additions and 730 deletions
+2 -2
View File
@@ -49,8 +49,8 @@ func executeAction(operation, executor, ip, objectType, objectName string, objec
if config.Actions.Hook == "" {
return
}
if !util.IsStringInSlice(operation, config.Actions.ExecuteOn) ||
!util.IsStringInSlice(objectType, config.Actions.ExecuteFor) {
if !util.Contains(config.Actions.ExecuteOn, operation) ||
!util.Contains(config.Actions.ExecuteFor, objectType) {
return
}
+5 -5
View File
@@ -68,7 +68,7 @@ func (c *AdminTOTPConfig) validate(username string) error {
if c.ConfigName == "" {
return util.NewValidationError("totp: config name is mandatory")
}
if !util.IsStringInSlice(c.ConfigName, mfa.GetAvailableTOTPConfigNames()) {
if !util.Contains(mfa.GetAvailableTOTPConfigNames(), c.ConfigName) {
return util.NewValidationError(fmt.Sprintf("totp: config name %#v not found", c.ConfigName))
}
if c.Secret.IsEmpty() {
@@ -182,11 +182,11 @@ func (a *Admin) validatePermissions() error {
if len(a.Permissions) == 0 {
return util.NewValidationError("please grant some permissions to this admin")
}
if util.IsStringInSlice(PermAdminAny, a.Permissions) {
if util.Contains(a.Permissions, PermAdminAny) {
a.Permissions = []string{PermAdminAny}
}
for _, perm := range a.Permissions {
if !util.IsStringInSlice(perm, validAdminPerms) {
if !util.Contains(validAdminPerms, perm) {
return util.NewValidationError(fmt.Sprintf("invalid permission: %#v", perm))
}
}
@@ -345,10 +345,10 @@ func (a *Admin) SetNilSecretsIfEmpty() {
// HasPermission returns true if the admin has the specified permission
func (a *Admin) HasPermission(perm string) bool {
if util.IsStringInSlice(PermAdminAny, a.Permissions) {
if util.Contains(a.Permissions, PermAdminAny) {
return true
}
return util.IsStringInSlice(perm, a.Permissions)
return util.Contains(a.Permissions, perm)
}
// GetPermissionsAsString returns permission as string
+28 -12
View File
@@ -20,7 +20,7 @@ import (
)
const (
boltDatabaseVersion = 18
boltDatabaseVersion = 19
)
var (
@@ -1916,6 +1916,22 @@ func (p *BoltProvider) getActiveTransfers(from time.Time) ([]ActiveTransfer, err
return nil, ErrNotImplemented
}
func (p *BoltProvider) addSharedSession(session Session) error {
return ErrNotImplemented
}
func (p *BoltProvider) deleteSharedSession(key string) error {
return ErrNotImplemented
}
func (p *BoltProvider) getSharedSession(key string) (Session, error) {
return Session{}, ErrNotImplemented
}
func (p *BoltProvider) cleanupSharedSessions(sessionType SessionType, before int64) error {
return ErrNotImplemented
}
func (p *BoltProvider) close() error {
return p.dbHandle.Close()
}
@@ -1943,13 +1959,13 @@ func (p *BoltProvider) migrateDatabase() error {
providerLog(logger.LevelError, "%v", err)
logger.ErrorToConsole("%v", err)
return err
case version == 15, version == 16, version == 17:
logger.InfoToConsole(fmt.Sprintf("updating database version: %v -> 18", version))
providerLog(logger.LevelInfo, "updating database version: %v -> 18", version)
case version == 15, version == 16, version == 17, version == 18:
logger.InfoToConsole(fmt.Sprintf("updating database version: %v -> 19", version))
providerLog(logger.LevelInfo, "updating database version: %v -> 19", version)
if err = importGCSCredentials(); err != nil {
return err
}
return updateBoltDatabaseVersion(p.dbHandle, 18)
return updateBoltDatabaseVersion(p.dbHandle, 19)
default:
if version > boltDatabaseVersion {
providerLog(logger.LevelError, "database version %v is newer than the supported one: %v", version,
@@ -1971,7 +1987,7 @@ func (p *BoltProvider) revertDatabase(targetVersion int) error {
return errors.New("current version match target version, nothing to do")
}
switch dbVersion.Version {
case 16, 17, 18:
case 16, 17, 18, 19:
return updateBoltDatabaseVersion(p.dbHandle, 15)
default:
return fmt.Errorf("database version not handled: %v", dbVersion.Version)
@@ -2081,7 +2097,7 @@ func (p *BoltProvider) addUserToGroupMapping(username, groupname string, bucket
if err != nil {
return err
}
if !util.IsStringInSlice(username, group.Users) {
if !util.Contains(group.Users, username) {
group.Users = append(group.Users, username)
buf, err := json.Marshal(group)
if err != nil {
@@ -2102,7 +2118,7 @@ func (p *BoltProvider) removeUserFromGroupMapping(username, groupname string, bu
if err != nil {
return err
}
if util.IsStringInSlice(username, group.Users) {
if util.Contains(group.Users, username) {
var users []string
for _, u := range group.Users {
if u != username {
@@ -2145,10 +2161,10 @@ func (p *BoltProvider) addRelationToFolderMapping(baseFolder *vfs.BaseVirtualFol
baseFolder.UsedQuotaSize = oldFolder.UsedQuotaSize
baseFolder.Users = oldFolder.Users
baseFolder.Groups = oldFolder.Groups
if user != nil && !util.IsStringInSlice(user.Username, baseFolder.Users) {
if user != nil && !util.Contains(baseFolder.Users, user.Username) {
baseFolder.Users = append(baseFolder.Users, user.Username)
}
if group != nil && !util.IsStringInSlice(group.Name, baseFolder.Groups) {
if group != nil && !util.Contains(baseFolder.Groups, group.Name) {
baseFolder.Groups = append(baseFolder.Groups, group.Name)
}
buf, err := json.Marshal(baseFolder)
@@ -2172,7 +2188,7 @@ func (p *BoltProvider) removeRelationFromFolderMapping(folder vfs.VirtualFolder,
return err
}
found := false
if username != "" && util.IsStringInSlice(username, baseFolder.Users) {
if username != "" && util.Contains(baseFolder.Users, username) {
found = true
var newUserMapping []string
for _, u := range baseFolder.Users {
@@ -2182,7 +2198,7 @@ func (p *BoltProvider) removeRelationFromFolderMapping(folder vfs.VirtualFolder,
}
baseFolder.Users = newUserMapping
}
if groupname != "" && util.IsStringInSlice(groupname, baseFolder.Groups) {
if groupname != "" && util.Contains(baseFolder.Groups, groupname) {
found = true
var newGroupMapping []string
for _, g := range baseFolder.Groups {
+62 -21
View File
@@ -167,6 +167,7 @@ var (
sqlTableGroups = "groups"
sqlTableUsersGroupsMapping = "users_groups_mapping"
sqlTableGroupsFoldersMapping = "groups_folders_mapping"
sqlTableSharedSessions = "shared_sessions"
sqlTableSchemaVersion = "schema_version"
argon2Params *argon2id.Params
lastLoginMinDelay = 10 * time.Minute
@@ -409,7 +410,7 @@ type Config struct {
// GetShared returns the provider share mode
func (c *Config) GetShared() int {
if !util.IsStringInSlice(c.Driver, sharedProviders) {
if !util.Contains(sharedProviders, c.Driver) {
return 0
}
return c.IsShared
@@ -686,6 +687,10 @@ type Provider interface {
removeActiveTransfer(transferID int64, connectionID string) error
cleanupActiveTransfers(before time.Time) error
getActiveTransfers(from time.Time) ([]ActiveTransfer, error)
addSharedSession(session Session) error
deleteSharedSession(key string) error
getSharedSession(key string) (Session, error)
cleanupSharedSessions(sessionType SessionType, before int64) error
checkAvailability() error
close() error
reloadConfig() error
@@ -1138,7 +1143,7 @@ func CheckKeyboardInteractiveAuth(username, authHook string, client ssh.Keyboard
// after a successful authentication with an external identity provider.
// If a pre-login hook is defined it will be executed so the SFTPGo user
// can be created if it does not exist
func GetUserAfterIDPAuth(username, ip, protocol string, oidcTokenFields *map[string]interface{}) (User, error) {
func GetUserAfterIDPAuth(username, ip, protocol string, oidcTokenFields *map[string]any) (User, error) {
var user User
var err error
if config.PreLoginHook != "" {
@@ -1643,6 +1648,42 @@ func GetActiveTransfers(from time.Time) ([]ActiveTransfer, error) {
return provider.getActiveTransfers(from)
}
// AddSharedSession stores a new session within the data provider
func AddSharedSession(session Session) error {
err := provider.addSharedSession(session)
if err != nil {
providerLog(logger.LevelError, "unable to add shared session, key %#v, type: %v, err: %v",
session.Key, session.Type, err)
}
return err
}
// DeleteSharedSession deletes the session with the specified key
func DeleteSharedSession(key string) error {
err := provider.deleteSharedSession(key)
if err != nil {
providerLog(logger.LevelError, "unable to add shared session, key %#v, err: %v", key, err)
}
return err
}
// GetSharedSession retrieves the session with the specified key
func GetSharedSession(key string) (Session, error) {
return provider.getSharedSession(key)
}
// CleanupSharedSessions removes the shared session with the specified type and
// before the specified time
func CleanupSharedSessions(sessionType SessionType, before time.Time) error {
err := provider.cleanupSharedSessions(sessionType, util.GetTimeAsMsSinceEpoch(before))
if err == nil {
providerLog(logger.LevelDebug, "deleted shared sessions before: %v, type: %v", before, sessionType)
} else {
providerLog(logger.LevelError, "error deleting shared session before %v, type %v: %v", before, sessionType, err)
}
return err
}
// ReloadConfig reloads provider configuration.
// Currently only implemented for memory provider, allows to reload the users
// from the configured file, if defined
@@ -2047,7 +2088,7 @@ func validateUserTOTPConfig(c *UserTOTPConfig, username string) error {
if c.ConfigName == "" {
return util.NewValidationError("totp: config name is mandatory")
}
if !util.IsStringInSlice(c.ConfigName, mfa.GetAvailableTOTPConfigNames()) {
if !util.Contains(mfa.GetAvailableTOTPConfigNames(), c.ConfigName) {
return util.NewValidationError(fmt.Sprintf("totp: config name %#v not found", c.ConfigName))
}
if c.Secret.IsEmpty() {
@@ -2063,7 +2104,7 @@ func validateUserTOTPConfig(c *UserTOTPConfig, username string) error {
return util.NewValidationError("totp: specify at least one protocol")
}
for _, protocol := range c.Protocols {
if !util.IsStringInSlice(protocol, MFAProtocols) {
if !util.Contains(MFAProtocols, protocol) {
return util.NewValidationError(fmt.Sprintf("totp: invalid protocol %#v", protocol))
}
}
@@ -2096,7 +2137,7 @@ func validateUserPermissions(permsToCheck map[string][]string) (map[string][]str
return permissions, util.NewValidationError("invalid permissions")
}
for _, p := range perms {
if !util.IsStringInSlice(p, ValidPerms) {
if !util.Contains(ValidPerms, p) {
return permissions, util.NewValidationError(fmt.Sprintf("invalid permission: %#v", p))
}
}
@@ -2110,7 +2151,7 @@ func validateUserPermissions(permsToCheck map[string][]string) (map[string][]str
if dir != cleanedDir && cleanedDir == "/" {
return permissions, util.NewValidationError(fmt.Sprintf("cannot set permissions for invalid subdirectory: %#v is an alias for \"/\"", dir))
}
if util.IsStringInSlice(PermAny, perms) {
if util.Contains(perms, PermAny) {
permissions[cleanedDir] = []string{PermAny}
} else {
permissions[cleanedDir] = util.RemoveDuplicates(perms)
@@ -2166,7 +2207,7 @@ func validateFiltersPatternExtensions(baseFilters *sdk.BaseUserFilters) error {
if !path.IsAbs(cleanedPath) {
return util.NewValidationError(fmt.Sprintf("invalid path %#v for file patterns filter", f.Path))
}
if util.IsStringInSlice(cleanedPath, filteredPaths) {
if util.Contains(filteredPaths, cleanedPath) {
return util.NewValidationError(fmt.Sprintf("duplicate file patterns filter for path %#v", f.Path))
}
if len(f.AllowedPatterns) == 0 && len(f.DeniedPatterns) == 0 {
@@ -2296,13 +2337,13 @@ func validateFilterProtocols(filters *sdk.BaseUserFilters) error {
return util.NewValidationError("invalid denied_protocols")
}
for _, p := range filters.DeniedProtocols {
if !util.IsStringInSlice(p, ValidProtocols) {
if !util.Contains(ValidProtocols, p) {
return util.NewValidationError(fmt.Sprintf("invalid denied protocol %#v", p))
}
}
for _, p := range filters.TwoFactorAuthProtocols {
if !util.IsStringInSlice(p, MFAProtocols) {
if !util.Contains(MFAProtocols, p) {
return util.NewValidationError(fmt.Sprintf("invalid two factor protocol %#v", p))
}
}
@@ -2324,7 +2365,7 @@ func validateBaseFilters(filters *sdk.BaseUserFilters) error {
return util.NewValidationError("invalid denied_login_methods")
}
for _, loginMethod := range filters.DeniedLoginMethods {
if !util.IsStringInSlice(loginMethod, ValidLoginMethods) {
if !util.Contains(ValidLoginMethods, loginMethod) {
return util.NewValidationError(fmt.Sprintf("invalid login method: %#v", loginMethod))
}
}
@@ -2332,12 +2373,12 @@ func validateBaseFilters(filters *sdk.BaseUserFilters) error {
return err
}
if filters.TLSUsername != "" {
if !util.IsStringInSlice(string(filters.TLSUsername), validTLSUsernames) {
if !util.Contains(validTLSUsernames, string(filters.TLSUsername)) {
return util.NewValidationError(fmt.Sprintf("invalid TLS username: %#v", filters.TLSUsername))
}
}
for _, opts := range filters.WebClient {
if !util.IsStringInSlice(opts, sdk.WebClientOptions) {
if !util.Contains(sdk.WebClientOptions, opts) {
return util.NewValidationError(fmt.Sprintf("invalid web client options %#v", opts))
}
}
@@ -2481,7 +2522,7 @@ func ValidateUser(user *User) error {
if !user.HasExternalAuth() {
user.Filters.ExternalAuthCacheTime = 0
}
if user.Filters.TOTPConfig.Enabled && util.IsStringInSlice(sdk.WebClientMFADisabled, user.Filters.WebClient) {
if user.Filters.TOTPConfig.Enabled && util.Contains(user.Filters.WebClient, sdk.WebClientMFADisabled) {
return util.NewValidationError("two-factor authentication cannot be disabled for a user with an active configuration")
}
return nil
@@ -2622,7 +2663,7 @@ func checkUserPasscode(user *User, password, protocol string) (string, error) {
if user.Filters.TOTPConfig.Enabled {
switch protocol {
case protocolFTP:
if util.IsStringInSlice(protocol, user.Filters.TOTPConfig.Protocols) {
if util.Contains(user.Filters.TOTPConfig.Protocols, protocol) {
// the TOTP passcode has six digits
pwdLen := len(password)
if pwdLen < 7 {
@@ -2810,7 +2851,7 @@ func doBuiltinKeyboardInteractiveAuth(user *User, client ssh.KeyboardInteractive
if err != nil {
return 0, err
}
if !user.Filters.TOTPConfig.Enabled || !util.IsStringInSlice(protocolSSH, user.Filters.TOTPConfig.Protocols) {
if !user.Filters.TOTPConfig.Enabled || !util.Contains(user.Filters.TOTPConfig.Protocols, protocolSSH) {
return 1, nil
}
err = user.Filters.TOTPConfig.Secret.TryDecrypt()
@@ -2934,7 +2975,7 @@ func getKeyboardInteractiveAnswers(client ssh.KeyboardInteractiveChallenge, resp
}
if len(answers) == 1 && response.CheckPwd > 0 {
if response.CheckPwd == 2 {
if !user.Filters.TOTPConfig.Enabled || !util.IsStringInSlice(protocolSSH, user.Filters.TOTPConfig.Protocols) {
if !user.Filters.TOTPConfig.Enabled || !util.Contains(user.Filters.TOTPConfig.Protocols, protocolSSH) {
providerLog(logger.LevelInfo, "keyboard interactive auth error: unable to check TOTP passcode, TOTP is not enabled for user %#v",
user.Username)
return answers, errors.New("TOTP not enabled for SSH protocol")
@@ -3190,7 +3231,7 @@ func getPreLoginHookResponse(loginMethod, ip, protocol string, userAsJSON []byte
return cmd.Output()
}
func executePreLoginHook(username, loginMethod, ip, protocol string, oidcTokenFields *map[string]interface{}) (User, error) {
func executePreLoginHook(username, loginMethod, ip, protocol string, oidcTokenFields *map[string]any) (User, error) {
u, mergedUser, userAsJSON, err := getUserAndJSONForHook(username, oidcTokenFields)
if err != nil {
return u, err
@@ -3340,7 +3381,7 @@ func getExternalAuthResponse(username, password, pkey, keyboardInteractive, ip,
}
if strings.HasPrefix(config.ExternalAuthHook, "http") {
var result []byte
authRequest := make(map[string]interface{})
authRequest := make(map[string]any)
authRequest["username"] = username
authRequest["ip"] = ip
authRequest["password"] = password
@@ -3552,7 +3593,7 @@ func doPluginAuth(username, password string, pubKey []byte, ip, protocol string,
return provider.userExists(user.Username)
}
func getUserForHook(username string, oidcTokenFields *map[string]interface{}) (User, User, error) {
func getUserForHook(username string, oidcTokenFields *map[string]any) (User, User, error) {
u, err := provider.userExists(username)
if err != nil {
if _, ok := err.(*util.RecordNotFoundError); !ok {
@@ -3575,7 +3616,7 @@ func getUserForHook(username string, oidcTokenFields *map[string]interface{}) (U
return u, mergedUser, err
}
func getUserAndJSONForHook(username string, oidcTokenFields *map[string]interface{}) (User, User, []byte, error) {
func getUserAndJSONForHook(username string, oidcTokenFields *map[string]any) (User, User, []byte, error) {
u, mergedUser, err := getUserForHook(username, oidcTokenFields)
if err != nil {
return u, mergedUser, nil, err
@@ -3689,6 +3730,6 @@ func getConfigPath(name, configDir string) string {
return name
}
func providerLog(level logger.LogLevel, format string, v ...interface{}) {
func providerLog(level logger.LogLevel, format string, v ...any) {
logger.Log(level, logSender, "", format, v...)
}
+21 -5
View File
@@ -988,7 +988,7 @@ func (p *MemoryProvider) addUserFromGroupMapping(username, groupname string) err
if err != nil {
return err
}
if !util.IsStringInSlice(username, g.Users) {
if !util.Contains(g.Users, username) {
g.Users = append(g.Users, username)
p.dbHandle.groups[groupname] = g
}
@@ -1000,7 +1000,7 @@ func (p *MemoryProvider) removeUserFromGroupMapping(username, groupname string)
if err != nil {
return err
}
if util.IsStringInSlice(username, g.Users) {
if util.Contains(g.Users, username) {
var users []string
for _, u := range g.Users {
if u != username {
@@ -1069,7 +1069,7 @@ func (p *MemoryProvider) removeRelationFromFolderMapping(folderName, username, g
func (p *MemoryProvider) updateFoldersMappingInternal(folder vfs.BaseVirtualFolder) {
p.dbHandle.vfolders[folder.Name] = folder
if !util.IsStringInSlice(folder.Name, p.dbHandle.vfoldersNames) {
if !util.Contains(p.dbHandle.vfoldersNames, folder.Name) {
p.dbHandle.vfoldersNames = append(p.dbHandle.vfoldersNames, folder.Name)
sort.Strings(p.dbHandle.vfoldersNames)
}
@@ -1084,10 +1084,10 @@ func (p *MemoryProvider) addOrUpdateFolderInternal(baseFolder *vfs.BaseVirtualFo
folder.MappedPath = baseFolder.MappedPath
folder.Description = baseFolder.Description
folder.FsConfig = baseFolder.FsConfig.GetACopy()
if username != "" && !util.IsStringInSlice(username, folder.Users) {
if username != "" && !util.Contains(folder.Users, username) {
folder.Users = append(folder.Users, username)
}
if groupname != "" && !util.IsStringInSlice(groupname, folder.Groups) {
if groupname != "" && !util.Contains(folder.Groups, groupname) {
folder.Groups = append(folder.Groups, groupname)
}
p.updateFoldersMappingInternal(folder)
@@ -1752,6 +1752,22 @@ func (p *MemoryProvider) getActiveTransfers(from time.Time) ([]ActiveTransfer, e
return nil, ErrNotImplemented
}
func (p *MemoryProvider) addSharedSession(session Session) error {
return ErrNotImplemented
}
func (p *MemoryProvider) deleteSharedSession(key string) error {
return ErrNotImplemented
}
func (p *MemoryProvider) getSharedSession(key string) (Session, error) {
return Session{}, ErrNotImplemented
}
func (p *MemoryProvider) cleanupSharedSessions(sessionType SessionType, before int64) error {
return ErrNotImplemented
}
func (p *MemoryProvider) getNextID() int64 {
nextID := int64(1)
for _, v := range p.dbHandle.users {
+65 -10
View File
@@ -35,6 +35,7 @@ const (
"DROP TABLE IF EXISTS `{{defender_events}}` CASCADE;" +
"DROP TABLE IF EXISTS `{{defender_hosts}}` CASCADE;" +
"DROP TABLE IF EXISTS `{{active_transfers}}` CASCADE;" +
"DROP TABLE IF EXISTS `{{shared_sessions}}` CASCADE;" +
"DROP TABLE IF EXISTS `{{schema_version}}` CASCADE;"
mysqlInitialSQL = "CREATE TABLE `{{schema_version}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `version` integer NOT NULL);" +
"CREATE TABLE `{{admins}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `username` varchar(255) NOT NULL UNIQUE, " +
@@ -152,6 +153,11 @@ const (
"FOREIGN KEY (`user_id`) REFERENCES `{{users}}` (`id`) ON DELETE CASCADE;" +
"ALTER TABLE `{{folders_mapping}}` ADD CONSTRAINT `{{prefix}}folders_mapping_folder_id_fk_folders_id` " +
"FOREIGN KEY (`folder_id`) REFERENCES `{{folders}}` (`id`) ON DELETE CASCADE;"
mysqlV19SQL = "CREATE TABLE `{{shared_sessions}}` (`key` varchar(128) NOT NULL PRIMARY KEY, " +
"`data` longtext NOT NULL, `type` integer NOT NULL, `timestamp` bigint NOT NULL);" +
"CREATE INDEX `{{prefix}}shared_sessions_type_idx` ON `{{shared_sessions}}` (`type`);" +
"CREATE INDEX `{{prefix}}shared_sessions_timestamp_idx` ON `{{shared_sessions}}` (`timestamp`);"
mysqlV19DownSQL = "DROP TABLE `{{shared_sessions}}` CASCADE;"
)
// MySQLProvider defines the auth provider for MySQL/MariaDB database
@@ -520,6 +526,22 @@ func (p *MySQLProvider) getActiveTransfers(from time.Time) ([]ActiveTransfer, er
return sqlCommonGetActiveTransfers(from, p.dbHandle)
}
func (p *MySQLProvider) addSharedSession(session Session) error {
return sqlCommonAddSession(session, p.dbHandle)
}
func (p *MySQLProvider) deleteSharedSession(key string) error {
return sqlCommonDeleteSession(key, p.dbHandle)
}
func (p *MySQLProvider) getSharedSession(key string) (Session, error) {
return sqlCommonGetSession(key, p.dbHandle)
}
func (p *MySQLProvider) cleanupSharedSessions(sessionType SessionType, before int64) error {
return sqlCommonCleanupSessions(sessionType, before, p.dbHandle)
}
func (p *MySQLProvider) close() error {
return p.dbHandle.Close()
}
@@ -550,10 +572,10 @@ func (p *MySQLProvider) initializeDatabase() error {
initialSQL = strings.ReplaceAll(initialSQL, "{{defender_hosts}}", sqlTableDefenderHosts)
initialSQL = strings.ReplaceAll(initialSQL, "{{prefix}}", config.SQLTablesPrefix)
return sqlCommonExecSQLAndUpdateDBVersion(p.dbHandle, strings.Split(initialSQL, ";"), 15)
return sqlCommonExecSQLAndUpdateDBVersion(p.dbHandle, strings.Split(initialSQL, ";"), 15, true)
}
func (p *MySQLProvider) migrateDatabase() error {
func (p *MySQLProvider) migrateDatabase() error { //nolint:dupl
dbVersion, err := sqlCommonGetDatabaseVersion(p.dbHandle, true)
if err != nil {
return err
@@ -574,6 +596,8 @@ func (p *MySQLProvider) migrateDatabase() error {
return updateMySQLDatabaseFromV16(p.dbHandle)
case version == 17:
return updateMySQLDatabaseFromV17(p.dbHandle)
case version == 18:
return updateMySQLDatabaseFromV18(p.dbHandle)
default:
if version > sqlDatabaseVersion {
providerLog(logger.LevelError, "database version %v is newer than the supported one: %v", version,
@@ -602,6 +626,8 @@ func (p *MySQLProvider) revertDatabase(targetVersion int) error {
return downgradeMySQLDatabaseFromV17(p.dbHandle)
case 18:
return downgradeMySQLDatabaseFromV18(p.dbHandle)
case 19:
return downgradeMySQLDatabaseFromV19(p.dbHandle)
default:
return fmt.Errorf("database version not handled: %v", dbVersion.Version)
}
@@ -609,7 +635,7 @@ func (p *MySQLProvider) revertDatabase(targetVersion int) error {
func (p *MySQLProvider) resetDatabase() error {
sql := sqlReplaceAll(mysqlResetSQL)
return sqlCommonExecSQLAndUpdateDBVersion(p.dbHandle, strings.Split(sql, ";"), 0)
return sqlCommonExecSQLAndUpdateDBVersion(p.dbHandle, strings.Split(sql, ";"), 0, false)
}
func updateMySQLDatabaseFromV15(dbHandle *sql.DB) error {
@@ -627,7 +653,14 @@ func updateMySQLDatabaseFromV16(dbHandle *sql.DB) error {
}
func updateMySQLDatabaseFromV17(dbHandle *sql.DB) error {
return updateMySQLDatabaseFrom17To18(dbHandle)
if err := updateMySQLDatabaseFrom17To18(dbHandle); err != nil {
return err
}
return updateMySQLDatabaseFromV18(dbHandle)
}
func updateMySQLDatabaseFromV18(dbHandle *sql.DB) error {
return updateMySQLDatabaseFrom18To19(dbHandle)
}
func downgradeMySQLDatabaseFromV16(dbHandle *sql.DB) error {
@@ -648,13 +681,20 @@ func downgradeMySQLDatabaseFromV18(dbHandle *sql.DB) error {
return downgradeMySQLDatabaseFromV17(dbHandle)
}
func downgradeMySQLDatabaseFromV19(dbHandle *sql.DB) error {
if err := downgradeMySQLDatabaseFrom19To18(dbHandle); err != nil {
return err
}
return downgradeMySQLDatabaseFromV18(dbHandle)
}
func updateMySQLDatabaseFrom15To16(dbHandle *sql.DB) error {
logger.InfoToConsole("updating database version: 15 -> 16")
providerLog(logger.LevelInfo, "updating database version: 15 -> 16")
sql := strings.ReplaceAll(mysqlV16SQL, "{{users}}", sqlTableUsers)
sql = strings.ReplaceAll(sql, "{{active_transfers}}", sqlTableActiveTransfers)
sql = strings.ReplaceAll(sql, "{{prefix}}", config.SQLTablesPrefix)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, strings.Split(sql, ";"), 16)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, strings.Split(sql, ";"), 16, true)
}
func updateMySQLDatabaseFrom16To17(dbHandle *sql.DB) error {
@@ -668,7 +708,7 @@ func updateMySQLDatabaseFrom16To17(dbHandle *sql.DB) error {
sql = strings.ReplaceAll(sql, "{{users_groups_mapping}}", sqlTableUsersGroupsMapping)
sql = strings.ReplaceAll(sql, "{{groups_folders_mapping}}", sqlTableGroupsFoldersMapping)
sql = strings.ReplaceAll(sql, "{{prefix}}", config.SQLTablesPrefix)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, strings.Split(sql, ";"), 17)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, strings.Split(sql, ";"), 17, true)
}
func updateMySQLDatabaseFrom17To18(dbHandle *sql.DB) error {
@@ -677,7 +717,15 @@ func updateMySQLDatabaseFrom17To18(dbHandle *sql.DB) error {
if err := importGCSCredentials(); err != nil {
return err
}
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, nil, 18)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, nil, 18, true)
}
func updateMySQLDatabaseFrom18To19(dbHandle *sql.DB) error {
logger.InfoToConsole("updating database version: 18 -> 19")
providerLog(logger.LevelInfo, "updating database version: 18 -> 19")
sql := strings.ReplaceAll(mysqlV19SQL, "{{shared_sessions}}", sqlTableSharedSessions)
sql = strings.ReplaceAll(sql, "{{prefix}}", config.SQLTablesPrefix)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, strings.Split(sql, ";"), 19, true)
}
func downgradeMySQLDatabaseFrom16To15(dbHandle *sql.DB) error {
@@ -685,7 +733,7 @@ func downgradeMySQLDatabaseFrom16To15(dbHandle *sql.DB) error {
providerLog(logger.LevelInfo, "downgrading database version: 16 -> 15")
sql := strings.ReplaceAll(mysqlV16DownSQL, "{{users}}", sqlTableUsers)
sql = strings.ReplaceAll(sql, "{{active_transfers}}", sqlTableActiveTransfers)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, strings.Split(sql, ";"), 15)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, strings.Split(sql, ";"), 15, false)
}
func downgradeMySQLDatabaseFrom17To16(dbHandle *sql.DB) error {
@@ -699,11 +747,18 @@ func downgradeMySQLDatabaseFrom17To16(dbHandle *sql.DB) error {
sql = strings.ReplaceAll(sql, "{{users_groups_mapping}}", sqlTableUsersGroupsMapping)
sql = strings.ReplaceAll(sql, "{{groups_folders_mapping}}", sqlTableGroupsFoldersMapping)
sql = strings.ReplaceAll(sql, "{{prefix}}", config.SQLTablesPrefix)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, strings.Split(sql, ";"), 16)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, strings.Split(sql, ";"), 16, false)
}
func downgradeMySQLDatabaseFrom18To17(dbHandle *sql.DB) error {
logger.InfoToConsole("downgrading database version: 18 -> 17")
providerLog(logger.LevelInfo, "downgrading database version: 18 -> 17")
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, nil, 17)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, nil, 17, false)
}
func downgradeMySQLDatabaseFrom19To18(dbHandle *sql.DB) error {
logger.InfoToConsole("downgrading database version: 19 -> 18")
providerLog(logger.LevelInfo, "downgrading database version: 19 -> 18")
sql := strings.ReplaceAll(mysqlV19DownSQL, "{{shared_sessions}}", sqlTableSharedSessions)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 18, false)
}
+65 -10
View File
@@ -34,6 +34,7 @@ DROP TABLE IF EXISTS "{{groups}}" CASCADE;
DROP TABLE IF EXISTS "{{defender_events}}" CASCADE;
DROP TABLE IF EXISTS "{{defender_hosts}}" CASCADE;
DROP TABLE IF EXISTS "{{active_transfers}}" CASCADE;
DROP TABLE IF EXISTS "{{shared_sessions}}" CASCADE;
DROP TABLE IF EXISTS "{{schema_version}}" CASCADE;
`
pgsqlInitial = `CREATE TABLE "{{schema_version}}" ("id" serial NOT NULL PRIMARY KEY, "version" integer NOT NULL);
@@ -158,6 +159,11 @@ ALTER TABLE "{{folders_mapping}}" ADD CONSTRAINT "{{prefix}}unique_mapping" UNIQ
CREATE INDEX "{{prefix}}folders_mapping_folder_id_idx" ON "{{folders_mapping}}" ("folder_id");
CREATE INDEX "{{prefix}}folders_mapping_user_id_idx" ON "{{folders_mapping}}" ("user_id");
`
pgsqlV19SQL = `CREATE TABLE "{{shared_sessions}}" ("key" varchar(128) NOT NULL PRIMARY KEY,
"data" text NOT NULL, "type" integer NOT NULL, "timestamp" bigint NOT NULL);
CREATE INDEX "{{prefix}}shared_sessions_type_idx" ON "{{shared_sessions}}" ("type");
CREATE INDEX "{{prefix}}shared_sessions_timestamp_idx" ON "{{shared_sessions}}" ("timestamp");`
pgsqlV19DownSQL = `DROP TABLE "{{shared_sessions}}" CASCADE;`
)
// PGSQLProvider defines the auth provider for PostgreSQL database
@@ -489,6 +495,22 @@ func (p *PGSQLProvider) getActiveTransfers(from time.Time) ([]ActiveTransfer, er
return sqlCommonGetActiveTransfers(from, p.dbHandle)
}
func (p *PGSQLProvider) addSharedSession(session Session) error {
return sqlCommonAddSession(session, p.dbHandle)
}
func (p *PGSQLProvider) deleteSharedSession(key string) error {
return sqlCommonDeleteSession(key, p.dbHandle)
}
func (p *PGSQLProvider) getSharedSession(key string) (Session, error) {
return sqlCommonGetSession(key, p.dbHandle)
}
func (p *PGSQLProvider) cleanupSharedSessions(sessionType SessionType, before int64) error {
return sqlCommonCleanupSessions(sessionType, before, p.dbHandle)
}
func (p *PGSQLProvider) close() error {
return p.dbHandle.Close()
}
@@ -525,10 +547,10 @@ func (p *PGSQLProvider) initializeDatabase() error {
initialSQL = strings.ReplaceAll(initialSQL, "DEFERRABLE INITIALLY DEFERRED", "")
}
return sqlCommonExecSQLAndUpdateDBVersion(p.dbHandle, []string{initialSQL}, 15)
return sqlCommonExecSQLAndUpdateDBVersion(p.dbHandle, []string{initialSQL}, 15, true)
}
func (p *PGSQLProvider) migrateDatabase() error {
func (p *PGSQLProvider) migrateDatabase() error { //nolint:dupl
dbVersion, err := sqlCommonGetDatabaseVersion(p.dbHandle, true)
if err != nil {
return err
@@ -549,6 +571,8 @@ func (p *PGSQLProvider) migrateDatabase() error {
return updatePGSQLDatabaseFromV16(p.dbHandle)
case version == 17:
return updatePGSQLDatabaseFromV17(p.dbHandle)
case version == 18:
return updatePGSQLDatabaseFromV18(p.dbHandle)
default:
if version > sqlDatabaseVersion {
providerLog(logger.LevelError, "database version %v is newer than the supported one: %v", version,
@@ -577,6 +601,8 @@ func (p *PGSQLProvider) revertDatabase(targetVersion int) error {
return downgradePGSQLDatabaseFromV17(p.dbHandle)
case 18:
return downgradePGSQLDatabaseFromV18(p.dbHandle)
case 19:
return downgradePGSQLDatabaseFromV19(p.dbHandle)
default:
return fmt.Errorf("database version not handled: %v", dbVersion.Version)
}
@@ -584,7 +610,7 @@ func (p *PGSQLProvider) revertDatabase(targetVersion int) error {
func (p *PGSQLProvider) resetDatabase() error {
sql := sqlReplaceAll(pgsqlResetSQL)
return sqlCommonExecSQLAndUpdateDBVersion(p.dbHandle, []string{sql}, 0)
return sqlCommonExecSQLAndUpdateDBVersion(p.dbHandle, []string{sql}, 0, false)
}
func updatePGSQLDatabaseFromV15(dbHandle *sql.DB) error {
@@ -602,7 +628,14 @@ func updatePGSQLDatabaseFromV16(dbHandle *sql.DB) error {
}
func updatePGSQLDatabaseFromV17(dbHandle *sql.DB) error {
return updatePGSQLDatabaseFrom17To18(dbHandle)
if err := updatePGSQLDatabaseFrom17To18(dbHandle); err != nil {
return err
}
return updatePGSQLDatabaseFromV18(dbHandle)
}
func updatePGSQLDatabaseFromV18(dbHandle *sql.DB) error {
return updatePGSQLDatabaseFrom18To19(dbHandle)
}
func downgradePGSQLDatabaseFromV16(dbHandle *sql.DB) error {
@@ -623,6 +656,13 @@ func downgradePGSQLDatabaseFromV18(dbHandle *sql.DB) error {
return downgradePGSQLDatabaseFromV17(dbHandle)
}
func downgradePGSQLDatabaseFromV19(dbHandle *sql.DB) error {
if err := downgradePGSQLDatabaseFrom19To18(dbHandle); err != nil {
return err
}
return downgradePGSQLDatabaseFromV18(dbHandle)
}
func updatePGSQLDatabaseFrom15To16(dbHandle *sql.DB) error {
logger.InfoToConsole("updating database version: 15 -> 16")
providerLog(logger.LevelInfo, "updating database version: 15 -> 16")
@@ -645,7 +685,7 @@ func updatePGSQLDatabaseFrom15To16(dbHandle *sql.DB) error {
}
return sqlCommonUpdateDatabaseVersion(ctx, dbHandle, 16)
}
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 16)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 16, true)
}
func updatePGSQLDatabaseFrom16To17(dbHandle *sql.DB) error {
@@ -664,7 +704,7 @@ func updatePGSQLDatabaseFrom16To17(dbHandle *sql.DB) error {
sql = strings.ReplaceAll(sql, "{{users_groups_mapping}}", sqlTableUsersGroupsMapping)
sql = strings.ReplaceAll(sql, "{{groups_folders_mapping}}", sqlTableGroupsFoldersMapping)
sql = strings.ReplaceAll(sql, "{{prefix}}", config.SQLTablesPrefix)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 17)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 17, true)
}
func updatePGSQLDatabaseFrom17To18(dbHandle *sql.DB) error {
@@ -673,7 +713,15 @@ func updatePGSQLDatabaseFrom17To18(dbHandle *sql.DB) error {
if err := importGCSCredentials(); err != nil {
return err
}
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, nil, 18)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, nil, 18, true)
}
func updatePGSQLDatabaseFrom18To19(dbHandle *sql.DB) error {
logger.InfoToConsole("updating database version: 18 -> 19")
providerLog(logger.LevelInfo, "updating database version: 18 -> 19")
sql := strings.ReplaceAll(pgsqlV19SQL, "{{shared_sessions}}", sqlTableSharedSessions)
sql = strings.ReplaceAll(sql, "{{prefix}}", config.SQLTablesPrefix)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 19, true)
}
func downgradePGSQLDatabaseFrom16To15(dbHandle *sql.DB) error {
@@ -681,7 +729,7 @@ func downgradePGSQLDatabaseFrom16To15(dbHandle *sql.DB) error {
providerLog(logger.LevelInfo, "downgrading database version: 16 -> 15")
sql := strings.ReplaceAll(pgsqlV16DownSQL, "{{users}}", sqlTableUsers)
sql = strings.ReplaceAll(sql, "{{active_transfers}}", sqlTableActiveTransfers)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 15)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 15, false)
}
func downgradePGSQLDatabaseFrom17To16(dbHandle *sql.DB) error {
@@ -700,11 +748,18 @@ func downgradePGSQLDatabaseFrom17To16(dbHandle *sql.DB) error {
sql = strings.ReplaceAll(sql, "{{users_groups_mapping}}", sqlTableUsersGroupsMapping)
sql = strings.ReplaceAll(sql, "{{groups_folders_mapping}}", sqlTableGroupsFoldersMapping)
sql = strings.ReplaceAll(sql, "{{prefix}}", config.SQLTablesPrefix)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 16)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 16, false)
}
func downgradePGSQLDatabaseFrom18To17(dbHandle *sql.DB) error {
logger.InfoToConsole("downgrading database version: 18 -> 17")
providerLog(logger.LevelInfo, "downgrading database version: 18 -> 17")
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, nil, 17)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, nil, 17, false)
}
func downgradePGSQLDatabaseFrom19To18(dbHandle *sql.DB) error {
logger.InfoToConsole("downgrading database version: 19 -> 18")
providerLog(logger.LevelInfo, "downgrading database version: 19 -> 18")
sql := strings.ReplaceAll(pgsqlV19DownSQL, "{{shared_sessions}}", sqlTableSharedSessions)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 18, false)
}
+34
View File
@@ -0,0 +1,34 @@
package dataprovider
import (
"errors"
"fmt"
)
// SessionType defines the supported session types
type SessionType int
// Supported session types
const (
SessionTypeOIDCAuth SessionType = iota + 1
SessionTypeOIDCToken
SessionTypeResetCode
)
// Session defines a shared session persisted in the data provider
type Session struct {
Key string
Data any
Type SessionType
Timestamp int64
}
func (s *Session) validate() error {
if s.Key == "" {
return errors.New("unable to save a session with an empty key")
}
if s.Type < SessionTypeOIDCAuth || s.Type > SessionTypeResetCode {
return fmt.Errorf("invalid session type: %v", s.Type)
}
return nil
}
+137 -26
View File
@@ -20,7 +20,7 @@ import (
)
const (
sqlDatabaseVersion = 18
sqlDatabaseVersion = 19
defaultSQLQueryTimeout = 10 * time.Second
longSQLQueryTimeout = 60 * time.Second
)
@@ -37,7 +37,7 @@ type sqlQuerier interface {
}
type sqlScanner interface {
Scan(dest ...interface{}) error
Scan(dest ...any) error
}
func sqlReplaceAll(sql string) string {
@@ -203,8 +203,11 @@ func sqlCommonDeleteShare(share Share, dbHandle *sql.DB) error {
return err
}
defer stmt.Close()
_, err = stmt.ExecContext(ctx, share.ShareID)
return err
res, err := stmt.ExecContext(ctx, share.ShareID)
if err != nil {
return err
}
return sqlCommonRequireRowAffected(res)
}
func sqlCommonGetShares(limit, offset int, order, username string, dbHandle sqlQuerier) ([]Share, error) {
@@ -352,8 +355,11 @@ func sqlCommonDeleteAPIKey(apiKey APIKey, dbHandle *sql.DB) error {
return err
}
defer stmt.Close()
_, err = stmt.ExecContext(ctx, apiKey.KeyID)
return err
res, err := stmt.ExecContext(ctx, apiKey.KeyID)
if err != nil {
return err
}
return sqlCommonRequireRowAffected(res)
}
func sqlCommonGetAPIKeys(limit, offset int, order string, dbHandle sqlQuerier) ([]APIKey, error) {
@@ -532,8 +538,11 @@ func sqlCommonDeleteAdmin(admin Admin, dbHandle *sql.DB) error {
return err
}
defer stmt.Close()
_, err = stmt.ExecContext(ctx, admin.Username)
return err
res, err := stmt.ExecContext(ctx, admin.Username)
if err != nil {
return err
}
return sqlCommonRequireRowAffected(res)
}
func sqlCommonGetAdmins(limit, offset int, order string, dbHandle sqlQuerier) ([]Admin, error) {
@@ -667,7 +676,7 @@ func sqlCommonGetUsersInGroups(names []string, dbHandle sqlQuerier) ([]string, e
}
defer stmt.Close()
args := make([]interface{}, 0, len(names))
args := make([]any, 0, len(names))
for _, name := range names {
args = append(args, name)
}
@@ -705,7 +714,7 @@ func sqlCommonGetGroupsWithNames(names []string, dbHandle sqlQuerier) ([]Group,
}
defer stmt.Close()
args := make([]interface{}, 0, len(names))
args := make([]any, 0, len(names))
for _, name := range names {
args = append(args, name)
}
@@ -849,8 +858,11 @@ func sqlCommonDeleteGroup(group Group, dbHandle *sql.DB) error {
return err
}
defer stmt.Close()
_, err = stmt.ExecContext(ctx, group.Name)
return err
res, err := stmt.ExecContext(ctx, group.Name)
if err != nil {
return err
}
return sqlCommonRequireRowAffected(res)
}
func sqlCommonGetUserByUsername(username string, dbHandle sqlQuerier) (User, error) {
@@ -1206,8 +1218,11 @@ func sqlCommonDeleteUser(user User, dbHandle *sql.DB) error {
return err
}
defer stmt.Close()
_, err = stmt.ExecContext(ctx, user.ID)
return err
res, err := stmt.ExecContext(ctx, user.ID)
if err != nil {
return err
}
return sqlCommonRequireRowAffected(res)
}
func sqlCommonDumpUsers(dbHandle sqlQuerier) ([]User, error) {
@@ -1389,7 +1404,7 @@ func sqlCommonGetUsersRangeForQuotaCheck(usernames []string, dbHandle sqlQuerier
}
defer stmt.Close()
queryArgs := make([]interface{}, 0, len(usernames))
queryArgs := make([]any, 0, len(usernames))
for idx := range usernames {
queryArgs = append(queryArgs, usernames[idx])
}
@@ -1730,11 +1745,12 @@ func sqlCommonDeleteDefenderHost(ip string, dbHandle sqlQuerier) error {
return err
}
defer stmt.Close()
_, err = stmt.ExecContext(ctx, ip)
res, err := stmt.ExecContext(ctx, ip)
if err != nil {
providerLog(logger.LevelError, "unable to delete defender host %#v: %v", ip, err)
return err
}
return err
return sqlCommonRequireRowAffected(res)
}
func sqlCommonAddDefenderHostAndEvent(ip string, score int, dbHandle *sql.DB) error {
@@ -2160,8 +2176,11 @@ func sqlCommonDeleteFolder(folder vfs.BaseVirtualFolder, dbHandle sqlQuerier) er
return err
}
defer stmt.Close()
_, err = stmt.ExecContext(ctx, folder.ID)
return err
res, err := stmt.ExecContext(ctx, folder.ID)
if err != nil {
return err
}
return sqlCommonRequireRowAffected(res)
}
func sqlCommonDumpFolders(dbHandle sqlQuerier) ([]vfs.BaseVirtualFolder, error) {
@@ -2911,6 +2930,86 @@ func sqlCommonGetAPIKeyRelatedIDs(apiKey *APIKey) (sql.NullInt64, sql.NullInt64,
return userID, adminID, nil
}
func sqlCommonAddSession(session Session, dbHandle *sql.DB) error {
if err := session.validate(); err != nil {
return err
}
data, err := json.Marshal(session.Data)
if err != nil {
return err
}
ctx, cancel := context.WithTimeout(context.Background(), defaultSQLQueryTimeout)
defer cancel()
q := getAddSessionQuery()
stmt, err := dbHandle.PrepareContext(ctx, q)
if err != nil {
providerLog(logger.LevelError, "error preparing database query %#v: %v", q, err)
return err
}
defer stmt.Close()
_, err = stmt.ExecContext(ctx, session.Key, data, session.Type, session.Timestamp)
return err
}
func sqlCommonGetSession(key string, dbHandle sqlQuerier) (Session, error) {
var session Session
ctx, cancel := context.WithTimeout(context.Background(), defaultSQLQueryTimeout)
defer cancel()
q := getSessionQuery()
stmt, err := dbHandle.PrepareContext(ctx, q)
if err != nil {
providerLog(logger.LevelError, "error preparing database query %#v: %v", q, err)
return session, err
}
defer stmt.Close()
var data []byte // type hint, some driver will use string instead of []byte if the type is any
err = stmt.QueryRowContext(ctx, key).Scan(&session.Key, &data, &session.Type, &session.Timestamp)
if err != nil {
return session, err
}
session.Data = data
return session, nil
}
func sqlCommonDeleteSession(key string, dbHandle *sql.DB) error {
ctx, cancel := context.WithTimeout(context.Background(), defaultSQLQueryTimeout)
defer cancel()
q := getDeleteSessionQuery()
stmt, err := dbHandle.PrepareContext(ctx, q)
if err != nil {
providerLog(logger.LevelError, "error preparing database query %#v: %v", q, err)
return err
}
defer stmt.Close()
res, err := stmt.ExecContext(ctx, key)
if err != nil {
return err
}
return sqlCommonRequireRowAffected(res)
}
func sqlCommonCleanupSessions(sessionType SessionType, before int64, dbHandle *sql.DB) error {
ctx, cancel := context.WithTimeout(context.Background(), defaultSQLQueryTimeout)
defer cancel()
q := getCleanupSessionsQuery()
stmt, err := dbHandle.PrepareContext(ctx, q)
if err != nil {
providerLog(logger.LevelError, "error preparing database query %#v: %v", q, err)
return err
}
defer stmt.Close()
_, err = stmt.ExecContext(ctx, sessionType, before)
return err
}
func sqlCommonGetDatabaseVersion(dbHandle sqlQuerier, showInitWarn bool) (schemaVersion, error) {
var result schemaVersion
ctx, cancel := context.WithTimeout(context.Background(), defaultSQLQueryTimeout)
@@ -2931,6 +3030,16 @@ func sqlCommonGetDatabaseVersion(dbHandle sqlQuerier, showInitWarn bool) (schema
return result, err
}
func sqlCommonRequireRowAffected(res sql.Result) error {
// MariaDB/MySQL returns 0 rows affected for updates that don't change anything
// so we don't check rows affected for updates
affected, err := res.RowsAffected()
if err == nil && affected == 0 {
return util.NewRecordNotFoundError(sql.ErrNoRows.Error())
}
return nil
}
func sqlCommonUpdateDatabaseVersion(ctx context.Context, dbHandle sqlQuerier, version int) error {
q := getUpdateDBVersionQuery()
stmt, err := dbHandle.PrepareContext(ctx, q)
@@ -2943,8 +3052,8 @@ func sqlCommonUpdateDatabaseVersion(ctx context.Context, dbHandle sqlQuerier, ve
return err
}
func sqlCommonExecSQLAndUpdateDBVersion(dbHandle *sql.DB, sqlQueries []string, newVersion int) error {
if err := sqlAquireLock(dbHandle); err != nil {
func sqlCommonExecSQLAndUpdateDBVersion(dbHandle *sql.DB, sqlQueries []string, newVersion int, isUp bool) error {
if err := sqlAcquireLock(dbHandle); err != nil {
return err
}
defer sqlReleaseLock(dbHandle)
@@ -2954,10 +3063,12 @@ func sqlCommonExecSQLAndUpdateDBVersion(dbHandle *sql.DB, sqlQueries []string, n
if newVersion > 0 {
currentVersion, err := sqlCommonGetDatabaseVersion(dbHandle, false)
if err == nil && currentVersion.Version >= newVersion {
providerLog(logger.LevelInfo, "current schema version: %v, requested: %v, did you execute simultaneous migrations?",
currentVersion.Version, newVersion)
return nil
if err == nil {
if (isUp && currentVersion.Version >= newVersion) || (!isUp && currentVersion.Version <= newVersion) {
providerLog(logger.LevelInfo, "current schema version: %v, requested: %v, did you execute simultaneous migrations?",
currentVersion.Version, newVersion)
return nil
}
}
}
@@ -2978,7 +3089,7 @@ func sqlCommonExecSQLAndUpdateDBVersion(dbHandle *sql.DB, sqlQueries []string, n
})
}
func sqlAquireLock(dbHandle *sql.DB) error {
func sqlAcquireLock(dbHandle *sql.DB) error {
ctx, cancel := context.WithTimeout(context.Background(), longSQLQueryTimeout)
defer cancel()
+66 -10
View File
@@ -36,6 +36,7 @@ DROP TABLE IF EXISTS "{{groups}}";
DROP TABLE IF EXISTS "{{defender_events}}";
DROP TABLE IF EXISTS "{{defender_hosts}}";
DROP TABLE IF EXISTS "{{active_transfers}}";
DROP TABLE IF EXISTS "{{shared_sessions}}";
DROP TABLE IF EXISTS "{{schema_version}}";
`
sqliteInitialSQL = `CREATE TABLE "{{schema_version}}" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "version" integer NOT NULL);
@@ -149,6 +150,12 @@ ALTER TABLE "new__folders_mapping" RENAME TO "{{folders_mapping}}";
CREATE INDEX "{{prefix}}folders_mapping_folder_id_idx" ON "{{folders_mapping}}" ("folder_id");
CREATE INDEX "{{prefix}}folders_mapping_user_id_idx" ON "{{folders_mapping}}" ("user_id");
`
sqliteV19SQL = `CREATE TABLE "{{shared_sessions}}" ("key" varchar(128) NOT NULL PRIMARY KEY, "data" text NOT NULL,
"type" integer NOT NULL, "timestamp" bigint NOT NULL);
CREATE INDEX "{{prefix}}shared_sessions_type_idx" ON "{{shared_sessions}}" ("type");
CREATE INDEX "{{prefix}}shared_sessions_timestamp_idx" ON "{{shared_sessions}}" ("timestamp");
`
sqliteV19DownSQL = `DROP TABLE "{{shared_sessions}}";`
)
// SQLiteProvider defines the auth provider for SQLite database
@@ -466,6 +473,22 @@ func (p *SQLiteProvider) getActiveTransfers(from time.Time) ([]ActiveTransfer, e
return sqlCommonGetActiveTransfers(from, p.dbHandle)
}
func (p *SQLiteProvider) addSharedSession(session Session) error {
return sqlCommonAddSession(session, p.dbHandle)
}
func (p *SQLiteProvider) deleteSharedSession(key string) error {
return sqlCommonDeleteSession(key, p.dbHandle)
}
func (p *SQLiteProvider) getSharedSession(key string) (Session, error) {
return sqlCommonGetSession(key, p.dbHandle)
}
func (p *SQLiteProvider) cleanupSharedSessions(sessionType SessionType, before int64) error {
return sqlCommonCleanupSessions(sessionType, before, p.dbHandle)
}
func (p *SQLiteProvider) close() error {
return p.dbHandle.Close()
}
@@ -496,10 +519,10 @@ func (p *SQLiteProvider) initializeDatabase() error {
initialSQL = strings.ReplaceAll(initialSQL, "{{defender_hosts}}", sqlTableDefenderHosts)
initialSQL = strings.ReplaceAll(initialSQL, "{{prefix}}", config.SQLTablesPrefix)
return sqlCommonExecSQLAndUpdateDBVersion(p.dbHandle, []string{initialSQL}, 15)
return sqlCommonExecSQLAndUpdateDBVersion(p.dbHandle, []string{initialSQL}, 15, true)
}
func (p *SQLiteProvider) migrateDatabase() error {
func (p *SQLiteProvider) migrateDatabase() error { //nolint:dupl
dbVersion, err := sqlCommonGetDatabaseVersion(p.dbHandle, true)
if err != nil {
return err
@@ -520,6 +543,8 @@ func (p *SQLiteProvider) migrateDatabase() error {
return updateSQLiteDatabaseFromV16(p.dbHandle)
case version == 17:
return updateSQLiteDatabaseFromV17(p.dbHandle)
case version == 18:
return updateSQLiteDatabaseFromV18(p.dbHandle)
default:
if version > sqlDatabaseVersion {
providerLog(logger.LevelError, "database version %v is newer than the supported one: %v", version,
@@ -548,6 +573,8 @@ func (p *SQLiteProvider) revertDatabase(targetVersion int) error {
return downgradeSQLiteDatabaseFromV17(p.dbHandle)
case 18:
return downgradeSQLiteDatabaseFromV18(p.dbHandle)
case 19:
return downgradeSQLiteDatabaseFromV19(p.dbHandle)
default:
return fmt.Errorf("database version not handled: %v", dbVersion.Version)
}
@@ -555,7 +582,7 @@ func (p *SQLiteProvider) revertDatabase(targetVersion int) error {
func (p *SQLiteProvider) resetDatabase() error {
sql := sqlReplaceAll(sqliteResetSQL)
return sqlCommonExecSQLAndUpdateDBVersion(p.dbHandle, []string{sql}, 0)
return sqlCommonExecSQLAndUpdateDBVersion(p.dbHandle, []string{sql}, 0, false)
}
func updateSQLiteDatabaseFromV15(dbHandle *sql.DB) error {
@@ -573,7 +600,14 @@ func updateSQLiteDatabaseFromV16(dbHandle *sql.DB) error {
}
func updateSQLiteDatabaseFromV17(dbHandle *sql.DB) error {
return updateSQLiteDatabaseFrom17To18(dbHandle)
if err := updateSQLiteDatabaseFrom17To18(dbHandle); err != nil {
return err
}
return updateSQLiteDatabaseFromV18(dbHandle)
}
func updateSQLiteDatabaseFromV18(dbHandle *sql.DB) error {
return updateSQLiteDatabaseFrom18To19(dbHandle)
}
func downgradeSQLiteDatabaseFromV16(dbHandle *sql.DB) error {
@@ -594,13 +628,20 @@ func downgradeSQLiteDatabaseFromV18(dbHandle *sql.DB) error {
return downgradeSQLiteDatabaseFromV17(dbHandle)
}
func downgradeSQLiteDatabaseFromV19(dbHandle *sql.DB) error {
if err := downgradeSQLiteDatabaseFrom19To18(dbHandle); err != nil {
return err
}
return downgradeSQLiteDatabaseFromV18(dbHandle)
}
func updateSQLiteDatabaseFrom15To16(dbHandle *sql.DB) error {
logger.InfoToConsole("updating database version: 15 -> 16")
providerLog(logger.LevelInfo, "updating database version: 15 -> 16")
sql := strings.ReplaceAll(sqliteV16SQL, "{{users}}", sqlTableUsers)
sql = strings.ReplaceAll(sql, "{{active_transfers}}", sqlTableActiveTransfers)
sql = strings.ReplaceAll(sql, "{{prefix}}", config.SQLTablesPrefix)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 16)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 16, true)
}
func updateSQLiteDatabaseFrom16To17(dbHandle *sql.DB) error {
@@ -617,7 +658,7 @@ func updateSQLiteDatabaseFrom16To17(dbHandle *sql.DB) error {
sql = strings.ReplaceAll(sql, "{{users_groups_mapping}}", sqlTableUsersGroupsMapping)
sql = strings.ReplaceAll(sql, "{{groups_folders_mapping}}", sqlTableGroupsFoldersMapping)
sql = strings.ReplaceAll(sql, "{{prefix}}", config.SQLTablesPrefix)
if err := sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 17); err != nil {
if err := sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 17, true); err != nil {
return err
}
return setPragmaFK(dbHandle, "ON")
@@ -629,7 +670,15 @@ func updateSQLiteDatabaseFrom17To18(dbHandle *sql.DB) error {
if err := importGCSCredentials(); err != nil {
return err
}
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, nil, 18)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, nil, 18, true)
}
func updateSQLiteDatabaseFrom18To19(dbHandle *sql.DB) error {
logger.InfoToConsole("updating database version: 18 -> 19")
providerLog(logger.LevelInfo, "updating database version: 18 -> 19")
sql := strings.ReplaceAll(sqliteV19SQL, "{{shared_sessions}}", sqlTableSharedSessions)
sql = strings.ReplaceAll(sql, "{{prefix}}", config.SQLTablesPrefix)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 19, true)
}
func downgradeSQLiteDatabaseFrom16To15(dbHandle *sql.DB) error {
@@ -637,7 +686,7 @@ func downgradeSQLiteDatabaseFrom16To15(dbHandle *sql.DB) error {
providerLog(logger.LevelInfo, "downgrading database version: 16 -> 15")
sql := strings.ReplaceAll(sqliteV16DownSQL, "{{users}}", sqlTableUsers)
sql = strings.ReplaceAll(sql, "{{active_transfers}}", sqlTableActiveTransfers)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 15)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 15, false)
}
func downgradeSQLiteDatabaseFrom17To16(dbHandle *sql.DB) error {
@@ -654,7 +703,7 @@ func downgradeSQLiteDatabaseFrom17To16(dbHandle *sql.DB) error {
sql = strings.ReplaceAll(sql, "{{users_groups_mapping}}", sqlTableUsersGroupsMapping)
sql = strings.ReplaceAll(sql, "{{groups_folders_mapping}}", sqlTableGroupsFoldersMapping)
sql = strings.ReplaceAll(sql, "{{prefix}}", config.SQLTablesPrefix)
if err := sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 16); err != nil {
if err := sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 16, false); err != nil {
return err
}
return setPragmaFK(dbHandle, "ON")
@@ -663,7 +712,14 @@ func downgradeSQLiteDatabaseFrom17To16(dbHandle *sql.DB) error {
func downgradeSQLiteDatabaseFrom18To17(dbHandle *sql.DB) error {
logger.InfoToConsole("downgrading database version: 18 -> 17")
providerLog(logger.LevelInfo, "downgrading database version: 18 -> 17")
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, nil, 17)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, nil, 17, false)
}
func downgradeSQLiteDatabaseFrom19To18(dbHandle *sql.DB) error {
logger.InfoToConsole("downgrading database version: 19 -> 18")
providerLog(logger.LevelInfo, "downgrading database version: 19 -> 18")
sql := strings.ReplaceAll(sqliteV19DownSQL, "{{shared_sessions}}", sqlTableSharedSessions)
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 18, false)
}
func setPragmaFK(dbHandle *sql.DB, value string) error {
+32
View File
@@ -33,6 +33,38 @@ func getSQLPlaceholders() []string {
return placeholders
}
func getAddSessionQuery() string {
if config.Driver == MySQLDataProviderName {
return fmt.Sprintf("INSERT INTO %s (`key`,`data`,`type`,`timestamp`) VALUES (%s,%s,%s,%s) "+
"ON DUPLICATE KEY UPDATE `data`=VALUES(`data`), `timestamp`=VALUES(`timestamp`)",
sqlTableSharedSessions, sqlPlaceholders[0], sqlPlaceholders[1], sqlPlaceholders[2], sqlPlaceholders[3])
}
return fmt.Sprintf(`INSERT INTO %s (key,data,type,timestamp) VALUES (%s,%s,%s,%s) ON CONFLICT(key) DO UPDATE SET data=
EXCLUDED.data, timestamp=EXCLUDED.timestamp`,
sqlTableSharedSessions, sqlPlaceholders[0], sqlPlaceholders[1], sqlPlaceholders[2], sqlPlaceholders[3])
}
func getDeleteSessionQuery() string {
if config.Driver == MySQLDataProviderName {
return fmt.Sprintf("DELETE FROM %s WHERE `key` = %s", sqlTableSharedSessions, sqlPlaceholders[0])
}
return fmt.Sprintf(`DELETE FROM %s WHERE key = %s`, sqlTableSharedSessions, sqlPlaceholders[0])
}
func getSessionQuery() string {
if config.Driver == MySQLDataProviderName {
return fmt.Sprintf("SELECT `key`,`data`,`type`,`timestamp` FROM %s WHERE `key` = %s", sqlTableSharedSessions,
sqlPlaceholders[0])
}
return fmt.Sprintf(`SELECT key,data,type,timestamp FROM %s WHERE key = %s`, sqlTableSharedSessions,
sqlPlaceholders[0])
}
func getCleanupSessionsQuery() string {
return fmt.Sprintf(`DELETE from %s WHERE type = %s AND timestamp < %s`,
sqlTableSharedSessions, sqlPlaceholders[0], sqlPlaceholders[1])
}
func getAddDefenderHostQuery() string {
if config.Driver == MySQLDataProviderName {
return fmt.Sprintf("INSERT INTO %v (`ip`,`updated_at`,`ban_time`) VALUES (%v,%v,0) ON DUPLICATE KEY UPDATE `updated_at`=VALUES(`updated_at`)",
+24 -24
View File
@@ -756,20 +756,20 @@ func (u *User) HasPermissionsInside(virtualPath string) bool {
// HasPerm returns true if the user has the given permission or any permission
func (u *User) HasPerm(permission, path string) bool {
perms := u.GetPermissionsForPath(path)
if util.IsStringInSlice(PermAny, perms) {
if util.Contains(perms, PermAny) {
return true
}
return util.IsStringInSlice(permission, perms)
return util.Contains(perms, permission)
}
// HasAnyPerm returns true if the user has at least one of the given permissions
func (u *User) HasAnyPerm(permissions []string, path string) bool {
perms := u.GetPermissionsForPath(path)
if util.IsStringInSlice(PermAny, perms) {
if util.Contains(perms, PermAny) {
return true
}
for _, permission := range permissions {
if util.IsStringInSlice(permission, perms) {
if util.Contains(perms, permission) {
return true
}
}
@@ -779,11 +779,11 @@ func (u *User) HasAnyPerm(permissions []string, path string) bool {
// HasPerms returns true if the user has all the given permissions
func (u *User) HasPerms(permissions []string, path string) bool {
perms := u.GetPermissionsForPath(path)
if util.IsStringInSlice(PermAny, perms) {
if util.Contains(perms, PermAny) {
return true
}
for _, permission := range permissions {
if !util.IsStringInSlice(permission, perms) {
if !util.Contains(perms, permission) {
return false
}
}
@@ -850,11 +850,11 @@ func (u *User) IsLoginMethodAllowed(loginMethod, protocol string, partialSuccess
}
}
}
if util.IsStringInSlice(loginMethod, u.Filters.DeniedLoginMethods) {
if util.Contains(u.Filters.DeniedLoginMethods, loginMethod) {
return false
}
if protocol == protocolSSH && loginMethod == LoginMethodPassword {
if util.IsStringInSlice(SSHLoginMethodPassword, u.Filters.DeniedLoginMethods) {
if util.Contains(u.Filters.DeniedLoginMethods, SSHLoginMethodPassword) {
return false
}
}
@@ -896,7 +896,7 @@ func (u *User) IsPartialAuth(loginMethod string) bool {
method == SSHLoginMethodPassword {
continue
}
if !util.IsStringInSlice(method, SSHMultiStepsLoginMethods) {
if !util.Contains(SSHMultiStepsLoginMethods, method) {
return false
}
}
@@ -910,7 +910,7 @@ func (u *User) GetAllowedLoginMethods() []string {
if method == SSHLoginMethodPassword {
continue
}
if !util.IsStringInSlice(method, u.Filters.DeniedLoginMethods) {
if !util.Contains(u.Filters.DeniedLoginMethods, method) {
allowedMethods = append(allowedMethods, method)
}
}
@@ -968,7 +968,7 @@ func (u *User) IsFileAllowed(virtualPath string) (bool, int) {
// CanManageMFA returns true if the user can add a multi-factor authentication configuration
func (u *User) CanManageMFA() bool {
if util.IsStringInSlice(sdk.WebClientMFADisabled, u.Filters.WebClient) {
if util.Contains(u.Filters.WebClient, sdk.WebClientMFADisabled) {
return false
}
return len(mfa.GetAvailableTOTPConfigs()) > 0
@@ -987,39 +987,39 @@ func (u *User) isExternalAuthCached() bool {
// CanManageShares returns true if the user can add, update and list shares
func (u *User) CanManageShares() bool {
return !util.IsStringInSlice(sdk.WebClientSharesDisabled, u.Filters.WebClient)
return !util.Contains(u.Filters.WebClient, sdk.WebClientSharesDisabled)
}
// CanResetPassword returns true if this user is allowed to reset its password
func (u *User) CanResetPassword() bool {
return !util.IsStringInSlice(sdk.WebClientPasswordResetDisabled, u.Filters.WebClient)
return !util.Contains(u.Filters.WebClient, sdk.WebClientPasswordResetDisabled)
}
// CanChangePassword returns true if this user is allowed to change its password
func (u *User) CanChangePassword() bool {
return !util.IsStringInSlice(sdk.WebClientPasswordChangeDisabled, u.Filters.WebClient)
return !util.Contains(u.Filters.WebClient, sdk.WebClientPasswordChangeDisabled)
}
// CanChangeAPIKeyAuth returns true if this user is allowed to enable/disable API key authentication
func (u *User) CanChangeAPIKeyAuth() bool {
return !util.IsStringInSlice(sdk.WebClientAPIKeyAuthChangeDisabled, u.Filters.WebClient)
return !util.Contains(u.Filters.WebClient, sdk.WebClientAPIKeyAuthChangeDisabled)
}
// CanChangeInfo returns true if this user is allowed to change its info such as email and description
func (u *User) CanChangeInfo() bool {
return !util.IsStringInSlice(sdk.WebClientInfoChangeDisabled, u.Filters.WebClient)
return !util.Contains(u.Filters.WebClient, sdk.WebClientInfoChangeDisabled)
}
// CanManagePublicKeys returns true if this user is allowed to manage public keys
// from the web client. Used in web client UI
func (u *User) CanManagePublicKeys() bool {
return !util.IsStringInSlice(sdk.WebClientPubKeyChangeDisabled, u.Filters.WebClient)
return !util.Contains(u.Filters.WebClient, sdk.WebClientPubKeyChangeDisabled)
}
// CanAddFilesFromWeb returns true if the client can add files from the web UI.
// The specified target is the directory where the files must be uploaded
func (u *User) CanAddFilesFromWeb(target string) bool {
if util.IsStringInSlice(sdk.WebClientWriteDisabled, u.Filters.WebClient) {
if util.Contains(u.Filters.WebClient, sdk.WebClientWriteDisabled) {
return false
}
return u.HasPerm(PermUpload, target) || u.HasPerm(PermOverwrite, target)
@@ -1028,7 +1028,7 @@ func (u *User) CanAddFilesFromWeb(target string) bool {
// CanAddDirsFromWeb returns true if the client can add directories from the web UI.
// The specified target is the directory where the new directory must be created
func (u *User) CanAddDirsFromWeb(target string) bool {
if util.IsStringInSlice(sdk.WebClientWriteDisabled, u.Filters.WebClient) {
if util.Contains(u.Filters.WebClient, sdk.WebClientWriteDisabled) {
return false
}
return u.HasPerm(PermCreateDirs, target)
@@ -1037,7 +1037,7 @@ func (u *User) CanAddDirsFromWeb(target string) bool {
// CanRenameFromWeb returns true if the client can rename objects from the web UI.
// The specified src and dest are the source and target directories for the rename.
func (u *User) CanRenameFromWeb(src, dest string) bool {
if util.IsStringInSlice(sdk.WebClientWriteDisabled, u.Filters.WebClient) {
if util.Contains(u.Filters.WebClient, sdk.WebClientWriteDisabled) {
return false
}
return u.HasAnyPerm(permsRenameAny, src) && u.HasAnyPerm(permsRenameAny, dest)
@@ -1046,7 +1046,7 @@ func (u *User) CanRenameFromWeb(src, dest string) bool {
// CanDeleteFromWeb returns true if the client can delete objects from the web UI.
// The specified target is the parent directory for the object to delete
func (u *User) CanDeleteFromWeb(target string) bool {
if util.IsStringInSlice(sdk.WebClientWriteDisabled, u.Filters.WebClient) {
if util.Contains(u.Filters.WebClient, sdk.WebClientWriteDisabled) {
return false
}
return u.HasAnyPerm(permsDeleteAny, target)
@@ -1059,7 +1059,7 @@ func (u *User) MustSetSecondFactor() bool {
return true
}
for _, p := range u.Filters.TwoFactorAuthProtocols {
if !util.IsStringInSlice(p, u.Filters.TOTPConfig.Protocols) {
if !util.Contains(u.Filters.TOTPConfig.Protocols, p) {
return true
}
}
@@ -1070,11 +1070,11 @@ func (u *User) MustSetSecondFactor() bool {
// MustSetSecondFactorForProtocol returns true if the user must set a second factor authentication
// for the specified protocol
func (u *User) MustSetSecondFactorForProtocol(protocol string) bool {
if util.IsStringInSlice(protocol, u.Filters.TwoFactorAuthProtocols) {
if util.Contains(u.Filters.TwoFactorAuthProtocols, protocol) {
if !u.Filters.TOTPConfig.Enabled {
return true
}
if !util.IsStringInSlice(protocol, u.Filters.TOTPConfig.Protocols) {
if !util.Contains(u.Filters.TOTPConfig.Protocols, protocol) {
return true
}
}