fix: harden token auth error handling to prevent info leakage

- Create model/errors.go to centralize all sentinel errors
- ValidateAccessToken now returns error to distinguish DB failures
- ValidateUserToken uses unified ErrTokenInvalid for all auth failures
  (expired/exhausted/disabled/not-found) to prevent token enumeration
- authHelper and TokenAuthReadOnly use i18n messages instead of
  hardcoded Chinese strings
- All err.Error() removed from user-facing responses; DB errors logged
  server-side and return generic "contact admin" message (HTTP 500)
- Migrate ErrRedeemFailed, ErrTwoFANotEnabled to model/errors.go
This commit is contained in:
CaIon
2026-04-12 17:39:00 +08:00
parent 2819e3a1d1
commit 59c582d13c
10 changed files with 144 additions and 55 deletions
+10 -12
View File
@@ -18,12 +18,6 @@ import (
const UserNameMaxLength = 20
var (
ErrDatabase = errors.New("database error")
ErrInvalidCredentials = errors.New("invalid credentials")
ErrUserEmptyCredentials = errors.New("empty credentials")
)
// User if you add sensitive fields, don't forget to clean them in setupLogin function.
// Otherwise, the sensitive information will be saved on local storage in plain text!
type User struct {
@@ -766,16 +760,20 @@ func IsAdmin(userId int) bool {
// return user.Status == common.UserStatusEnabled, nil
//}
func ValidateAccessToken(token string) (user *User) {
func ValidateAccessToken(token string) (*User, error) {
if token == "" {
return nil
return nil, nil
}
token = strings.Replace(token, "Bearer ", "", 1)
user = &User{}
if DB.Where("access_token = ?", token).First(user).RowsAffected == 1 {
return user
user := &User{}
err := DB.Where("access_token = ?", token).First(user).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, fmt.Errorf("%w: %v", ErrDatabase, err)
}
return nil
return user, nil
}
// GetUserQuota gets quota from Redis first, falls back to DB if needed