diff --git a/src/handlers/fileshdr/handlers.go b/src/handlers/fileshdr/handlers.go index 2856149..7db3f53 100644 --- a/src/handlers/fileshdr/handlers.go +++ b/src/handlers/fileshdr/handlers.go @@ -24,7 +24,7 @@ import ( "github.com/ihexxa/quickshare/src/worker/localworker" ) -var ( +const ( // queries FilePathQuery = "fp" ListDirQuery = "dp" @@ -104,7 +104,7 @@ func (h *FileHandlers) canAccess(userName, role, op, sharedPath string) bool { parts := strings.Split(sharedPath, "/") if len(parts) < 2 { // the path must be longer than /files return false - } else if parts[0] == userName { + } else if parts[0] == userName && userName != "" && parts[1] != "" { return true } @@ -143,6 +143,12 @@ func (h *FileHandlers) Create(c *gin.Context) { return } + fsFilePath, err := h.getFSFilePath(userID, req.Path) + if err != nil { + c.JSON(q.ErrResp(c, 500, err)) + return + } + if req.FileSize == 0 { err = h.deps.FS().MkdirAll(filepath.Dir(req.Path)) if err != nil { @@ -152,12 +158,6 @@ func (h *FileHandlers) Create(c *gin.Context) { // TODO: limit the number of files with 0 byte - fsFilePath, err := h.getFSFilePath(userID, req.Path) - if err != nil { - c.JSON(q.ErrResp(c, 500, err)) - return - } - err = h.deps.FS().Create(fsFilePath) if err != nil { if os.IsExist(err) { @@ -512,6 +512,7 @@ func (h *FileHandlers) getFSFilePath(userID, fsFilePath string) (string, error) // this file exists maxDetect := 1024 + fsFilePath = filepath.Clean(fsFilePath) for i := 1; i < maxDetect; i++ { dir := path.Dir(fsFilePath) nameAndExt := path.Base(fsFilePath) @@ -1041,11 +1042,10 @@ func (h *FileHandlers) GetSharingDir(c *gin.Context) { func (h *FileHandlers) GetStreamReader(userID uint64, fd io.Reader) (io.ReadCloser, error) { pr, pw := io.Pipe() - chunkSize := 100 * 1024 // notice: it can not be greater than limiter's token count go func() { for { - ok, err := h.deps.Limiter().CanRead(userID, chunkSize) + ok, err := h.deps.Limiter().CanRead(userID, q.DownloadChunkSize) if err != nil { pw.CloseWithError(err) break @@ -1054,7 +1054,7 @@ func (h *FileHandlers) GetStreamReader(userID uint64, fd io.Reader) (io.ReadClos continue } - _, err = io.CopyN(pw, fd, int64(chunkSize)) + _, err = io.CopyN(pw, fd, int64(q.DownloadChunkSize)) if err != nil { if err != io.EOF { pw.CloseWithError(err) diff --git a/src/handlers/multiusers/handlers.go b/src/handlers/multiusers/handlers.go index 4d4aeb2..541ffab 100644 --- a/src/handlers/multiusers/handlers.go +++ b/src/handlers/multiusers/handlers.go @@ -156,6 +156,9 @@ func (h *MultiUsersSvc) Init(adminName, adminPwd string) (string, error) { spaceLimit := int64(h.cfg.IntOr("Users.SpaceLimit", 100*1024*1024)) uploadSpeedLimit := h.cfg.IntOr("Users.UploadSpeedLimit", 100*1024) downloadSpeedLimit := h.cfg.IntOr("Users.DownloadSpeedLimit", 100*1024) + if downloadSpeedLimit < q.DownloadChunkSize { + return "", fmt.Errorf("download speed limit can not be lower than chunk size: %d", q.DownloadChunkSize) + } if ok { userCfgs, ok := usersInterface.([]*userstore.UserCfg) if !ok { @@ -166,7 +169,6 @@ func (h *MultiUsersSvc) Init(adminName, adminPwd string) (string, error) { // TODO: check if the folders already exists fsRootFolder := q.FsRootPath(userCfg.Name, "/") if err = h.deps.FS().MkdirAll(fsRootFolder); err != nil { - return "", err } uploadFolder := q.UploadFolder(userCfg.Name) @@ -276,7 +278,7 @@ func (h *MultiUsersSvc) IsAuthed(c *gin.Context) { // token alreay verified in the authn middleware role := c.MustGet(q.RoleParam).(string) if role == userstore.VisitorRole { - c.JSON(q.ErrResp(c, 401, q.ErrUnauthorized)) + c.JSON(q.ErrResp(c, 403, q.ErrUnauthorized)) return } c.JSON(q.Resp(200)) @@ -299,7 +301,7 @@ func (h *MultiUsersSvc) SetPwd(c *gin.Context) { claims, err := h.getUserInfo(c) if err != nil { - c.JSON(q.ErrResp(c, 401, err)) + c.JSON(q.ErrResp(c, 403, err)) return } @@ -350,7 +352,7 @@ func (h *MultiUsersSvc) ForceSetPwd(c *gin.Context) { claims, err := h.getUserInfo(c) if err != nil { - c.JSON(q.ErrResp(c, 401, err)) + c.JSON(q.ErrResp(c, 403, err)) return } if claims[q.RoleParam] != userstore.AdminRole { @@ -472,7 +474,7 @@ func (h *MultiUsersSvc) DelUser(c *gin.Context) { claims, err := h.getUserInfo(c) if err != nil { - c.JSON(q.ErrResp(c, 401, err)) + c.JSON(q.ErrResp(c, 403, err)) return } if claims[q.UserIDParam] == userIDStr { @@ -645,7 +647,7 @@ type SelfResp struct { func (h *MultiUsersSvc) Self(c *gin.Context) { claims, err := h.getUserInfo(c) if err != nil { - c.JSON(q.ErrResp(c, 401, err)) + c.JSON(q.ErrResp(c, 403, err)) return } @@ -679,6 +681,12 @@ func (h *MultiUsersSvc) SetUser(c *gin.Context) { return } + role := c.MustGet(q.RoleParam).(string) + if role != userstore.AdminRole { + c.JSON(q.ErrResp(c, 403, errors.New("Forbidden"))) + return + } + err := h.deps.Users().SetInfo(req.ID, &userstore.User{ Role: req.Role, Quota: req.Quota, diff --git a/src/handlers/util.go b/src/handlers/util.go index 0b25717..856c032 100644 --- a/src/handlers/util.go +++ b/src/handlers/util.go @@ -27,6 +27,10 @@ var ( TokenCookie = "tk" LastID = "lid" + // DownloadChunkSize can not be greater than limiter's token count + // downloadSpeedLimit can not be lower than DownloadChunkSize + DownloadChunkSize = 100 * 1024 + ErrAccessDenied = errors.New("access denied") ErrUnauthorized = errors.New("unauthorized") ) diff --git a/src/server/server_permission_test.go b/src/server/server_permission_test.go index e3dc107..d531586 100644 --- a/src/server/server_permission_test.go +++ b/src/server/server_permission_test.go @@ -2,19 +2,15 @@ package server import ( "encoding/base64" - "fmt" - "math/rand" "net/http" "os" "path/filepath" "strconv" - "sync" "testing" - "time" "github.com/ihexxa/quickshare/src/client" + "github.com/ihexxa/quickshare/src/db/userstore" q "github.com/ihexxa/quickshare/src/handlers" - "github.com/ihexxa/quickshare/src/handlers/fileshdr" ) func TestPermissions(t *testing.T) { @@ -37,11 +33,26 @@ func TestPermissions(t *testing.T) { "pwd": "1234", "role": "admin" }, + { + "name": "admin2", + "pwd": "1234", + "role": "admin" + }, { "name": "user", "pwd": "1234", "role": "user" }, + { + "name": "user2", + "pwd": "1234", + "role": "user" + }, + { + "name": "share", + "pwd": "1234", + "role": "user" + } ] }, "server": { @@ -63,30 +74,15 @@ func TestPermissions(t *testing.T) { srv := startTestServer(config) defer srv.Shutdown() - fs := srv.depsFS() if !isServerReady(addr) { t.Fatal("fail to start server") } - // adminUsersCl := client.NewSingleUserClient(addr) - // resp, _, errs := adminUsersCl.Login(adminName, adminPwd) - // if len(errs) > 0 { - // t.Fatal(errs) - // } else if resp.StatusCode != 200 { - // t.Fatal(resp.StatusCode) - // } - // adminToken := client.GetCookie(resp.Cookies(), q.TokenCookie) - // cl := client.NewFilesClient(addr, adminToken) - - var err error - // TODO: remove all files under home folder before testing - // or the count of files is incorrect - // tests only check the status code for checking permission t.Run("Users API Permissions", func(t *testing.T) { testUsersAPIs := func(user string, pwd string, requireAuth bool, expectedCodes map[string]int) { cl := client.NewSingleUserClient(addr) - var token *http.Cookie + token := &http.Cookie{} if requireAuth { resp, _, errs := cl.Login(user, pwd) if len(errs) > 0 { @@ -135,7 +131,7 @@ func TestPermissions(t *testing.T) { if len(errs) > 0 { t.Fatal(errs) } else if resp.StatusCode != expectedCode { - t.Fatalf("%s %d", user, resp.StatusCode) + t.Fatalf("%s %d %d", user, expectedCode, resp.StatusCode) } // test user operations @@ -145,7 +141,7 @@ func TestPermissions(t *testing.T) { if len(errs) > 0 { t.Fatal(errs) } else if resp.StatusCode != expectedCode { - t.Fatalf("%s %d", user, resp.StatusCode) + t.Fatalf("%s %d %d", user, expectedCode, resp.StatusCode) } expectedCode = expectedCodes["ListUsers"] @@ -153,21 +149,53 @@ func TestPermissions(t *testing.T) { if len(errs) > 0 { t.Fatal(errs) } else if resp.StatusCode != expectedCode { - t.Fatalf("%s %d", user, resp.StatusCode) + t.Fatalf("%s %d %d", user, expectedCode, resp.StatusCode) } // TODO: the id here should be uint64 - uintID, err := strconv.ParseUint(addUserResp.ID, 64, 10) - if err != nil { - t.Fatal(err) + tmpUserID := uint64(0) + var err error + if addUserResp.ID != "" { + tmpUserID, err = strconv.ParseUint(addUserResp.ID, 10, 64) + if err != nil { + t.Fatal(err) + } } - newRole := "user" - expectedCode = expectedCodes["SetUser"] - resp, _, errs = cl.SetUser(uintID, newRole, selfResp.Quota, token) + userID := uint64(0) + if selfResp.ID != "" { + userID, err = strconv.ParseUint(selfResp.ID, 10, 64) + if err != nil { + t.Fatal(err) + } + } + + newRole := userstore.AdminRole + newQuota := &userstore.Quota{ + SpaceLimit: int64(2046), + UploadSpeedLimit: int(8 * 1024 * 1024), + DownloadSpeedLimit: int(8 * 1024 * 1024), + } + // update self + expectedCode = expectedCodes["SetUserSelf"] + resp, _, errs = cl.SetUser(userID, newRole, newQuota, token) if len(errs) > 0 { t.Fatal(errs) } else if resp.StatusCode != expectedCode { - t.Fatalf("%s %d", user, resp.StatusCode) + t.Fatalf("%s %d %d", user, expectedCode, resp.StatusCode) + } + // update other users + expectedCode = expectedCodes["SetUserOthers"] + resp, _, errs = cl.SetUser(tmpUserID, userstore.AdminRole, newQuota, token) + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != expectedCode { + t.Fatalf("%s %d %d", user, expectedCode, resp.StatusCode) + } + resp, _, errs = cl.SetUser(0, userstore.UserRole, newQuota, token) + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != expectedCode { + t.Fatalf("%s %d %d", user, expectedCode, resp.StatusCode) } expectedCode = expectedCodes["DelUser"] @@ -175,7 +203,7 @@ func TestPermissions(t *testing.T) { if len(errs) > 0 { t.Fatal(errs) } else if resp.StatusCode != expectedCode { - t.Fatalf("%s %d", user, resp.StatusCode) + t.Fatalf("%s %d %d", user, expectedCode, resp.StatusCode) } // test role operations @@ -185,7 +213,7 @@ func TestPermissions(t *testing.T) { if len(errs) > 0 { t.Fatal(errs) } else if resp.StatusCode != expectedCode { - t.Fatalf("%s %d", user, resp.StatusCode) + t.Fatalf("%s %d %d", user, expectedCode, resp.StatusCode) } expectedCode = expectedCodes["ListRoles"] @@ -193,7 +221,7 @@ func TestPermissions(t *testing.T) { if len(errs) > 0 { t.Fatal(errs) } else if resp.StatusCode != expectedCode { - t.Fatalf("%s %d", user, resp.StatusCode) + t.Fatalf("%s %d %d", user, expectedCode, resp.StatusCode) } expectedCode = expectedCodes["DelRole"] @@ -201,7 +229,7 @@ func TestPermissions(t *testing.T) { if len(errs) > 0 { t.Fatal(errs) } else if resp.StatusCode != expectedCode { - t.Fatalf("%s %d", user, resp.StatusCode) + t.Fatalf("%s %d %d", user, expectedCode, resp.StatusCode) } if requireAuth { @@ -221,7 +249,9 @@ func TestPermissions(t *testing.T) { "IsAuthed": 200, "AddUser": 200, "ListUsers": 200, - "SetUser": 200, + "SetUserSelf": 200, + "SetUserOthers": 200, + "SetOtherUser": 200, "DelUser": 200, "AddRole": 200, "ListRoles": 200, @@ -233,27 +263,376 @@ func TestPermissions(t *testing.T) { "Self": 200, "SetPreferences": 200, "IsAuthed": 200, - "AddUser": 401, - "ListUsers": 401, - "SetUser": 401, - "DelUser": 401, - "AddRole": 401, - "ListRoles": 401, - "DelRole": 401, + "AddUser": 403, + "ListUsers": 403, + "SetUserSelf": 403, + "SetUserOthers": 403, + "DelUser": 403, + "AddRole": 403, + "ListRoles": 403, + "DelRole": 403, }) testUsersAPIs("visitor", "", false, map[string]int{ - "SetPwd": 401, - "Self": 401, - "SetPreferences": 401, - "IsAuthed": 401, - "AddUser": 401, - "ListUsers": 401, - "SetUser": 401, - "DelUser": 401, - "AddRole": 401, - "ListRoles": 401, - "DelRole": 401, + "SetPwd": 403, + "Self": 403, + "SetPreferences": 403, + "IsAuthed": 403, + "AddUser": 403, + "ListUsers": 403, + "SetUserSelf": 403, + "SetUserOthers": 403, + "DelUser": 403, + "AddRole": 403, + "ListRoles": 403, + "DelRole": 403, }) }) + + t.Run("Files operation API Permissions", func(t *testing.T) { + // ListUploadings(c *gin.Context) { + // DelUploading(c *gin.Context) { + + // AddSharing(c *gin.Context) { + // DelSharing(c *gin.Context) { + // IsSharing(c *gin.Context) { + // ListSharings(c *gin.Context) { + // ListSharingIDs(c *gin.Context) { + + // GenerateHash(c *gin.Context) { + // GetSharingDir(c *gin.Context) { + + testFolderOpPermission := func(user string, pwd string, requireAuth bool, expectedCodes map[string]int) { + // List(c *gin.Context) { + // ListHome(c *gin.Context) { + // Mkdir(c *gin.Context) { + // Move(c *gin.Context) { + + // Create(c *gin.Context) { + // UploadChunk(c *gin.Context) { + // UploadStatus(c *gin.Context) { + // Metadata(c *gin.Context) { + // Move(c *gin.Context) { + // Download(c *gin.Context) { + // GetStreamReader(userID uint64, fd io.Reader) (io.ReadCloser, error) { + // Delete(c *gin.Context) { + + cl := client.NewSingleUserClient(addr) + token := &http.Cookie{} + if requireAuth { + resp, _, errs := cl.Login(user, pwd) + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != 200 { + t.Fatal(resp.StatusCode) + } + token = client.GetCookie(resp.Cookies(), q.TokenCookie) + } + + filesCl := client.NewFilesClient(addr, token) + + expectedCode := expectedCodes["ListHome"] + resp, lhResp, errs := filesCl.ListHome() + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != expectedCode { + t.Fatal(user, resp.StatusCode, expectedCode) + } + + expectedCode = expectedCodes["List"] + homePath := lhResp.Cwd + if !requireAuth { + homePath = "/" + } + resp, _, errs = filesCl.List(homePath) + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != expectedCode { + t.Fatal(user, resp.StatusCode, expectedCode) + } + + expectedCode = expectedCodes["ListPaths"] + for _, itemPath := range []string{ + "/", + "admin/", + "admin/files", + "user2/", + "user2/files", + } { + resp, _, errs = filesCl.List(itemPath) + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != expectedCode { + t.Fatal(user, resp.StatusCode, expectedCode) + } + } + + expectedCode = expectedCodes["Mkdir"] + testPath := filepath.Join(lhResp.Cwd, "test") + resp, _, errs = filesCl.Mkdir(testPath) + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != expectedCode { + t.Fatal(user, resp.StatusCode, expectedCode) + } + + expectedCode = expectedCodes["Move"] + newPath := filepath.Join(lhResp.Cwd, "test2") + resp, _, errs = filesCl.Move(testPath, newPath) + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != expectedCode { + t.Fatal(user, resp.StatusCode, expectedCode) + } + + if requireAuth { + resp, _, errs := cl.Logout(token) + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != 200 { + t.Fatal(user, resp.StatusCode, expectedCode) + } + } + } + + testFolderOpPermission("admin", "1234", true, map[string]int{ + "ListHome": 200, + "List": 200, + "ListPaths": 200, + "Mkdir": 200, + "Move": 200, + }) + testFolderOpPermission("user", "1234", true, map[string]int{ + "ListHome": 200, + "List": 200, + "ListPaths": 403, + "Mkdir": 200, + "Move": 200, + }) + testFolderOpPermission("visitor", "", false, map[string]int{ + "ListHome": 403, + "List": 403, + "ListPaths": 403, + "Mkdir": 403, + "Move": 403, + }) + + testFileOpPermission := func(user string, pwd string, requireAuth bool, targetPath, targetFile string, expectedCodes map[string]int) { + // Create(c *gin.Context) { + // UploadChunk(c *gin.Context) { + // UploadStatus(c *gin.Context) { + // Metadata(c *gin.Context) { + // Move(c *gin.Context) { + // Download(c *gin.Context) { + // Delete(c *gin.Context) { + + cl := client.NewSingleUserClient(addr) + token := &http.Cookie{} + if requireAuth { + resp, _, errs := cl.Login(user, pwd) + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != 200 { + t.Fatal(resp.StatusCode) + } + token = client.GetCookie(resp.Cookies(), q.TokenCookie) + } + + expectedCode := expectedCodes["ListHome"] + filesCl := client.NewFilesClient(addr, token) + resp, _, errs := filesCl.ListHome() + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != expectedCode { + t.Fatal(user, resp.StatusCode, expectedCode) + } + + fileContent := []byte("01010") + filePath := filepath.Join(targetPath, "old") + fileSize := int64(len(fileContent)) + expectedCode = expectedCodes["Create"] + resp, _, errs = filesCl.Create(filePath, fileSize) + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != expectedCode { + t.Fatal(user, resp.StatusCode, expectedCode) + } + + expectedCode = expectedCodes["UploadStatus"] + resp, _, errs = filesCl.UploadStatus(filePath) + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != expectedCode { + t.Fatal(user, resp.StatusCode, expectedCode) + } + + expectedCode = expectedCodes["UploadChunk"] + base64Content := base64.StdEncoding.EncodeToString([]byte(fileContent)) + resp, _, errs = filesCl.UploadChunk(filePath, base64Content, 0) + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != expectedCode { + t.Fatal(user, resp.StatusCode, expectedCode) + } + + expectedCode = expectedCodes["Metadata"] + resp, _, errs = filesCl.Metadata(filePath) + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != expectedCode { + t.Fatal(user, resp.StatusCode, expectedCode) + } + + expectedCode = expectedCodes["MetadataTarget"] + resp, _, errs = filesCl.Metadata(targetPath) + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != expectedCode { + t.Fatal(user, resp.StatusCode, expectedCode) + } + + expectedCode = expectedCodes["Download"] + resp, _, errs = filesCl.Download(filePath, map[string]string{}) + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != expectedCode { + t.Fatal(user, resp.StatusCode, expectedCode) + } + + if targetFile != "" { + expectedCode = expectedCodes["DownloadTarget"] + resp, _, errs = filesCl.Download(targetFile, map[string]string{}) + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != expectedCode { + t.Fatal(user, resp.StatusCode, expectedCode) + } + } + + expectedCode = expectedCodes["Move"] + newPath := filepath.Join(targetPath, "new") + resp, _, errs = filesCl.Move(filePath, newPath) + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != expectedCode { + t.Fatal(user, resp.StatusCode, expectedCode) + } + + expectedCode = expectedCodes["Delete"] + resp, _, errs = filesCl.Delete(newPath) + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != expectedCode { + t.Fatal(user, resp.StatusCode, expectedCode) + } + + if requireAuth { + resp, _, errs := cl.Logout(token) + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != 200 { + t.Fatal(user, resp.StatusCode, expectedCode) + } + } + } + + testFileOpPermission("admin", "1234", true, "admin/files", "", map[string]int{ + "ListHome": 200, + "Create": 200, + "UploadChunk": 200, + "UploadStatus": 200, + "Metadata": 200, + "MetadataTarget": 200, + "Move": 200, + "Download": 200, + "Delete": 200, + }) + testFileOpPermission("user", "1234", true, "user/files", "", map[string]int{ + "ListHome": 200, + "Create": 200, + "UploadChunk": 200, + "UploadStatus": 200, + "Metadata": 200, + "MetadataTarget": 200, + "Move": 200, + "Download": 200, + "Delete": 200, + }) + testFileOpPermission("visitor", "", false, "user/files", "", map[string]int{ + "ListHome": 403, + "Create": 403, + "UploadChunk": 403, + "UploadStatus": 403, + "Metadata": 403, + "MetadataTarget": 403, + "Move": 403, + "Download": 403, + "Delete": 403, + }) + testFileOpPermission("admin", "1234", true, "user2/files", "", map[string]int{ + "ListHome": 200, + "Create": 200, + "UploadChunk": 200, + "UploadStatus": 200, + "Metadata": 200, + "MetadataTarget": 200, + "Move": 200, + "Download": 200, + "Delete": 200, + }) + testFileOpPermission("user", "1234", true, "user2/files", "", map[string]int{ + "ListHome": 200, + "Create": 403, + "UploadChunk": 403, + "UploadStatus": 403, + "Metadata": 403, + "MetadataTarget": 403, + "Move": 403, + "Download": 403, + "Delete": 403, + }) + + // test sharing permission + enableSharing := func() { + cl := client.NewSingleUserClient(addr) + token := &http.Cookie{} + + resp, _, errs := cl.Login("share", "1234") + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != 200 { + t.Fatal(resp.StatusCode) + } + token = client.GetCookie(resp.Cookies(), q.TokenCookie) + + filesCl := client.NewFilesClient(addr, token) + resp, _, errs = filesCl.AddSharing("share/files") + if len(errs) > 0 { + t.Fatal(errs) + } else if resp.StatusCode != 200 { + t.Fatal(resp.StatusCode) + } + + assertUploadOK(t, "share/files/share", "101", addr, token) + } + enableSharing() + + testFileOpPermission("user", "1234", true, "share/files", "share/files/share", map[string]int{ + "ListHome": 200, + "Create": 403, + "UploadChunk": 403, + "UploadStatus": 403, + "Metadata": 403, + "MetadataTarget": 403, + "Move": 403, + "Download": 404, + "DownloadTarget": 200, + "Delete": 403, + // List is not tested + }) + }) + + t.Run("Settings API Permissions", func(t *testing.T) { + + }) }