diff --git a/apps/token-server/config.ts b/apps/token-server/config.ts --- a/apps/token-server/config.ts +++ b/apps/token-server/config.ts @@ -2,6 +2,14 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +interface TokenServerRateLimits { + windowMs: number; + limit: number; + standardHeaders: 'draft-6' | 'draft-7'; + legacyHeaders: boolean; + message: string; +} + interface TokenServerConfig { port: Number; chronikUrls: string[]; @@ -13,6 +21,7 @@ rejectedDir: string; maxUploadSize: number; whitelist: string[]; + limiter: TokenServerRateLimits; iconSizes: number[]; } @@ -42,6 +51,14 @@ 'chrome-extension://aleabaopoakgpbijdnicepefdiglggfl', // dev extension 'chrome-extension://obldfcmebhllhjlhjbnghaipekcppeag', // prod extension ], + limiter: { + windowMs: 120 * 60 * 1000, // 120 minutes + limit: 3, // Limit each IP to 10 requests per `window` + standardHeaders: 'draft-7', // draft-6: `RateLimit-*` headers; draft-7: combined `RateLimit` header + legacyHeaders: false, // Disable the `X-RateLimit-*` headers. + message: + 'If you really need some eCash, throw up a diff. reviews.bitcoinabc.org', + }, iconSizes: [32, 64, 128, 256, 512], }; diff --git a/apps/token-server/index.ts b/apps/token-server/index.ts --- a/apps/token-server/index.ts +++ b/apps/token-server/index.ts @@ -10,6 +10,7 @@ import { initializeTelegramBot } from './src/telegram'; import fs from 'fs'; import { Ecc, initWasm } from 'ecash-lib'; +import { rateLimit } from 'express-rate-limit'; // Connect to available in-node chronik servers const chronik = new ChronikClient(config.chronikUrls); @@ -32,6 +33,7 @@ telegramBot, fs, ecc, + rateLimit(config.limiter), ); console.log(`Express server started on port ${config.port}`); diff --git a/apps/token-server/src/routes.ts b/apps/token-server/src/routes.ts --- a/apps/token-server/src/routes.ts +++ b/apps/token-server/src/routes.ts @@ -20,7 +20,7 @@ import { alertNewTokenIcon } from '../src/telegram'; import cashaddr from 'ecashaddrjs'; import { Ecc } from 'ecash-lib'; -import { rateLimit } from 'express-rate-limit'; +import { RateLimitRequestHandler } from 'express-rate-limit'; /** * routes.ts @@ -50,16 +50,6 @@ }, }; -// Basic IP rate limiting -const limiter = rateLimit({ - windowMs: 60 * 60 * 1000, // 10 minutes - limit: 10, // Limit each IP to 10 requests per `window` (here, per 10 minutes). - standardHeaders: 'draft-7', // draft-6: `RateLimit-*` headers; draft-7: combined `RateLimit` header - legacyHeaders: false, // Disable the `X-RateLimit-*` headers. - message: - 'If you really need some eCash, throw up a diff. reviews.bitcoinabc.org', -}); - /** * Standard IP logger function to be called by all endpoints * @param request express request @@ -75,6 +65,7 @@ telegramBot: TelegramBot, fs: any, ecc: Ecc, + limiter: RateLimitRequestHandler, ): http.Server => { // Initialize express const app: Express = express(); diff --git a/apps/token-server/test/routes.test.ts b/apps/token-server/test/routes.test.ts --- a/apps/token-server/test/routes.test.ts +++ b/apps/token-server/test/routes.test.ts @@ -19,6 +19,7 @@ MOCK_UTXO_TOKEN, } from './vectors'; import { Ecc, initWasm } from 'ecash-lib'; +import { rateLimit } from 'express-rate-limit'; describe('routes.js', async function () { let ecc: Ecc; @@ -159,6 +160,14 @@ mockedTgBot as unknown as TelegramBot, fs, ecc, + // We need higher rate limits so we do not rate limit ourselves in the tests + rateLimit({ + windowMs: 60000, + limit: 100, // Limit each IP to 10 requests per `window` + standardHeaders: 'draft-7', // draft-6: `RateLimit-*` headers; draft-7: combined `RateLimit` header + legacyHeaders: false, // Disable the `X-RateLimit-*` headers. + message: 'You have rate limited your own unit tests.', + }), ); }); afterEach(async () => {