mirror of
https://github.com/drakkan/sftpgo.git
synced 2024-11-22 07:30:25 +00:00
4e41a5583d
The common package defines the interfaces that a protocol must implement and contain code that can be shared among supported protocols. This way should be easier to support new protocols
675 lines
18 KiB
Go
675 lines
18 KiB
Go
package dataprovider
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/drakkan/sftpgo/logger"
|
|
"github.com/drakkan/sftpgo/utils"
|
|
"github.com/drakkan/sftpgo/vfs"
|
|
)
|
|
|
|
var (
|
|
errMemoryProviderClosed = errors.New("memory provider is closed")
|
|
)
|
|
|
|
type memoryProviderHandle struct {
|
|
// configuration file to use for loading users
|
|
configFile string
|
|
sync.Mutex
|
|
isClosed bool
|
|
// slice with ordered usernames
|
|
usernames []string
|
|
// mapping between ID and username
|
|
usersIdx map[int64]string
|
|
// map for users, username is the key
|
|
users map[string]User
|
|
// map for virtual folders, MappedPath is the key
|
|
vfolders map[string]vfs.BaseVirtualFolder
|
|
// slice with ordered folders mapped path
|
|
vfoldersPaths []string
|
|
}
|
|
|
|
// MemoryProvider auth provider for a memory store
|
|
type MemoryProvider struct {
|
|
dbHandle *memoryProviderHandle
|
|
}
|
|
|
|
func initializeMemoryProvider(basePath string) error {
|
|
logSender = fmt.Sprintf("dataprovider_%v", MemoryDataProviderName)
|
|
configFile := ""
|
|
if utils.IsFileInputValid(config.Name) {
|
|
configFile = config.Name
|
|
if !filepath.IsAbs(configFile) {
|
|
configFile = filepath.Join(basePath, configFile)
|
|
}
|
|
}
|
|
provider = MemoryProvider{
|
|
dbHandle: &memoryProviderHandle{
|
|
isClosed: false,
|
|
usernames: []string{},
|
|
usersIdx: make(map[int64]string),
|
|
users: make(map[string]User),
|
|
vfolders: make(map[string]vfs.BaseVirtualFolder),
|
|
vfoldersPaths: []string{},
|
|
configFile: configFile,
|
|
},
|
|
}
|
|
return provider.reloadConfig()
|
|
}
|
|
|
|
func (p MemoryProvider) checkAvailability() error {
|
|
p.dbHandle.Lock()
|
|
defer p.dbHandle.Unlock()
|
|
if p.dbHandle.isClosed {
|
|
return errMemoryProviderClosed
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (p MemoryProvider) close() error {
|
|
p.dbHandle.Lock()
|
|
defer p.dbHandle.Unlock()
|
|
if p.dbHandle.isClosed {
|
|
return errMemoryProviderClosed
|
|
}
|
|
p.dbHandle.isClosed = true
|
|
return nil
|
|
}
|
|
|
|
func (p MemoryProvider) validateUserAndPass(username string, password string) (User, error) {
|
|
var user User
|
|
if len(password) == 0 {
|
|
return user, errors.New("Credentials cannot be null or empty")
|
|
}
|
|
user, err := p.userExists(username)
|
|
if err != nil {
|
|
providerLog(logger.LevelWarn, "error authenticating user %#v, error: %v", username, err)
|
|
return user, err
|
|
}
|
|
return checkUserAndPass(user, password)
|
|
}
|
|
|
|
func (p MemoryProvider) validateUserAndPubKey(username string, pubKey []byte) (User, string, error) {
|
|
var user User
|
|
if len(pubKey) == 0 {
|
|
return user, "", errors.New("Credentials cannot be null or empty")
|
|
}
|
|
user, err := p.userExists(username)
|
|
if err != nil {
|
|
providerLog(logger.LevelWarn, "error authenticating user %#v, error: %v", username, err)
|
|
return user, "", err
|
|
}
|
|
return checkUserAndPubKey(user, pubKey)
|
|
}
|
|
|
|
func (p MemoryProvider) getUserByID(ID int64) (User, error) {
|
|
p.dbHandle.Lock()
|
|
defer p.dbHandle.Unlock()
|
|
if p.dbHandle.isClosed {
|
|
return User{}, errMemoryProviderClosed
|
|
}
|
|
if val, ok := p.dbHandle.usersIdx[ID]; ok {
|
|
return p.userExistsInternal(val)
|
|
}
|
|
return User{}, &RecordNotFoundError{err: fmt.Sprintf("user with ID %v does not exist", ID)}
|
|
}
|
|
|
|
func (p MemoryProvider) updateLastLogin(username string) error {
|
|
p.dbHandle.Lock()
|
|
defer p.dbHandle.Unlock()
|
|
if p.dbHandle.isClosed {
|
|
return errMemoryProviderClosed
|
|
}
|
|
user, err := p.userExistsInternal(username)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
user.LastLogin = utils.GetTimeAsMsSinceEpoch(time.Now())
|
|
p.dbHandle.users[user.Username] = user
|
|
return nil
|
|
}
|
|
|
|
func (p MemoryProvider) updateQuota(username string, filesAdd int, sizeAdd int64, reset bool) error {
|
|
p.dbHandle.Lock()
|
|
defer p.dbHandle.Unlock()
|
|
if p.dbHandle.isClosed {
|
|
return errMemoryProviderClosed
|
|
}
|
|
user, err := p.userExistsInternal(username)
|
|
if err != nil {
|
|
providerLog(logger.LevelWarn, "unable to update quota for user %#v error: %v", username, err)
|
|
return err
|
|
}
|
|
if reset {
|
|
user.UsedQuotaSize = sizeAdd
|
|
user.UsedQuotaFiles = filesAdd
|
|
} else {
|
|
user.UsedQuotaSize += sizeAdd
|
|
user.UsedQuotaFiles += filesAdd
|
|
}
|
|
user.LastQuotaUpdate = utils.GetTimeAsMsSinceEpoch(time.Now())
|
|
providerLog(logger.LevelDebug, "quota updated for user %#v, files increment: %v size increment: %v is reset? %v",
|
|
username, filesAdd, sizeAdd, reset)
|
|
p.dbHandle.users[user.Username] = user
|
|
return nil
|
|
}
|
|
|
|
func (p MemoryProvider) getUsedQuota(username string) (int, int64, error) {
|
|
p.dbHandle.Lock()
|
|
defer p.dbHandle.Unlock()
|
|
if p.dbHandle.isClosed {
|
|
return 0, 0, errMemoryProviderClosed
|
|
}
|
|
user, err := p.userExistsInternal(username)
|
|
if err != nil {
|
|
providerLog(logger.LevelWarn, "unable to get quota for user %#v error: %v", username, err)
|
|
return 0, 0, err
|
|
}
|
|
return user.UsedQuotaFiles, user.UsedQuotaSize, err
|
|
}
|
|
|
|
func (p MemoryProvider) addUser(user User) error {
|
|
p.dbHandle.Lock()
|
|
defer p.dbHandle.Unlock()
|
|
if p.dbHandle.isClosed {
|
|
return errMemoryProviderClosed
|
|
}
|
|
err := validateUser(&user)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = p.userExistsInternal(user.Username)
|
|
if err == nil {
|
|
return fmt.Errorf("username %#v already exists", user.Username)
|
|
}
|
|
user.ID = p.getNextID()
|
|
user.LastQuotaUpdate = 0
|
|
user.UsedQuotaSize = 0
|
|
user.UsedQuotaFiles = 0
|
|
user.LastLogin = 0
|
|
user.VirtualFolders = p.joinVirtualFoldersFields(user)
|
|
p.dbHandle.users[user.Username] = user
|
|
p.dbHandle.usersIdx[user.ID] = user.Username
|
|
p.dbHandle.usernames = append(p.dbHandle.usernames, user.Username)
|
|
sort.Strings(p.dbHandle.usernames)
|
|
return nil
|
|
}
|
|
|
|
func (p MemoryProvider) updateUser(user User) error {
|
|
p.dbHandle.Lock()
|
|
defer p.dbHandle.Unlock()
|
|
if p.dbHandle.isClosed {
|
|
return errMemoryProviderClosed
|
|
}
|
|
err := validateUser(&user)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
u, err := p.userExistsInternal(user.Username)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, oldFolder := range u.VirtualFolders {
|
|
p.removeUserFromFolderMapping(oldFolder.MappedPath, u.Username)
|
|
}
|
|
user.VirtualFolders = p.joinVirtualFoldersFields(user)
|
|
user.LastQuotaUpdate = u.LastQuotaUpdate
|
|
user.UsedQuotaSize = u.UsedQuotaSize
|
|
user.UsedQuotaFiles = u.UsedQuotaFiles
|
|
user.LastLogin = u.LastLogin
|
|
p.dbHandle.users[user.Username] = user
|
|
return nil
|
|
}
|
|
|
|
func (p MemoryProvider) deleteUser(user User) error {
|
|
p.dbHandle.Lock()
|
|
defer p.dbHandle.Unlock()
|
|
if p.dbHandle.isClosed {
|
|
return errMemoryProviderClosed
|
|
}
|
|
u, err := p.userExistsInternal(user.Username)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, oldFolder := range u.VirtualFolders {
|
|
p.removeUserFromFolderMapping(oldFolder.MappedPath, u.Username)
|
|
}
|
|
delete(p.dbHandle.users, user.Username)
|
|
delete(p.dbHandle.usersIdx, user.ID)
|
|
// this could be more efficient
|
|
p.dbHandle.usernames = []string{}
|
|
for username := range p.dbHandle.users {
|
|
p.dbHandle.usernames = append(p.dbHandle.usernames, username)
|
|
}
|
|
sort.Strings(p.dbHandle.usernames)
|
|
return nil
|
|
}
|
|
|
|
func (p MemoryProvider) dumpUsers() ([]User, error) {
|
|
p.dbHandle.Lock()
|
|
defer p.dbHandle.Unlock()
|
|
users := make([]User, 0, len(p.dbHandle.usernames))
|
|
var err error
|
|
if p.dbHandle.isClosed {
|
|
return users, errMemoryProviderClosed
|
|
}
|
|
for _, username := range p.dbHandle.usernames {
|
|
user := p.dbHandle.users[username]
|
|
err = addCredentialsToUser(&user)
|
|
if err != nil {
|
|
return users, err
|
|
}
|
|
users = append(users, user)
|
|
}
|
|
return users, err
|
|
}
|
|
|
|
func (p MemoryProvider) dumpFolders() ([]vfs.BaseVirtualFolder, error) {
|
|
p.dbHandle.Lock()
|
|
defer p.dbHandle.Unlock()
|
|
folders := make([]vfs.BaseVirtualFolder, 0, len(p.dbHandle.vfoldersPaths))
|
|
if p.dbHandle.isClosed {
|
|
return folders, errMemoryProviderClosed
|
|
}
|
|
for _, f := range p.dbHandle.vfolders {
|
|
folders = append(folders, f)
|
|
}
|
|
return folders, nil
|
|
}
|
|
|
|
func (p MemoryProvider) getUsers(limit int, offset int, order string, username string) ([]User, error) {
|
|
users := make([]User, 0, limit)
|
|
var err error
|
|
p.dbHandle.Lock()
|
|
defer p.dbHandle.Unlock()
|
|
if p.dbHandle.isClosed {
|
|
return users, errMemoryProviderClosed
|
|
}
|
|
if limit <= 0 {
|
|
return users, err
|
|
}
|
|
if len(username) > 0 {
|
|
if offset == 0 {
|
|
user, err := p.userExistsInternal(username)
|
|
if err == nil {
|
|
users = append(users, HideUserSensitiveData(&user))
|
|
}
|
|
}
|
|
return users, err
|
|
}
|
|
itNum := 0
|
|
if order == OrderASC {
|
|
for _, username := range p.dbHandle.usernames {
|
|
itNum++
|
|
if itNum <= offset {
|
|
continue
|
|
}
|
|
user := p.dbHandle.users[username]
|
|
users = append(users, HideUserSensitiveData(&user))
|
|
if len(users) >= limit {
|
|
break
|
|
}
|
|
}
|
|
} else {
|
|
for i := len(p.dbHandle.usernames) - 1; i >= 0; i-- {
|
|
itNum++
|
|
if itNum <= offset {
|
|
continue
|
|
}
|
|
username := p.dbHandle.usernames[i]
|
|
user := p.dbHandle.users[username]
|
|
users = append(users, HideUserSensitiveData(&user))
|
|
if len(users) >= limit {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
return users, err
|
|
}
|
|
|
|
func (p MemoryProvider) userExists(username string) (User, error) {
|
|
p.dbHandle.Lock()
|
|
defer p.dbHandle.Unlock()
|
|
if p.dbHandle.isClosed {
|
|
return User{}, errMemoryProviderClosed
|
|
}
|
|
return p.userExistsInternal(username)
|
|
}
|
|
|
|
func (p MemoryProvider) userExistsInternal(username string) (User, error) {
|
|
if val, ok := p.dbHandle.users[username]; ok {
|
|
return val.getACopy(), nil
|
|
}
|
|
return User{}, &RecordNotFoundError{err: fmt.Sprintf("username %#v does not exist", username)}
|
|
}
|
|
|
|
func (p MemoryProvider) updateFolderQuota(mappedPath string, filesAdd int, sizeAdd int64, reset bool) error {
|
|
p.dbHandle.Lock()
|
|
defer p.dbHandle.Unlock()
|
|
if p.dbHandle.isClosed {
|
|
return errMemoryProviderClosed
|
|
}
|
|
folder, err := p.folderExistsInternal(mappedPath)
|
|
if err != nil {
|
|
providerLog(logger.LevelWarn, "unable to update quota for folder %#v error: %v", mappedPath, err)
|
|
return err
|
|
}
|
|
if reset {
|
|
folder.UsedQuotaSize = sizeAdd
|
|
folder.UsedQuotaFiles = filesAdd
|
|
} else {
|
|
folder.UsedQuotaSize += sizeAdd
|
|
folder.UsedQuotaFiles += filesAdd
|
|
}
|
|
folder.LastQuotaUpdate = utils.GetTimeAsMsSinceEpoch(time.Now())
|
|
p.dbHandle.vfolders[mappedPath] = folder
|
|
return nil
|
|
}
|
|
|
|
func (p MemoryProvider) getUsedFolderQuota(mappedPath string) (int, int64, error) {
|
|
p.dbHandle.Lock()
|
|
defer p.dbHandle.Unlock()
|
|
if p.dbHandle.isClosed {
|
|
return 0, 0, errMemoryProviderClosed
|
|
}
|
|
folder, err := p.folderExistsInternal(mappedPath)
|
|
if err != nil {
|
|
providerLog(logger.LevelWarn, "unable to get quota for folder %#v error: %v", mappedPath, err)
|
|
return 0, 0, err
|
|
}
|
|
return folder.UsedQuotaFiles, folder.UsedQuotaSize, err
|
|
}
|
|
|
|
func (p MemoryProvider) joinVirtualFoldersFields(user User) []vfs.VirtualFolder {
|
|
var folders []vfs.VirtualFolder
|
|
for _, folder := range user.VirtualFolders {
|
|
f, err := p.addOrGetFolderInternal(folder.MappedPath, user.Username, folder.UsedQuotaSize, folder.UsedQuotaFiles,
|
|
folder.LastQuotaUpdate)
|
|
if err == nil {
|
|
folder.UsedQuotaFiles = f.UsedQuotaFiles
|
|
folder.UsedQuotaSize = f.UsedQuotaSize
|
|
folder.LastQuotaUpdate = f.LastQuotaUpdate
|
|
folder.ID = f.ID
|
|
folders = append(folders, folder)
|
|
}
|
|
}
|
|
return folders
|
|
}
|
|
|
|
func (p MemoryProvider) removeUserFromFolderMapping(mappedPath, username string) {
|
|
folder, err := p.folderExistsInternal(mappedPath)
|
|
if err == nil {
|
|
var usernames []string
|
|
for _, user := range folder.Users {
|
|
if user != username {
|
|
usernames = append(usernames, user)
|
|
}
|
|
}
|
|
folder.Users = usernames
|
|
p.dbHandle.vfolders[folder.MappedPath] = folder
|
|
}
|
|
}
|
|
|
|
func (p MemoryProvider) updateFoldersMappingInternal(folder vfs.BaseVirtualFolder) {
|
|
p.dbHandle.vfolders[folder.MappedPath] = folder
|
|
if !utils.IsStringInSlice(folder.MappedPath, p.dbHandle.vfoldersPaths) {
|
|
p.dbHandle.vfoldersPaths = append(p.dbHandle.vfoldersPaths, folder.MappedPath)
|
|
sort.Strings(p.dbHandle.vfoldersPaths)
|
|
}
|
|
}
|
|
|
|
func (p MemoryProvider) addOrGetFolderInternal(mappedPath, username string, usedQuotaSize int64, usedQuotaFiles int, lastQuotaUpdate int64) (vfs.BaseVirtualFolder, error) {
|
|
folder, err := p.folderExistsInternal(mappedPath)
|
|
if _, ok := err.(*RecordNotFoundError); ok {
|
|
folder := vfs.BaseVirtualFolder{
|
|
ID: p.getNextFolderID(),
|
|
MappedPath: mappedPath,
|
|
UsedQuotaSize: usedQuotaSize,
|
|
UsedQuotaFiles: usedQuotaFiles,
|
|
LastQuotaUpdate: lastQuotaUpdate,
|
|
Users: []string{username},
|
|
}
|
|
p.updateFoldersMappingInternal(folder)
|
|
return folder, nil
|
|
}
|
|
if err == nil && !utils.IsStringInSlice(username, folder.Users) {
|
|
folder.Users = append(folder.Users, username)
|
|
p.updateFoldersMappingInternal(folder)
|
|
}
|
|
return folder, err
|
|
}
|
|
|
|
func (p MemoryProvider) folderExistsInternal(mappedPath string) (vfs.BaseVirtualFolder, error) {
|
|
if val, ok := p.dbHandle.vfolders[mappedPath]; ok {
|
|
return val, nil
|
|
}
|
|
return vfs.BaseVirtualFolder{}, &RecordNotFoundError{err: fmt.Sprintf("folder %#v does not exist", mappedPath)}
|
|
}
|
|
|
|
func (p MemoryProvider) getFolders(limit, offset int, order, folderPath string) ([]vfs.BaseVirtualFolder, error) {
|
|
folders := make([]vfs.BaseVirtualFolder, 0, limit)
|
|
var err error
|
|
p.dbHandle.Lock()
|
|
defer p.dbHandle.Unlock()
|
|
if p.dbHandle.isClosed {
|
|
return folders, errMemoryProviderClosed
|
|
}
|
|
if limit <= 0 {
|
|
return folders, err
|
|
}
|
|
if len(folderPath) > 0 {
|
|
if offset == 0 {
|
|
var folder vfs.BaseVirtualFolder
|
|
folder, err = p.folderExistsInternal(folderPath)
|
|
if err == nil {
|
|
folders = append(folders, folder)
|
|
}
|
|
}
|
|
return folders, err
|
|
}
|
|
itNum := 0
|
|
if order == OrderASC {
|
|
for _, mappedPath := range p.dbHandle.vfoldersPaths {
|
|
itNum++
|
|
if itNum <= offset {
|
|
continue
|
|
}
|
|
folder := p.dbHandle.vfolders[mappedPath]
|
|
folders = append(folders, folder)
|
|
if len(folders) >= limit {
|
|
break
|
|
}
|
|
}
|
|
} else {
|
|
for i := len(p.dbHandle.vfoldersPaths) - 1; i >= 0; i-- {
|
|
itNum++
|
|
if itNum <= offset {
|
|
continue
|
|
}
|
|
mappedPath := p.dbHandle.vfoldersPaths[i]
|
|
folder := p.dbHandle.vfolders[mappedPath]
|
|
folders = append(folders, folder)
|
|
if len(folders) >= limit {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
return folders, err
|
|
}
|
|
|
|
func (p MemoryProvider) getFolderByPath(mappedPath string) (vfs.BaseVirtualFolder, error) {
|
|
p.dbHandle.Lock()
|
|
defer p.dbHandle.Unlock()
|
|
if p.dbHandle.isClosed {
|
|
return vfs.BaseVirtualFolder{}, errMemoryProviderClosed
|
|
}
|
|
return p.folderExistsInternal(mappedPath)
|
|
}
|
|
|
|
func (p MemoryProvider) addFolder(folder vfs.BaseVirtualFolder) error {
|
|
p.dbHandle.Lock()
|
|
defer p.dbHandle.Unlock()
|
|
if p.dbHandle.isClosed {
|
|
return errMemoryProviderClosed
|
|
}
|
|
err := validateFolder(&folder)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = p.folderExistsInternal(folder.MappedPath)
|
|
if err == nil {
|
|
return fmt.Errorf("folder %#v already exists", folder.MappedPath)
|
|
}
|
|
folder.ID = p.getNextFolderID()
|
|
p.dbHandle.vfolders[folder.MappedPath] = folder
|
|
p.dbHandle.vfoldersPaths = append(p.dbHandle.vfoldersPaths, folder.MappedPath)
|
|
sort.Strings(p.dbHandle.vfoldersPaths)
|
|
return nil
|
|
}
|
|
|
|
func (p MemoryProvider) deleteFolder(folder vfs.BaseVirtualFolder) error {
|
|
p.dbHandle.Lock()
|
|
defer p.dbHandle.Unlock()
|
|
if p.dbHandle.isClosed {
|
|
return errMemoryProviderClosed
|
|
}
|
|
|
|
_, err := p.folderExistsInternal(folder.MappedPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, username := range folder.Users {
|
|
user, err := p.userExistsInternal(username)
|
|
if err == nil {
|
|
var folders []vfs.VirtualFolder
|
|
for _, userFolder := range user.VirtualFolders {
|
|
if folder.MappedPath != userFolder.MappedPath {
|
|
folders = append(folders, userFolder)
|
|
}
|
|
}
|
|
user.VirtualFolders = folders
|
|
p.dbHandle.users[user.Username] = user
|
|
}
|
|
}
|
|
delete(p.dbHandle.vfolders, folder.MappedPath)
|
|
p.dbHandle.vfoldersPaths = []string{}
|
|
for mappedPath := range p.dbHandle.vfolders {
|
|
p.dbHandle.vfoldersPaths = append(p.dbHandle.vfoldersPaths, mappedPath)
|
|
}
|
|
sort.Strings(p.dbHandle.vfoldersPaths)
|
|
return nil
|
|
}
|
|
|
|
func (p MemoryProvider) getNextID() int64 {
|
|
nextID := int64(1)
|
|
for id := range p.dbHandle.usersIdx {
|
|
if id >= nextID {
|
|
nextID = id + 1
|
|
}
|
|
}
|
|
return nextID
|
|
}
|
|
|
|
func (p MemoryProvider) getNextFolderID() int64 {
|
|
nextID := int64(1)
|
|
for _, v := range p.dbHandle.vfolders {
|
|
if v.ID >= nextID {
|
|
nextID = v.ID + 1
|
|
}
|
|
}
|
|
return nextID
|
|
}
|
|
|
|
func (p MemoryProvider) clear() {
|
|
p.dbHandle.Lock()
|
|
defer p.dbHandle.Unlock()
|
|
p.dbHandle.usernames = []string{}
|
|
p.dbHandle.usersIdx = make(map[int64]string)
|
|
p.dbHandle.users = make(map[string]User)
|
|
p.dbHandle.vfoldersPaths = []string{}
|
|
p.dbHandle.vfolders = make(map[string]vfs.BaseVirtualFolder)
|
|
}
|
|
|
|
func (p MemoryProvider) reloadConfig() error {
|
|
if len(p.dbHandle.configFile) == 0 {
|
|
providerLog(logger.LevelDebug, "no users configuration file defined")
|
|
return nil
|
|
}
|
|
providerLog(logger.LevelDebug, "loading users from file: %#v", p.dbHandle.configFile)
|
|
fi, err := os.Stat(p.dbHandle.configFile)
|
|
if err != nil {
|
|
providerLog(logger.LevelWarn, "error loading users: %v", err)
|
|
return err
|
|
}
|
|
if fi.Size() == 0 {
|
|
err = errors.New("users configuration file is invalid, its size must be > 0")
|
|
providerLog(logger.LevelWarn, "error loading users: %v", err)
|
|
return err
|
|
}
|
|
if fi.Size() > 10485760 {
|
|
err = errors.New("users configuration file is invalid, its size must be <= 10485760 bytes")
|
|
providerLog(logger.LevelWarn, "error loading users: %v", err)
|
|
return err
|
|
}
|
|
content, err := ioutil.ReadFile(p.dbHandle.configFile)
|
|
if err != nil {
|
|
providerLog(logger.LevelWarn, "error loading users: %v", err)
|
|
return err
|
|
}
|
|
var dump BackupData
|
|
err = json.Unmarshal(content, &dump)
|
|
if err != nil {
|
|
providerLog(logger.LevelWarn, "error loading users: %v", err)
|
|
return err
|
|
}
|
|
p.clear()
|
|
for _, folder := range dump.Folders {
|
|
_, err := p.getFolderByPath(folder.MappedPath)
|
|
if err == nil {
|
|
logger.Debug(logSender, "", "folder %#v already exists, restore not needed", folder.MappedPath)
|
|
continue
|
|
}
|
|
folder.Users = nil
|
|
err = p.addFolder(folder)
|
|
if err != nil {
|
|
providerLog(logger.LevelWarn, "error adding folder %#v: %v", folder.MappedPath, err)
|
|
return err
|
|
}
|
|
}
|
|
for _, user := range dump.Users {
|
|
u, err := p.userExists(user.Username)
|
|
if err == nil {
|
|
user.ID = u.ID
|
|
err = p.updateUser(user)
|
|
if err != nil {
|
|
providerLog(logger.LevelWarn, "error updating user %#v: %v", user.Username, err)
|
|
return err
|
|
}
|
|
} else {
|
|
err = p.addUser(user)
|
|
if err != nil {
|
|
providerLog(logger.LevelWarn, "error adding user %#v: %v", user.Username, err)
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
providerLog(logger.LevelDebug, "user and folders loaded from file: %#v", p.dbHandle.configFile)
|
|
return nil
|
|
}
|
|
|
|
// initializeDatabase does nothing, no initilization is needed for memory provider
|
|
func (p MemoryProvider) initializeDatabase() error {
|
|
return errNoInitRequired
|
|
}
|
|
|
|
func (p MemoryProvider) migrateDatabase() error {
|
|
return nil
|
|
}
|