diff --git a/internal/bootstrap/data/dev.go b/internal/bootstrap/data/dev.go index cb73a11b..2d360062 100644 --- a/internal/bootstrap/data/dev.go +++ b/internal/bootstrap/data/dev.go @@ -20,14 +20,11 @@ func initDevData() { log.Fatalf("failed to create account: %+v", err) } err = db.CreateUser(&model.User{ - Username: "Noah", - Password: "hsu", - BasePath: "/data", - ReadOnly: false, - Webdav: false, - Role: 0, - IgnoreHide: false, - IgnorePassword: false, + Username: "Noah", + Password: "hsu", + BasePath: "/data", + Role: 0, + Permission: 512, }) if err != nil { log.Fatalf("failed to create user: %+v", err) diff --git a/internal/bootstrap/data/user.go b/internal/bootstrap/data/user.go index b3f7a7bd..77147f06 100644 --- a/internal/bootstrap/data/user.go +++ b/internal/bootstrap/data/user.go @@ -23,7 +23,6 @@ func initUser() { Password: adminPassword, Role: model.ADMIN, BasePath: "/", - Webdav: true, } if err := db.CreateUser(admin); err != nil { panic(err) @@ -36,12 +35,11 @@ func initUser() { if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { guest = &model.User{ - Username: "guest", - Password: "guest", - ReadOnly: true, - Webdav: true, - Role: model.GUEST, - BasePath: "/", + Username: "guest", + Password: "guest", + Role: model.GUEST, + BasePath: "/", + Permission: 512, } if err := db.CreateUser(guest); err != nil { panic(err) diff --git a/internal/errs/operate.go b/internal/errs/operate.go new file mode 100644 index 00000000..92fbd6a1 --- /dev/null +++ b/internal/errs/operate.go @@ -0,0 +1,7 @@ +package errs + +import "errors" + +var ( + PermissionDenied = errors.New("permission denied") +) diff --git a/internal/fs/list.go b/internal/fs/list.go index e60f307f..103e6682 100644 --- a/internal/fs/list.go +++ b/internal/fs/list.go @@ -66,7 +66,7 @@ func whetherHide(user *model.User, meta *model.Meta, path string) bool { if user.IsGuest() { return true } - return !user.IgnoreHide + return !user.CanSeeHides() } func hide(objs []model.Obj, meta *model.Meta) { diff --git a/internal/model/user.go b/internal/model/user.go index ba18d831..f6bb5556 100644 --- a/internal/model/user.go +++ b/internal/model/user.go @@ -12,16 +12,24 @@ const ( ) type User struct { - ID uint `json:"id" gorm:"primaryKey"` // unique key - Username string `json:"username" gorm:"unique" binding:"required"` // username - Password string `json:"password"` // password - BasePath string `json:"base_path"` // base path - ReadOnly bool `json:"read_only"` // read only - Webdav bool `json:"webdav"` // allow webdav - Role int `json:"role"` // user's role - IgnoreHide bool `json:"can_hide"` // can see hide files - IgnorePassword bool `json:"ignore_password"` // can access without password - Aira2 bool `json:"aira_2"` // can add aria2 tasks + ID uint `json:"id" gorm:"primaryKey"` // unique key + Username string `json:"username" gorm:"unique" binding:"required"` // username + Password string `json:"password"` // password + BasePath string `json:"base_path"` // base path + Role int `json:"role"` // user's role + // Determine permissions by bit + // 0: can see hidden files + // 1: can access without password + // 2: can add aria2 tasks + // 3: can mkdir + // 4: can upload + // 5: can rename + // 6: can move + // 7: can copy + // 8: can remove + // 9: webdav read + // 10: webdav write + Permission int32 `json:"permission"` } func (u User) IsGuest() bool { @@ -42,6 +50,46 @@ func (u User) ValidatePassword(password string) error { return nil } -func (u User) CanWrite() bool { - return u.IsAdmin() || !u.ReadOnly +func (u User) CanSeeHides() bool { + return u.IsAdmin() || u.Permission&1 == 1 +} + +func (u User) CanAccessWithoutPassword() bool { + return u.IsAdmin() || (u.Permission>>1)&1 == 1 +} + +func (u User) CanAddAria2Tasks() bool { + return u.IsAdmin() || (u.Permission>>2)&1 == 1 +} + +func (u User) CanMkdir() bool { + return u.IsAdmin() || (u.Permission>>3)&1 == 1 +} + +func (u User) CanUpload() bool { + return u.IsAdmin() || (u.Permission>>4)&1 == 1 +} + +func (u User) CanRename() bool { + return u.IsAdmin() || (u.Permission>>5)&1 == 1 +} + +func (u User) CanMove() bool { + return u.IsAdmin() || (u.Permission>>6)&1 == 1 +} + +func (u User) CanCopy() bool { + return u.IsAdmin() || (u.Permission>>7)&1 == 1 +} + +func (u User) CanRemove() bool { + return u.IsAdmin() || (u.Permission>>8)&1 == 1 +} + +func (u User) CanWebdavRead() bool { + return u.IsAdmin() || (u.Permission>>9)&1 == 1 +} + +func (u User) CanWebdavWrite() bool { + return u.IsAdmin() || (u.Permission>>10)&1 == 1 } diff --git a/server/controllers/aria2.go b/server/controllers/aria2.go index 41438450..91241173 100644 --- a/server/controllers/aria2.go +++ b/server/controllers/aria2.go @@ -44,7 +44,7 @@ type AddAria2Req struct { func AddAria2(c *gin.Context) { user := c.MustGet("user").(*model.User) - if !user.IsAdmin() && !user.Aira2 { + if !user.CanAddAria2Tasks() { common.ErrorStrResp(c, "permission denied", 403) return } diff --git a/server/controllers/fsmanage.go b/server/controllers/fsmanage.go index 98d82f21..5ab9dfe0 100644 --- a/server/controllers/fsmanage.go +++ b/server/controllers/fsmanage.go @@ -3,6 +3,7 @@ package controllers import ( "fmt" "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/internal/sign" @@ -25,14 +26,14 @@ func FsMkdir(c *gin.Context) { } user := c.MustGet("user").(*model.User) req.Path = stdpath.Join(user.BasePath, req.Path) - if !user.CanWrite() { + if !user.CanMkdir() { meta, err := db.GetNearestMeta(req.Path) if err != nil { common.ErrorResp(c, err, 500) return } if !canMkdirOrPut(meta, req.Path) { - common.ErrorStrResp(c, "Permission denied", 403) + common.ErrorResp(c, errs.PermissionDenied, 403) return } } @@ -67,6 +68,10 @@ func FsMove(c *gin.Context) { return } user := c.MustGet("user").(*model.User) + if !user.CanMove() { + common.ErrorResp(c, errs.PermissionDenied, 403) + return + } req.SrcDir = stdpath.Join(user.BasePath, req.SrcDir) req.DstDir = stdpath.Join(user.BasePath, req.DstDir) for _, name := range req.Names { @@ -90,6 +95,10 @@ func FsCopy(c *gin.Context) { return } user := c.MustGet("user").(*model.User) + if !user.CanCopy() { + common.ErrorResp(c, errs.PermissionDenied, 403) + return + } req.SrcDir = stdpath.Join(user.BasePath, req.SrcDir) req.DstDir = stdpath.Join(user.BasePath, req.DstDir) var addedTask []string @@ -122,6 +131,10 @@ func FsRename(c *gin.Context) { return } user := c.MustGet("user").(*model.User) + if !user.CanRename() { + common.ErrorResp(c, errs.PermissionDenied, 403) + return + } req.Path = stdpath.Join(user.BasePath, req.Path) if err := fs.Rename(c, req.Path, req.Name); err != nil { common.ErrorResp(c, err, 500) @@ -146,6 +159,10 @@ func FsRemove(c *gin.Context) { return } user := c.MustGet("user").(*model.User) + if !user.CanRemove() { + common.ErrorResp(c, errs.PermissionDenied, 403) + return + } req.Path = stdpath.Join(user.BasePath, req.Path) for _, name := range req.Names { err := fs.Remove(c, stdpath.Join(req.Path, name)) @@ -161,14 +178,14 @@ func FsPut(c *gin.Context) { path := c.GetHeader("File-Path") user := c.MustGet("user").(*model.User) path = stdpath.Join(user.BasePath, path) - if !user.CanWrite() { + if !user.CanUpload() { meta, err := db.GetNearestMeta(path) if err != nil { common.ErrorResp(c, err, 500) return } if !canMkdirOrPut(meta, path) { - common.ErrorStrResp(c, "Permission denied", 403) + common.ErrorResp(c, errs.PermissionDenied, 403) return } } diff --git a/server/controllers/fsread.go b/server/controllers/fsread.go index 548b5ad1..7bdcf521 100644 --- a/server/controllers/fsread.go +++ b/server/controllers/fsread.go @@ -71,7 +71,7 @@ func FsList(c *gin.Context) { func canAccess(user *model.User, meta *model.Meta, path string, password string) bool { // if is not guest, can access - if user.IsAdmin() || user.IgnorePassword { + if user.CanAccessWithoutPassword() { return true } // if meta is nil or password is empty, can access diff --git a/server/controllers/task.go b/server/controllers/task.go new file mode 100644 index 00000000..2d329367 --- /dev/null +++ b/server/controllers/task.go @@ -0,0 +1 @@ +package controllers diff --git a/server/middlewares/auth.go b/server/middlewares/auth.go index 38abe0ac..0570f53b 100644 --- a/server/middlewares/auth.go +++ b/server/middlewares/auth.go @@ -60,13 +60,3 @@ func AuthAdmin(c *gin.Context) { c.Next() } } - -func AuthManage(c *gin.Context) { - user := c.MustGet("user").(*model.User) - if user.CanWrite() { - c.Next() - return - } - common.ErrorStrResp(c, "You have no write access", 403) - c.Abort() -} diff --git a/server/router.go b/server/router.go index f0fd6345..cd123d40 100644 --- a/server/router.go +++ b/server/router.go @@ -51,20 +51,24 @@ func Init(r *gin.Engine) { setting.POST("/save", controllers.SaveSettings) setting.POST("/delete", controllers.DeleteSetting) setting.POST("/reset_token", controllers.ResetToken) + setting.POST("/set_aria2", controllers.SetAria2) + // guest can public := api.Group("/public") public.GET("/settings", controllers.PublicSettings) public.Any("/list", controllers.FsList) public.Any("/get", controllers.FsGet) + // gust can't fs := api.Group("/fs") fs.POST("/mkdir", controllers.FsMkdir) - fs.POST("/rename", middlewares.AuthManage, controllers.FsRename) - fs.POST("/move", middlewares.AuthManage, controllers.FsMove) - fs.POST("/copy", middlewares.AuthManage, controllers.FsCopy) - fs.POST("/remove", middlewares.AuthManage, controllers.FsRemove) + fs.POST("/rename", controllers.FsRename) + fs.POST("/move", controllers.FsMove) + fs.POST("/copy", controllers.FsCopy) + fs.POST("/remove", controllers.FsRemove) fs.POST("/put", controllers.FsPut) fs.POST("/link", middlewares.AuthAdmin, controllers.Link) + fs.POST("/add_aria2", controllers.AddAria2) } func Cors(r *gin.Engine) {