fix: enforce request body size limits across the API

Ultraworked with Sisyphus (https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-05-31 10:55:33 +01:00
co-authored by Sisyphus
parent 700b7c1152
commit 1a6947a9b6
2 changed files with 25 additions and 6 deletions
+23 -5
View File
@@ -42,6 +42,22 @@ func init() {
auth.InitJWT(jwtSecret)
}
func limitBody(limit int64) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Body != nil {
r.Body = http.MaxBytesReader(w, r.Body, limit)
}
next.ServeHTTP(w, r)
})
}
}
const (
defaultBodyLimit int64 = 1 * 1024 * 1024 // 1MB
uploadBodyLimit int64 = 15 * 1024 * 1024 // 15MB
)
func initDB() {
if err := db.Connect(); err != nil {
log.Fatal("Failed to connect to DB:", err)
@@ -146,11 +162,11 @@ func main() {
r.With(mw.RateLimit(10, time.Minute)).Post("/register", authHandlers.RegisterHandler)
// Login: Has its own internal rate limiting
r.Post("/login", authHandlers.LoginHandler)
r.With(mw.RateLimit(10, time.Minute)).Post("/login", authHandlers.LoginHandler)
// Email verification
r.Post("/verify/generate", authHandlers.GenerateVerificationCodeHandler)
r.Post("/verify/check", authHandlers.VerifyCodeHandler)
r.With(mw.RateLimit(10, time.Minute)).Post("/verify/generate", authHandlers.GenerateVerificationCodeHandler)
r.With(mw.RateLimit(20, time.Minute)).Post("/verify/check", authHandlers.VerifyCodeHandler)
// Health check
r.Get("/health", healthCheckHandler)
@@ -169,7 +185,7 @@ func main() {
r.Use(mw.RequireAuth)
r.Use(mw.RequireAdmin)
r.Use(mw.RateLimit(60, time.Minute))
r.Post("/images", portfolio.UploadImage)
r.With(limitBody(uploadBodyLimit)).Post("/images", portfolio.UploadImage)
r.Delete("/images/{id}", portfolio.DeleteImage)
})
})
@@ -208,12 +224,12 @@ func main() {
r.Group(func(r chi.Router) {
r.Use(mw.RequireAuth)
r.Use(mw.RateLimit(120, time.Minute))
r.Use(limitBody(defaultBodyLimit))
r.Post("/refresh-token", authHandlers.RefreshTokenHandler)
r.Get("/user/profile", user.GetProfileHandler)
r.Put("/user/profile", user.UpdateProfileHandler)
r.Post("/user/profile-picture", user.UploadProfilePictureHandler)
r.Put("/user/change-password", user.ChangePasswordHandler)
r.Get("/user/notification-preferences", user.GetNotificationPreferencesHandler)
r.Put("/user/notification-preferences", user.UpdateNotificationPreferencesHandler)
@@ -239,6 +255,8 @@ func main() {
r.Get("/bookings/{id}/payment-summary", payments.GetBookingPaymentSummary)
})
r.With(mw.RequireAuth, mw.RequireVerified, limitBody(uploadBodyLimit)).Post("/user/profile-picture", user.UploadProfilePictureHandler)
// Admin-only (no rate limit - trusted users with authenticated sessions)
r.Group(func(r chi.Router) {
r.Use(mw.RequireAuth)