diff --git a/middleware.js b/middleware.js new file mode 100644 index 0000000..3ac9925 --- /dev/null +++ b/middleware.js @@ -0,0 +1,14 @@ +import { NextRequest, NextResponse } from 'next/server' +import { Ratelimit } from '@upstash/ratelimit' +import { kv } from '@vercel/kv' + +const rateLimit = new Ratelimit({ + redis: kv, + limiter: Ratelimit.slidingWindow(1000, '1 h'), +}); + +export default async function middleware(request) { + const ip = request.ip || '127.0.0.1' + const { success } = await rateLimit.limit(ip) + return success ? NextResponse.next() : NextResponse.json({ error: 'Too many requests' }, { status: 429 }) +} diff --git a/package.json b/package.json index 6d540e1..21a12f0 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,8 @@ }, "dependencies": { "@next/third-parties": "^14.2.3", + "@upstash/ratelimit": "^2.0.5", + "@vercel/kv": "^3.0.0", "autoprefixer": "10.4.0", "benchmark": "2.1.4", "codejar": "3.2.3", diff --git a/yarn.lock b/yarn.lock index d2170f5..b33d697 100644 --- a/yarn.lock +++ b/yarn.lock @@ -162,6 +162,34 @@ "@types/node" "*" "@types/webidl-conversions" "*" +"@upstash/core-analytics@^0.0.10": + version "0.0.10" + resolved "https://registry.yarnpkg.com/@upstash/core-analytics/-/core-analytics-0.0.10.tgz#e686a313ec2279d5a8d53e6c215085f1c0f5ab4b" + integrity sha512-7qJHGxpQgQr9/vmeS1PktEwvNAF7TI4iJDi8Pu2CFZ9YUGHZH4fOP5TfYlZ4aVxfopnELiE4BS4FBjyK7V1/xQ== + dependencies: + "@upstash/redis" "^1.28.3" + +"@upstash/ratelimit@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@upstash/ratelimit/-/ratelimit-2.0.5.tgz#0e8e693b79bdcf5d8643c38bebe8b76e7b79b54a" + integrity sha512-1FRv0cs3ZlBjCNOCpCmKYmt9BYGIJf0J0R3pucOPE88R21rL7jNjXG+I+rN/BVOvYJhI9niRAS/JaSNjiSICxA== + dependencies: + "@upstash/core-analytics" "^0.0.10" + +"@upstash/redis@^1.28.3", "@upstash/redis@^1.34.0": + version "1.34.3" + resolved "https://registry.yarnpkg.com/@upstash/redis/-/redis-1.34.3.tgz#df0338f4983bba5141878e851be4fced494b44a0" + integrity sha512-VT25TyODGy/8ljl7GADnJoMmtmJ1F8d84UXfGonRRF8fWYJz7+2J6GzW+a6ETGtk4OyuRTt7FRSvFG5GvrfSdQ== + dependencies: + crypto-js "^4.2.0" + +"@vercel/kv@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@vercel/kv/-/kv-3.0.0.tgz#4579153536c9fc0ca8c52d3d7cfe944ccffd08c0" + integrity sha512-pKT8fRnfyYk2MgvyB6fn6ipJPCdfZwiKDdw7vB+HL50rjboEBHDVBEcnwfkEpVSp2AjNtoaOUH7zG+bVC/rvSg== + dependencies: + "@upstash/redis" "^1.34.0" + abab@^2.0.3, abab@^2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" @@ -335,6 +363,11 @@ cookie@^0.5.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== +crypto-js@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631" + integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== + cssesc@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"