user.go 4.1 KB

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