diff --git a/server/common/check.go b/server/common/check.go new file mode 100644 index 00000000..afed353e --- /dev/null +++ b/server/common/check.go @@ -0,0 +1,30 @@ +package common + +import ( + "github.com/alist-org/alist/v3/internal/model" + "github.com/alist-org/alist/v3/pkg/utils" +) + +func CanWrite(meta *model.Meta, path string) bool { + if meta == nil || !meta.Write { + return false + } + return meta.WSub || meta.Path == path +} + +func CanAccess(user *model.User, meta *model.Meta, path string, password string) bool { + // if is not guest, can access + if user.CanAccessWithoutPassword() { + return true + } + // if meta is nil or password is empty, can access + if meta == nil || meta.Password == "" { + return true + } + // if meta doesn't apply to sub_folder, can access + if !utils.PathEqual(meta.Path, path) && !meta.PSub { + return true + } + // validate password + return meta.Password == password +} diff --git a/server/handles/fsmanage.go b/server/handles/fsmanage.go index 3ab97b1f..dc2f9787 100644 --- a/server/handles/fsmanage.go +++ b/server/handles/fsmanage.go @@ -35,7 +35,7 @@ func FsMkdir(c *gin.Context) { return } } - if !canWrite(meta, req.Path) { + if !common.CanWrite(meta, req.Path) { common.ErrorResp(c, errs.PermissionDenied, 403) return } @@ -48,13 +48,6 @@ func FsMkdir(c *gin.Context) { common.SuccessResp(c) } -func canWrite(meta *model.Meta, path string) bool { - if meta == nil || !meta.Write { - return false - } - return meta.WSub || meta.Path == path -} - type MoveCopyReq struct { SrcDir string `json:"src_dir"` DstDir string `json:"dst_dir"` diff --git a/server/handles/fsread.go b/server/handles/fsread.go index 8e546bdb..106c87ae 100644 --- a/server/handles/fsread.go +++ b/server/handles/fsread.go @@ -66,11 +66,11 @@ func FsList(c *gin.Context) { } } c.Set("meta", meta) - if !canAccess(user, meta, req.Path, req.Password) { + if !common.CanAccess(user, meta, req.Path, req.Password) { common.ErrorStrResp(c, "password is incorrect", 403) return } - if !user.CanWrite() && !canWrite(meta, req.Path) && req.Refresh { + if !user.CanWrite() && !common.CanWrite(meta, req.Path) && req.Refresh { common.ErrorStrResp(c, "Refresh without permission", 403) return } @@ -89,7 +89,7 @@ func FsList(c *gin.Context) { Content: toObjResp(objs, req.Path, isEncrypt(meta, req.Path)), Total: int64(total), Readme: getReadme(meta, req.Path), - Write: user.CanWrite() || canWrite(meta, req.Path), + Write: user.CanWrite() || common.CanWrite(meta, req.Path), Provider: provider, }) } @@ -117,7 +117,7 @@ func FsDirs(c *gin.Context) { } } c.Set("meta", meta) - if !canAccess(user, meta, req.Path, req.Password) { + if !common.CanAccess(user, meta, req.Path, req.Password) { common.ErrorStrResp(c, "password is incorrect", 403) return } @@ -155,23 +155,6 @@ func getReadme(meta *model.Meta, path string) string { return "" } -func canAccess(user *model.User, meta *model.Meta, path string, password string) bool { - // if is not guest, can access - if user.CanAccessWithoutPassword() { - return true - } - // if meta is nil or password is empty, can access - if meta == nil || meta.Password == "" { - return true - } - // if meta doesn't apply to sub_folder, can access - if !utils.PathEqual(meta.Path, path) && !meta.PSub { - return true - } - // validate password - return meta.Password == password -} - func isEncrypt(meta *model.Meta, path string) bool { if meta == nil || meta.Password == "" { return false @@ -249,7 +232,7 @@ func FsGet(c *gin.Context) { } } c.Set("meta", meta) - if !canAccess(user, meta, req.Path, req.Password) { + if !common.CanAccess(user, meta, req.Path, req.Password) { common.ErrorStrResp(c, "password is incorrect", 403) return } @@ -355,7 +338,7 @@ func FsOther(c *gin.Context) { } } c.Set("meta", meta) - if !canAccess(user, meta, req.Path, req.Password) { + if !common.CanAccess(user, meta, req.Path, req.Password) { common.ErrorStrResp(c, "password is incorrect", 403) return } diff --git a/server/handles/fsup.go b/server/handles/fsup.go index 185cec1c..a5f466f4 100644 --- a/server/handles/fsup.go +++ b/server/handles/fsup.go @@ -6,13 +6,10 @@ import ( "strconv" "time" - "github.com/alist-org/alist/v3/internal/db" - "github.com/alist-org/alist/v3/internal/errs" "github.com/alist-org/alist/v3/internal/fs" "github.com/alist-org/alist/v3/internal/model" "github.com/alist-org/alist/v3/server/common" "github.com/gin-gonic/gin" - "github.com/pkg/errors" ) func FsStream(c *gin.Context) { @@ -25,19 +22,6 @@ func FsStream(c *gin.Context) { asTask := c.GetHeader("As-Task") == "true" user := c.MustGet("user").(*model.User) path = stdpath.Join(user.BasePath, path) - if !user.CanWrite() { - meta, err := db.GetNearestMeta(stdpath.Dir(path)) - if err != nil { - if !errors.Is(errors.Cause(err), errs.MetaNotFound) { - common.ErrorResp(c, err, 500, true) - return - } - } - if !canWrite(meta, path) { - common.ErrorResp(c, errs.PermissionDenied, 403) - return - } - } dir, name := stdpath.Split(path) sizeStr := c.GetHeader("Content-Length") @@ -78,19 +62,7 @@ func FsForm(c *gin.Context) { asTask := c.GetHeader("As-Task") == "true" user := c.MustGet("user").(*model.User) path = stdpath.Join(user.BasePath, path) - if !user.CanWrite() { - meta, err := db.GetNearestMeta(stdpath.Dir(path)) - if err != nil { - if !errors.Is(errors.Cause(err), errs.MetaNotFound) { - common.ErrorResp(c, err, 500, true) - return - } - } - if !canWrite(meta, path) { - common.ErrorResp(c, errs.PermissionDenied, 403) - return - } - } + storage, err := fs.GetStorage(path) if err != nil { common.ErrorResp(c, err, 400) diff --git a/server/middlewares/fsup.go b/server/middlewares/fsup.go new file mode 100644 index 00000000..91b9f470 --- /dev/null +++ b/server/middlewares/fsup.go @@ -0,0 +1,40 @@ +package middlewares + +import ( + "net/url" + stdpath "path" + + "github.com/alist-org/alist/v3/internal/db" + "github.com/alist-org/alist/v3/internal/errs" + "github.com/alist-org/alist/v3/internal/model" + "github.com/alist-org/alist/v3/server/common" + "github.com/gin-gonic/gin" + "github.com/pkg/errors" +) + +func FsUp(c *gin.Context) { + path := c.GetHeader("File-Path") + password := c.GetHeader("Password") + path, err := url.PathUnescape(path) + if err != nil { + common.ErrorResp(c, err, 400) + c.Abort() + return + } + user := c.MustGet("user").(*model.User) + path = stdpath.Join(user.BasePath, path) + meta, err := db.GetNearestMeta(stdpath.Dir(path)) + if err != nil { + if !errors.Is(errors.Cause(err), errs.MetaNotFound) { + common.ErrorResp(c, err, 500, true) + c.Abort() + return + } + } + if !(common.CanAccess(user, meta, path, password) && (user.CanWrite() || common.CanWrite(meta, path))) { + common.ErrorResp(c, errs.PermissionDenied, 403) + c.Abort() + return + } + c.Next() +} diff --git a/server/router.go b/server/router.go index 098ffeba..c7bd26b7 100644 --- a/server/router.go +++ b/server/router.go @@ -119,8 +119,8 @@ func _fs(g *gin.RouterGroup) { g.POST("/move", handles.FsMove) g.POST("/copy", handles.FsCopy) g.POST("/remove", handles.FsRemove) - g.PUT("/put", handles.FsStream) - g.PUT("/form", handles.FsForm) + g.PUT("/put", middlewares.FsUp, handles.FsStream) + g.PUT("/form", middlewares.FsUp, handles.FsForm) g.POST("/link", middlewares.AuthAdmin, handles.Link) g.POST("/add_aria2", handles.AddAria2) } @@ -128,6 +128,6 @@ func _fs(g *gin.RouterGroup) { func Cors(r *gin.Engine) { config := cors.DefaultConfig() config.AllowAllOrigins = true - config.AllowHeaders = append(config.AllowHeaders, "Authorization", "range", "File-Path", "As-Task") + config.AllowHeaders = append(config.AllowHeaders, "Authorization", "range", "File-Path", "As-Task", "Password") r.Use(cors.New(config)) }