1
0

user.go 4.4 KB

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