Skip to content

Commit

Permalink
feat: add the new rate limit
Browse files Browse the repository at this point in the history
This rate limit will use the method, path and ip as a key, and will be route based rate limiter. Also, this rate limit will be in memory for now using a Map as the store.
  • Loading branch information
bjarneo committed Jan 28, 2024
1 parent 5a88732 commit f6633a6
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 70 deletions.
57 changes: 7 additions & 50 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
"@fastify/helmet": "^9.1.0",
"@fastify/jwt": "^7.2.3",
"@fastify/multipart": "^7.1.1",
"@fastify/rate-limit": "^8.0.0",
"@fastify/static": "^6.5.0",
"@mantine/core": "^6.0.6",
"@mantine/form": "^6.0.6",
Expand All @@ -54,7 +53,7 @@
"email-validator": "^2.0.4",
"extract-domain": "^2.4.8",
"fastify": "^4.9.1",
"fastify-plugin": "^3.0.0",
"fastify-plugin": "^3.0.1",
"file-type": "^18.0.0",
"generate-password-browser": "^1.1.0",
"ip-range-check": "^0.2.0",
Expand Down
43 changes: 25 additions & 18 deletions server.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,41 @@
// Boot scripts
import('./src/server/bootstrap.js');

import cookie from '@fastify/cookie';
import cors from '@fastify/cors';
import helmet from '@fastify/helmet';
import jwt from '@fastify/jwt';
import fstatic from '@fastify/static';
import config from 'config';
import path from 'path';
import importFastify from 'fastify';
import fs from 'fs';
import { fileURLToPath } from 'url';
import { JSDOM } from 'jsdom';
import importFastify from 'fastify';
import path from 'path';
import { fileURLToPath } from 'url';
import template from 'y8';
import helmet from '@fastify/helmet';
import cors from '@fastify/cors';
import fstatic from '@fastify/static';
import cookie from '@fastify/cookie';
import jwt from '@fastify/jwt';
import rateLimit from '@fastify/rate-limit';

import rateLimit from './src/server/plugins/rate-limit.js';

import adminDecorator from './src/server/decorators/admin.js';
import jwtDecorator from './src/server/decorators/jwt.js';
import userFeatures from './src/server/decorators/user-features.js';
import allowedIp from './src/server/decorators/allowed-ip.js';
import attachment from './src/server/decorators/attachment-upload.js';
import jwtDecorator from './src/server/decorators/jwt.js';
import userFeatures from './src/server/decorators/user-features.js';

import readCookieAllRoutesHandler from './src/server/prehandlers/cookie-all-routes.js';
import readOnlyHandler from './src/server/prehandlers/read-only.js';
import disableUserHandler from './src/server/prehandlers/disable-users.js';
import disableUserAccountCreationHandler from './src/server/prehandlers/disable-user-account-creation.js';
import disableUserHandler from './src/server/prehandlers/disable-users.js';
import readOnlyHandler from './src/server/prehandlers/read-only.js';
import restrictOrganizationEmailHandler from './src/server/prehandlers/restrict-organization-email.js';

import usersRoute from './src/server/controllers/admin/users.js';
import accountRoute from './src/server/controllers/account.js';
import adminSettingsRoute from './src/server/controllers/admin/settings.js';
import usersRoute from './src/server/controllers/admin/users.js';
import authenticationRoute from './src/server/controllers/authentication.js';
import accountRoute from './src/server/controllers/account.js';
import downloadRoute from './src/server/controllers/download.js';
import healthzRoute from './src/server/controllers/healthz.js';
import secretRoute from './src/server/controllers/secret.js';
import statsRoute from './src/server/controllers/stats.js';
import healthzRoute from './src/server/controllers/healthz.js';

const isDev = process.env.NODE_ENV === 'development';

Expand All @@ -45,12 +46,18 @@ const fastify = importFastify({
bodyLimit: MAX_FILE_BYTES,
});

// https://github.com/fastify/fastify-rate-limit
fastify.register(rateLimit, {
prefix: '/api/',
max: 100,
timeWindow: 60 * 1000, // 1 minute
});

// https://github.com/fastify/fastify-rate-limit
/*fastify.register(rateLimit, {
prefix: '/api/',
max: 10000,
timeWindow: '1 minute',
});
});*/

// https://github.com/fastify/fastify-helmet
fastify.register(helmet, {
Expand Down
39 changes: 39 additions & 0 deletions src/server/plugins/rate-limit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import fp from 'fastify-plugin';
import getClientIp from '../helpers/client-ip.js';

const store = new Map();

export default fp(function (fastify, opts, done) {
fastify.decorate('rateLimit', async (req, res) => {
if (!req.url.startsWith(opts.prefix)) {
done();
}

const ip = getClientIp(req.headers);
const key = `${req.method}${req.url}${ip}`;

const currentTime = Date.now();
const resetTime = currentTime + opts.timeWindow;

if (!store.has(key) || currentTime > store.get(key)?.reset) {
store.set(key, {
count: 0,
reset: resetTime,
});
}

const current = store.get(key);
current.count += 1;

if (current.count > opts.max && currentTime <= current.reset) {
return res.code(429).send({ message: 'Too many requests, please try again later.' });
}

res.header('X-RateLimit-Limit', opts.max);
res.header('X-RateLimit-Remaining', opts.max - current.count);
res.header('X-RateLimit-Reset', Math.floor((current.reset - currentTime) / 1000));
});

fastify.addHook('onRequest', fastify.rateLimit);
done();
});

0 comments on commit f6633a6

Please sign in to comment.