feat(sharing): enable APIs for sharing

This commit is contained in:
hexxa 2021-08-12 18:47:42 +08:00 committed by Hexxa
parent a96f552323
commit df0264ecfd
3 changed files with 109 additions and 11 deletions

View file

@ -88,7 +88,8 @@ func (lk *AutoLocker) Exec(handler func()) {
handler()
}
func (h *FileHandlers) canAccess(userID, role, path string) bool {
// related elements: role, user, action(listing, downloading)/sharing
func (h *FileHandlers) canAccess(userID, role, op, path string) bool {
if role == userstore.AdminRole {
return true
}
@ -97,8 +98,23 @@ func (h *FileHandlers) canAccess(userID, role, path string) bool {
parts := strings.Split(path, "/")
if len(parts) < 1 {
return false
} else if parts[0] == userID {
return true
}
return parts[0] == userID
// check if it is shared
// TODO: find a better approach
if op != "list" && op != "download" {
return false
}
// TODO: improve performance
for i := 1; i <= len(parts); i++ {
_, ok := h.deps.FileInfos().GetSharing(strings.Join(parts[0:i], "/"))
if ok {
return true
}
}
return false
}
type CreateReq struct {
@ -114,7 +130,7 @@ func (h *FileHandlers) Create(c *gin.Context) {
}
role := c.MustGet(q.RoleParam).(string)
userID := c.MustGet(q.UserIDParam).(string)
if !h.canAccess(userID, role, req.Path) {
if !h.canAccess(userID, role, "create", req.Path) {
c.JSON(q.ErrResp(c, 403, q.ErrAccessDenied))
return
}
@ -155,7 +171,7 @@ func (h *FileHandlers) Delete(c *gin.Context) {
}
role := c.MustGet(q.RoleParam).(string)
userID := c.MustGet(q.UserIDParam).(string)
if !h.canAccess(userID, role, filePath) {
if !h.canAccess(userID, role, "delete", filePath) {
c.JSON(q.ErrResp(c, 403, q.ErrAccessDenied))
return
}
@ -184,7 +200,7 @@ func (h *FileHandlers) Metadata(c *gin.Context) {
}
role := c.MustGet(q.RoleParam).(string)
userID := c.MustGet(q.UserIDParam).(string)
if !h.canAccess(userID, role, filePath) {
if !h.canAccess(userID, role, "metadata", filePath) {
c.JSON(q.ErrResp(c, 403, q.ErrAccessDenied))
return
}
@ -215,7 +231,7 @@ func (h *FileHandlers) Mkdir(c *gin.Context) {
}
role := c.MustGet(q.RoleParam).(string)
userID := c.MustGet(q.UserIDParam).(string)
if !h.canAccess(userID, role, req.Path) {
if !h.canAccess(userID, role, "mkdir", req.Path) {
c.JSON(q.ErrResp(c, 403, q.ErrAccessDenied))
return
}
@ -242,7 +258,7 @@ func (h *FileHandlers) Move(c *gin.Context) {
}
role := c.MustGet(q.RoleParam).(string)
userID := c.MustGet(q.UserIDParam).(string)
if !h.canAccess(userID, role, req.OldPath) || !h.canAccess(userID, role, req.NewPath) {
if !h.canAccess(userID, role, "move", req.OldPath) || !h.canAccess(userID, role, "move", req.NewPath) {
c.JSON(q.ErrResp(c, 403, q.ErrAccessDenied))
return
}
@ -285,7 +301,7 @@ func (h *FileHandlers) UploadChunk(c *gin.Context) {
}
role := c.MustGet(q.RoleParam).(string)
userID := c.MustGet(q.UserIDParam).(string)
if !h.canAccess(userID, role, req.Path) {
if !h.canAccess(userID, role, "upload.chunk", req.Path) {
c.JSON(q.ErrResp(c, 403, q.ErrAccessDenied))
return
}
@ -411,7 +427,7 @@ func (h *FileHandlers) UploadStatus(c *gin.Context) {
}
role := c.MustGet(q.RoleParam).(string)
userID := c.MustGet(q.UserIDParam).(string)
if !h.canAccess(userID, role, filePath) {
if !h.canAccess(userID, role, "upload.status", filePath) {
c.JSON(q.ErrResp(c, 403, q.ErrAccessDenied))
return
}
@ -449,7 +465,7 @@ func (h *FileHandlers) Download(c *gin.Context) {
}
role := c.MustGet(q.RoleParam).(string)
userID := c.MustGet(q.UserIDParam).(string)
if !h.canAccess(userID, role, filePath) {
if !h.canAccess(userID, role, "download", filePath) {
c.JSON(q.ErrResp(c, 403, q.ErrAccessDenied))
return
}
@ -545,7 +561,7 @@ func (h *FileHandlers) List(c *gin.Context) {
}
role := c.MustGet(q.RoleParam).(string)
userID := c.MustGet(q.UserIDParam).(string)
if !h.canAccess(userID, role, dirPath) {
if !h.canAccess(userID, role, "list", dirPath) {
c.JSON(q.ErrResp(c, 403, q.ErrAccessDenied))
return
}
@ -649,6 +665,78 @@ func (h *FileHandlers) DelUploading(c *gin.Context) {
})
}
type SharingReq struct {
SharingPath string `json:"sharingPath"`
}
func (h *FileHandlers) AddSharing(c *gin.Context) {
req := &SharingReq{}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(q.ErrResp(c, 400, err))
return
}
// TODO: move canAccess to authedFS
userID := c.MustGet(q.UserIDParam).(string)
role := c.MustGet(q.RoleParam).(string)
// op is empty, because users must be admin, or the path belongs to this user
if !h.canAccess(userID, role, "", req.SharingPath) {
c.JSON(q.ErrResp(c, 403, errors.New("forbidden")))
return
}
err := h.deps.FileInfos().AddSharing(req.SharingPath)
if err != nil {
c.JSON(q.ErrResp(c, 500, err))
return
}
c.JSON(q.Resp(200))
}
func (h *FileHandlers) DelSharing(c *gin.Context) {
req := &SharingReq{}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(q.ErrResp(c, 400, err))
return
}
// TODO: move canAccess to authedFS
userID := c.MustGet(q.UserIDParam).(string)
role := c.MustGet(q.RoleParam).(string)
if !h.canAccess(userID, role, "", req.SharingPath) {
c.JSON(q.ErrResp(c, 403, errors.New("forbidden")))
return
}
err := h.deps.FileInfos().DelSharing(req.SharingPath)
if err != nil {
c.JSON(q.ErrResp(c, 500, err))
return
}
c.JSON(q.Resp(200))
}
type SharingResp struct {
SharingDirs []string `json:"sharingPaths"`
}
func (h *FileHandlers) ListSharings(c *gin.Context) {
// TODO: move canAccess to authedFS
userID := c.MustGet(q.UserIDParam).(string)
sharingDirs, err := h.deps.FileInfos().ListSharings(q.FsRootPath(userID, "/"))
if err != nil {
c.JSON(q.ErrResp(c, 500, err))
return
}
dirs := []string{}
for sharingDir := range sharingDirs {
dirs = append(dirs, sharingDir)
}
c.JSON(200, &SharingResp{SharingDirs: dirs})
}
func (h *FileHandlers) GetStreamReader(userID uint64, fd io.Reader) (io.Reader, error) {
pr, pw := io.Pipe()
chunkSize := 100 * 1024 // notice: it can not be greater than limiter's token count

View file

@ -64,6 +64,9 @@ func NewMultiUsersSvc(cfg gocfg.ICfg, deps *depidx.Deps) (*MultiUsersSvc, error)
apiRuleCname(userstore.AdminRole, "OPTIONS", "/v1/settings/health"): true,
apiRuleCname(userstore.AdminRole, "GET", "/v1/captchas/"): true,
apiRuleCname(userstore.AdminRole, "GET", "/v1/captchas/imgs"): true,
apiRuleCname(userstore.AdminRole, "POST", "/v1/fs/sharings"): true,
apiRuleCname(userstore.AdminRole, "DELETE", "/v1/fs/sharings"): true,
apiRuleCname(userstore.AdminRole, "GET", "/v1/fs/sharings"): true,
// user rules
apiRuleCname(userstore.UserRole, "GET", "/"): true,
apiRuleCname(userstore.UserRole, "GET", publicPath): true,
@ -87,6 +90,9 @@ func NewMultiUsersSvc(cfg gocfg.ICfg, deps *depidx.Deps) (*MultiUsersSvc, error)
apiRuleCname(userstore.UserRole, "OPTIONS", "/v1/settings/health"): true,
apiRuleCname(userstore.UserRole, "GET", "/v1/captchas/"): true,
apiRuleCname(userstore.UserRole, "GET", "/v1/captchas/imgs"): true,
apiRuleCname(userstore.UserRole, "POST", "/v1/fs/sharings"): true,
apiRuleCname(userstore.UserRole, "DELETE", "/v1/fs/sharings"): true,
apiRuleCname(userstore.UserRole, "GET", "/v1/fs/sharings"): true,
// visitor rules
apiRuleCname(userstore.VisitorRole, "GET", "/"): true,
apiRuleCname(userstore.VisitorRole, "GET", publicPath): true,

View file

@ -222,6 +222,10 @@ func initHandlers(router *gin.Engine, cfg gocfg.ICfg, deps *depidx.Deps) (*gin.E
filesAPI.GET("/uploadings", fileHdrs.ListUploadings)
filesAPI.DELETE("/uploadings", fileHdrs.DelUploading)
filesAPI.POST("/sharings", fileHdrs.AddSharing)
filesAPI.DELETE("/sharings", fileHdrs.DelSharing)
filesAPI.GET("/sharings", fileHdrs.ListSharings)
filesAPI.GET("/metadata", fileHdrs.Metadata)
settingsAPI := v1.Group("/settings")