1+ import { createRateLimiter } from '../utils/rateLimit'
2+
3+ const SAFE_METHODS = new Set ( [ 'GET' , 'HEAD' ] )
4+ const SKIP_METHODS = new Set ( [ 'OPTIONS' ] )
5+
6+ // Baseline global API limits (per IP)
7+ const globalReadLimiter = createRateLimiter ( {
8+ windowMs : 60 * 1000 ,
9+ maxRequests : 300 ,
10+ message : 'Too many API requests. Please try again shortly.' ,
11+ } )
12+
13+ const globalWriteLimiter = createRateLimiter ( {
14+ windowMs : 60 * 1000 ,
15+ maxRequests : 80 ,
16+ message : 'Too many write requests. Please try again shortly.' ,
17+ } )
18+
19+ // Auth endpoints get their own buckets to reduce brute-force risk without
20+ // starving the rest of the API traffic from the same IP.
21+ const authReadLimiter = createRateLimiter ( {
22+ windowMs : 5 * 60 * 1000 ,
23+ maxRequests : 600 ,
24+ message : 'Too many auth requests. Please try again shortly.' ,
25+ } )
26+
27+ const authWriteLimiter = createRateLimiter ( {
28+ windowMs : 5 * 60 * 1000 ,
29+ maxRequests : 40 ,
30+ message : 'Too many sign-in attempts. Please wait before trying again.' ,
31+ } )
32+
33+ export default defineEventHandler ( async ( event ) => {
34+ const path = getRequestURL ( event ) . pathname
35+ if ( ! path . startsWith ( '/api/' ) ) return
36+
37+ const method = event . method . toUpperCase ( )
38+ if ( SKIP_METHODS . has ( method ) ) return
39+
40+ if ( path . startsWith ( '/api/auth/' ) ) {
41+ if ( SAFE_METHODS . has ( method ) ) {
42+ await authReadLimiter ( event )
43+ return
44+ }
45+
46+ await authWriteLimiter ( event )
47+ return
48+ }
49+
50+ if ( SAFE_METHODS . has ( method ) ) {
51+ await globalReadLimiter ( event )
52+ return
53+ }
54+
55+ await globalWriteLimiter ( event )
56+ } )
0 commit comments