diff --git a/src/middleware.ts b/src/middleware.ts index 1cbcabc..1755409 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -1,7 +1,7 @@ import { defineMiddleware } from "astro:middleware"; -const RATE_LIMIT_WINDOW_MS = 60_000; // 1 minute -const RATE_LIMIT_MAX_REQUESTS = 60; // requests per window +const RATE_LIMIT_WINDOW_MS = 60_000; +const RATE_LIMIT_MAX_REQUESTS = 60; interface RateLimitEntry { count: number; @@ -10,7 +10,6 @@ interface RateLimitEntry { const store = new Map(); -// Cleanup stale entries every 5 minutes to avoid memory leaks setInterval(() => { const now = Date.now(); for (const [key, entry] of store) { @@ -19,7 +18,6 @@ setInterval(() => { }, 5 * 60_000); function getClientIp(request: Request): string { - // Cloudflare sets CF-Connecting-IP — use it first. return ( request.headers.get("CF-Connecting-IP") ?? request.headers.get("X-Forwarded-For")?.split(",")[0].trim() ?? @@ -47,31 +45,16 @@ function isRateLimited(ip: string): { limited: boolean; retryAfter: number } { } const SECURITY_HEADERS: Record = { - // Prevent MIME-type sniffing "X-Content-Type-Options": "nosniff", - - // Disallow embedding in iframes (clickjacking) "X-Frame-Options": "DENY", - - // Only send referrer on same-origin requests "Referrer-Policy": "strict-origin-when-cross-origin", - - // Disable browser features you don't use "Permissions-Policy": "camera=(), microphone=(), geolocation=()", - - // Content Security Policy - // - default-src 'self' → only load resources from your own origin by default - // - img-src 'self' cdn.jsdelivr.net data: → allow Simple Icons CDN + inline SVGs - // - style-src 'self' 'unsafe-inline' → DaisyUI injects inline styles at runtime - // - script-src 'self' → no third-party scripts - // - connect-src 'self' → API calls only to your own origin - // - frame-ancestors 'none' → redundant with X-Frame-Options but defense-in-depth "Content-Security-Policy": [ "default-src 'self'", "img-src 'self' cdn.jsdelivr.net data:", "style-src 'self' 'unsafe-inline'", - "script-src 'self'", - "connect-src 'self'", + "script-src 'self' 'unsafe-inline' static.cloudflareinsights.com", + "connect-src 'self' cloudflareinsights.com", "frame-ancestors 'none'", ].join("; "), };