mirror of
https://github.com/AustinKelsay/plebdevs.git
synced 2025-06-06 09:12:05 +00:00
Add rate limiting / origin middleware using vercel kv and upstash, need to deploy to fully test
This commit is contained in:
parent
f48559bb29
commit
3ce3a2f037
44
package-lock.json
generated
44
package-lock.json
generated
@ -25,6 +25,8 @@
|
|||||||
"@tanstack/react-query": "^5.51.21",
|
"@tanstack/react-query": "^5.51.21",
|
||||||
"@uiw/react-markdown-preview": "^5.1.2",
|
"@uiw/react-markdown-preview": "^5.1.2",
|
||||||
"@uiw/react-md-editor": "^3.11.0",
|
"@uiw/react-md-editor": "^3.11.0",
|
||||||
|
"@upstash/ratelimit": "^2.0.3",
|
||||||
|
"@vercel/kv": "^3.0.0",
|
||||||
"axios": "^1.7.2",
|
"axios": "^1.7.2",
|
||||||
"bech32": "^2.0.0",
|
"bech32": "^2.0.0",
|
||||||
"chart.js": "^4.4.4",
|
"chart.js": "^4.4.4",
|
||||||
@ -5065,6 +5067,48 @@
|
|||||||
"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
|
"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/@upstash/core-analytics": {
|
||||||
|
"version": "0.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@upstash/core-analytics/-/core-analytics-0.0.10.tgz",
|
||||||
|
"integrity": "sha512-7qJHGxpQgQr9/vmeS1PktEwvNAF7TI4iJDi8Pu2CFZ9YUGHZH4fOP5TfYlZ4aVxfopnELiE4BS4FBjyK7V1/xQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@upstash/redis": "^1.28.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@upstash/ratelimit": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@upstash/ratelimit/-/ratelimit-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-BMUpZPZ9IMwrUwohw0HoVAwjBRo5SDb0riAxfCGrLbutuZTPiVagh017Cm3GfhMqwUWLOp0xJQxTCXp812UJVQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@upstash/core-analytics": "^0.0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@upstash/redis": {
|
||||||
|
"version": "1.34.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@upstash/redis/-/redis-1.34.0.tgz",
|
||||||
|
"integrity": "sha512-TrXNoJLkysIl8SBc4u9bNnyoFYoILpCcFJcLyWCccb/QSUmaVKdvY0m5diZqc3btExsapcMbaw/s/wh9Sf1pJw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"crypto-js": "^4.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vercel/kv": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vercel/kv/-/kv-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-pKT8fRnfyYk2MgvyB6fn6ipJPCdfZwiKDdw7vB+HL50rjboEBHDVBEcnwfkEpVSp2AjNtoaOUH7zG+bVC/rvSg==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@upstash/redis": "^1.34.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@vladfrangu/async_event_emitter": {
|
"node_modules/@vladfrangu/async_event_emitter": {
|
||||||
"version": "2.4.6",
|
"version": "2.4.6",
|
||||||
"resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.4.6.tgz",
|
"resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.4.6.tgz",
|
||||||
|
@ -26,6 +26,8 @@
|
|||||||
"@tanstack/react-query": "^5.51.21",
|
"@tanstack/react-query": "^5.51.21",
|
||||||
"@uiw/react-markdown-preview": "^5.1.2",
|
"@uiw/react-markdown-preview": "^5.1.2",
|
||||||
"@uiw/react-md-editor": "^3.11.0",
|
"@uiw/react-md-editor": "^3.11.0",
|
||||||
|
"@upstash/ratelimit": "^2.0.3",
|
||||||
|
"@vercel/kv": "^3.0.0",
|
||||||
"axios": "^1.7.2",
|
"axios": "^1.7.2",
|
||||||
"bech32": "^2.0.0",
|
"bech32": "^2.0.0",
|
||||||
"chart.js": "^4.4.4",
|
"chart.js": "^4.4.4",
|
||||||
|
46
src/middleware.js
Normal file
46
src/middleware.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { NextResponse } from 'next/server';
|
||||||
|
import { Ratelimit } from '@upstash/ratelimit';
|
||||||
|
import { kv } from '@vercel/kv';
|
||||||
|
|
||||||
|
const FRONTEND_HOSTNAME = process.env.FRONTEND_HOSTNAME
|
||||||
|
const FRONTEND_STAGING_HOSTNAME = process.env.FRONTEND_STAGING_HOSTNAME
|
||||||
|
|
||||||
|
const ratelimit = new Ratelimit({
|
||||||
|
redis: kv,
|
||||||
|
// 5 requests from the same IP in 10 seconds
|
||||||
|
limiter: Ratelimit.slidingWindow(5, '10 s'),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const config = {
|
||||||
|
matcher: ['/api/:path*'],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function combinedMiddleware(request) {
|
||||||
|
const ip = request.ip ?? '127.0.0.1';
|
||||||
|
const hostname = request.nextUrl.hostname;
|
||||||
|
const referer = request.headers.get('referer') || '';
|
||||||
|
|
||||||
|
// Bypass rate limiting and referer check for the deployment IP
|
||||||
|
if (hostname === FRONTEND_HOSTNAME || hostname === FRONTEND_STAGING_HOSTNAME) {
|
||||||
|
return NextResponse.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bypass referer check for paths following /link
|
||||||
|
if (request.nextUrl.pathname.startsWith('/.well-known')) {
|
||||||
|
const { success } = await ratelimit.limit(ip);
|
||||||
|
return success
|
||||||
|
? NextResponse.next()
|
||||||
|
: NextResponse.redirect(new URL('/blocked', request.url));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply referer check for all other routes
|
||||||
|
if (!referer.startsWith(FRONTEND_HOSTNAME) && !referer.startsWith(FRONTEND_STAGING_HOSTNAME)) {
|
||||||
|
return new NextResponse(JSON.stringify({ error: 'Forbidden' }), { status: 403 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply rate limiting for all other routes
|
||||||
|
const { success } = await ratelimit.limit(ip);
|
||||||
|
return success
|
||||||
|
? NextResponse.next()
|
||||||
|
: NextResponse.redirect(new URL('/blocked', request.url));
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user