diff --git a/cmd/portable.go b/cmd/portable.go index 3f6ecd4c..6f78834d 100644 --- a/cmd/portable.go +++ b/cmd/portable.go @@ -43,7 +43,7 @@ var ( portableS3Region string portableS3AccessKey string portableS3AccessSecret string - portableS3SessionToken string + portableS3RoleARN string portableS3Endpoint string portableS3StorageClass string portableS3ACL string @@ -175,7 +175,7 @@ Please take a look at the usage below to customize the serving parameters`, Bucket: portableS3Bucket, Region: portableS3Region, AccessKey: portableS3AccessKey, - SessionToken: portableS3SessionToken, + RoleARN: portableS3RoleARN, Endpoint: portableS3Endpoint, StorageClass: portableS3StorageClass, ACL: portableS3ACL, @@ -301,7 +301,7 @@ sftpfs => SFTP (legacy: 5)`) portableCmd.Flags().StringVar(&portableS3Region, "s3-region", "", "") portableCmd.Flags().StringVar(&portableS3AccessKey, "s3-access-key", "", "") portableCmd.Flags().StringVar(&portableS3AccessSecret, "s3-access-secret", "", "") - portableCmd.Flags().StringVar(&portableS3SessionToken, "s3-session-token", "", "") + portableCmd.Flags().StringVar(&portableS3RoleARN, "s3-role-arn", "", "") portableCmd.Flags().StringVar(&portableS3Endpoint, "s3-endpoint", "", "") portableCmd.Flags().StringVar(&portableS3StorageClass, "s3-storage-class", "", "") portableCmd.Flags().StringVar(&portableS3ACL, "s3-acl", "", "") diff --git a/docs/portable-mode.md b/docs/portable-mode.md index 91ac8123..ab29c3ca 100644 --- a/docs/portable-mode.md +++ b/docs/portable-mode.md @@ -93,7 +93,7 @@ Flags: virtual folder identified by this prefix and its contents --s3-region string - --s3-session-token string + --s3-role-arn string --s3-storage-class string --s3-upload-concurrency int How many parts are uploaded in parallel (default 2) @@ -125,7 +125,7 @@ Flags: -c, --ssh-commands strings SSH commands to enable. "*" means any supported SSH command including scp - (default [md5sum,sha1sum,cd,pwd,scp]) + (default [md5sum,sha1sum,sha256sum,cd,pwd,scp]) --start-directory string Alternate start directory. This is a virtual path not a filesystem path (default "/") diff --git a/go.mod b/go.mod index 46891a7c..9eebfad9 100644 --- a/go.mod +++ b/go.mod @@ -46,8 +46,8 @@ require ( github.com/robfig/cron/v3 v3.0.1 github.com/rs/cors v1.8.2 github.com/rs/xid v1.4.0 - github.com/rs/zerolog v1.26.2-0.20220227173336-263b0bde3672 - github.com/sftpgo/sdk v0.1.1-0.20220323191209-5d4ff81576b4 + github.com/rs/zerolog v1.26.2-0.20220312163309-e9344a8c507b + github.com/sftpgo/sdk v0.1.1-0.20220327080604-3c0f878c8c37 github.com/shirou/gopsutil/v3 v3.22.2 github.com/spf13/afero v1.8.2 github.com/spf13/cobra v1.4.0 diff --git a/go.sum b/go.sum index 3a06d5ec..88aaaaff 100644 --- a/go.sum +++ b/go.sum @@ -656,14 +656,14 @@ github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/rs/zerolog v1.26.2-0.20220227173336-263b0bde3672 h1:8tqGbO3HWm9kqGZxc8YLAND7QGJNppiwq+kMTpn8oOk= -github.com/rs/zerolog v1.26.2-0.20220227173336-263b0bde3672/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U= +github.com/rs/zerolog v1.26.2-0.20220312163309-e9344a8c507b h1:72Plc168SB6g5i9cOEPaCuMK01bKNyniHnCpqPnX0Cg= +github.com/rs/zerolog v1.26.2-0.20220312163309-e9344a8c507b/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/secsy/goftp v0.0.0-20200609142545-aa2de14babf4 h1:PT+ElG/UUFMfqy5HrxJxNzj3QBOf7dZwupeVC+mG1Lo= -github.com/sftpgo/sdk v0.1.1-0.20220323191209-5d4ff81576b4 h1:zpu89DMnl3d5Bu3YlvQuu3/KsjkhERgvqgqz+Lnn4CY= -github.com/sftpgo/sdk v0.1.1-0.20220323191209-5d4ff81576b4/go.mod h1:m5J7DH8unhD5RUsREFRiidP8zgBjup0+iQaxQnYHJOM= +github.com/sftpgo/sdk v0.1.1-0.20220327080604-3c0f878c8c37 h1:ESruo35Pb9cCgaGslAmw6leGhzeL0pLzD6o+z9gsZeQ= +github.com/sftpgo/sdk v0.1.1-0.20220327080604-3c0f878c8c37/go.mod h1:m5J7DH8unhD5RUsREFRiidP8zgBjup0+iQaxQnYHJOM= github.com/shirou/gopsutil/v3 v3.22.2 h1:wCrArWFkHYIdDxx/FSfF5RB4dpJYW6t7rcp3+zL8uks= github.com/shirou/gopsutil/v3 v3.22.2/go.mod h1:WapW1AOOPlHyXr+yOyw3uYx36enocrtSoSBy0L5vUHY= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= diff --git a/httpd/httpd_test.go b/httpd/httpd_test.go index 4b098a0d..cf758d8d 100644 --- a/httpd/httpd_test.go +++ b/httpd/httpd_test.go @@ -1906,7 +1906,6 @@ 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.SessionToken = "session token" u.FsConfig.S3Config.RoleARN = "myRoleARN" u.FsConfig.S3Config.AccessSecret = kms.NewSecret(sdkkms.SecretStatusRedacted, "access-secret", "", "") u.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000/path?k=m" @@ -2685,7 +2684,6 @@ func TestUserS3Config(t *testing.T) { user.FsConfig.S3Config.Region = "us-east-1" //nolint:goconst user.FsConfig.S3Config.AccessKey = "Server-Access-Key" user.FsConfig.S3Config.AccessSecret = kms.NewPlainSecret("Server-Access-Secret") - user.FsConfig.S3Config.SessionToken = "Session token" user.FsConfig.S3Config.RoleARN = "myRoleARN" user.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000" user.FsConfig.S3Config.UploadPartSize = 8 @@ -15470,6 +15468,117 @@ func TestUserTemplateMock(t *testing.T) { require.True(t, user2.Filters.DisableFsChecks) } +func TestUserPlaceholders(t *testing.T) { + token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) + assert.NoError(t, err) + csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) + assert.NoError(t, err) + u := getTestUser() + u.HomeDir = filepath.Join(os.TempDir(), "%username%_%password%") + form := make(url.Values) + form.Set(csrfFormToken, csrfToken) + form.Set("username", u.Username) + form.Set("home_dir", u.HomeDir) + form.Set("password", u.Password) + form.Set("status", strconv.Itoa(u.Status)) + form.Set("expiration_date", "") + form.Set("permissions", "*") + form.Set("public_keys", testPubKey) + form.Add("public_keys", testPubKey1) + form.Set("uid", "0") + form.Set("gid", "0") + form.Set("max_sessions", "0") + form.Set("quota_size", "0") + form.Set("quota_files", "0") + form.Set("upload_bandwidth", "0") + form.Set("download_bandwidth", "0") + form.Set("total_data_transfer", "0") + form.Set("upload_data_transfer", "0") + form.Set("download_data_transfer", "0") + form.Set("external_auth_cache_time", "0") + form.Set("max_upload_file_size", "0") + b, contentType, _ := getMultipartFormData(form, "", "") + req, _ := http.NewRequest(http.MethodPost, webUserPath, &b) + setJWTCookieForReq(req, token) + req.Header.Set("Content-Type", contentType) + rr := executeRequest(req) + checkResponseCode(t, http.StatusSeeOther, rr) + + user, _, err := httpdtest.GetUserByUsername(defaultUsername, http.StatusOK) + assert.NoError(t, err) + assert.Equal(t, filepath.Join(os.TempDir(), fmt.Sprintf("%v_%v", defaultUsername, defaultPassword)), user.HomeDir) + + dbUser, err := dataprovider.UserExists(defaultUsername) + assert.NoError(t, err) + assert.True(t, dbUser.IsPasswordHashed()) + hashedPwd := dbUser.Password + + form.Set("password", redactedSecret) + b, contentType, _ = getMultipartFormData(form, "", "") + req, err = http.NewRequest(http.MethodPost, path.Join(webUserPath, defaultUsername), &b) + assert.NoError(t, err) + setJWTCookieForReq(req, token) + req.Header.Set("Content-Type", contentType) + rr = executeRequest(req) + checkResponseCode(t, http.StatusSeeOther, rr) + + user, _, err = httpdtest.GetUserByUsername(defaultUsername, http.StatusOK) + assert.NoError(t, err) + assert.Equal(t, filepath.Join(os.TempDir(), defaultUsername+"_%password%"), user.HomeDir) + // check that the password was unchanged + dbUser, err = dataprovider.UserExists(defaultUsername) + assert.NoError(t, err) + assert.True(t, dbUser.IsPasswordHashed()) + assert.Equal(t, hashedPwd, dbUser.Password) + + err = os.RemoveAll(user.GetHomeDir()) + assert.NoError(t, err) + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) +} + +func TestFolderPlaceholders(t *testing.T) { + token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) + assert.NoError(t, err) + csrfToken, err := getCSRFToken(httpBaseURL + webLoginPath) + assert.NoError(t, err) + folderName := "folderName" + form := make(url.Values) + form.Set("name", folderName) + form.Set("mapped_path", filepath.Join(os.TempDir(), "%name%")) + form.Set("description", "desc folder %name%") + form.Set(csrfFormToken, csrfToken) + b, contentType, _ := getMultipartFormData(form, "", "") + req, err := http.NewRequest(http.MethodPost, webFolderPath, &b) + assert.NoError(t, err) + setJWTCookieForReq(req, token) + req.Header.Set("Content-Type", contentType) + rr := executeRequest(req) + checkResponseCode(t, http.StatusSeeOther, rr) + + folderGet, _, err := httpdtest.GetFolderByName(folderName, http.StatusOK) + assert.NoError(t, err) + assert.Equal(t, filepath.Join(os.TempDir(), folderName), folderGet.MappedPath) + assert.Equal(t, fmt.Sprintf("desc folder %v", folderName), folderGet.Description) + + form.Set("mapped_path", filepath.Join(os.TempDir(), "%name%_%name%")) + b, contentType, _ = getMultipartFormData(form, "", "") + req, err = http.NewRequest(http.MethodPost, path.Join(webFolderPath, folderName), &b) + assert.NoError(t, err) + setJWTCookieForReq(req, token) + req.Header.Set("Content-Type", contentType) + rr = executeRequest(req) + checkResponseCode(t, http.StatusSeeOther, rr) + + folderGet, _, err = httpdtest.GetFolderByName(folderName, http.StatusOK) + assert.NoError(t, err) + assert.Equal(t, filepath.Join(os.TempDir(), fmt.Sprintf("%v_%v", folderName, folderName)), folderGet.MappedPath) + assert.Equal(t, fmt.Sprintf("desc folder %v", folderName), folderGet.Description) + + _, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: folderName}, http.StatusOK) + assert.NoError(t, err) +} + func TestFolderSaveFromTemplateMock(t *testing.T) { folder1 := "f1" folder2 := "f2" @@ -15677,7 +15786,6 @@ func TestWebUserS3Mock(t *testing.T) { user.FsConfig.S3Config.Region = "eu-west-1" user.FsConfig.S3Config.AccessKey = "access-key" user.FsConfig.S3Config.AccessSecret = kms.NewPlainSecret("access-secret") - user.FsConfig.S3Config.SessionToken = "new session token" user.FsConfig.S3Config.RoleARN = "arn:aws:iam::123456789012:user/Development/product_1234/*" user.FsConfig.S3Config.Endpoint = "http://127.0.0.1:9000/path?a=b" user.FsConfig.S3Config.StorageClass = "Standard" @@ -15717,7 +15825,6 @@ func TestWebUserS3Mock(t *testing.T) { form.Set("s3_region", user.FsConfig.S3Config.Region) form.Set("s3_access_key", user.FsConfig.S3Config.AccessKey) form.Set("s3_access_secret", user.FsConfig.S3Config.AccessSecret.GetPayload()) - form.Set("s3_session_token", user.FsConfig.S3Config.SessionToken) form.Set("s3_role_arn", user.FsConfig.S3Config.RoleARN) form.Set("s3_storage_class", user.FsConfig.S3Config.StorageClass) form.Set("s3_acl", user.FsConfig.S3Config.ACL) @@ -15808,7 +15915,6 @@ func TestWebUserS3Mock(t *testing.T) { assert.Equal(t, updateUser.FsConfig.S3Config.Bucket, user.FsConfig.S3Config.Bucket) assert.Equal(t, updateUser.FsConfig.S3Config.Region, user.FsConfig.S3Config.Region) assert.Equal(t, updateUser.FsConfig.S3Config.AccessKey, user.FsConfig.S3Config.AccessKey) - assert.Equal(t, updateUser.FsConfig.S3Config.SessionToken, user.FsConfig.S3Config.SessionToken) assert.Equal(t, updateUser.FsConfig.S3Config.RoleARN, user.FsConfig.S3Config.RoleARN) assert.Equal(t, updateUser.FsConfig.S3Config.StorageClass, user.FsConfig.S3Config.StorageClass) assert.Equal(t, updateUser.FsConfig.S3Config.ACL, user.FsConfig.S3Config.ACL) @@ -16577,7 +16683,6 @@ func TestS3WebFolderMock(t *testing.T) { assert.Equal(t, S3Bucket, folder.FsConfig.S3Config.Bucket) assert.Equal(t, S3Region, folder.FsConfig.S3Config.Region) assert.Equal(t, S3AccessKey, folder.FsConfig.S3Config.AccessKey) - assert.Equal(t, S3SessionToken, folder.FsConfig.S3Config.SessionToken) assert.NotEmpty(t, folder.FsConfig.S3Config.AccessSecret.GetPayload()) assert.Equal(t, S3Endpoint, folder.FsConfig.S3Config.Endpoint) assert.Equal(t, S3StorageClass, folder.FsConfig.S3Config.StorageClass) @@ -16626,7 +16731,6 @@ func TestS3WebFolderMock(t *testing.T) { assert.Equal(t, S3Bucket, folder.FsConfig.S3Config.Bucket) assert.Equal(t, S3Region, folder.FsConfig.S3Config.Region) assert.Equal(t, S3AccessKey, folder.FsConfig.S3Config.AccessKey) - assert.Equal(t, S3SessionToken, folder.FsConfig.S3Config.SessionToken) assert.Equal(t, S3RoleARN, folder.FsConfig.S3Config.RoleARN) assert.NotEmpty(t, folder.FsConfig.S3Config.AccessSecret.GetPayload()) assert.Equal(t, S3Endpoint, folder.FsConfig.S3Config.Endpoint) diff --git a/httpd/webadmin.go b/httpd/webadmin.go index 3756d1f7..45783ca1 100644 --- a/httpd/webadmin.go +++ b/httpd/webadmin.go @@ -235,9 +235,9 @@ type messagePage struct { } type userTemplateFields struct { - Username string - Password string - PublicKey string + Username string + Password string + PublicKeys []string } func loadAdminTemplates(templatesPath string) { @@ -714,9 +714,9 @@ func getUsersForTemplate(r *http.Request) []userTemplateFields { users[username] = true res = append(res, userTemplateFields{ - Username: username, - Password: password, - PublicKey: publicKey, + Username: username, + Password: password, + PublicKeys: []string{publicKey}, }) } @@ -982,7 +982,6 @@ func getS3Config(r *http.Request) (vfs.S3FsConfig, error) { config.Bucket = r.Form.Get("s3_bucket") config.Region = r.Form.Get("s3_region") config.AccessKey = r.Form.Get("s3_access_key") - config.SessionToken = strings.TrimSpace(r.Form.Get("s3_session_token")) config.RoleARN = r.Form.Get("s3_role_arn") config.AccessSecret = getSecretFromFormField(r, "s3_access_secret") config.Endpoint = r.Form.Get("s3_endpoint") @@ -1224,14 +1223,13 @@ func getSFTPFsFromTemplate(fsConfig vfs.SFTPFsConfig, replacements map[string]st func getUserFromTemplate(user dataprovider.User, template userTemplateFields) dataprovider.User { user.Username = template.Username user.Password = template.Password - user.PublicKeys = nil - if template.PublicKey != "" { - user.PublicKeys = append(user.PublicKeys, template.PublicKey) - } + user.PublicKeys = template.PublicKeys replacements := make(map[string]string) replacements["%username%"] = user.Username - user.Password = replacePlaceholders(user.Password, replacements) - replacements["%password%"] = user.Password + if user.Password != "" && !user.IsPasswordHashed() { + user.Password = replacePlaceholders(user.Password, replacements) + replacements["%password%"] = user.Password + } user.HomeDir = replacePlaceholders(user.HomeDir, replacements) var vfolders []vfs.VirtualFolder @@ -1263,19 +1261,31 @@ func getUserFromTemplate(user dataprovider.User, template userTemplateFields) da func getTransferLimits(r *http.Request) (int64, int64, int64, error) { dataTransferUL, err := strconv.ParseInt(r.Form.Get("upload_data_transfer"), 10, 64) if err != nil { - return 0, 0, 0, err + return 0, 0, 0, fmt.Errorf("invalid upload data transfer: %w", err) } dataTransferDL, err := strconv.ParseInt(r.Form.Get("download_data_transfer"), 10, 64) if err != nil { - return 0, 0, 0, err + return 0, 0, 0, fmt.Errorf("invalid download data transfer: %w", err) } dataTransferTotal, err := strconv.ParseInt(r.Form.Get("total_data_transfer"), 10, 64) if err != nil { - return 0, 0, 0, err + return 0, 0, 0, fmt.Errorf("invalid total data transfer: %w", err) } return dataTransferUL, dataTransferDL, dataTransferTotal, nil } +func getQuotaLimits(r *http.Request) (int64, int, error) { + quotaSize, err := strconv.ParseInt(r.Form.Get("quota_size"), 10, 64) + if err != nil { + return 0, 0, fmt.Errorf("invalid quota size: %w", err) + } + quotaFiles, err := strconv.Atoi(r.Form.Get("quota_files")) + if err != nil { + return 0, 0, fmt.Errorf("invalid quota files: %w", err) + } + return quotaSize, quotaFiles, nil +} + func getUserFromPostFields(r *http.Request) (dataprovider.User, error) { var user dataprovider.User err := r.ParseMultipartForm(maxRequestSize) @@ -1285,31 +1295,27 @@ func getUserFromPostFields(r *http.Request) (dataprovider.User, error) { defer r.MultipartForm.RemoveAll() //nolint:errcheck uid, err := strconv.Atoi(r.Form.Get("uid")) if err != nil { - return user, err + return user, fmt.Errorf("invalid uid: %w", err) } gid, err := strconv.Atoi(r.Form.Get("gid")) if err != nil { - return user, err + return user, fmt.Errorf("invalid uid: %w", err) } maxSessions, err := strconv.Atoi(r.Form.Get("max_sessions")) if err != nil { - return user, err + return user, fmt.Errorf("invalid max sessions: %w", err) } - quotaSize, err := strconv.ParseInt(r.Form.Get("quota_size"), 10, 64) - if err != nil { - return user, err - } - quotaFiles, err := strconv.Atoi(r.Form.Get("quota_files")) + quotaSize, quotaFiles, err := getQuotaLimits(r) if err != nil { return user, err } bandwidthUL, err := strconv.ParseInt(r.Form.Get("upload_bandwidth"), 10, 64) if err != nil { - return user, err + return user, fmt.Errorf("invalid upload bandwidth: %w", err) } bandwidthDL, err := strconv.ParseInt(r.Form.Get("download_bandwidth"), 10, 64) if err != nil { - return user, err + return user, fmt.Errorf("invalid download bandwidth: %w", err) } dataTransferUL, dataTransferDL, dataTransferTotal, err := getTransferLimits(r) if err != nil { @@ -1317,7 +1323,7 @@ func getUserFromPostFields(r *http.Request) (dataprovider.User, error) { } status, err := strconv.Atoi(r.Form.Get("status")) if err != nil { - return user, err + return user, fmt.Errorf("invalid status: %w", err) } expirationDateMillis := int64(0) expirationDateString := r.Form.Get("expiration_date") @@ -1366,6 +1372,9 @@ func getUserFromPostFields(r *http.Request) (dataprovider.User, error) { FsConfig: fsConfig, } maxFileSize, err := strconv.ParseInt(r.Form.Get("max_upload_file_size"), 10, 64) + if err != nil { + return user, fmt.Errorf("invalid max upload file size: %w", err) + } user.Filters.MaxUploadFileSize = maxFileSize return user, err } @@ -1912,6 +1921,11 @@ func (s *httpdServer) handleWebAddUserPost(w http.ResponseWriter, r *http.Reques s.renderForbiddenPage(w, r, err.Error()) return } + user = getUserFromTemplate(user, userTemplateFields{ + Username: user.Username, + Password: user.Password, + PublicKeys: user.PublicKeys, + }) err = dataprovider.AddUser(&user, claims.Username, ipAddr) if err == nil { http.Redirect(w, r, webUsersPath, http.StatusSeeOther) @@ -1958,6 +1972,12 @@ func (s *httpdServer) handleWebUpdateUserPost(w http.ResponseWriter, r *http.Req user.FsConfig.AzBlobConfig.SASURL, user.FsConfig.GCSConfig.Credentials, user.FsConfig.CryptConfig.Passphrase, user.FsConfig.SFTPConfig.Password, user.FsConfig.SFTPConfig.PrivateKey) + updatedUser = getUserFromTemplate(updatedUser, userTemplateFields{ + Username: updatedUser.Username, + Password: updatedUser.Password, + PublicKeys: updatedUser.PublicKeys, + }) + err = dataprovider.UpdateUser(&updatedUser, claims.Username, ipAddr) if err == nil { if len(r.Form.Get("disconnect")) > 0 { @@ -2017,6 +2037,7 @@ func (s *httpdServer) handleWebAddFolderPost(w http.ResponseWriter, r *http.Requ return } folder.FsConfig = fsConfig + folder = getFolderFromTemplate(folder, folder.Name) err = dataprovider.AddFolder(&folder) if err == nil { @@ -2073,7 +2094,7 @@ func (s *httpdServer) handleWebUpdateFolderPost(w http.ResponseWriter, r *http.R s.renderFolderPage(w, r, folder, folderPageModeUpdate, err.Error()) return } - updatedFolder := &vfs.BaseVirtualFolder{ + updatedFolder := vfs.BaseVirtualFolder{ MappedPath: r.Form.Get("mapped_path"), Description: r.Form.Get("description"), } @@ -2085,7 +2106,9 @@ func (s *httpdServer) handleWebUpdateFolderPost(w http.ResponseWriter, r *http.R folder.FsConfig.AzBlobConfig.SASURL, folder.FsConfig.GCSConfig.Credentials, folder.FsConfig.CryptConfig.Passphrase, folder.FsConfig.SFTPConfig.Password, folder.FsConfig.SFTPConfig.PrivateKey) - err = dataprovider.UpdateFolder(updatedFolder, folder.Users, claims.Username, ipAddr) + updatedFolder = getFolderFromTemplate(updatedFolder, updatedFolder.Name) + + err = dataprovider.UpdateFolder(&updatedFolder, folder.Users, claims.Username, ipAddr) if err != nil { s.renderFolderPage(w, r, folder, folderPageModeUpdate, err.Error()) return diff --git a/httpdtest/httpdtest.go b/httpdtest/httpdtest.go index bb75269a..eb109565 100644 --- a/httpdtest/httpdtest.go +++ b/httpdtest/httpdtest.go @@ -1275,9 +1275,6 @@ func compareS3Config(expected *vfs.Filesystem, actual *vfs.Filesystem) error { / if expected.S3Config.AccessKey != actual.S3Config.AccessKey { return errors.New("fs S3 access key mismatch") } - if expected.S3Config.SessionToken != actual.S3Config.SessionToken { - return errors.New("fs S3 session token mismatch") - } if expected.S3Config.RoleARN != actual.S3Config.RoleARN { return errors.New("fs S3 role ARN mismatch") } diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 20ee8fbf..677a08a9 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -4729,11 +4729,9 @@ components: type: string access_secret: $ref: '#/components/schemas/Secret' - session_token: - type: string role_arn: type: string - description: 'IAM Role ARN to assume' + description: 'Optional IAM Role ARN to assume' endpoint: type: string description: optional endpoint diff --git a/telemetry/telemetry.go b/telemetry/telemetry.go index 3d1a209c..002ce817 100644 --- a/telemetry/telemetry.go +++ b/telemetry/telemetry.go @@ -33,7 +33,7 @@ var ( // Conf telemetry server configuration. type Conf struct { - // The port used for serving HTTP requests. 0 disable the HTTP server. Default: 10000 + // The port used for serving HTTP requests. 0 disable the HTTP server. Default: 0 BindPort int `json:"bind_port" mapstructure:"bind_port"` // The address to listen on. A blank value means listen on all available network interfaces. Default: "127.0.0.1" BindAddress string `json:"bind_address" mapstructure:"bind_address"` diff --git a/templates/webadmin/folder.html b/templates/webadmin/folder.html index d4d8d1ea..6af267e7 100644 --- a/templates/webadmin/folder.html +++ b/templates/webadmin/folder.html @@ -23,7 +23,7 @@