Repository navigation
Expand file tree
/
Copy pathmiddleware.ts
More file actions
59 lines (51 loc) · 1.47 KB
/
Copy pathmiddleware.ts
File metadata and controls
59 lines (51 loc) · 1.47 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
import type { NextFetchEvent, NextRequest } from "next/server";
import { NextResponse } from "next/server";
import type { NextRequestWithAuth } from "next-auth/middleware";
import { withAuth } from "next-auth/middleware";
import { isLoginBypassed } from "@/lib/config";
import { checkRateLimit } from "@/lib/security/rate-limit";
const authMiddleware = withAuth({
pages: {
signIn: "/sign-in",
},
});
const MIDDLEWARE_RATE_LIMIT = {
capacity: 120,
refillRatePerSec: 4,
};
function getMiddlewareKey(request: NextRequest): string {
const forwarded = request.headers.get("x-forwarded-for");
if (forwarded) {
const first = forwarded.split(",")[0]?.trim();
if (first) {
return `mw:${first}`;
}
}
const realIp = request.headers.get("x-real-ip");
if (realIp) {
return `mw:${realIp.trim()}`;
}
return "mw:unknown";
}
export default function middleware(request: NextRequest, event: NextFetchEvent) {
const outcome = checkRateLimit(getMiddlewareKey(request), MIDDLEWARE_RATE_LIMIT);
if (!outcome.allowed) {
return new NextResponse(
JSON.stringify({ error: "Rate limit exceeded." }),
{
status: 429,
headers: {
"Content-Type": "application/json",
"Retry-After": String(outcome.retryAfterSec),
},
},
);
}
if (isLoginBypassed()) {
return NextResponse.next();
}
return authMiddleware(request as NextRequestWithAuth, event);
}
export const config = {
matcher: ["/admin/:path*"],
};