Skip to content

Commit

Permalink
feat(console): adding Rate Limiter middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
xmlking committed Jan 18, 2024
1 parent 2497fed commit ca02542
Show file tree
Hide file tree
Showing 24 changed files with 913 additions and 889 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ PUBLIC_GRAPHQL_ENDPOINT=api.mycompany.com:443 turbo dev
To update the packages to their latest versions in `package.json`

```shell
# TODO: not at available for pnpm
pnpm up --latest -r
pnpm audit --fix
```
Expand Down
32 changes: 16 additions & 16 deletions apps/console-fb/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,36 +27,36 @@
"generate": "concurrently pnpm:generate:*"
},
"devDependencies": {
"@auth/core": "0.20.0",
"@auth/hasura-adapter": "0.2.13",
"@auth/sveltekit": "0.5.2",
"@auth/core": "0.21.0",
"@auth/hasura-adapter": "0.2.14",
"@auth/sveltekit": "0.6.0",
"@ethercorps/sveltekit-og": "3.0.0",
"@neoconfetti/svelte": "2.2.1",
"@neodrag/svelte": "2.0.3",
"@popperjs/core": "2.11.8",
"@skeletonlabs/skeleton": "2.7.0",
"@skeletonlabs/skeleton": "2.7.1",
"@spectacular/eslint-config": "workspace:*",
"@spectacular/prettier-config": "workspace:*",
"@spectacular/typescript-config": "workspace:*",
"@spectacular/utils": "workspace:*",
"@svelte-put/resize": "3.0.0",
"@sveltejs/adapter-auto": "3.1.0",
"@sveltejs/adapter-node": "3.0.0",
"@sveltejs/adapter-vercel": "4.0.4",
"@sveltejs/adapter-node": "3.0.1",
"@sveltejs/adapter-vercel": "4.0.5",
"@sveltejs/enhanced-img": "0.1.8",
"@sveltejs/kit": "2.3.2",
"@sveltejs/kit": "2.3.3",
"@sveltejs/vite-plugin-svelte": "3.0.1",
"@tailwindcss/container-queries": "0.1.1",
"@testing-library/jest-dom": "6.2.0",
"@testing-library/svelte": "4.0.5",
"@types/gtag.js": "0.0.18",
"@types/js-cookie": "3.0.6",
"@types/node": "20.11.3",
"@types/node": "20.11.5",
"@typescript-eslint/eslint-plugin": "6.19.0",
"@typescript-eslint/parser": "6.19.0",
"@vercel/analytics": "1.1.1",
"@vite-pwa/sveltekit": "0.3.0",
"@vitest/coverage-v8": "1.2.0",
"@vitest/coverage-v8": "1.2.1",
"autoprefixer": "10.4.16",
"c8": "9.1.0",
"cross-fetch": "4.0.0",
Expand All @@ -80,21 +80,21 @@
"js-cookie": "3.0.5",
"jsdom": "23.2.0",
"layercake": "8.0.2",
"msw": "2.1.0",
"msw": "2.1.2",
"postcss": "8.4.33",
"postcss-preset-env": "9.3.0",
"prettier": "3.2.2",
"prettier": "3.2.4",
"prettier-plugin-svelte": "3.1.2",
"prettier-plugin-tailwindcss": "0.5.11",
"svelte": "4.2.8",
"svelte": "4.2.9",
"svelte-adapter-bun": "0.5.1",
"svelte-check": "3.6.3",
"svelte-headless-table": "0.18.1",
"svelte-meta-tags": "3.1.0",
"svelte-select": "5.8.3",
"svelte-time-distance": "0.0.3",
"sveltekit-flash-message": "2.3.1",
"sveltekit-rate-limiter": "0.4.2",
"sveltekit-rate-limiter": "0.4.3",
"sveltekit-superforms": "1.13.3",
"sveltekit-view-transition": "0.5.3",
"tailwind-merge": "2.2.0",
Expand All @@ -105,13 +105,13 @@
"vite": "5.0.11",
"vite-plugin-pwa": "0.17.4",
"vite-plugin-tailwind-purgecss": "0.2.0",
"vitest": "1.2.0",
"vitest": "1.2.1",
"workbox-window": "7.0.0",
"zod": "3.22.4"
},
"optionalDependencies": {
"@playwright/test": "1.40.1",
"@vitest/ui": "1.2.0"
"@playwright/test": "1.41.0",
"@vitest/ui": "1.2.1"
},
"dependencies": {
"cookie": "0.6.0"
Expand Down
20 changes: 10 additions & 10 deletions apps/console-sc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@
"@spectacular/utils": "workspace:*",
"@sveltejs/adapter-auto": "3.1.0",
"@sveltejs/enhanced-img": "0.1.8",
"@sveltejs/kit": "2.3.2",
"@sveltejs/kit": "2.3.3",
"@sveltejs/vite-plugin-svelte": "3.0.1",
"@tailwindcss/container-queries": "0.1.1",
"@tailwindcss/forms": "0.5.7",
"@tailwindcss/typography": "0.5.10",
"@types/eslint": "8.56.2",
"@types/node": "20.11.3",
"@types/node": "20.11.5",
"@typescript-eslint/eslint-plugin": "6.19.0",
"@typescript-eslint/parser": "6.19.0",
"@vincjo/datatables": "1.14.2",
Expand All @@ -44,17 +44,17 @@
"eslint-config-prettier": "9.1.0",
"eslint-plugin-svelte": "2.35.1",
"formsnap": "0.4.2",
"lucide-svelte": "0.309.0",
"lucide-svelte": "0.311.0",
"postcss": "8.4.33",
"postcss-import": "16.0.0",
"postcss-load-config": "5.0.2",
"postcss-nested": "6.0.1",
"prettier": "3.2.2",
"prettier": "3.2.4",
"prettier-plugin-svelte": "3.1.2",
"prettier-plugin-tailwindcss": "0.5.11",
"svelte": "4.2.8",
"svelte": "4.2.9",
"svelte-check": "3.6.3",
"sveltekit-rate-limiter": "0.4.2",
"sveltekit-rate-limiter": "0.4.3",
"sveltekit-superforms": "1.13.3",
"sveltekit-view-transition": "0.5.3",
"tailwind-merge": "2.2.0",
Expand All @@ -66,12 +66,12 @@
"typescript": "5.3.3",
"vite": "5.0.11",
"vite-plugin-tailwind-purgecss": "0.2.0",
"vite-tsconfig-paths": "4.2.3",
"vitest": "1.2.0",
"vite-tsconfig-paths": "4.3.1",
"vitest": "1.2.1",
"zod": "3.22.4"
},
"optionalDependencies": {
"@playwright/test": "1.40.1",
"@vitest/ui": "1.2.0"
"@playwright/test": "1.41.0",
"@vitest/ui": "1.2.1"
}
}
4 changes: 4 additions & 0 deletions apps/console/.env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
VERCEL_ENV=dev
# RATE_LIMIT_SECRET: On UNIX systems you can use `openssl rand -hex 32` or
# https://generate-secret.vercel.app/64 to generate a secret.
# or copy (openssl rand -hex 64) output here
RATE_LIMIT_SECRET='fill-me-in'

### Privacy and Terms ###
PUBLIC_TERMS_PRIVACY_COMPANY='Your Company'
Expand Down
36 changes: 18 additions & 18 deletions apps/console/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,34 +28,34 @@
"@floating-ui/dom": "1.5.4",
"@fontsource-variable/inter": "5.0.16",
"@inlang/cli": "2.4.0",
"@inlang/paraglide-js": "1.2.0",
"@inlang/paraglide-js-adapter-vite": "1.2.2",
"@inlang/paraglide-js": "1.2.1",
"@inlang/paraglide-js-adapter-vite": "1.2.4",
"@nhost/nhost-js": "3.0.1",
"@skeletonlabs/skeleton": "2.7.0",
"@skeletonlabs/skeleton": "2.7.1",
"@skeletonlabs/tw-plugin": "0.3.1",
"@spectacular/eslint-config": "workspace:*",
"@spectacular/prettier-config": "workspace:*",
"@spectacular/skeleton": "workspace:*",
"@spectacular/typescript-config": "workspace:*",
"@spectacular/utils": "workspace:*",
"@sveltejs/adapter-auto": "3.1.0",
"@sveltejs/adapter-node": "3.0.0",
"@sveltejs/adapter-vercel": "4.0.4",
"@sveltejs/adapter-node": "3.0.1",
"@sveltejs/adapter-vercel": "4.0.5",
"@sveltejs/enhanced-img": "0.1.8",
"@sveltejs/kit": "2.3.2",
"@sveltejs/kit": "2.3.3",
"@sveltejs/vite-plugin-svelte": "3.0.1",
"@tailwindcss/container-queries": "0.1.1",
"@tailwindcss/forms": "0.5.7",
"@tailwindcss/typography": "0.5.10",
"@types/d3-scale": "4.0.8",
"@types/eslint": "8.56.2",
"@types/node": "20.11.3",
"@types/node": "20.11.5",
"@typescript-eslint/eslint-plugin": "6.19.0",
"@typescript-eslint/parser": "6.19.0",
"@vercel/analytics": "1.1.1",
"@vincjo/datatables": "1.14.2",
"@vitest/coverage-v8": "1.2.0",
"@xyflow/svelte": "0.0.33",
"@vitest/coverage-v8": "1.2.1",
"@xyflow/svelte": "0.0.34",
"autoprefixer": "10.4.16",
"d3-array": "3.2.4",
"d3-scale": "4.0.2",
Expand All @@ -69,19 +69,19 @@
"houdini": "1.2.36",
"houdini-svelte": "1.2.36",
"layerchart": "0.27.1",
"lucide-svelte": "0.309.0",
"lucide-svelte": "0.311.0",
"postcss": "8.4.33",
"prettier": "3.2.2",
"prettier": "3.2.4",
"prettier-plugin-svelte": "3.1.2",
"prettier-plugin-tailwindcss": "0.5.11",
"svelte": "4.2.8",
"svelte": "4.2.9",
"svelte-adapter-bun": "0.5.1",
"svelte-check": "3.6.3",
"svelte-meta-tags": "3.1.0",
"svelte-ux": "0.57.3",
"sveltekit-flash-message": "2.3.1",
"sveltekit-rate-limiter": "0.4.2",
"sveltekit-superforms": "2.0.0-alpha.18",
"sveltekit-rate-limiter": "0.4.3",
"sveltekit-superforms": "2.0.0-alpha.22",
"sveltekit-view-transition": "0.5.3",
"tailwind-merge": "2.2.0",
"tailwind-variants": "0.1.20",
Expand All @@ -91,13 +91,13 @@
"typescript": "5.3.3",
"vite": "5.0.11",
"vite-plugin-tailwind-purgecss": "0.2.0",
"vite-tsconfig-paths": "4.2.3",
"vitest": "1.2.0",
"vite-tsconfig-paths": "4.3.1",
"vitest": "1.2.1",
"xstate": "4.38.3",
"zod": "3.22.4"
},
"optionalDependencies": {
"@playwright/test": "1.40.1",
"@vitest/ui": "1.2.0"
"@playwright/test": "1.41.0",
"@vitest/ui": "1.2.1"
}
}
1 change: 1 addition & 0 deletions apps/console/project.inlang/project_id
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
e6731b45f2ca8b05c752c4fecae9b158497987233dcfaa0d6965a2672be8ea04
8 changes: 4 additions & 4 deletions apps/console/src/lib/server/limiter/limiter.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { RateLimiter } from 'sveltekit-rate-limiter/server';
import { RATE_LIMITER_KEY } from '$env/static/private';
import { RetryAfterRateLimiter } from 'sveltekit-rate-limiter/server';
import { RATE_LIMIT_SECRET } from '$env/static/private';

export const limiter = new RateLimiter({
export const limiter = new RetryAfterRateLimiter({
// A rate is defined as [number, unit]
rates: {
IP: [10, 'h'], // IP address limiter
IPUA: [5, 'm'], // IP + User Agent limiter
cookie: {
// Cookie limiter
name: 'limiterid', // Unique cookie name for this limiter
secret: RATE_LIMITER_KEY, // Use $env/static/private
secret: RATE_LIMIT_SECRET, // Use $env/static/private
rate: [2, 'm'],
preflight: true // Require preflight call (see load function)
}
Expand Down
27 changes: 0 additions & 27 deletions apps/console/src/lib/server/middleware/links.ts

This file was deleted.

44 changes: 44 additions & 0 deletions apps/console/src/lib/server/middleware/rate-limiter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import type { Handle } from '@sveltejs/kit';
import { Logger, startsWith } from '@spectacular/utils';
import { dev } from '$app/environment';
import { limiter } from '$lib/server/limiter/limiter';

/**
* Rate Limit some routes
* This should be the first middleware.
*/
const log = new Logger('server:middleware:limiter');
const rateLimitedPaths = ['/auth/sign-up', '/auth/forgot-password', '/auth/change-password', '/downlaod'];

export const rateLimiter = (async ({ event, resolve }) => {
const {
url: { pathname }
} = event;

// bypass limiter for all protected routes.
if (dev || !startsWith(pathname, rateLimitedPaths)) {
return await resolve(event);
}

await limiter.cookieLimiter?.preflight(event);

const status = await limiter.check(event);
log.debug({ status });

console.log(status);
if (status.limited) {
event.setHeaders({
'Retry-After': status.retryAfter.toString()
});
return new Response('Too many requests', {
status: 429,
headers: {
'Retry-After': status.retryAfter.toString()
},
statusText: 'You have made too many requests, please try again later.'
});
}

const response = await resolve(event);
return response;
}) satisfies Handle;
20 changes: 16 additions & 4 deletions apps/console/src/routes/[[lang=lang]]/auth/sign-up/+page.server.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { fail, error as swError } from '@sveltejs/kit';
import { fail } from '@sveltejs/kit';
import { redirect as redirectWithFlash } from 'sveltekit-flash-message/server';
import { message, setError, superValidate } from 'sveltekit-superforms';
import { zod } from 'sveltekit-superforms/adapters';
Expand Down Expand Up @@ -40,13 +40,25 @@ export const actions = {
cookies,
locals: { lang, nhost }
} = event;
// Every call to `isLimited` counts as a hit towards the rate limit for the event.
if (await limiter.isLimited(event)) swError(429);

const form = await superValidate(request, zod(signUpSchema));

const status = await limiter.check(event);
if (status.limited) {
event.setHeaders({
'Retry-After': status.retryAfter.toString()
});
return message(
form,
{
type: 'error',
message: `Rate limit has been reached. Please retry after ${status.retryAfter} seconds`
},
{ status: 429 }
);
}

log.debug({ lang, nhost });
log.debug('raw form:', form);
// await sleep(8000)

if (!form.valid) return fail(400, { form });
Expand Down
Loading

1 comment on commit ca02542

@vercel
Copy link

@vercel vercel bot commented on ca02542 Jan 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

spectacular-docs – ./apps/docs

spectacular-docs-xmlking.vercel.app
spectacular-docs-git-main-xmlking.vercel.app
spectacular-docs.vercel.app

Please sign in to comment.