user.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. package panel
  2. import (
  3. "errors"
  4. "time"
  5. "gorm.io/gorm"
  6. "github.com/mhsanaei/3x-ui/v3/internal/database"
  7. "github.com/mhsanaei/3x-ui/v3/internal/database/model"
  8. "github.com/mhsanaei/3x-ui/v3/internal/logger"
  9. "github.com/mhsanaei/3x-ui/v3/internal/util/crypto"
  10. ldaputil "github.com/mhsanaei/3x-ui/v3/internal/util/ldap"
  11. "github.com/mhsanaei/3x-ui/v3/internal/util/totp"
  12. "github.com/mhsanaei/3x-ui/v3/internal/web/service"
  13. )
  14. // UserService provides business logic for user management and authentication.
  15. // It handles user creation, login, password management, and 2FA operations.
  16. type UserService struct {
  17. settingService service.SettingService
  18. }
  19. // GetFirstUser retrieves the first user from the database.
  20. // This is typically used for initial setup or when there's only one admin user.
  21. func (s *UserService) GetFirstUser() (*model.User, error) {
  22. db := database.GetDB()
  23. user := &model.User{}
  24. err := db.Model(model.User{}).
  25. First(user).
  26. Error
  27. if err != nil {
  28. return nil, err
  29. }
  30. return user, nil
  31. }
  32. func (s *UserService) CheckUser(username string, password string, twoFactorCode string) (*model.User, error) {
  33. db := database.GetDB()
  34. user := &model.User{}
  35. err := db.Model(model.User{}).
  36. Where("username = ?", username).
  37. First(user).
  38. Error
  39. if errors.Is(err, gorm.ErrRecordNotFound) {
  40. return nil, errors.New("invalid credentials")
  41. } else if err != nil {
  42. logger.Warning("check user err:", err)
  43. return nil, err
  44. }
  45. if !crypto.CheckPasswordHash(user.Password, password) {
  46. ldapEnabled, _ := s.settingService.GetLdapEnable()
  47. if !ldapEnabled {
  48. return nil, errors.New("invalid credentials")
  49. }
  50. host, _ := s.settingService.GetLdapHost()
  51. port, _ := s.settingService.GetLdapPort()
  52. useTLS, _ := s.settingService.GetLdapUseTLS()
  53. skipVerify, _ := s.settingService.GetLdapInsecureSkipVerify()
  54. bindDN, _ := s.settingService.GetLdapBindDN()
  55. ldapPass, _ := s.settingService.GetLdapPassword()
  56. baseDN, _ := s.settingService.GetLdapBaseDN()
  57. userFilter, _ := s.settingService.GetLdapUserFilter()
  58. userAttr, _ := s.settingService.GetLdapUserAttr()
  59. cfg := ldaputil.Config{
  60. Host: host,
  61. Port: port,
  62. UseTLS: useTLS,
  63. InsecureSkipVerify: skipVerify,
  64. BindDN: bindDN,
  65. Password: ldapPass,
  66. BaseDN: baseDN,
  67. UserFilter: userFilter,
  68. UserAttr: userAttr,
  69. }
  70. ok, err := ldaputil.AuthenticateUser(cfg, username, password)
  71. if err != nil || !ok {
  72. return nil, errors.New("invalid credentials")
  73. }
  74. }
  75. twoFactorEnable, err := s.settingService.GetTwoFactorEnable()
  76. if err != nil {
  77. logger.Warning("check two factor err:", err)
  78. return nil, err
  79. }
  80. if twoFactorEnable {
  81. twoFactorToken, err := s.settingService.GetTwoFactorToken()
  82. if err != nil {
  83. logger.Warning("check two factor token err:", err)
  84. return nil, err
  85. }
  86. if !totp.VerifyWithSkew(twoFactorToken, twoFactorCode, time.Now()) {
  87. return nil, errors.New("invalid 2fa code")
  88. }
  89. }
  90. return user, nil
  91. }
  92. func (s *UserService) BumpLoginEpoch() error {
  93. db := database.GetDB()
  94. return db.Model(model.User{}).
  95. Where("1 = 1").
  96. Update("login_epoch", gorm.Expr("login_epoch + 1")).
  97. Error
  98. }
  99. func (s *UserService) UpdateUser(id int, username string, password string) error {
  100. db := database.GetDB()
  101. hashedPassword, err := crypto.HashPasswordAsBcrypt(password)
  102. if err != nil {
  103. return err
  104. }
  105. twoFactorEnable, err := s.settingService.GetTwoFactorEnable()
  106. if err != nil {
  107. return err
  108. }
  109. if twoFactorEnable {
  110. _ = s.settingService.SetTwoFactorEnable(false)
  111. _ = s.settingService.SetTwoFactorToken("")
  112. }
  113. return db.Model(model.User{}).
  114. Where("id = ?", id).
  115. Updates(map[string]any{
  116. "username": username,
  117. "password": hashedPassword,
  118. "login_epoch": gorm.Expr("login_epoch + 1"),
  119. }).
  120. Error
  121. }
  122. func (s *UserService) UpdateFirstUser(username string, password string) error {
  123. if username == "" {
  124. return errors.New("username can not be empty")
  125. } else if password == "" {
  126. return errors.New("password can not be empty")
  127. }
  128. hashedPassword, er := crypto.HashPasswordAsBcrypt(password)
  129. if er != nil {
  130. return er
  131. }
  132. db := database.GetDB()
  133. user := &model.User{}
  134. err := db.Model(model.User{}).First(user).Error
  135. if database.IsNotFound(err) {
  136. user.Username = username
  137. user.Password = hashedPassword
  138. return db.Model(model.User{}).Create(user).Error
  139. } else if err != nil {
  140. return err
  141. }
  142. user.Username = username
  143. user.Password = hashedPassword
  144. user.LoginEpoch++
  145. return db.Save(user).Error
  146. }