From 0e2d673889dfc89e239cb599a9f3e715587c91a4 Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Thu, 6 Jan 2022 10:11:47 +0100 Subject: [PATCH] move kms implementation outside the sdk package Signed-off-by: Nicola Murino --- cmd/portable.go | 30 +-- common/actions_test.go | 8 +- common/common_test.go | 10 +- common/connection_test.go | 12 +- common/protocol_test.go | 24 +- common/transfer_test.go | 4 +- config/config.go | 2 +- config/config_test.go | 18 +- dataprovider/admin.go | 17 +- dataprovider/dataprovider.go | 8 +- dataprovider/sqlcommon.go | 3 +- dataprovider/user.go | 45 +++- ftpd/cryptfs_test.go | 2 +- ftpd/ftpd_test.go | 11 +- httpd/api_admin.go | 4 +- httpd/api_mfa.go | 17 +- httpd/api_user.go | 6 +- httpd/httpd_test.go | 293 +++++++++++------------ httpd/internal_test.go | 18 +- httpd/webadmin.go | 15 +- httpd/webclient.go | 2 +- httpdtest/httpdtest.go | 2 +- {sdk/kms => kms}/basesecret.go | 16 +- {sdk/kms => kms}/builtin.go | 14 +- kms/kms.go | 417 ++++++++++++++++++++++++++++++++ {sdk/kms => kms}/local.go | 12 +- logger/logger.go | 21 -- plugin/kms.go | 13 +- plugin/plugin.go | 4 +- sdk/filesystem.go | 80 ++++--- sdk/kms/kms.go | 419 +-------------------------------- sdk/logger/logger.go | 57 ----- sdk/user.go | 35 +-- service/service_portable.go | 2 +- sftpd/cryptfs_test.go | 2 +- sftpd/internal_test.go | 8 +- sftpd/sftpd_test.go | 83 ++++--- vfs/filesystem.go | 26 +- vfs/gcsfs.go | 2 +- vfs/sftpfs.go | 8 +- vfs/vfs.go | 17 +- webdavd/internal_test.go | 2 +- webdavd/webdavd_test.go | 17 +- 43 files changed, 899 insertions(+), 907 deletions(-) rename {sdk/kms => kms}/basesecret.go (73%) rename {sdk/kms => kms}/builtin.go (88%) create mode 100644 kms/kms.go rename {sdk/kms => kms}/local.go (90%) delete mode 100644 sdk/logger/logger.go diff --git a/cmd/portable.go b/cmd/portable.go index 6f3d2a66..0d3b4242 100644 --- a/cmd/portable.go +++ b/cmd/portable.go @@ -14,8 +14,8 @@ import ( "github.com/drakkan/sftpgo/v2/common" "github.com/drakkan/sftpgo/v2/dataprovider" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/service" "github.com/drakkan/sftpgo/v2/sftpd" "github.com/drakkan/sftpgo/v2/version" @@ -157,18 +157,19 @@ Please take a look at the usage below to customize the serving parameters`, Permissions: permissions, HomeDir: portableDir, Status: 1, - Filters: sdk.UserFilters{ + }, + Filters: dataprovider.UserFilters{ + BaseUserFilters: sdk.BaseUserFilters{ FilePatterns: parsePatternsFilesFilters(), }, }, FsConfig: vfs.Filesystem{ Provider: sdk.GetProviderByName(portableFsProvider), S3Config: vfs.S3FsConfig{ - S3FsConfig: sdk.S3FsConfig{ + BaseS3FsConfig: sdk.BaseS3FsConfig{ Bucket: portableS3Bucket, Region: portableS3Region, AccessKey: portableS3AccessKey, - AccessSecret: kms.NewPlainSecret(portableS3AccessSecret), Endpoint: portableS3Endpoint, StorageClass: portableS3StorageClass, ACL: portableS3ACL, @@ -177,46 +178,45 @@ Please take a look at the usage below to customize the serving parameters`, UploadConcurrency: portableS3ULConcurrency, ForcePathStyle: portableS3ForcePathStyle, }, + AccessSecret: kms.NewPlainSecret(portableS3AccessSecret), }, GCSConfig: vfs.GCSFsConfig{ - GCSFsConfig: sdk.GCSFsConfig{ + BaseGCSFsConfig: sdk.BaseGCSFsConfig{ Bucket: portableGCSBucket, - Credentials: kms.NewPlainSecret(portableGCSCredentials), AutomaticCredentials: portableGCSAutoCredentials, StorageClass: portableGCSStorageClass, KeyPrefix: portableGCSKeyPrefix, }, + Credentials: kms.NewPlainSecret(portableGCSCredentials), }, AzBlobConfig: vfs.AzBlobFsConfig{ - AzBlobFsConfig: sdk.AzBlobFsConfig{ + BaseAzBlobFsConfig: sdk.BaseAzBlobFsConfig{ Container: portableAzContainer, AccountName: portableAzAccountName, - AccountKey: kms.NewPlainSecret(portableAzAccountKey), Endpoint: portableAzEndpoint, AccessTier: portableAzAccessTier, - SASURL: kms.NewPlainSecret(portableAzSASURL), KeyPrefix: portableAzKeyPrefix, UseEmulator: portableAzUseEmulator, UploadPartSize: int64(portableAzULPartSize), UploadConcurrency: portableAzULConcurrency, }, + AccountKey: kms.NewPlainSecret(portableAzAccountKey), + SASURL: kms.NewPlainSecret(portableAzSASURL), }, CryptConfig: vfs.CryptFsConfig{ - CryptFsConfig: sdk.CryptFsConfig{ - Passphrase: kms.NewPlainSecret(portableCryptPassphrase), - }, + Passphrase: kms.NewPlainSecret(portableCryptPassphrase), }, SFTPConfig: vfs.SFTPFsConfig{ - SFTPFsConfig: sdk.SFTPFsConfig{ + BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{ Endpoint: portableSFTPEndpoint, Username: portableSFTPUsername, - Password: kms.NewPlainSecret(portableSFTPPassword), - PrivateKey: kms.NewPlainSecret(portableSFTPPrivateKey), Fingerprints: portableSFTPFingerprints, Prefix: portableSFTPPrefix, DisableCouncurrentReads: portableSFTPDisableConcurrentReads, BufferSize: portableSFTPDBufferSize, }, + Password: kms.NewPlainSecret(portableSFTPPassword), + PrivateKey: kms.NewPlainSecret(portableSFTPPrivateKey), }, }, }, diff --git a/common/actions_test.go b/common/actions_test.go index 9f83d9eb..9c1f6fcb 100644 --- a/common/actions_test.go +++ b/common/actions_test.go @@ -28,24 +28,24 @@ func TestNewActionNotification(t *testing.T) { } user.FsConfig.Provider = sdk.LocalFilesystemProvider user.FsConfig.S3Config = vfs.S3FsConfig{ - S3FsConfig: sdk.S3FsConfig{ + BaseS3FsConfig: sdk.BaseS3FsConfig{ Bucket: "s3bucket", Endpoint: "endpoint", }, } user.FsConfig.GCSConfig = vfs.GCSFsConfig{ - GCSFsConfig: sdk.GCSFsConfig{ + BaseGCSFsConfig: sdk.BaseGCSFsConfig{ Bucket: "gcsbucket", }, } user.FsConfig.AzBlobConfig = vfs.AzBlobFsConfig{ - AzBlobFsConfig: sdk.AzBlobFsConfig{ + BaseAzBlobFsConfig: sdk.BaseAzBlobFsConfig{ Container: "azcontainer", Endpoint: "azendpoint", }, } user.FsConfig.SFTPConfig = vfs.SFTPFsConfig{ - SFTPFsConfig: sdk.SFTPFsConfig{ + BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{ Endpoint: "sftpendpoint", }, } diff --git a/common/common_test.go b/common/common_test.go index d543102a..d5079a20 100644 --- a/common/common_test.go +++ b/common/common_test.go @@ -19,8 +19,8 @@ import ( "golang.org/x/crypto/bcrypt" "github.com/drakkan/sftpgo/v2/dataprovider" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/util" "github.com/drakkan/sftpgo/v2/vfs" ) @@ -731,9 +731,7 @@ func TestPostConnectHook(t *testing.T) { func TestCryptoConvertFileInfo(t *testing.T) { name := "name" fs, err := vfs.NewCryptFs("connID1", os.TempDir(), "", vfs.CryptFsConfig{ - CryptFsConfig: sdk.CryptFsConfig{ - Passphrase: kms.NewPlainSecret("secret"), - }, + Passphrase: kms.NewPlainSecret("secret"), }) require.NoError(t, err) cryptFs := fs.(*vfs.CryptFs) @@ -772,9 +770,7 @@ func TestFolderCopy(t *testing.T) { folder.FsConfig = vfs.Filesystem{ CryptConfig: vfs.CryptFsConfig{ - CryptFsConfig: sdk.CryptFsConfig{ - Passphrase: kms.NewPlainSecret("crypto secret"), - }, + Passphrase: kms.NewPlainSecret("crypto secret"), }, } folderCopy = folder.GetACopy() diff --git a/common/connection_test.go b/common/connection_test.go index bd74bc29..92b3abc0 100644 --- a/common/connection_test.go +++ b/common/connection_test.go @@ -13,8 +13,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/drakkan/sftpgo/v2/dataprovider" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/vfs" ) @@ -419,12 +419,12 @@ func TestCheckParentDirsErrors(t *testing.T) { FsConfig: vfs.Filesystem{ Provider: sdk.S3FilesystemProvider, S3Config: vfs.S3FsConfig{ - S3FsConfig: sdk.S3FsConfig{ - Bucket: "buck", - Region: "us-east-1", - AccessKey: "key", - AccessSecret: kms.NewPlainSecret("s3secret"), + BaseS3FsConfig: sdk.BaseS3FsConfig{ + Bucket: "buck", + Region: "us-east-1", + AccessKey: "key", }, + AccessSecret: kms.NewPlainSecret("s3secret"), }, }, } diff --git a/common/protocol_test.go b/common/protocol_test.go index 1775aff1..af0665ef 100644 --- a/common/protocol_test.go +++ b/common/protocol_test.go @@ -34,10 +34,10 @@ import ( "github.com/drakkan/sftpgo/v2/dataprovider" "github.com/drakkan/sftpgo/v2/httpclient" "github.com/drakkan/sftpgo/v2/httpdtest" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/logger" "github.com/drakkan/sftpgo/v2/mfa" "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/util" "github.com/drakkan/sftpgo/v2/vfs" ) @@ -2758,7 +2758,7 @@ func TestBuiltinKeyboardInteractiveAuthentication(t *testing.T) { configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], user.Username) assert.NoError(t, err) user.Password = defaultPassword - user.Filters.TOTPConfig = sdk.TOTPConfig{ + user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{ Enabled: true, ConfigName: configName, Secret: kms.NewPlainSecret(secret), @@ -2926,11 +2926,11 @@ func TestSFTPLoopError(t *testing.T) { FsConfig: vfs.Filesystem{ Provider: sdk.SFTPFilesystemProvider, SFTPConfig: vfs.SFTPFsConfig{ - SFTPFsConfig: sdk.SFTPFsConfig{ + BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{ Endpoint: sftpServerAddr, Username: user2.Username, - Password: kms.NewPlainSecret(defaultPassword), }, + Password: kms.NewPlainSecret(defaultPassword), }, }, }, @@ -2939,11 +2939,11 @@ func TestSFTPLoopError(t *testing.T) { user2.FsConfig.Provider = sdk.SFTPFilesystemProvider user2.FsConfig.SFTPConfig = vfs.SFTPFsConfig{ - SFTPFsConfig: sdk.SFTPFsConfig{ + BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{ Endpoint: sftpServerAddr, Username: user1.Username, - Password: kms.NewPlainSecret(defaultPassword), }, + Password: kms.NewPlainSecret(defaultPassword), } user1, resp, err := httpdtest.AddUser(user1, http.StatusCreated) @@ -2995,11 +2995,11 @@ func TestNonLocalCrossRename(t *testing.T) { FsConfig: vfs.Filesystem{ Provider: sdk.SFTPFilesystemProvider, SFTPConfig: vfs.SFTPFsConfig{ - SFTPFsConfig: sdk.SFTPFsConfig{ + BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{ Endpoint: sftpServerAddr, Username: baseUser.Username, - Password: kms.NewPlainSecret(defaultPassword), }, + Password: kms.NewPlainSecret(defaultPassword), }, }, }, @@ -3014,9 +3014,7 @@ func TestNonLocalCrossRename(t *testing.T) { FsConfig: vfs.Filesystem{ Provider: sdk.CryptedFilesystemProvider, CryptConfig: vfs.CryptFsConfig{ - CryptFsConfig: sdk.CryptFsConfig{ - Passphrase: kms.NewPlainSecret(defaultPassword), - }, + Passphrase: kms.NewPlainSecret(defaultPassword), }, }, MappedPath: mappedPathCrypt, @@ -3117,9 +3115,7 @@ func TestNonLocalCrossRenameNonLocalBaseUser(t *testing.T) { FsConfig: vfs.Filesystem{ Provider: sdk.CryptedFilesystemProvider, CryptConfig: vfs.CryptFsConfig{ - CryptFsConfig: sdk.CryptFsConfig{ - Passphrase: kms.NewPlainSecret(defaultPassword), - }, + Passphrase: kms.NewPlainSecret(defaultPassword), }, }, MappedPath: mappedPathCrypt, diff --git a/common/transfer_test.go b/common/transfer_test.go index e01ef6ac..15421d07 100644 --- a/common/transfer_test.go +++ b/common/transfer_test.go @@ -11,8 +11,8 @@ import ( "github.com/stretchr/testify/require" "github.com/drakkan/sftpgo/v2/dataprovider" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/vfs" ) @@ -264,7 +264,7 @@ func TestTransferErrors(t *testing.T) { func TestRemovePartialCryptoFile(t *testing.T) { testFile := filepath.Join(os.TempDir(), "transfer_test_file") - fs, err := vfs.NewCryptFs("id", os.TempDir(), "", vfs.CryptFsConfig{CryptFsConfig: sdk.CryptFsConfig{Passphrase: kms.NewPlainSecret("secret")}}) + fs, err := vfs.NewCryptFs("id", os.TempDir(), "", vfs.CryptFsConfig{Passphrase: kms.NewPlainSecret("secret")}) require.NoError(t, err) u := dataprovider.User{ BaseUser: sdk.BaseUser{ diff --git a/config/config.go b/config/config.go index 6cc84998..1b83953e 100644 --- a/config/config.go +++ b/config/config.go @@ -16,10 +16,10 @@ import ( "github.com/drakkan/sftpgo/v2/ftpd" "github.com/drakkan/sftpgo/v2/httpclient" "github.com/drakkan/sftpgo/v2/httpd" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/logger" "github.com/drakkan/sftpgo/v2/mfa" "github.com/drakkan/sftpgo/v2/plugin" - "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/sftpd" "github.com/drakkan/sftpgo/v2/smtp" "github.com/drakkan/sftpgo/v2/telemetry" diff --git a/config/config_test.go b/config/config_test.go index b7c7f0b5..0c15521e 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -19,7 +19,7 @@ import ( "github.com/drakkan/sftpgo/v2/httpd" "github.com/drakkan/sftpgo/v2/mfa" "github.com/drakkan/sftpgo/v2/plugin" - "github.com/drakkan/sftpgo/v2/sdk/kms" + sdkkms "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/sftpd" "github.com/drakkan/sftpgo/v2/smtp" "github.com/drakkan/sftpgo/v2/util" @@ -467,8 +467,8 @@ func TestPluginsFromEnv(t *testing.T) { os.Setenv("SFTPGO_PLUGINS__0__ARGS", "arg1,arg2") os.Setenv("SFTPGO_PLUGINS__0__SHA256SUM", "0a71ded61fccd59c4f3695b51c1b3d180da8d2d77ea09ccee20dac242675c193") os.Setenv("SFTPGO_PLUGINS__0__AUTO_MTLS", "1") - os.Setenv("SFTPGO_PLUGINS__0__KMS_OPTIONS__SCHEME", kms.SchemeAWS) - os.Setenv("SFTPGO_PLUGINS__0__KMS_OPTIONS__ENCRYPTED_STATUS", kms.SecretStatusAWS) + os.Setenv("SFTPGO_PLUGINS__0__KMS_OPTIONS__SCHEME", sdkkms.SchemeAWS) + os.Setenv("SFTPGO_PLUGINS__0__KMS_OPTIONS__ENCRYPTED_STATUS", sdkkms.SecretStatusAWS) os.Setenv("SFTPGO_PLUGINS__0__AUTH_OPTIONS__SCOPE", "14") t.Cleanup(func() { os.Unsetenv("SFTPGO_PLUGINS__0__TYPE") @@ -510,8 +510,8 @@ func TestPluginsFromEnv(t *testing.T) { require.Equal(t, "arg2", pluginConf.Args[1]) require.Equal(t, "0a71ded61fccd59c4f3695b51c1b3d180da8d2d77ea09ccee20dac242675c193", pluginConf.SHA256Sum) require.True(t, pluginConf.AutoMTLS) - require.Equal(t, kms.SchemeAWS, pluginConf.KMSOptions.Scheme) - require.Equal(t, kms.SecretStatusAWS, pluginConf.KMSOptions.EncryptedStatus) + require.Equal(t, sdkkms.SchemeAWS, pluginConf.KMSOptions.Scheme) + require.Equal(t, sdkkms.SecretStatusAWS, pluginConf.KMSOptions.EncryptedStatus) require.Equal(t, 14, pluginConf.AuthOptions.Scope) configAsJSON, err := json.Marshal(pluginsConf) @@ -524,8 +524,8 @@ func TestPluginsFromEnv(t *testing.T) { os.Setenv("SFTPGO_PLUGINS__0__CMD", "plugin_start_cmd1") os.Setenv("SFTPGO_PLUGINS__0__ARGS", "") os.Setenv("SFTPGO_PLUGINS__0__AUTO_MTLS", "0") - os.Setenv("SFTPGO_PLUGINS__0__KMS_OPTIONS__SCHEME", kms.SchemeVaultTransit) - os.Setenv("SFTPGO_PLUGINS__0__KMS_OPTIONS__ENCRYPTED_STATUS", kms.SecretStatusVaultTransit) + os.Setenv("SFTPGO_PLUGINS__0__KMS_OPTIONS__SCHEME", sdkkms.SchemeVaultTransit) + os.Setenv("SFTPGO_PLUGINS__0__KMS_OPTIONS__ENCRYPTED_STATUS", sdkkms.SecretStatusVaultTransit) err = config.LoadConfig(configDir, confName) assert.NoError(t, err) pluginsConf = config.GetPluginsConfig() @@ -547,8 +547,8 @@ func TestPluginsFromEnv(t *testing.T) { require.Len(t, pluginConf.Args, 0) require.Equal(t, "0a71ded61fccd59c4f3695b51c1b3d180da8d2d77ea09ccee20dac242675c193", pluginConf.SHA256Sum) require.False(t, pluginConf.AutoMTLS) - require.Equal(t, kms.SchemeVaultTransit, pluginConf.KMSOptions.Scheme) - require.Equal(t, kms.SecretStatusVaultTransit, pluginConf.KMSOptions.EncryptedStatus) + require.Equal(t, sdkkms.SchemeVaultTransit, pluginConf.KMSOptions.Scheme) + require.Equal(t, sdkkms.SecretStatusVaultTransit, pluginConf.KMSOptions.EncryptedStatus) require.Equal(t, 14, pluginConf.AuthOptions.Scope) err = os.Remove(configFilePath) diff --git a/dataprovider/admin.go b/dataprovider/admin.go index 07116e91..ca1a9a45 100644 --- a/dataprovider/admin.go +++ b/dataprovider/admin.go @@ -15,10 +15,9 @@ import ( passwordvalidator "github.com/wagslane/go-password-validator" "golang.org/x/crypto/bcrypt" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/logger" "github.com/drakkan/sftpgo/v2/mfa" - "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/util" ) @@ -52,14 +51,14 @@ var ( PermAdminViewEvents} ) -// TOTPConfig defines the time-based one time password configuration -type TOTPConfig struct { +// AdminTOTPConfig defines the time-based one time password configuration +type AdminTOTPConfig struct { Enabled bool `json:"enabled,omitempty"` ConfigName string `json:"config_name,omitempty"` Secret *kms.Secret `json:"secret,omitempty"` } -func (c *TOTPConfig) validate(username string) error { +func (c *AdminTOTPConfig) validate(username string) error { if !c.Enabled { c.ConfigName = "" c.Secret = kms.NewEmptySecret() @@ -93,11 +92,11 @@ type AdminFilters struct { // API key auth allows to impersonate this administrator with an API key AllowAPIKeyAuth bool `json:"allow_api_key_auth,omitempty"` // Time-based one time passwords configuration - TOTPConfig TOTPConfig `json:"totp_config,omitempty"` + TOTPConfig AdminTOTPConfig `json:"totp_config,omitempty"` // Recovery codes to use if the user loses access to their second factor auth device. // Each code can only be used once, you should use these codes to login and disable or // reset 2FA for your account - RecoveryCodes []sdk.RecoveryCode `json:"recovery_codes,omitempty"` + RecoveryCodes []RecoveryCode `json:"recovery_codes,omitempty"` } // Admin defines a SFTPGo admin @@ -403,12 +402,12 @@ func (a *Admin) getACopy() Admin { filters.TOTPConfig.ConfigName = a.Filters.TOTPConfig.ConfigName filters.TOTPConfig.Secret = a.Filters.TOTPConfig.Secret.Clone() copy(filters.AllowList, a.Filters.AllowList) - filters.RecoveryCodes = make([]sdk.RecoveryCode, 0) + filters.RecoveryCodes = make([]RecoveryCode, 0) for _, code := range a.Filters.RecoveryCodes { if code.Secret == nil { code.Secret = kms.NewEmptySecret() } - filters.RecoveryCodes = append(filters.RecoveryCodes, sdk.RecoveryCode{ + filters.RecoveryCodes = append(filters.RecoveryCodes, RecoveryCode{ Secret: code.Secret.Clone(), Used: code.Used, }) diff --git a/dataprovider/dataprovider.go b/dataprovider/dataprovider.go index ea215d34..68d6c3ff 100644 --- a/dataprovider/dataprovider.go +++ b/dataprovider/dataprovider.go @@ -46,12 +46,12 @@ import ( "golang.org/x/crypto/ssh" "github.com/drakkan/sftpgo/v2/httpclient" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/logger" "github.com/drakkan/sftpgo/v2/metric" "github.com/drakkan/sftpgo/v2/mfa" "github.com/drakkan/sftpgo/v2/plugin" "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/util" "github.com/drakkan/sftpgo/v2/vfs" ) @@ -1153,7 +1153,7 @@ func HasAdmin() bool { // AddAdmin adds a new SFTPGo admin func AddAdmin(admin *Admin, executor, ipAddress string) error { admin.Filters.RecoveryCodes = nil - admin.Filters.TOTPConfig = TOTPConfig{ + admin.Filters.TOTPConfig = AdminTOTPConfig{ Enabled: false, } err := provider.addAdmin(admin) @@ -1199,7 +1199,7 @@ func UserExists(username string) (User, error) { // AddUser adds a new SFTPGo user. func AddUser(user *User, executor, ipAddress string) error { user.Filters.RecoveryCodes = nil - user.Filters.TOTPConfig = sdk.TOTPConfig{ + user.Filters.TOTPConfig = UserTOTPConfig{ Enabled: false, } err := provider.addUser(user) @@ -1559,7 +1559,7 @@ func validateUserVirtualFolders(user *User) error { return nil } -func validateUserTOTPConfig(c *sdk.TOTPConfig, username string) error { +func validateUserTOTPConfig(c *UserTOTPConfig, username string) error { if !c.Enabled { c.ConfigName = "" c.Secret = kms.NewEmptySecret() diff --git a/dataprovider/sqlcommon.go b/dataprovider/sqlcommon.go index 38ea510e..98cc2891 100644 --- a/dataprovider/sqlcommon.go +++ b/dataprovider/sqlcommon.go @@ -13,7 +13,6 @@ import ( "github.com/cockroachdb/cockroach-go/v2/crdb" "github.com/drakkan/sftpgo/v2/logger" - "github.com/drakkan/sftpgo/v2/sdk" "github.com/drakkan/sftpgo/v2/util" "github.com/drakkan/sftpgo/v2/vfs" ) @@ -1386,7 +1385,7 @@ func getUserFromDbRow(row sqlScanner) (User, error) { user.Permissions = perms } if filters.Valid { - var userFilters sdk.UserFilters + var userFilters UserFilters err = json.Unmarshal([]byte(filters.String), &userFilters) if err == nil { user.Filters = userFilters diff --git a/dataprovider/user.go b/dataprovider/user.go index 3da3cb26..530d4050 100644 --- a/dataprovider/user.go +++ b/dataprovider/user.go @@ -15,10 +15,10 @@ import ( "strings" "time" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/logger" "github.com/drakkan/sftpgo/v2/mfa" "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/util" "github.com/drakkan/sftpgo/v2/vfs" ) @@ -79,9 +79,44 @@ var ( permsCreateAny = []string{PermUpload, PermCreateDirs} ) +// RecoveryCode defines a 2FA recovery code +type RecoveryCode struct { + Secret *kms.Secret `json:"secret"` + Used bool `json:"used,omitempty"` +} + +// UserTOTPConfig defines the time-based one time password configuration +type UserTOTPConfig struct { + Enabled bool `json:"enabled,omitempty"` + ConfigName string `json:"config_name,omitempty"` + Secret *kms.Secret `json:"secret,omitempty"` + // TOTP will be required for the specified protocols. + // SSH protocol (SFTP/SCP/SSH commands) will ask for the TOTP passcode if the client uses keyboard interactive + // authentication. + // FTP have no standard way to support two factor authentication, if you + // enable the support for this protocol you have to add the TOTP passcode after the password. + // For example if your password is "password" and your one time passcode is + // "123456" you have to use "password123456" as password. + Protocols []string `json:"protocols,omitempty"` +} + +// UserFilters defines additional restrictions for a user +// TODO: rename to UserOptions in v3 +type UserFilters struct { + sdk.BaseUserFilters + // Time-based one time passwords configuration + TOTPConfig UserTOTPConfig `json:"totp_config,omitempty"` + // Recovery codes to use if the user loses access to their second factor auth device. + // Each code can only be used once, you should use these codes to login and disable or + // reset 2FA for your account + RecoveryCodes []RecoveryCode `json:"recovery_codes,omitempty"` +} + // User defines a SFTPGo user type User struct { sdk.BaseUser + // Additional restrictions + Filters UserFilters `json:"filters"` // Mapping between virtual paths and virtual folders VirtualFolders []vfs.VirtualFolder `json:"virtual_folders,omitempty"` // Filesystem configuration details @@ -1168,7 +1203,7 @@ func (u *User) getACopy() User { copy(perms, v) permissions[k] = perms } - filters := sdk.UserFilters{} + filters := UserFilters{} filters.MaxUploadFileSize = u.Filters.MaxUploadFileSize filters.TLSUsername = u.Filters.TLSUsername filters.UserType = u.Filters.UserType @@ -1194,12 +1229,12 @@ func (u *User) getACopy() User { filters.AllowAPIKeyAuth = u.Filters.AllowAPIKeyAuth filters.WebClient = make([]string, len(u.Filters.WebClient)) copy(filters.WebClient, u.Filters.WebClient) - filters.RecoveryCodes = make([]sdk.RecoveryCode, 0, len(u.Filters.RecoveryCodes)) + filters.RecoveryCodes = make([]RecoveryCode, 0, len(u.Filters.RecoveryCodes)) for _, code := range u.Filters.RecoveryCodes { if code.Secret == nil { code.Secret = kms.NewEmptySecret() } - filters.RecoveryCodes = append(filters.RecoveryCodes, sdk.RecoveryCode{ + filters.RecoveryCodes = append(filters.RecoveryCodes, RecoveryCode{ Secret: code.Secret.Clone(), Used: code.Used, }) @@ -1238,12 +1273,12 @@ func (u *User) getACopy() User { Status: u.Status, ExpirationDate: u.ExpirationDate, LastLogin: u.LastLogin, - Filters: filters, AdditionalInfo: u.AdditionalInfo, Description: u.Description, CreatedAt: u.CreatedAt, UpdatedAt: u.UpdatedAt, }, + Filters: filters, VirtualFolders: virtualFolders, FsConfig: u.FsConfig.GetACopy(), } diff --git a/ftpd/cryptfs_test.go b/ftpd/cryptfs_test.go index c1627faf..4667411c 100644 --- a/ftpd/cryptfs_test.go +++ b/ftpd/cryptfs_test.go @@ -18,8 +18,8 @@ import ( "github.com/drakkan/sftpgo/v2/common" "github.com/drakkan/sftpgo/v2/dataprovider" "github.com/drakkan/sftpgo/v2/httpdtest" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" ) func TestBasicFTPHandlingCryptFs(t *testing.T) { diff --git a/ftpd/ftpd_test.go b/ftpd/ftpd_test.go index cd841803..2d195536 100644 --- a/ftpd/ftpd_test.go +++ b/ftpd/ftpd_test.go @@ -32,10 +32,11 @@ import ( "github.com/drakkan/sftpgo/v2/dataprovider" "github.com/drakkan/sftpgo/v2/ftpd" "github.com/drakkan/sftpgo/v2/httpdtest" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/logger" "github.com/drakkan/sftpgo/v2/mfa" "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" + sdkkms "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/sftpd" "github.com/drakkan/sftpgo/v2/vfs" ) @@ -604,7 +605,7 @@ func TestMultiFactorAuth(t *testing.T) { configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], user.Username) assert.NoError(t, err) user.Password = defaultPassword - user.Filters.TOTPConfig = sdk.TOTPConfig{ + user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{ Enabled: true, ConfigName: configName, Secret: kms.NewPlainSecret(secret), @@ -1686,7 +1687,7 @@ func TestLoginWithDatabaseCredentials(t *testing.T) { user, _, err := httpdtest.AddUser(u, http.StatusCreated) assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.GCSConfig.Credentials.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.GCSConfig.Credentials.GetStatus()) assert.NotEmpty(t, user.FsConfig.GCSConfig.Credentials.GetPayload()) assert.Empty(t, user.FsConfig.GCSConfig.Credentials.GetAdditionalData()) assert.Empty(t, user.FsConfig.GCSConfig.Credentials.GetKey()) @@ -2808,9 +2809,7 @@ func TestNestedVirtualFolders(t *testing.T) { FsConfig: vfs.Filesystem{ Provider: sdk.CryptedFilesystemProvider, CryptConfig: vfs.CryptFsConfig{ - CryptFsConfig: sdk.CryptFsConfig{ - Passphrase: kms.NewPlainSecret(defaultPassword), - }, + Passphrase: kms.NewPlainSecret(defaultPassword), }, }, MappedPath: mappedPathCrypt, diff --git a/httpd/api_admin.go b/httpd/api_admin.go index 718feef6..a944d498 100644 --- a/httpd/api_admin.go +++ b/httpd/api_admin.go @@ -83,7 +83,7 @@ func disableAdmin2FA(w http.ResponseWriter, r *http.Request) { return } admin.Filters.RecoveryCodes = nil - admin.Filters.TOTPConfig = dataprovider.TOTPConfig{ + admin.Filters.TOTPConfig = dataprovider.AdminTOTPConfig{ Enabled: false, } if err := dataprovider.UpdateAdmin(&admin, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil { @@ -105,7 +105,7 @@ func updateAdmin(w http.ResponseWriter, r *http.Request) { adminID := admin.ID totpConfig := admin.Filters.TOTPConfig recoveryCodes := admin.Filters.RecoveryCodes - admin.Filters.TOTPConfig = dataprovider.TOTPConfig{} + admin.Filters.TOTPConfig = dataprovider.AdminTOTPConfig{} admin.Filters.RecoveryCodes = nil err = render.DecodeJSON(r.Body, &admin) if err != nil { diff --git a/httpd/api_mfa.go b/httpd/api_mfa.go index cad6616a..a72eb09e 100644 --- a/httpd/api_mfa.go +++ b/httpd/api_mfa.go @@ -8,9 +8,8 @@ import ( "github.com/go-chi/render" "github.com/drakkan/sftpgo/v2/dataprovider" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/mfa" - "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/util" ) @@ -81,10 +80,10 @@ func saveTOTPConfig(w http.ResponseWriter, r *http.Request) { sendAPIResponse(w, r, err, "Invalid token claims", http.StatusBadRequest) return } - recoveryCodes := make([]sdk.RecoveryCode, 0, 12) + recoveryCodes := make([]dataprovider.RecoveryCode, 0, 12) for i := 0; i < 12; i++ { code := getNewRecoveryCode() - recoveryCodes = append(recoveryCodes, sdk.RecoveryCode{Secret: kms.NewPlainSecret(code)}) + recoveryCodes = append(recoveryCodes, dataprovider.RecoveryCode{Secret: kms.NewPlainSecret(code)}) } if claims.hasUserAudience() { if err := saveUserTOTPConfig(claims.Username, r, recoveryCodes); err != nil { @@ -125,7 +124,7 @@ func getRecoveryCodes(w http.ResponseWriter, r *http.Request) { return } recoveryCodes := make([]recoveryCode, 0, 12) - var accountRecoveryCodes []sdk.RecoveryCode + var accountRecoveryCodes []dataprovider.RecoveryCode if claims.hasUserAudience() { user, err := dataprovider.UserExists(claims.Username) if err != nil { @@ -163,11 +162,11 @@ func generateRecoveryCodes(w http.ResponseWriter, r *http.Request) { return } recoveryCodes := make([]string, 0, 12) - accountRecoveryCodes := make([]sdk.RecoveryCode, 0, 12) + accountRecoveryCodes := make([]dataprovider.RecoveryCode, 0, 12) for i := 0; i < 12; i++ { code := getNewRecoveryCode() recoveryCodes = append(recoveryCodes, code) - accountRecoveryCodes = append(accountRecoveryCodes, sdk.RecoveryCode{Secret: kms.NewPlainSecret(code)}) + accountRecoveryCodes = append(accountRecoveryCodes, dataprovider.RecoveryCode{Secret: kms.NewPlainSecret(code)}) } if claims.hasUserAudience() { user, err := dataprovider.UserExists(claims.Username) @@ -200,7 +199,7 @@ func getNewRecoveryCode() string { return fmt.Sprintf("RC-%v", strings.ToUpper(util.GenerateUniqueID())) } -func saveUserTOTPConfig(username string, r *http.Request, recoveryCodes []sdk.RecoveryCode) error { +func saveUserTOTPConfig(username string, r *http.Request, recoveryCodes []dataprovider.RecoveryCode) error { user, err := dataprovider.UserExists(username) if err != nil { return err @@ -220,7 +219,7 @@ func saveUserTOTPConfig(username string, r *http.Request, recoveryCodes []sdk.Re return dataprovider.UpdateUser(&user, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr)) } -func saveAdminTOTPConfig(username string, r *http.Request, recoveryCodes []sdk.RecoveryCode) error { +func saveAdminTOTPConfig(username string, r *http.Request, recoveryCodes []dataprovider.RecoveryCode) error { admin, err := dataprovider.AdminExists(username) if err != nil { return err diff --git a/httpd/api_user.go b/httpd/api_user.go index 2731d399..1170105b 100644 --- a/httpd/api_user.go +++ b/httpd/api_user.go @@ -10,8 +10,8 @@ import ( "github.com/drakkan/sftpgo/v2/common" "github.com/drakkan/sftpgo/v2/dataprovider" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/smtp" "github.com/drakkan/sftpgo/v2/util" "github.com/drakkan/sftpgo/v2/vfs" @@ -89,7 +89,7 @@ func disableUser2FA(w http.ResponseWriter, r *http.Request) { return } user.Filters.RecoveryCodes = nil - user.Filters.TOTPConfig = sdk.TOTPConfig{ + user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{ Enabled: false, } if err := dataprovider.UpdateUser(&user, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil { @@ -140,7 +140,7 @@ func updateUser(w http.ResponseWriter, r *http.Request) { user.FsConfig.GCSConfig = vfs.GCSFsConfig{} user.FsConfig.CryptConfig = vfs.CryptFsConfig{} user.FsConfig.SFTPConfig = vfs.SFTPFsConfig{} - user.Filters.TOTPConfig = sdk.TOTPConfig{} + user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{} user.Filters.RecoveryCodes = nil user.VirtualFolders = nil err = render.DecodeJSON(r.Body, &user) diff --git a/httpd/httpd_test.go b/httpd/httpd_test.go index d5173a8e..941cc2b2 100644 --- a/httpd/httpd_test.go +++ b/httpd/httpd_test.go @@ -45,11 +45,12 @@ import ( "github.com/drakkan/sftpgo/v2/httpclient" "github.com/drakkan/sftpgo/v2/httpd" "github.com/drakkan/sftpgo/v2/httpdtest" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/logger" "github.com/drakkan/sftpgo/v2/mfa" "github.com/drakkan/sftpgo/v2/plugin" "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" + sdkkms "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/sftpd" "github.com/drakkan/sftpgo/v2/smtp" "github.com/drakkan/sftpgo/v2/util" @@ -826,7 +827,7 @@ func TestPermMFADisabled(t *testing.T) { assert.NoError(t, err) token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) assert.NoError(t, err) - userTOTPConfig := sdk.TOTPConfig{ + userTOTPConfig := dataprovider.UserTOTPConfig{ Enabled: true, ConfigName: configName, Secret: kms.NewPlainSecret(secret), @@ -867,7 +868,7 @@ func TestPermMFADisabled(t *testing.T) { rr = executeRequest(req) checkResponseCode(t, http.StatusOK, rr) - user.Filters.RecoveryCodes = []sdk.RecoveryCode{ + user.Filters.RecoveryCodes = []dataprovider.RecoveryCode{ { Secret: kms.NewPlainSecret(util.GenerateUniqueID()), }, @@ -901,7 +902,7 @@ func TestLoginUserAPITOTP(t *testing.T) { assert.NoError(t, err) token, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword) assert.NoError(t, err) - userTOTPConfig := sdk.TOTPConfig{ + userTOTPConfig := dataprovider.UserTOTPConfig{ Enabled: true, ConfigName: configName, Secret: kms.NewPlainSecret(secret), @@ -968,7 +969,7 @@ func TestLoginAdminAPITOTP(t *testing.T) { assert.NoError(t, err) altToken, err := getJWTAPITokenFromTestServer(altAdminUsername, altAdminPassword) assert.NoError(t, err) - adminTOTPConfig := dataprovider.TOTPConfig{ + adminTOTPConfig := dataprovider.AdminTOTPConfig{ Enabled: true, ConfigName: configName, Secret: kms.NewPlainSecret(secret), @@ -1510,13 +1511,13 @@ func TestAddUserInvalidFsConfig(t *testing.T) { u.FsConfig.S3Config.Bucket = "testbucket" u.FsConfig.S3Config.Region = "eu-west-1" //nolint:goconst u.FsConfig.S3Config.AccessKey = "access-key" //nolint:goconst - u.FsConfig.S3Config.AccessSecret = kms.NewSecret(kms.SecretStatusRedacted, "access-secret", "", "") + u.FsConfig.S3Config.AccessSecret = kms.NewSecret(sdkkms.SecretStatusRedacted, "access-secret", "", "") u.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000/path?a=b" u.FsConfig.S3Config.StorageClass = "Standard" //nolint:goconst u.FsConfig.S3Config.KeyPrefix = "/adir/subdir/" _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) assert.NoError(t, err) - u.FsConfig.S3Config.AccessSecret.SetStatus(kms.SecretStatusPlain) + u.FsConfig.S3Config.AccessSecret.SetStatus(sdkkms.SecretStatusPlain) _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) assert.NoError(t, err) u.FsConfig.S3Config.KeyPrefix = "" @@ -1560,10 +1561,10 @@ func TestAddUserInvalidFsConfig(t *testing.T) { u.FsConfig.GCSConfig.Bucket = "abucket" u.FsConfig.GCSConfig.StorageClass = "Standard" u.FsConfig.GCSConfig.KeyPrefix = "/somedir/subdir/" - u.FsConfig.GCSConfig.Credentials = kms.NewSecret(kms.SecretStatusRedacted, "test", "", "") //nolint:goconst + u.FsConfig.GCSConfig.Credentials = kms.NewSecret(sdkkms.SecretStatusRedacted, "test", "", "") //nolint:goconst _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) assert.NoError(t, err) - u.FsConfig.GCSConfig.Credentials.SetStatus(kms.SecretStatusPlain) + u.FsConfig.GCSConfig.Credentials.SetStatus(sdkkms.SecretStatusPlain) _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) assert.NoError(t, err) u.FsConfig.GCSConfig.KeyPrefix = "somedir/subdir/" //nolint:goconst @@ -1571,7 +1572,7 @@ func TestAddUserInvalidFsConfig(t *testing.T) { u.FsConfig.GCSConfig.AutomaticCredentials = 0 _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) assert.NoError(t, err) - u.FsConfig.GCSConfig.Credentials = kms.NewSecret(kms.SecretStatusSecretBox, "invalid", "", "") + u.FsConfig.GCSConfig.Credentials = kms.NewSecret(sdkkms.SecretStatusSecretBox, "invalid", "", "") _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) assert.NoError(t, err) @@ -1580,7 +1581,7 @@ func TestAddUserInvalidFsConfig(t *testing.T) { u.FsConfig.AzBlobConfig.SASURL = kms.NewPlainSecret("http://foo\x7f.com/") _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) assert.NoError(t, err) - u.FsConfig.AzBlobConfig.SASURL = kms.NewSecret(kms.SecretStatusRedacted, "key", "", "") + u.FsConfig.AzBlobConfig.SASURL = kms.NewSecret(sdkkms.SecretStatusRedacted, "key", "", "") _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) assert.NoError(t, err) u.FsConfig.AzBlobConfig.SASURL = kms.NewEmptySecret() @@ -1590,11 +1591,11 @@ func TestAddUserInvalidFsConfig(t *testing.T) { u.FsConfig.AzBlobConfig.Container = "container" _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) assert.NoError(t, err) - u.FsConfig.AzBlobConfig.AccountKey = kms.NewSecret(kms.SecretStatusRedacted, "key", "", "") + u.FsConfig.AzBlobConfig.AccountKey = kms.NewSecret(sdkkms.SecretStatusRedacted, "key", "", "") u.FsConfig.AzBlobConfig.KeyPrefix = "/amedir/subdir/" _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) assert.NoError(t, err) - u.FsConfig.AzBlobConfig.AccountKey.SetStatus(kms.SecretStatusPlain) + u.FsConfig.AzBlobConfig.AccountKey.SetStatus(sdkkms.SecretStatusPlain) _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) assert.NoError(t, err) u.FsConfig.AzBlobConfig.KeyPrefix = "amedir/subdir/" @@ -1609,18 +1610,18 @@ func TestAddUserInvalidFsConfig(t *testing.T) { u.FsConfig.Provider = sdk.CryptedFilesystemProvider _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) assert.NoError(t, err) - u.FsConfig.CryptConfig.Passphrase = kms.NewSecret(kms.SecretStatusRedacted, "akey", "", "") + u.FsConfig.CryptConfig.Passphrase = kms.NewSecret(sdkkms.SecretStatusRedacted, "akey", "", "") _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) assert.NoError(t, err) u = getTestUser() u.FsConfig.Provider = sdk.SFTPFilesystemProvider _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) assert.NoError(t, err) - u.FsConfig.SFTPConfig.Password = kms.NewSecret(kms.SecretStatusRedacted, "randompkey", "", "") + u.FsConfig.SFTPConfig.Password = kms.NewSecret(sdkkms.SecretStatusRedacted, "randompkey", "", "") _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) assert.NoError(t, err) u.FsConfig.SFTPConfig.Password = kms.NewEmptySecret() - u.FsConfig.SFTPConfig.PrivateKey = kms.NewSecret(kms.SecretStatusRedacted, "keyforpkey", "", "") + u.FsConfig.SFTPConfig.PrivateKey = kms.NewSecret(sdkkms.SecretStatusRedacted, "keyforpkey", "", "") _, _, err = httpdtest.AddUser(u, http.StatusBadRequest) assert.NoError(t, err) u.FsConfig.SFTPConfig.PrivateKey = kms.NewPlainSecret("pk") @@ -1644,7 +1645,7 @@ func TestUserRedactedPassword(t *testing.T) { u.FsConfig.S3Config.Bucket = "b" u.FsConfig.S3Config.Region = "eu-west-1" u.FsConfig.S3Config.AccessKey = "access-key" - u.FsConfig.S3Config.AccessSecret = kms.NewSecret(kms.SecretStatusRedacted, "access-secret", "", "") + u.FsConfig.S3Config.AccessSecret = kms.NewSecret(sdkkms.SecretStatusRedacted, "access-secret", "", "") u.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000/path?k=m" u.FsConfig.S3Config.StorageClass = "Standard" u.FsConfig.S3Config.ACL = "bucket-owner-full-control" @@ -1667,9 +1668,7 @@ func TestUserRedactedPassword(t *testing.T) { FsConfig: vfs.Filesystem{ Provider: sdk.CryptedFilesystemProvider, CryptConfig: vfs.CryptFsConfig{ - CryptFsConfig: sdk.CryptFsConfig{ - Passphrase: kms.NewSecret(kms.SecretStatusRedacted, "crypted-secret", "", ""), - }, + Passphrase: kms.NewSecret(sdkkms.SecretStatusRedacted, "crypted-secret", "", ""), }, }, }, @@ -2356,9 +2355,7 @@ func TestUserS3Config(t *testing.T) { FsConfig: vfs.Filesystem{ Provider: sdk.CryptedFilesystemProvider, CryptConfig: vfs.CryptFsConfig{ - CryptFsConfig: sdk.CryptFsConfig{ - Passphrase: kms.NewPlainSecret("Crypted-Secret"), - }, + Passphrase: kms.NewPlainSecret("Crypted-Secret"), }, }, }, @@ -2366,14 +2363,14 @@ func TestUserS3Config(t *testing.T) { }) user, body, err := httpdtest.UpdateUser(user, http.StatusOK, "") assert.NoError(t, err, string(body)) - assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.S3Config.AccessSecret.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.S3Config.AccessSecret.GetStatus()) assert.NotEmpty(t, user.FsConfig.S3Config.AccessSecret.GetPayload()) assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetAdditionalData()) assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetKey()) assert.Equal(t, 60, user.FsConfig.S3Config.DownloadPartMaxTime) if assert.Len(t, user.VirtualFolders, 1) { folder := user.VirtualFolders[0] - assert.Equal(t, kms.SecretStatusSecretBox, folder.FsConfig.CryptConfig.Passphrase.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, folder.FsConfig.CryptConfig.Passphrase.GetStatus()) assert.NotEmpty(t, folder.FsConfig.CryptConfig.Passphrase.GetPayload()) assert.Empty(t, folder.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) assert.Empty(t, folder.FsConfig.CryptConfig.Passphrase.GetKey()) @@ -2382,7 +2379,7 @@ func TestUserS3Config(t *testing.T) { assert.NoError(t, err) folder, _, err := httpdtest.GetFolderByName(folderName, http.StatusOK) assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusSecretBox, folder.FsConfig.CryptConfig.Passphrase.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, folder.FsConfig.CryptConfig.Passphrase.GetStatus()) assert.NotEmpty(t, folder.FsConfig.CryptConfig.Passphrase.GetPayload()) assert.Empty(t, folder.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) assert.Empty(t, folder.FsConfig.CryptConfig.Passphrase.GetKey()) @@ -2392,15 +2389,15 @@ func TestUserS3Config(t *testing.T) { user.ID = 0 user.CreatedAt = 0 user.VirtualFolders = nil - secret := kms.NewSecret(kms.SecretStatusSecretBox, "Server-Access-Secret", "", "") + secret := kms.NewSecret(sdkkms.SecretStatusSecretBox, "Server-Access-Secret", "", "") user.FsConfig.S3Config.AccessSecret = secret _, _, err = httpdtest.AddUser(user, http.StatusCreated) assert.Error(t, err) - user.FsConfig.S3Config.AccessSecret.SetStatus(kms.SecretStatusPlain) + user.FsConfig.S3Config.AccessSecret.SetStatus(sdkkms.SecretStatusPlain) user, _, err = httpdtest.AddUser(user, http.StatusCreated) assert.NoError(t, err) initialSecretPayload := user.FsConfig.S3Config.AccessSecret.GetPayload() - assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.S3Config.AccessSecret.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.S3Config.AccessSecret.GetStatus()) assert.NotEmpty(t, initialSecretPayload) assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetAdditionalData()) assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetKey()) @@ -2414,7 +2411,7 @@ func TestUserS3Config(t *testing.T) { user.FsConfig.S3Config.DownloadConcurrency = 4 user, bb, err := httpdtest.UpdateUser(user, http.StatusOK, "") assert.NoError(t, err, string(bb)) - assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.S3Config.AccessSecret.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.S3Config.AccessSecret.GetStatus()) assert.Equal(t, initialSecretPayload, user.FsConfig.S3Config.AccessSecret.GetPayload()) assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetAdditionalData()) assert.Empty(t, user.FsConfig.S3Config.AccessSecret.GetKey()) @@ -2466,7 +2463,7 @@ func TestUserGCSConfig(t *testing.T) { err = secret.Decrypt() assert.NoError(t, err) assert.Equal(t, "fake credentials", secret.GetPayload()) - user.FsConfig.GCSConfig.Credentials = kms.NewSecret(kms.SecretStatusSecretBox, "fake encrypted credentials", "", "") + user.FsConfig.GCSConfig.Credentials = kms.NewSecret(sdkkms.SecretStatusSecretBox, "fake encrypted credentials", "", "") user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") assert.NoError(t, err) assert.FileExists(t, credentialFile) @@ -2483,10 +2480,10 @@ func TestUserGCSConfig(t *testing.T) { user.Password = defaultPassword user.ID = 0 user.CreatedAt = 0 - user.FsConfig.GCSConfig.Credentials = kms.NewSecret(kms.SecretStatusSecretBox, "fake credentials", "", "") + user.FsConfig.GCSConfig.Credentials = kms.NewSecret(sdkkms.SecretStatusSecretBox, "fake credentials", "", "") _, _, err = httpdtest.AddUser(user, http.StatusCreated) assert.Error(t, err) - user.FsConfig.GCSConfig.Credentials.SetStatus(kms.SecretStatusPlain) + user.FsConfig.GCSConfig.Credentials.SetStatus(sdkkms.SecretStatusPlain) user, body, err := httpdtest.AddUser(user, http.StatusCreated) assert.NoError(t, err, string(body)) err = os.RemoveAll(credentialsPath) @@ -2531,16 +2528,16 @@ func TestUserAzureBlobConfig(t *testing.T) { user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") assert.NoError(t, err) initialPayload := user.FsConfig.AzBlobConfig.AccountKey.GetPayload() - assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.AccountKey.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.AccountKey.GetStatus()) assert.NotEmpty(t, initialPayload) assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData()) assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetKey()) - user.FsConfig.AzBlobConfig.AccountKey.SetStatus(kms.SecretStatusSecretBox) + user.FsConfig.AzBlobConfig.AccountKey.SetStatus(sdkkms.SecretStatusSecretBox) user.FsConfig.AzBlobConfig.AccountKey.SetAdditionalData("data") user.FsConfig.AzBlobConfig.AccountKey.SetKey("fake key") user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.AccountKey.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.AccountKey.GetStatus()) assert.Equal(t, initialPayload, user.FsConfig.AzBlobConfig.AccountKey.GetPayload()) assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData()) assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetKey()) @@ -2550,7 +2547,7 @@ func TestUserAzureBlobConfig(t *testing.T) { user.Password = defaultPassword user.ID = 0 user.CreatedAt = 0 - secret := kms.NewSecret(kms.SecretStatusSecretBox, "Server-Account-Key", "", "") + secret := kms.NewSecret(sdkkms.SecretStatusSecretBox, "Server-Account-Key", "", "") user.FsConfig.AzBlobConfig.AccountKey = secret _, _, err = httpdtest.AddUser(user, http.StatusCreated) assert.Error(t, err) @@ -2558,7 +2555,7 @@ func TestUserAzureBlobConfig(t *testing.T) { user, _, err = httpdtest.AddUser(user, http.StatusCreated) assert.NoError(t, err) initialPayload = user.FsConfig.AzBlobConfig.AccountKey.GetPayload() - assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.AccountKey.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.AccountKey.GetStatus()) assert.NotEmpty(t, initialPayload) assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData()) assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetKey()) @@ -2569,7 +2566,7 @@ func TestUserAzureBlobConfig(t *testing.T) { user.FsConfig.AzBlobConfig.UploadConcurrency = 5 user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.AccountKey.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.AccountKey.GetStatus()) assert.NotEmpty(t, initialPayload) assert.Equal(t, initialPayload, user.FsConfig.AzBlobConfig.AccountKey.GetPayload()) assert.Empty(t, user.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData()) @@ -2593,25 +2590,25 @@ func TestUserAzureBlobConfig(t *testing.T) { user.CreatedAt = 0 // sas test for add instead of update user.FsConfig.AzBlobConfig = vfs.AzBlobFsConfig{ - AzBlobFsConfig: sdk.AzBlobFsConfig{ + BaseAzBlobFsConfig: sdk.BaseAzBlobFsConfig{ Container: user.FsConfig.AzBlobConfig.Container, - SASURL: kms.NewPlainSecret("http://127.0.0.1/fake/sass/url"), }, + SASURL: kms.NewPlainSecret("http://127.0.0.1/fake/sass/url"), } user, _, err = httpdtest.AddUser(user, http.StatusCreated) assert.NoError(t, err) assert.Nil(t, user.FsConfig.AzBlobConfig.AccountKey) initialPayload = user.FsConfig.AzBlobConfig.SASURL.GetPayload() - assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.SASURL.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.SASURL.GetStatus()) assert.NotEmpty(t, initialPayload) assert.Empty(t, user.FsConfig.AzBlobConfig.SASURL.GetAdditionalData()) assert.Empty(t, user.FsConfig.AzBlobConfig.SASURL.GetKey()) - user.FsConfig.AzBlobConfig.SASURL.SetStatus(kms.SecretStatusSecretBox) + user.FsConfig.AzBlobConfig.SASURL.SetStatus(sdkkms.SecretStatusSecretBox) user.FsConfig.AzBlobConfig.SASURL.SetAdditionalData("data") user.FsConfig.AzBlobConfig.SASURL.SetKey("fake key") user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.SASURL.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.AzBlobConfig.SASURL.GetStatus()) assert.Equal(t, initialPayload, user.FsConfig.AzBlobConfig.SASURL.GetPayload()) assert.Empty(t, user.FsConfig.AzBlobConfig.SASURL.GetAdditionalData()) assert.Empty(t, user.FsConfig.AzBlobConfig.SASURL.GetKey()) @@ -2628,16 +2625,16 @@ func TestUserCryptFs(t *testing.T) { user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") assert.NoError(t, err) initialPayload := user.FsConfig.CryptConfig.Passphrase.GetPayload() - assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.CryptConfig.Passphrase.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.CryptConfig.Passphrase.GetStatus()) assert.NotEmpty(t, initialPayload) assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetKey()) - user.FsConfig.CryptConfig.Passphrase.SetStatus(kms.SecretStatusSecretBox) + user.FsConfig.CryptConfig.Passphrase.SetStatus(sdkkms.SecretStatusSecretBox) user.FsConfig.CryptConfig.Passphrase.SetAdditionalData("data") user.FsConfig.CryptConfig.Passphrase.SetKey("fake pass key") user, bb, err := httpdtest.UpdateUser(user, http.StatusOK, "") assert.NoError(t, err, string(bb)) - assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.CryptConfig.Passphrase.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.CryptConfig.Passphrase.GetStatus()) assert.Equal(t, initialPayload, user.FsConfig.CryptConfig.Passphrase.GetPayload()) assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetKey()) @@ -2647,7 +2644,7 @@ func TestUserCryptFs(t *testing.T) { user.Password = defaultPassword user.ID = 0 user.CreatedAt = 0 - secret := kms.NewSecret(kms.SecretStatusSecretBox, "invalid encrypted payload", "", "") + secret := kms.NewSecret(sdkkms.SecretStatusSecretBox, "invalid encrypted payload", "", "") user.FsConfig.CryptConfig.Passphrase = secret _, _, err = httpdtest.AddUser(user, http.StatusCreated) assert.Error(t, err) @@ -2655,7 +2652,7 @@ func TestUserCryptFs(t *testing.T) { user, _, err = httpdtest.AddUser(user, http.StatusCreated) assert.NoError(t, err) initialPayload = user.FsConfig.CryptConfig.Passphrase.GetPayload() - assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.CryptConfig.Passphrase.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.CryptConfig.Passphrase.GetStatus()) assert.NotEmpty(t, initialPayload) assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetKey()) @@ -2663,7 +2660,7 @@ func TestUserCryptFs(t *testing.T) { user.FsConfig.CryptConfig.Passphrase.SetKey("pass") user, bb, err = httpdtest.UpdateUser(user, http.StatusOK, "") assert.NoError(t, err, string(bb)) - assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.CryptConfig.Passphrase.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.CryptConfig.Passphrase.GetStatus()) assert.NotEmpty(t, initialPayload) assert.Equal(t, initialPayload, user.FsConfig.CryptConfig.Passphrase.GetPayload()) assert.Empty(t, user.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) @@ -2696,28 +2693,28 @@ func TestUserSFTPFs(t *testing.T) { assert.Equal(t, int64(2), user.FsConfig.SFTPConfig.BufferSize) initialPwdPayload := user.FsConfig.SFTPConfig.Password.GetPayload() initialPkeyPayload := user.FsConfig.SFTPConfig.PrivateKey.GetPayload() - assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.Password.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.Password.GetStatus()) assert.NotEmpty(t, initialPwdPayload) assert.Empty(t, user.FsConfig.SFTPConfig.Password.GetAdditionalData()) assert.Empty(t, user.FsConfig.SFTPConfig.Password.GetKey()) - assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.PrivateKey.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.PrivateKey.GetStatus()) assert.NotEmpty(t, initialPkeyPayload) assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData()) assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetKey()) - user.FsConfig.SFTPConfig.Password.SetStatus(kms.SecretStatusSecretBox) + user.FsConfig.SFTPConfig.Password.SetStatus(sdkkms.SecretStatusSecretBox) user.FsConfig.SFTPConfig.Password.SetAdditionalData("adata") user.FsConfig.SFTPConfig.Password.SetKey("fake pwd key") - user.FsConfig.SFTPConfig.PrivateKey.SetStatus(kms.SecretStatusSecretBox) + user.FsConfig.SFTPConfig.PrivateKey.SetStatus(sdkkms.SecretStatusSecretBox) user.FsConfig.SFTPConfig.PrivateKey.SetAdditionalData("adata") user.FsConfig.SFTPConfig.PrivateKey.SetKey("fake key") user.FsConfig.SFTPConfig.DisableCouncurrentReads = false user, bb, err := httpdtest.UpdateUser(user, http.StatusOK, "") assert.NoError(t, err, string(bb)) - assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.Password.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.Password.GetStatus()) assert.Equal(t, initialPwdPayload, user.FsConfig.SFTPConfig.Password.GetPayload()) assert.Empty(t, user.FsConfig.SFTPConfig.Password.GetAdditionalData()) assert.Empty(t, user.FsConfig.SFTPConfig.Password.GetKey()) - assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.PrivateKey.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.PrivateKey.GetStatus()) assert.Equal(t, initialPkeyPayload, user.FsConfig.SFTPConfig.PrivateKey.GetPayload()) assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData()) assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetKey()) @@ -2728,7 +2725,7 @@ func TestUserSFTPFs(t *testing.T) { user.Password = defaultPassword user.ID = 0 user.CreatedAt = 0 - secret := kms.NewSecret(kms.SecretStatusSecretBox, "invalid encrypted payload", "", "") + secret := kms.NewSecret(sdkkms.SecretStatusSecretBox, "invalid encrypted payload", "", "") user.FsConfig.SFTPConfig.Password = secret _, _, err = httpdtest.AddUser(user, http.StatusCreated) assert.Error(t, err) @@ -2742,7 +2739,7 @@ func TestUserSFTPFs(t *testing.T) { assert.NoError(t, err) initialPkeyPayload = user.FsConfig.SFTPConfig.PrivateKey.GetPayload() assert.Nil(t, user.FsConfig.SFTPConfig.Password) - assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.PrivateKey.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.PrivateKey.GetStatus()) assert.NotEmpty(t, initialPkeyPayload) assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData()) assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetKey()) @@ -2750,7 +2747,7 @@ func TestUserSFTPFs(t *testing.T) { user.FsConfig.SFTPConfig.PrivateKey.SetKey("k") user, bb, err = httpdtest.UpdateUser(user, http.StatusOK, "") assert.NoError(t, err, string(bb)) - assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.PrivateKey.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.SFTPConfig.PrivateKey.GetStatus()) assert.NotEmpty(t, initialPkeyPayload) assert.Equal(t, initialPkeyPayload, user.FsConfig.SFTPConfig.PrivateKey.GetPayload()) assert.Empty(t, user.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData()) @@ -2882,7 +2879,7 @@ func TestUserHiddenFields(t *testing.T) { assert.NotEmpty(t, user1.FsConfig.S3Config.AccessSecret.GetPayload()) err = user1.FsConfig.S3Config.AccessSecret.Decrypt() assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusPlain, user1.FsConfig.S3Config.AccessSecret.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusPlain, user1.FsConfig.S3Config.AccessSecret.GetStatus()) assert.Equal(t, u1.FsConfig.S3Config.AccessSecret.GetPayload(), user1.FsConfig.S3Config.AccessSecret.GetPayload()) assert.Empty(t, user1.FsConfig.S3Config.AccessSecret.GetKey()) assert.Empty(t, user1.FsConfig.S3Config.AccessSecret.GetAdditionalData()) @@ -2896,7 +2893,7 @@ func TestUserHiddenFields(t *testing.T) { assert.NotEmpty(t, user2.FsConfig.GCSConfig.Credentials.GetPayload()) err = user2.FsConfig.GCSConfig.Credentials.Decrypt() assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusPlain, user2.FsConfig.GCSConfig.Credentials.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusPlain, user2.FsConfig.GCSConfig.Credentials.GetStatus()) assert.Equal(t, u2.FsConfig.GCSConfig.Credentials.GetPayload(), user2.FsConfig.GCSConfig.Credentials.GetPayload()) assert.Empty(t, user2.FsConfig.GCSConfig.Credentials.GetKey()) assert.Empty(t, user2.FsConfig.GCSConfig.Credentials.GetAdditionalData()) @@ -2910,7 +2907,7 @@ func TestUserHiddenFields(t *testing.T) { assert.NotEmpty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetPayload()) err = user3.FsConfig.AzBlobConfig.AccountKey.Decrypt() assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusPlain, user3.FsConfig.AzBlobConfig.AccountKey.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusPlain, user3.FsConfig.AzBlobConfig.AccountKey.GetStatus()) assert.Equal(t, u3.FsConfig.AzBlobConfig.AccountKey.GetPayload(), user3.FsConfig.AzBlobConfig.AccountKey.GetPayload()) assert.Empty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetKey()) assert.Empty(t, user3.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData()) @@ -2924,7 +2921,7 @@ func TestUserHiddenFields(t *testing.T) { assert.NotEmpty(t, user4.FsConfig.CryptConfig.Passphrase.GetPayload()) err = user4.FsConfig.CryptConfig.Passphrase.Decrypt() assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusPlain, user4.FsConfig.CryptConfig.Passphrase.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusPlain, user4.FsConfig.CryptConfig.Passphrase.GetStatus()) assert.Equal(t, u4.FsConfig.CryptConfig.Passphrase.GetPayload(), user4.FsConfig.CryptConfig.Passphrase.GetPayload()) assert.Empty(t, user4.FsConfig.CryptConfig.Passphrase.GetKey()) assert.Empty(t, user4.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) @@ -2938,7 +2935,7 @@ func TestUserHiddenFields(t *testing.T) { assert.NotEmpty(t, user5.FsConfig.SFTPConfig.Password.GetPayload()) err = user5.FsConfig.SFTPConfig.Password.Decrypt() assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusPlain, user5.FsConfig.SFTPConfig.Password.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusPlain, user5.FsConfig.SFTPConfig.Password.GetStatus()) assert.Equal(t, u5.FsConfig.SFTPConfig.Password.GetPayload(), user5.FsConfig.SFTPConfig.Password.GetPayload()) assert.Empty(t, user5.FsConfig.SFTPConfig.Password.GetKey()) assert.Empty(t, user5.FsConfig.SFTPConfig.Password.GetAdditionalData()) @@ -2948,7 +2945,7 @@ func TestUserHiddenFields(t *testing.T) { assert.NotEmpty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetPayload()) err = user5.FsConfig.SFTPConfig.PrivateKey.Decrypt() assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusPlain, user5.FsConfig.SFTPConfig.PrivateKey.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusPlain, user5.FsConfig.SFTPConfig.PrivateKey.GetStatus()) assert.Equal(t, u5.FsConfig.SFTPConfig.PrivateKey.GetPayload(), user5.FsConfig.SFTPConfig.PrivateKey.GetPayload()) assert.Empty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetKey()) assert.Empty(t, user5.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData()) @@ -2996,13 +2993,13 @@ func TestSecretObject(t *testing.T) { require.True(t, s.IsValid()) err := s.Encrypt() require.NoError(t, err) - require.Equal(t, kms.SecretStatusSecretBox, s.GetStatus()) + require.Equal(t, sdkkms.SecretStatusSecretBox, s.GetStatus()) require.NotEmpty(t, s.GetPayload()) require.NotEmpty(t, s.GetKey()) require.True(t, s.IsValid()) err = s.Decrypt() require.NoError(t, err) - require.Equal(t, kms.SecretStatusPlain, s.GetStatus()) + require.Equal(t, sdkkms.SecretStatusPlain, s.GetStatus()) require.Equal(t, "test data", s.GetPayload()) require.Empty(t, s.GetKey()) } @@ -3017,10 +3014,10 @@ func TestSecretObjectCompatibility(t *testing.T) { localAsJSON, err := json.Marshal(s) assert.NoError(t, err) - for _, secretStatus := range []string{kms.SecretStatusSecretBox} { + for _, secretStatus := range []string{sdkkms.SecretStatusSecretBox} { kmsConfig := config.GetKMSConfig() assert.Empty(t, kmsConfig.Secrets.MasterKeyPath) - if secretStatus == kms.SecretStatusVaultTransit { + if secretStatus == sdkkms.SecretStatusVaultTransit { os.Setenv("VAULT_SERVER_URL", "http://127.0.0.1:8200") os.Setenv("VAULT_SERVER_TOKEN", "s.9lYGq83MbgG5KR5kfebXVyhJ") kmsConfig.Secrets.URL = "hashivault://mykey" @@ -3037,20 +3034,20 @@ func TestSecretObjectCompatibility(t *testing.T) { err = secretClone.Decrypt() assert.NoError(t, err) assert.Equal(t, testPayload, secretClone.GetPayload()) - if secretStatus == kms.SecretStatusVaultTransit { + if secretStatus == sdkkms.SecretStatusVaultTransit { // decrypt the local secret now that the provider is vault secretLocal := kms.NewEmptySecret() err = json.Unmarshal(localAsJSON, secretLocal) assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusSecretBox, secretLocal.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, secretLocal.GetStatus()) assert.Equal(t, 0, secretLocal.GetMode()) err = secretLocal.Decrypt() assert.NoError(t, err) assert.Equal(t, testPayload, secretLocal.GetPayload()) - assert.Equal(t, kms.SecretStatusPlain, secretLocal.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusPlain, secretLocal.GetStatus()) err = secretLocal.Encrypt() assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusSecretBox, secretLocal.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, secretLocal.GetStatus()) assert.Equal(t, 0, secretLocal.GetMode()) } @@ -3065,7 +3062,7 @@ func TestSecretObjectCompatibility(t *testing.T) { MasterKeyPath: masterKeyPath, }, } - if secretStatus == kms.SecretStatusVaultTransit { + if secretStatus == sdkkms.SecretStatusVaultTransit { config.Secrets.URL = "hashivault://mykey" } err = config.Initialize() @@ -3085,22 +3082,22 @@ func TestSecretObjectCompatibility(t *testing.T) { err = secret.Decrypt() assert.NoError(t, err) assert.Equal(t, testPayload, secret.GetPayload()) - if secretStatus == kms.SecretStatusVaultTransit { + if secretStatus == sdkkms.SecretStatusVaultTransit { // decrypt the local secret encryped without a master key now that // the provider is vault and a master key is set. // The provider will not change, the master key will be used secretLocal := kms.NewEmptySecret() err = json.Unmarshal(localAsJSON, secretLocal) assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusSecretBox, secretLocal.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, secretLocal.GetStatus()) assert.Equal(t, 0, secretLocal.GetMode()) err = secretLocal.Decrypt() assert.NoError(t, err) assert.Equal(t, testPayload, secretLocal.GetPayload()) - assert.Equal(t, kms.SecretStatusPlain, secretLocal.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusPlain, secretLocal.GetStatus()) err = secretLocal.Encrypt() assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusSecretBox, secretLocal.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, secretLocal.GetStatus()) assert.Equal(t, 1, secretLocal.GetMode()) } @@ -3108,7 +3105,7 @@ func TestSecretObjectCompatibility(t *testing.T) { assert.NoError(t, err) err = os.Remove(masterKeyPath) assert.NoError(t, err) - if secretStatus == kms.SecretStatusVaultTransit { + if secretStatus == sdkkms.SecretStatusVaultTransit { os.Unsetenv("VAULT_SERVER_URL") os.Unsetenv("VAULT_SERVER_TOKEN") } @@ -3373,13 +3370,13 @@ func TestEmbeddedFoldersUpdate(t *testing.T) { FsConfig: vfs.Filesystem{ Provider: sdk.S3FilesystemProvider, S3Config: vfs.S3FsConfig{ - S3FsConfig: sdk.S3FsConfig{ - Bucket: "test", - Region: "us-east-1", - AccessKey: "akey", - AccessSecret: kms.NewPlainSecret("asecret"), - Endpoint: "http://127.0.1.1:9090", + BaseS3FsConfig: sdk.BaseS3FsConfig{ + Bucket: "test", + Region: "us-east-1", + AccessKey: "akey", + Endpoint: "http://127.0.1.1:9090", }, + AccessSecret: kms.NewPlainSecret("asecret"), }, }, }, @@ -3399,7 +3396,7 @@ func TestEmbeddedFoldersUpdate(t *testing.T) { assert.Equal(t, "test", userFolder.FsConfig.S3Config.Bucket) assert.Equal(t, "us-east-1", userFolder.FsConfig.S3Config.Region) assert.Equal(t, "http://127.0.1.1:9090", userFolder.FsConfig.S3Config.Endpoint) - assert.Equal(t, kms.SecretStatusSecretBox, userFolder.FsConfig.S3Config.AccessSecret.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, userFolder.FsConfig.S3Config.AccessSecret.GetStatus()) assert.NotEmpty(t, userFolder.FsConfig.S3Config.AccessSecret.GetPayload()) assert.Empty(t, userFolder.FsConfig.S3Config.AccessSecret.GetKey()) assert.Empty(t, userFolder.FsConfig.S3Config.AccessSecret.GetAdditionalData()) @@ -3414,7 +3411,7 @@ func TestEmbeddedFoldersUpdate(t *testing.T) { assert.Equal(t, "test", folder.FsConfig.S3Config.Bucket) assert.Equal(t, "us-east-1", folder.FsConfig.S3Config.Region) assert.Equal(t, "http://127.0.1.1:9090", folder.FsConfig.S3Config.Endpoint) - assert.Equal(t, kms.SecretStatusSecretBox, folder.FsConfig.S3Config.AccessSecret.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, folder.FsConfig.S3Config.AccessSecret.GetStatus()) assert.NotEmpty(t, folder.FsConfig.S3Config.AccessSecret.GetPayload()) assert.Empty(t, folder.FsConfig.S3Config.AccessSecret.GetKey()) assert.Empty(t, folder.FsConfig.S3Config.AccessSecret.GetAdditionalData()) @@ -3432,7 +3429,7 @@ func TestEmbeddedFoldersUpdate(t *testing.T) { assert.Equal(t, "test", folder.FsConfig.S3Config.Bucket) assert.Equal(t, "us-east-1", folder.FsConfig.S3Config.Region) assert.Equal(t, "http://127.0.1.1:9090", folder.FsConfig.S3Config.Endpoint) - assert.Equal(t, kms.SecretStatusSecretBox, folder.FsConfig.S3Config.AccessSecret.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, folder.FsConfig.S3Config.AccessSecret.GetStatus()) assert.NotEmpty(t, folder.FsConfig.S3Config.AccessSecret.GetPayload()) assert.Empty(t, folder.FsConfig.S3Config.AccessSecret.GetKey()) assert.Empty(t, folder.FsConfig.S3Config.AccessSecret.GetAdditionalData()) @@ -3449,7 +3446,7 @@ func TestEmbeddedFoldersUpdate(t *testing.T) { assert.Equal(t, "test", userFolder.FsConfig.S3Config.Bucket) assert.Equal(t, "us-east-1", userFolder.FsConfig.S3Config.Region) assert.Equal(t, "http://127.0.1.1:9090", userFolder.FsConfig.S3Config.Endpoint) - assert.Equal(t, kms.SecretStatusSecretBox, userFolder.FsConfig.S3Config.AccessSecret.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, userFolder.FsConfig.S3Config.AccessSecret.GetStatus()) assert.NotEmpty(t, userFolder.FsConfig.S3Config.AccessSecret.GetPayload()) assert.Empty(t, userFolder.FsConfig.S3Config.AccessSecret.GetKey()) assert.Empty(t, userFolder.FsConfig.S3Config.AccessSecret.GetAdditionalData()) @@ -3775,7 +3772,7 @@ func TestSaveErrors(t *testing.T) { assert.NoError(t, err) recCode := "recovery code" - recoveryCodes := []sdk.RecoveryCode{ + recoveryCodes := []dataprovider.RecoveryCode{ { Secret: kms.NewPlainSecret(recCode), Used: false, @@ -3791,7 +3788,7 @@ func TestSaveErrors(t *testing.T) { configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], user.Username) assert.NoError(t, err) user.Password = u.Password - user.Filters.TOTPConfig = sdk.TOTPConfig{ + user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{ Enabled: true, ConfigName: configName, Secret: kms.NewPlainSecret(secret), @@ -3813,7 +3810,7 @@ func TestSaveErrors(t *testing.T) { admin, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK) assert.NoError(t, err) admin.Password = a.Password - admin.Filters.TOTPConfig = dataprovider.TOTPConfig{ + admin.Filters.TOTPConfig = dataprovider.AdminTOTPConfig{ Enabled: true, ConfigName: configName, Secret: kms.NewPlainSecret(secret), @@ -4141,9 +4138,7 @@ func TestFolders(t *testing.T) { FsConfig: vfs.Filesystem{ Provider: sdk.CryptedFilesystemProvider, CryptConfig: vfs.CryptFsConfig{ - CryptFsConfig: sdk.CryptFsConfig{ - Passphrase: kms.NewPlainSecret("asecret"), - }, + Passphrase: kms.NewPlainSecret("asecret"), }, }, } @@ -4157,7 +4152,7 @@ func TestFolders(t *testing.T) { assert.Equal(t, 0, folder1.UsedQuotaFiles) assert.Equal(t, int64(0), folder1.UsedQuotaSize) assert.Equal(t, int64(0), folder1.LastQuotaUpdate) - assert.Equal(t, kms.SecretStatusSecretBox, folder1.FsConfig.CryptConfig.Passphrase.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, folder1.FsConfig.CryptConfig.Passphrase.GetStatus()) assert.NotEmpty(t, folder1.FsConfig.CryptConfig.Passphrase.GetPayload()) assert.Empty(t, folder1.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) assert.Empty(t, folder1.FsConfig.CryptConfig.Passphrase.GetKey()) @@ -4185,7 +4180,7 @@ func TestFolders(t *testing.T) { if f.Name == folder1.Name { found = true assert.Equal(t, folder1.MappedPath, f.MappedPath) - assert.Equal(t, kms.SecretStatusSecretBox, f.FsConfig.CryptConfig.Passphrase.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, f.FsConfig.CryptConfig.Passphrase.GetStatus()) assert.NotEmpty(t, f.FsConfig.CryptConfig.Passphrase.GetPayload()) assert.Empty(t, f.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) assert.Empty(t, f.FsConfig.CryptConfig.Passphrase.GetKey()) @@ -4203,7 +4198,7 @@ func TestFolders(t *testing.T) { assert.NoError(t, err) assert.Equal(t, folder1.Name, f.Name) assert.Equal(t, folder1.MappedPath, f.MappedPath) - assert.Equal(t, kms.SecretStatusSecretBox, f.FsConfig.CryptConfig.Passphrase.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, f.FsConfig.CryptConfig.Passphrase.GetStatus()) assert.NotEmpty(t, f.FsConfig.CryptConfig.Passphrase.GetPayload()) assert.Empty(t, f.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) assert.Empty(t, f.FsConfig.CryptConfig.Passphrase.GetKey()) @@ -5086,7 +5081,7 @@ func TestAdminTwoFactorLogin(t *testing.T) { assert.NoError(t, err) altToken, err := getJWTAPITokenFromTestServer(altAdminUsername, altAdminPassword) assert.NoError(t, err) - adminTOTPConfig := dataprovider.TOTPConfig{ + adminTOTPConfig := dataprovider.AdminTOTPConfig{ Enabled: true, ConfigName: configName, Secret: kms.NewPlainSecret(secret), @@ -5118,7 +5113,7 @@ func TestAdminTwoFactorLogin(t *testing.T) { for _, c := range admin.Filters.RecoveryCodes { assert.Empty(t, c.Secret.GetAdditionalData()) assert.Empty(t, c.Secret.GetKey()) - assert.Equal(t, kms.SecretStatusSecretBox, c.Secret.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, c.Secret.GetStatus()) assert.NotEmpty(t, c.Secret.GetPayload()) } @@ -5409,7 +5404,7 @@ func TestAdminTOTP(t *testing.T) { admin.Username = altAdminUsername admin.Password = altAdminPassword // TOTPConfig will be ignored on add - admin.Filters.TOTPConfig = dataprovider.TOTPConfig{ + admin.Filters.TOTPConfig = dataprovider.AdminTOTPConfig{ Enabled: true, ConfigName: "config", Secret: kms.NewEmptySecret(), @@ -5478,7 +5473,7 @@ func TestAdminTOTP(t *testing.T) { checkResponseCode(t, http.StatusBadRequest, rr) assert.Contains(t, rr.Body.String(), "this passcode was already used") - adminTOTPConfig := dataprovider.TOTPConfig{ + adminTOTPConfig := dataprovider.AdminTOTPConfig{ Enabled: true, ConfigName: totpGenResp.ConfigName, Secret: kms.NewPlainSecret(totpGenResp.Secret), @@ -5497,13 +5492,13 @@ func TestAdminTOTP(t *testing.T) { assert.Empty(t, admin.Filters.TOTPConfig.Secret.GetKey()) assert.Empty(t, admin.Filters.TOTPConfig.Secret.GetAdditionalData()) assert.NotEmpty(t, admin.Filters.TOTPConfig.Secret.GetPayload()) - assert.Equal(t, kms.SecretStatusSecretBox, admin.Filters.TOTPConfig.Secret.GetStatus()) - admin.Filters.TOTPConfig = dataprovider.TOTPConfig{ + assert.Equal(t, sdkkms.SecretStatusSecretBox, admin.Filters.TOTPConfig.Secret.GetStatus()) + admin.Filters.TOTPConfig = dataprovider.AdminTOTPConfig{ Enabled: false, ConfigName: util.GenerateUniqueID(), Secret: kms.NewEmptySecret(), } - admin.Filters.RecoveryCodes = []sdk.RecoveryCode{ + admin.Filters.RecoveryCodes = []dataprovider.RecoveryCode{ { Secret: kms.NewEmptySecret(), }, @@ -5655,7 +5650,7 @@ func TestWebUserTwoFactorLogin(t *testing.T) { webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) assert.NoError(t, err) - userTOTPConfig := sdk.TOTPConfig{ + userTOTPConfig := dataprovider.UserTOTPConfig{ Enabled: true, ConfigName: configName, Secret: kms.NewPlainSecret(secret), @@ -5685,7 +5680,7 @@ func TestWebUserTwoFactorLogin(t *testing.T) { for _, c := range user.Filters.RecoveryCodes { assert.Empty(t, c.Secret.GetAdditionalData()) assert.Empty(t, c.Secret.GetKey()) - assert.Equal(t, kms.SecretStatusSecretBox, c.Secret.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, c.Secret.GetStatus()) assert.NotEmpty(t, c.Secret.GetPayload()) } @@ -6111,7 +6106,7 @@ func TestMFAErrors(t *testing.T) { rr = executeRequest(req) checkResponseCode(t, http.StatusBadRequest, rr) // invalid TOTP config name - userTOTPConfig := sdk.TOTPConfig{ + userTOTPConfig := dataprovider.UserTOTPConfig{ Enabled: true, ConfigName: "missing name", Secret: kms.NewPlainSecret(xid.New().String()), @@ -6126,7 +6121,7 @@ func TestMFAErrors(t *testing.T) { checkResponseCode(t, http.StatusBadRequest, rr) assert.Contains(t, rr.Body.String(), "totp: config name") // invalid TOTP secret - userTOTPConfig = sdk.TOTPConfig{ + userTOTPConfig = dataprovider.UserTOTPConfig{ Enabled: true, ConfigName: mfa.GetAvailableTOTPConfigNames()[0], Secret: nil, @@ -6141,7 +6136,7 @@ func TestMFAErrors(t *testing.T) { checkResponseCode(t, http.StatusBadRequest, rr) assert.Contains(t, rr.Body.String(), "totp: secret is mandatory") // no protocol - userTOTPConfig = sdk.TOTPConfig{ + userTOTPConfig = dataprovider.UserTOTPConfig{ Enabled: true, ConfigName: mfa.GetAvailableTOTPConfigNames()[0], Secret: kms.NewPlainSecret(xid.New().String()), @@ -6156,7 +6151,7 @@ func TestMFAErrors(t *testing.T) { checkResponseCode(t, http.StatusBadRequest, rr) assert.Contains(t, rr.Body.String(), "totp: specify at least one protocol") // invalid protocol - userTOTPConfig = sdk.TOTPConfig{ + userTOTPConfig = dataprovider.UserTOTPConfig{ Enabled: true, ConfigName: mfa.GetAvailableTOTPConfigNames()[0], Secret: kms.NewPlainSecret(xid.New().String()), @@ -6171,7 +6166,7 @@ func TestMFAErrors(t *testing.T) { checkResponseCode(t, http.StatusBadRequest, rr) assert.Contains(t, rr.Body.String(), "totp: invalid protocol") - adminTOTPConfig := dataprovider.TOTPConfig{ + adminTOTPConfig := dataprovider.AdminTOTPConfig{ Enabled: true, ConfigName: "", Secret: kms.NewPlainSecret("secret"), @@ -6185,7 +6180,7 @@ func TestMFAErrors(t *testing.T) { checkResponseCode(t, http.StatusBadRequest, rr) assert.Contains(t, rr.Body.String(), "totp: config name is mandatory") - adminTOTPConfig = dataprovider.TOTPConfig{ + adminTOTPConfig = dataprovider.AdminTOTPConfig{ Enabled: true, ConfigName: mfa.GetAvailableTOTPConfigNames()[0], Secret: nil, @@ -6200,10 +6195,10 @@ func TestMFAErrors(t *testing.T) { assert.Contains(t, rr.Body.String(), "totp: secret is mandatory") // invalid TOTP secret status - userTOTPConfig = sdk.TOTPConfig{ + userTOTPConfig = dataprovider.UserTOTPConfig{ Enabled: true, ConfigName: mfa.GetAvailableTOTPConfigNames()[0], - Secret: kms.NewSecret(kms.SecretStatusRedacted, "", "", ""), + Secret: kms.NewSecret(sdkkms.SecretStatusRedacted, "", "", ""), Protocols: []string{common.ProtocolSSH}, } asJSON, err = json.Marshal(userTOTPConfig) @@ -6237,15 +6232,15 @@ func TestMFAInvalidSecret(t *testing.T) { assert.NoError(t, err) user.Password = defaultPassword - user.Filters.TOTPConfig = sdk.TOTPConfig{ + user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{ Enabled: true, ConfigName: mfa.GetAvailableTOTPConfigNames()[0], - Secret: kms.NewSecret(kms.SecretStatusSecretBox, "payload", "key", user.Username), + Secret: kms.NewSecret(sdkkms.SecretStatusSecretBox, "payload", "key", user.Username), Protocols: []string{common.ProtocolSSH, common.ProtocolHTTP}, } - user.Filters.RecoveryCodes = append(user.Filters.RecoveryCodes, sdk.RecoveryCode{ + user.Filters.RecoveryCodes = append(user.Filters.RecoveryCodes, dataprovider.RecoveryCode{ Used: false, - Secret: kms.NewSecret(kms.SecretStatusSecretBox, "payload", "key", user.Username), + Secret: kms.NewSecret(sdkkms.SecretStatusSecretBox, "payload", "key", user.Username), }) err = dataprovider.UpdateUser(&user, "", "") assert.NoError(t, err) @@ -6310,14 +6305,14 @@ func TestMFAInvalidSecret(t *testing.T) { assert.NoError(t, err) admin.Password = altAdminPassword - admin.Filters.TOTPConfig = dataprovider.TOTPConfig{ + admin.Filters.TOTPConfig = dataprovider.AdminTOTPConfig{ Enabled: true, ConfigName: mfa.GetAvailableTOTPConfigNames()[0], - Secret: kms.NewSecret(kms.SecretStatusSecretBox, "payload", "key", user.Username), + Secret: kms.NewSecret(sdkkms.SecretStatusSecretBox, "payload", "key", user.Username), } - admin.Filters.RecoveryCodes = append(user.Filters.RecoveryCodes, sdk.RecoveryCode{ + admin.Filters.RecoveryCodes = append(user.Filters.RecoveryCodes, dataprovider.RecoveryCode{ Used: false, - Secret: kms.NewSecret(kms.SecretStatusSecretBox, "payload", "key", user.Username), + Secret: kms.NewSecret(sdkkms.SecretStatusSecretBox, "payload", "key", user.Username), }) err = dataprovider.UpdateAdmin(&admin, "", "") assert.NoError(t, err) @@ -6370,7 +6365,7 @@ func TestMFAInvalidSecret(t *testing.T) { func TestWebUserTOTP(t *testing.T) { u := getTestUser() // TOTPConfig will be ignored on add - u.Filters.TOTPConfig = sdk.TOTPConfig{ + u.Filters.TOTPConfig = dataprovider.UserTOTPConfig{ Enabled: true, ConfigName: "", Secret: kms.NewEmptySecret(), @@ -6430,7 +6425,7 @@ func TestWebUserTOTP(t *testing.T) { checkResponseCode(t, http.StatusBadRequest, rr) assert.Contains(t, rr.Body.String(), "this passcode was already used") - userTOTPConfig := sdk.TOTPConfig{ + userTOTPConfig := dataprovider.UserTOTPConfig{ Enabled: true, ConfigName: totpGenResp.ConfigName, Secret: kms.NewPlainSecret(totpGenResp.Secret), @@ -6453,11 +6448,11 @@ func TestWebUserTOTP(t *testing.T) { assert.Empty(t, totpCfg.Secret.GetKey()) assert.Empty(t, totpCfg.Secret.GetAdditionalData()) assert.NotEmpty(t, secretPayload) - assert.Equal(t, kms.SecretStatusSecretBox, totpCfg.Secret.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, totpCfg.Secret.GetStatus()) assert.Len(t, totpCfg.Protocols, 1) assert.Contains(t, totpCfg.Protocols, common.ProtocolSSH) // update protocols only - userTOTPConfig = sdk.TOTPConfig{ + userTOTPConfig = dataprovider.UserTOTPConfig{ Protocols: []string{common.ProtocolSSH, common.ProtocolFTP}, Secret: kms.NewEmptySecret(), } @@ -6470,7 +6465,7 @@ func TestWebUserTOTP(t *testing.T) { checkResponseCode(t, http.StatusOK, rr) // update the user, TOTP should not be affected - user.Filters.TOTPConfig = sdk.TOTPConfig{ + user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{ Enabled: false, Secret: kms.NewEmptySecret(), } @@ -6484,7 +6479,7 @@ func TestWebUserTOTP(t *testing.T) { assert.Empty(t, user.Filters.TOTPConfig.Secret.GetKey()) assert.Empty(t, user.Filters.TOTPConfig.Secret.GetAdditionalData()) assert.Equal(t, secretPayload, user.Filters.TOTPConfig.Secret.GetPayload()) - assert.Equal(t, kms.SecretStatusSecretBox, user.Filters.TOTPConfig.Secret.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.Filters.TOTPConfig.Secret.GetStatus()) assert.Len(t, user.Filters.TOTPConfig.Protocols, 2) assert.Contains(t, user.Filters.TOTPConfig.Protocols, common.ProtocolSSH) assert.Contains(t, user.Filters.TOTPConfig.Protocols, common.ProtocolFTP) @@ -8520,21 +8515,21 @@ func TestSFTPLoopError(t *testing.T) { user1.FsConfig = vfs.Filesystem{ Provider: sdk.SFTPFilesystemProvider, SFTPConfig: vfs.SFTPFsConfig{ - SFTPFsConfig: sdk.SFTPFsConfig{ + BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{ Endpoint: sftpServerAddr, Username: user2.Username, - Password: kms.NewPlainSecret(defaultPassword), }, + Password: kms.NewPlainSecret(defaultPassword), }, } user2.FsConfig.Provider = sdk.SFTPFilesystemProvider user2.FsConfig.SFTPConfig = vfs.SFTPFsConfig{ - SFTPFsConfig: sdk.SFTPFsConfig{ + BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{ Endpoint: sftpServerAddr, Username: user1.Username, - Password: kms.NewPlainSecret(defaultPassword), }, + Password: kms.NewPlainSecret(defaultPassword), } user1, resp, err := httpdtest.AddUser(user1, http.StatusCreated) @@ -12644,7 +12639,7 @@ func TestWebAdminBasicMock(t *testing.T) { assert.NoError(t, err) altToken, err := getJWTWebTokenFromTestServer(altAdminUsername, altAdminPassword) assert.NoError(t, err) - adminTOTPConfig := dataprovider.TOTPConfig{ + adminTOTPConfig := dataprovider.AdminTOTPConfig{ Enabled: true, ConfigName: configName, Secret: kms.NewPlainSecret(secret), @@ -12672,7 +12667,7 @@ func TestWebAdminBasicMock(t *testing.T) { secretPayload := admin.Filters.TOTPConfig.Secret.GetPayload() assert.NotEmpty(t, secretPayload) - adminTOTPConfig = dataprovider.TOTPConfig{ + adminTOTPConfig = dataprovider.AdminTOTPConfig{ Enabled: true, ConfigName: configName, Secret: kms.NewEmptySecret(), @@ -12691,7 +12686,7 @@ func TestWebAdminBasicMock(t *testing.T) { assert.True(t, admin.Filters.TOTPConfig.Enabled) assert.Equal(t, secretPayload, admin.Filters.TOTPConfig.Secret.GetPayload()) - adminTOTPConfig = dataprovider.TOTPConfig{ + adminTOTPConfig = dataprovider.AdminTOTPConfig{ Enabled: true, ConfigName: configName, Secret: nil, @@ -13374,7 +13369,7 @@ func TestWebUserUpdateMock(t *testing.T) { assert.NoError(t, err) userToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword) assert.NoError(t, err) - userTOTPConfig := sdk.TOTPConfig{ + userTOTPConfig := dataprovider.UserTOTPConfig{ Enabled: true, ConfigName: configName, Secret: kms.NewPlainSecret(secret), @@ -14131,7 +14126,7 @@ func TestWebUserS3Mock(t *testing.T) { assert.Equal(t, updateUser.FsConfig.S3Config.DownloadConcurrency, user.FsConfig.S3Config.DownloadConcurrency) assert.True(t, updateUser.FsConfig.S3Config.ForcePathStyle) assert.Equal(t, 2, len(updateUser.Filters.FilePatterns)) - assert.Equal(t, kms.SecretStatusSecretBox, updateUser.FsConfig.S3Config.AccessSecret.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, updateUser.FsConfig.S3Config.AccessSecret.GetStatus()) assert.NotEmpty(t, updateUser.FsConfig.S3Config.AccessSecret.GetPayload()) assert.Empty(t, updateUser.FsConfig.S3Config.AccessSecret.GetKey()) assert.Empty(t, updateUser.FsConfig.S3Config.AccessSecret.GetAdditionalData()) @@ -14157,7 +14152,7 @@ func TestWebUserS3Mock(t *testing.T) { var lastUpdatedUser dataprovider.User err = render.DecodeJSON(rr.Body, &lastUpdatedUser) assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.S3Config.AccessSecret.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.S3Config.AccessSecret.GetStatus()) assert.Equal(t, updateUser.FsConfig.S3Config.AccessSecret.GetPayload(), lastUpdatedUser.FsConfig.S3Config.AccessSecret.GetPayload()) assert.Empty(t, lastUpdatedUser.FsConfig.S3Config.AccessSecret.GetKey()) assert.Empty(t, lastUpdatedUser.FsConfig.S3Config.AccessSecret.GetAdditionalData()) @@ -14392,7 +14387,7 @@ func TestWebUserAzureBlobMock(t *testing.T) { assert.Equal(t, updateUser.FsConfig.AzBlobConfig.UploadPartSize, user.FsConfig.AzBlobConfig.UploadPartSize) assert.Equal(t, updateUser.FsConfig.AzBlobConfig.UploadConcurrency, user.FsConfig.AzBlobConfig.UploadConcurrency) assert.Equal(t, 2, len(updateUser.Filters.FilePatterns)) - assert.Equal(t, kms.SecretStatusSecretBox, updateUser.FsConfig.AzBlobConfig.AccountKey.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, updateUser.FsConfig.AzBlobConfig.AccountKey.GetStatus()) assert.NotEmpty(t, updateUser.FsConfig.AzBlobConfig.AccountKey.GetPayload()) assert.Empty(t, updateUser.FsConfig.AzBlobConfig.AccountKey.GetKey()) assert.Empty(t, updateUser.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData()) @@ -14411,7 +14406,7 @@ func TestWebUserAzureBlobMock(t *testing.T) { var lastUpdatedUser dataprovider.User err = render.DecodeJSON(rr.Body, &lastUpdatedUser) assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.AzBlobConfig.AccountKey.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.AzBlobConfig.AccountKey.GetStatus()) assert.Equal(t, updateUser.FsConfig.AzBlobConfig.AccountKey.GetPayload(), lastUpdatedUser.FsConfig.AzBlobConfig.AccountKey.GetPayload()) assert.Empty(t, lastUpdatedUser.FsConfig.AzBlobConfig.AccountKey.GetKey()) assert.Empty(t, lastUpdatedUser.FsConfig.AzBlobConfig.AccountKey.GetAdditionalData()) @@ -14434,7 +14429,7 @@ func TestWebUserAzureBlobMock(t *testing.T) { updateUser = dataprovider.User{} err = render.DecodeJSON(rr.Body, &updateUser) assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusSecretBox, updateUser.FsConfig.AzBlobConfig.SASURL.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, updateUser.FsConfig.AzBlobConfig.SASURL.GetStatus()) assert.NotEmpty(t, updateUser.FsConfig.AzBlobConfig.SASURL.GetPayload()) assert.Empty(t, updateUser.FsConfig.AzBlobConfig.SASURL.GetKey()) assert.Empty(t, updateUser.FsConfig.AzBlobConfig.SASURL.GetAdditionalData()) @@ -14453,7 +14448,7 @@ func TestWebUserAzureBlobMock(t *testing.T) { lastUpdatedUser = dataprovider.User{} err = render.DecodeJSON(rr.Body, &lastUpdatedUser) assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.AzBlobConfig.SASURL.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.AzBlobConfig.SASURL.GetStatus()) assert.Equal(t, updateUser.FsConfig.AzBlobConfig.SASURL.GetPayload(), lastUpdatedUser.FsConfig.AzBlobConfig.SASURL.GetPayload()) assert.Empty(t, lastUpdatedUser.FsConfig.AzBlobConfig.SASURL.GetKey()) assert.Empty(t, lastUpdatedUser.FsConfig.AzBlobConfig.SASURL.GetAdditionalData()) @@ -14530,7 +14525,7 @@ func TestWebUserCryptMock(t *testing.T) { assert.NoError(t, err) assert.Equal(t, int64(1577836800000), updateUser.ExpirationDate) assert.Equal(t, 2, len(updateUser.Filters.FilePatterns)) - assert.Equal(t, kms.SecretStatusSecretBox, updateUser.FsConfig.CryptConfig.Passphrase.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, updateUser.FsConfig.CryptConfig.Passphrase.GetStatus()) assert.NotEmpty(t, updateUser.FsConfig.CryptConfig.Passphrase.GetPayload()) assert.Empty(t, updateUser.FsConfig.CryptConfig.Passphrase.GetKey()) assert.Empty(t, updateUser.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) @@ -14549,7 +14544,7 @@ func TestWebUserCryptMock(t *testing.T) { var lastUpdatedUser dataprovider.User err = render.DecodeJSON(rr.Body, &lastUpdatedUser) assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.CryptConfig.Passphrase.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.CryptConfig.Passphrase.GetStatus()) assert.Equal(t, updateUser.FsConfig.CryptConfig.Passphrase.GetPayload(), lastUpdatedUser.FsConfig.CryptConfig.Passphrase.GetPayload()) assert.Empty(t, lastUpdatedUser.FsConfig.CryptConfig.Passphrase.GetKey()) assert.Empty(t, lastUpdatedUser.FsConfig.CryptConfig.Passphrase.GetAdditionalData()) @@ -14639,11 +14634,11 @@ func TestWebUserSFTPFsMock(t *testing.T) { assert.NoError(t, err) assert.Equal(t, int64(1577836800000), updateUser.ExpirationDate) assert.Equal(t, 2, len(updateUser.Filters.FilePatterns)) - assert.Equal(t, kms.SecretStatusSecretBox, updateUser.FsConfig.SFTPConfig.Password.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, updateUser.FsConfig.SFTPConfig.Password.GetStatus()) assert.NotEmpty(t, updateUser.FsConfig.SFTPConfig.Password.GetPayload()) assert.Empty(t, updateUser.FsConfig.SFTPConfig.Password.GetKey()) assert.Empty(t, updateUser.FsConfig.SFTPConfig.Password.GetAdditionalData()) - assert.Equal(t, kms.SecretStatusSecretBox, updateUser.FsConfig.SFTPConfig.PrivateKey.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, updateUser.FsConfig.SFTPConfig.PrivateKey.GetStatus()) assert.NotEmpty(t, updateUser.FsConfig.SFTPConfig.PrivateKey.GetPayload()) assert.Empty(t, updateUser.FsConfig.SFTPConfig.PrivateKey.GetKey()) assert.Empty(t, updateUser.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData()) @@ -14670,11 +14665,11 @@ func TestWebUserSFTPFsMock(t *testing.T) { var lastUpdatedUser dataprovider.User err = render.DecodeJSON(rr.Body, &lastUpdatedUser) assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.SFTPConfig.Password.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.SFTPConfig.Password.GetStatus()) assert.Equal(t, updateUser.FsConfig.SFTPConfig.Password.GetPayload(), lastUpdatedUser.FsConfig.SFTPConfig.Password.GetPayload()) assert.Empty(t, lastUpdatedUser.FsConfig.SFTPConfig.Password.GetKey()) assert.Empty(t, lastUpdatedUser.FsConfig.SFTPConfig.Password.GetAdditionalData()) - assert.Equal(t, kms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.SFTPConfig.PrivateKey.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.SFTPConfig.PrivateKey.GetStatus()) assert.Equal(t, updateUser.FsConfig.SFTPConfig.PrivateKey.GetPayload(), lastUpdatedUser.FsConfig.SFTPConfig.PrivateKey.GetPayload()) assert.Empty(t, lastUpdatedUser.FsConfig.SFTPConfig.PrivateKey.GetKey()) assert.Empty(t, lastUpdatedUser.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData()) diff --git a/httpd/internal_test.go b/httpd/internal_test.go index 29667e86..06560668 100644 --- a/httpd/internal_test.go +++ b/httpd/internal_test.go @@ -33,9 +33,9 @@ import ( "github.com/drakkan/sftpgo/v2/common" "github.com/drakkan/sftpgo/v2/dataprovider" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/plugin" "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/util" "github.com/drakkan/sftpgo/v2/vfs" ) @@ -1773,10 +1773,10 @@ func TestConnection(t *testing.T) { FsConfig: vfs.Filesystem{ Provider: sdk.GCSFilesystemProvider, GCSConfig: vfs.GCSFsConfig{ - GCSFsConfig: sdk.GCSFsConfig{ - Bucket: "test_bucket_name", - Credentials: kms.NewPlainSecret("invalid JSON payload"), + BaseGCSFsConfig: sdk.BaseGCSFsConfig{ + Bucket: "test_bucket_name", }, + Credentials: kms.NewPlainSecret("invalid JSON payload"), }, }, } @@ -1815,12 +1815,12 @@ func TestGetFileWriterErrors(t *testing.T) { user.FsConfig.Provider = sdk.S3FilesystemProvider user.FsConfig.S3Config = vfs.S3FsConfig{ - S3FsConfig: sdk.S3FsConfig{ - Bucket: "b", - Region: "us-west-1", - AccessKey: "key", - AccessSecret: kms.NewPlainSecret("secret"), + BaseS3FsConfig: sdk.BaseS3FsConfig{ + Bucket: "b", + Region: "us-west-1", + AccessKey: "key", }, + AccessSecret: kms.NewPlainSecret("secret"), } connection = &Connection{ BaseConnection: common.NewBaseConnection(xid.New().String(), common.ProtocolHTTP, "", "", user), diff --git a/httpd/webadmin.go b/httpd/webadmin.go index 27081f8d..402ca8f6 100644 --- a/httpd/webadmin.go +++ b/httpd/webadmin.go @@ -16,9 +16,10 @@ import ( "github.com/drakkan/sftpgo/v2/common" "github.com/drakkan/sftpgo/v2/dataprovider" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/mfa" "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" + sdkkms "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/smtp" "github.com/drakkan/sftpgo/v2/util" "github.com/drakkan/sftpgo/v2/version" @@ -179,7 +180,7 @@ type changePasswordPage struct { type mfaPage struct { basePage TOTPConfigs []string - TOTPConfig dataprovider.TOTPConfig + TOTPConfig dataprovider.AdminTOTPConfig GenerateTOTPURL string ValidateTOTPURL string SaveTOTPURL string @@ -821,8 +822,8 @@ func getFilePatternsFromPostField(r *http.Request) []sdk.PatternsFilter { return result } -func getFiltersFromUserPostFields(r *http.Request) (sdk.UserFilters, error) { - var filters sdk.UserFilters +func getFiltersFromUserPostFields(r *http.Request) (sdk.BaseUserFilters, error) { + var filters sdk.BaseUserFilters bwLimits, err := getBandwidthLimitsFromPostFields(r) if err != nil { return filters, err @@ -853,7 +854,7 @@ func getFiltersFromUserPostFields(r *http.Request) (sdk.UserFilters, error) { func getSecretFromFormField(r *http.Request, field string) *kms.Secret { secret := kms.NewPlainSecret(r.Form.Get(field)) if strings.TrimSpace(secret.GetPayload()) == redactedSecret { - secret.SetStatus(kms.SecretStatusRedacted) + secret.SetStatus(sdkkms.SecretStatusRedacted) } if strings.TrimSpace(secret.GetPayload()) == "" { secret.SetStatus("") @@ -1204,10 +1205,12 @@ func getUserFromPostFields(r *http.Request) (dataprovider.User, error) { DownloadBandwidth: bandwidthDL, Status: status, ExpirationDate: expirationDateMillis, - Filters: filters, AdditionalInfo: r.Form.Get("additional_info"), Description: r.Form.Get("description"), }, + Filters: dataprovider.UserFilters{ + BaseUserFilters: filters, + }, VirtualFolders: getVirtualFoldersFromPostFields(r), FsConfig: fsConfig, } diff --git a/httpd/webclient.go b/httpd/webclient.go index 763fd84f..4d85dc86 100644 --- a/httpd/webclient.go +++ b/httpd/webclient.go @@ -158,7 +158,7 @@ type changeClientPasswordPage struct { type clientMFAPage struct { baseClientPage TOTPConfigs []string - TOTPConfig sdk.TOTPConfig + TOTPConfig dataprovider.UserTOTPConfig GenerateTOTPURL string ValidateTOTPURL string SaveTOTPURL string diff --git a/httpdtest/httpdtest.go b/httpdtest/httpdtest.go index e05b99b9..dcabb3b1 100644 --- a/httpdtest/httpdtest.go +++ b/httpdtest/httpdtest.go @@ -20,7 +20,7 @@ import ( "github.com/drakkan/sftpgo/v2/dataprovider" "github.com/drakkan/sftpgo/v2/httpclient" "github.com/drakkan/sftpgo/v2/httpd" - "github.com/drakkan/sftpgo/v2/sdk/kms" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/util" "github.com/drakkan/sftpgo/v2/version" "github.com/drakkan/sftpgo/v2/vfs" diff --git a/sdk/kms/basesecret.go b/kms/basesecret.go similarity index 73% rename from sdk/kms/basesecret.go rename to kms/basesecret.go index 9e8a5c49..66604f74 100644 --- a/sdk/kms/basesecret.go +++ b/kms/basesecret.go @@ -1,17 +1,21 @@ package kms +import ( + sdkkms "github.com/drakkan/sftpgo/v2/sdk/kms" +) + // BaseSecret defines the base struct shared among all the secret providers type BaseSecret struct { - Status SecretStatus `json:"status,omitempty"` - Payload string `json:"payload,omitempty"` - Key string `json:"key,omitempty"` - AdditionalData string `json:"additional_data,omitempty"` + Status sdkkms.SecretStatus `json:"status,omitempty"` + Payload string `json:"payload,omitempty"` + Key string `json:"key,omitempty"` + AdditionalData string `json:"additional_data,omitempty"` // 1 means encrypted using a master key Mode int `json:"mode,omitempty"` } // GetStatus returns the secret's status -func (s *BaseSecret) GetStatus() SecretStatus { +func (s *BaseSecret) GetStatus() sdkkms.SecretStatus { return s.Status } @@ -46,7 +50,7 @@ func (s *BaseSecret) SetAdditionalData(value string) { } // SetStatus sets the secret's status -func (s *BaseSecret) SetStatus(value SecretStatus) { +func (s *BaseSecret) SetStatus(value sdkkms.SecretStatus) { s.Status = value } diff --git a/sdk/kms/builtin.go b/kms/builtin.go similarity index 88% rename from sdk/kms/builtin.go rename to kms/builtin.go index bfb001e9..56c40a6c 100644 --- a/sdk/kms/builtin.go +++ b/kms/builtin.go @@ -8,6 +8,8 @@ import ( "encoding/hex" "errors" "io" + + sdkkms "github.com/drakkan/sftpgo/v2/sdk/kms" ) var ( @@ -19,7 +21,7 @@ type builtinSecret struct { } func init() { - RegisterSecretProvider(SchemeBuiltin, SecretStatusAES256GCM, newBuiltinSecret) + RegisterSecretProvider(sdkkms.SchemeBuiltin, sdkkms.SecretStatusAES256GCM, newBuiltinSecret) } func newBuiltinSecret(base BaseSecret, url, masterKey string) SecretProvider { @@ -33,7 +35,7 @@ func (s *builtinSecret) Name() string { } func (s *builtinSecret) IsEncrypted() bool { - return s.Status == SecretStatusAES256GCM + return s.Status == sdkkms.SecretStatusAES256GCM } func (s *builtinSecret) deriveKey(key []byte) []byte { @@ -52,7 +54,7 @@ func (s *builtinSecret) Encrypt() error { return ErrInvalidSecret } switch s.Status { - case SecretStatusPlain: + case sdkkms.SecretStatusPlain: key := make([]byte, 32) if _, err := io.ReadFull(rand.Reader, key); err != nil { return err @@ -76,7 +78,7 @@ func (s *builtinSecret) Encrypt() error { ciphertext := gcm.Seal(nonce, nonce, []byte(s.Payload), aad) s.Key = hex.EncodeToString(key) s.Payload = hex.EncodeToString(ciphertext) - s.Status = SecretStatusAES256GCM + s.Status = sdkkms.SecretStatusAES256GCM return nil default: return ErrWrongSecretStatus @@ -85,7 +87,7 @@ func (s *builtinSecret) Encrypt() error { func (s *builtinSecret) Decrypt() error { switch s.Status { - case SecretStatusAES256GCM: + case sdkkms.SecretStatusAES256GCM: encrypted, err := hex.DecodeString(s.Payload) if err != nil { return err @@ -115,7 +117,7 @@ func (s *builtinSecret) Decrypt() error { if err != nil { return err } - s.Status = SecretStatusPlain + s.Status = sdkkms.SecretStatusPlain s.Payload = string(plaintext) s.Key = "" s.AdditionalData = "" diff --git a/kms/kms.go b/kms/kms.go new file mode 100644 index 00000000..e2a94e65 --- /dev/null +++ b/kms/kms.go @@ -0,0 +1,417 @@ +// Package kms provides Key Management Services support +package kms + +import ( + "encoding/json" + "errors" + "os" + "strings" + "sync" + + "github.com/drakkan/sftpgo/v2/logger" + sdkkms "github.com/drakkan/sftpgo/v2/sdk/kms" +) + +// SecretProvider defines the interface for a KMS secrets provider +type SecretProvider interface { + Name() string + Encrypt() error + Decrypt() error + IsEncrypted() bool + GetStatus() sdkkms.SecretStatus + GetPayload() string + GetKey() string + GetAdditionalData() string + GetMode() int + SetKey(string) + SetAdditionalData(string) + SetStatus(sdkkms.SecretStatus) + Clone() SecretProvider +} + +const ( + logSender = "kms" +) + +// Configuration defines the KMS configuration +type Configuration struct { + Secrets Secrets `json:"secrets" mapstructure:"secrets"` +} + +// Secrets define the KMS configuration for encryption/decryption +type Secrets struct { + URL string `json:"url" mapstructure:"url"` + MasterKeyPath string `json:"master_key_path" mapstructure:"master_key_path"` + MasterKeyString string `json:"master_key" mapstructure:"master_key"` + masterKey string +} + +type registeredSecretProvider struct { + encryptedStatus sdkkms.SecretStatus + newFn func(base BaseSecret, url, masterKey string) SecretProvider +} + +var ( + // ErrWrongSecretStatus defines the error to return if the secret status is not appropriate + // for the request operation + ErrWrongSecretStatus = errors.New("wrong secret status") + // ErrInvalidSecret defines the error to return if a secret is not valid + ErrInvalidSecret = errors.New("invalid secret") + validSecretStatuses = []string{sdkkms.SecretStatusPlain, sdkkms.SecretStatusAES256GCM, sdkkms.SecretStatusSecretBox, + sdkkms.SecretStatusVaultTransit, sdkkms.SecretStatusAWS, sdkkms.SecretStatusGCP, sdkkms.SecretStatusRedacted} + config Configuration + secretProviders = make(map[string]registeredSecretProvider) +) + +// RegisterSecretProvider register a new secret provider +func RegisterSecretProvider(scheme string, encryptedStatus sdkkms.SecretStatus, + fn func(base BaseSecret, url, masterKey string) SecretProvider, +) { + secretProviders[scheme] = registeredSecretProvider{ + encryptedStatus: encryptedStatus, + newFn: fn, + } +} + +// NewSecret builds a new Secret using the provided arguments +func NewSecret(status sdkkms.SecretStatus, payload, key, data string) *Secret { + return config.newSecret(status, payload, key, data) +} + +// NewEmptySecret returns an empty secret +func NewEmptySecret() *Secret { + return NewSecret("", "", "", "") +} + +// NewPlainSecret stores the give payload in a plain text secret +func NewPlainSecret(payload string) *Secret { + return NewSecret(sdkkms.SecretStatusPlain, payload, "", "") +} + +// Initialize configures the KMS support +func (c *Configuration) Initialize() error { + if c.Secrets.MasterKeyString != "" { + c.Secrets.masterKey = c.Secrets.MasterKeyString + } + if c.Secrets.masterKey == "" && c.Secrets.MasterKeyPath != "" { + mKey, err := os.ReadFile(c.Secrets.MasterKeyPath) + if err != nil { + return err + } + c.Secrets.masterKey = strings.TrimSpace(string(mKey)) + } + config = *c + if config.Secrets.URL == "" { + config.Secrets.URL = sdkkms.SchemeLocal + "://" + } + for k, v := range secretProviders { + logger.Info(logSender, "", "secret provider registered for scheme: %#v, encrypted status: %#v", + k, v.encryptedStatus) + } + return nil +} + +func (c *Configuration) newSecret(status sdkkms.SecretStatus, payload, key, data string) *Secret { + base := BaseSecret{ + Status: status, + Key: key, + Payload: payload, + AdditionalData: data, + } + return &Secret{ + provider: c.getSecretProvider(base), + } +} + +func (c *Configuration) getSecretProvider(base BaseSecret) SecretProvider { + for k, v := range secretProviders { + if strings.HasPrefix(c.Secrets.URL, k) { + return v.newFn(base, c.Secrets.URL, c.Secrets.masterKey) + } + } + logger.Warn(logSender, "", "no secret provider registered for URL %v, fallback to local provider", c.Secrets.URL) + return NewLocalSecret(base, c.Secrets.URL, c.Secrets.masterKey) +} + +// Secret defines the struct used to store confidential data +type Secret struct { + sync.RWMutex + provider SecretProvider +} + +// MarshalJSON return the JSON encoding of the Secret object +func (s *Secret) MarshalJSON() ([]byte, error) { + s.RLock() + defer s.RUnlock() + + return json.Marshal(&BaseSecret{ + Status: s.provider.GetStatus(), + Payload: s.provider.GetPayload(), + Key: s.provider.GetKey(), + AdditionalData: s.provider.GetAdditionalData(), + Mode: s.provider.GetMode(), + }) +} + +// UnmarshalJSON parses the JSON-encoded data and stores the result +// in the Secret object +func (s *Secret) UnmarshalJSON(data []byte) error { + s.Lock() + defer s.Unlock() + + baseSecret := BaseSecret{} + err := json.Unmarshal(data, &baseSecret) + if err != nil { + return err + } + if baseSecret.isEmpty() { + s.provider = config.getSecretProvider(baseSecret) + return nil + } + + if baseSecret.Status == sdkkms.SecretStatusPlain || baseSecret.Status == sdkkms.SecretStatusRedacted { + s.provider = config.getSecretProvider(baseSecret) + return nil + } + + for _, v := range secretProviders { + if v.encryptedStatus == baseSecret.Status { + s.provider = v.newFn(baseSecret, config.Secrets.URL, config.Secrets.masterKey) + return nil + } + } + logger.Error(logSender, "", "no provider registered for status %#v", baseSecret.Status) + return ErrInvalidSecret +} + +// IsEqual returns true if all the secrets fields are equal +func (s *Secret) IsEqual(other *Secret) bool { + if s.GetStatus() != other.GetStatus() { + return false + } + if s.GetPayload() != other.GetPayload() { + return false + } + if s.GetKey() != other.GetKey() { + return false + } + if s.GetAdditionalData() != other.GetAdditionalData() { + return false + } + if s.GetMode() != other.GetMode() { + return false + } + return true +} + +// Clone returns a copy of the secret object +func (s *Secret) Clone() *Secret { + s.RLock() + defer s.RUnlock() + + return &Secret{ + provider: s.provider.Clone(), + } +} + +// IsEncrypted returns true if the secret is encrypted +// This isn't a pointer receiver because we don't want to pass +// a pointer to html template +func (s *Secret) IsEncrypted() bool { + s.RLock() + defer s.RUnlock() + + return s.provider.IsEncrypted() +} + +// IsPlain returns true if the secret is in plain text +func (s *Secret) IsPlain() bool { + s.RLock() + defer s.RUnlock() + + return s.provider.GetStatus() == sdkkms.SecretStatusPlain +} + +// IsNotPlainAndNotEmpty returns true if the secret is not plain and not empty. +// This is an utility method, we update the secret for an existing user +// if it is empty or plain +func (s *Secret) IsNotPlainAndNotEmpty() bool { + s.RLock() + defer s.RUnlock() + + return !s.IsPlain() && !s.IsEmpty() +} + +// IsRedacted returns true if the secret is redacted +func (s *Secret) IsRedacted() bool { + s.RLock() + defer s.RUnlock() + + return s.provider.GetStatus() == sdkkms.SecretStatusRedacted +} + +// GetPayload returns the secret payload +func (s *Secret) GetPayload() string { + s.RLock() + defer s.RUnlock() + + return s.provider.GetPayload() +} + +// GetAdditionalData returns the secret additional data +func (s *Secret) GetAdditionalData() string { + s.RLock() + defer s.RUnlock() + + return s.provider.GetAdditionalData() +} + +// GetStatus returns the secret status +func (s *Secret) GetStatus() sdkkms.SecretStatus { + s.RLock() + defer s.RUnlock() + + return s.provider.GetStatus() +} + +// GetKey returns the secret key +func (s *Secret) GetKey() string { + s.RLock() + defer s.RUnlock() + + return s.provider.GetKey() +} + +// GetMode returns the secret mode +func (s *Secret) GetMode() int { + s.RLock() + defer s.RUnlock() + + return s.provider.GetMode() +} + +// SetAdditionalData sets the given additional data +func (s *Secret) SetAdditionalData(value string) { + s.Lock() + defer s.Unlock() + + s.provider.SetAdditionalData(value) +} + +// SetStatus sets the status for this secret +func (s *Secret) SetStatus(value sdkkms.SecretStatus) { + s.Lock() + defer s.Unlock() + + s.provider.SetStatus(value) +} + +// SetKey sets the key for this secret +func (s *Secret) SetKey(value string) { + s.Lock() + defer s.Unlock() + + s.provider.SetKey(value) +} + +// IsEmpty returns true if all fields are empty +func (s *Secret) IsEmpty() bool { + s.RLock() + defer s.RUnlock() + + if s.provider.GetStatus() != "" { + return false + } + if s.provider.GetPayload() != "" { + return false + } + if s.provider.GetKey() != "" { + return false + } + if s.provider.GetAdditionalData() != "" { + return false + } + return true +} + +// IsValid returns true if the secret is not empty and valid +func (s *Secret) IsValid() bool { + s.RLock() + defer s.RUnlock() + + if !s.IsValidInput() { + return false + } + switch s.provider.GetStatus() { + case sdkkms.SecretStatusAES256GCM, sdkkms.SecretStatusSecretBox: + if len(s.provider.GetKey()) != 64 { + return false + } + case sdkkms.SecretStatusAWS, sdkkms.SecretStatusGCP, sdkkms.SecretStatusVaultTransit: + key := s.provider.GetKey() + if key != "" && len(key) != 64 { + return false + } + } + return true +} + +// IsValidInput returns true if the secret is a valid user input +func (s *Secret) IsValidInput() bool { + s.RLock() + defer s.RUnlock() + + if !isSecretStatusValid(s.provider.GetStatus()) { + return false + } + if s.provider.GetPayload() == "" { + return false + } + return true +} + +// Hide hides info to decrypt data +func (s *Secret) Hide() { + s.Lock() + defer s.Unlock() + + s.provider.SetKey("") + s.provider.SetAdditionalData("") +} + +// Encrypt encrypts a plain text Secret object +func (s *Secret) Encrypt() error { + s.Lock() + defer s.Unlock() + + return s.provider.Encrypt() +} + +// Decrypt decrypts a Secret object +func (s *Secret) Decrypt() error { + s.Lock() + defer s.Unlock() + + return s.provider.Decrypt() +} + +// TryDecrypt decrypts a Secret object if encrypted. +// It returns a nil error if the object is not encrypted +func (s *Secret) TryDecrypt() error { + s.Lock() + defer s.Unlock() + + if s.provider.IsEncrypted() { + return s.provider.Decrypt() + } + return nil +} + +func isSecretStatusValid(status string) bool { + for idx := range validSecretStatuses { + if validSecretStatuses[idx] == status { + return true + } + } + return false +} diff --git a/sdk/kms/local.go b/kms/local.go similarity index 90% rename from sdk/kms/local.go rename to kms/local.go index a360b163..53afeb42 100644 --- a/sdk/kms/local.go +++ b/kms/local.go @@ -9,10 +9,12 @@ import ( "gocloud.dev/secrets/localsecrets" "golang.org/x/crypto/hkdf" + + sdkkms "github.com/drakkan/sftpgo/v2/sdk/kms" ) func init() { - RegisterSecretProvider(SchemeLocal, SecretStatusSecretBox, NewLocalSecret) + RegisterSecretProvider(sdkkms.SchemeLocal, sdkkms.SecretStatusSecretBox, NewLocalSecret) } type localSecret struct { @@ -33,11 +35,11 @@ func (s *localSecret) Name() string { } func (s *localSecret) IsEncrypted() bool { - return s.Status == SecretStatusSecretBox + return s.Status == sdkkms.SecretStatusSecretBox } func (s *localSecret) Encrypt() error { - if s.Status != SecretStatusPlain { + if s.Status != sdkkms.SecretStatusPlain { return ErrWrongSecretStatus } if s.Payload == "" { @@ -60,7 +62,7 @@ func (s *localSecret) Encrypt() error { } s.Key = hex.EncodeToString(secretKey[:]) s.Payload = base64.StdEncoding.EncodeToString(ciphertext) - s.Status = SecretStatusSecretBox + s.Status = sdkkms.SecretStatusSecretBox s.Mode = s.getEncryptionMode() return nil } @@ -88,7 +90,7 @@ func (s *localSecret) Decrypt() error { if err != nil { return err } - s.Status = SecretStatusPlain + s.Status = sdkkms.SecretStatusPlain s.Payload = string(plaintext) s.Key = "" s.AdditionalData = "" diff --git a/logger/logger.go b/logger/logger.go index f191a355..0b946fe2 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -18,8 +18,6 @@ import ( ftpserverlog "github.com/fclairamb/go-log" "github.com/rs/zerolog" lumberjack "gopkg.in/natefinch/lumberjack.v2" - - sdklogger "github.com/drakkan/sftpgo/v2/sdk/logger" ) const ( @@ -43,22 +41,6 @@ var ( rollingLogger *lumberjack.Logger ) -type logWrapper struct{} - -// Log logs at the specified level for the specified sender -func (l *logWrapper) Log(level int, sender, format string, v ...interface{}) { - switch level { - case 1: - Log(LevelInfo, sender, "", format, v...) - case 2: - Log(LevelWarn, sender, "", format, v...) - case 3: - Log(LevelError, sender, "", format, v...) - default: - Log(LevelDebug, sender, "", format, v...) - } -} - // StdLoggerWrapper is a wrapper for standard logger compatibility type StdLoggerWrapper struct { Sender string @@ -194,7 +176,6 @@ func InitLogger(logFilePath string, logMaxSize int, logMaxBackups int, logMaxAge consoleLogger = zerolog.Nop() } logger = logger.Level(level) - sdklogger.SetLogger(&logWrapper{}) } // InitStdErrLogger configures the logger to write to stderr @@ -203,7 +184,6 @@ func InitStdErrLogger(level zerolog.Level) { output: os.Stderr, }).Level(level) consoleLogger = zerolog.Nop() - sdklogger.SetLogger(&logWrapper{}) } // DisableLogger disable the main logger. @@ -211,7 +191,6 @@ func InitStdErrLogger(level zerolog.Level) { func DisableLogger() { logger = zerolog.Nop() rollingLogger = nil - sdklogger.DisableLogger() } // EnableConsoleLogger enables the console logger diff --git a/plugin/kms.go b/plugin/kms.go index 6e80a51b..5f4b34cc 100644 --- a/plugin/kms.go +++ b/plugin/kms.go @@ -9,16 +9,17 @@ import ( "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-plugin" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/logger" - "github.com/drakkan/sftpgo/v2/sdk/kms" + sdkkms "github.com/drakkan/sftpgo/v2/sdk/kms" kmsplugin "github.com/drakkan/sftpgo/v2/sdk/plugin/kms" "github.com/drakkan/sftpgo/v2/util" ) var ( - validKMSSchemes = []string{kms.SchemeAWS, kms.SchemeGCP, kms.SchemeVaultTransit, kms.SchemeAzureKeyVault} - validKMSEncryptedStatuses = []string{kms.SecretStatusVaultTransit, kms.SecretStatusAWS, kms.SecretStatusGCP, - kms.SecretStatusAzureKeyVault} + validKMSSchemes = []string{sdkkms.SchemeAWS, sdkkms.SchemeGCP, sdkkms.SchemeVaultTransit, sdkkms.SchemeAzureKeyVault} + validKMSEncryptedStatuses = []string{sdkkms.SecretStatusVaultTransit, sdkkms.SecretStatusAWS, sdkkms.SecretStatusGCP, + sdkkms.SecretStatusAzureKeyVault} ) // KMSConfig defines configuration parameters for kms plugins @@ -133,7 +134,7 @@ func (s *kmsPluginSecretProvider) IsEncrypted() bool { } func (s *kmsPluginSecretProvider) Encrypt() error { - if s.Status != kms.SecretStatusPlain { + if s.Status != sdkkms.SecretStatusPlain { return kms.ErrWrongSecretStatus } if s.Payload == "" { @@ -160,7 +161,7 @@ func (s *kmsPluginSecretProvider) Decrypt() error { if err != nil { return err } - s.Status = kms.SecretStatusPlain + s.Status = sdkkms.SecretStatusPlain s.Payload = payload s.Key = "" s.AdditionalData = "" diff --git a/plugin/plugin.go b/plugin/plugin.go index 29c564ad..cb17a8d7 100644 --- a/plugin/plugin.go +++ b/plugin/plugin.go @@ -11,8 +11,8 @@ import ( "github.com/hashicorp/go-hclog" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/logger" - "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/sdk/plugin/auth" "github.com/drakkan/sftpgo/v2/sdk/plugin/eventsearcher" kmsplugin "github.com/drakkan/sftpgo/v2/sdk/plugin/kms" @@ -135,7 +135,7 @@ func Initialize(configs []Config, logVerbose bool) error { kmsID++ kms.RegisterSecretProvider(config.KMSOptions.Scheme, config.KMSOptions.EncryptedStatus, Handler.Configs[idx].newKMSPluginSecretProvider) - logger.Debug(logSender, "", "registered secret provider for scheme: %v, encrypted status: %v", + logger.Info(logSender, "", "registered secret provider for scheme: %v, encrypted status: %v", config.KMSOptions.Scheme, config.KMSOptions.EncryptedStatus) case auth.PluginName: plugin, err := newAuthPlugin(config) diff --git a/sdk/filesystem.go b/sdk/filesystem.go index 6f75582e..063b5442 100644 --- a/sdk/filesystem.go +++ b/sdk/filesystem.go @@ -84,8 +84,8 @@ func ListProviders() []FilesystemProvider { } } -// S3FsConfig defines the configuration for S3 based filesystem -type S3FsConfig struct { +// BaseS3FsConfig defines the base configuration for S3 based filesystems +type BaseS3FsConfig struct { Bucket string `json:"bucket,omitempty"` // KeyPrefix is similar to a chroot directory for local filesystem. // If specified then the SFTP user will only see objects that starts @@ -93,12 +93,11 @@ type S3FsConfig struct { // folder. The prefix, if not empty, must not start with "/" and must // end with "/". // If empty the whole bucket contents will be available - KeyPrefix string `json:"key_prefix,omitempty"` - Region string `json:"region,omitempty"` - AccessKey string `json:"access_key,omitempty"` - AccessSecret *kms.Secret `json:"access_secret,omitempty"` - Endpoint string `json:"endpoint,omitempty"` - StorageClass string `json:"storage_class,omitempty"` + KeyPrefix string `json:"key_prefix,omitempty"` + Region string `json:"region,omitempty"` + AccessKey string `json:"access_key,omitempty"` + Endpoint string `json:"endpoint,omitempty"` + StorageClass string `json:"storage_class,omitempty"` // The canned ACL to apply to uploaded objects. Leave empty to use the default ACL. // For more information and available ACLs, see here: // https://docs.aws.amazon.com/AmazonS3/latest/userguide/acl-overview.html#canned-acl @@ -129,8 +128,14 @@ type S3FsConfig struct { ForcePathStyle bool `json:"force_path_style,omitempty"` } -// GCSFsConfig defines the configuration for Google Cloud Storage based filesystem -type GCSFsConfig struct { +// S3FsConfig defines the base configuration for S3 based filesystems +type S3FsConfig struct { + BaseS3FsConfig + AccessSecret kms.BaseSecret `json:"access_secret,omitempty"` +} + +// BaseGCSFsConfig defines the base configuration for Google Cloud Storage based filesystems +type BaseGCSFsConfig struct { Bucket string `json:"bucket,omitempty"` // KeyPrefix is similar to a chroot directory for local filesystem. // If specified then the SFTP user will only see objects that starts @@ -138,9 +143,8 @@ type GCSFsConfig struct { // folder. The prefix, if not empty, must not start with "/" and must // end with "/". // If empty the whole bucket contents will be available - KeyPrefix string `json:"key_prefix,omitempty"` - CredentialFile string `json:"-"` - Credentials *kms.Secret `json:"credentials,omitempty"` + KeyPrefix string `json:"key_prefix,omitempty"` + CredentialFile string `json:"-"` // 0 explicit, 1 automatic AutomaticCredentials int `json:"automatic_credentials,omitempty"` StorageClass string `json:"storage_class,omitempty"` @@ -150,20 +154,21 @@ type GCSFsConfig struct { ACL string `json:"acl,omitempty"` } -// AzBlobFsConfig defines the configuration for Azure Blob Storage based filesystem -type AzBlobFsConfig struct { +// GCSFsConfig defines the configuration for Google Cloud Storage based filesystems +type GCSFsConfig struct { + BaseGCSFsConfig + Credentials kms.BaseSecret `json:"credentials,omitempty"` +} + +// BaseAzBlobFsConfig defines the base configuration for Azure Blob Storage based filesystem +type BaseAzBlobFsConfig struct { Container string `json:"container,omitempty"` // Storage Account Name, leave blank to use SAS URL AccountName string `json:"account_name,omitempty"` - // Storage Account Key leave blank to use SAS URL. - // The access key is stored encrypted based on the kms configuration - AccountKey *kms.Secret `json:"account_key,omitempty"` // Optional endpoint. Default is "blob.core.windows.net". // If you use the emulator the endpoint must include the protocol, // for example "http://127.0.0.1:10000" Endpoint string `json:"endpoint,omitempty"` - // Shared access signature URL, leave blank if using account/key - SASURL *kms.Secret `json:"sas_url,omitempty"` // KeyPrefix is similar to a chroot directory for local filesystem. // If specified then the SFTPGo user will only see objects that starts // with this prefix and so you can restrict access to a specific @@ -187,18 +192,26 @@ type AzBlobFsConfig struct { AccessTier string `json:"access_tier,omitempty"` } -// CryptFsConfig defines the configuration to store local files as encrypted -type CryptFsConfig struct { - Passphrase *kms.Secret `json:"passphrase,omitempty"` +// AzBlobFsConfig defines the configuration for Azure Blob Storage based filesystem +type AzBlobFsConfig struct { + BaseAzBlobFsConfig + // Storage Account Key leave blank to use SAS URL. + // The access key is stored encrypted based on the kms configuration + AccountKey kms.BaseSecret `json:"account_key,omitempty"` + // Shared access signature URL, leave blank if using account/key + SASURL kms.BaseSecret `json:"sas_url,omitempty"` } -// SFTPFsConfig defines the configuration for SFTP based filesystem -type SFTPFsConfig struct { - Endpoint string `json:"endpoint,omitempty"` - Username string `json:"username,omitempty"` - Password *kms.Secret `json:"password,omitempty"` - PrivateKey *kms.Secret `json:"private_key,omitempty"` - Fingerprints []string `json:"fingerprints,omitempty"` +// CryptFsConfig defines the configuration to store local files as encrypted +type CryptFsConfig struct { + Passphrase kms.BaseSecret `json:"passphrase,omitempty"` +} + +// BaseSFTPFsConfig defines the base configuration for SFTP based filesystem +type BaseSFTPFsConfig struct { + Endpoint string `json:"endpoint,omitempty"` + Username string `json:"username,omitempty"` + Fingerprints []string `json:"fingerprints,omitempty"` // Prefix is the path prefix to strip from SFTP resource paths. Prefix string `json:"prefix,omitempty"` // Concurrent reads are safe to use and disabling them will degrade performance. @@ -213,6 +226,13 @@ type SFTPFsConfig struct { BufferSize int64 `json:"buffer_size,omitempty"` } +// SFTPFsConfig defines the configuration for SFTP based filesystem +type SFTPFsConfig struct { + BaseSFTPFsConfig + Password kms.BaseSecret `json:"password,omitempty"` + PrivateKey kms.BaseSecret `json:"private_key,omitempty"` +} + // Filesystem defines filesystem details type Filesystem struct { Provider FilesystemProvider `json:"provider"` diff --git a/sdk/kms/kms.go b/sdk/kms/kms.go index 8d4446e4..4618c106 100644 --- a/sdk/kms/kms.go +++ b/sdk/kms/kms.go @@ -1,37 +1,6 @@ // Package kms provides Key Management Services support package kms -import ( - "encoding/json" - "errors" - "os" - "strings" - "sync" - - "github.com/drakkan/sftpgo/v2/sdk/logger" -) - -// SecretProvider defines the interface for a KMS secrets provider -type SecretProvider interface { - Name() string - Encrypt() error - Decrypt() error - IsEncrypted() bool - GetStatus() SecretStatus - GetPayload() string - GetKey() string - GetAdditionalData() string - GetMode() int - SetKey(string) - SetAdditionalData(string) - SetStatus(SecretStatus) - Clone() SecretProvider -} - -const ( - logSender = "kms" -) - // SecretStatus defines the statuses of a Secret object type SecretStatus = string @@ -70,384 +39,12 @@ const ( SchemeAzureKeyVault Scheme = "azurekeyvault" ) -// Configuration defines the KMS configuration -type Configuration struct { - Secrets Secrets `json:"secrets" mapstructure:"secrets"` -} - -// Secrets define the KMS configuration for encryption/decryption -type Secrets struct { - URL string `json:"url" mapstructure:"url"` - MasterKeyPath string `json:"master_key_path" mapstructure:"master_key_path"` - MasterKeyString string `json:"master_key" mapstructure:"master_key"` - masterKey string -} - -type registeredSecretProvider struct { - encryptedStatus SecretStatus - newFn func(base BaseSecret, url, masterKey string) SecretProvider -} - -var ( - // ErrWrongSecretStatus defines the error to return if the secret status is not appropriate - // for the request operation - ErrWrongSecretStatus = errors.New("wrong secret status") - // ErrInvalidSecret defines the error to return if a secret is not valid - ErrInvalidSecret = errors.New("invalid secret") - validSecretStatuses = []string{SecretStatusPlain, SecretStatusAES256GCM, SecretStatusSecretBox, - SecretStatusVaultTransit, SecretStatusAWS, SecretStatusGCP, SecretStatusRedacted} - config Configuration - secretProviders = make(map[string]registeredSecretProvider) -) - -// RegisterSecretProvider register a new secret provider -func RegisterSecretProvider(scheme string, encryptedStatus SecretStatus, fn func(base BaseSecret, url, masterKey string) SecretProvider) { - secretProviders[scheme] = registeredSecretProvider{ - encryptedStatus: encryptedStatus, - newFn: fn, - } -} - -// NewSecret builds a new Secret using the provided arguments -func NewSecret(status SecretStatus, payload, key, data string) *Secret { - return config.newSecret(status, payload, key, data) -} - -// NewEmptySecret returns an empty secret -func NewEmptySecret() *Secret { - return NewSecret("", "", "", "") -} - -// NewPlainSecret stores the give payload in a plain text secret -func NewPlainSecret(payload string) *Secret { - return NewSecret(SecretStatusPlain, payload, "", "") -} - -// Initialize configures the KMS support -func (c *Configuration) Initialize() error { - if c.Secrets.MasterKeyString != "" { - c.Secrets.masterKey = c.Secrets.MasterKeyString - } - if c.Secrets.masterKey == "" && c.Secrets.MasterKeyPath != "" { - mKey, err := os.ReadFile(c.Secrets.MasterKeyPath) - if err != nil { - return err - } - c.Secrets.masterKey = strings.TrimSpace(string(mKey)) - } - config = *c - if config.Secrets.URL == "" { - config.Secrets.URL = SchemeLocal + "://" - } - for k, v := range secretProviders { - logger.Info(logSender, "secret provider registered for scheme: %#v, encrypted status: %#v", - k, v.encryptedStatus) - } - return nil -} - -func (c *Configuration) newSecret(status SecretStatus, payload, key, data string) *Secret { - base := BaseSecret{ - Status: status, - Key: key, - Payload: payload, - AdditionalData: data, - } - return &Secret{ - provider: c.getSecretProvider(base), - } -} - -func (c *Configuration) getSecretProvider(base BaseSecret) SecretProvider { - for k, v := range secretProviders { - if strings.HasPrefix(c.Secrets.URL, k) { - return v.newFn(base, c.Secrets.URL, c.Secrets.masterKey) - } - } - // we assume that SchemeLocal is always registered - logger.Warn(logSender, "no secret provider registered for URL %v, fallback to local provider", c.Secrets.URL) - return NewLocalSecret(base, c.Secrets.URL, c.Secrets.masterKey) -} - -// Secret defines the struct used to store confidential data -type Secret struct { - sync.RWMutex - provider SecretProvider -} - -// MarshalJSON return the JSON encoding of the Secret object -func (s *Secret) MarshalJSON() ([]byte, error) { - s.RLock() - defer s.RUnlock() - - return json.Marshal(&BaseSecret{ - Status: s.provider.GetStatus(), - Payload: s.provider.GetPayload(), - Key: s.provider.GetKey(), - AdditionalData: s.provider.GetAdditionalData(), - Mode: s.provider.GetMode(), - }) -} - -// UnmarshalJSON parses the JSON-encoded data and stores the result -// in the Secret object -func (s *Secret) UnmarshalJSON(data []byte) error { - s.Lock() - defer s.Unlock() - - baseSecret := BaseSecret{} - err := json.Unmarshal(data, &baseSecret) - if err != nil { - return err - } - if baseSecret.isEmpty() { - s.provider = config.getSecretProvider(baseSecret) - return nil - } - - if baseSecret.Status == SecretStatusPlain || baseSecret.Status == SecretStatusRedacted { - s.provider = config.getSecretProvider(baseSecret) - return nil - } - - for _, v := range secretProviders { - if v.encryptedStatus == baseSecret.Status { - s.provider = v.newFn(baseSecret, config.Secrets.URL, config.Secrets.masterKey) - return nil - } - } - logger.Error(logSender, "no provider registered for status %#v", baseSecret.Status) - return ErrInvalidSecret -} - -// IsEqual returns true if all the secrets fields are equal -func (s *Secret) IsEqual(other *Secret) bool { - if s.GetStatus() != other.GetStatus() { - return false - } - if s.GetPayload() != other.GetPayload() { - return false - } - if s.GetKey() != other.GetKey() { - return false - } - if s.GetAdditionalData() != other.GetAdditionalData() { - return false - } - if s.GetMode() != other.GetMode() { - return false - } - return true -} - -// Clone returns a copy of the secret object -func (s *Secret) Clone() *Secret { - s.RLock() - defer s.RUnlock() - - return &Secret{ - provider: s.provider.Clone(), - } -} - -// IsEncrypted returns true if the secret is encrypted -// This isn't a pointer receiver because we don't want to pass -// a pointer to html template -func (s *Secret) IsEncrypted() bool { - s.RLock() - defer s.RUnlock() - - return s.provider.IsEncrypted() -} - -// IsPlain returns true if the secret is in plain text -func (s *Secret) IsPlain() bool { - s.RLock() - defer s.RUnlock() - - return s.provider.GetStatus() == SecretStatusPlain -} - -// IsNotPlainAndNotEmpty returns true if the secret is not plain and not empty. -// This is an utility method, we update the secret for an existing user -// if it is empty or plain -func (s *Secret) IsNotPlainAndNotEmpty() bool { - s.RLock() - defer s.RUnlock() - - return !s.IsPlain() && !s.IsEmpty() -} - -// IsRedacted returns true if the secret is redacted -func (s *Secret) IsRedacted() bool { - s.RLock() - defer s.RUnlock() - - return s.provider.GetStatus() == SecretStatusRedacted -} - -// GetPayload returns the secret payload -func (s *Secret) GetPayload() string { - s.RLock() - defer s.RUnlock() - - return s.provider.GetPayload() -} - -// GetAdditionalData returns the secret additional data -func (s *Secret) GetAdditionalData() string { - s.RLock() - defer s.RUnlock() - - return s.provider.GetAdditionalData() -} - -// GetStatus returns the secret status -func (s *Secret) GetStatus() SecretStatus { - s.RLock() - defer s.RUnlock() - - return s.provider.GetStatus() -} - -// GetKey returns the secret key -func (s *Secret) GetKey() string { - s.RLock() - defer s.RUnlock() - - return s.provider.GetKey() -} - -// GetMode returns the secret mode -func (s *Secret) GetMode() int { - s.RLock() - defer s.RUnlock() - - return s.provider.GetMode() -} - -// SetAdditionalData sets the given additional data -func (s *Secret) SetAdditionalData(value string) { - s.Lock() - defer s.Unlock() - - s.provider.SetAdditionalData(value) -} - -// SetStatus sets the status for this secret -func (s *Secret) SetStatus(value SecretStatus) { - s.Lock() - defer s.Unlock() - - s.provider.SetStatus(value) -} - -// SetKey sets the key for this secret -func (s *Secret) SetKey(value string) { - s.Lock() - defer s.Unlock() - - s.provider.SetKey(value) -} - -// IsEmpty returns true if all fields are empty -func (s *Secret) IsEmpty() bool { - s.RLock() - defer s.RUnlock() - - if s.provider.GetStatus() != "" { - return false - } - if s.provider.GetPayload() != "" { - return false - } - if s.provider.GetKey() != "" { - return false - } - if s.provider.GetAdditionalData() != "" { - return false - } - return true -} - -// IsValid returns true if the secret is not empty and valid -func (s *Secret) IsValid() bool { - s.RLock() - defer s.RUnlock() - - if !s.IsValidInput() { - return false - } - switch s.provider.GetStatus() { - case SecretStatusAES256GCM, SecretStatusSecretBox: - if len(s.provider.GetKey()) != 64 { - return false - } - case SecretStatusAWS, SecretStatusGCP, SecretStatusVaultTransit: - key := s.provider.GetKey() - if key != "" && len(key) != 64 { - return false - } - } - return true -} - -// IsValidInput returns true if the secret is a valid user input -func (s *Secret) IsValidInput() bool { - s.RLock() - defer s.RUnlock() - - if !isSecretStatusValid(s.provider.GetStatus()) { - return false - } - if s.provider.GetPayload() == "" { - return false - } - return true -} - -// Hide hides info to decrypt data -func (s *Secret) Hide() { - s.Lock() - defer s.Unlock() - - s.provider.SetKey("") - s.provider.SetAdditionalData("") -} - -// Encrypt encrypts a plain text Secret object -func (s *Secret) Encrypt() error { - s.Lock() - defer s.Unlock() - - return s.provider.Encrypt() -} - -// Decrypt decrypts a Secret object -func (s *Secret) Decrypt() error { - s.Lock() - defer s.Unlock() - - return s.provider.Decrypt() -} - -// TryDecrypt decrypts a Secret object if encrypted. -// It returns a nil error if the object is not encrypted -func (s *Secret) TryDecrypt() error { - s.Lock() - defer s.Unlock() - - if s.provider.IsEncrypted() { - return s.provider.Decrypt() - } - return nil -} - -func isSecretStatusValid(status string) bool { - for idx := range validSecretStatuses { - if validSecretStatuses[idx] == status { - return true - } - } - return false +// BaseSecret defines the base struct shared among all the secret providers +type BaseSecret struct { + Status SecretStatus `json:"status,omitempty"` + Payload string `json:"payload,omitempty"` + Key string `json:"key,omitempty"` + AdditionalData string `json:"additional_data,omitempty"` + // 1 means encrypted using a master key + Mode int `json:"mode,omitempty"` } diff --git a/sdk/logger/logger.go b/sdk/logger/logger.go deleted file mode 100644 index 883cb5f0..00000000 --- a/sdk/logger/logger.go +++ /dev/null @@ -1,57 +0,0 @@ -// Package logger provides logging capabilities. -package logger - -const ( - levelDebug = iota - levelInfo - levelWarn - levelError -) - -var ( - logger Logger -) - -func init() { - DisableLogger() -} - -// Logger interface -type Logger interface { - // Log logs at the specified level for the specified sender - Log(level int, sender, format string, v ...interface{}) -} - -// SetLogger sets the specified logger -func SetLogger(l Logger) { - logger = l -} - -// DisableLogger disables logging -func DisableLogger() { - logger = &noLogger{} -} - -type noLogger struct{} - -func (*noLogger) Log(level int, sender, format string, v ...interface{}) {} - -// Debug logs at debug level for the specified sender -func Debug(sender, format string, v ...interface{}) { - logger.Log(levelDebug, sender, format, v...) -} - -// Info logs at info level for the specified sender -func Info(sender, format string, v ...interface{}) { - logger.Log(levelInfo, sender, format, v...) -} - -// Warn logs at warn level for the specified sender -func Warn(sender, format string, v ...interface{}) { - logger.Log(levelWarn, sender, format, v...) -} - -// Error logs at error level for the specified sender -func Error(sender, format string, v ...interface{}) { - logger.Log(levelError, sender, format, v...) -} diff --git a/sdk/user.go b/sdk/user.go index 12f31abc..879bc360 100644 --- a/sdk/user.go +++ b/sdk/user.go @@ -100,15 +100,15 @@ type HooksFilter struct { // RecoveryCode defines a 2FA recovery code type RecoveryCode struct { - Secret *kms.Secret `json:"secret"` - Used bool `json:"used,omitempty"` + Secret kms.BaseSecret `json:"secret"` + Used bool `json:"used,omitempty"` } // TOTPConfig defines the time-based one time password configuration type TOTPConfig struct { - Enabled bool `json:"enabled,omitempty"` - ConfigName string `json:"config_name,omitempty"` - Secret *kms.Secret `json:"secret,omitempty"` + Enabled bool `json:"enabled,omitempty"` + ConfigName string `json:"config_name,omitempty"` + Secret kms.BaseSecret `json:"secret,omitempty"` // TOTP will be required for the specified protocols. // SSH protocol (SFTP/SCP/SSH commands) will ask for the TOTP passcode if the client uses keyboard interactive // authentication. @@ -136,9 +136,8 @@ func (l *BandwidthLimit) GetSourcesAsString() string { return strings.Join(l.Sources, ",") } -// UserFilters defines additional restrictions for a user -// TODO: rename to UserOptions in v3 -type UserFilters struct { +// BaseUserFilters defines additional restrictions for a user +type BaseUserFilters struct { // only clients connecting from these IP/Mask are allowed. // IP/Mask must be in CIDR notation as defined in RFC 4632 and RFC 4291 // for example "192.0.2.0/24" or "2001:db8::/32" @@ -175,17 +174,23 @@ type UserFilters struct { WebClient []string `json:"web_client,omitempty"` // API key auth allows to impersonate this user with an API key AllowAPIKeyAuth bool `json:"allow_api_key_auth,omitempty"` + // UserType is an hint for authentication plugins. + // It is ignored when using SFTPGo internal authentication + UserType string `json:"user_type,omitempty"` + // Per-source bandwidth limits + BandwidthLimits []BandwidthLimit `json:"bandwidth_limits,omitempty"` +} + +// UserFilters defines additional restrictions for a user +// TODO: rename to UserOptions in v3 +type UserFilters struct { + BaseUserFilters // Time-based one time passwords configuration TOTPConfig TOTPConfig `json:"totp_config,omitempty"` // Recovery codes to use if the user loses access to their second factor auth device. // Each code can only be used once, you should use these codes to login and disable or // reset 2FA for your account RecoveryCodes []RecoveryCode `json:"recovery_codes,omitempty"` - // UserType is an hint for authentication plugins. - // It is ignored when using SFTPGo internal authentication - UserType string `json:"user_type,omitempty"` - // Per-source bandwidth limits - BandwidthLimits []BandwidthLimit `json:"bandwidth_limits,omitempty"` } // BaseUser defines the shared user fields @@ -239,8 +244,6 @@ type BaseUser struct { CreatedAt int64 `json:"created_at"` // last update time as unix timestamp in milliseconds UpdatedAt int64 `json:"updated_at"` - // Additional restrictions - Filters UserFilters `json:"filters"` // optional description, for example full name Description string `json:"description,omitempty"` // free form text field for external systems @@ -250,6 +253,8 @@ type BaseUser struct { // User defines a SFTPGo user type User struct { BaseUser + // Additional restrictions + Filters UserFilters `json:"filters"` // Mapping between virtual paths and virtual folders VirtualFolders []VirtualFolder `json:"virtual_folders,omitempty"` // Filesystem configuration details diff --git a/service/service_portable.go b/service/service_portable.go index 8e801458..326d1bc0 100644 --- a/service/service_portable.go +++ b/service/service_portable.go @@ -17,9 +17,9 @@ import ( "github.com/drakkan/sftpgo/v2/config" "github.com/drakkan/sftpgo/v2/dataprovider" "github.com/drakkan/sftpgo/v2/ftpd" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/logger" "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/sftpd" "github.com/drakkan/sftpgo/v2/util" "github.com/drakkan/sftpgo/v2/version" diff --git a/sftpd/cryptfs_test.go b/sftpd/cryptfs_test.go index aefaaf9b..6d8f2c84 100644 --- a/sftpd/cryptfs_test.go +++ b/sftpd/cryptfs_test.go @@ -15,8 +15,8 @@ import ( "github.com/drakkan/sftpgo/v2/dataprovider" "github.com/drakkan/sftpgo/v2/httpdtest" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/vfs" ) diff --git a/sftpd/internal_test.go b/sftpd/internal_test.go index 6d5b57c7..4933fe34 100644 --- a/sftpd/internal_test.go +++ b/sftpd/internal_test.go @@ -20,8 +20,8 @@ import ( "github.com/drakkan/sftpgo/v2/common" "github.com/drakkan/sftpgo/v2/dataprovider" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/util" "github.com/drakkan/sftpgo/v2/vfs" ) @@ -667,7 +667,7 @@ func TestSSHCommandsRemoteFs(t *testing.T) { user.FsConfig = vfs.Filesystem{ Provider: sdk.S3FilesystemProvider, S3Config: vfs.S3FsConfig{ - S3FsConfig: sdk.S3FsConfig{ + BaseS3FsConfig: sdk.BaseS3FsConfig{ Bucket: "s3bucket", Endpoint: "endpoint", Region: "eu-west-1", @@ -1753,9 +1753,7 @@ func TestTransferFailingReader(t *testing.T) { FsConfig: vfs.Filesystem{ Provider: sdk.CryptedFilesystemProvider, CryptConfig: vfs.CryptFsConfig{ - CryptFsConfig: sdk.CryptFsConfig{ - Passphrase: kms.NewPlainSecret("crypt secret"), - }, + Passphrase: kms.NewPlainSecret("crypt secret"), }, }, } diff --git a/sftpd/sftpd_test.go b/sftpd/sftpd_test.go index 959fa822..0f134db9 100644 --- a/sftpd/sftpd_test.go +++ b/sftpd/sftpd_test.go @@ -42,10 +42,11 @@ import ( "github.com/drakkan/sftpgo/v2/config" "github.com/drakkan/sftpgo/v2/dataprovider" "github.com/drakkan/sftpgo/v2/httpdtest" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/logger" "github.com/drakkan/sftpgo/v2/mfa" "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" + sdkkms "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/sftpd" "github.com/drakkan/sftpgo/v2/util" "github.com/drakkan/sftpgo/v2/vfs" @@ -1999,7 +2000,7 @@ func TestLoginWithDatabaseCredentials(t *testing.T) { user, _, err := httpdtest.AddUser(u, http.StatusCreated) assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.GCSConfig.Credentials.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.GCSConfig.Credentials.GetStatus()) assert.NotEmpty(t, user.FsConfig.GCSConfig.Credentials.GetPayload()) assert.Empty(t, user.FsConfig.GCSConfig.Credentials.GetAdditionalData()) assert.Empty(t, user.FsConfig.GCSConfig.Credentials.GetKey()) @@ -2283,7 +2284,7 @@ func TestInteractiveLoginWithPasscode(t *testing.T) { configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], user.Username) assert.NoError(t, err) user.Password = defaultPassword - user.Filters.TOTPConfig = sdk.TOTPConfig{ + user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{ Enabled: true, ConfigName: configName, Secret: kms.NewPlainSecret(secret), @@ -2332,7 +2333,7 @@ func TestInteractiveLoginWithPasscode(t *testing.T) { configName, _, secret, _, err = mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], user.Username) assert.NoError(t, err) user.Password = defaultPassword - user.Filters.TOTPConfig = sdk.TOTPConfig{ + user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{ Enabled: true, ConfigName: configName, Secret: kms.NewPlainSecret(secret), @@ -2521,14 +2522,14 @@ func TestPreLoginHookPreserveMFAConfig(t *testing.T) { configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], user.Username) assert.NoError(t, err) user.Password = defaultPassword - user.Filters.TOTPConfig = sdk.TOTPConfig{ + user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{ Enabled: true, ConfigName: configName, Secret: kms.NewPlainSecret(secret), Protocols: []string{common.ProtocolSSH}, } for i := 0; i < 12; i++ { - user.Filters.RecoveryCodes = append(user.Filters.RecoveryCodes, sdk.RecoveryCode{ + user.Filters.RecoveryCodes = append(user.Filters.RecoveryCodes, dataprovider.RecoveryCode{ Secret: kms.NewPlainSecret(fmt.Sprintf("RC-%v", strings.ToUpper(util.GenerateUniqueID()))), }) } @@ -2548,7 +2549,7 @@ func TestPreLoginHookPreserveMFAConfig(t *testing.T) { assert.True(t, user.Filters.TOTPConfig.Enabled) assert.Equal(t, configName, user.Filters.TOTPConfig.ConfigName) assert.Equal(t, []string{common.ProtocolSSH}, user.Filters.TOTPConfig.Protocols) - assert.Equal(t, kms.SecretStatusSecretBox, user.Filters.TOTPConfig.Secret.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.Filters.TOTPConfig.Secret.GetStatus()) err = os.WriteFile(extAuthPath, getExitCodeScriptContent(0), os.ModePerm) assert.NoError(t, err) @@ -2566,7 +2567,7 @@ func TestPreLoginHookPreserveMFAConfig(t *testing.T) { assert.True(t, user.Filters.TOTPConfig.Enabled) assert.Equal(t, configName, user.Filters.TOTPConfig.ConfigName) assert.Equal(t, []string{common.ProtocolSSH}, user.Filters.TOTPConfig.Protocols) - assert.Equal(t, kms.SecretStatusSecretBox, user.Filters.TOTPConfig.Secret.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.Filters.TOTPConfig.Secret.GetStatus()) _, err = httpdtest.RemoveUser(user, http.StatusOK) assert.NoError(t, err) @@ -3463,14 +3464,14 @@ func TestExternalAuthPreserveMFAConfig(t *testing.T) { configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], user.Username) assert.NoError(t, err) user.Password = defaultPassword - user.Filters.TOTPConfig = sdk.TOTPConfig{ + user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{ Enabled: true, ConfigName: configName, Secret: kms.NewPlainSecret(secret), Protocols: []string{common.ProtocolSSH}, } for i := 0; i < 12; i++ { - user.Filters.RecoveryCodes = append(user.Filters.RecoveryCodes, sdk.RecoveryCode{ + user.Filters.RecoveryCodes = append(user.Filters.RecoveryCodes, dataprovider.RecoveryCode{ Secret: kms.NewPlainSecret(fmt.Sprintf("RC-%v", strings.ToUpper(util.GenerateUniqueID()))), }) } @@ -3490,7 +3491,7 @@ func TestExternalAuthPreserveMFAConfig(t *testing.T) { assert.True(t, user.Filters.TOTPConfig.Enabled) assert.Equal(t, configName, user.Filters.TOTPConfig.ConfigName) assert.Equal(t, []string{common.ProtocolSSH}, user.Filters.TOTPConfig.Protocols) - assert.Equal(t, kms.SecretStatusSecretBox, user.Filters.TOTPConfig.Secret.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.Filters.TOTPConfig.Secret.GetStatus()) err = os.WriteFile(extAuthPath, getExtAuthScriptContent(u, false, true, ""), os.ModePerm) assert.NoError(t, err) @@ -3508,7 +3509,7 @@ func TestExternalAuthPreserveMFAConfig(t *testing.T) { assert.True(t, user.Filters.TOTPConfig.Enabled) assert.Equal(t, configName, user.Filters.TOTPConfig.ConfigName) assert.Equal(t, []string{common.ProtocolSSH}, user.Filters.TOTPConfig.Protocols) - assert.Equal(t, kms.SecretStatusSecretBox, user.Filters.TOTPConfig.Secret.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.Filters.TOTPConfig.Secret.GetStatus()) _, err = httpdtest.RemoveUser(user, http.StatusOK) assert.NoError(t, err) @@ -4428,18 +4429,18 @@ func TestSFTPLoopSimple(t *testing.T) { user1.FsConfig.Provider = sdk.SFTPFilesystemProvider user2.FsConfig.Provider = sdk.SFTPFilesystemProvider user1.FsConfig.SFTPConfig = vfs.SFTPFsConfig{ - SFTPFsConfig: sdk.SFTPFsConfig{ + BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{ Endpoint: sftpServerAddr, Username: user2.Username, - Password: kms.NewPlainSecret(defaultPassword), }, + Password: kms.NewPlainSecret(defaultPassword), } user2.FsConfig.SFTPConfig = vfs.SFTPFsConfig{ - SFTPFsConfig: sdk.SFTPFsConfig{ + BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{ Endpoint: sftpServerAddr, Username: user1.Username, - Password: kms.NewPlainSecret(defaultPassword), }, + Password: kms.NewPlainSecret(defaultPassword), } user1, resp, err := httpdtest.AddUser(user1, http.StatusCreated) assert.NoError(t, err, string(resp)) @@ -4487,11 +4488,11 @@ func TestSFTPLoopVirtualFolders(t *testing.T) { FsConfig: vfs.Filesystem{ Provider: sdk.SFTPFilesystemProvider, SFTPConfig: vfs.SFTPFsConfig{ - SFTPFsConfig: sdk.SFTPFsConfig{ + BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{ Endpoint: sftpServerAddr, Username: user2.Username, - Password: kms.NewPlainSecret(defaultPassword), }, + Password: kms.NewPlainSecret(defaultPassword), }, }, }, @@ -4500,19 +4501,19 @@ func TestSFTPLoopVirtualFolders(t *testing.T) { user2.FsConfig.Provider = sdk.SFTPFilesystemProvider user2.FsConfig.SFTPConfig = vfs.SFTPFsConfig{ - SFTPFsConfig: sdk.SFTPFsConfig{ + BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{ Endpoint: sftpServerAddr, Username: user1.Username, - Password: kms.NewPlainSecret(defaultPassword), }, + Password: kms.NewPlainSecret(defaultPassword), } user3.FsConfig.Provider = sdk.SFTPFilesystemProvider user3.FsConfig.SFTPConfig = vfs.SFTPFsConfig{ - SFTPFsConfig: sdk.SFTPFsConfig{ + BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{ Endpoint: sftpServerAddr, Username: user1.Username, - Password: kms.NewPlainSecret(defaultPassword), }, + Password: kms.NewPlainSecret(defaultPassword), } user1, resp, err := httpdtest.AddUser(user1, http.StatusCreated) @@ -4546,11 +4547,11 @@ func TestSFTPLoopVirtualFolders(t *testing.T) { FsConfig: vfs.Filesystem{ Provider: sdk.SFTPFilesystemProvider, SFTPConfig: vfs.SFTPFsConfig{ - SFTPFsConfig: sdk.SFTPFsConfig{ + BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{ Endpoint: sftpServerAddr, Username: user3.Username, - Password: kms.NewPlainSecret(defaultPassword), }, + Password: kms.NewPlainSecret(defaultPassword), }, }, }, @@ -4602,9 +4603,7 @@ func TestNestedVirtualFolders(t *testing.T) { FsConfig: vfs.Filesystem{ Provider: sdk.CryptedFilesystemProvider, CryptConfig: vfs.CryptFsConfig{ - CryptFsConfig: sdk.CryptFsConfig{ - Passphrase: kms.NewPlainSecret(defaultPassword), - }, + Passphrase: kms.NewPlainSecret(defaultPassword), }, }, MappedPath: mappedPathCrypt, @@ -7222,24 +7221,24 @@ func TestRelativePaths(t *testing.T) { filesystems := []vfs.Fs{vfs.NewOsFs("", user.GetHomeDir(), "")} keyPrefix := strings.TrimPrefix(user.GetHomeDir(), "/") + "/" s3config := vfs.S3FsConfig{ - S3FsConfig: sdk.S3FsConfig{ + BaseS3FsConfig: sdk.BaseS3FsConfig{ KeyPrefix: keyPrefix, }, } s3fs, _ := vfs.NewS3Fs("", user.GetHomeDir(), "", s3config) gcsConfig := vfs.GCSFsConfig{ - GCSFsConfig: sdk.GCSFsConfig{ + BaseGCSFsConfig: sdk.BaseGCSFsConfig{ KeyPrefix: keyPrefix, }, } gcsfs, _ := vfs.NewGCSFs("", user.GetHomeDir(), "", gcsConfig) sftpconfig := vfs.SFTPFsConfig{ - SFTPFsConfig: sdk.SFTPFsConfig{ + BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{ Endpoint: sftpServerAddr, Username: defaultUsername, - Password: kms.NewPlainSecret(defaultPassword), Prefix: keyPrefix, }, + Password: kms.NewPlainSecret(defaultPassword), } sftpfs, _ := vfs.NewSFTPFs("", "", os.TempDir(), []string{user.Username}, sftpconfig) if runtime.GOOS != osWindows { @@ -7287,7 +7286,7 @@ func TestResolvePaths(t *testing.T) { filesystems := []vfs.Fs{vfs.NewOsFs("", user.GetHomeDir(), "")} keyPrefix := strings.TrimPrefix(user.GetHomeDir(), "/") + "/" s3config := vfs.S3FsConfig{ - S3FsConfig: sdk.S3FsConfig{ + BaseS3FsConfig: sdk.BaseS3FsConfig{ KeyPrefix: keyPrefix, Bucket: "bucket", Region: "us-east-1", @@ -7298,7 +7297,7 @@ func TestResolvePaths(t *testing.T) { s3fs, err := vfs.NewS3Fs("", user.GetHomeDir(), "", s3config) assert.NoError(t, err) gcsConfig := vfs.GCSFsConfig{ - GCSFsConfig: sdk.GCSFsConfig{ + BaseGCSFsConfig: sdk.BaseGCSFsConfig{ KeyPrefix: keyPrefix, }, } @@ -7401,8 +7400,10 @@ func TestFilterFilePatterns(t *testing.T) { AllowedPatterns: []string{"*.jpg", "*.png"}, DeniedPatterns: []string{"*.pdf"}, } - filters := sdk.UserFilters{ - FilePatterns: []sdk.PatternsFilter{pattern}, + filters := dataprovider.UserFilters{ + BaseUserFilters: sdk.BaseUserFilters{ + FilePatterns: []sdk.PatternsFilter{pattern}, + }, } user.Filters = filters assert.True(t, user.IsFileAllowed("/test/test.jPg")) @@ -8482,9 +8483,7 @@ func TestSSHRemoveCryptFs(t *testing.T) { FsConfig: vfs.Filesystem{ Provider: sdk.CryptedFilesystemProvider, CryptConfig: vfs.CryptFsConfig{ - CryptFsConfig: sdk.CryptFsConfig{ - Passphrase: kms.NewPlainSecret(defaultPassword), - }, + Passphrase: kms.NewPlainSecret(defaultPassword), }, }, }, @@ -9070,11 +9069,11 @@ func TestSCPNestedFolders(t *testing.T) { FsConfig: vfs.Filesystem{ Provider: sdk.SFTPFilesystemProvider, SFTPConfig: vfs.SFTPFsConfig{ - SFTPFsConfig: sdk.SFTPFsConfig{ + BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{ Endpoint: sftpServerAddr, Username: baseUser.Username, - Password: kms.NewPlainSecret(defaultPassword), }, + Password: kms.NewPlainSecret(defaultPassword), }, }, }, @@ -9089,9 +9088,7 @@ func TestSCPNestedFolders(t *testing.T) { FsConfig: vfs.Filesystem{ Provider: sdk.CryptedFilesystemProvider, CryptConfig: vfs.CryptFsConfig{ - CryptFsConfig: sdk.CryptFsConfig{ - Passphrase: kms.NewPlainSecret(defaultPassword), - }, + Passphrase: kms.NewPlainSecret(defaultPassword), }, }, MappedPath: mappedPathCrypt, diff --git a/vfs/filesystem.go b/vfs/filesystem.go index 7f15c06e..a8c7713b 100644 --- a/vfs/filesystem.go +++ b/vfs/filesystem.go @@ -3,8 +3,8 @@ package vfs import ( "fmt" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/util" ) @@ -228,11 +228,10 @@ func (f *Filesystem) GetACopy() Filesystem { fs := Filesystem{ Provider: f.Provider, S3Config: S3FsConfig{ - S3FsConfig: sdk.S3FsConfig{ + BaseS3FsConfig: sdk.BaseS3FsConfig{ Bucket: f.S3Config.Bucket, Region: f.S3Config.Region, AccessKey: f.S3Config.AccessKey, - AccessSecret: f.S3Config.AccessSecret.Clone(), Endpoint: f.S3Config.Endpoint, StorageClass: f.S3Config.StorageClass, ACL: f.S3Config.ACL, @@ -244,47 +243,46 @@ func (f *Filesystem) GetACopy() Filesystem { DownloadPartMaxTime: f.S3Config.DownloadPartMaxTime, ForcePathStyle: f.S3Config.ForcePathStyle, }, + AccessSecret: f.S3Config.AccessSecret.Clone(), }, GCSConfig: GCSFsConfig{ - GCSFsConfig: sdk.GCSFsConfig{ + BaseGCSFsConfig: sdk.BaseGCSFsConfig{ Bucket: f.GCSConfig.Bucket, CredentialFile: f.GCSConfig.CredentialFile, - Credentials: f.GCSConfig.Credentials.Clone(), AutomaticCredentials: f.GCSConfig.AutomaticCredentials, StorageClass: f.GCSConfig.StorageClass, ACL: f.GCSConfig.ACL, KeyPrefix: f.GCSConfig.KeyPrefix, }, + Credentials: f.GCSConfig.Credentials.Clone(), }, AzBlobConfig: AzBlobFsConfig{ - AzBlobFsConfig: sdk.AzBlobFsConfig{ + BaseAzBlobFsConfig: sdk.BaseAzBlobFsConfig{ Container: f.AzBlobConfig.Container, AccountName: f.AzBlobConfig.AccountName, - AccountKey: f.AzBlobConfig.AccountKey.Clone(), Endpoint: f.AzBlobConfig.Endpoint, - SASURL: f.AzBlobConfig.SASURL.Clone(), KeyPrefix: f.AzBlobConfig.KeyPrefix, UploadPartSize: f.AzBlobConfig.UploadPartSize, UploadConcurrency: f.AzBlobConfig.UploadConcurrency, UseEmulator: f.AzBlobConfig.UseEmulator, AccessTier: f.AzBlobConfig.AccessTier, }, + AccountKey: f.AzBlobConfig.AccountKey.Clone(), + SASURL: f.AzBlobConfig.SASURL.Clone(), }, CryptConfig: CryptFsConfig{ - CryptFsConfig: sdk.CryptFsConfig{ - Passphrase: f.CryptConfig.Passphrase.Clone(), - }, + Passphrase: f.CryptConfig.Passphrase.Clone(), }, SFTPConfig: SFTPFsConfig{ - SFTPFsConfig: sdk.SFTPFsConfig{ + BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{ Endpoint: f.SFTPConfig.Endpoint, Username: f.SFTPConfig.Username, - Password: f.SFTPConfig.Password.Clone(), - PrivateKey: f.SFTPConfig.PrivateKey.Clone(), Prefix: f.SFTPConfig.Prefix, DisableCouncurrentReads: f.SFTPConfig.DisableCouncurrentReads, BufferSize: f.SFTPConfig.BufferSize, }, + Password: f.SFTPConfig.Password.Clone(), + PrivateKey: f.SFTPConfig.PrivateKey.Clone(), }, } if len(f.SFTPConfig.Fingerprints) > 0 { diff --git a/vfs/gcsfs.go b/vfs/gcsfs.go index 627c3d39..12429bbb 100644 --- a/vfs/gcsfs.go +++ b/vfs/gcsfs.go @@ -23,10 +23,10 @@ import ( "google.golang.org/api/iterator" "google.golang.org/api/option" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/logger" "github.com/drakkan/sftpgo/v2/metric" "github.com/drakkan/sftpgo/v2/plugin" - "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/util" "github.com/drakkan/sftpgo/v2/version" ) diff --git a/vfs/sftpfs.go b/vfs/sftpfs.go index 692c0d98..9193e019 100644 --- a/vfs/sftpfs.go +++ b/vfs/sftpfs.go @@ -19,9 +19,9 @@ import ( "github.com/rs/xid" "golang.org/x/crypto/ssh" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/logger" "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/util" "github.com/drakkan/sftpgo/v2/version" ) @@ -36,8 +36,10 @@ var ErrSFTPLoop = errors.New("SFTP loop or nested local SFTP folders detected") // SFTPFsConfig defines the configuration for SFTP based filesystem type SFTPFsConfig struct { - sdk.SFTPFsConfig - forbiddenSelfUsernames []string `json:"-"` + sdk.BaseSFTPFsConfig + Password *kms.Secret `json:"password,omitempty"` + PrivateKey *kms.Secret `json:"private_key,omitempty"` + forbiddenSelfUsernames []string `json:"-"` } // HideConfidentialData hides confidential data diff --git a/vfs/vfs.go b/vfs/vfs.go index 6f2ec171..806bb61f 100644 --- a/vfs/vfs.go +++ b/vfs/vfs.go @@ -16,10 +16,10 @@ import ( "github.com/eikenb/pipeat" "github.com/pkg/sftp" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/logger" "github.com/drakkan/sftpgo/v2/plugin" "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/sdk/plugin/metadata" "github.com/drakkan/sftpgo/v2/util" ) @@ -150,7 +150,8 @@ func (q *QuotaCheckResult) GetRemainingFiles() int { // S3FsConfig defines the configuration for S3 based filesystem type S3FsConfig struct { - sdk.S3FsConfig + sdk.BaseS3FsConfig + AccessSecret *kms.Secret `json:"access_secret,omitempty"` } // HideConfidentialData hides confidential data @@ -287,7 +288,8 @@ func (c *S3FsConfig) Validate() error { // GCSFsConfig defines the configuration for Google Cloud Storage based filesystem type GCSFsConfig struct { - sdk.GCSFsConfig + sdk.BaseGCSFsConfig + Credentials *kms.Secret `json:"credentials,omitempty"` } // HideConfidentialData hides confidential data @@ -358,7 +360,12 @@ func (c *GCSFsConfig) Validate(credentialsFilePath string) error { // AzBlobFsConfig defines the configuration for Azure Blob Storage based filesystem type AzBlobFsConfig struct { - sdk.AzBlobFsConfig + sdk.BaseAzBlobFsConfig + // Storage Account Key leave blank to use SAS URL. + // The access key is stored encrypted based on the kms configuration + AccountKey *kms.Secret `json:"account_key,omitempty"` + // Shared access signature URL, leave blank if using account/key + SASURL *kms.Secret `json:"sas_url,omitempty"` } // HideConfidentialData hides confidential data @@ -489,7 +496,7 @@ func (c *AzBlobFsConfig) Validate() error { // CryptFsConfig defines the configuration to store local files as encrypted type CryptFsConfig struct { - sdk.CryptFsConfig + Passphrase *kms.Secret `json:"passphrase,omitempty"` } // HideConfidentialData hides confidential data diff --git a/webdavd/internal_test.go b/webdavd/internal_test.go index 2a2b099d..326cc2de 100644 --- a/webdavd/internal_test.go +++ b/webdavd/internal_test.go @@ -22,8 +22,8 @@ import ( "github.com/drakkan/sftpgo/v2/common" "github.com/drakkan/sftpgo/v2/dataprovider" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/util" "github.com/drakkan/sftpgo/v2/vfs" ) diff --git a/webdavd/webdavd_test.go b/webdavd/webdavd_test.go index e0ed2771..60ef5048 100644 --- a/webdavd/webdavd_test.go +++ b/webdavd/webdavd_test.go @@ -31,9 +31,10 @@ import ( "github.com/drakkan/sftpgo/v2/dataprovider" "github.com/drakkan/sftpgo/v2/httpclient" "github.com/drakkan/sftpgo/v2/httpdtest" + "github.com/drakkan/sftpgo/v2/kms" "github.com/drakkan/sftpgo/v2/logger" "github.com/drakkan/sftpgo/v2/sdk" - "github.com/drakkan/sftpgo/v2/sdk/kms" + sdkkms "github.com/drakkan/sftpgo/v2/sdk/kms" "github.com/drakkan/sftpgo/v2/sftpd" "github.com/drakkan/sftpgo/v2/vfs" "github.com/drakkan/sftpgo/v2/webdavd" @@ -1621,7 +1622,7 @@ func TestLoginWithDatabaseCredentials(t *testing.T) { user, _, err := httpdtest.AddUser(u, http.StatusCreated) assert.NoError(t, err) - assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.GCSConfig.Credentials.GetStatus()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.GCSConfig.Credentials.GetStatus()) assert.NotEmpty(t, user.FsConfig.GCSConfig.Credentials.GetPayload()) assert.Empty(t, user.FsConfig.GCSConfig.Credentials.GetAdditionalData()) assert.Empty(t, user.FsConfig.GCSConfig.Credentials.GetKey()) @@ -2443,11 +2444,11 @@ func TestSFTPLoopVirtualFolders(t *testing.T) { FsConfig: vfs.Filesystem{ Provider: sdk.SFTPFilesystemProvider, SFTPConfig: vfs.SFTPFsConfig{ - SFTPFsConfig: sdk.SFTPFsConfig{ + BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{ Endpoint: sftpServerAddr, Username: user2.Username, - Password: kms.NewPlainSecret(defaultPassword), }, + Password: kms.NewPlainSecret(defaultPassword), }, }, }, @@ -2455,11 +2456,11 @@ func TestSFTPLoopVirtualFolders(t *testing.T) { }) user2.FsConfig.Provider = sdk.SFTPFilesystemProvider user2.FsConfig.SFTPConfig = vfs.SFTPFsConfig{ - SFTPFsConfig: sdk.SFTPFsConfig{ + BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{ Endpoint: sftpServerAddr, Username: user1.Username, - Password: kms.NewPlainSecret(defaultPassword), }, + Password: kms.NewPlainSecret(defaultPassword), } user1, resp, err := httpdtest.AddUser(user1, http.StatusCreated) @@ -2506,9 +2507,7 @@ func TestNestedVirtualFolders(t *testing.T) { FsConfig: vfs.Filesystem{ Provider: sdk.CryptedFilesystemProvider, CryptConfig: vfs.CryptFsConfig{ - CryptFsConfig: sdk.CryptFsConfig{ - Passphrase: kms.NewPlainSecret(defaultPassword), - }, + Passphrase: kms.NewPlainSecret(defaultPassword), }, }, MappedPath: mappedPathCrypt,