mirror of
https://github.com/drakkan/sftpgo.git
synced 2024-11-25 17:10:28 +00:00
move kms implementation outside the sdk package
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
parent
0a3d94f73d
commit
6d3d94a01f
43 changed files with 899 additions and 907 deletions
|
@ -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),
|
||||
},
|
||||
},
|
||||
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),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -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",
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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"),
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
cryptFs := fs.(*vfs.CryptFs)
|
||||
|
@ -772,10 +770,8 @@ func TestFolderCopy(t *testing.T) {
|
|||
|
||||
folder.FsConfig = vfs.Filesystem{
|
||||
CryptConfig: vfs.CryptFsConfig{
|
||||
CryptFsConfig: sdk.CryptFsConfig{
|
||||
Passphrase: kms.NewPlainSecret("crypto secret"),
|
||||
},
|
||||
},
|
||||
}
|
||||
folderCopy = folder.GetACopy()
|
||||
folder.FsConfig.CryptConfig.Passphrase = kms.NewEmptySecret()
|
||||
|
|
|
@ -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{
|
||||
BaseS3FsConfig: sdk.BaseS3FsConfig{
|
||||
Bucket: "buck",
|
||||
Region: "us-east-1",
|
||||
AccessKey: "key",
|
||||
AccessSecret: kms.NewPlainSecret("s3secret"),
|
||||
},
|
||||
AccessSecret: kms.NewPlainSecret("s3secret"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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,11 +3014,9 @@ func TestNonLocalCrossRename(t *testing.T) {
|
|||
FsConfig: vfs.Filesystem{
|
||||
Provider: sdk.CryptedFilesystemProvider,
|
||||
CryptConfig: vfs.CryptFsConfig{
|
||||
CryptFsConfig: sdk.CryptFsConfig{
|
||||
Passphrase: kms.NewPlainSecret(defaultPassword),
|
||||
},
|
||||
},
|
||||
},
|
||||
MappedPath: mappedPathCrypt,
|
||||
},
|
||||
VirtualPath: vdirCryptPath,
|
||||
|
@ -3117,11 +3115,9 @@ func TestNonLocalCrossRenameNonLocalBaseUser(t *testing.T) {
|
|||
FsConfig: vfs.Filesystem{
|
||||
Provider: sdk.CryptedFilesystemProvider,
|
||||
CryptConfig: vfs.CryptFsConfig{
|
||||
CryptFsConfig: sdk.CryptFsConfig{
|
||||
Passphrase: kms.NewPlainSecret(defaultPassword),
|
||||
},
|
||||
},
|
||||
},
|
||||
MappedPath: mappedPathCrypt,
|
||||
},
|
||||
VirtualPath: vdirCryptPath,
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,11 +2809,9 @@ func TestNestedVirtualFolders(t *testing.T) {
|
|||
FsConfig: vfs.Filesystem{
|
||||
Provider: sdk.CryptedFilesystemProvider,
|
||||
CryptConfig: vfs.CryptFsConfig{
|
||||
CryptFsConfig: sdk.CryptFsConfig{
|
||||
Passphrase: kms.NewPlainSecret(defaultPassword),
|
||||
},
|
||||
},
|
||||
},
|
||||
MappedPath: mappedPathCrypt,
|
||||
},
|
||||
VirtualPath: vdirCryptPath,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,24 +2355,22 @@ func TestUserS3Config(t *testing.T) {
|
|||
FsConfig: vfs.Filesystem{
|
||||
Provider: sdk.CryptedFilesystemProvider,
|
||||
CryptConfig: vfs.CryptFsConfig{
|
||||
CryptFsConfig: sdk.CryptFsConfig{
|
||||
Passphrase: kms.NewPlainSecret("Crypted-Secret"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
VirtualPath: "/folderPath",
|
||||
})
|
||||
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{
|
||||
BaseS3FsConfig: sdk.BaseS3FsConfig{
|
||||
Bucket: "test",
|
||||
Region: "us-east-1",
|
||||
AccessKey: "akey",
|
||||
AccessSecret: kms.NewPlainSecret("asecret"),
|
||||
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,11 +4138,9 @@ func TestFolders(t *testing.T) {
|
|||
FsConfig: vfs.Filesystem{
|
||||
Provider: sdk.CryptedFilesystemProvider,
|
||||
CryptConfig: vfs.CryptFsConfig{
|
||||
CryptFsConfig: sdk.CryptFsConfig{
|
||||
Passphrase: kms.NewPlainSecret("asecret"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
_, _, err := httpdtest.AddFolder(folder, http.StatusBadRequest)
|
||||
assert.NoError(t, err)
|
||||
|
@ -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())
|
||||
|
|
|
@ -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{
|
||||
BaseGCSFsConfig: sdk.BaseGCSFsConfig{
|
||||
Bucket: "test_bucket_name",
|
||||
Credentials: kms.NewPlainSecret("invalid JSON payload"),
|
||||
},
|
||||
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{
|
||||
BaseS3FsConfig: sdk.BaseS3FsConfig{
|
||||
Bucket: "b",
|
||||
Region: "us-west-1",
|
||||
AccessKey: "key",
|
||||
AccessSecret: kms.NewPlainSecret("secret"),
|
||||
},
|
||||
AccessSecret: kms.NewPlainSecret("secret"),
|
||||
}
|
||||
connection = &Connection{
|
||||
BaseConnection: common.NewBaseConnection(xid.New().String(), common.ProtocolHTTP, "", "", user),
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
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"`
|
||||
Status sdkkms.SecretStatus `json:"status,omitempty"`
|
||||
Payload string `json:"payload,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
AdditionalData string `json:"additional_data,omitempty"`
|
||||
|
@ -11,7 +15,7 @@ type BaseSecret struct {
|
|||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
|
@ -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 = ""
|
417
kms/kms.go
Normal file
417
kms/kms.go
Normal file
|
@ -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
|
||||
}
|
|
@ -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 = ""
|
|
@ -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
|
||||
|
|
|
@ -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 = ""
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
@ -96,7 +96,6 @@ type S3FsConfig struct {
|
|||
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"`
|
||||
// The canned ACL to apply to uploaded objects. Leave empty to use the default 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
|
||||
|
@ -140,7 +145,6 @@ type GCSFsConfig struct {
|
|||
// If empty the whole bucket contents will be available
|
||||
KeyPrefix string `json:"key_prefix,omitempty"`
|
||||
CredentialFile string `json:"-"`
|
||||
Credentials *kms.Secret `json:"credentials,omitempty"`
|
||||
// 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,17 +192,25 @@ 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 {
|
||||
// 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"`
|
||||
Password *kms.Secret `json:"password,omitempty"`
|
||||
PrivateKey *kms.Secret `json:"private_key,omitempty"`
|
||||
Fingerprints []string `json:"fingerprints,omitempty"`
|
||||
// Prefix is the path prefix to strip from SFTP resource paths.
|
||||
Prefix string `json:"prefix,omitempty"`
|
||||
|
@ -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"`
|
||||
|
|
419
sdk/kms/kms.go
419
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"`
|
||||
}
|
||||
|
|
|
@ -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...)
|
||||
}
|
29
sdk/user.go
29
sdk/user.go
|
@ -100,7 +100,7 @@ type HooksFilter struct {
|
|||
|
||||
// RecoveryCode defines a 2FA recovery code
|
||||
type RecoveryCode struct {
|
||||
Secret *kms.Secret `json:"secret"`
|
||||
Secret kms.BaseSecret `json:"secret"`
|
||||
Used bool `json:"used,omitempty"`
|
||||
}
|
||||
|
||||
|
@ -108,7 +108,7 @@ type RecoveryCode struct {
|
|||
type TOTPConfig struct {
|
||||
Enabled bool `json:"enabled,omitempty"`
|
||||
ConfigName string `json:"config_name,omitempty"`
|
||||
Secret *kms.Secret `json:"secret,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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
)
|
||||
|
||||
|
|
|
@ -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,11 +1753,9 @@ func TestTransferFailingReader(t *testing.T) {
|
|||
FsConfig: vfs.Filesystem{
|
||||
Provider: sdk.CryptedFilesystemProvider,
|
||||
CryptConfig: vfs.CryptFsConfig{
|
||||
CryptFsConfig: sdk.CryptFsConfig{
|
||||
Passphrase: kms.NewPlainSecret("crypt secret"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
user.Permissions = make(map[string][]string)
|
||||
user.Permissions["/"] = []string{dataprovider.PermAny}
|
||||
|
|
|
@ -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,11 +4603,9 @@ func TestNestedVirtualFolders(t *testing.T) {
|
|||
FsConfig: vfs.Filesystem{
|
||||
Provider: sdk.CryptedFilesystemProvider,
|
||||
CryptConfig: vfs.CryptFsConfig{
|
||||
CryptFsConfig: sdk.CryptFsConfig{
|
||||
Passphrase: kms.NewPlainSecret(defaultPassword),
|
||||
},
|
||||
},
|
||||
},
|
||||
MappedPath: mappedPathCrypt,
|
||||
},
|
||||
VirtualPath: vdirCryptPath,
|
||||
|
@ -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{
|
||||
filters := dataprovider.UserFilters{
|
||||
BaseUserFilters: sdk.BaseUserFilters{
|
||||
FilePatterns: []sdk.PatternsFilter{pattern},
|
||||
},
|
||||
}
|
||||
user.Filters = filters
|
||||
assert.True(t, user.IsFileAllowed("/test/test.jPg"))
|
||||
|
@ -8482,12 +8483,10 @@ func TestSSHRemoveCryptFs(t *testing.T) {
|
|||
FsConfig: vfs.Filesystem{
|
||||
Provider: sdk.CryptedFilesystemProvider,
|
||||
CryptConfig: vfs.CryptFsConfig{
|
||||
CryptFsConfig: sdk.CryptFsConfig{
|
||||
Passphrase: kms.NewPlainSecret(defaultPassword),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
VirtualPath: vdirPath2,
|
||||
QuotaFiles: 100,
|
||||
QuotaSize: 0,
|
||||
|
@ -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,11 +9088,9 @@ func TestSCPNestedFolders(t *testing.T) {
|
|||
FsConfig: vfs.Filesystem{
|
||||
Provider: sdk.CryptedFilesystemProvider,
|
||||
CryptConfig: vfs.CryptFsConfig{
|
||||
CryptFsConfig: sdk.CryptFsConfig{
|
||||
Passphrase: kms.NewPlainSecret(defaultPassword),
|
||||
},
|
||||
},
|
||||
},
|
||||
MappedPath: mappedPathCrypt,
|
||||
},
|
||||
VirtualPath: vdirCryptPath,
|
||||
|
|
|
@ -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(),
|
||||
},
|
||||
},
|
||||
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 {
|
||||
|
|
|
@ -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"
|
||||
)
|
||||
|
|
|
@ -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,7 +36,9 @@ 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
|
||||
sdk.BaseSFTPFsConfig
|
||||
Password *kms.Secret `json:"password,omitempty"`
|
||||
PrivateKey *kms.Secret `json:"private_key,omitempty"`
|
||||
forbiddenSelfUsernames []string `json:"-"`
|
||||
}
|
||||
|
||||
|
|
17
vfs/vfs.go
17
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
|
||||
|
|
|
@ -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"
|
||||
)
|
||||
|
|
|
@ -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,11 +2507,9 @@ func TestNestedVirtualFolders(t *testing.T) {
|
|||
FsConfig: vfs.Filesystem{
|
||||
Provider: sdk.CryptedFilesystemProvider,
|
||||
CryptConfig: vfs.CryptFsConfig{
|
||||
CryptFsConfig: sdk.CryptFsConfig{
|
||||
Passphrase: kms.NewPlainSecret(defaultPassword),
|
||||
},
|
||||
},
|
||||
},
|
||||
MappedPath: mappedPathCrypt,
|
||||
},
|
||||
VirtualPath: vdirCryptPath,
|
||||
|
|
Loading…
Reference in a new issue