mirror of
https://github.com/drakkan/sftpgo.git
synced 2024-04-21 12:32:38 +00:00
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:
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user