chore: implement 2fa auth (#2968)
* chore: implement 2fa auth from #2786 * chore: format code * chore: replace two factor token input with qr-code * chore: requesting confirmation of setting/removing two-factor authentication otpauth library was taken from cdnjs * chore: revert changes in `ClipboardManager` don't need it. * chore: removing twoFactor prop in settings page * chore: remove `twoFactorQr` object in `mounted` function
This commit is contained in:
+11
-11
@@ -48,7 +48,8 @@ var defaultValueMap = map[string]string{
|
||||
"tgBotLoginNotify": "true",
|
||||
"tgCpu": "80",
|
||||
"tgLang": "en-US",
|
||||
"secretEnable": "false",
|
||||
"twoFactorEnable": "false",
|
||||
"twoFactorToken": "",
|
||||
"subEnable": "false",
|
||||
"subTitle": "",
|
||||
"subListen": "",
|
||||
@@ -166,8 +167,7 @@ func (s *SettingService) ResetSettings() error {
|
||||
return err
|
||||
}
|
||||
return db.Model(model.User{}).
|
||||
Where("1 = 1").
|
||||
Update("login_secret", "").Error
|
||||
Where("1 = 1").Error
|
||||
}
|
||||
|
||||
func (s *SettingService) getSetting(key string) (*model.Setting, error) {
|
||||
@@ -318,6 +318,14 @@ func (s *SettingService) GetTgLang() (string, error) {
|
||||
return s.getString("tgLang")
|
||||
}
|
||||
|
||||
func (s *SettingService) GetTwoFactorEnable() (bool, error) {
|
||||
return s.getBool("twoFactorEnable")
|
||||
}
|
||||
|
||||
func (s *SettingService) GetTwoFactorToken() (string, error) {
|
||||
return s.getString("twoFactorToken")
|
||||
}
|
||||
|
||||
func (s *SettingService) GetPort() (int, error) {
|
||||
return s.getInt("webPort")
|
||||
}
|
||||
@@ -358,14 +366,6 @@ func (s *SettingService) GetRemarkModel() (string, error) {
|
||||
return s.getString("remarkModel")
|
||||
}
|
||||
|
||||
func (s *SettingService) GetSecretStatus() (bool, error) {
|
||||
return s.getBool("secretEnable")
|
||||
}
|
||||
|
||||
func (s *SettingService) SetSecretStatus(value bool) error {
|
||||
return s.setBool("secretEnable", value)
|
||||
}
|
||||
|
||||
func (s *SettingService) GetSecret() ([]byte, error) {
|
||||
secret, err := s.getString("secret")
|
||||
if secret == defaultValueMap["secret"] {
|
||||
|
||||
+28
-50
@@ -8,10 +8,13 @@ import (
|
||||
"x-ui/logger"
|
||||
"x-ui/util/crypto"
|
||||
|
||||
"github.com/xlzd/gotp"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type UserService struct{}
|
||||
type UserService struct {
|
||||
settingService SettingService
|
||||
}
|
||||
|
||||
func (s *UserService) GetFirstUser() (*model.User, error) {
|
||||
db := database.GetDB()
|
||||
@@ -26,13 +29,13 @@ func (s *UserService) GetFirstUser() (*model.User, error) {
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (s *UserService) CheckUser(username string, password string, secret string) *model.User {
|
||||
func (s *UserService) CheckUser(username string, password string, twoFactorCode string) *model.User {
|
||||
db := database.GetDB()
|
||||
|
||||
user := &model.User{}
|
||||
|
||||
err := db.Model(model.User{}).
|
||||
Where("username = ? and login_secret = ?", username, secret).
|
||||
Where("username = ?", username).
|
||||
First(user).
|
||||
Error
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
@@ -42,11 +45,30 @@ func (s *UserService) CheckUser(username string, password string, secret string)
|
||||
return nil
|
||||
}
|
||||
|
||||
if crypto.CheckPasswordHash(user.Password, password) {
|
||||
return user
|
||||
if !crypto.CheckPasswordHash(user.Password, password) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
twoFactorEnable, err := s.settingService.GetTwoFactorEnable()
|
||||
if err != nil {
|
||||
logger.Warning("check two factor err:", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if twoFactorEnable {
|
||||
twoFactorToken, err := s.settingService.GetTwoFactorToken()
|
||||
|
||||
if err != nil {
|
||||
logger.Warning("check two factor token err:", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if gotp.NewDefaultTOTP(twoFactorToken).Now() != twoFactorCode {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
func (s *UserService) UpdateUser(id int, username string, password string) error {
|
||||
@@ -63,50 +85,6 @@ func (s *UserService) UpdateUser(id int, username string, password string) error
|
||||
Error
|
||||
}
|
||||
|
||||
func (s *UserService) UpdateUserSecret(id int, secret string) error {
|
||||
db := database.GetDB()
|
||||
return db.Model(model.User{}).
|
||||
Where("id = ?", id).
|
||||
Update("login_secret", secret).
|
||||
Error
|
||||
}
|
||||
|
||||
func (s *UserService) RemoveUserSecret() error {
|
||||
db := database.GetDB()
|
||||
return db.Model(model.User{}).
|
||||
Where("1 = 1").
|
||||
Update("login_secret", "").
|
||||
Error
|
||||
}
|
||||
|
||||
func (s *UserService) GetUserSecret(id int) *model.User {
|
||||
db := database.GetDB()
|
||||
user := &model.User{}
|
||||
err := db.Model(model.User{}).
|
||||
Where("id = ?", id).
|
||||
First(user).
|
||||
Error
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
func (s *UserService) CheckSecretExistence() (bool, error) {
|
||||
db := database.GetDB()
|
||||
|
||||
var count int64
|
||||
err := db.Model(model.User{}).
|
||||
Where("login_secret IS NOT NULL").
|
||||
Count(&count).
|
||||
Error
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
func (s *UserService) UpdateFirstUser(username string, password string) error {
|
||||
if username == "" {
|
||||
return errors.New("username can not be empty")
|
||||
|
||||
Reference in New Issue
Block a user