refactor: rework rate limit logic (#1008)

This commit is contained in:
Stavros
2026-07-15 15:30:57 +03:00
committed by GitHub
parent 6e095fd4f2
commit dade1e2c8f
7 changed files with 78 additions and 120 deletions
+16 -25
View File
@@ -72,27 +72,12 @@ func (controller *UserController) loginHandler(c *gin.Context) {
controller.log.App.Debug().Str("username", req.Username).Msg("Login attempt")
isLocked, remaining := controller.auth.IsAccountLocked(req.Username)
if isLocked {
controller.log.App.Warn().Str("username", req.Username).Msg("Account is locked due to too many failed login attempts")
controller.log.AuditLoginFailure(req.Username, "local", c.ClientIP(), "account locked")
c.Writer.Header().Add("x-tinyauth-lock-locked", "true")
c.Writer.Header().Add("x-tinyauth-lock-reset", time.Now().Add(time.Duration(remaining)*time.Second).Format(time.RFC3339))
c.JSON(429, gin.H{
"status": 429,
"message": fmt.Sprintf("Too many failed login attempts. Try again in %d seconds", remaining),
})
return
}
search, err := controller.auth.SearchUser(req.Username)
if err != nil {
if errors.Is(err, service.ErrUserNotFound) {
controller.auth.DummyPasswordCheck(req.Password)
controller.log.App.Warn().Str("username", req.Username).Msg("User not found during login attempt")
controller.auth.RecordLoginAttempt(req.Username, false)
controller.log.AuditLoginFailure(req.Username, "unknown", c.ClientIP(), "user not found")
c.JSON(401, gin.H{
"status": 401,
@@ -108,14 +93,24 @@ func (controller *UserController) loginHandler(c *gin.Context) {
return
}
isLocked, remaining := controller.auth.IsAccountLocked(req.Username)
if isLocked {
controller.log.App.Warn().Str("username", req.Username).Msg("Account is locked due to too many failed login attempts")
controller.log.AuditLoginFailure(req.Username, search.Type.String(), c.ClientIP(), "account locked")
c.Writer.Header().Add("x-tinyauth-lock-locked", "true")
c.Writer.Header().Add("x-tinyauth-lock-reset", time.Now().Add(time.Duration(remaining)*time.Second).Format(time.RFC3339))
c.JSON(429, gin.H{
"status": 429,
"message": fmt.Sprintf("Too many failed login attempts. Try again in %d seconds", remaining),
})
return
}
if err := controller.auth.CheckUserPassword(*search, req.Password); err != nil {
controller.log.App.Warn().Str("username", req.Username).Msg("Invalid password during login attempt")
controller.auth.RecordLoginAttempt(req.Username, false)
if search.Type == model.UserLocal {
controller.log.AuditLoginFailure(req.Username, "local", c.ClientIP(), "invalid password")
} else {
controller.log.AuditLoginFailure(req.Username, "ldap", c.ClientIP(), "invalid password")
}
controller.log.AuditLoginFailure(req.Username, search.Type.String(), c.ClientIP(), "invalid password")
c.JSON(401, gin.H{
"status": 401,
"message": "Unauthorized",
@@ -216,11 +211,7 @@ func (controller *UserController) loginHandler(c *gin.Context) {
controller.log.App.Info().Str("username", req.Username).Msg("Login successful")
if search.Type == model.UserLocal {
controller.log.AuditLoginSuccess(req.Username, "local", c.ClientIP())
} else {
controller.log.AuditLoginSuccess(req.Username, "ldap", c.ClientIP())
}
controller.log.AuditLoginSuccess(req.Username, search.Type.String(), c.ClientIP())
controller.auth.RecordLoginAttempt(req.Username, true)