This repository was archived by the owner on Dec 1, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmiddleware.ts
More file actions
83 lines (69 loc) · 2.46 KB
/
middleware.ts
File metadata and controls
83 lines (69 loc) · 2.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { generateCSRFToken, validateCSRFToken } from '@/lib/csrf'
// Simple in-memory store for rate limiting
const rateLimit = new Map()
// Rate limit configuration
const RATE_LIMIT = 10
const RATE_LIMIT_WINDOW = 60 * 1000 // 1 minute in milliseconds
// Paths that require CSRF protection
const CSRF_PROTECTED_METHODS = ['POST', 'PUT', 'DELETE', 'PATCH']
const CSRF_PROTECTED_PATHS = ['/api/auth', '/api/checkout', '/api/user']
export async function middleware(request: NextRequest) {
const path = request.nextUrl.pathname
// Rate limiting logic
const ip = request.ip ?? '127.0.0.1'
const rateLimitKey = `${ip}:${request.method}:${request.nextUrl.pathname}`
const now = Date.now()
const rateData = rateLimit.get(rateLimitKey) || { count: 0, timestamp: now }
// Reset count if outside window
if (now - rateData.timestamp > RATE_LIMIT_WINDOW) {
rateData.count = 0
rateData.timestamp = now
}
if (rateData.count >= RATE_LIMIT) {
return new NextResponse('Too Many Requests', {
status: 429,
headers: {
'Retry-After': `${RATE_LIMIT_WINDOW / 1000}`,
},
})
}
rateData.count++
rateLimit.set(rateLimitKey, rateData)
// CSRF protection for mutations
if (request.method !== 'GET' &&
CSRF_PROTECTED_METHODS.includes(request.method) &&
CSRF_PROTECTED_PATHS.some(path => request.nextUrl.pathname.startsWith(path))) {
const csrfToken = request.headers.get('x-csrf-token')
if (!validateCSRFToken(csrfToken)) {
return NextResponse.json(
{ error: 'Invalid or missing CSRF token' },
{ status: 403 }
)
}
}
// For GET requests to protected paths, generate and attach CSRF token
if (request.method === 'GET' &&
CSRF_PROTECTED_PATHS.some(path => request.nextUrl.pathname.startsWith(path))) {
const response = NextResponse.next()
const token = await generateCSRFToken()
response.headers.set('x-csrf-token', token)
return response
}
// Add security headers
const response = NextResponse.next()
if (!path.startsWith('/api/')) {
// Only add CSRF token for non-API routes
const token = await generateCSRFToken()
response.headers.set('X-CSRF-Token', token)
}
return response
}
// Update matcher to only handle routes that need protection
export const config = {
matcher: [
'/api/:path*',
'/((?!_next/static|favicon.ico|images/|.well-known/|robots.txt).*)',
],
}