🔒️ Rate limit by ip address (#1155)

This commit is contained in:
Luke Vella 2024-06-17 22:13:40 +01:00 committed by GitHub
parent 491af5c71b
commit f7eda38e0a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 32 additions and 12 deletions

View file

@ -38,6 +38,7 @@
"@trpc/react-query": "^10.13.0",
"@upstash/ratelimit": "^1.2.1",
"@vercel/kv": "^2.0.0",
"request-ip": "^3.3.0",
"@vercel/functions": "^1.0.2",
"accept-language-parser": "^1.5.0",
"autoprefixer": "^10.4.13",
@ -83,6 +84,7 @@
"@rallly/eslint-config": "*",
"@types/accept-language-parser": "^1.5.3",
"@types/color-hash": "^1.0.2",
"@types/request-ip": "^0.0.41",
"@types/lodash": "^4.14.178",
"@types/react-big-calendar": "^1.8.8",
"@types/smoothscroll-polyfill": "^0.3.1",

View file

@ -4,6 +4,7 @@ import * as Sentry from "@sentry/nextjs";
import { createNextApiHandler } from "@trpc/server/adapters/next";
import { Ratelimit } from "@upstash/ratelimit";
import { kv } from "@vercel/kv";
import requestIp from "request-ip";
import { posthog, posthogApiHandler } from "@/app/posthog";
import { absoluteUrl, shortUrl } from "@/utils/absolute-url";
@ -46,11 +47,18 @@ const trpcApiHandler = createNextApiHandler<AppRouter>({
isEmailBlocked,
absoluteUrl,
shortUrl,
ratelimit: async (key: string) => {
ratelimit: async () => {
if (!process.env.KV_REST_API_URL) {
return { success: true };
}
return ratelimit.limit(key);
const clientIp = requestIp.getClientIp(opts.req);
if (!clientIp) {
return { success: false };
}
return ratelimit.limit(clientIp);
},
});

View file

@ -21,7 +21,7 @@ export interface TRPCContextParams {
*/
absoluteUrl: (path?: string) => string;
shortUrl: (path?: string) => string;
ratelimit: (key: string) => Promise<{ success: boolean }>;
ratelimit: () => Promise<{ success: boolean }>;
}
export const createTRPCContext = async (

View file

@ -24,14 +24,12 @@ export const auth = router({
| { ok: true; token: string }
| { ok: false; reason: "userAlreadyExists" | "emailNotAllowed" }
> => {
if (process.env.KV_REST_API_URL) {
const { success } = await ctx.ratelimit(ctx.user.id);
if (!success) {
throw new TRPCError({
code: "TOO_MANY_REQUESTS",
message: "Too many requests",
});
}
const { success } = await ctx.ratelimit();
if (!success) {
throw new TRPCError({
code: "TOO_MANY_REQUESTS",
message: "Too many requests",
});
}
if (ctx.isEmailBlocked?.(input.email)) {

View file

@ -64,7 +64,7 @@ export const participants = router({
}),
)
.mutation(async ({ ctx, input: { pollId, votes, name, email } }) => {
const { success } = await ctx.ratelimit(ctx.user.id);
const { success } = await ctx.ratelimit();
if (!success) {
throw new TRPCError({

View file

@ -4538,6 +4538,13 @@
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/request-ip@^0.0.41":
version "0.0.41"
resolved "https://registry.yarnpkg.com/@types/request-ip/-/request-ip-0.0.41.tgz#c22a3244df2573402989346062851b06b7a5ac4e"
integrity sha512-Qzz0PM2nSZej4lsLzzNfADIORZhhxO7PED0fXpg4FjXiHuJ/lMyUg+YFF5q8x9HPZH3Gl6N+NOM8QZjItNgGKg==
dependencies:
"@types/node" "*"
"@types/scheduler@*":
version "0.16.2"
resolved "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz"
@ -10990,6 +10997,11 @@ replace-ext@^1.0.0:
resolved "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz"
integrity sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==
request-ip@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/request-ip/-/request-ip-3.3.0.tgz#863451e8fec03847d44f223e30a5d63e369fa611"
integrity sha512-cA6Xh6e0fDBBBwH77SLJaJPBmD3nWVAcF9/XAcsrIHdjhFzFiB5aNQFytdjCGPezU3ROwrR11IddKAM08vohxA==
resize-observer-polyfill@^1.5.1:
version "1.5.1"
resolved "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz"