From d3e76898cd0f9ac85751fbefa95e1e420366448c Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Tue, 26 Nov 2024 20:39:36 +0100 Subject: [PATCH] WebAdmin: refactor template permissions Signed-off-by: Nicola Murino --- internal/dataprovider/admin.go | 10 + internal/httpd/httpd_test.go | 437 +++++++++++++---------------- internal/httpd/internal_test.go | 4 +- internal/httpd/middleware.go | 16 +- internal/httpd/server.go | 305 ++++++++++---------- internal/httpd/webadmin.go | 25 +- static/locales/en/translation.json | 4 - static/locales/it/translation.json | 4 - templates/webadmin/folder.html | 13 +- templates/webadmin/folders.html | 4 - templates/webadmin/user.html | 13 +- templates/webadmin/users.html | 2 +- 12 files changed, 372 insertions(+), 465 deletions(-) diff --git a/internal/dataprovider/admin.go b/internal/dataprovider/admin.go index 3bb3fcfa..fb8d2774 100644 --- a/internal/dataprovider/admin.go +++ b/internal/dataprovider/admin.go @@ -547,6 +547,16 @@ func (a *Admin) HasPermission(perm string) bool { return slices.Contains(a.Permissions, perm) } +// HasPermissions returns true if the admin has all the specified permissions +func (a *Admin) HasPermissions(perms ...string) bool { + for _, perm := range perms { + if !a.HasPermission(perm) { + return false + } + } + return len(perms) > 0 +} + // GetAllowedIPAsString returns the allowed IP as comma separated string func (a *Admin) GetAllowedIPAsString() string { return strings.Join(a.Filters.AllowList, ",") diff --git a/internal/httpd/httpd_test.go b/internal/httpd/httpd_test.go index 064a7488..285a0338 100644 --- a/internal/httpd/httpd_test.go +++ b/internal/httpd/httpd_test.go @@ -13555,7 +13555,9 @@ func TestMaxTransfers(t *testing.T) { assert.NoError(t, err) err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) - assert.Len(t, common.Connections.GetStats(""), 0) + assert.Eventually(t, func() bool { + return len(common.Connections.GetStats("")) == 0 + }, 1000*time.Millisecond, 50*time.Millisecond) assert.Eventually(t, func() bool { return common.Connections.GetTotalTransfers() == 0 }, 1000*time.Millisecond, 50*time.Millisecond) @@ -22158,108 +22160,6 @@ func TestRenderUserTemplateMock(t *testing.T) { assert.NoError(t, err) } -func TestUserTemplateWithFoldersMock(t *testing.T) { - folder := vfs.BaseVirtualFolder{ - Name: "vfolder", - MappedPath: filepath.Join(os.TempDir(), "mapped"), - Description: "vfolder desc with spéciàl ch@rs", - } - - token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) - assert.NoError(t, err) - csrfToken, err := getCSRFTokenFromInternalPageMock(webTemplateFolder, token) - assert.NoError(t, err) - user := getTestUser() - form := make(url.Values) - form.Set("username", user.Username) - form.Set("home_dir", filepath.Join(os.TempDir(), "%username%")) - form.Set("uid", strconv.FormatInt(int64(user.UID), 10)) - form.Set("gid", strconv.FormatInt(int64(user.GID), 10)) - form.Set("max_sessions", strconv.FormatInt(int64(user.MaxSessions), 10)) - form.Set("quota_size", strconv.FormatInt(user.QuotaSize, 10)) - form.Set("quota_files", strconv.FormatInt(int64(user.QuotaFiles), 10)) - form.Set("upload_bandwidth", "0") - form.Set("download_bandwidth", "0") - form.Set("upload_data_transfer", "0") - form.Set("download_data_transfer", "0") - form.Set("total_data_transfer", "0") - form.Set("permissions", "*") - form.Set("status", strconv.Itoa(user.Status)) - form.Set("expiration_date", "2020-01-01 00:00:00") - form.Set("fs_provider", "0") - form.Set("max_upload_file_size", "0") - form.Set("default_shares_expiration", "0") - form.Set("max_shares_expiration", "0") - form.Set("password_expiration", "0") - form.Set("password_strength", "0") - form.Set("ftp_security", "1") - form.Set("external_auth_cache_time", "0") - form.Set("description", "desc %username% %password%") - form.Set("start_directory", "/base/%username%") - form.Set("vfolder_path", "/vdir%username%") - form.Set("vfolder_name", folder.Name) - form.Set("vfolder_quota_size", "-1") - form.Set("vfolder_quota_files", "-1") - form.Add("tpl_username", "auser1") - form.Add("tpl_password", "password1") - form.Add("tpl_public_keys", " ") - form.Add("tpl_username", "auser2") - form.Add("tpl_password", "password2") - form.Add("tpl_public_keys", testPubKey) - form.Add("tpl_username", "auser1") - form.Add("tpl_password", "password") - form.Add("tpl_public_keys", "") - form.Set("form_action", "export_from_template") - b, contentType, _ := getMultipartFormData(form, "", "") - req, _ := http.NewRequest(http.MethodPost, webTemplateUser, &b) - setJWTCookieForReq(req, token) - req.Header.Set("Content-Type", contentType) - rr := executeRequest(req) - checkResponseCode(t, http.StatusForbidden, rr) - require.Contains(t, rr.Body.String(), util.I18nErrorInvalidCSRF) - - folder, resp, err := httpdtest.AddFolder(folder, http.StatusCreated) - assert.NoError(t, err, string(resp)) - - form.Set(csrfFormToken, csrfToken) - b, contentType, _ = getMultipartFormData(form, "", "") - req, _ = http.NewRequest(http.MethodPost, webTemplateUser, &b) - setJWTCookieForReq(req, token) - req.Header.Set("Content-Type", contentType) - rr = executeRequest(req) - checkResponseCode(t, http.StatusOK, rr) - - var dump dataprovider.BackupData - err = json.Unmarshal(rr.Body.Bytes(), &dump) - assert.NoError(t, err) - assert.Len(t, dump.Users, 2) - assert.Len(t, dump.Folders, 1) - user1 := dump.Users[0] - user2 := dump.Users[1] - folder1 := dump.Folders[0] - assert.Equal(t, "auser1", user1.Username) - assert.Equal(t, "auser2", user2.Username) - assert.Equal(t, "desc auser1 password1", user1.Description) - assert.Equal(t, "desc auser2 password2", user2.Description) - assert.Equal(t, filepath.Join(os.TempDir(), user1.Username), user1.HomeDir) - assert.Equal(t, filepath.Join(os.TempDir(), user2.Username), user2.HomeDir) - assert.Equal(t, path.Join("/base", user1.Username), user1.Filters.StartDirectory) - assert.Equal(t, path.Join("/base", user2.Username), user2.Filters.StartDirectory) - assert.Equal(t, 0, user2.Filters.DefaultSharesExpiration) - assert.Equal(t, folder.Name, folder1.Name) - assert.Len(t, user1.PublicKeys, 0) - assert.Len(t, user2.PublicKeys, 1) - assert.Len(t, user1.VirtualFolders, 1) - assert.Len(t, user2.VirtualFolders, 1) - assert.Equal(t, "/vdirauser1", user1.VirtualFolders[0].VirtualPath) - assert.Equal(t, "/vdirauser2", user2.VirtualFolders[0].VirtualPath) - assert.Equal(t, 1, user1.Filters.FTPSecurity) - assert.Equal(t, 1, user2.Filters.FTPSecurity) - - _, err = httpdtest.RemoveFolder(folder, http.StatusOK) - assert.NoError(t, err) -} - func TestUserSaveFromTemplateMock(t *testing.T) { token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) assert.NoError(t, err) @@ -22295,12 +22195,20 @@ func TestUserSaveFromTemplateMock(t *testing.T) { form.Add("template_users[0][tpl_public_keys]", " ") form.Add("template_users[1][tpl_username]", user2) form.Add("template_users[1][tpl_public_keys]", testPubKey) - form.Set(csrfFormToken, csrfToken) b, contentType, _ := getMultipartFormData(form, "", "") req, _ := http.NewRequest(http.MethodPost, webTemplateUser, &b) setJWTCookieForReq(req, token) req.Header.Set("Content-Type", contentType) rr := executeRequest(req) + checkResponseCode(t, http.StatusForbidden, rr) + assert.Contains(t, rr.Body.String(), util.I18nErrorInvalidCSRF) + + form.Set(csrfFormToken, csrfToken) + b, contentType, _ = getMultipartFormData(form, "", "") + req, _ = http.NewRequest(http.MethodPost, webTemplateUser, &b) + setJWTCookieForReq(req, token) + req.Header.Set("Content-Type", contentType) + rr = executeRequest(req) checkResponseCode(t, http.StatusSeeOther, rr) u1, _, err := httpdtest.GetUserByUsername(user1, http.StatusOK) @@ -22333,7 +22241,7 @@ func TestUserSaveFromTemplateMock(t *testing.T) { assert.NoError(t, err) } -func TestUserTemplateMock(t *testing.T) { +func TestUserTemplateErrors(t *testing.T) { token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) assert.NoError(t, err) csrfToken, err := getCSRFTokenFromInternalPageMock(webTemplateFolder, token) @@ -22398,13 +22306,14 @@ func TestUserTemplateMock(t *testing.T) { form.Set("s3_upload_concurrency", strconv.Itoa(user.FsConfig.S3Config.UploadConcurrency)) form.Set("s3_download_part_size", strconv.FormatInt(user.FsConfig.S3Config.DownloadPartSize, 10)) form.Set("s3_download_concurrency", strconv.Itoa(user.FsConfig.S3Config.DownloadConcurrency)) - + // no user defined b, contentType, _ = getMultipartFormData(form, "", "") req, _ = http.NewRequest(http.MethodPost, webTemplateUser, &b) setJWTCookieForReq(req, token) req.Header.Set("Content-Type", contentType) rr = executeRequest(req) checkResponseCode(t, http.StatusBadRequest, rr) + assert.Contains(t, rr.Body.String(), util.I18nErrorUserTemplate) form.Set("template_users[0][tpl_username]", "user1") form.Set("template_users[0][tpl_password]", "password1") @@ -22427,75 +22336,135 @@ func TestUserTemplateMock(t *testing.T) { rr = executeRequest(req) checkResponseCode(t, http.StatusBadRequest, rr) require.Contains(t, rr.Body.String(), util.I18nErrorUserTemplate) +} + +func TestUserTemplateRoleAndPermissions(t *testing.T) { + r1 := getTestRole() + r2 := getTestRole() + r2.Name += "_mod" + role1, resp, err := httpdtest.AddRole(r1, http.StatusCreated) + assert.NoError(t, err, string(resp)) + role2, resp, err := httpdtest.AddRole(r2, http.StatusCreated) + assert.NoError(t, err, string(resp)) + admin := getTestAdmin() + admin.Username = altAdminUsername + admin.Password = altAdminPassword + admin.Role = role1.Name + admin.Permissions = []string{dataprovider.PermAdminManageFolders, dataprovider.PermAdminChangeUsers, + dataprovider.PermAdminViewUsers} + admin, _, err = httpdtest.AddAdmin(admin, http.StatusCreated) + assert.NoError(t, err) + + token, err := getJWTWebTokenFromTestServer(altAdminUsername, altAdminPassword) + assert.NoError(t, err) + + req, _ := http.NewRequest(http.MethodGet, webTemplateUser, nil) + setJWTCookieForReq(req, token) + rr := executeRequest(req) + checkResponseCode(t, http.StatusForbidden, rr) + + csrfToken, err := getCSRFTokenFromInternalPageMock(webTemplateFolder, token) + assert.NoError(t, err) + user1 := "u1" + user2 := "u2" + form := make(url.Values) + form.Set("username", "") + form.Set("role", role2.Name) + form.Set("home_dir", filepath.Join(os.TempDir(), "%username%")) + form.Set("upload_bandwidth", "0") + form.Set("download_bandwidth", "0") + form.Set("upload_data_transfer", "0") + form.Set("download_data_transfer", "0") + form.Set("total_data_transfer", "0") + 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("permissions", "*") + form.Set("status", "1") + form.Set("expiration_date", "") + form.Set("fs_provider", "0") + form.Set("max_upload_file_size", "0") + form.Set("default_shares_expiration", "0") + form.Set("max_shares_expiration", "0") + form.Set("password_expiration", "0") + form.Set("password_strength", "0") + form.Set("external_auth_cache_time", "0") + form.Add("template_users[0][tpl_username]", user1) + form.Add("template_users[0][tpl_password]", "password1") + form.Add("template_users[0][tpl_public_keys]", " ") + form.Add("template_users[1][tpl_username]", user2) + form.Add("template_users[1][tpl_public_keys]", testPubKey) + form.Set(csrfFormToken, csrfToken) + b, contentType, _ := getMultipartFormData(form, "", "") + req, _ = http.NewRequest(http.MethodPost, webTemplateUser, &b) + setJWTCookieForReq(req, token) + req.Header.Set("Content-Type", contentType) + rr = executeRequest(req) + checkResponseCode(t, http.StatusForbidden, rr) + // Add the required permissions + admin.Permissions = append(admin.Permissions, dataprovider.PermAdminAddUsers) + _, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK) + assert.NoError(t, err) + + token, err = getJWTWebTokenFromTestServer(altAdminUsername, altAdminPassword) + assert.NoError(t, err) + + req, _ = http.NewRequest(http.MethodGet, webTemplateUser, nil) + setJWTCookieForReq(req, token) + rr = executeRequest(req) + checkResponseCode(t, http.StatusOK, rr) + + csrfToken, err = getCSRFTokenFromInternalPageMock(webTemplateUser, token) + assert.NoError(t, err) + form.Set(csrfFormToken, csrfToken) - form.Set("template_users[0][tpl_username]", "user1") - form.Set("template_users[0][tpl_password]", "password1") - form.Set("template_users[0][tpl_public_keys]", " ") - form.Set("template_users[1][tpl_username]", "user2") - form.Set("template_users[1][tpl_password]", "password2") - form.Set("template_users[1][tpl_public_keys]", testPubKey) - form.Set("template_users[2][tpl_username]", "") - form.Set("template_users[2][tpl_password]", "password3") - form.Set("template_users[2][tpl_public_keys]", testPubKey) b, contentType, _ = getMultipartFormData(form, "", "") req, _ = http.NewRequest(http.MethodPost, webTemplateUser, &b) setJWTCookieForReq(req, token) req.Header.Set("Content-Type", contentType) rr = executeRequest(req) - checkResponseCode(t, http.StatusOK, rr) + checkResponseCode(t, http.StatusSeeOther, rr) - var dump dataprovider.BackupData - err = json.Unmarshal(rr.Body.Bytes(), &dump) - require.NoError(t, err) - require.Len(t, dump.Users, 2) - require.Len(t, dump.Admins, 0) - require.Len(t, dump.Folders, 0) + u1, _, err := httpdtest.GetUserByUsername(user1, http.StatusOK) + assert.NoError(t, err) + assert.Equal(t, admin.Role, u1.Role) + u2, _, err := httpdtest.GetUserByUsername(user2, http.StatusOK) + assert.NoError(t, err) + assert.Equal(t, admin.Role, u2.Role) - var user1, user2 dataprovider.User - for _, u := range dump.Users { - switch u.Username { - case "user1": - user1 = u - default: - user2 = u - } - } - require.Equal(t, "user1", user1.Username) - require.Equal(t, sdk.S3FilesystemProvider, user1.FsConfig.Provider) - require.Equal(t, "user2", user2.Username) - require.Equal(t, sdk.S3FilesystemProvider, user2.FsConfig.Provider) - require.Len(t, user1.PublicKeys, 0) - require.Len(t, user2.PublicKeys, 1) - require.Equal(t, filepath.Join(os.TempDir(), user1.Username), user1.HomeDir) - require.Equal(t, filepath.Join(os.TempDir(), user2.Username), user2.HomeDir) - require.Equal(t, user1.Username, user1.FsConfig.S3Config.AccessKey) - require.Equal(t, user2.Username, user2.FsConfig.S3Config.AccessKey) - require.Equal(t, path.Join("base", user1.Username)+"/", user1.FsConfig.S3Config.KeyPrefix) - require.Equal(t, path.Join("base", user2.Username)+"/", user2.FsConfig.S3Config.KeyPrefix) - require.True(t, user1.FsConfig.S3Config.AccessSecret.IsEncrypted()) - require.True(t, user1.FsConfig.S3Config.SSECustomerKey.IsEncrypted()) - err = user1.FsConfig.S3Config.AccessSecret.Decrypt() - require.NoError(t, err) - err = user1.FsConfig.S3Config.SSECustomerKey.Decrypt() - require.NoError(t, err) - require.Equal(t, "password1", user1.FsConfig.S3Config.AccessSecret.GetPayload()) - require.Equal(t, "password1", user1.FsConfig.S3Config.SSECustomerKey.GetPayload()) - require.True(t, user2.FsConfig.S3Config.AccessSecret.IsEncrypted()) - require.True(t, user2.FsConfig.S3Config.SSECustomerKey.IsEncrypted()) - err = user2.FsConfig.S3Config.AccessSecret.Decrypt() - require.NoError(t, err) - err = user2.FsConfig.S3Config.SSECustomerKey.Decrypt() - require.NoError(t, err) - require.Equal(t, "password2", user2.FsConfig.S3Config.AccessSecret.GetPayload()) - require.Equal(t, "password2", user2.FsConfig.S3Config.SSECustomerKey.GetPayload()) - require.True(t, user1.Filters.Hooks.ExternalAuthDisabled) - require.True(t, user1.Filters.Hooks.CheckPasswordDisabled) - require.False(t, user1.Filters.Hooks.PreLoginDisabled) - require.True(t, user2.Filters.Hooks.ExternalAuthDisabled) - require.True(t, user2.Filters.Hooks.CheckPasswordDisabled) - require.False(t, user2.Filters.Hooks.PreLoginDisabled) - require.True(t, user1.Filters.DisableFsChecks) - require.True(t, user2.Filters.DisableFsChecks) + _, err = httpdtest.RemoveUser(u1, http.StatusOK) + assert.NoError(t, err) + _, err = httpdtest.RemoveUser(u2, http.StatusOK) + assert.NoError(t, err) + // Set an empty role + form.Set("role", "") + b, contentType, _ = getMultipartFormData(form, "", "") + req, _ = http.NewRequest(http.MethodPost, webTemplateUser, &b) + setJWTCookieForReq(req, token) + req.Header.Set("Content-Type", contentType) + rr = executeRequest(req) + checkResponseCode(t, http.StatusSeeOther, rr) + + u1, _, err = httpdtest.GetUserByUsername(user1, http.StatusOK) + assert.NoError(t, err) + assert.Equal(t, admin.Role, u1.Role) + u2, _, err = httpdtest.GetUserByUsername(user2, http.StatusOK) + assert.NoError(t, err) + assert.Equal(t, admin.Role, u2.Role) + + _, err = httpdtest.RemoveUser(u1, http.StatusOK) + assert.NoError(t, err) + _, err = httpdtest.RemoveUser(u2, http.StatusOK) + assert.NoError(t, err) + + _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) + assert.NoError(t, err) + _, err = httpdtest.RemoveRole(role1, http.StatusOK) + assert.NoError(t, err) + _, err = httpdtest.RemoveRole(role2, http.StatusOK) + assert.NoError(t, err) } func TestUserPlaceholders(t *testing.T) { @@ -22664,7 +22633,7 @@ func TestFolderSaveFromTemplateMock(t *testing.T) { assert.NoError(t, err) } -func TestFolderTemplateMock(t *testing.T) { +func TestFolderTemplateErrors(t *testing.T) { folderName := "vfolder-template" mappedPath := filepath.Join(os.TempDir(), "%name%mapped%name%path") token, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) @@ -22680,7 +22649,6 @@ func TestFolderTemplateMock(t *testing.T) { form.Set("template_folders[2][tpl_foldername]", "folder3") form.Set("template_folders[3][tpl_foldername]", "folder1 ") form.Add("template_folders[3][tpl_foldername]", " ") - form.Set("form_action", "export_from_template") b, contentType, _ := getMultipartFormData(form, "", "") req, _ := http.NewRequest(http.MethodPost, webTemplateFolder, &b) setJWTCookieForReq(req, token) @@ -22698,36 +22666,6 @@ func TestFolderTemplateMock(t *testing.T) { checkResponseCode(t, http.StatusBadRequest, rr) assert.Contains(t, rr.Body.String(), util.I18nErrorInvalidForm) - folder1 := "folder1" - folder2 := "folder2" - folder3 := "folder3" - b, contentType, _ = getMultipartFormData(form, "", "") - req, _ = http.NewRequest(http.MethodPost, webTemplateFolder, &b) - setJWTCookieForReq(req, token) - req.Header.Set("Content-Type", contentType) - rr = executeRequest(req) - checkResponseCode(t, http.StatusOK, rr) - - var dump dataprovider.BackupData - err = json.Unmarshal(rr.Body.Bytes(), &dump) - require.NoError(t, err) - require.Len(t, dump.Users, 0) - require.Len(t, dump.Admins, 0) - require.Len(t, dump.Folders, 3) - for _, folder := range dump.Folders { - switch folder.Name { - case folder1: - require.Equal(t, "desc folder folder1", folder.Description) - require.True(t, strings.HasSuffix(folder.MappedPath, "folder1mappedfolder1path")) - case folder2: - require.Equal(t, "desc folder folder2", folder.Description) - require.True(t, strings.HasSuffix(folder.MappedPath, "folder2mappedfolder2path")) - default: - require.Equal(t, "desc folder folder3", folder.Description) - require.True(t, strings.HasSuffix(folder.MappedPath, "folder3mappedfolder3path")) - } - } - form.Set("fs_provider", "1") form.Set("s3_bucket", "bucket") form.Set("s3_region", "us-east-1") @@ -22750,52 +22688,6 @@ func TestFolderTemplateMock(t *testing.T) { form.Set("s3_upload_part_max_time", "0") form.Set("s3_download_part_size", "6") form.Set("s3_download_concurrency", "2") - b, contentType, _ = getMultipartFormData(form, "", "") - req, _ = http.NewRequest(http.MethodPost, webTemplateFolder, &b) - setJWTCookieForReq(req, token) - req.Header.Set("Content-Type", contentType) - rr = executeRequest(req) - checkResponseCode(t, http.StatusOK, rr) - - dump = dataprovider.BackupData{ - Version: dataprovider.DumpVersion, - } - err = json.Unmarshal(rr.Body.Bytes(), &dump) - require.NoError(t, err) - require.Len(t, dump.Users, 0) - require.Len(t, dump.Admins, 0) - require.Len(t, dump.Folders, 3) - for _, folder := range dump.Folders { - switch folder.Name { - case folder1: - require.Equal(t, folder1, folder.FsConfig.S3Config.AccessKey) - err = folder.FsConfig.S3Config.AccessSecret.Decrypt() - require.NoError(t, err) - require.Equal(t, fmt.Sprintf("pwd%s", folder1), folder.FsConfig.S3Config.AccessSecret.GetPayload()) - require.Equal(t, path.Join("base", folder1)+"/", folder.FsConfig.S3Config.KeyPrefix) - err = folder.FsConfig.S3Config.SSECustomerKey.Decrypt() - require.NoError(t, err) - require.Equal(t, fmt.Sprintf("key%s", folder1), folder.FsConfig.S3Config.SSECustomerKey.GetPayload()) - case folder2: - require.Equal(t, folder2, folder.FsConfig.S3Config.AccessKey) - err = folder.FsConfig.S3Config.AccessSecret.Decrypt() - require.NoError(t, err) - require.Equal(t, "pwd"+folder2, folder.FsConfig.S3Config.AccessSecret.GetPayload()) - require.Equal(t, "base/"+folder2+"/", folder.FsConfig.S3Config.KeyPrefix) - err = folder.FsConfig.S3Config.SSECustomerKey.Decrypt() - require.NoError(t, err) - require.Equal(t, "key"+folder2, folder.FsConfig.S3Config.SSECustomerKey.GetPayload()) - default: - require.Equal(t, folder3, folder.FsConfig.S3Config.AccessKey) - err = folder.FsConfig.S3Config.AccessSecret.Decrypt() - require.NoError(t, err) - require.Equal(t, "pwd"+folder3, folder.FsConfig.S3Config.AccessSecret.GetPayload()) - require.Equal(t, "base/"+folder3+"/", folder.FsConfig.S3Config.KeyPrefix) - err = folder.FsConfig.S3Config.SSECustomerKey.Decrypt() - require.NoError(t, err) - require.Equal(t, "key"+folder3, folder.FsConfig.S3Config.SSECustomerKey.GetPayload()) - } - } form.Set("template_folders[0][tpl_foldername]", " ") form.Set("template_folders[1][tpl_foldername]", "") @@ -22820,6 +22712,61 @@ func TestFolderTemplateMock(t *testing.T) { assert.Contains(t, rr.Body.String(), util.I18nErrorInvalidHomeDir) } +func TestFolderTemplatePermission(t *testing.T) { + admin := getTestAdmin() + admin.Username = altAdminUsername + admin.Password = altAdminPassword + admin.Permissions = []string{dataprovider.PermAdminChangeUsers, dataprovider.PermAdminAddUsers, dataprovider.PermAdminViewUsers} + admin, _, err := httpdtest.AddAdmin(admin, http.StatusCreated) + assert.NoError(t, err) + // no permission to view or add folders from templates + token, err := getJWTWebTokenFromTestServer(altAdminUsername, altAdminPassword) + assert.NoError(t, err) + csrfToken, err := getCSRFTokenFromInternalPageMock(webTemplateUser, token) + assert.NoError(t, err) + + req, err := http.NewRequest(http.MethodGet, webTemplateFolder, nil) + assert.NoError(t, err) + req.RequestURI = webTemplateFolder + setJWTCookieForReq(req, token) + rr := executeRequest(req) + checkResponseCode(t, http.StatusForbidden, rr) + + form := make(url.Values) + form.Set("name", "name") + form.Set("mapped_path", filepath.Join(os.TempDir(), "%name%")) + form.Set("description", "desc folder %name%") + form.Set("template_folders[0][tpl_foldername]", "folder1") + form.Set("template_folders[1][tpl_foldername]", "folder2") + form.Set(csrfFormToken, csrfToken) + b, contentType, _ := getMultipartFormData(form, "", "") + req, err = http.NewRequest(http.MethodPost, webTemplateFolder, &b) + assert.NoError(t, err) + setJWTCookieForReq(req, token) + req.Header.Set("Content-Type", contentType) + rr = executeRequest(req) + checkResponseCode(t, http.StatusForbidden, rr) + + admin.Permissions = append(admin.Permissions, dataprovider.PermAdminManageFolders) + _, _, err = httpdtest.UpdateAdmin(admin, http.StatusOK) + assert.NoError(t, err) + + token, err = getJWTWebTokenFromTestServer(altAdminUsername, altAdminPassword) + assert.NoError(t, err) + _, err = getCSRFTokenFromInternalPageMock(webTemplateUser, token) + assert.NoError(t, err) + + req, err = http.NewRequest(http.MethodGet, webTemplateFolder, nil) + assert.NoError(t, err) + req.RequestURI = webTemplateFolder + setJWTCookieForReq(req, token) + rr = executeRequest(req) + checkResponseCode(t, http.StatusOK, rr) + + _, err = httpdtest.RemoveAdmin(admin, http.StatusOK) + assert.NoError(t, err) +} + func TestWebUserS3Mock(t *testing.T) { webToken, err := getJWTWebTokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass) assert.NoError(t, err) diff --git a/internal/httpd/internal_test.go b/internal/httpd/internal_test.go index 6eae37b5..8bfd7d88 100644 --- a/internal/httpd/internal_test.go +++ b/internal/httpd/internal_test.go @@ -1794,7 +1794,7 @@ func TestJWTTokenValidation(t *testing.T) { assert.Equal(t, webClientLoginPath, rr.Header().Get("Location")) errTest := errors.New("test error") - permFn := server.checkPerm(dataprovider.PermAdminAny) + permFn := server.checkPerms(dataprovider.PermAdminAny) fn = permFn(r) rr = httptest.NewRecorder() req, _ = http.NewRequest(http.MethodGet, userPath, nil) @@ -1802,7 +1802,7 @@ func TestJWTTokenValidation(t *testing.T) { fn.ServeHTTP(rr, req.WithContext(ctx)) assert.Equal(t, http.StatusBadRequest, rr.Code) - permFn = server.checkPerm(dataprovider.PermAdminAny) + permFn = server.checkPerms(dataprovider.PermAdminAny) fn = permFn(r) rr = httptest.NewRecorder() req, _ = http.NewRequest(http.MethodGet, webUserPath, nil) diff --git a/internal/httpd/middleware.go b/internal/httpd/middleware.go index e3c5f3f6..e282916e 100644 --- a/internal/httpd/middleware.go +++ b/internal/httpd/middleware.go @@ -297,7 +297,7 @@ func (s *httpdServer) requireBuiltinLogin(next http.Handler) http.Handler { }) } -func (s *httpdServer) checkPerm(perm string) func(next http.Handler) http.Handler { +func (s *httpdServer) checkPerms(perms ...string) func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, claims, err := jwtauth.FromContext(r.Context()) @@ -312,13 +312,15 @@ func (s *httpdServer) checkPerm(perm string) func(next http.Handler) http.Handle tokenClaims := jwtTokenClaims{} tokenClaims.Decode(claims) - if !tokenClaims.hasPerm(perm) { - if isWebRequest(r) { - s.renderForbiddenPage(w, r, util.NewI18nError(fs.ErrPermission, util.I18nError403Message)) - } else { - sendAPIResponse(w, r, nil, http.StatusText(http.StatusForbidden), http.StatusForbidden) + for _, perm := range perms { + if !tokenClaims.hasPerm(perm) { + if isWebRequest(r) { + s.renderForbiddenPage(w, r, util.NewI18nError(fs.ErrPermission, util.I18nError403Message)) + } else { + sendAPIResponse(w, r, nil, http.StatusText(http.StatusForbidden), http.StatusForbidden) + } + return } - return } next.ServeHTTP(w, r) diff --git a/internal/httpd/server.go b/internal/httpd/server.go index e6f76c32..04597fa2 100644 --- a/internal/httpd/server.go +++ b/internal/httpd/server.go @@ -1325,97 +1325,97 @@ func (s *httpdServer) initializeRouter() { router.With(forbidAPIKeyAuthentication).Get(admin2FARecoveryCodesPath, getRecoveryCodes) router.With(forbidAPIKeyAuthentication).Post(admin2FARecoveryCodesPath, generateRecoveryCodes) - router.With(forbidAPIKeyAuthentication, s.checkPerm(dataprovider.PermAdminAny)). + router.With(forbidAPIKeyAuthentication, s.checkPerms(dataprovider.PermAdminAny)). Get(apiKeysPath, getAPIKeys) - router.With(forbidAPIKeyAuthentication, s.checkPerm(dataprovider.PermAdminAny)). + router.With(forbidAPIKeyAuthentication, s.checkPerms(dataprovider.PermAdminAny)). Post(apiKeysPath, addAPIKey) - router.With(forbidAPIKeyAuthentication, s.checkPerm(dataprovider.PermAdminAny)). + router.With(forbidAPIKeyAuthentication, s.checkPerms(dataprovider.PermAdminAny)). Get(apiKeysPath+"/{id}", getAPIKeyByID) - router.With(forbidAPIKeyAuthentication, s.checkPerm(dataprovider.PermAdminAny)). + router.With(forbidAPIKeyAuthentication, s.checkPerms(dataprovider.PermAdminAny)). Put(apiKeysPath+"/{id}", updateAPIKey) - router.With(forbidAPIKeyAuthentication, s.checkPerm(dataprovider.PermAdminAny)). + router.With(forbidAPIKeyAuthentication, s.checkPerms(dataprovider.PermAdminAny)). Delete(apiKeysPath+"/{id}", deleteAPIKey) router.Group(func(router chi.Router) { router.Use(s.checkAuthRequirements) - router.With(s.checkPerm(dataprovider.PermAdminViewServerStatus)). + router.With(s.checkPerms(dataprovider.PermAdminViewServerStatus)). Get(serverStatusPath, func(w http.ResponseWriter, r *http.Request) { r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize) render.JSON(w, r, getServicesStatus()) }) - router.With(s.checkPerm(dataprovider.PermAdminViewConnections)).Get(activeConnectionsPath, getActiveConnections) - router.With(s.checkPerm(dataprovider.PermAdminCloseConnections)). + router.With(s.checkPerms(dataprovider.PermAdminViewConnections)).Get(activeConnectionsPath, getActiveConnections) + router.With(s.checkPerms(dataprovider.PermAdminCloseConnections)). Delete(activeConnectionsPath+"/{connectionID}", handleCloseConnection) - router.With(s.checkPerm(dataprovider.PermAdminQuotaScans)).Get(quotasBasePath+"/users/scans", getUsersQuotaScans) - router.With(s.checkPerm(dataprovider.PermAdminQuotaScans)).Post(quotasBasePath+"/users/{username}/scan", startUserQuotaScan) - router.With(s.checkPerm(dataprovider.PermAdminQuotaScans)).Get(quotasBasePath+"/folders/scans", getFoldersQuotaScans) - router.With(s.checkPerm(dataprovider.PermAdminQuotaScans)).Post(quotasBasePath+"/folders/{name}/scan", startFolderQuotaScan) - router.With(s.checkPerm(dataprovider.PermAdminViewUsers)).Get(userPath, getUsers) - router.With(s.checkPerm(dataprovider.PermAdminAddUsers)).Post(userPath, addUser) - router.With(s.checkPerm(dataprovider.PermAdminViewUsers)).Get(userPath+"/{username}", getUserByUsername) //nolint:goconst - router.With(s.checkPerm(dataprovider.PermAdminChangeUsers)).Put(userPath+"/{username}", updateUser) - router.With(s.checkPerm(dataprovider.PermAdminDeleteUsers)).Delete(userPath+"/{username}", deleteUser) - router.With(s.checkPerm(dataprovider.PermAdminDisableMFA)).Put(userPath+"/{username}/2fa/disable", disableUser2FA) //nolint:goconst - router.With(s.checkPerm(dataprovider.PermAdminManageFolders)).Get(folderPath, getFolders) - router.With(s.checkPerm(dataprovider.PermAdminManageFolders)).Get(folderPath+"/{name}", getFolderByName) //nolint:goconst - router.With(s.checkPerm(dataprovider.PermAdminManageFolders)).Post(folderPath, addFolder) - router.With(s.checkPerm(dataprovider.PermAdminManageFolders)).Put(folderPath+"/{name}", updateFolder) - router.With(s.checkPerm(dataprovider.PermAdminManageFolders)).Delete(folderPath+"/{name}", deleteFolder) - router.With(s.checkPerm(dataprovider.PermAdminManageGroups)).Get(groupPath, getGroups) - router.With(s.checkPerm(dataprovider.PermAdminManageGroups)).Get(groupPath+"/{name}", getGroupByName) - router.With(s.checkPerm(dataprovider.PermAdminManageGroups)).Post(groupPath, addGroup) - router.With(s.checkPerm(dataprovider.PermAdminManageGroups)).Put(groupPath+"/{name}", updateGroup) - router.With(s.checkPerm(dataprovider.PermAdminManageGroups)).Delete(groupPath+"/{name}", deleteGroup) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Get(dumpDataPath, dumpData) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Get(loadDataPath, loadData) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Post(loadDataPath, loadDataFromRequest) - router.With(s.checkPerm(dataprovider.PermAdminChangeUsers)).Put(quotasBasePath+"/users/{username}/usage", + router.With(s.checkPerms(dataprovider.PermAdminQuotaScans)).Get(quotasBasePath+"/users/scans", getUsersQuotaScans) + router.With(s.checkPerms(dataprovider.PermAdminQuotaScans)).Post(quotasBasePath+"/users/{username}/scan", startUserQuotaScan) + router.With(s.checkPerms(dataprovider.PermAdminQuotaScans)).Get(quotasBasePath+"/folders/scans", getFoldersQuotaScans) + router.With(s.checkPerms(dataprovider.PermAdminQuotaScans)).Post(quotasBasePath+"/folders/{name}/scan", startFolderQuotaScan) + router.With(s.checkPerms(dataprovider.PermAdminViewUsers)).Get(userPath, getUsers) + router.With(s.checkPerms(dataprovider.PermAdminAddUsers)).Post(userPath, addUser) + router.With(s.checkPerms(dataprovider.PermAdminViewUsers)).Get(userPath+"/{username}", getUserByUsername) //nolint:goconst + router.With(s.checkPerms(dataprovider.PermAdminChangeUsers)).Put(userPath+"/{username}", updateUser) + router.With(s.checkPerms(dataprovider.PermAdminDeleteUsers)).Delete(userPath+"/{username}", deleteUser) + router.With(s.checkPerms(dataprovider.PermAdminDisableMFA)).Put(userPath+"/{username}/2fa/disable", disableUser2FA) //nolint:goconst + router.With(s.checkPerms(dataprovider.PermAdminManageFolders)).Get(folderPath, getFolders) + router.With(s.checkPerms(dataprovider.PermAdminManageFolders)).Get(folderPath+"/{name}", getFolderByName) //nolint:goconst + router.With(s.checkPerms(dataprovider.PermAdminManageFolders)).Post(folderPath, addFolder) + router.With(s.checkPerms(dataprovider.PermAdminManageFolders)).Put(folderPath+"/{name}", updateFolder) + router.With(s.checkPerms(dataprovider.PermAdminManageFolders)).Delete(folderPath+"/{name}", deleteFolder) + router.With(s.checkPerms(dataprovider.PermAdminManageGroups)).Get(groupPath, getGroups) + router.With(s.checkPerms(dataprovider.PermAdminManageGroups)).Get(groupPath+"/{name}", getGroupByName) + router.With(s.checkPerms(dataprovider.PermAdminManageGroups)).Post(groupPath, addGroup) + router.With(s.checkPerms(dataprovider.PermAdminManageGroups)).Put(groupPath+"/{name}", updateGroup) + router.With(s.checkPerms(dataprovider.PermAdminManageGroups)).Delete(groupPath+"/{name}", deleteGroup) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Get(dumpDataPath, dumpData) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Get(loadDataPath, loadData) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Post(loadDataPath, loadDataFromRequest) + router.With(s.checkPerms(dataprovider.PermAdminChangeUsers)).Put(quotasBasePath+"/users/{username}/usage", updateUserQuotaUsage) - router.With(s.checkPerm(dataprovider.PermAdminChangeUsers)).Put(quotasBasePath+"/users/{username}/transfer-usage", + router.With(s.checkPerms(dataprovider.PermAdminChangeUsers)).Put(quotasBasePath+"/users/{username}/transfer-usage", updateUserTransferQuotaUsage) - router.With(s.checkPerm(dataprovider.PermAdminChangeUsers)).Put(quotasBasePath+"/folders/{name}/usage", + router.With(s.checkPerms(dataprovider.PermAdminChangeUsers)).Put(quotasBasePath+"/folders/{name}/usage", updateFolderQuotaUsage) - router.With(s.checkPerm(dataprovider.PermAdminViewDefender)).Get(defenderHosts, getDefenderHosts) - router.With(s.checkPerm(dataprovider.PermAdminViewDefender)).Get(defenderHosts+"/{id}", getDefenderHostByID) - router.With(s.checkPerm(dataprovider.PermAdminManageDefender)).Delete(defenderHosts+"/{id}", deleteDefenderHostByID) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Get(adminPath, getAdmins) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Post(adminPath, addAdmin) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Get(adminPath+"/{username}", getAdminByUsername) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Put(adminPath+"/{username}", updateAdmin) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Delete(adminPath+"/{username}", deleteAdmin) - router.With(s.checkPerm(dataprovider.PermAdminDisableMFA)).Put(adminPath+"/{username}/2fa/disable", disableAdmin2FA) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Get(retentionChecksPath, getRetentionChecks) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Post(retentionBasePath+"/{username}/check", + router.With(s.checkPerms(dataprovider.PermAdminViewDefender)).Get(defenderHosts, getDefenderHosts) + router.With(s.checkPerms(dataprovider.PermAdminViewDefender)).Get(defenderHosts+"/{id}", getDefenderHostByID) + router.With(s.checkPerms(dataprovider.PermAdminManageDefender)).Delete(defenderHosts+"/{id}", deleteDefenderHostByID) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Get(adminPath, getAdmins) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Post(adminPath, addAdmin) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Get(adminPath+"/{username}", getAdminByUsername) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Put(adminPath+"/{username}", updateAdmin) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Delete(adminPath+"/{username}", deleteAdmin) + router.With(s.checkPerms(dataprovider.PermAdminDisableMFA)).Put(adminPath+"/{username}/2fa/disable", disableAdmin2FA) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Get(retentionChecksPath, getRetentionChecks) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Post(retentionBasePath+"/{username}/check", startRetentionCheck) - router.With(s.checkPerm(dataprovider.PermAdminViewEvents), compressor.Handler). + router.With(s.checkPerms(dataprovider.PermAdminViewEvents), compressor.Handler). Get(fsEventsPath, searchFsEvents) - router.With(s.checkPerm(dataprovider.PermAdminViewEvents), compressor.Handler). + router.With(s.checkPerms(dataprovider.PermAdminViewEvents), compressor.Handler). Get(providerEventsPath, searchProviderEvents) - router.With(s.checkPerm(dataprovider.PermAdminViewEvents), compressor.Handler). + router.With(s.checkPerms(dataprovider.PermAdminViewEvents), compressor.Handler). Get(logEventsPath, searchLogEvents) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Get(eventActionsPath, getEventActions) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Get(eventActionsPath+"/{name}", getEventActionByName) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Post(eventActionsPath, addEventAction) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Put(eventActionsPath+"/{name}", updateEventAction) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Delete(eventActionsPath+"/{name}", deleteEventAction) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Get(eventRulesPath, getEventRules) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Get(eventRulesPath+"/{name}", getEventRuleByName) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Post(eventRulesPath, addEventRule) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Put(eventRulesPath+"/{name}", updateEventRule) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Delete(eventRulesPath+"/{name}", deleteEventRule) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Post(eventRulesPath+"/run/{name}", runOnDemandRule) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Get(rolesPath, getRoles) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Post(rolesPath, addRole) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Get(rolesPath+"/{name}", getRoleByName) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Put(rolesPath+"/{name}", updateRole) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Delete(rolesPath+"/{name}", deleteRole) - router.With(s.checkPerm(dataprovider.PermAdminAny), compressor.Handler).Get(ipListsPath+"/{type}", getIPListEntries) //nolint:goconst - router.With(s.checkPerm(dataprovider.PermAdminAny)).Post(ipListsPath+"/{type}", addIPListEntry) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Get(ipListsPath+"/{type}/{ipornet}", getIPListEntry) //nolint:goconst - router.With(s.checkPerm(dataprovider.PermAdminAny)).Put(ipListsPath+"/{type}/{ipornet}", updateIPListEntry) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Delete(ipListsPath+"/{type}/{ipornet}", deleteIPListEntry) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Get(eventActionsPath, getEventActions) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Get(eventActionsPath+"/{name}", getEventActionByName) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Post(eventActionsPath, addEventAction) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Put(eventActionsPath+"/{name}", updateEventAction) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Delete(eventActionsPath+"/{name}", deleteEventAction) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Get(eventRulesPath, getEventRules) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Get(eventRulesPath+"/{name}", getEventRuleByName) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Post(eventRulesPath, addEventRule) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Put(eventRulesPath+"/{name}", updateEventRule) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Delete(eventRulesPath+"/{name}", deleteEventRule) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Post(eventRulesPath+"/run/{name}", runOnDemandRule) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Get(rolesPath, getRoles) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Post(rolesPath, addRole) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Get(rolesPath+"/{name}", getRoleByName) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Put(rolesPath+"/{name}", updateRole) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Delete(rolesPath+"/{name}", deleteRole) + router.With(s.checkPerms(dataprovider.PermAdminAny), compressor.Handler).Get(ipListsPath+"/{type}", getIPListEntries) //nolint:goconst + router.With(s.checkPerms(dataprovider.PermAdminAny)).Post(ipListsPath+"/{type}", addIPListEntry) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Get(ipListsPath+"/{type}/{ipornet}", getIPListEntry) //nolint:goconst + router.With(s.checkPerms(dataprovider.PermAdminAny)).Put(ipListsPath+"/{type}/{ipornet}", updateIPListEntry) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Delete(ipListsPath+"/{type}/{ipornet}", deleteIPListEntry) }) }) @@ -1730,156 +1730,157 @@ func (s *httpdServer) setupWebAdminRoutes() { router.Group(func(router chi.Router) { router.Use(s.checkAuthRequirements) - router.With(s.checkPerm(dataprovider.PermAdminViewUsers), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminViewUsers), s.refreshCookie). Get(webUsersPath, s.handleGetWebUsers) - router.With(s.checkPerm(dataprovider.PermAdminViewUsers), compressor.Handler, s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminViewUsers), compressor.Handler, s.refreshCookie). Get(webUsersPath+jsonAPISuffix, getAllUsers) - router.With(s.checkPerm(dataprovider.PermAdminAddUsers), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminAddUsers), s.refreshCookie). Get(webUserPath, s.handleWebAddUserGet) - router.With(s.checkPerm(dataprovider.PermAdminChangeUsers), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminChangeUsers), s.refreshCookie). Get(webUserPath+"/{username}", s.handleWebUpdateUserGet) - router.With(s.checkPerm(dataprovider.PermAdminAddUsers)).Post(webUserPath, s.handleWebAddUserPost) - router.With(s.checkPerm(dataprovider.PermAdminChangeUsers)).Post(webUserPath+"/{username}", + router.With(s.checkPerms(dataprovider.PermAdminAddUsers)).Post(webUserPath, s.handleWebAddUserPost) + router.With(s.checkPerms(dataprovider.PermAdminChangeUsers)).Post(webUserPath+"/{username}", s.handleWebUpdateUserPost) - router.With(s.checkPerm(dataprovider.PermAdminManageGroups), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminManageGroups), s.refreshCookie). Get(webGroupsPath, s.handleWebGetGroups) - router.With(s.checkPerm(dataprovider.PermAdminManageGroups), compressor.Handler, s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminManageGroups), compressor.Handler, s.refreshCookie). Get(webGroupsPath+jsonAPISuffix, getAllGroups) - router.With(s.checkPerm(dataprovider.PermAdminManageGroups), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminManageGroups), s.refreshCookie). Get(webGroupPath, s.handleWebAddGroupGet) - router.With(s.checkPerm(dataprovider.PermAdminManageGroups)).Post(webGroupPath, s.handleWebAddGroupPost) - router.With(s.checkPerm(dataprovider.PermAdminManageGroups), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminManageGroups)).Post(webGroupPath, s.handleWebAddGroupPost) + router.With(s.checkPerms(dataprovider.PermAdminManageGroups), s.refreshCookie). Get(webGroupPath+"/{name}", s.handleWebUpdateGroupGet) - router.With(s.checkPerm(dataprovider.PermAdminManageGroups)).Post(webGroupPath+"/{name}", + router.With(s.checkPerms(dataprovider.PermAdminManageGroups)).Post(webGroupPath+"/{name}", s.handleWebUpdateGroupPost) - router.With(s.checkPerm(dataprovider.PermAdminManageGroups), s.verifyCSRFHeader). + router.With(s.checkPerms(dataprovider.PermAdminManageGroups), s.verifyCSRFHeader). Delete(webGroupPath+"/{name}", deleteGroup) - router.With(s.checkPerm(dataprovider.PermAdminViewConnections), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminViewConnections), s.refreshCookie). Get(webConnectionsPath, s.handleWebGetConnections) - router.With(s.checkPerm(dataprovider.PermAdminViewConnections), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminViewConnections), s.refreshCookie). Get(webConnectionsPath+jsonAPISuffix, getActiveConnections) - router.With(s.checkPerm(dataprovider.PermAdminManageFolders), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminManageFolders), s.refreshCookie). Get(webFoldersPath, s.handleWebGetFolders) - router.With(s.checkPerm(dataprovider.PermAdminManageFolders), compressor.Handler, s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminManageFolders), compressor.Handler, s.refreshCookie). Get(webFoldersPath+jsonAPISuffix, getAllFolders) - router.With(s.checkPerm(dataprovider.PermAdminManageFolders), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminManageFolders), s.refreshCookie). Get(webFolderPath, s.handleWebAddFolderGet) - router.With(s.checkPerm(dataprovider.PermAdminManageFolders)).Post(webFolderPath, s.handleWebAddFolderPost) - router.With(s.checkPerm(dataprovider.PermAdminViewServerStatus), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminManageFolders)).Post(webFolderPath, s.handleWebAddFolderPost) + router.With(s.checkPerms(dataprovider.PermAdminViewServerStatus), s.refreshCookie). Get(webStatusPath, s.handleWebGetStatus) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminAny), s.refreshCookie). Get(webAdminsPath, s.handleGetWebAdmins) - router.With(s.checkPerm(dataprovider.PermAdminAny), compressor.Handler, s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminAny), compressor.Handler, s.refreshCookie). Get(webAdminsPath+jsonAPISuffix, getAllAdmins) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminAny), s.refreshCookie). Get(webAdminPath, s.handleWebAddAdminGet) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminAny), s.refreshCookie). Get(webAdminPath+"/{username}", s.handleWebUpdateAdminGet) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Post(webAdminPath, s.handleWebAddAdminPost) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Post(webAdminPath+"/{username}", + router.With(s.checkPerms(dataprovider.PermAdminAny)).Post(webAdminPath, s.handleWebAddAdminPost) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Post(webAdminPath+"/{username}", s.handleWebUpdateAdminPost) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.verifyCSRFHeader). + router.With(s.checkPerms(dataprovider.PermAdminAny), s.verifyCSRFHeader). Delete(webAdminPath+"/{username}", deleteAdmin) - router.With(s.checkPerm(dataprovider.PermAdminDisableMFA), s.verifyCSRFHeader). + router.With(s.checkPerms(dataprovider.PermAdminDisableMFA), s.verifyCSRFHeader). Put(webAdminPath+"/{username}/2fa/disable", disableAdmin2FA) - router.With(s.checkPerm(dataprovider.PermAdminCloseConnections), s.verifyCSRFHeader). + router.With(s.checkPerms(dataprovider.PermAdminCloseConnections), s.verifyCSRFHeader). Delete(webConnectionsPath+"/{connectionID}", handleCloseConnection) - router.With(s.checkPerm(dataprovider.PermAdminManageFolders), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminManageFolders), s.refreshCookie). Get(webFolderPath+"/{name}", s.handleWebUpdateFolderGet) - router.With(s.checkPerm(dataprovider.PermAdminManageFolders)).Post(webFolderPath+"/{name}", + router.With(s.checkPerms(dataprovider.PermAdminManageFolders)).Post(webFolderPath+"/{name}", s.handleWebUpdateFolderPost) - router.With(s.checkPerm(dataprovider.PermAdminManageFolders), s.verifyCSRFHeader). + router.With(s.checkPerms(dataprovider.PermAdminManageFolders), s.verifyCSRFHeader). Delete(webFolderPath+"/{name}", deleteFolder) - router.With(s.checkPerm(dataprovider.PermAdminQuotaScans), s.verifyCSRFHeader). + router.With(s.checkPerms(dataprovider.PermAdminQuotaScans), s.verifyCSRFHeader). Post(webScanVFolderPath+"/{name}", startFolderQuotaScan) - router.With(s.checkPerm(dataprovider.PermAdminDeleteUsers), s.verifyCSRFHeader). + router.With(s.checkPerms(dataprovider.PermAdminDeleteUsers), s.verifyCSRFHeader). Delete(webUserPath+"/{username}", deleteUser) - router.With(s.checkPerm(dataprovider.PermAdminDisableMFA), s.verifyCSRFHeader). + router.With(s.checkPerms(dataprovider.PermAdminDisableMFA), s.verifyCSRFHeader). Put(webUserPath+"/{username}/2fa/disable", disableUser2FA) - router.With(s.checkPerm(dataprovider.PermAdminQuotaScans), s.verifyCSRFHeader). + router.With(s.checkPerms(dataprovider.PermAdminQuotaScans), s.verifyCSRFHeader). Post(webQuotaScanPath+"/{username}", startUserQuotaScan) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Get(webMaintenancePath, s.handleWebMaintenance) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Get(webBackupPath, dumpData) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Post(webRestorePath, s.handleWebRestore) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminAny)).Get(webMaintenancePath, s.handleWebMaintenance) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Get(webBackupPath, dumpData) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Post(webRestorePath, s.handleWebRestore) + router.With(s.checkPerms(dataprovider.PermAdminAddUsers, dataprovider.PermAdminChangeUsers), s.refreshCookie). Get(webTemplateUser, s.handleWebTemplateUserGet) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Post(webTemplateUser, s.handleWebTemplateUserPost) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminAddUsers, dataprovider.PermAdminChangeUsers)). + Post(webTemplateUser, s.handleWebTemplateUserPost) + router.With(s.checkPerms(dataprovider.PermAdminManageFolders), s.refreshCookie). Get(webTemplateFolder, s.handleWebTemplateFolderGet) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Post(webTemplateFolder, s.handleWebTemplateFolderPost) - router.With(s.checkPerm(dataprovider.PermAdminViewDefender)).Get(webDefenderPath, s.handleWebDefenderPage) - router.With(s.checkPerm(dataprovider.PermAdminViewDefender)).Get(webDefenderHostsPath, getDefenderHosts) - router.With(s.checkPerm(dataprovider.PermAdminManageDefender), s.verifyCSRFHeader). + router.With(s.checkPerms(dataprovider.PermAdminManageFolders)).Post(webTemplateFolder, s.handleWebTemplateFolderPost) + router.With(s.checkPerms(dataprovider.PermAdminViewDefender)).Get(webDefenderPath, s.handleWebDefenderPage) + router.With(s.checkPerms(dataprovider.PermAdminViewDefender)).Get(webDefenderHostsPath, getDefenderHosts) + router.With(s.checkPerms(dataprovider.PermAdminManageDefender), s.verifyCSRFHeader). Delete(webDefenderHostsPath+"/{id}", deleteDefenderHostByID) - router.With(s.checkPerm(dataprovider.PermAdminAny), compressor.Handler, s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminAny), compressor.Handler, s.refreshCookie). Get(webAdminEventActionsPath+jsonAPISuffix, getAllActions) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminAny), s.refreshCookie). Get(webAdminEventActionsPath, s.handleWebGetEventActions) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminAny), s.refreshCookie). Get(webAdminEventActionPath, s.handleWebAddEventActionGet) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Post(webAdminEventActionPath, + router.With(s.checkPerms(dataprovider.PermAdminAny)).Post(webAdminEventActionPath, s.handleWebAddEventActionPost) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminAny), s.refreshCookie). Get(webAdminEventActionPath+"/{name}", s.handleWebUpdateEventActionGet) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Post(webAdminEventActionPath+"/{name}", + router.With(s.checkPerms(dataprovider.PermAdminAny)).Post(webAdminEventActionPath+"/{name}", s.handleWebUpdateEventActionPost) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.verifyCSRFHeader). + router.With(s.checkPerms(dataprovider.PermAdminAny), s.verifyCSRFHeader). Delete(webAdminEventActionPath+"/{name}", deleteEventAction) - router.With(s.checkPerm(dataprovider.PermAdminAny), compressor.Handler, s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminAny), compressor.Handler, s.refreshCookie). Get(webAdminEventRulesPath+jsonAPISuffix, getAllRules) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminAny), s.refreshCookie). Get(webAdminEventRulesPath, s.handleWebGetEventRules) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminAny), s.refreshCookie). Get(webAdminEventRulePath, s.handleWebAddEventRuleGet) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Post(webAdminEventRulePath, + router.With(s.checkPerms(dataprovider.PermAdminAny)).Post(webAdminEventRulePath, s.handleWebAddEventRulePost) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminAny), s.refreshCookie). Get(webAdminEventRulePath+"/{name}", s.handleWebUpdateEventRuleGet) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Post(webAdminEventRulePath+"/{name}", + router.With(s.checkPerms(dataprovider.PermAdminAny)).Post(webAdminEventRulePath+"/{name}", s.handleWebUpdateEventRulePost) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.verifyCSRFHeader). + router.With(s.checkPerms(dataprovider.PermAdminAny), s.verifyCSRFHeader). Delete(webAdminEventRulePath+"/{name}", deleteEventRule) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.verifyCSRFHeader). + router.With(s.checkPerms(dataprovider.PermAdminAny), s.verifyCSRFHeader). Post(webAdminEventRulePath+"/run/{name}", runOnDemandRule) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminAny), s.refreshCookie). Get(webAdminRolesPath, s.handleWebGetRoles) - router.With(s.checkPerm(dataprovider.PermAdminAny), compressor.Handler, s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminAny), compressor.Handler, s.refreshCookie). Get(webAdminRolesPath+jsonAPISuffix, getAllRoles) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminAny), s.refreshCookie). Get(webAdminRolePath, s.handleWebAddRoleGet) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Post(webAdminRolePath, s.handleWebAddRolePost) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminAny)).Post(webAdminRolePath, s.handleWebAddRolePost) + router.With(s.checkPerms(dataprovider.PermAdminAny), s.refreshCookie). Get(webAdminRolePath+"/{name}", s.handleWebUpdateRoleGet) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Post(webAdminRolePath+"/{name}", + router.With(s.checkPerms(dataprovider.PermAdminAny)).Post(webAdminRolePath+"/{name}", s.handleWebUpdateRolePost) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.verifyCSRFHeader). + router.With(s.checkPerms(dataprovider.PermAdminAny), s.verifyCSRFHeader). Delete(webAdminRolePath+"/{name}", deleteRole) - router.With(s.checkPerm(dataprovider.PermAdminViewEvents), s.refreshCookie).Get(webEventsPath, + router.With(s.checkPerms(dataprovider.PermAdminViewEvents), s.refreshCookie).Get(webEventsPath, s.handleWebGetEvents) - router.With(s.checkPerm(dataprovider.PermAdminViewEvents), compressor.Handler, s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminViewEvents), compressor.Handler, s.refreshCookie). Get(webEventsFsSearchPath, searchFsEvents) - router.With(s.checkPerm(dataprovider.PermAdminViewEvents), compressor.Handler, s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminViewEvents), compressor.Handler, s.refreshCookie). Get(webEventsProviderSearchPath, searchProviderEvents) - router.With(s.checkPerm(dataprovider.PermAdminViewEvents), compressor.Handler, s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminViewEvents), compressor.Handler, s.refreshCookie). Get(webEventsLogSearchPath, searchLogEvents) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Get(webIPListsPath, s.handleWebIPListsPage) - router.With(s.checkPerm(dataprovider.PermAdminAny), compressor.Handler, s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminAny)).Get(webIPListsPath, s.handleWebIPListsPage) + router.With(s.checkPerms(dataprovider.PermAdminAny), compressor.Handler, s.refreshCookie). Get(webIPListsPath+"/{type}", getIPListEntries) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.refreshCookie).Get(webIPListPath+"/{type}", + router.With(s.checkPerms(dataprovider.PermAdminAny), s.refreshCookie).Get(webIPListPath+"/{type}", s.handleWebAddIPListEntryGet) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Post(webIPListPath+"/{type}", + router.With(s.checkPerms(dataprovider.PermAdminAny)).Post(webIPListPath+"/{type}", s.handleWebAddIPListEntryPost) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.refreshCookie).Get(webIPListPath+"/{type}/{ipornet}", + router.With(s.checkPerms(dataprovider.PermAdminAny), s.refreshCookie).Get(webIPListPath+"/{type}/{ipornet}", s.handleWebUpdateIPListEntryGet) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Post(webIPListPath+"/{type}/{ipornet}", + router.With(s.checkPerms(dataprovider.PermAdminAny)).Post(webIPListPath+"/{type}/{ipornet}", s.handleWebUpdateIPListEntryPost) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.verifyCSRFHeader). + router.With(s.checkPerms(dataprovider.PermAdminAny), s.verifyCSRFHeader). Delete(webIPListPath+"/{type}/{ipornet}", deleteIPListEntry) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.refreshCookie).Get(webConfigsPath, s.handleWebConfigs) - router.With(s.checkPerm(dataprovider.PermAdminAny)).Post(webConfigsPath, s.handleWebConfigsPost) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.verifyCSRFHeader, s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminAny), s.refreshCookie).Get(webConfigsPath, s.handleWebConfigs) + router.With(s.checkPerms(dataprovider.PermAdminAny)).Post(webConfigsPath, s.handleWebConfigsPost) + router.With(s.checkPerms(dataprovider.PermAdminAny), s.verifyCSRFHeader, s.refreshCookie). Post(webConfigsPath+"/smtp/test", testSMTPConfig) - router.With(s.checkPerm(dataprovider.PermAdminAny), s.verifyCSRFHeader, s.refreshCookie). + router.With(s.checkPerms(dataprovider.PermAdminAny), s.verifyCSRFHeader, s.refreshCookie). Post(webOAuth2TokenPath, s.handleSMTPOAuth2TokenRequestPost) }) }) diff --git a/internal/httpd/webadmin.go b/internal/httpd/webadmin.go index 4b4d52d4..fdbc58b8 100644 --- a/internal/httpd/webadmin.go +++ b/internal/httpd/webadmin.go @@ -31,7 +31,6 @@ import ( "strings" "time" - "github.com/go-chi/render" "github.com/rs/xid" "github.com/sftpgo/sdk" sdkkms "github.com/sftpgo/sdk/kms" @@ -3280,7 +3279,6 @@ func (s *httpdServer) handleWebTemplateFolderPost(w http.ResponseWriter, r *http templateFolder.FsConfig = fsConfig var dump dataprovider.BackupData - dump.Version = dataprovider.DumpVersion foldersFields := getFoldersForTemplate(r) for _, tmpl := range foldersFields { @@ -3300,12 +3298,6 @@ func (s *httpdServer) handleWebTemplateFolderPost(w http.ResponseWriter, r *http ), "") return } - if r.Form.Get("form_action") == "export_from_template" { - w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"sftpgo-%v-folders-from-template.json\"", - len(dump.Folders))) - render.JSON(w, r, dump) - return - } if err = RestoreFolders(dump.Folders, "", 1, 0, claims.Username, ipAddr, claims.Role); err != nil { s.renderMessagePage(w, r, util.I18nTemplateFolderTitle, getRespStatus(err), err, "") return @@ -3372,7 +3364,6 @@ func (s *httpdServer) handleWebTemplateUserPost(w http.ResponseWriter, r *http.R } var dump dataprovider.BackupData - dump.Version = dataprovider.DumpVersion userTmplFields := getUsersForTemplate(r) for _, tmpl := range userTmplFields { @@ -3381,14 +3372,10 @@ func (s *httpdServer) handleWebTemplateUserPost(w http.ResponseWriter, r *http.R s.renderMessagePage(w, r, util.I18nTemplateUserTitle, http.StatusBadRequest, err, "") return } - // to create a template the "*" permission is required, so role admins cannot use - // this method, we don't need to force the role - dump.Users = append(dump.Users, u) - for _, folder := range u.VirtualFolders { - if !dump.HasFolder(folder.Name) { - dump.Folders = append(dump.Folders, folder.BaseVirtualFolder) - } + if claims.Role != "" { + u.Role = claims.Role } + dump.Users = append(dump.Users, u) } if len(dump.Users) == 0 { @@ -3399,12 +3386,6 @@ func (s *httpdServer) handleWebTemplateUserPost(w http.ResponseWriter, r *http.R ), "") return } - if r.Form.Get("form_action") == "export_from_template" { - w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"sftpgo-%v-users-from-template.json\"", - len(dump.Users))) - render.JSON(w, r, dump) - return - } if err = RestoreUsers(dump.Users, "", 1, 0, claims.Username, ipAddr, claims.Role); err != nil { s.renderMessagePage(w, r, util.I18nTemplateUserTitle, getRespStatus(err), err, "") return diff --git a/static/locales/en/translation.json b/static/locales/en/translation.json index 78523777..68229e12 100644 --- a/static/locales/en/translation.json +++ b/static/locales/en/translation.json @@ -535,8 +535,6 @@ "virtual_folders_help": "Quota size/files -1 means included within user quota, 0 unlimited. Don't set -1 for shared folders. You can use MB/GB/TB suffix. Without suffix we assume bytes", "disconnect": "Disconnect the user after the update", "disconnect_help": "This way you force the user to login again, if connected, and so to use the new configuration", - "submit_generate": "Generate and save users", - "submit_export": "Generate and export users", "invalid_quota_size": "Invalid quota size", "expires_in": "Expires in", "expires_in_help": "Account expiration as number of days from the creation. 0 means no expiration", @@ -570,8 +568,6 @@ "template_name_placeholder": "replaced with the name of the specified virtual folder", "template_help": "The generated virtual folders can be saved or exported. Exported folders can be imported from the \"Maintenance\" section of this SFTPGo instance or another.", "name": "Virtual folder name", - "submit_generate": "Generate and save folders", - "submit_export": "Generate and export folder", "template_no_folder": "No valid virtual folder defined, unable to complete the requested action" }, "storage": { diff --git a/static/locales/it/translation.json b/static/locales/it/translation.json index aae9b0e2..7860605e 100644 --- a/static/locales/it/translation.json +++ b/static/locales/it/translation.json @@ -535,8 +535,6 @@ "virtual_folders_help": "Dimensione quota/numero file -1 significa incluso nella quota utente, 0 illimitato. Non impostare -1 per le cartelle condivise. È possibile utilizzare il suffisso MB/GB/TB. Senza suffisso assumiamo byte", "disconnect": "Disconnettere l'utente dopo l'aggiornamento", "disconnect_help": "In questo modo si obbliga l'utente a effettuare nuovamente il login, se connesso, e quindi ad utilizzare la nuova configurazione", - "submit_generate": "Genera e salva utenti", - "submit_export": "Genera ed esporta utenti", "invalid_quota_size": "Quota (dimensione) non valida", "expires_in": "Scadenza", "expires_in_help": "Scadenza dell'account espressa in numero di giorni dalla creazione. 0 significa nessuna scadenza", @@ -570,8 +568,6 @@ "template_name_placeholder": "sostituito con il nome della cartella virtuale specificata", "template_help": "Le cartelle virtuali generate possono essere salvate o esportate. Le cartelle esportate possono essere importate dalla sezione \"Manutenzione\" di questa istanza SFTPGo o di un'altra.", "name": "Nome cartella virtuale", - "submit_generate": "Genera e salva cartelle", - "submit_export": "Genera e esporta cartelle", "template_no_folder": "Nessuna cartella virtuale valida definita. Impossibile completare l'azione richiesta" }, "storage": { diff --git a/templates/webadmin/folder.html b/templates/webadmin/folder.html index 8923bbcb..d3d9707b 100644 --- a/templates/webadmin/folder.html +++ b/templates/webadmin/folder.html @@ -108,19 +108,8 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
- {{- if eq .Mode 3}} - - {{- end}} - {{- end}}
`; //{{- end}} - //{{- if .LoggedUser.HasPermission "*"}} + //{{- if .LoggedUser.HasPermissions "add_users" "edit_users"}} numActions++; actions+=`