diff --git a/internal/bootstrap/data/user.go b/internal/bootstrap/data/user.go index 2e0fc3e8..b12d32e5 100644 --- a/internal/bootstrap/data/user.go +++ b/internal/bootstrap/data/user.go @@ -26,17 +26,17 @@ func initUser() { if errors.Is(err, gorm.ErrRecordNotFound) { admin = &model.User{ Username: "admin", - Password: adminPassword, + PwdHash: model.HashPwd(adminPassword), Role: model.ADMIN, BasePath: "/", } if err := op.CreateUser(admin); err != nil { panic(err) } else { - utils.Log.Infof("Successfully created the admin user and the initial password is: %s", admin.Password) + utils.Log.Infof("Successfully created the admin user and the initial password is: %s", adminPassword) } } else { - panic(err) + utils.Log.Fatalf("[init user] Failed to get admin user: %v", err) } } guest, err := op.GetGuest() @@ -44,17 +44,34 @@ func initUser() { if errors.Is(err, gorm.ErrRecordNotFound) { guest = &model.User{ Username: "guest", - Password: "guest", + PwdHash: model.HashPwd("guest"), Role: model.GUEST, BasePath: "/", Permission: 0, Disabled: true, } if err := db.CreateUser(guest); err != nil { - panic(err) + utils.Log.Fatalf("[init user] Failed to create guest user: %v", err) } } else { - panic(err) + utils.Log.Fatalf("[init user] Failed to get guest user: %v", err) + } + } + hashPwdForOldVersion() +} + +func hashPwdForOldVersion() { + users, _, err := op.GetUsers(1, -1) + if err != nil { + utils.Log.Fatalf("[hash pwd for old version] failed get users: %v", err) + } + for i := range users { + user := users[i] + if user.PwdHash == "" { + user.PwdHash = model.HashPwd(user.Password) + if err := db.UpdateUser(&user); err != nil { + utils.Log.Fatalf("[hash pwd for old version] failed update user: %v", err) + } } } } diff --git a/internal/model/user.go b/internal/model/user.go index ca225c07..b276cc60 100644 --- a/internal/model/user.go +++ b/internal/model/user.go @@ -1,6 +1,8 @@ package model import ( + "fmt" + "github.com/alist-org/alist/v3/internal/errs" "github.com/alist-org/alist/v3/pkg/utils" "github.com/pkg/errors" @@ -12,10 +14,13 @@ const ( ADMIN ) +const HashSalt = "https://github.com/alist-org/alist" + 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 + PwdHash string `json:"-"` // password hash + Password string `json:"-"` // password BasePath string `json:"base_path"` // base path Role int `json:"role"` // user's role Disabled bool `json:"disabled"` @@ -45,10 +50,14 @@ func (u User) IsAdmin() bool { } func (u User) ValidatePassword(password string) error { - if password == "" { + return u.ValidatePwdHash(HashPwd(password)) +} + +func (u User) ValidatePwdHash(pwdHash string) error { + if pwdHash == "" { return errors.WithStack(errs.EmptyPassword) } - if u.Password != password { + if u.PwdHash != pwdHash { return errors.WithStack(errs.WrongPassword) } return nil @@ -101,3 +110,7 @@ func (u User) CanAddQbittorrentTasks() bool { func (u User) JoinPath(reqPath string) (string, error) { return utils.JoinBasePath(u.BasePath, reqPath) } + +func HashPwd(password string) string { + return utils.GetSHA256Encode([]byte(fmt.Sprintf("%s-%s", password, HashSalt))) +} diff --git a/server/handles/auth.go b/server/handles/auth.go index acc8c95b..4e140d72 100644 --- a/server/handles/auth.go +++ b/server/handles/auth.go @@ -28,6 +28,26 @@ type LoginReq struct { // Login Deprecated func Login(c *gin.Context) { + var req LoginReq + if err := c.ShouldBind(&req); err != nil { + common.ErrorResp(c, err, 400) + return + } + req.Password = model.HashPwd(req.Password) + loginHash(c, &req) +} + +// LoginHash login with password hashed by sha256 +func LoginHash(c *gin.Context) { + var req LoginReq + if err := c.ShouldBind(&req); err != nil { + common.ErrorResp(c, err, 400) + return + } + loginHash(c, &req) +} + +func loginHash(c *gin.Context, req *LoginReq) { // check count of login ip := c.ClientIP() count, ok := loginCache.Get(ip) @@ -37,19 +57,14 @@ func Login(c *gin.Context) { return } // check username - var req LoginReq - if err := c.ShouldBind(&req); err != nil { - common.ErrorResp(c, err, 400) - return - } user, err := op.GetUserByName(req.Username) if err != nil { common.ErrorResp(c, err, 400) loginCache.Set(ip, count+1) return } - // validate password - if err := user.ValidatePassword(req.Password); err != nil { + // validate password hash + if err := user.ValidatePwdHash(req.Password); err != nil { common.ErrorResp(c, err, 400) loginCache.Set(ip, count+1) return diff --git a/server/router.go b/server/router.go index 871658c1..dd4e4328 100644 --- a/server/router.go +++ b/server/router.go @@ -46,6 +46,7 @@ func Init(e *gin.Engine) { auth := api.Group("", middlewares.Auth) api.POST("/auth/login", handles.Login) + api.POST("/auth/login/hash", handles.LoginHash) auth.GET("/me", handles.CurrentUser) auth.POST("/me/update", handles.UpdateCurrent) auth.POST("/auth/2fa/generate", handles.Generate2FA)