mirror of
https://github.com/drakkan/sftpgo.git
synced 2024-11-21 23:20:24 +00:00
squash database migrations and remove compat code
This commit is contained in:
parent
41e1d9e68a
commit
49830516be
13 changed files with 208 additions and 2013 deletions
29
README.md
29
README.md
|
@ -120,27 +120,42 @@ sftpgo initprovider --help
|
|||
|
||||
You can disable automatic data provider checks/updates at startup by setting the `update_mode` configuration key to `1`.
|
||||
|
||||
## Upgrading
|
||||
|
||||
SFTPGo supports upgrading from the previous release branch to the current one.
|
||||
Some examples for supported upgrade paths are:
|
||||
|
||||
- from 1.2.x to 2.0.x
|
||||
- from 2.0.x to 2.1.x and so on.
|
||||
|
||||
For supported upgrade paths, the data and schema are migrated automatically, alternately you can use the `initprovider` command.
|
||||
|
||||
So if, for example, you want to upgrade from a version before 1.2.x to 2.0.x, you must first install version 1.2.x, update the data provider and finally install the version 2.0.x. It is recommended to always install the latest available minor version, ie do not install 1.2.0 if 1.2.2 is available.
|
||||
|
||||
Loading data from a provider independent JSON dump is supported from the previous release branch to the current one too. After updating SFTPGo it is advisable to load the old dump and regenerate it from the new version.
|
||||
|
||||
## Downgrading
|
||||
|
||||
If for some reason you want to downgrade SFTPGo, you may need to downgrade your data provider schema and data as well. You can use the `revertprovider` command for this task.
|
||||
|
||||
We support the follwing schema versions:
|
||||
As for upgrading, SFTPGo supports downgrading from the previous release branch to the current one.
|
||||
|
||||
- `8`, this is the latest version
|
||||
- `4`, this is the schema for v1.0.0-v1.2.x
|
||||
|
||||
So, if you plan to downgrade from 2.0.x to 1.2.x, you can prepare your data provider executing the following command from the configuration directory:
|
||||
So, if you plan to downgrade from 2.0.x to 1.2.x, before uninstalling 2.0.x version, you can prepare your data provider executing the following command from the configuration directory:
|
||||
|
||||
```shell
|
||||
sftpgo revertprovider --to-version 4
|
||||
```
|
||||
|
||||
Take a look at the CLI usage to learn how to specify a different configuration file:
|
||||
Take a look at the CLI usage to see the supported parameter for the `--to-version` argument and to learn how to specify a different configuration file:
|
||||
|
||||
```bash
|
||||
```shell
|
||||
sftpgo revertprovider --help
|
||||
```
|
||||
|
||||
The `revertprovider` command is not supported for the memory provider.
|
||||
|
||||
Please note that we only support the current release branch and the current main branch, if you find a bug it is better to report it rather than downgrading to an older unsupported version.
|
||||
|
||||
## Users and folders management
|
||||
|
||||
After starting SFTPGo you can manage users and folders using:
|
||||
|
|
|
@ -26,8 +26,8 @@ Please take a look at the usage below to customize the options.`,
|
|||
Run: func(cmd *cobra.Command, args []string) {
|
||||
logger.DisableLogger()
|
||||
logger.EnableConsoleLogger(zerolog.DebugLevel)
|
||||
if revertProviderTargetVersion != 4 {
|
||||
logger.WarnToConsole("Unsupported target version, 4 is the only supported one")
|
||||
if revertProviderTargetVersion != 8 {
|
||||
logger.WarnToConsole("Unsupported target version, 8 is the only supported one")
|
||||
os.Exit(1)
|
||||
}
|
||||
configDir = utils.CleanDirInput(configDir)
|
||||
|
@ -57,7 +57,7 @@ Please take a look at the usage below to customize the options.`,
|
|||
|
||||
func init() {
|
||||
addConfigFlags(revertProviderCmd)
|
||||
revertProviderCmd.Flags().IntVar(&revertProviderTargetVersion, "to-version", 0, `4 means the version supported in v1.0.0-v1.2.x`)
|
||||
revertProviderCmd.Flags().IntVar(&revertProviderTargetVersion, "to-version", 0, `8 means the version supported in v2.0.x`)
|
||||
revertProviderCmd.MarkFlagRequired("to-version") //nolint:errcheck
|
||||
|
||||
rootCmd.AddCommand(revertProviderCmd)
|
||||
|
|
|
@ -836,30 +836,24 @@ func (p *BoltProvider) migrateDatabase() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dbVersion.Version == boltDatabaseVersion {
|
||||
providerLog(logger.LevelDebug, "bolt database is up to date, current version: %v", dbVersion.Version)
|
||||
switch version := dbVersion.Version; {
|
||||
case version == boltDatabaseVersion:
|
||||
providerLog(logger.LevelDebug, "bolt database is up to date, current version: %v", version)
|
||||
return ErrNoInitRequired
|
||||
}
|
||||
switch dbVersion.Version {
|
||||
case 1:
|
||||
return updateBoltDatabaseFromV1(p.dbHandle)
|
||||
case 2:
|
||||
return updateBoltDatabaseFromV2(p.dbHandle)
|
||||
case 3:
|
||||
return updateBoltDatabaseFromV3(p.dbHandle)
|
||||
case 4:
|
||||
return updateBoltDatabaseFromV4(p.dbHandle)
|
||||
case 5:
|
||||
return updateBoltDatabaseFromV5(p.dbHandle)
|
||||
case version < 6:
|
||||
err = fmt.Errorf("database version %v is too old, please see the upgrading docs", version)
|
||||
providerLog(logger.LevelError, "%v", err)
|
||||
logger.ErrorToConsole("%v", err)
|
||||
return err
|
||||
default:
|
||||
if dbVersion.Version > boltDatabaseVersion {
|
||||
providerLog(logger.LevelWarn, "database version %v is newer than the supported: %v", dbVersion.Version,
|
||||
if version > boltDatabaseVersion {
|
||||
providerLog(logger.LevelWarn, "database version %v is newer than the supported one: %v", version,
|
||||
boltDatabaseVersion)
|
||||
logger.WarnToConsole("database version %v is newer than the supported: %v", dbVersion.Version,
|
||||
logger.WarnToConsole("database version %v is newer than the supported one: %v", version,
|
||||
boltDatabaseVersion)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Database version not handled: %v", dbVersion.Version)
|
||||
return fmt.Errorf("Database version not handled: %v", version)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -868,57 +862,13 @@ func (p *BoltProvider) revertDatabase(targetVersion int) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if targetVersion == 8 {
|
||||
targetVersion = 6
|
||||
}
|
||||
if dbVersion.Version == targetVersion {
|
||||
return fmt.Errorf("current version match target version, nothing to do")
|
||||
return errors.New("current version match target version, nothing to do")
|
||||
}
|
||||
switch dbVersion.Version {
|
||||
case 5:
|
||||
return downgradeBoltDatabaseFrom5To4(p.dbHandle)
|
||||
case 6:
|
||||
err := downgradeBoltDatabaseFrom6To5(p.dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return downgradeBoltDatabaseFrom5To4(p.dbHandle)
|
||||
default:
|
||||
return fmt.Errorf("Database version not handled: %v", dbVersion.Version)
|
||||
}
|
||||
}
|
||||
|
||||
func updateBoltDatabaseFromV1(dbHandle *bolt.DB) error {
|
||||
err := updateDatabaseFrom1To2(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updateBoltDatabaseFromV2(dbHandle)
|
||||
}
|
||||
|
||||
func updateBoltDatabaseFromV2(dbHandle *bolt.DB) error {
|
||||
err := updateDatabaseFrom2To3(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updateBoltDatabaseFromV3(dbHandle)
|
||||
}
|
||||
|
||||
func updateBoltDatabaseFromV3(dbHandle *bolt.DB) error {
|
||||
err := updateDatabaseFrom3To4(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updateBoltDatabaseFromV4(dbHandle)
|
||||
}
|
||||
|
||||
func updateBoltDatabaseFromV4(dbHandle *bolt.DB) error {
|
||||
err := updateDatabaseFrom4To5(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updateBoltDatabaseFromV5(dbHandle)
|
||||
}
|
||||
|
||||
func updateBoltDatabaseFromV5(dbHandle *bolt.DB) error {
|
||||
return updateDatabaseFrom5To6(dbHandle)
|
||||
return errors.New("the current version cannot be reverted")
|
||||
}
|
||||
|
||||
func joinUserAndFolders(u []byte, foldersBucket *bolt.Bucket) (User, error) {
|
||||
|
@ -1029,44 +979,6 @@ func removeUserFromFolderMapping(folder vfs.VirtualFolder, user *User, bucket *b
|
|||
return err
|
||||
}
|
||||
|
||||
func updateV4BoltCompatUser(dbHandle *bolt.DB, user compatUserV4) error {
|
||||
return dbHandle.Update(func(tx *bolt.Tx) error {
|
||||
bucket, err := getUsersBucket(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if u := bucket.Get([]byte(user.Username)); u == nil {
|
||||
return &RecordNotFoundError{err: fmt.Sprintf("username %v does not exist", user.Username)}
|
||||
}
|
||||
buf, err := json.Marshal(user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return bucket.Put([]byte(user.Username), buf)
|
||||
})
|
||||
}
|
||||
|
||||
func updateV4BoltUser(dbHandle *bolt.DB, user User) error {
|
||||
err := ValidateUser(&user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return dbHandle.Update(func(tx *bolt.Tx) error {
|
||||
bucket, err := getUsersBucket(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if u := bucket.Get([]byte(user.Username)); u == nil {
|
||||
return &RecordNotFoundError{err: fmt.Sprintf("username %v does not exist", user.Username)}
|
||||
}
|
||||
buf, err := json.Marshal(user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return bucket.Put([]byte(user.Username), buf)
|
||||
})
|
||||
}
|
||||
|
||||
func getAdminBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
|
||||
var err error
|
||||
|
||||
|
@ -1095,367 +1007,6 @@ func getFolderBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
|
|||
return bucket, err
|
||||
}
|
||||
|
||||
func updateDatabaseFrom1To2(dbHandle *bolt.DB) error {
|
||||
logger.InfoToConsole("updating bolt database version: 1 -> 2")
|
||||
providerLog(logger.LevelInfo, "updating bolt database version: 1 -> 2")
|
||||
usernames, err := getBoltAvailableUsernames(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, u := range usernames {
|
||||
user, err := provider.userExists(u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user.Status = 1
|
||||
err = provider.updateUser(&user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
providerLog(logger.LevelInfo, "user %#v updated, \"status\" setted to 1", user.Username)
|
||||
}
|
||||
return updateBoltDatabaseVersion(dbHandle, 2)
|
||||
}
|
||||
|
||||
func updateDatabaseFrom2To3(dbHandle *bolt.DB) error {
|
||||
logger.InfoToConsole("updating bolt database version: 2 -> 3")
|
||||
providerLog(logger.LevelInfo, "updating bolt database version: 2 -> 3")
|
||||
users := []User{}
|
||||
err := dbHandle.View(func(tx *bolt.Tx) error {
|
||||
bucket, err := getUsersBucket(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cursor := bucket.Cursor()
|
||||
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||
var compatUser compatUserV2
|
||||
err = json.Unmarshal(v, &compatUser)
|
||||
if err == nil {
|
||||
user := User{}
|
||||
user.ID = compatUser.ID
|
||||
user.Username = compatUser.Username
|
||||
user.Password = compatUser.Password
|
||||
user.PublicKeys = compatUser.PublicKeys
|
||||
user.HomeDir = compatUser.HomeDir
|
||||
user.UID = compatUser.UID
|
||||
user.GID = compatUser.GID
|
||||
user.MaxSessions = compatUser.MaxSessions
|
||||
user.QuotaSize = compatUser.QuotaSize
|
||||
user.QuotaFiles = compatUser.QuotaFiles
|
||||
user.Permissions = make(map[string][]string)
|
||||
user.Permissions["/"] = compatUser.Permissions
|
||||
user.UsedQuotaSize = compatUser.UsedQuotaSize
|
||||
user.UsedQuotaFiles = compatUser.UsedQuotaFiles
|
||||
user.LastQuotaUpdate = compatUser.LastQuotaUpdate
|
||||
user.UploadBandwidth = compatUser.UploadBandwidth
|
||||
user.DownloadBandwidth = compatUser.DownloadBandwidth
|
||||
user.ExpirationDate = compatUser.ExpirationDate
|
||||
user.LastLogin = compatUser.LastLogin
|
||||
user.Status = compatUser.Status
|
||||
users = append(users, user)
|
||||
}
|
||||
}
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, user := range users {
|
||||
user := user
|
||||
err = provider.updateUser(&user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
providerLog(logger.LevelInfo, "user %#v updated, \"permissions\" setted to %+v", user.Username, user.Permissions)
|
||||
}
|
||||
|
||||
return updateBoltDatabaseVersion(dbHandle, 3)
|
||||
}
|
||||
|
||||
func updateDatabaseFrom3To4(dbHandle *bolt.DB) error {
|
||||
logger.InfoToConsole("updating bolt database version: 3 -> 4")
|
||||
providerLog(logger.LevelInfo, "updating bolt database version: 3 -> 4")
|
||||
foldersToScan := []string{}
|
||||
users := []userCompactVFolders{}
|
||||
err := dbHandle.View(func(tx *bolt.Tx) error {
|
||||
bucket, err := getUsersBucket(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cursor := bucket.Cursor()
|
||||
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||
var compatUser userCompactVFolders
|
||||
err = json.Unmarshal(v, &compatUser)
|
||||
if err == nil && len(compatUser.VirtualFolders) > 0 {
|
||||
users = append(users, compatUser)
|
||||
}
|
||||
}
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, u := range users {
|
||||
user, err := provider.userExists(u.Username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var folders []vfs.VirtualFolder
|
||||
for _, f := range u.VirtualFolders {
|
||||
providerLog(logger.LevelInfo, "restoring virtual folder: %+v for user %#v", f, user.Username)
|
||||
quotaSize := int64(-1)
|
||||
quotaFiles := -1
|
||||
if f.ExcludeFromQuota {
|
||||
quotaSize = 0
|
||||
quotaFiles = 0
|
||||
}
|
||||
folder := vfs.VirtualFolder{
|
||||
QuotaSize: quotaSize,
|
||||
QuotaFiles: quotaFiles,
|
||||
VirtualPath: f.VirtualPath,
|
||||
}
|
||||
folder.MappedPath = f.MappedPath
|
||||
folders = append(folders, folder)
|
||||
if !utils.IsStringInSlice(folder.MappedPath, foldersToScan) {
|
||||
foldersToScan = append(foldersToScan, folder.MappedPath)
|
||||
}
|
||||
}
|
||||
user.VirtualFolders = folders
|
||||
err = provider.updateUser(&user)
|
||||
providerLog(logger.LevelInfo, "number of virtual folders to restore %v, user %#v, error: %v", len(user.VirtualFolders),
|
||||
user.Username, err)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return updateBoltDatabaseVersion(dbHandle, 4)
|
||||
/*if err == nil {
|
||||
go updateVFoldersQuotaAfterRestore(foldersToScan)
|
||||
}
|
||||
return err*/
|
||||
}
|
||||
|
||||
//nolint:dupl
|
||||
func downgradeBoltDatabaseFrom5To4(dbHandle *bolt.DB) error {
|
||||
logger.InfoToConsole("downgrading bolt database version: 5 -> 4")
|
||||
providerLog(logger.LevelInfo, "downgrading bolt database version: 5 -> 4")
|
||||
users := []compatUserV4{}
|
||||
err := dbHandle.View(func(tx *bolt.Tx) error {
|
||||
bucket, err := getUsersBucket(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cursor := bucket.Cursor()
|
||||
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||
var user User
|
||||
err = json.Unmarshal(v, &user)
|
||||
if err != nil {
|
||||
logger.WarnToConsole("failed to unmarshal user %#v to v4, is it already migrated?", string(k))
|
||||
continue
|
||||
}
|
||||
fsConfig, err := convertFsConfigToV4(user.FsConfig, user.Username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
users = append(users, convertUserToV4(user, fsConfig))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, user := range users {
|
||||
err = updateV4BoltCompatUser(dbHandle, user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
providerLog(logger.LevelInfo, "filesystem config updated for user %#v", user.Username)
|
||||
}
|
||||
|
||||
return updateBoltDatabaseVersion(dbHandle, 4)
|
||||
}
|
||||
|
||||
//nolint:dupl
|
||||
func updateDatabaseFrom4To5(dbHandle *bolt.DB) error {
|
||||
logger.InfoToConsole("updating bolt database version: 4 -> 5")
|
||||
providerLog(logger.LevelInfo, "updating bolt database version: 4 -> 5")
|
||||
users := []User{}
|
||||
err := dbHandle.View(func(tx *bolt.Tx) error {
|
||||
bucket, err := getUsersBucket(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cursor := bucket.Cursor()
|
||||
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||
var compatUser compatUserV4
|
||||
err = json.Unmarshal(v, &compatUser)
|
||||
if err != nil {
|
||||
logger.WarnToConsole("failed to unmarshal v4 user %#v, is it already migrated?", string(k))
|
||||
continue
|
||||
}
|
||||
fsConfig, err := convertFsConfigFromV4(compatUser.FsConfig, compatUser.Username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
users = append(users, createUserFromV4(compatUser, fsConfig))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, user := range users {
|
||||
err = updateV4BoltUser(dbHandle, user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
providerLog(logger.LevelInfo, "filesystem config updated for user %#v", user.Username)
|
||||
}
|
||||
|
||||
return updateBoltDatabaseVersion(dbHandle, 5)
|
||||
}
|
||||
|
||||
// this compat code will be removed after 2.0.0, ignore the lint warning for now
|
||||
//nolint:gocyclo
|
||||
func updateDatabaseFrom5To6(dbHandle *bolt.DB) error {
|
||||
logger.InfoToConsole("updating bolt database version: 5 -> 6")
|
||||
providerLog(logger.LevelInfo, "updating bolt database version: 5 -> 6")
|
||||
err := dbHandle.Update(func(tx *bolt.Tx) error {
|
||||
bucket, err := getFolderBucket(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
usersBucket, err := getUsersBucket(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cursor := bucket.Cursor()
|
||||
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||
if filepath.IsAbs(string(k)) {
|
||||
var folder vfs.BaseVirtualFolder
|
||||
err = json.Unmarshal(v, &folder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
folder.Name = fmt.Sprintf("Folder%v", folder.ID)
|
||||
buf, err := json.Marshal(folder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// insert the folder with the new structure
|
||||
err = bucket.Put([]byte(folder.Name), buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// delete the folder with the old structure
|
||||
err = bucket.Delete(k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// update users mapping
|
||||
for _, username := range folder.Users {
|
||||
var u []byte
|
||||
if u = usersBucket.Get([]byte(username)); u == nil {
|
||||
continue
|
||||
}
|
||||
var user User
|
||||
err = json.Unmarshal(u, &user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var folders []vfs.VirtualFolder
|
||||
for _, userFolder := range user.VirtualFolders {
|
||||
if folder.MappedPath == userFolder.MappedPath {
|
||||
userFolder.Name = folder.Name
|
||||
}
|
||||
folders = append(folders, userFolder)
|
||||
}
|
||||
user.VirtualFolders = folders
|
||||
buf, err := json.Marshal(user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = usersBucket.Put([]byte(user.Username), buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updateBoltDatabaseVersion(dbHandle, 6)
|
||||
}
|
||||
|
||||
func downgradeBoltDatabaseFrom6To5(dbHandle *bolt.DB) error {
|
||||
logger.InfoToConsole("downgrading bolt database version: 6 -> 5")
|
||||
providerLog(logger.LevelInfo, "downgrading bolt database version: 6 -> 5")
|
||||
// best effort we'll remove this code soon
|
||||
err := dbHandle.Update(func(tx *bolt.Tx) error {
|
||||
// just update the folder keys
|
||||
bucket, err := getFolderBucket(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cursor := bucket.Cursor()
|
||||
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||
if !filepath.IsAbs(string(k)) {
|
||||
var folder vfs.BaseVirtualFolder
|
||||
err = json.Unmarshal(v, &folder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if filepath.IsAbs(folder.MappedPath) {
|
||||
buf, err := json.Marshal(folder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// insert the folder with the old key
|
||||
err = bucket.Put([]byte(folder.MappedPath), buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// delete the folder with the new key
|
||||
err = bucket.Delete(k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updateBoltDatabaseVersion(dbHandle, 5)
|
||||
}
|
||||
|
||||
func getBoltAvailableUsernames(dbHandle *bolt.DB) ([]string, error) {
|
||||
usernames := []string{}
|
||||
err := dbHandle.View(func(tx *bolt.Tx) error {
|
||||
bucket, err := getUsersBucket(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cursor := bucket.Cursor()
|
||||
for k, _ := cursor.First(); k != nil; k, _ = cursor.Next() {
|
||||
usernames = append(usernames, string(k))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return usernames, err
|
||||
}
|
||||
|
||||
func getBoltDatabaseVersion(dbHandle *bolt.DB) (schemaVersion, error) {
|
||||
var dbVersion schemaVersion
|
||||
err := dbHandle.View(func(tx *bolt.Tx) error {
|
||||
|
@ -1466,7 +1017,7 @@ func getBoltDatabaseVersion(dbHandle *bolt.DB) (schemaVersion, error) {
|
|||
v := bucket.Get(dbVersionKey)
|
||||
if v == nil {
|
||||
dbVersion = schemaVersion{
|
||||
Version: 1,
|
||||
Version: 6,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1475,7 +1026,7 @@ func getBoltDatabaseVersion(dbHandle *bolt.DB) (schemaVersion, error) {
|
|||
return dbVersion, err
|
||||
}
|
||||
|
||||
func updateBoltDatabaseVersion(dbHandle *bolt.DB, version int) error {
|
||||
/*func updateBoltDatabaseVersion(dbHandle *bolt.DB, version int) error {
|
||||
err := dbHandle.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket(dbVersionBucket)
|
||||
if bucket == nil {
|
||||
|
@ -1491,4 +1042,4 @@ func updateBoltDatabaseVersion(dbHandle *bolt.DB, version int) error {
|
|||
return bucket.Put(dbVersionKey, buf)
|
||||
})
|
||||
return err
|
||||
}
|
||||
}*/
|
||||
|
|
|
@ -1,358 +0,0 @@
|
|||
package dataprovider
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/drakkan/sftpgo/kms"
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
"github.com/drakkan/sftpgo/vfs"
|
||||
)
|
||||
|
||||
type compatUserV2 struct {
|
||||
ID int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password,omitempty"`
|
||||
PublicKeys []string `json:"public_keys,omitempty"`
|
||||
HomeDir string `json:"home_dir"`
|
||||
UID int `json:"uid"`
|
||||
GID int `json:"gid"`
|
||||
MaxSessions int `json:"max_sessions"`
|
||||
QuotaSize int64 `json:"quota_size"`
|
||||
QuotaFiles int `json:"quota_files"`
|
||||
Permissions []string `json:"permissions"`
|
||||
UsedQuotaSize int64 `json:"used_quota_size"`
|
||||
UsedQuotaFiles int `json:"used_quota_files"`
|
||||
LastQuotaUpdate int64 `json:"last_quota_update"`
|
||||
UploadBandwidth int64 `json:"upload_bandwidth"`
|
||||
DownloadBandwidth int64 `json:"download_bandwidth"`
|
||||
ExpirationDate int64 `json:"expiration_date"`
|
||||
LastLogin int64 `json:"last_login"`
|
||||
Status int `json:"status"`
|
||||
}
|
||||
|
||||
type compatS3FsConfigV4 struct {
|
||||
Bucket string `json:"bucket,omitempty"`
|
||||
KeyPrefix string `json:"key_prefix,omitempty"`
|
||||
Region string `json:"region,omitempty"`
|
||||
AccessKey string `json:"access_key,omitempty"`
|
||||
AccessSecret string `json:"access_secret,omitempty"`
|
||||
Endpoint string `json:"endpoint,omitempty"`
|
||||
StorageClass string `json:"storage_class,omitempty"`
|
||||
UploadPartSize int64 `json:"upload_part_size,omitempty"`
|
||||
UploadConcurrency int `json:"upload_concurrency,omitempty"`
|
||||
}
|
||||
|
||||
type compatGCSFsConfigV4 struct {
|
||||
Bucket string `json:"bucket,omitempty"`
|
||||
KeyPrefix string `json:"key_prefix,omitempty"`
|
||||
CredentialFile string `json:"-"`
|
||||
Credentials []byte `json:"credentials,omitempty"`
|
||||
AutomaticCredentials int `json:"automatic_credentials,omitempty"`
|
||||
StorageClass string `json:"storage_class,omitempty"`
|
||||
}
|
||||
|
||||
type compatAzBlobFsConfigV4 struct {
|
||||
Container string `json:"container,omitempty"`
|
||||
AccountName string `json:"account_name,omitempty"`
|
||||
AccountKey string `json:"account_key,omitempty"`
|
||||
Endpoint string `json:"endpoint,omitempty"`
|
||||
SASURL string `json:"sas_url,omitempty"`
|
||||
KeyPrefix string `json:"key_prefix,omitempty"`
|
||||
UploadPartSize int64 `json:"upload_part_size,omitempty"`
|
||||
UploadConcurrency int `json:"upload_concurrency,omitempty"`
|
||||
UseEmulator bool `json:"use_emulator,omitempty"`
|
||||
AccessTier string `json:"access_tier,omitempty"`
|
||||
}
|
||||
|
||||
type compatFilesystemV4 struct {
|
||||
Provider FilesystemProvider `json:"provider"`
|
||||
S3Config compatS3FsConfigV4 `json:"s3config,omitempty"`
|
||||
GCSConfig compatGCSFsConfigV4 `json:"gcsconfig,omitempty"`
|
||||
AzBlobConfig compatAzBlobFsConfigV4 `json:"azblobconfig,omitempty"`
|
||||
}
|
||||
|
||||
type compatUserV4 struct {
|
||||
ID int64 `json:"id"`
|
||||
Status int `json:"status"`
|
||||
Username string `json:"username"`
|
||||
ExpirationDate int64 `json:"expiration_date"`
|
||||
Password string `json:"password,omitempty"`
|
||||
PublicKeys []string `json:"public_keys,omitempty"`
|
||||
HomeDir string `json:"home_dir"`
|
||||
VirtualFolders []vfs.VirtualFolder `json:"virtual_folders,omitempty"`
|
||||
UID int `json:"uid"`
|
||||
GID int `json:"gid"`
|
||||
MaxSessions int `json:"max_sessions"`
|
||||
QuotaSize int64 `json:"quota_size"`
|
||||
QuotaFiles int `json:"quota_files"`
|
||||
Permissions map[string][]string `json:"permissions"`
|
||||
UsedQuotaSize int64 `json:"used_quota_size"`
|
||||
UsedQuotaFiles int `json:"used_quota_files"`
|
||||
LastQuotaUpdate int64 `json:"last_quota_update"`
|
||||
UploadBandwidth int64 `json:"upload_bandwidth"`
|
||||
DownloadBandwidth int64 `json:"download_bandwidth"`
|
||||
LastLogin int64 `json:"last_login"`
|
||||
Filters UserFilters `json:"filters"`
|
||||
FsConfig compatFilesystemV4 `json:"filesystem"`
|
||||
}
|
||||
|
||||
type backupDataV4Compat struct {
|
||||
Users []compatUserV4 `json:"users"`
|
||||
Folders []vfs.BaseVirtualFolder `json:"folders"`
|
||||
}
|
||||
|
||||
func createUserFromV4(u compatUserV4, fsConfig Filesystem) User {
|
||||
user := User{
|
||||
ID: u.ID,
|
||||
Status: u.Status,
|
||||
Username: u.Username,
|
||||
ExpirationDate: u.ExpirationDate,
|
||||
Password: u.Password,
|
||||
PublicKeys: u.PublicKeys,
|
||||
HomeDir: u.HomeDir,
|
||||
VirtualFolders: u.VirtualFolders,
|
||||
UID: u.UID,
|
||||
GID: u.GID,
|
||||
MaxSessions: u.MaxSessions,
|
||||
QuotaSize: u.QuotaSize,
|
||||
QuotaFiles: u.QuotaFiles,
|
||||
Permissions: u.Permissions,
|
||||
UsedQuotaSize: u.UsedQuotaSize,
|
||||
UsedQuotaFiles: u.UsedQuotaFiles,
|
||||
LastQuotaUpdate: u.LastQuotaUpdate,
|
||||
UploadBandwidth: u.UploadBandwidth,
|
||||
DownloadBandwidth: u.DownloadBandwidth,
|
||||
LastLogin: u.LastLogin,
|
||||
Filters: u.Filters,
|
||||
}
|
||||
user.FsConfig = fsConfig
|
||||
user.SetEmptySecretsIfNil()
|
||||
return user
|
||||
}
|
||||
|
||||
func convertUserToV4(u User, fsConfig compatFilesystemV4) compatUserV4 {
|
||||
user := compatUserV4{
|
||||
ID: u.ID,
|
||||
Status: u.Status,
|
||||
Username: u.Username,
|
||||
ExpirationDate: u.ExpirationDate,
|
||||
Password: u.Password,
|
||||
PublicKeys: u.PublicKeys,
|
||||
HomeDir: u.HomeDir,
|
||||
VirtualFolders: u.VirtualFolders,
|
||||
UID: u.UID,
|
||||
GID: u.GID,
|
||||
MaxSessions: u.MaxSessions,
|
||||
QuotaSize: u.QuotaSize,
|
||||
QuotaFiles: u.QuotaFiles,
|
||||
Permissions: u.Permissions,
|
||||
UsedQuotaSize: u.UsedQuotaSize,
|
||||
UsedQuotaFiles: u.UsedQuotaFiles,
|
||||
LastQuotaUpdate: u.LastQuotaUpdate,
|
||||
UploadBandwidth: u.UploadBandwidth,
|
||||
DownloadBandwidth: u.DownloadBandwidth,
|
||||
LastLogin: u.LastLogin,
|
||||
Filters: u.Filters,
|
||||
}
|
||||
user.FsConfig = fsConfig
|
||||
return user
|
||||
}
|
||||
|
||||
func getCGSCredentialsFromV4(config compatGCSFsConfigV4) (*kms.Secret, error) {
|
||||
secret := kms.NewEmptySecret()
|
||||
var err error
|
||||
if len(config.Credentials) > 0 {
|
||||
secret = kms.NewPlainSecret(string(config.Credentials))
|
||||
return secret, nil
|
||||
}
|
||||
if config.CredentialFile != "" {
|
||||
creds, err := ioutil.ReadFile(config.CredentialFile)
|
||||
if err != nil {
|
||||
return secret, err
|
||||
}
|
||||
secret = kms.NewPlainSecret(string(creds))
|
||||
return secret, nil
|
||||
}
|
||||
return secret, err
|
||||
}
|
||||
|
||||
func getCGSCredentialsFromV6(config vfs.GCSFsConfig, username string) (string, error) {
|
||||
if config.Credentials == nil {
|
||||
config.Credentials = kms.NewEmptySecret()
|
||||
}
|
||||
if config.Credentials.IsEmpty() {
|
||||
config.CredentialFile = filepath.Join(credentialsDirPath, fmt.Sprintf("%v_gcs_credentials.json",
|
||||
username))
|
||||
creds, err := ioutil.ReadFile(config.CredentialFile)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = json.Unmarshal(creds, &config.Credentials)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
if config.Credentials.IsEncrypted() {
|
||||
err := config.Credentials.Decrypt()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// in V4 GCS credentials were not encrypted
|
||||
return config.Credentials.GetPayload(), nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func convertFsConfigToV4(fs Filesystem, username string) (compatFilesystemV4, error) {
|
||||
fsV4 := compatFilesystemV4{
|
||||
Provider: fs.Provider,
|
||||
S3Config: compatS3FsConfigV4{},
|
||||
AzBlobConfig: compatAzBlobFsConfigV4{},
|
||||
GCSConfig: compatGCSFsConfigV4{},
|
||||
}
|
||||
switch fs.Provider {
|
||||
case S3FilesystemProvider:
|
||||
fsV4.S3Config = compatS3FsConfigV4{
|
||||
Bucket: fs.S3Config.Bucket,
|
||||
KeyPrefix: fs.S3Config.KeyPrefix,
|
||||
Region: fs.S3Config.Region,
|
||||
AccessKey: fs.S3Config.AccessKey,
|
||||
AccessSecret: "",
|
||||
Endpoint: fs.S3Config.Endpoint,
|
||||
StorageClass: fs.S3Config.StorageClass,
|
||||
UploadPartSize: fs.S3Config.UploadPartSize,
|
||||
UploadConcurrency: fs.S3Config.UploadConcurrency,
|
||||
}
|
||||
if fs.S3Config.AccessSecret.IsEncrypted() {
|
||||
err := fs.S3Config.AccessSecret.Decrypt()
|
||||
if err != nil {
|
||||
return fsV4, err
|
||||
}
|
||||
secretV4, err := utils.EncryptData(fs.S3Config.AccessSecret.GetPayload())
|
||||
if err != nil {
|
||||
return fsV4, err
|
||||
}
|
||||
fsV4.S3Config.AccessSecret = secretV4
|
||||
}
|
||||
case AzureBlobFilesystemProvider:
|
||||
fsV4.AzBlobConfig = compatAzBlobFsConfigV4{
|
||||
Container: fs.AzBlobConfig.Container,
|
||||
AccountName: fs.AzBlobConfig.AccountName,
|
||||
AccountKey: "",
|
||||
Endpoint: fs.AzBlobConfig.Endpoint,
|
||||
SASURL: fs.AzBlobConfig.SASURL,
|
||||
KeyPrefix: fs.AzBlobConfig.KeyPrefix,
|
||||
UploadPartSize: fs.AzBlobConfig.UploadPartSize,
|
||||
UploadConcurrency: fs.AzBlobConfig.UploadConcurrency,
|
||||
UseEmulator: fs.AzBlobConfig.UseEmulator,
|
||||
AccessTier: fs.AzBlobConfig.AccessTier,
|
||||
}
|
||||
if fs.AzBlobConfig.AccountKey.IsEncrypted() {
|
||||
err := fs.AzBlobConfig.AccountKey.Decrypt()
|
||||
if err != nil {
|
||||
return fsV4, err
|
||||
}
|
||||
secretV4, err := utils.EncryptData(fs.AzBlobConfig.AccountKey.GetPayload())
|
||||
if err != nil {
|
||||
return fsV4, err
|
||||
}
|
||||
fsV4.AzBlobConfig.AccountKey = secretV4
|
||||
}
|
||||
case GCSFilesystemProvider:
|
||||
fsV4.GCSConfig = compatGCSFsConfigV4{
|
||||
Bucket: fs.GCSConfig.Bucket,
|
||||
KeyPrefix: fs.GCSConfig.KeyPrefix,
|
||||
CredentialFile: fs.GCSConfig.CredentialFile,
|
||||
AutomaticCredentials: fs.GCSConfig.AutomaticCredentials,
|
||||
StorageClass: fs.GCSConfig.StorageClass,
|
||||
}
|
||||
if fs.GCSConfig.AutomaticCredentials == 0 {
|
||||
creds, err := getCGSCredentialsFromV6(fs.GCSConfig, username)
|
||||
if err != nil {
|
||||
return fsV4, err
|
||||
}
|
||||
fsV4.GCSConfig.Credentials = []byte(creds)
|
||||
}
|
||||
default:
|
||||
// a provider not supported in v4, the configuration will be lost
|
||||
providerLog(logger.LevelWarn, "provider %v was not supported in v4, the configuration for the user %#v will be lost",
|
||||
fs.Provider, username)
|
||||
fsV4.Provider = 0
|
||||
}
|
||||
return fsV4, nil
|
||||
}
|
||||
|
||||
func convertFsConfigFromV4(compatFs compatFilesystemV4, username string) (Filesystem, error) {
|
||||
fsConfig := Filesystem{
|
||||
Provider: compatFs.Provider,
|
||||
S3Config: vfs.S3FsConfig{},
|
||||
AzBlobConfig: vfs.AzBlobFsConfig{},
|
||||
GCSConfig: vfs.GCSFsConfig{},
|
||||
}
|
||||
switch compatFs.Provider {
|
||||
case S3FilesystemProvider:
|
||||
fsConfig.S3Config = vfs.S3FsConfig{
|
||||
Bucket: compatFs.S3Config.Bucket,
|
||||
KeyPrefix: compatFs.S3Config.KeyPrefix,
|
||||
Region: compatFs.S3Config.Region,
|
||||
AccessKey: compatFs.S3Config.AccessKey,
|
||||
AccessSecret: kms.NewEmptySecret(),
|
||||
Endpoint: compatFs.S3Config.Endpoint,
|
||||
StorageClass: compatFs.S3Config.StorageClass,
|
||||
UploadPartSize: compatFs.S3Config.UploadPartSize,
|
||||
UploadConcurrency: compatFs.S3Config.UploadConcurrency,
|
||||
}
|
||||
if compatFs.S3Config.AccessSecret != "" {
|
||||
secret, err := kms.GetSecretFromCompatString(compatFs.S3Config.AccessSecret)
|
||||
if err != nil {
|
||||
providerLog(logger.LevelError, "unable to convert v4 filesystem for user %#v: %v", username, err)
|
||||
return fsConfig, err
|
||||
}
|
||||
fsConfig.S3Config.AccessSecret = secret
|
||||
}
|
||||
case AzureBlobFilesystemProvider:
|
||||
fsConfig.AzBlobConfig = vfs.AzBlobFsConfig{
|
||||
Container: compatFs.AzBlobConfig.Container,
|
||||
AccountName: compatFs.AzBlobConfig.AccountName,
|
||||
AccountKey: kms.NewEmptySecret(),
|
||||
Endpoint: compatFs.AzBlobConfig.Endpoint,
|
||||
SASURL: compatFs.AzBlobConfig.SASURL,
|
||||
KeyPrefix: compatFs.AzBlobConfig.KeyPrefix,
|
||||
UploadPartSize: compatFs.AzBlobConfig.UploadPartSize,
|
||||
UploadConcurrency: compatFs.AzBlobConfig.UploadConcurrency,
|
||||
UseEmulator: compatFs.AzBlobConfig.UseEmulator,
|
||||
AccessTier: compatFs.AzBlobConfig.AccessTier,
|
||||
}
|
||||
if compatFs.AzBlobConfig.AccountKey != "" {
|
||||
secret, err := kms.GetSecretFromCompatString(compatFs.AzBlobConfig.AccountKey)
|
||||
if err != nil {
|
||||
providerLog(logger.LevelError, "unable to convert v4 filesystem for user %#v: %v", username, err)
|
||||
return fsConfig, err
|
||||
}
|
||||
fsConfig.AzBlobConfig.AccountKey = secret
|
||||
}
|
||||
case GCSFilesystemProvider:
|
||||
fsConfig.GCSConfig = vfs.GCSFsConfig{
|
||||
Bucket: compatFs.GCSConfig.Bucket,
|
||||
KeyPrefix: compatFs.GCSConfig.KeyPrefix,
|
||||
CredentialFile: compatFs.GCSConfig.CredentialFile,
|
||||
AutomaticCredentials: compatFs.GCSConfig.AutomaticCredentials,
|
||||
StorageClass: compatFs.GCSConfig.StorageClass,
|
||||
}
|
||||
if compatFs.GCSConfig.AutomaticCredentials == 0 {
|
||||
compatFs.GCSConfig.CredentialFile = filepath.Join(credentialsDirPath, fmt.Sprintf("%v_gcs_credentials.json",
|
||||
username))
|
||||
}
|
||||
secret, err := getCGSCredentialsFromV4(compatFs.GCSConfig)
|
||||
if err != nil {
|
||||
providerLog(logger.LevelError, "unable to convert v4 filesystem for user %#v: %v", username, err)
|
||||
return fsConfig, err
|
||||
}
|
||||
fsConfig.GCSConfig.Credentials = secret
|
||||
}
|
||||
return fsConfig, nil
|
||||
}
|
|
@ -104,7 +104,7 @@ var (
|
|||
// ValidProtocols defines all the valid protcols
|
||||
ValidProtocols = []string{"SSH", "FTP", "DAV"}
|
||||
// ErrNoInitRequired defines the error returned by InitProvider if no inizialization/update is required
|
||||
ErrNoInitRequired = errors.New("The data provider is already up to date")
|
||||
ErrNoInitRequired = errors.New("The data provider is up to date")
|
||||
// ErrInvalidCredentials defines the error to return if the supplied credentials are invalid
|
||||
ErrInvalidCredentials = errors.New("invalid credentials")
|
||||
webDAVUsersCache sync.Map
|
||||
|
@ -291,46 +291,6 @@ func (d *BackupData) HasFolder(name string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (d *BackupData) checkFolderNames() {
|
||||
if len(d.Folders) == 0 {
|
||||
return
|
||||
}
|
||||
if d.Folders[0].Name != "" {
|
||||
return
|
||||
}
|
||||
logger.WarnToConsole("You are loading folders without a name, please update to the latest supported format. This compatibility layer will be removed soon.")
|
||||
providerLog(logger.LevelWarn, "You are loading folders without a name, please update to the latest supported format. This compatibility layer will be removed soon.")
|
||||
folders := make([]vfs.BaseVirtualFolder, 0, len(d.Folders))
|
||||
for idx, folder := range d.Folders {
|
||||
if folder.Name == "" {
|
||||
folder.Name = fmt.Sprintf("Folder%v", idx)
|
||||
}
|
||||
folders = append(folders, folder)
|
||||
}
|
||||
d.Folders = folders
|
||||
users := make([]User, 0, len(d.Users))
|
||||
for _, user := range d.Users {
|
||||
if len(user.VirtualFolders) > 0 {
|
||||
vfolders := make([]vfs.VirtualFolder, 0, len(user.VirtualFolders))
|
||||
for _, vfolder := range user.VirtualFolders {
|
||||
if vfolder.Name == "" {
|
||||
for _, f := range d.Folders {
|
||||
if f.MappedPath == vfolder.MappedPath {
|
||||
vfolder.Name = f.Name
|
||||
}
|
||||
}
|
||||
}
|
||||
if vfolder.Name != "" {
|
||||
vfolders = append(vfolders, vfolder)
|
||||
}
|
||||
}
|
||||
user.VirtualFolders = vfolders
|
||||
}
|
||||
users = append(users, user)
|
||||
}
|
||||
d.Users = users
|
||||
}
|
||||
|
||||
type keyboardAuthHookRequest struct {
|
||||
RequestID string `json:"request_id"`
|
||||
Username string `json:"username,omitempty"`
|
||||
|
@ -363,18 +323,6 @@ type checkPasswordResponse struct {
|
|||
ToVerify string `json:"to_verify"`
|
||||
}
|
||||
|
||||
type virtualFoldersCompact struct {
|
||||
VirtualPath string `json:"virtual_path"`
|
||||
MappedPath string `json:"mapped_path"`
|
||||
ExcludeFromQuota bool `json:"exclude_from_quota"`
|
||||
}
|
||||
|
||||
type userCompactVFolders struct {
|
||||
ID int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
VirtualFolders []virtualFoldersCompact `json:"virtual_folders"`
|
||||
}
|
||||
|
||||
// ValidationError raised if input data is not valid
|
||||
type ValidationError struct {
|
||||
err string
|
||||
|
@ -864,28 +812,6 @@ func DumpData() (BackupData, error) {
|
|||
func ParseDumpData(data []byte) (BackupData, error) {
|
||||
var dump BackupData
|
||||
err := json.Unmarshal(data, &dump)
|
||||
if err == nil {
|
||||
dump.checkFolderNames()
|
||||
return dump, err
|
||||
}
|
||||
dump = BackupData{}
|
||||
// try to parse as version 4
|
||||
var dumpCompat backupDataV4Compat
|
||||
err = json.Unmarshal(data, &dumpCompat)
|
||||
if err != nil {
|
||||
return dump, err
|
||||
}
|
||||
logger.WarnToConsole("You are loading data from an old format, please update to the latest supported one. We only support the current and the previous format.")
|
||||
providerLog(logger.LevelWarn, "You are loading data from an old format, please update to the latest supported one. We only support the current and the previous format.")
|
||||
dump.Folders = dumpCompat.Folders
|
||||
for _, compatUser := range dumpCompat.Users {
|
||||
fsConfig, err := convertFsConfigFromV4(compatUser.FsConfig, compatUser.Username)
|
||||
if err != nil {
|
||||
return dump, err
|
||||
}
|
||||
dump.Users = append(dump.Users, createUserFromV4(compatUser, fsConfig))
|
||||
}
|
||||
dump.checkFolderNames()
|
||||
return dump, err
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ package dataprovider
|
|||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -18,41 +19,26 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
mysqlUsersTableSQL = "CREATE TABLE `{{users}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, " +
|
||||
"`username` varchar(255) NOT NULL UNIQUE, `password` varchar(255) NULL, `public_keys` longtext NULL, " +
|
||||
"`home_dir` varchar(255) NOT NULL, `uid` integer NOT NULL, `gid` integer NOT NULL, `max_sessions` integer NOT NULL, " +
|
||||
" `quota_size` bigint NOT NULL, `quota_files` integer NOT NULL, `permissions` longtext NOT NULL, " +
|
||||
"`used_quota_size` bigint NOT NULL, `used_quota_files` integer NOT NULL, `last_quota_update` bigint NOT NULL, " +
|
||||
"`upload_bandwidth` integer NOT NULL, `download_bandwidth` integer NOT NULL, `expiration_date` bigint(20) NOT NULL, " +
|
||||
"`last_login` bigint(20) NOT NULL, `status` int(11) NOT NULL, `filters` longtext DEFAULT NULL, " +
|
||||
"`filesystem` longtext DEFAULT NULL);"
|
||||
mysqlSchemaTableSQL = "CREATE TABLE `{{schema_version}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `version` integer NOT NULL);"
|
||||
mysqlV2SQL = "ALTER TABLE `{{users}}` ADD COLUMN `virtual_folders` longtext NULL;"
|
||||
mysqlV3SQL = "ALTER TABLE `{{users}}` MODIFY `password` longtext NULL;"
|
||||
mysqlV4SQL = "CREATE TABLE `{{folders}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `path` varchar(512) NOT NULL UNIQUE," +
|
||||
"`used_quota_size` bigint NOT NULL, `used_quota_files` integer NOT NULL, `last_quota_update` bigint NOT NULL);" +
|
||||
"ALTER TABLE `{{users}}` MODIFY `home_dir` varchar(512) NOT NULL;" +
|
||||
"ALTER TABLE `{{users}}` DROP COLUMN `virtual_folders`;" +
|
||||
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, " +
|
||||
"`password` varchar(255) NOT NULL, `email` varchar(255) NULL, `status` integer NOT NULL, `permissions` longtext NOT NULL, " +
|
||||
"`filters` longtext NULL, `additional_info` longtext NULL);" +
|
||||
"CREATE TABLE `{{folders}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(255) NOT NULL UNIQUE, " +
|
||||
"`path` varchar(512) NULL, `used_quota_size` bigint NOT NULL, `used_quota_files` integer NOT NULL, " +
|
||||
"`last_quota_update` bigint NOT NULL);" +
|
||||
"CREATE TABLE `{{users}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `status` integer NOT NULL, " +
|
||||
"`expiration_date` bigint NOT NULL, `username` varchar(255) NOT NULL UNIQUE, `password` longtext NULL, " +
|
||||
"`public_keys` longtext NULL, `home_dir` varchar(512) NOT NULL, `uid` integer NOT NULL, `gid` integer NOT NULL, " +
|
||||
"`max_sessions` integer NOT NULL, `quota_size` bigint NOT NULL, `quota_files` integer NOT NULL, " +
|
||||
"`permissions` longtext NOT NULL, `used_quota_size` bigint NOT NULL, `used_quota_files` integer NOT NULL, " +
|
||||
"`last_quota_update` bigint NOT NULL, `upload_bandwidth` integer NOT NULL, `download_bandwidth` integer NOT NULL, " +
|
||||
"`last_login` bigint NOT NULL, `filters` longtext NULL, `filesystem` longtext NULL, `additional_info` longtext NULL);" +
|
||||
"CREATE TABLE `{{folders_mapping}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `virtual_path` varchar(512) NOT NULL, " +
|
||||
"`quota_size` bigint NOT NULL, `quota_files` integer NOT NULL, `folder_id` integer NOT NULL, `user_id` integer NOT NULL);" +
|
||||
"ALTER TABLE `{{folders_mapping}}` ADD CONSTRAINT `unique_mapping` UNIQUE (`user_id`, `folder_id`);" +
|
||||
"ALTER TABLE `{{folders_mapping}}` ADD CONSTRAINT `folders_mapping_folder_id_fk_folders_id` FOREIGN KEY (`folder_id`) REFERENCES `{{folders}}` (`id`) ON DELETE CASCADE;" +
|
||||
"ALTER TABLE `{{folders_mapping}}` ADD CONSTRAINT `folders_mapping_user_id_fk_users_id` FOREIGN KEY (`user_id`) REFERENCES `{{users}}` (`id`) ON DELETE CASCADE;"
|
||||
mysqlV6SQL = "ALTER TABLE `{{users}}` ADD COLUMN `additional_info` longtext NULL;"
|
||||
mysqlV6DownSQL = "ALTER TABLE `{{users}}` DROP COLUMN `additional_info`;"
|
||||
mysqlV7SQL = "CREATE TABLE `{{admins}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `username` varchar(255) NOT NULL UNIQUE, " +
|
||||
"`password` varchar(255) NOT NULL, `email` varchar(255) NULL, `status` integer NOT NULL, `permissions` longtext NOT NULL, " +
|
||||
"`filters` longtext NULL, `additional_info` longtext NULL);"
|
||||
mysqlV7DownSQL = "DROP TABLE `{{admins}}` CASCADE;"
|
||||
mysqlV8SQL = "ALTER TABLE `{{folders}}` ADD COLUMN `name` varchar(255) NULL;" +
|
||||
"ALTER TABLE `{{folders}}` MODIFY `path` varchar(512) NULL;" +
|
||||
"ALTER TABLE `{{folders}}` DROP INDEX `path`;" +
|
||||
"UPDATE `{{folders}}` f1 SET name = CONCAT('folder',f1.id);" +
|
||||
"ALTER TABLE `{{folders}}` MODIFY `name` varchar(255) NOT NULL;" +
|
||||
"ALTER TABLE `{{folders}}` ADD CONSTRAINT `name` UNIQUE (`name`);"
|
||||
mysqlV8DownSQL = "ALTER TABLE `{{folders}}` DROP COLUMN `name`;" +
|
||||
"ALTER TABLE `{{folders}}` MODIFY `path` varchar(512) NOT NULL;" +
|
||||
"ALTER TABLE `{{folders}}` ADD CONSTRAINT `path` UNIQUE (`path`);"
|
||||
"ALTER TABLE `{{folders_mapping}}` ADD CONSTRAINT `folders_mapping_user_id_fk_users_id` FOREIGN KEY (`user_id`) REFERENCES `{{users}}` (`id`) ON DELETE CASCADE;" +
|
||||
"INSERT INTO {{schema_version}} (version) VALUES (8);"
|
||||
)
|
||||
|
||||
// MySQLProvider auth provider for MySQL/MariaDB database
|
||||
|
@ -224,27 +210,13 @@ func (p *MySQLProvider) initializeDatabase() error {
|
|||
if err == nil && dbVersion.Version > 0 {
|
||||
return ErrNoInitRequired
|
||||
}
|
||||
sqlUsers := strings.Replace(mysqlUsersTableSQL, "{{users}}", sqlTableUsers, 1)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), longSQLQueryTimeout)
|
||||
defer cancel()
|
||||
initialSQL := strings.ReplaceAll(mysqlInitialSQL, "{{schema_version}}", sqlTableSchemaVersion)
|
||||
initialSQL = strings.ReplaceAll(initialSQL, "{{admins}}", sqlTableAdmins)
|
||||
initialSQL = strings.ReplaceAll(initialSQL, "{{folders}}", sqlTableFolders)
|
||||
initialSQL = strings.ReplaceAll(initialSQL, "{{users}}", sqlTableUsers)
|
||||
initialSQL = strings.ReplaceAll(initialSQL, "{{folders_mapping}}", sqlTableFoldersMapping)
|
||||
|
||||
tx, err := p.dbHandle.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.Exec(sqlUsers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.Exec(strings.Replace(mysqlSchemaTableSQL, "{{schema_version}}", sqlTableSchemaVersion, 1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.Exec(strings.Replace(initialDBVersionSQL, "{{schema_version}}", sqlTableSchemaVersion, 1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Commit()
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(p.dbHandle, strings.Split(initialSQL, ";"), 8)
|
||||
}
|
||||
|
||||
func (p *MySQLProvider) migrateDatabase() error {
|
||||
|
@ -252,200 +224,35 @@ func (p *MySQLProvider) migrateDatabase() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dbVersion.Version == sqlDatabaseVersion {
|
||||
providerLog(logger.LevelDebug, "sql database is up to date, current version: %v", dbVersion.Version)
|
||||
|
||||
switch version := dbVersion.Version; {
|
||||
case version == sqlDatabaseVersion:
|
||||
providerLog(logger.LevelDebug, "sql database is up to date, current version: %v", version)
|
||||
return ErrNoInitRequired
|
||||
}
|
||||
switch dbVersion.Version {
|
||||
case 1:
|
||||
return updateMySQLDatabaseFromV1(p.dbHandle)
|
||||
case 2:
|
||||
return updateMySQLDatabaseFromV2(p.dbHandle)
|
||||
case 3:
|
||||
return updateMySQLDatabaseFromV3(p.dbHandle)
|
||||
case 4:
|
||||
return updateMySQLDatabaseFromV4(p.dbHandle)
|
||||
case 5:
|
||||
return updateMySQLDatabaseFromV5(p.dbHandle)
|
||||
case 6:
|
||||
return updateMySQLDatabaseFromV6(p.dbHandle)
|
||||
case 7:
|
||||
return updateMySQLDatabaseFromV7(p.dbHandle)
|
||||
case version < 8:
|
||||
err = fmt.Errorf("database version %v is too old, please see the upgrading docs", version)
|
||||
providerLog(logger.LevelError, "%v", err)
|
||||
logger.ErrorToConsole("%v", err)
|
||||
return err
|
||||
default:
|
||||
if dbVersion.Version > sqlDatabaseVersion {
|
||||
providerLog(logger.LevelWarn, "database version %v is newer than the supported: %v", dbVersion.Version,
|
||||
if version > sqlDatabaseVersion {
|
||||
providerLog(logger.LevelWarn, "database version %v is newer than the supported one: %v", version,
|
||||
sqlDatabaseVersion)
|
||||
logger.WarnToConsole("database version %v is newer than the supported: %v", dbVersion.Version,
|
||||
logger.WarnToConsole("database version %v is newer than the supported one: %v", version,
|
||||
sqlDatabaseVersion)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Database version not handled: %v", dbVersion.Version)
|
||||
return fmt.Errorf("Database version not handled: %v", version)
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:dupl
|
||||
func (p *MySQLProvider) revertDatabase(targetVersion int) error {
|
||||
dbVersion, err := sqlCommonGetDatabaseVersion(p.dbHandle, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dbVersion.Version == targetVersion {
|
||||
return fmt.Errorf("current version match target version, nothing to do")
|
||||
}
|
||||
switch dbVersion.Version {
|
||||
case 8:
|
||||
err = downgradeMySQLDatabaseFrom8To7(p.dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = downgradeMySQLDatabaseFrom7To6(p.dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = downgradeMySQLDatabaseFrom6To5(p.dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return downgradeMySQLDatabaseFrom5To4(p.dbHandle)
|
||||
case 7:
|
||||
err = downgradeMySQLDatabaseFrom7To6(p.dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = downgradeMySQLDatabaseFrom6To5(p.dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return downgradeMySQLDatabaseFrom5To4(p.dbHandle)
|
||||
case 6:
|
||||
err = downgradeMySQLDatabaseFrom6To5(p.dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return downgradeMySQLDatabaseFrom5To4(p.dbHandle)
|
||||
case 5:
|
||||
return downgradeMySQLDatabaseFrom5To4(p.dbHandle)
|
||||
default:
|
||||
return fmt.Errorf("Database version not handled: %v", dbVersion.Version)
|
||||
return errors.New("current version match target version, nothing to do")
|
||||
}
|
||||
}
|
||||
|
||||
func updateMySQLDatabaseFromV1(dbHandle *sql.DB) error {
|
||||
err := updateMySQLDatabaseFrom1To2(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updateMySQLDatabaseFromV2(dbHandle)
|
||||
}
|
||||
|
||||
func updateMySQLDatabaseFromV2(dbHandle *sql.DB) error {
|
||||
err := updateMySQLDatabaseFrom2To3(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updateMySQLDatabaseFromV3(dbHandle)
|
||||
}
|
||||
|
||||
func updateMySQLDatabaseFromV3(dbHandle *sql.DB) error {
|
||||
err := updateMySQLDatabaseFrom3To4(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updateMySQLDatabaseFromV4(dbHandle)
|
||||
}
|
||||
|
||||
func updateMySQLDatabaseFromV4(dbHandle *sql.DB) error {
|
||||
err := updateMySQLDatabaseFrom4To5(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updateMySQLDatabaseFromV5(dbHandle)
|
||||
}
|
||||
|
||||
func updateMySQLDatabaseFromV5(dbHandle *sql.DB) error {
|
||||
err := updateMySQLDatabaseFrom5To6(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updateMySQLDatabaseFromV6(dbHandle)
|
||||
}
|
||||
|
||||
func updateMySQLDatabaseFromV6(dbHandle *sql.DB) error {
|
||||
err := updateMySQLDatabaseFrom6To7(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updateMySQLDatabaseFromV7(dbHandle)
|
||||
}
|
||||
|
||||
func updateMySQLDatabaseFromV7(dbHandle *sql.DB) error {
|
||||
return updateMySQLDatabaseFrom7To8(dbHandle)
|
||||
}
|
||||
|
||||
func updateMySQLDatabaseFrom1To2(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("updating database version: 1 -> 2")
|
||||
providerLog(logger.LevelInfo, "updating database version: 1 -> 2")
|
||||
sql := strings.Replace(mysqlV2SQL, "{{users}}", sqlTableUsers, 1)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 2)
|
||||
}
|
||||
|
||||
func updateMySQLDatabaseFrom2To3(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("updating database version: 2 -> 3")
|
||||
providerLog(logger.LevelInfo, "updating database version: 2 -> 3")
|
||||
sql := strings.Replace(mysqlV3SQL, "{{users}}", sqlTableUsers, 1)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 3)
|
||||
}
|
||||
|
||||
func updateMySQLDatabaseFrom3To4(dbHandle *sql.DB) error {
|
||||
return sqlCommonUpdateDatabaseFrom3To4(mysqlV4SQL, dbHandle)
|
||||
}
|
||||
|
||||
func updateMySQLDatabaseFrom4To5(dbHandle *sql.DB) error {
|
||||
return sqlCommonUpdateDatabaseFrom4To5(dbHandle)
|
||||
}
|
||||
|
||||
func updateMySQLDatabaseFrom5To6(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("updating database version: 5 -> 6")
|
||||
providerLog(logger.LevelInfo, "updating database version: 5 -> 6")
|
||||
sql := strings.Replace(mysqlV6SQL, "{{users}}", sqlTableUsers, 1)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 6)
|
||||
}
|
||||
|
||||
func updateMySQLDatabaseFrom6To7(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("updating database version: 6 -> 7")
|
||||
providerLog(logger.LevelInfo, "updating database version: 6 -> 7")
|
||||
sql := strings.Replace(mysqlV7SQL, "{{admins}}", sqlTableAdmins, 1)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 7)
|
||||
}
|
||||
|
||||
func updateMySQLDatabaseFrom7To8(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("updating database version: 7 -> 8")
|
||||
providerLog(logger.LevelInfo, "updating database version: 7 -> 8")
|
||||
sql := strings.ReplaceAll(mysqlV8SQL, "{{folders}}", sqlTableFolders)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, strings.Split(sql, ";"), 8)
|
||||
}
|
||||
|
||||
func downgradeMySQLDatabaseFrom8To7(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("downgrading database version: 8 -> 7")
|
||||
providerLog(logger.LevelInfo, "downgrading database version: 8 -> 7")
|
||||
sql := strings.ReplaceAll(mysqlV8DownSQL, "{{folders}}", sqlTableFolders)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 7)
|
||||
}
|
||||
|
||||
func downgradeMySQLDatabaseFrom7To6(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("downgrading database version: 7 -> 6")
|
||||
providerLog(logger.LevelInfo, "downgrading database version: 7 -> 6")
|
||||
sql := strings.Replace(mysqlV7DownSQL, "{{admins}}", sqlTableAdmins, 1)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 6)
|
||||
}
|
||||
|
||||
func downgradeMySQLDatabaseFrom6To5(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("downgrading database version: 6 -> 5")
|
||||
providerLog(logger.LevelInfo, "downgrading database version: 6 -> 5")
|
||||
sql := strings.Replace(mysqlV6DownSQL, "{{users}}", sqlTableUsers, 1)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 5)
|
||||
}
|
||||
|
||||
func downgradeMySQLDatabaseFrom5To4(dbHandle *sql.DB) error {
|
||||
return sqlCommonDowngradeDatabaseFrom5To4(dbHandle)
|
||||
return errors.New("the current version cannot be reverted")
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ package dataprovider
|
|||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -18,43 +19,30 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
pgsqlUsersTableSQL = `CREATE TABLE "{{users}}" ("id" serial NOT NULL PRIMARY KEY, "username" varchar(255) NOT NULL UNIQUE,
|
||||
"password" varchar(255) NULL, "public_keys" text NULL, "home_dir" varchar(255) NOT NULL, "uid" integer NOT NULL,
|
||||
"gid" integer NOT NULL, "max_sessions" integer NOT NULL, "quota_size" bigint NOT NULL, "quota_files" integer NOT NULL,
|
||||
"permissions" text NOT NULL, "used_quota_size" bigint NOT NULL, "used_quota_files" integer NOT NULL,
|
||||
"last_quota_update" bigint NOT NULL, "upload_bandwidth" integer NOT NULL, "download_bandwidth" integer NOT NULL,
|
||||
"expiration_date" bigint NOT NULL, "last_login" bigint NOT NULL, "status" integer NOT NULL, "filters" text NULL,
|
||||
"filesystem" text NULL);`
|
||||
pgsqlSchemaTableSQL = `CREATE TABLE "{{schema_version}}" ("id" serial NOT NULL PRIMARY KEY, "version" integer NOT NULL);`
|
||||
pgsqlV2SQL = `ALTER TABLE "{{users}}" ADD COLUMN "virtual_folders" text NULL;`
|
||||
pgsqlV3SQL = `ALTER TABLE "{{users}}" ALTER COLUMN "password" TYPE text USING "password"::text;`
|
||||
pgsqlV4SQL = `CREATE TABLE "{{folders}}" ("id" serial NOT NULL PRIMARY KEY, "path" varchar(512) NOT NULL UNIQUE, "used_quota_size" bigint NOT NULL, "used_quota_files" integer NOT NULL, "last_quota_update" bigint NOT NULL);
|
||||
ALTER TABLE "{{users}}" ALTER COLUMN "home_dir" TYPE varchar(512) USING "home_dir"::varchar(512);
|
||||
ALTER TABLE "{{users}}" DROP COLUMN "virtual_folders" CASCADE;
|
||||
CREATE TABLE "{{folders_mapping}}" ("id" serial NOT NULL PRIMARY KEY, "virtual_path" varchar(512) NOT NULL, "quota_size" bigint NOT NULL, "quota_files" integer NOT NULL, "folder_id" integer NOT NULL, "user_id" integer NOT NULL);
|
||||
ALTER TABLE "{{folders_mapping}}" ADD CONSTRAINT "unique_mapping" UNIQUE ("user_id", "folder_id");
|
||||
ALTER TABLE "{{folders_mapping}}" ADD CONSTRAINT "folders_mapping_folder_id_fk_folders_id" FOREIGN KEY ("folder_id") REFERENCES "{{folders}}" ("id") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
|
||||
ALTER TABLE "{{folders_mapping}}" ADD CONSTRAINT "folders_mapping_user_id_fk_users_id" FOREIGN KEY ("user_id") REFERENCES "{{users}}" ("id") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
|
||||
CREATE INDEX "folders_mapping_folder_id_idx" ON "{{folders_mapping}}" ("folder_id");
|
||||
CREATE INDEX "folders_mapping_user_id_idx" ON "{{folders_mapping}}" ("user_id");
|
||||
`
|
||||
pgsqlV6SQL = `ALTER TABLE "{{users}}" ADD COLUMN "additional_info" text NULL;`
|
||||
pgsqlV6DownSQL = `ALTER TABLE "{{users}}" DROP COLUMN "additional_info" CASCADE;`
|
||||
pgsqlV7SQL = `CREATE TABLE "{{admins}}" ("id" serial NOT NULL PRIMARY KEY, "username" varchar(255) NOT NULL UNIQUE,
|
||||
pgsqlInitial = `CREATE TABLE "{{schema_version}}" ("id" serial NOT NULL PRIMARY KEY, "version" integer NOT NULL);
|
||||
CREATE TABLE "{{admins}}" ("id" serial NOT NULL PRIMARY KEY, "username" varchar(255) NOT NULL UNIQUE,
|
||||
"password" varchar(255) NOT NULL, "email" varchar(255) NULL, "status" integer NOT NULL, "permissions" text NOT NULL,
|
||||
"filters" text NULL, "additional_info" text NULL);
|
||||
`
|
||||
pgsqlV7DownSQL = `DROP TABLE "{{admins}}" CASCADE;`
|
||||
pgsqlV8SQL = `ALTER TABLE "{{folders}}" ADD COLUMN "name" varchar(255) NULL;
|
||||
ALTER TABLE "folders" ALTER COLUMN "path" DROP NOT NULL;
|
||||
ALTER TABLE "{{folders}}" DROP CONSTRAINT IF EXISTS folders_path_key;
|
||||
UPDATE "{{folders}}" f1 SET name = (SELECT CONCAT('folder',f2.id) FROM "{{folders}}" f2 WHERE f2.id = f1.id);
|
||||
ALTER TABLE "{{folders}}" ALTER COLUMN "name" SET NOT NULL;
|
||||
ALTER TABLE "{{folders}}" ADD CONSTRAINT "folders_name_uniq" UNIQUE ("name");
|
||||
`
|
||||
pgsqlV8DownSQL = `ALTER TABLE "{{folders}}" DROP COLUMN "name" CASCADE;
|
||||
ALTER TABLE "{{folders}}" ALTER COLUMN "path" SET NOT NULL;
|
||||
ALTER TABLE "{{folders}}" ADD CONSTRAINT folders_path_key UNIQUE (path);
|
||||
CREATE TABLE "{{folders}}" ("id" serial NOT NULL PRIMARY KEY, "name" varchar(255) NOT NULL UNIQUE,
|
||||
"path" varchar(512) NULL, "used_quota_size" bigint NOT NULL, "used_quota_files" integer NOT NULL,
|
||||
"last_quota_update" bigint NOT NULL);
|
||||
CREATE TABLE "{{users}}" ("id" serial NOT NULL PRIMARY KEY, "status" integer NOT NULL, "expiration_date" bigint NOT NULL,
|
||||
"username" varchar(255) NOT NULL UNIQUE, "password" text NULL, "public_keys" text NULL, "home_dir" varchar(512) NOT NULL,
|
||||
"uid" integer NOT NULL, "gid" integer NOT NULL, "max_sessions" integer NOT NULL, "quota_size" bigint NOT NULL,
|
||||
"quota_files" integer NOT NULL, "permissions" text NOT NULL, "used_quota_size" bigint NOT NULL,
|
||||
"used_quota_files" integer NOT NULL, "last_quota_update" bigint NOT NULL, "upload_bandwidth" integer NOT NULL,
|
||||
"download_bandwidth" integer NOT NULL, "last_login" bigint NOT NULL, "filters" text NULL, "filesystem" text NULL,
|
||||
"additional_info" text NULL);
|
||||
CREATE TABLE "{{folders_mapping}}" ("id" serial NOT NULL PRIMARY KEY, "virtual_path" varchar(512) NOT NULL,
|
||||
"quota_size" bigint NOT NULL, "quota_files" integer NOT NULL, "folder_id" integer NOT NULL, "user_id" integer NOT NULL);
|
||||
ALTER TABLE "{{folders_mapping}}" ADD CONSTRAINT "unique_mapping" UNIQUE ("user_id", "folder_id");
|
||||
ALTER TABLE "{{folders_mapping}}" ADD CONSTRAINT "folders_mapping_folder_id_fk_folders_id"
|
||||
FOREIGN KEY ("folder_id") REFERENCES "{{folders}}" ("id") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
|
||||
ALTER TABLE "{{folders_mapping}}" ADD CONSTRAINT "folders_mapping_user_id_fk_users_id"
|
||||
FOREIGN KEY ("user_id") REFERENCES "{{users}}" ("id") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
|
||||
CREATE INDEX "folders_mapping_folder_id_idx" ON "{{folders_mapping}}" ("folder_id");
|
||||
CREATE INDEX "folders_mapping_user_id_idx" ON "{{folders_mapping}}" ("user_id");
|
||||
INSERT INTO {{schema_version}} (version) VALUES (8);
|
||||
`
|
||||
)
|
||||
|
||||
|
@ -228,27 +216,13 @@ func (p *PGSQLProvider) initializeDatabase() error {
|
|||
if err == nil && dbVersion.Version > 0 {
|
||||
return ErrNoInitRequired
|
||||
}
|
||||
sqlUsers := strings.Replace(pgsqlUsersTableSQL, "{{users}}", sqlTableUsers, 1)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), longSQLQueryTimeout)
|
||||
defer cancel()
|
||||
initialSQL := strings.ReplaceAll(pgsqlInitial, "{{schema_version}}", sqlTableSchemaVersion)
|
||||
initialSQL = strings.ReplaceAll(initialSQL, "{{admins}}", sqlTableAdmins)
|
||||
initialSQL = strings.ReplaceAll(initialSQL, "{{folders}}", sqlTableFolders)
|
||||
initialSQL = strings.ReplaceAll(initialSQL, "{{users}}", sqlTableUsers)
|
||||
initialSQL = strings.ReplaceAll(initialSQL, "{{folders_mapping}}", sqlTableFoldersMapping)
|
||||
|
||||
tx, err := p.dbHandle.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.Exec(sqlUsers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.Exec(strings.Replace(pgsqlSchemaTableSQL, "{{schema_version}}", sqlTableSchemaVersion, 1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.Exec(strings.Replace(initialDBVersionSQL, "{{schema_version}}", sqlTableSchemaVersion, 1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Commit()
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(p.dbHandle, []string{initialSQL}, 8)
|
||||
}
|
||||
|
||||
func (p *PGSQLProvider) migrateDatabase() error {
|
||||
|
@ -256,200 +230,35 @@ func (p *PGSQLProvider) migrateDatabase() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dbVersion.Version == sqlDatabaseVersion {
|
||||
providerLog(logger.LevelDebug, "sql database is up to date, current version: %v", dbVersion.Version)
|
||||
|
||||
switch version := dbVersion.Version; {
|
||||
case version == sqlDatabaseVersion:
|
||||
providerLog(logger.LevelDebug, "sql database is up to date, current version: %v", version)
|
||||
return ErrNoInitRequired
|
||||
}
|
||||
switch dbVersion.Version {
|
||||
case 1:
|
||||
return updatePGSQLDatabaseFromV1(p.dbHandle)
|
||||
case 2:
|
||||
return updatePGSQLDatabaseFromV2(p.dbHandle)
|
||||
case 3:
|
||||
return updatePGSQLDatabaseFromV3(p.dbHandle)
|
||||
case 4:
|
||||
return updatePGSQLDatabaseFromV4(p.dbHandle)
|
||||
case 5:
|
||||
return updatePGSQLDatabaseFromV5(p.dbHandle)
|
||||
case 6:
|
||||
return updatePGSQLDatabaseFromV6(p.dbHandle)
|
||||
case 7:
|
||||
return updatePGSQLDatabaseFromV7(p.dbHandle)
|
||||
case version < 8:
|
||||
err = fmt.Errorf("database version %v is too old, please see the upgrading docs", version)
|
||||
providerLog(logger.LevelError, "%v", err)
|
||||
logger.ErrorToConsole("%v", err)
|
||||
return err
|
||||
default:
|
||||
if dbVersion.Version > sqlDatabaseVersion {
|
||||
providerLog(logger.LevelWarn, "database version %v is newer than the supported: %v", dbVersion.Version,
|
||||
if version > sqlDatabaseVersion {
|
||||
providerLog(logger.LevelWarn, "database version %v is newer than the supported one: %v", version,
|
||||
sqlDatabaseVersion)
|
||||
logger.WarnToConsole("database version %v is newer than the supported: %v", dbVersion.Version,
|
||||
logger.WarnToConsole("database version %v is newer than the supported one: %v", version,
|
||||
sqlDatabaseVersion)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Database version not handled: %v", dbVersion.Version)
|
||||
return fmt.Errorf("Database version not handled: %v", version)
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:dupl
|
||||
func (p *PGSQLProvider) revertDatabase(targetVersion int) error {
|
||||
dbVersion, err := sqlCommonGetDatabaseVersion(p.dbHandle, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dbVersion.Version == targetVersion {
|
||||
return fmt.Errorf("current version match target version, nothing to do")
|
||||
}
|
||||
switch dbVersion.Version {
|
||||
case 8:
|
||||
err = downgradePGSQLDatabaseFrom8To7(p.dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = downgradePGSQLDatabaseFrom7To6(p.dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = downgradePGSQLDatabaseFrom6To5(p.dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return downgradePGSQLDatabaseFrom5To4(p.dbHandle)
|
||||
case 7:
|
||||
err = downgradePGSQLDatabaseFrom7To6(p.dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = downgradePGSQLDatabaseFrom6To5(p.dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return downgradePGSQLDatabaseFrom5To4(p.dbHandle)
|
||||
case 6:
|
||||
err = downgradePGSQLDatabaseFrom6To5(p.dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return downgradePGSQLDatabaseFrom5To4(p.dbHandle)
|
||||
case 5:
|
||||
return downgradePGSQLDatabaseFrom5To4(p.dbHandle)
|
||||
default:
|
||||
return fmt.Errorf("Database version not handled: %v", dbVersion.Version)
|
||||
return errors.New("current version match target version, nothing to do")
|
||||
}
|
||||
}
|
||||
|
||||
func updatePGSQLDatabaseFromV1(dbHandle *sql.DB) error {
|
||||
err := updatePGSQLDatabaseFrom1To2(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updatePGSQLDatabaseFromV2(dbHandle)
|
||||
}
|
||||
|
||||
func updatePGSQLDatabaseFromV2(dbHandle *sql.DB) error {
|
||||
err := updatePGSQLDatabaseFrom2To3(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updatePGSQLDatabaseFromV3(dbHandle)
|
||||
}
|
||||
|
||||
func updatePGSQLDatabaseFromV3(dbHandle *sql.DB) error {
|
||||
err := updatePGSQLDatabaseFrom3To4(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updatePGSQLDatabaseFromV4(dbHandle)
|
||||
}
|
||||
|
||||
func updatePGSQLDatabaseFromV4(dbHandle *sql.DB) error {
|
||||
err := updatePGSQLDatabaseFrom4To5(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updatePGSQLDatabaseFromV5(dbHandle)
|
||||
}
|
||||
|
||||
func updatePGSQLDatabaseFromV5(dbHandle *sql.DB) error {
|
||||
err := updatePGSQLDatabaseFrom5To6(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updatePGSQLDatabaseFromV6(dbHandle)
|
||||
}
|
||||
|
||||
func updatePGSQLDatabaseFromV6(dbHandle *sql.DB) error {
|
||||
err := updatePGSQLDatabaseFrom6To7(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updatePGSQLDatabaseFromV7(dbHandle)
|
||||
}
|
||||
|
||||
func updatePGSQLDatabaseFromV7(dbHandle *sql.DB) error {
|
||||
return updatePGSQLDatabaseFrom7To8(dbHandle)
|
||||
}
|
||||
|
||||
func updatePGSQLDatabaseFrom1To2(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("updating database version: 1 -> 2")
|
||||
providerLog(logger.LevelInfo, "updating database version: 1 -> 2")
|
||||
sql := strings.Replace(pgsqlV2SQL, "{{users}}", sqlTableUsers, 1)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 2)
|
||||
}
|
||||
|
||||
func updatePGSQLDatabaseFrom2To3(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("updating database version: 2 -> 3")
|
||||
providerLog(logger.LevelInfo, "updating database version: 2 -> 3")
|
||||
sql := strings.Replace(pgsqlV3SQL, "{{users}}", sqlTableUsers, 1)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 3)
|
||||
}
|
||||
|
||||
func updatePGSQLDatabaseFrom3To4(dbHandle *sql.DB) error {
|
||||
return sqlCommonUpdateDatabaseFrom3To4(pgsqlV4SQL, dbHandle)
|
||||
}
|
||||
|
||||
func updatePGSQLDatabaseFrom4To5(dbHandle *sql.DB) error {
|
||||
return sqlCommonUpdateDatabaseFrom4To5(dbHandle)
|
||||
}
|
||||
|
||||
func updatePGSQLDatabaseFrom5To6(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("updating database version: 5 -> 6")
|
||||
providerLog(logger.LevelInfo, "updating database version: 5 -> 6")
|
||||
sql := strings.Replace(pgsqlV6SQL, "{{users}}", sqlTableUsers, 1)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 6)
|
||||
}
|
||||
|
||||
func updatePGSQLDatabaseFrom6To7(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("updating database version: 6 -> 7")
|
||||
providerLog(logger.LevelInfo, "updating database version: 6 -> 7")
|
||||
sql := strings.Replace(pgsqlV7SQL, "{{admins}}", sqlTableAdmins, 1)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 7)
|
||||
}
|
||||
|
||||
func updatePGSQLDatabaseFrom7To8(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("updating database version: 7 -> 8")
|
||||
providerLog(logger.LevelInfo, "updating database version: 7 -> 8")
|
||||
sql := strings.ReplaceAll(pgsqlV8SQL, "{{folders}}", sqlTableFolders)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 8)
|
||||
}
|
||||
|
||||
func downgradePGSQLDatabaseFrom8To7(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("downgrading database version: 8 -> 7")
|
||||
providerLog(logger.LevelInfo, "downgrading database version: 8 -> 7")
|
||||
sql := strings.ReplaceAll(pgsqlV8DownSQL, "{{folders}}", sqlTableAdmins)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 7)
|
||||
}
|
||||
|
||||
func downgradePGSQLDatabaseFrom7To6(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("downgrading database version: 7 -> 6")
|
||||
providerLog(logger.LevelInfo, "downgrading database version: 7 -> 6")
|
||||
sql := strings.Replace(pgsqlV7DownSQL, "{{admins}}", sqlTableAdmins, 1)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 6)
|
||||
}
|
||||
|
||||
func downgradePGSQLDatabaseFrom6To5(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("downgrading database version: 6 -> 5")
|
||||
providerLog(logger.LevelInfo, "downgrading database version: 6 -> 5")
|
||||
sql := strings.Replace(pgsqlV6DownSQL, "{{users}}", sqlTableUsers, 1)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 5)
|
||||
}
|
||||
|
||||
func downgradePGSQLDatabaseFrom5To4(dbHandle *sql.DB) error {
|
||||
return sqlCommonDowngradeDatabaseFrom5To4(dbHandle)
|
||||
return errors.New("the current version cannot be reverted")
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ import (
|
|||
|
||||
const (
|
||||
sqlDatabaseVersion = 8
|
||||
initialDBVersionSQL = "INSERT INTO {{schema_version}} (version) VALUES (1);"
|
||||
defaultSQLQueryTimeout = 10 * time.Second
|
||||
longSQLQueryTimeout = 60 * time.Second
|
||||
)
|
||||
|
@ -482,25 +481,6 @@ func sqlCommonGetUsers(limit int, offset int, order string, dbHandle sqlQuerier)
|
|||
return getUsersWithVirtualFolders(users, dbHandle)
|
||||
}
|
||||
|
||||
func updateUserPermissionsFromDb(user *User, permissions string) error {
|
||||
var err error
|
||||
perms := make(map[string][]string)
|
||||
err = json.Unmarshal([]byte(permissions), &perms)
|
||||
if err == nil {
|
||||
user.Permissions = perms
|
||||
} else {
|
||||
// compatibility layer: until version 0.9.4 permissions were a string list
|
||||
var list []string
|
||||
err = json.Unmarshal([]byte(permissions), &list)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
perms["/"] = list
|
||||
user.Permissions = perms
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func getAdminFromDbRow(row sqlScanner) (Admin, error) {
|
||||
var admin Admin
|
||||
var email, filters, additionalInfo, permissions sql.NullString
|
||||
|
@ -574,10 +554,13 @@ func getUserFromDbRow(row sqlScanner) (User, error) {
|
|||
}
|
||||
}
|
||||
if permissions.Valid {
|
||||
err = updateUserPermissionsFromDb(&user, permissions.String)
|
||||
perms := make(map[string][]string)
|
||||
err = json.Unmarshal([]byte(permissions.String), &perms)
|
||||
if err != nil {
|
||||
return user, err
|
||||
providerLog(logger.LevelDebug, "unable to deserialize permissions for user %#v: %v", user.Username, err)
|
||||
return user, fmt.Errorf("unable to deserialize permissions for user %#v: %v", user.Username, err)
|
||||
}
|
||||
user.Permissions = perms
|
||||
}
|
||||
if filters.Valid {
|
||||
var userFilters UserFilters
|
||||
|
@ -1020,276 +1003,3 @@ func sqlCommonExecSQLAndUpdateDBVersion(dbHandle *sql.DB, sql []string, newVersi
|
|||
}
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
/*func sqlCommonGetCompatVirtualFolders(dbHandle *sql.DB) ([]userCompactVFolders, error) {
|
||||
users := []userCompactVFolders{}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultSQLQueryTimeout)
|
||||
defer cancel()
|
||||
q := getCompatVirtualFoldersQuery()
|
||||
stmt, err := dbHandle.PrepareContext(ctx, q)
|
||||
if err != nil {
|
||||
providerLog(logger.LevelWarn, "error preparing database query %#v: %v", q, err)
|
||||
return nil, err
|
||||
}
|
||||
defer stmt.Close()
|
||||
rows, err := stmt.QueryContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var user userCompactVFolders
|
||||
var virtualFolders sql.NullString
|
||||
err = rows.Scan(&user.ID, &user.Username, &virtualFolders)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if virtualFolders.Valid {
|
||||
var list []virtualFoldersCompact
|
||||
err = json.Unmarshal([]byte(virtualFolders.String), &list)
|
||||
if err == nil && len(list) > 0 {
|
||||
user.VirtualFolders = list
|
||||
users = append(users, user)
|
||||
}
|
||||
}
|
||||
}
|
||||
return users, rows.Err()
|
||||
}*/
|
||||
|
||||
/*func sqlCommonRestoreCompatVirtualFolders(ctx context.Context, users []userCompactVFolders, dbHandle sqlQuerier) ([]string, error) {
|
||||
foldersToScan := []string{}
|
||||
for _, user := range users {
|
||||
for _, vfolder := range user.VirtualFolders {
|
||||
providerLog(logger.LevelInfo, "restoring virtual folder: %+v for user %#v", vfolder, user.Username)
|
||||
// -1 means included in user quota, 0 means unlimited
|
||||
quotaSize := int64(-1)
|
||||
quotaFiles := -1
|
||||
if vfolder.ExcludeFromQuota {
|
||||
quotaFiles = 0
|
||||
quotaSize = 0
|
||||
}
|
||||
b, err := sqlCommonAddOrGetFolder(ctx, vfolder.MappedPath, 0, 0, 0, dbHandle)
|
||||
if err != nil {
|
||||
providerLog(logger.LevelWarn, "error restoring virtual folder for user %#v: %v", user.Username, err)
|
||||
return foldersToScan, err
|
||||
}
|
||||
u := User{
|
||||
ID: user.ID,
|
||||
Username: user.Username,
|
||||
}
|
||||
f := vfs.VirtualFolder{
|
||||
BaseVirtualFolder: b,
|
||||
VirtualPath: vfolder.VirtualPath,
|
||||
QuotaSize: quotaSize,
|
||||
QuotaFiles: quotaFiles,
|
||||
}
|
||||
err = sqlCommonAddFolderMapping(ctx, &u, f, dbHandle)
|
||||
if err != nil {
|
||||
providerLog(logger.LevelWarn, "error adding virtual folder mapping for user %#v: %v", user.Username, err)
|
||||
return foldersToScan, err
|
||||
}
|
||||
if !utils.IsStringInSlice(vfolder.MappedPath, foldersToScan) {
|
||||
foldersToScan = append(foldersToScan, vfolder.MappedPath)
|
||||
}
|
||||
providerLog(logger.LevelInfo, "virtual folder: %+v for user %#v successfully restored", vfolder, user.Username)
|
||||
}
|
||||
}
|
||||
return foldersToScan, nil
|
||||
}*/
|
||||
|
||||
func sqlCommonUpdateDatabaseFrom3To4(sqlV4 string, dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("updating database version: 3 -> 4")
|
||||
providerLog(logger.LevelInfo, "updating database version: 3 -> 4")
|
||||
/*users, err := sqlCommonGetCompatVirtualFolders(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}*/
|
||||
sql := strings.ReplaceAll(sqlV4, "{{users}}", sqlTableUsers)
|
||||
sql = strings.ReplaceAll(sql, "{{folders}}", sqlTableFolders)
|
||||
sql = strings.ReplaceAll(sql, "{{folders_mapping}}", sqlTableFoldersMapping)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), longSQLQueryTimeout)
|
||||
defer cancel()
|
||||
|
||||
tx, err := dbHandle.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, q := range strings.Split(sql, ";") {
|
||||
if strings.TrimSpace(q) == "" {
|
||||
continue
|
||||
}
|
||||
_, err = tx.ExecContext(ctx, q)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = sqlCommonUpdateDatabaseVersion(ctx, tx, 4)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
//nolint:dupl
|
||||
func sqlCommonUpdateDatabaseFrom4To5(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("updating database version: 4 -> 5")
|
||||
providerLog(logger.LevelInfo, "updating database version: 4 -> 5")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), longSQLQueryTimeout)
|
||||
defer cancel()
|
||||
q := getCompatV4FsConfigQuery()
|
||||
stmt, err := dbHandle.PrepareContext(ctx, q)
|
||||
if err != nil {
|
||||
providerLog(logger.LevelWarn, "error preparing database query %#v: %v", q, err)
|
||||
return err
|
||||
}
|
||||
defer stmt.Close()
|
||||
rows, err := stmt.QueryContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
users := []User{}
|
||||
for rows.Next() {
|
||||
var compatUser compatUserV4
|
||||
var fsConfigString sql.NullString
|
||||
err = rows.Scan(&compatUser.ID, &compatUser.Username, &fsConfigString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if fsConfigString.Valid {
|
||||
err = json.Unmarshal([]byte(fsConfigString.String), &compatUser.FsConfig)
|
||||
if err != nil {
|
||||
logger.WarnToConsole("failed to unmarshal v4 user %#v, is it already migrated?", compatUser.Username)
|
||||
continue
|
||||
}
|
||||
fsConfig, err := convertFsConfigFromV4(compatUser.FsConfig, compatUser.Username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
users = append(users, createUserFromV4(compatUser, fsConfig))
|
||||
}
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, user := range users {
|
||||
err = sqlCommonUpdateV4User(dbHandle, user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
providerLog(logger.LevelInfo, "filesystem config updated for user %#v", user.Username)
|
||||
}
|
||||
|
||||
ctxVersion, cancelVersion := context.WithTimeout(context.Background(), defaultSQLQueryTimeout)
|
||||
defer cancelVersion()
|
||||
|
||||
return sqlCommonUpdateDatabaseVersion(ctxVersion, dbHandle, 5)
|
||||
}
|
||||
|
||||
func sqlCommonUpdateV4CompatUser(dbHandle *sql.DB, user compatUserV4) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultSQLQueryTimeout)
|
||||
defer cancel()
|
||||
|
||||
q := updateCompatV4FsConfigQuery()
|
||||
stmt, err := dbHandle.PrepareContext(ctx, q)
|
||||
if err != nil {
|
||||
providerLog(logger.LevelWarn, "error preparing database query %#v: %v", q, err)
|
||||
return err
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
fsConfig, err := json.Marshal(user.FsConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = stmt.ExecContext(ctx, string(fsConfig), user.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
func sqlCommonUpdateV4User(dbHandle *sql.DB, user User) error {
|
||||
err := validateFilesystemConfig(&user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = saveGCSCredentials(&user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultSQLQueryTimeout)
|
||||
defer cancel()
|
||||
|
||||
q := updateCompatV4FsConfigQuery()
|
||||
stmt, err := dbHandle.PrepareContext(ctx, q)
|
||||
if err != nil {
|
||||
providerLog(logger.LevelWarn, "error preparing database query %#v: %v", q, err)
|
||||
return err
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
fsConfig, err := user.GetFsConfigAsJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = stmt.ExecContext(ctx, string(fsConfig), user.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
//nolint:dupl
|
||||
func sqlCommonDowngradeDatabaseFrom5To4(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("downgrading database version: 5 -> 4")
|
||||
providerLog(logger.LevelInfo, "downgrading database version: 5 -> 4")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), longSQLQueryTimeout)
|
||||
defer cancel()
|
||||
q := getCompatV4FsConfigQuery()
|
||||
stmt, err := dbHandle.PrepareContext(ctx, q)
|
||||
if err != nil {
|
||||
providerLog(logger.LevelWarn, "error preparing database query %#v: %v", q, err)
|
||||
return err
|
||||
}
|
||||
defer stmt.Close()
|
||||
rows, err := stmt.QueryContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
users := []compatUserV4{}
|
||||
for rows.Next() {
|
||||
var user User
|
||||
var fsConfigString sql.NullString
|
||||
err = rows.Scan(&user.ID, &user.Username, &fsConfigString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if fsConfigString.Valid {
|
||||
err = json.Unmarshal([]byte(fsConfigString.String), &user.FsConfig)
|
||||
if err != nil {
|
||||
logger.WarnToConsole("failed to unmarshal user %#v to v4, is it already migrated?", user.Username)
|
||||
continue
|
||||
}
|
||||
fsConfig, err := convertFsConfigToV4(user.FsConfig, user.Username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
users = append(users, convertUserToV4(user, fsConfig))
|
||||
}
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, user := range users {
|
||||
err = sqlCommonUpdateV4CompatUser(dbHandle, user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
providerLog(logger.LevelInfo, "filesystem config downgraded for user %#v", user.Username)
|
||||
}
|
||||
|
||||
ctxVersion, cancelVersion := context.WithTimeout(context.Background(), defaultSQLQueryTimeout)
|
||||
defer cancelVersion()
|
||||
|
||||
return sqlCommonUpdateDatabaseVersion(ctxVersion, dbHandle, 4)
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ package dataprovider
|
|||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
@ -19,84 +20,27 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
sqliteUsersTableSQL = `CREATE TABLE "{{users}}" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "username" varchar(255)
|
||||
NOT NULL UNIQUE, "password" varchar(255) NULL, "public_keys" text NULL, "home_dir" varchar(255) NOT NULL, "uid" integer NOT NULL,
|
||||
"gid" integer NOT NULL, "max_sessions" integer NOT NULL, "quota_size" bigint NOT NULL, "quota_files" integer NOT NULL,
|
||||
"permissions" text NOT NULL, "used_quota_size" bigint NOT NULL, "used_quota_files" integer NOT NULL,
|
||||
"last_quota_update" bigint NOT NULL, "upload_bandwidth" integer NOT NULL, "download_bandwidth" integer NOT NULL,
|
||||
"expiration_date" bigint NOT NULL, "last_login" bigint NOT NULL, "status" integer NOT NULL, "filters" text NULL,
|
||||
"filesystem" text NULL);`
|
||||
sqliteSchemaTableSQL = `CREATE TABLE "{{schema_version}}" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "version" integer NOT NULL);`
|
||||
sqliteV2SQL = `ALTER TABLE "{{users}}" ADD COLUMN "virtual_folders" text NULL;`
|
||||
sqliteV3SQL = `CREATE TABLE "new__users" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "username" varchar(255) NOT NULL UNIQUE,
|
||||
"password" text NULL, "public_keys" text NULL, "home_dir" varchar(255) NOT NULL, "uid" integer NOT NULL,
|
||||
"gid" integer NOT NULL, "max_sessions" integer NOT NULL, "quota_size" bigint NOT NULL, "quota_files" integer NOT NULL,
|
||||
"permissions" text NOT NULL, "used_quota_size" bigint NOT NULL, "used_quota_files" integer NOT NULL, "last_quota_update" bigint NOT NULL,
|
||||
"upload_bandwidth" integer NOT NULL, "download_bandwidth" integer NOT NULL, "expiration_date" bigint NOT NULL, "last_login" bigint NOT NULL,
|
||||
"status" integer NOT NULL, "filters" text NULL, "filesystem" text NULL, "virtual_folders" text NULL);
|
||||
INSERT INTO "new__users" ("id", "username", "public_keys", "home_dir", "uid", "gid", "max_sessions", "quota_size", "quota_files",
|
||||
"permissions", "used_quota_size", "used_quota_files", "last_quota_update", "upload_bandwidth", "download_bandwidth", "expiration_date",
|
||||
"last_login", "status", "filters", "filesystem", "virtual_folders", "password") SELECT "id", "username", "public_keys", "home_dir",
|
||||
"uid", "gid", "max_sessions", "quota_size", "quota_files", "permissions", "used_quota_size", "used_quota_files", "last_quota_update",
|
||||
"upload_bandwidth", "download_bandwidth", "expiration_date", "last_login", "status", "filters", "filesystem", "virtual_folders",
|
||||
"password" FROM "{{users}}";
|
||||
DROP TABLE "{{users}}";
|
||||
ALTER TABLE "new__users" RENAME TO "{{users}}";`
|
||||
sqliteV4SQL = `CREATE TABLE "{{folders}}" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "path" varchar(512) NOT NULL UNIQUE,
|
||||
"used_quota_size" bigint NOT NULL, "used_quota_files" integer NOT NULL, "last_quota_update" bigint NOT NULL);
|
||||
sqliteInitialSQL = `CREATE TABLE "{{schema_version}}" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "version" integer NOT NULL);
|
||||
CREATE TABLE "{{admins}}" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "username" varchar(255) NOT NULL UNIQUE,
|
||||
"password" varchar(255) NOT NULL, "email" varchar(255) NULL, "status" integer NOT NULL, "permissions" text NOT NULL,
|
||||
"filters" text NULL, "additional_info" text NULL);
|
||||
CREATE TABLE "{{folders}}" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(255) NOT NULL UNIQUE,
|
||||
"path" varchar(512) NULL, "used_quota_size" bigint NOT NULL, "used_quota_files" integer NOT NULL,
|
||||
"last_quota_update" bigint NOT NULL);
|
||||
CREATE TABLE "{{users}}" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "username" varchar(255) NOT NULL UNIQUE,
|
||||
"password" text NULL, "public_keys" text NULL, "home_dir" varchar(512) NOT NULL, "uid" integer NOT NULL, "gid" integer NOT NULL,
|
||||
"max_sessions" integer NOT NULL, "quota_size" bigint NOT NULL, "quota_files" integer NOT NULL, "permissions" text NOT NULL,
|
||||
"used_quota_size" bigint NOT NULL, "used_quota_files" integer NOT NULL, "last_quota_update" bigint NOT NULL,
|
||||
"upload_bandwidth" integer NOT NULL, "download_bandwidth" integer NOT NULL, "expiration_date" bigint NOT NULL,
|
||||
"last_login" bigint NOT NULL, "status" integer NOT NULL, "filters" text NULL, "filesystem" text NULL,
|
||||
"additional_info" text NULL);
|
||||
CREATE TABLE "{{folders_mapping}}" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "virtual_path" varchar(512) NOT NULL,
|
||||
"quota_size" bigint NOT NULL, "quota_files" integer NOT NULL, "folder_id" integer NOT NULL REFERENCES "{{folders}}" ("id")
|
||||
ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, "user_id" integer NOT NULL REFERENCES "{{users}}" ("id") ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
||||
CONSTRAINT "unique_mapping" UNIQUE ("user_id", "folder_id"));
|
||||
CREATE TABLE "new__users" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "username" varchar(255) NOT NULL UNIQUE, "password" text NULL,
|
||||
"public_keys" text NULL, "home_dir" varchar(512) NOT NULL, "uid" integer NOT NULL, "gid" integer NOT NULL, "max_sessions" integer NOT NULL,
|
||||
"quota_size" bigint NOT NULL, "quota_files" integer NOT NULL, "permissions" text NOT NULL, "used_quota_size" bigint NOT NULL,
|
||||
"used_quota_files" integer NOT NULL, "last_quota_update" bigint NOT NULL, "upload_bandwidth" integer NOT NULL, "download_bandwidth" integer NOT NULL,
|
||||
"expiration_date" bigint NOT NULL, "last_login" bigint NOT NULL, "status" integer NOT NULL, "filters" text NULL, "filesystem" text NULL);
|
||||
INSERT INTO "new__users" ("id", "username", "password", "public_keys", "home_dir", "uid", "gid", "max_sessions", "quota_size", "quota_files",
|
||||
"permissions", "used_quota_size", "used_quota_files", "last_quota_update", "upload_bandwidth", "download_bandwidth", "expiration_date",
|
||||
"last_login", "status", "filters", "filesystem") SELECT "id", "username", "password", "public_keys", "home_dir", "uid", "gid", "max_sessions",
|
||||
"quota_size", "quota_files", "permissions", "used_quota_size", "used_quota_files", "last_quota_update", "upload_bandwidth", "download_bandwidth",
|
||||
"expiration_date", "last_login", "status", "filters", "filesystem" FROM "{{users}}";
|
||||
DROP TABLE "{{users}}";
|
||||
ALTER TABLE "new__users" RENAME TO "{{users}}";
|
||||
CREATE INDEX "folders_mapping_folder_id_idx" ON "{{folders_mapping}}" ("folder_id");
|
||||
CREATE INDEX "folders_mapping_user_id_idx" ON "{{folders_mapping}}" ("user_id");
|
||||
`
|
||||
sqliteV6SQL = `ALTER TABLE "{{users}}" ADD COLUMN "additional_info" text NULL;`
|
||||
sqliteV6DownSQL = `CREATE TABLE "new__users" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "username" varchar(255) NOT NULL UNIQUE,
|
||||
"password" text NULL, "public_keys" text NULL, "home_dir" varchar(512) NOT NULL, "uid" integer NOT NULL, "gid" integer NOT NULL,
|
||||
"max_sessions" integer NOT NULL, "quota_size" bigint NOT NULL, "quota_files" integer NOT NULL, "permissions" text NOT NULL,
|
||||
"used_quota_size" bigint NOT NULL, "used_quota_files" integer NOT NULL, "last_quota_update" bigint NOT NULL, "upload_bandwidth" integer NOT NULL,
|
||||
"download_bandwidth" integer NOT NULL, "expiration_date" bigint NOT NULL, "last_login" bigint NOT NULL, "status" integer NOT NULL,
|
||||
"filters" text NULL, "filesystem" text NULL);
|
||||
INSERT INTO "new__users" ("id", "username", "password", "public_keys", "home_dir", "uid", "gid", "max_sessions", "quota_size", "quota_files",
|
||||
"permissions", "used_quota_size", "used_quota_files", "last_quota_update", "upload_bandwidth", "download_bandwidth", "expiration_date",
|
||||
"last_login", "status", "filters", "filesystem") SELECT "id", "username", "password", "public_keys", "home_dir", "uid", "gid", "max_sessions",
|
||||
"quota_size", "quota_files", "permissions", "used_quota_size", "used_quota_files", "last_quota_update", "upload_bandwidth", "download_bandwidth",
|
||||
"expiration_date", "last_login", "status", "filters", "filesystem" FROM "{{users}}";
|
||||
DROP TABLE "{{users}}";
|
||||
ALTER TABLE "new__users" RENAME TO "{{users}}";
|
||||
`
|
||||
sqliteV7SQL = `CREATE TABLE "{{admins}}" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "username" varchar(255) NOT NULL UNIQUE,
|
||||
"password" varchar(255) NOT NULL, "email" varchar(255) NULL, "status" integer NOT NULL, "permissions" text NOT NULL, "filters" text NULL,
|
||||
"additional_info" text NULL);`
|
||||
sqliteV7DownSQL = `DROP TABLE "{{admins}}";`
|
||||
sqliteV8SQL = `CREATE TABLE "new__folders" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"name" varchar(255) NOT NULL UNIQUE, "path" varchar(512) NULL, "used_quota_size" bigint NOT NULL,
|
||||
"used_quota_files" integer NOT NULL, "last_quota_update" bigint NOT NULL);
|
||||
INSERT INTO "new__folders" ("id", "path", "used_quota_size", "used_quota_files", "last_quota_update", "name")
|
||||
SELECT "id", "path", "used_quota_size", "used_quota_files", "last_quota_update", ('folder' || "id") FROM "{{folders}}";
|
||||
DROP TABLE "{{folders}}";
|
||||
ALTER TABLE "new__folders" RENAME TO "{{folders}}";
|
||||
`
|
||||
sqliteV8DownSQL = `CREATE TABLE "new__folders" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"path" varchar(512) NOT NULL UNIQUE, "used_quota_size" bigint NOT NULL, "used_quota_files" integer NOT NULL,
|
||||
"last_quota_update" bigint NOT NULL);
|
||||
INSERT INTO "new__folders" ("id", "path", "used_quota_size", "used_quota_files", "last_quota_update")
|
||||
SELECT "id", "path", "used_quota_size", "used_quota_files", "last_quota_update" FROM "{{folders}}";
|
||||
DROP TABLE "{{folders}}";
|
||||
ALTER TABLE "new__folders" RENAME TO "{{folders}}";
|
||||
INSERT INTO {{schema_version}} (version) VALUES (8);
|
||||
`
|
||||
)
|
||||
|
||||
|
@ -261,27 +205,13 @@ func (p *SQLiteProvider) initializeDatabase() error {
|
|||
if err == nil && dbVersion.Version > 0 {
|
||||
return ErrNoInitRequired
|
||||
}
|
||||
sqlUsers := strings.Replace(sqliteUsersTableSQL, "{{users}}", sqlTableUsers, 1)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), longSQLQueryTimeout)
|
||||
defer cancel()
|
||||
initialSQL := strings.ReplaceAll(sqliteInitialSQL, "{{schema_version}}", sqlTableSchemaVersion)
|
||||
initialSQL = strings.ReplaceAll(initialSQL, "{{admins}}", sqlTableAdmins)
|
||||
initialSQL = strings.ReplaceAll(initialSQL, "{{folders}}", sqlTableFolders)
|
||||
initialSQL = strings.ReplaceAll(initialSQL, "{{users}}", sqlTableUsers)
|
||||
initialSQL = strings.ReplaceAll(initialSQL, "{{folders_mapping}}", sqlTableFoldersMapping)
|
||||
|
||||
tx, err := p.dbHandle.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.Exec(sqlUsers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.Exec(strings.Replace(sqliteSchemaTableSQL, "{{schema_version}}", sqlTableSchemaVersion, 1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.Exec(strings.Replace(initialDBVersionSQL, "{{schema_version}}", sqlTableSchemaVersion, 1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Commit()
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(p.dbHandle, []string{initialSQL}, 8)
|
||||
}
|
||||
|
||||
func (p *SQLiteProvider) migrateDatabase() error {
|
||||
|
@ -289,222 +219,35 @@ func (p *SQLiteProvider) migrateDatabase() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dbVersion.Version == sqlDatabaseVersion {
|
||||
providerLog(logger.LevelDebug, "sql database is up to date, current version: %v", dbVersion.Version)
|
||||
|
||||
switch version := dbVersion.Version; {
|
||||
case version == sqlDatabaseVersion:
|
||||
providerLog(logger.LevelDebug, "sql database is up to date, current version: %v", version)
|
||||
return ErrNoInitRequired
|
||||
}
|
||||
switch dbVersion.Version {
|
||||
case 1:
|
||||
return updateSQLiteDatabaseFromV1(p.dbHandle)
|
||||
case 2:
|
||||
return updateSQLiteDatabaseFromV2(p.dbHandle)
|
||||
case 3:
|
||||
return updateSQLiteDatabaseFromV3(p.dbHandle)
|
||||
case 4:
|
||||
return updateSQLiteDatabaseFromV4(p.dbHandle)
|
||||
case 5:
|
||||
return updateSQLiteDatabaseFromV5(p.dbHandle)
|
||||
case 6:
|
||||
return updateSQLiteDatabaseFromV6(p.dbHandle)
|
||||
case 7:
|
||||
return updateSQLiteDatabaseFromV7(p.dbHandle)
|
||||
case version < 8:
|
||||
err = fmt.Errorf("database version %v is too old, please see the upgrading docs", version)
|
||||
providerLog(logger.LevelError, "%v", err)
|
||||
logger.ErrorToConsole("%v", err)
|
||||
return err
|
||||
default:
|
||||
if dbVersion.Version > sqlDatabaseVersion {
|
||||
providerLog(logger.LevelWarn, "database version %v is newer than the supported: %v", dbVersion.Version,
|
||||
if version > sqlDatabaseVersion {
|
||||
providerLog(logger.LevelWarn, "database version %v is newer than the supported one: %v", version,
|
||||
sqlDatabaseVersion)
|
||||
logger.WarnToConsole("database version %v is newer than the supported: %v", dbVersion.Version,
|
||||
logger.WarnToConsole("database version %v is newer than the supported one: %v", version,
|
||||
sqlDatabaseVersion)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Database version not handled: %v", dbVersion.Version)
|
||||
return fmt.Errorf("Database version not handled: %v", version)
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:dupl
|
||||
func (p *SQLiteProvider) revertDatabase(targetVersion int) error {
|
||||
dbVersion, err := sqlCommonGetDatabaseVersion(p.dbHandle, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dbVersion.Version == targetVersion {
|
||||
return fmt.Errorf("current version match target version, nothing to do")
|
||||
}
|
||||
switch dbVersion.Version {
|
||||
case 8:
|
||||
err = downgradeSQLiteDatabaseFrom8To7(p.dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = downgradeSQLiteDatabaseFrom7To6(p.dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = downgradeSQLiteDatabaseFrom6To5(p.dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return downgradeSQLiteDatabaseFrom5To4(p.dbHandle)
|
||||
case 7:
|
||||
err = downgradeSQLiteDatabaseFrom7To6(p.dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = downgradeSQLiteDatabaseFrom6To5(p.dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return downgradeSQLiteDatabaseFrom5To4(p.dbHandle)
|
||||
case 6:
|
||||
err = downgradeSQLiteDatabaseFrom6To5(p.dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return downgradeSQLiteDatabaseFrom5To4(p.dbHandle)
|
||||
case 5:
|
||||
return downgradeSQLiteDatabaseFrom5To4(p.dbHandle)
|
||||
default:
|
||||
return fmt.Errorf("Database version not handled: %v", dbVersion.Version)
|
||||
return errors.New("current version match target version, nothing to do")
|
||||
}
|
||||
}
|
||||
|
||||
func updateSQLiteDatabaseFromV1(dbHandle *sql.DB) error {
|
||||
err := updateSQLiteDatabaseFrom1To2(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updateSQLiteDatabaseFromV2(dbHandle)
|
||||
}
|
||||
|
||||
func updateSQLiteDatabaseFromV2(dbHandle *sql.DB) error {
|
||||
err := updateSQLiteDatabaseFrom2To3(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updateSQLiteDatabaseFromV3(dbHandle)
|
||||
}
|
||||
|
||||
func updateSQLiteDatabaseFromV3(dbHandle *sql.DB) error {
|
||||
err := updateSQLiteDatabaseFrom3To4(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updateSQLiteDatabaseFromV4(dbHandle)
|
||||
}
|
||||
|
||||
func updateSQLiteDatabaseFromV4(dbHandle *sql.DB) error {
|
||||
err := updateSQLiteDatabaseFrom4To5(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updateSQLiteDatabaseFromV5(dbHandle)
|
||||
}
|
||||
|
||||
func updateSQLiteDatabaseFromV5(dbHandle *sql.DB) error {
|
||||
err := updateSQLiteDatabaseFrom5To6(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updateSQLiteDatabaseFromV6(dbHandle)
|
||||
}
|
||||
|
||||
func updateSQLiteDatabaseFromV6(dbHandle *sql.DB) error {
|
||||
err := updateSQLiteDatabaseFrom6To7(dbHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updateSQLiteDatabaseFromV7(dbHandle)
|
||||
}
|
||||
|
||||
func updateSQLiteDatabaseFromV7(dbHandle *sql.DB) error {
|
||||
return updateSQLiteDatabaseFrom7To8(dbHandle)
|
||||
}
|
||||
|
||||
func updateSQLiteDatabaseFrom1To2(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("updating database version: 1 -> 2")
|
||||
providerLog(logger.LevelInfo, "updating database version: 1 -> 2")
|
||||
sql := strings.Replace(sqliteV2SQL, "{{users}}", sqlTableUsers, 1)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 2)
|
||||
}
|
||||
|
||||
func updateSQLiteDatabaseFrom2To3(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("updating database version: 2 -> 3")
|
||||
providerLog(logger.LevelInfo, "updating database version: 2 -> 3")
|
||||
sql := strings.ReplaceAll(sqliteV3SQL, "{{users}}", sqlTableUsers)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 3)
|
||||
}
|
||||
|
||||
func updateSQLiteDatabaseFrom3To4(dbHandle *sql.DB) error {
|
||||
return sqlCommonUpdateDatabaseFrom3To4(sqliteV4SQL, dbHandle)
|
||||
}
|
||||
|
||||
func updateSQLiteDatabaseFrom4To5(dbHandle *sql.DB) error {
|
||||
return sqlCommonUpdateDatabaseFrom4To5(dbHandle)
|
||||
}
|
||||
|
||||
func updateSQLiteDatabaseFrom5To6(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("updating database version: 5 -> 6")
|
||||
providerLog(logger.LevelInfo, "updating database version: 5 -> 6")
|
||||
sql := strings.Replace(sqliteV6SQL, "{{users}}", sqlTableUsers, 1)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 6)
|
||||
}
|
||||
|
||||
func updateSQLiteDatabaseFrom6To7(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("updating database version: 6 -> 7")
|
||||
providerLog(logger.LevelInfo, "updating database version: 6 -> 7")
|
||||
sql := strings.Replace(sqliteV7SQL, "{{admins}}", sqlTableAdmins, 1)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 7)
|
||||
}
|
||||
|
||||
func updateSQLiteDatabaseFrom7To8(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("updating database version: 7 -> 8")
|
||||
providerLog(logger.LevelInfo, "updating database version: 7 -> 8")
|
||||
if err := setPragmaFK(dbHandle, "OFF"); err != nil {
|
||||
return err
|
||||
}
|
||||
sql := strings.ReplaceAll(sqliteV8SQL, "{{folders}}", sqlTableFolders)
|
||||
if err := sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 8); err != nil {
|
||||
return err
|
||||
}
|
||||
return setPragmaFK(dbHandle, "ON")
|
||||
}
|
||||
|
||||
func setPragmaFK(dbHandle *sql.DB, value string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), longSQLQueryTimeout)
|
||||
defer cancel()
|
||||
|
||||
sql := fmt.Sprintf("PRAGMA foreign_keys=%v;", value)
|
||||
|
||||
_, err := dbHandle.ExecContext(ctx, sql)
|
||||
return err
|
||||
}
|
||||
|
||||
func downgradeSQLiteDatabaseFrom8To7(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("downgrading database version: 8 -> 7")
|
||||
providerLog(logger.LevelInfo, "downgrading database version: 8 -> 7")
|
||||
if err := setPragmaFK(dbHandle, "OFF"); err != nil {
|
||||
return err
|
||||
}
|
||||
sql := strings.ReplaceAll(sqliteV8DownSQL, "{{folders}}", sqlTableFolders)
|
||||
if err := sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 7); err != nil {
|
||||
return err
|
||||
}
|
||||
return setPragmaFK(dbHandle, "ON")
|
||||
}
|
||||
|
||||
func downgradeSQLiteDatabaseFrom7To6(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("downgrading database version: 7 -> 6")
|
||||
providerLog(logger.LevelInfo, "downgrading database version: 7 -> 6")
|
||||
sql := strings.Replace(sqliteV7DownSQL, "{{admins}}", sqlTableAdmins, 1)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 6)
|
||||
}
|
||||
|
||||
func downgradeSQLiteDatabaseFrom6To5(dbHandle *sql.DB) error {
|
||||
logger.InfoToConsole("downgrading database version: 6 -> 5")
|
||||
providerLog(logger.LevelInfo, "downgrading database version: 6 -> 5")
|
||||
sql := strings.ReplaceAll(sqliteV6DownSQL, "{{users}}", sqlTableUsers)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(dbHandle, []string{sql}, 5)
|
||||
}
|
||||
|
||||
func downgradeSQLiteDatabaseFrom5To4(dbHandle *sql.DB) error {
|
||||
return sqlCommonDowngradeDatabaseFrom5To4(dbHandle)
|
||||
return errors.New("the current version cannot be reverted")
|
||||
}
|
||||
|
|
|
@ -203,15 +203,3 @@ func getDatabaseVersionQuery() string {
|
|||
func getUpdateDBVersionQuery() string {
|
||||
return fmt.Sprintf(`UPDATE %v SET version=%v`, sqlTableSchemaVersion, sqlPlaceholders[0])
|
||||
}
|
||||
|
||||
/*func getCompatVirtualFoldersQuery() string {
|
||||
return fmt.Sprintf(`SELECT id,username,virtual_folders FROM %v`, sqlTableUsers)
|
||||
}*/
|
||||
|
||||
func getCompatV4FsConfigQuery() string {
|
||||
return fmt.Sprintf(`SELECT id,username,filesystem FROM %v`, sqlTableUsers)
|
||||
}
|
||||
|
||||
func updateCompatV4FsConfigQuery() string {
|
||||
return fmt.Sprintf(`UPDATE %v SET filesystem=%v WHERE id=%v`, sqlTableUsers, sqlPlaceholders[0], sqlPlaceholders[1])
|
||||
}
|
||||
|
|
22
go.mod
22
go.mod
|
@ -3,21 +3,22 @@ module github.com/drakkan/sftpgo
|
|||
go 1.15
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.76.0 // indirect
|
||||
cloud.google.com/go v0.77.0 // indirect
|
||||
cloud.google.com/go/storage v1.13.0
|
||||
github.com/Azure/azure-storage-blob-go v0.13.0
|
||||
github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962
|
||||
github.com/alexedwards/argon2id v0.0.0-20201228115903-cf543ebc1f7b
|
||||
github.com/aws/aws-sdk-go v1.37.10
|
||||
github.com/aws/aws-sdk-go v1.37.15
|
||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect
|
||||
github.com/eikenb/pipeat v0.0.0-20200430215831-470df5986b6d
|
||||
github.com/fclairamb/ftpserverlib v0.12.0
|
||||
github.com/frankban/quicktest v1.11.3 // indirect
|
||||
github.com/go-chi/chi v1.5.2
|
||||
github.com/go-chi/chi v1.5.3
|
||||
github.com/go-chi/jwtauth v1.2.0
|
||||
github.com/go-chi/render v1.0.1
|
||||
github.com/go-ole/go-ole v1.2.5 // indirect
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/goccy/go-json v0.4.6 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||
github.com/google/uuid v1.2.0 // indirect
|
||||
github.com/google/wire v0.5.0 // indirect
|
||||
|
@ -25,7 +26,7 @@ require (
|
|||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.6.8
|
||||
github.com/jlaffaye/ftp v0.0.0-20201112195030-9aae4d151126
|
||||
github.com/lestrrat-go/jwx v1.1.1
|
||||
github.com/lestrrat-go/jwx v1.1.2
|
||||
github.com/lib/pq v1.9.0
|
||||
github.com/magiconair/properties v1.8.4 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.6
|
||||
|
@ -38,6 +39,7 @@ require (
|
|||
github.com/pires/go-proxyproto v0.4.2
|
||||
github.com/pkg/sftp v1.12.1-0.20201128220914-b5b6f3393fe9
|
||||
github.com/prometheus/client_golang v1.9.0
|
||||
github.com/prometheus/common v0.17.0 // indirect
|
||||
github.com/prometheus/procfs v0.6.0 // indirect
|
||||
github.com/rs/cors v1.7.1-0.20200626170627-8b4a00bd362b
|
||||
github.com/rs/xid v1.2.1
|
||||
|
@ -59,11 +61,11 @@ require (
|
|||
gocloud.dev/secrets/hashivault v0.22.0
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777
|
||||
golang.org/x/oauth2 v0.0.0-20210210192628-66670185b0cd // indirect
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c
|
||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93 // indirect
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
|
||||
google.golang.org/api v0.40.0
|
||||
google.golang.org/genproto v0.0.0-20210212180131-e7f2df4ecc2d // indirect
|
||||
google.golang.org/genproto v0.0.0-20210219173056-d891e3cb3b5b // indirect
|
||||
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
|
@ -72,6 +74,6 @@ require (
|
|||
replace (
|
||||
github.com/jlaffaye/ftp => github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9
|
||||
github.com/pkg/sftp => github.com/drakkan/sftp v0.0.0-20210210202350-a2b46fc9c0d5
|
||||
golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20201217113543-470e61ed2598
|
||||
golang.org/x/net => github.com/drakkan/net v0.0.0-20210201075003-5fb2b186574d
|
||||
golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20210221212101-dc57d1956176
|
||||
golang.org/x/net => github.com/drakkan/net v0.0.0-20210221212420-9117fa75ae3d
|
||||
)
|
||||
|
|
48
go.sum
48
go.sum
|
@ -19,8 +19,8 @@ cloud.google.com/go v0.66.0/go.mod h1:dgqGAjKCDxyhGTtC9dAREQGUJpkceNm1yt590Qno0K
|
|||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
|
||||
cloud.google.com/go v0.76.0 h1:Ckw+E/QYZgd/5bpI4wz4h6f+jmpvh9S9uSrKNnbicJI=
|
||||
cloud.google.com/go v0.76.0/go.mod h1:r9EvIAvLrunusnetGdQ50M/gKui1x3zdGW/VELGkdpw=
|
||||
cloud.google.com/go v0.77.0 h1:qA5V5+uQf6Mgr+tmFI8UT3D/ELyhIYkPwNGao/3Y+sQ=
|
||||
cloud.google.com/go v0.77.0/go.mod h1:R8fYSLIilC247Iu8WS2OGHw1E/Ufn7Pd7HiDjTqiURs=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
|
@ -116,8 +116,8 @@ github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZo
|
|||
github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.36.1/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go v1.37.10 h1:LRwl+97B4D69Z7tz+eRUxJ1C7baBaIYhgrn5eLtua+Q=
|
||||
github.com/aws/aws-sdk-go v1.37.10/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go v1.37.15 h1:W7l7gLLMcYRlg6a+uvf3Zz4jYwdqYzhe5ymqwWoOhp4=
|
||||
github.com/aws/aws-sdk-go v1.37.15/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
|
@ -167,12 +167,12 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
|
|||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
|
||||
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
|
||||
github.com/drakkan/crypto v0.0.0-20201217113543-470e61ed2598 h1:JawLnfGaG2uL0eFTRRX0t8J7pp0FhojAt9FSPqzV38U=
|
||||
github.com/drakkan/crypto v0.0.0-20201217113543-470e61ed2598/go.mod h1:HCh3rfXxsHzqOEbzc/nqz6WnUhb7Nv19n/o64V0Zmbg=
|
||||
github.com/drakkan/crypto v0.0.0-20210221212101-dc57d1956176 h1:ZQY12NIZ1HtS8Jqrw0oOEEgYfh3JtPLYsiZNDdkdW0w=
|
||||
github.com/drakkan/crypto v0.0.0-20210221212101-dc57d1956176/go.mod h1:HCh3rfXxsHzqOEbzc/nqz6WnUhb7Nv19n/o64V0Zmbg=
|
||||
github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9 h1:LPH1dEblAOO/LoG7yHPMtBLXhQmjaga91/DDjWk9jWA=
|
||||
github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9/go.mod h1:2lmrmq866uF2tnje75wQHzmPXhmSWUt7Gyx2vgK1RCU=
|
||||
github.com/drakkan/net v0.0.0-20210201075003-5fb2b186574d h1:h2rU/lTUkEYB3y4k6+FgQNMajf4uE+sbMRn85kT+VTQ=
|
||||
github.com/drakkan/net v0.0.0-20210201075003-5fb2b186574d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
github.com/drakkan/net v0.0.0-20210221212420-9117fa75ae3d h1:VUM47Q+HId0s2Kr6Cx/Iej3V3JQHxw/C9FzMRlaicDc=
|
||||
github.com/drakkan/net v0.0.0-20210221212420-9117fa75ae3d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
github.com/drakkan/sftp v0.0.0-20210210202350-a2b46fc9c0d5 h1:jVxjoPrGY9Ypw65tTHRdDvumOE3ys2fLZfvFT6+gFPU=
|
||||
github.com/drakkan/sftp v0.0.0-20210210202350-a2b46fc9c0d5/go.mod h1:fUqqXB5vEgVCZ131L+9say31RAri6aF6KDViawhxKK8=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
|
@ -208,10 +208,9 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
|
|||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/go-chi/chi v1.5.1 h1:kfTK3Cxd/dkMu/rKs5ZceWYp+t5CtiE7vmaTv3LjC6w=
|
||||
github.com/go-chi/chi v1.5.1/go.mod h1:REp24E+25iKvxgeTfHmdUoL5x15kBiDBlnIl5bCwe2k=
|
||||
github.com/go-chi/chi v1.5.2 h1:YcLIBANL4OTaAOcTdp//sskGa0yGACQMCtbnr7YEn0Q=
|
||||
github.com/go-chi/chi v1.5.2/go.mod h1:REp24E+25iKvxgeTfHmdUoL5x15kBiDBlnIl5bCwe2k=
|
||||
github.com/go-chi/chi v1.5.3 h1:+DVDS9/D3MTbEu3WrrH3oz9oP6PlSPSNj8LLw3X17yU=
|
||||
github.com/go-chi/chi v1.5.3/go.mod h1:Q8xfe6s3fjZyMr8ZTv5jL+vxhVaFyCq2s+RvSfzTD0E=
|
||||
github.com/go-chi/jwtauth v1.2.0 h1:Z116SPpevIABBYsv8ih/AHYBHmd4EufKSKsLUnWdrTM=
|
||||
github.com/go-chi/jwtauth v1.2.0/go.mod h1:NTUpKoTQV6o25UwYE6w/VaLUu83hzrVKYTVo+lE6qDA=
|
||||
github.com/go-chi/render v1.0.1 h1:4/5tis2cKaNdnv9zFLfXzcquC9HbeZgCnxGnKrltBS8=
|
||||
|
@ -247,8 +246,10 @@ github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr6
|
|||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
||||
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
||||
github.com/goccy/go-json v0.3.5 h1:HqrLjEWx7hD62JRhBh+mHv+rEEzBANIu6O0kbDlaLzU=
|
||||
github.com/goccy/go-json v0.3.5/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/goccy/go-json v0.4.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/goccy/go-json v0.4.6 h1:zpWhZVrIu+WfuJ1waElFa1KOnKj2p0H9wpJn/TTY0zQ=
|
||||
github.com/goccy/go-json v0.4.6/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
|
@ -458,8 +459,8 @@ github.com/lestrrat-go/httpcc v1.0.0/go.mod h1:tGS/u00Vh5N6FHNkExqGGNId8e0Big+++
|
|||
github.com/lestrrat-go/iter v1.0.0 h1:QD+hHQPDSHC4rCJkZYY/yXChYr/vjfBopKekTc+7l4Q=
|
||||
github.com/lestrrat-go/iter v1.0.0/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc=
|
||||
github.com/lestrrat-go/jwx v1.1.0/go.mod h1:vn9FzD6gJtKkgYs7RTKV7CjWtEka8F/voUollhnn4QE=
|
||||
github.com/lestrrat-go/jwx v1.1.1 h1:L7TqffHhO0qSyUcDGfCkDV42GQMp9fNOBi/zFOigMEY=
|
||||
github.com/lestrrat-go/jwx v1.1.1/go.mod h1:vn9FzD6gJtKkgYs7RTKV7CjWtEka8F/voUollhnn4QE=
|
||||
github.com/lestrrat-go/jwx v1.1.2 h1:Cpl6Y8KrMEilSdaX0YW9Zrdy2hPQ7lzYOh7bRAYLGNU=
|
||||
github.com/lestrrat-go/jwx v1.1.2/go.mod h1:gr+Z6vxDJQoGW6fA3b5PMgPE8AmaRXNUImLKp/S3vrk=
|
||||
github.com/lestrrat-go/option v0.0.0-20210103042652-6f1ecfceda35/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
||||
github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4=
|
||||
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
||||
|
@ -592,8 +593,9 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
|
|||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.15.0 h1:4fgOnadei3EZvgRwxJ7RMpG1k1pOZth5Pc13tyspaKM=
|
||||
github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
|
||||
github.com/prometheus/common v0.17.0 h1:kDIZLI74SS+3tedSvEkykgBkD7txMxaJAPj8DtJUKYA=
|
||||
github.com/prometheus/common v0.17.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
|
@ -661,7 +663,6 @@ github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3
|
|||
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
|
@ -762,8 +763,8 @@ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ
|
|||
golang.org/x/oauth2 v0.0.0-20201203001011-0b49973bad19/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210113205817-d3ed898aa8a3/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210210192628-66670185b0cd h1:2arJsLyTCJGek+eeptQ3z49Rqndm0f+zvvpwNIXWNIA=
|
||||
golang.org/x/oauth2 v0.0.0-20210210192628-66670185b0cd/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93 h1:alLDrZkL34Y2bnGHfvC1CYBRBXCXgx8AC2vY4MRtYX4=
|
||||
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -831,8 +832,9 @@ golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43 h1:SgQ6LNaYJU0JIuEHv9+s6EbhSCwYeAf5Yvj6lpYlqAE=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
|
@ -850,8 +852,8 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb
|
|||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE=
|
||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
@ -1000,10 +1002,10 @@ google.golang.org/genproto v0.0.0-20201203001206-6486ece9c497/go.mod h1:FWY/as6D
|
|||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210202153253-cf70463f6119/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210203152818-3206188e46ba/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210212180131-e7f2df4ecc2d h1:Edhcm0CKDPLQIecHCp5Iz57Lo7MfT6zUFBAlocmOjcY=
|
||||
google.golang.org/genproto v0.0.0-20210212180131-e7f2df4ecc2d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210219173056-d891e3cb3b5b h1:zTeTu5p/EXQSqNJboHUw32wdNFYQTT9vSc+ibSpCoLk=
|
||||
google.golang.org/genproto v0.0.0-20210219173056-d891e3cb3b5b/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
|
|
|
@ -2,7 +2,7 @@ package version
|
|||
|
||||
import "strings"
|
||||
|
||||
const version = "2.0.2-dev"
|
||||
const version = "2.0.90-dev"
|
||||
|
||||
var (
|
||||
commit = ""
|
||||
|
|
Loading…
Reference in a new issue