diff --git a/go.mod b/go.mod index c6f625b4..5a5a68c8 100644 --- a/go.mod +++ b/go.mod @@ -52,7 +52,7 @@ require ( github.com/rs/cors v1.11.0 github.com/rs/xid v1.5.0 github.com/rs/zerolog v1.32.0 - github.com/sftpgo/sdk v0.1.6-0.20240409173349-421b3dff3896 + github.com/sftpgo/sdk v0.1.6-0.20240426175227-52f492b8b83b github.com/shirou/gopsutil/v3 v3.24.3 github.com/spf13/afero v1.11.0 github.com/spf13/cobra v1.8.0 diff --git a/go.sum b/go.sum index 89e84c8a..bf640401 100644 --- a/go.sum +++ b/go.sum @@ -351,8 +351,8 @@ github.com/secsy/goftp v0.0.0-20200609142545-aa2de14babf4 h1:PT+ElG/UUFMfqy5HrxJ github.com/secsy/goftp v0.0.0-20200609142545-aa2de14babf4/go.mod h1:MnkX001NG75g3p8bhFycnyIjeQoOjGL6CEIsdE/nKSY= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= -github.com/sftpgo/sdk v0.1.6-0.20240409173349-421b3dff3896 h1:ykxybS9WKurHTatKJ9WjqYD+WH9YH/2QMxCkxUPTVLY= -github.com/sftpgo/sdk v0.1.6-0.20240409173349-421b3dff3896/go.mod h1:AWoY2YYe/P1ymfTlRER/meERQjCcZZTbgVPGcPQgaqc= +github.com/sftpgo/sdk v0.1.6-0.20240426175227-52f492b8b83b h1:BazWPub9GBUKvfM2O6MHhAwd9JbPD1i3UudhmHfGc2w= +github.com/sftpgo/sdk v0.1.6-0.20240426175227-52f492b8b83b/go.mod h1:AWoY2YYe/P1ymfTlRER/meERQjCcZZTbgVPGcPQgaqc= github.com/shirou/gopsutil/v3 v3.24.3 h1:eoUGJSmdfLzJ3mxIhmOAhgKEKgQkeOwKpz1NbhVnuPE= github.com/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= diff --git a/internal/cmd/portable.go b/internal/cmd/portable.go index 4cf274b8..c9c32487 100644 --- a/internal/cmd/portable.go +++ b/internal/cmd/portable.go @@ -112,7 +112,7 @@ $ sftpgo portable Please take a look at the usage below to customize the serving parameters`, Run: func(_ *cobra.Command, _ []string) { portableDir := directoryToServe - fsProvider := sdk.GetProviderByName(portableFsProvider) + fsProvider := dataprovider.GetProviderFromValue(convertFsProvider()) if !filepath.IsAbs(portableDir) { if fsProvider == sdk.LocalFilesystemProvider { portableDir, _ = filepath.Abs(portableDir) @@ -227,7 +227,7 @@ Please take a look at the usage below to customize the serving parameters`, }, }, FsConfig: vfs.Filesystem{ - Provider: sdk.GetProviderByName(portableFsProvider), + Provider: fsProvider, S3Config: vfs.S3FsConfig{ BaseS3FsConfig: sdk.BaseS3FsConfig{ Bucket: portableS3Bucket, @@ -282,8 +282,9 @@ Please take a look at the usage below to customize the serving parameters`, DisableCouncurrentReads: portableSFTPDisableConcurrentReads, BufferSize: portableSFTPDBufferSize, }, - Password: kms.NewPlainSecret(portableSFTPPassword), - PrivateKey: kms.NewPlainSecret(portableSFTPPrivateKey), + Password: kms.NewPlainSecret(portableSFTPPassword), + PrivateKey: kms.NewPlainSecret(portableSFTPPrivateKey), + KeyPassphrase: kms.NewEmptySecret(), }, }, }, @@ -524,3 +525,22 @@ func getFileContents(name string) (string, error) { } return string(contents), nil } + +func convertFsProvider() string { + switch portableFsProvider { + case "osfs", "6": // httpfs (6) is not supported in portable mode, so return the default + return "0" + case "s3fs": + return "1" + case "gcsfs": + return "2" + case "azblobfs": + return "3" + case "cryptfs": + return "4" + case "sftpfs": + return "5" + default: + return portableFsProvider + } +} diff --git a/internal/dataprovider/dataprovider.go b/internal/dataprovider/dataprovider.go index d0f29fd1..8252b0de 100644 --- a/internal/dataprovider/dataprovider.go +++ b/internal/dataprovider/dataprovider.go @@ -319,32 +319,6 @@ type PasswordValidation struct { Users PasswordValidationRules `json:"users" mapstructure:"users"` } -// FilesystemProvider defines the supported storage filesystems -type FilesystemProvider struct { - sdk.FilesystemProvider -} - -// I18nString returns the translation key -func (p FilesystemProvider) I18nString() string { - switch p.FilesystemProvider { - case sdk.LocalFilesystemProvider: - return util.I18nStorageLocal - case sdk.S3FilesystemProvider: - return util.I18nStorageS3 - case sdk.GCSFilesystemProvider: - return util.I18nStorageGCS - case sdk.AzureBlobFilesystemProvider: - return util.I18nStorageAzureBlob - case sdk.CryptedFilesystemProvider: - return util.I18nStorageLocalEncrypted - case sdk.SFTPFilesystemProvider: - return util.I18nStorageSFTP - case sdk.HTTPFilesystemProvider: - return util.I18nStorageHTTP - } - return "" -} - type wrappedFolder struct { Folder vfs.BaseVirtualFolder } @@ -1014,6 +988,20 @@ func GetBackupsPath() string { return config.BackupsPath } +// GetProviderFromValue returns the FilesystemProvider matching the specified value. +// If no match is found LocalFilesystemProvider is returned. +func GetProviderFromValue(value string) sdk.FilesystemProvider { + val, err := strconv.Atoi(value) + if err != nil { + return sdk.LocalFilesystemProvider + } + result := sdk.FilesystemProvider(val) + if sdk.IsProviderSupported(result) { + return result + } + return sdk.LocalFilesystemProvider +} + func initializeHashingAlgo(cnf *Config) error { parallelism := cnf.PasswordHashing.Argon2Options.Parallelism if parallelism == 0 { diff --git a/internal/httpd/webadmin.go b/internal/httpd/webadmin.go index 76a0e6f8..98f6851d 100644 --- a/internal/httpd/webadmin.go +++ b/internal/httpd/webadmin.go @@ -509,17 +509,6 @@ func loadAdminTemplates(templatesPath string) { } fsBaseTpl := template.New("fsBaseTemplate").Funcs(template.FuncMap{ - "ListFSProviders": func() []dataprovider.FilesystemProvider { - return []dataprovider.FilesystemProvider{ - {FilesystemProvider: sdk.LocalFilesystemProvider}, - {FilesystemProvider: sdk.CryptedFilesystemProvider}, - {FilesystemProvider: sdk.S3FilesystemProvider}, - {FilesystemProvider: sdk.GCSFilesystemProvider}, - {FilesystemProvider: sdk.AzureBlobFilesystemProvider}, - {FilesystemProvider: sdk.SFTPFilesystemProvider}, - {FilesystemProvider: sdk.HTTPFilesystemProvider}, - } - }, "HumanizeBytes": util.ByteCountSI, }) usersTmpl := util.LoadTemplate(nil, usersPaths...) @@ -1694,7 +1683,7 @@ func getOsConfigFromPostFields(r *http.Request, readBufferField, writeBufferFiel func getFsConfigFromPostFields(r *http.Request) (vfs.Filesystem, error) { var fs vfs.Filesystem - fs.Provider = sdk.GetProviderByName(r.Form.Get("fs_provider")) + fs.Provider = dataprovider.GetProviderFromValue(r.Form.Get("fs_provider")) switch fs.Provider { case sdk.LocalFilesystemProvider: fs.OSConfig = getOsConfigFromPostFields(r, "osfs_read_buffer_size", "osfs_write_buffer_size") diff --git a/internal/util/i18n.go b/internal/util/i18n.go index c15f6b84..0c578794 100644 --- a/internal/util/i18n.go +++ b/internal/util/i18n.go @@ -183,13 +183,6 @@ const ( I18nOIDCTokenInvalidRoleAdmin = "oidc.role_admin_err" I18nOIDCTokenInvalidRoleUser = "oidc.role_user_err" I18nOIDCErrGetUser = "oidc.get_user_err" - I18nStorageLocal = "storage.local" - I18nStorageLocalEncrypted = "storage.encrypted" - I18nStorageS3 = "storage.s3" - I18nStorageGCS = "storage.gcs" - I18nStorageAzureBlob = "storage.azblob" - I18nStorageSFTP = "storage.sftp" - I18nStorageHTTP = "storage.http" I18nErrorInvalidQuotaSize = "user.invalid_quota_size" I18nErrorTimeOfDayInvalid = "user.time_of_day_invalid" I18nErrorTimeOfDayConflict = "user.time_of_day_conflict" diff --git a/internal/util/resources.go b/internal/util/resources.go index 876fa8c1..9d1a360c 100644 --- a/internal/util/resources.go +++ b/internal/util/resources.go @@ -58,25 +58,29 @@ func FindSharedDataPath(name, searchDir string) string { // LoadTemplate parses the given template paths. // It behaves like template.Must but it writes a log before exiting. -// You can optionally provide a base template (e.g. to define some custom functions) func LoadTemplate(base *template.Template, paths ...string) *template.Template { - var t *template.Template - var err error - if base != nil { - base, err = base.Clone() - if err == nil { - t, err = base.ParseFiles(paths...) + baseTmpl, err := base.Clone() + if err != nil { + showTemplateLoadingError(err) } - } else { - t, err = template.ParseFiles(paths...) + t, err := baseTmpl.ParseFiles(paths...) + if err != nil { + showTemplateLoadingError(err) + } + return t } + t, err := template.ParseFiles(paths...) if err != nil { - logger.ErrorToConsole("error loading required template: %v", err) - logger.ErrorToConsole(templateLoadErrorHints) - logger.Error(logSender, "", "error loading required template: %v", err) - os.Exit(1) + showTemplateLoadingError(err) } return t } + +func showTemplateLoadingError(err error) { + logger.ErrorToConsole("error loading required template: %v", err) + logger.ErrorToConsole(templateLoadErrorHints) + logger.Error(logSender, "", "error loading required template: %v", err) + os.Exit(1) +} diff --git a/templates/common/base.html b/templates/common/base.html index 0016eec4..75e88fb0 100644 --- a/templates/common/base.html +++ b/templates/common/base.html @@ -278,6 +278,38 @@ explicit grant from the SFTPGo Team (support@sftpgo.com). return window.location.protocol+"//"+window.location.hostname; } + function onFilesystemChanged(val){ + const supportedFs = ["local", "s3", "gcs", "azblob", "crypt", "sftp", "http"]; + let fsName = "local"; + switch (val){ + case '1': + fsName = "s3"; + break; + case '2': + fsName = "gcs"; + break; + case '3': + fsName = "azblob"; + break; + case '4': + fsName = "crypt"; + break; + case '5': + fsName = "sftp"; + break; + case '6': + fsName = "http"; + break; + } + for (let i = 0; i < supportedFs.length; i++){ + if (supportedFs[i] == fsName){ + $('.form-group.fsconfig-'+fsName).show(); + } else { + $('.form-group.fsconfig-'+supportedFs[i]).hide(); + } + } + } + KTUtil.onDOMContentLoaded(function () { var dismissErrorBtn = $('#id_dismiss_error_msg'); if (dismissErrorBtn){ diff --git a/templates/webadmin/folder.html b/templates/webadmin/folder.html index 8991baed..f8b69dd2 100644 --- a/templates/webadmin/folder.html +++ b/templates/webadmin/folder.html @@ -137,13 +137,9 @@ explicit grant from the SFTPGo Team (support@sftpgo.com). {{- define "extra_js"}}