mirror of https://github.com/Xhofe/alist
chore: user permissions
parent
3c7a2f78cf
commit
d24e51bc86
|
@ -20,14 +20,11 @@ func initDevData() {
|
||||||
log.Fatalf("failed to create account: %+v", err)
|
log.Fatalf("failed to create account: %+v", err)
|
||||||
}
|
}
|
||||||
err = db.CreateUser(&model.User{
|
err = db.CreateUser(&model.User{
|
||||||
Username: "Noah",
|
Username: "Noah",
|
||||||
Password: "hsu",
|
Password: "hsu",
|
||||||
BasePath: "/data",
|
BasePath: "/data",
|
||||||
ReadOnly: false,
|
Role: 0,
|
||||||
Webdav: false,
|
Permission: 512,
|
||||||
Role: 0,
|
|
||||||
IgnoreHide: false,
|
|
||||||
IgnorePassword: false,
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to create user: %+v", err)
|
log.Fatalf("failed to create user: %+v", err)
|
||||||
|
|
|
@ -23,7 +23,6 @@ func initUser() {
|
||||||
Password: adminPassword,
|
Password: adminPassword,
|
||||||
Role: model.ADMIN,
|
Role: model.ADMIN,
|
||||||
BasePath: "/",
|
BasePath: "/",
|
||||||
Webdav: true,
|
|
||||||
}
|
}
|
||||||
if err := db.CreateUser(admin); err != nil {
|
if err := db.CreateUser(admin); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -36,12 +35,11 @@ func initUser() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
guest = &model.User{
|
guest = &model.User{
|
||||||
Username: "guest",
|
Username: "guest",
|
||||||
Password: "guest",
|
Password: "guest",
|
||||||
ReadOnly: true,
|
Role: model.GUEST,
|
||||||
Webdav: true,
|
BasePath: "/",
|
||||||
Role: model.GUEST,
|
Permission: 512,
|
||||||
BasePath: "/",
|
|
||||||
}
|
}
|
||||||
if err := db.CreateUser(guest); err != nil {
|
if err := db.CreateUser(guest); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package errs
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var (
|
||||||
|
PermissionDenied = errors.New("permission denied")
|
||||||
|
)
|
|
@ -66,7 +66,7 @@ func whetherHide(user *model.User, meta *model.Meta, path string) bool {
|
||||||
if user.IsGuest() {
|
if user.IsGuest() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return !user.IgnoreHide
|
return !user.CanSeeHides()
|
||||||
}
|
}
|
||||||
|
|
||||||
func hide(objs []model.Obj, meta *model.Meta) {
|
func hide(objs []model.Obj, meta *model.Meta) {
|
||||||
|
|
|
@ -12,16 +12,24 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
ID uint `json:"id" gorm:"primaryKey"` // unique key
|
ID uint `json:"id" gorm:"primaryKey"` // unique key
|
||||||
Username string `json:"username" gorm:"unique" binding:"required"` // username
|
Username string `json:"username" gorm:"unique" binding:"required"` // username
|
||||||
Password string `json:"password"` // password
|
Password string `json:"password"` // password
|
||||||
BasePath string `json:"base_path"` // base path
|
BasePath string `json:"base_path"` // base path
|
||||||
ReadOnly bool `json:"read_only"` // read only
|
Role int `json:"role"` // user's role
|
||||||
Webdav bool `json:"webdav"` // allow webdav
|
// Determine permissions by bit
|
||||||
Role int `json:"role"` // user's role
|
// 0: can see hidden files
|
||||||
IgnoreHide bool `json:"can_hide"` // can see hide files
|
// 1: can access without password
|
||||||
IgnorePassword bool `json:"ignore_password"` // can access without password
|
// 2: can add aria2 tasks
|
||||||
Aira2 bool `json:"aira_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 {
|
func (u User) IsGuest() bool {
|
||||||
|
@ -42,6 +50,46 @@ func (u User) ValidatePassword(password string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u User) CanWrite() bool {
|
func (u User) CanSeeHides() bool {
|
||||||
return u.IsAdmin() || !u.ReadOnly
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ type AddAria2Req struct {
|
||||||
|
|
||||||
func AddAria2(c *gin.Context) {
|
func AddAria2(c *gin.Context) {
|
||||||
user := c.MustGet("user").(*model.User)
|
user := c.MustGet("user").(*model.User)
|
||||||
if !user.IsAdmin() && !user.Aira2 {
|
if !user.CanAddAria2Tasks() {
|
||||||
common.ErrorStrResp(c, "permission denied", 403)
|
common.ErrorStrResp(c, "permission denied", 403)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package controllers
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/alist-org/alist/v3/internal/db"
|
"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/fs"
|
||||||
"github.com/alist-org/alist/v3/internal/model"
|
"github.com/alist-org/alist/v3/internal/model"
|
||||||
"github.com/alist-org/alist/v3/internal/sign"
|
"github.com/alist-org/alist/v3/internal/sign"
|
||||||
|
@ -25,14 +26,14 @@ func FsMkdir(c *gin.Context) {
|
||||||
}
|
}
|
||||||
user := c.MustGet("user").(*model.User)
|
user := c.MustGet("user").(*model.User)
|
||||||
req.Path = stdpath.Join(user.BasePath, req.Path)
|
req.Path = stdpath.Join(user.BasePath, req.Path)
|
||||||
if !user.CanWrite() {
|
if !user.CanMkdir() {
|
||||||
meta, err := db.GetNearestMeta(req.Path)
|
meta, err := db.GetNearestMeta(req.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.ErrorResp(c, err, 500)
|
common.ErrorResp(c, err, 500)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !canMkdirOrPut(meta, req.Path) {
|
if !canMkdirOrPut(meta, req.Path) {
|
||||||
common.ErrorStrResp(c, "Permission denied", 403)
|
common.ErrorResp(c, errs.PermissionDenied, 403)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,6 +68,10 @@ func FsMove(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user := c.MustGet("user").(*model.User)
|
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.SrcDir = stdpath.Join(user.BasePath, req.SrcDir)
|
||||||
req.DstDir = stdpath.Join(user.BasePath, req.DstDir)
|
req.DstDir = stdpath.Join(user.BasePath, req.DstDir)
|
||||||
for _, name := range req.Names {
|
for _, name := range req.Names {
|
||||||
|
@ -90,6 +95,10 @@ func FsCopy(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user := c.MustGet("user").(*model.User)
|
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.SrcDir = stdpath.Join(user.BasePath, req.SrcDir)
|
||||||
req.DstDir = stdpath.Join(user.BasePath, req.DstDir)
|
req.DstDir = stdpath.Join(user.BasePath, req.DstDir)
|
||||||
var addedTask []string
|
var addedTask []string
|
||||||
|
@ -122,6 +131,10 @@ func FsRename(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user := c.MustGet("user").(*model.User)
|
user := c.MustGet("user").(*model.User)
|
||||||
|
if !user.CanRename() {
|
||||||
|
common.ErrorResp(c, errs.PermissionDenied, 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
req.Path = stdpath.Join(user.BasePath, req.Path)
|
req.Path = stdpath.Join(user.BasePath, req.Path)
|
||||||
if err := fs.Rename(c, req.Path, req.Name); err != nil {
|
if err := fs.Rename(c, req.Path, req.Name); err != nil {
|
||||||
common.ErrorResp(c, err, 500)
|
common.ErrorResp(c, err, 500)
|
||||||
|
@ -146,6 +159,10 @@ func FsRemove(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user := c.MustGet("user").(*model.User)
|
user := c.MustGet("user").(*model.User)
|
||||||
|
if !user.CanRemove() {
|
||||||
|
common.ErrorResp(c, errs.PermissionDenied, 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
req.Path = stdpath.Join(user.BasePath, req.Path)
|
req.Path = stdpath.Join(user.BasePath, req.Path)
|
||||||
for _, name := range req.Names {
|
for _, name := range req.Names {
|
||||||
err := fs.Remove(c, stdpath.Join(req.Path, name))
|
err := fs.Remove(c, stdpath.Join(req.Path, name))
|
||||||
|
@ -161,14 +178,14 @@ func FsPut(c *gin.Context) {
|
||||||
path := c.GetHeader("File-Path")
|
path := c.GetHeader("File-Path")
|
||||||
user := c.MustGet("user").(*model.User)
|
user := c.MustGet("user").(*model.User)
|
||||||
path = stdpath.Join(user.BasePath, path)
|
path = stdpath.Join(user.BasePath, path)
|
||||||
if !user.CanWrite() {
|
if !user.CanUpload() {
|
||||||
meta, err := db.GetNearestMeta(path)
|
meta, err := db.GetNearestMeta(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.ErrorResp(c, err, 500)
|
common.ErrorResp(c, err, 500)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !canMkdirOrPut(meta, path) {
|
if !canMkdirOrPut(meta, path) {
|
||||||
common.ErrorStrResp(c, "Permission denied", 403)
|
common.ErrorResp(c, errs.PermissionDenied, 403)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ func FsList(c *gin.Context) {
|
||||||
|
|
||||||
func canAccess(user *model.User, meta *model.Meta, path string, password string) bool {
|
func canAccess(user *model.User, meta *model.Meta, path string, password string) bool {
|
||||||
// if is not guest, can access
|
// if is not guest, can access
|
||||||
if user.IsAdmin() || user.IgnorePassword {
|
if user.CanAccessWithoutPassword() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// if meta is nil or password is empty, can access
|
// if meta is nil or password is empty, can access
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
package controllers
|
|
@ -60,13 +60,3 @@ func AuthAdmin(c *gin.Context) {
|
||||||
c.Next()
|
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()
|
|
||||||
}
|
|
||||||
|
|
|
@ -51,20 +51,24 @@ func Init(r *gin.Engine) {
|
||||||
setting.POST("/save", controllers.SaveSettings)
|
setting.POST("/save", controllers.SaveSettings)
|
||||||
setting.POST("/delete", controllers.DeleteSetting)
|
setting.POST("/delete", controllers.DeleteSetting)
|
||||||
setting.POST("/reset_token", controllers.ResetToken)
|
setting.POST("/reset_token", controllers.ResetToken)
|
||||||
|
setting.POST("/set_aria2", controllers.SetAria2)
|
||||||
|
|
||||||
|
// guest can
|
||||||
public := api.Group("/public")
|
public := api.Group("/public")
|
||||||
public.GET("/settings", controllers.PublicSettings)
|
public.GET("/settings", controllers.PublicSettings)
|
||||||
public.Any("/list", controllers.FsList)
|
public.Any("/list", controllers.FsList)
|
||||||
public.Any("/get", controllers.FsGet)
|
public.Any("/get", controllers.FsGet)
|
||||||
|
|
||||||
|
// gust can't
|
||||||
fs := api.Group("/fs")
|
fs := api.Group("/fs")
|
||||||
fs.POST("/mkdir", controllers.FsMkdir)
|
fs.POST("/mkdir", controllers.FsMkdir)
|
||||||
fs.POST("/rename", middlewares.AuthManage, controllers.FsRename)
|
fs.POST("/rename", controllers.FsRename)
|
||||||
fs.POST("/move", middlewares.AuthManage, controllers.FsMove)
|
fs.POST("/move", controllers.FsMove)
|
||||||
fs.POST("/copy", middlewares.AuthManage, controllers.FsCopy)
|
fs.POST("/copy", controllers.FsCopy)
|
||||||
fs.POST("/remove", middlewares.AuthManage, controllers.FsRemove)
|
fs.POST("/remove", controllers.FsRemove)
|
||||||
fs.POST("/put", controllers.FsPut)
|
fs.POST("/put", controllers.FsPut)
|
||||||
fs.POST("/link", middlewares.AuthAdmin, controllers.Link)
|
fs.POST("/link", middlewares.AuthAdmin, controllers.Link)
|
||||||
|
fs.POST("/add_aria2", controllers.AddAria2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Cors(r *gin.Engine) {
|
func Cors(r *gin.Engine) {
|
||||||
|
|
Loading…
Reference in New Issue