diff --git a/bun.lockb b/bun.lockb index d2abc85..f5a6b33 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index a0a3dff..0a7f2a4 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "svelte": "^4.2.19", "svelte-adapter-bun": "^0.5.2", "svelte-check": "^3.8.6", + "sveltekit-rate-limiter": "^0.6.1", "tailwindcss": "^3.4.15", "tslib": "^2.8.1", "typescript": "^5.7.2", diff --git a/src/routes/guestbook/+page.server.ts b/src/routes/guestbook/+page.server.ts index d69c9fb..d5e52b9 100644 --- a/src/routes/guestbook/+page.server.ts +++ b/src/routes/guestbook/+page.server.ts @@ -1,10 +1,16 @@ import { env } from '$env/dynamic/private' -import { redirect, type Cookies } from '@sveltejs/kit' +import { redirect, type Cookies, type RequestEvent } from '@sveltejs/kit' import auth from '$lib/guestbookAuth' import { scopeCookies as _scopeCookies } from '$lib'; +import { RetryAfterRateLimiter } from 'sveltekit-rate-limiter/server'; export const prerender = false; +const createPostRatelimiter = new RetryAfterRateLimiter({ + IP: [10, 'd'], + IPUA: [5, 'h'], +}) + interface Entry { author: string, content: string, @@ -16,9 +22,15 @@ const scopeCookies = (cookies: Cookies) => { } const postAction = (client: any, scopes: string[]) => { - return async ({ request, cookies }: { request: Request, cookies: Cookies }) => { + return async (event: RequestEvent) => { + const { request, cookies } = event const scopedCookies = scopeCookies(cookies) scopedCookies.set("postAuth", client.name) + const rateStatus = await createPostRatelimiter.check(event) + if (rateStatus.limited) { + scopedCookies.set("sendError", `you are being ratelimited sowwy :c, try again after ${rateStatus.retryAfter} seconds`) + redirect(303, auth.callbackUrl) + } const form = await request.formData() const content = form.get("content")?.toString().substring(0, 512) const anon = !(form.get("anon") === null)