Add rate limiting for password reset and improve SMTP tests
- Add RateLimitByEmail middleware (3 attempts/hour per email) - Apply rate limiting to /api/v1/auth/forgot-password endpoint - Expand SMTP tests with config validation, message types, and error detection - Improve test coverage from 44.6% to 53.3%
This commit is contained in:
@@ -1,8 +1,12 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"apocapoc-api/internal/infrastructure/auth"
|
||||
@@ -36,3 +40,39 @@ func RateLimitByUser(jwtService *auth.JWTService, requestsPerMinute int, duratio
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func RateLimitByEmail(requests int, duration time.Duration) func(http.Handler) http.Handler {
|
||||
limiter := httprate.NewRateLimiter(
|
||||
requests,
|
||||
duration,
|
||||
httprate.WithKeyFuncs(func(r *http.Request) (string, error) {
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return r.RemoteAddr, nil
|
||||
}
|
||||
r.Body = io.NopCloser(bytes.NewBuffer(body))
|
||||
|
||||
var data map[string]interface{}
|
||||
if err := json.Unmarshal(body, &data); err != nil {
|
||||
return r.RemoteAddr, nil
|
||||
}
|
||||
|
||||
if email, ok := data["email"].(string); ok && email != "" {
|
||||
return "email:" + strings.ToLower(email), nil
|
||||
}
|
||||
|
||||
return r.RemoteAddr, nil
|
||||
}),
|
||||
httprate.WithLimitHandler(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusTooManyRequests)
|
||||
w.Write([]byte(`{"error":"Too many password reset attempts. Please try again later."}`))
|
||||
}),
|
||||
)
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
limiter.Handler(next).ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user