-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathmiddleware copy.ts
169 lines (145 loc) · 4.42 KB
/
middleware copy.ts
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { kv } from "@vercel/kv";
const SupabaseRoutes = [
"/api/push/token",
"/api/evm/contract",
"/api/users/update",
"/api/push/lp-token",
"/api/update/quotes",
];
const RateLimits = {
rpc: {
limitDuration: 60,
maxRequests: 60,
},
simulation: {
limitDuration: 60,
maxRequests: 10,
},
};
const logIncomingRequest = (request: NextRequest) => {
console.log("Incoming request:", request.nextUrl.pathname);
};
export async function middleware(request: NextRequest) {
if (process.env.NODE_ENV === "development") {
// logIncomingRequest(request);
}
/**
* Current path
*/
const pathname = request.nextUrl.pathname;
// Forward to 🐻⛓ RPC
if (pathname.startsWith("/api/rpc/80094")) {
// Clone the request headers
const requestHeaders = new Headers(request.headers);
// Add the Authorization header
requestHeaders.set(
"Authorization",
`Bearer ${process.env.RPC_80094_AUTH_TOKEN}`
);
// Return response with the modified headers
return NextResponse.next({
request: {
headers: requestHeaders,
},
});
}
/**
* Content-type checking for all API routes
*/
if (pathname.startsWith("/api/")) {
if (["POST", "PUT", "PATCH"].includes(request.method)) {
// Check if content-type is application/json
const contentType = request.headers.get("content-type");
// If not application/json, return 415
if (!contentType || contentType !== "application/json") {
return new NextResponse(
JSON.stringify({ error: "Content-Type must be application/json" }),
{
status: 415,
headers: { "Content-Type": "application/json" },
}
);
}
}
}
let rateLimitTag: string | null = null;
if (pathname.startsWith("/api/rpc/")) {
rateLimitTag = "rpc";
} else if (pathname.startsWith("/api/simulation/")) {
rateLimitTag = "simulation";
}
/**
* Rate limiting for specific routes that have been tagged
*/
if (rateLimitTag) {
const ip =
request.ip ?? request.headers.get("x-forwarded-for") ?? "unknown";
const key = `rate-limit:${ip}:${rateLimitTag}`;
const currentRequests = (await kv.get<number>(key)) || 0;
if (
currentRequests >=
RateLimits[rateLimitTag as keyof typeof RateLimits].maxRequests
) {
return new NextResponse(
JSON.stringify({ error: "Rate limit exceeded" }),
{
status: 429,
headers: {
"Content-Type": "application/json",
"X-RateLimit-Limit":
RateLimits[
rateLimitTag as keyof typeof RateLimits
].maxRequests.toString(),
"X-RateLimit-Remaining": "0",
},
}
);
}
await kv.set(key, currentRequests + 1, {
ex: RateLimits[rateLimitTag as keyof typeof RateLimits].limitDuration,
});
}
/**
* Supabase routes are only accessible by Supabase
*/
if (SupabaseRoutes.includes(pathname)) {
// 1. Auth token can be passed in header
const headerToken = request.headers.get("auth-token")?.trim();
// 2. Auth token can be passed in url params
const urlToken = request.nextUrl.searchParams.get("auth_token")?.trim();
// It must be one of the two
const authToken = headerToken || urlToken;
// Check if auth token is valid
if (!authToken || authToken.trim() !== process.env.API_AUTH_TOKEN?.trim()) {
return new NextResponse(JSON.stringify({ status: "Unauthorized" }), {
status: 401,
headers: {
"Content-Type": "application/json",
},
});
}
}
// if (process.env.NEXT_PUBLIC_FRONTEND_TAG === "boyco") {
// // Check if the request is for the auth/verify route
// if (
// pathname.startsWith("/api/") &&
// !pathname.startsWith("/api/auth/verify") &&
// !pathname.startsWith("/api/push/token")
// ) {
// const authToken = request.headers.get("auth-token");
// const isValid = await fetch("/api/auth/verify?auth_token=" + authToken);
// if (!isValid) {
// return new NextResponse(JSON.stringify({ status: "Unauthorized" }), {
// status: 401,
// headers: { "Content-Type": "application/json" },
// });
// }
// }
// }
return NextResponse.next();
}
export const config = {
matcher: "/api/:path*",
};