mirror of https://github.com/Xhofe/alist
perf: sha256 for user's password (close #3552)
parent
30415cefbe
commit
75acbcc115
|
@ -26,17 +26,17 @@ func initUser() {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
admin = &model.User{
|
admin = &model.User{
|
||||||
Username: "admin",
|
Username: "admin",
|
||||||
Password: adminPassword,
|
PwdHash: model.HashPwd(adminPassword),
|
||||||
Role: model.ADMIN,
|
Role: model.ADMIN,
|
||||||
BasePath: "/",
|
BasePath: "/",
|
||||||
}
|
}
|
||||||
if err := op.CreateUser(admin); err != nil {
|
if err := op.CreateUser(admin); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
} else {
|
} 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 {
|
} else {
|
||||||
panic(err)
|
utils.Log.Fatalf("[init user] Failed to get admin user: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
guest, err := op.GetGuest()
|
guest, err := op.GetGuest()
|
||||||
|
@ -44,17 +44,34 @@ func initUser() {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
guest = &model.User{
|
guest = &model.User{
|
||||||
Username: "guest",
|
Username: "guest",
|
||||||
Password: "guest",
|
PwdHash: model.HashPwd("guest"),
|
||||||
Role: model.GUEST,
|
Role: model.GUEST,
|
||||||
BasePath: "/",
|
BasePath: "/",
|
||||||
Permission: 0,
|
Permission: 0,
|
||||||
Disabled: true,
|
Disabled: true,
|
||||||
}
|
}
|
||||||
if err := db.CreateUser(guest); err != nil {
|
if err := db.CreateUser(guest); err != nil {
|
||||||
panic(err)
|
utils.Log.Fatalf("[init user] Failed to create guest user: %v", err)
|
||||||
}
|
}
|
||||||
} else {
|
} 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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/alist-org/alist/v3/internal/errs"
|
"github.com/alist-org/alist/v3/internal/errs"
|
||||||
"github.com/alist-org/alist/v3/pkg/utils"
|
"github.com/alist-org/alist/v3/pkg/utils"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -12,10 +14,13 @@ const (
|
||||||
ADMIN
|
ADMIN
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const HashSalt = "https://github.com/alist-org/alist"
|
||||||
|
|
||||||
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
|
PwdHash string `json:"-"` // password hash
|
||||||
|
Password string `json:"-"` // password
|
||||||
BasePath string `json:"base_path"` // base path
|
BasePath string `json:"base_path"` // base path
|
||||||
Role int `json:"role"` // user's role
|
Role int `json:"role"` // user's role
|
||||||
Disabled bool `json:"disabled"`
|
Disabled bool `json:"disabled"`
|
||||||
|
@ -45,10 +50,14 @@ func (u User) IsAdmin() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u User) ValidatePassword(password string) error {
|
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)
|
return errors.WithStack(errs.EmptyPassword)
|
||||||
}
|
}
|
||||||
if u.Password != password {
|
if u.PwdHash != pwdHash {
|
||||||
return errors.WithStack(errs.WrongPassword)
|
return errors.WithStack(errs.WrongPassword)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -101,3 +110,7 @@ func (u User) CanAddQbittorrentTasks() bool {
|
||||||
func (u User) JoinPath(reqPath string) (string, error) {
|
func (u User) JoinPath(reqPath string) (string, error) {
|
||||||
return utils.JoinBasePath(u.BasePath, reqPath)
|
return utils.JoinBasePath(u.BasePath, reqPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HashPwd(password string) string {
|
||||||
|
return utils.GetSHA256Encode([]byte(fmt.Sprintf("%s-%s", password, HashSalt)))
|
||||||
|
}
|
||||||
|
|
|
@ -28,6 +28,26 @@ type LoginReq struct {
|
||||||
|
|
||||||
// Login Deprecated
|
// Login Deprecated
|
||||||
func Login(c *gin.Context) {
|
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
|
// check count of login
|
||||||
ip := c.ClientIP()
|
ip := c.ClientIP()
|
||||||
count, ok := loginCache.Get(ip)
|
count, ok := loginCache.Get(ip)
|
||||||
|
@ -37,19 +57,14 @@ func Login(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// check username
|
// check username
|
||||||
var req LoginReq
|
|
||||||
if err := c.ShouldBind(&req); err != nil {
|
|
||||||
common.ErrorResp(c, err, 400)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
user, err := op.GetUserByName(req.Username)
|
user, err := op.GetUserByName(req.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.ErrorResp(c, err, 400)
|
common.ErrorResp(c, err, 400)
|
||||||
loginCache.Set(ip, count+1)
|
loginCache.Set(ip, count+1)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// validate password
|
// validate password hash
|
||||||
if err := user.ValidatePassword(req.Password); err != nil {
|
if err := user.ValidatePwdHash(req.Password); err != nil {
|
||||||
common.ErrorResp(c, err, 400)
|
common.ErrorResp(c, err, 400)
|
||||||
loginCache.Set(ip, count+1)
|
loginCache.Set(ip, count+1)
|
||||||
return
|
return
|
||||||
|
|
|
@ -46,6 +46,7 @@ func Init(e *gin.Engine) {
|
||||||
auth := api.Group("", middlewares.Auth)
|
auth := api.Group("", middlewares.Auth)
|
||||||
|
|
||||||
api.POST("/auth/login", handles.Login)
|
api.POST("/auth/login", handles.Login)
|
||||||
|
api.POST("/auth/login/hash", handles.LoginHash)
|
||||||
auth.GET("/me", handles.CurrentUser)
|
auth.GET("/me", handles.CurrentUser)
|
||||||
auth.POST("/me/update", handles.UpdateCurrent)
|
auth.POST("/me/update", handles.UpdateCurrent)
|
||||||
auth.POST("/auth/2fa/generate", handles.Generate2FA)
|
auth.POST("/auth/2fa/generate", handles.Generate2FA)
|
||||||
|
|
Loading…
Reference in New Issue