diff --git a/src/config.ts b/src/config.ts index b82ef5ea..b65e0cfd 100644 --- a/src/config.ts +++ b/src/config.ts @@ -36,6 +36,10 @@ class Conf { static get port(): number { return parseInt(Deno.env.get('PORT') || '4036'); } + /** IP addresses not affected by rate limiting. */ + static get ipWhitelist(): string[] { + return Deno.env.get('IP_WHITELIST')?.split(',') || []; + } /** Relay URL to the Ditto server's relay. */ static get relay(): `wss://${string}` | `ws://${string}` { const { protocol, host } = Conf.url; diff --git a/src/controllers/nostr/relay.ts b/src/controllers/nostr/relay.ts index 4c7feea8..5412cdc1 100644 --- a/src/controllers/nostr/relay.ts +++ b/src/controllers/nostr/relay.ts @@ -210,7 +210,12 @@ const relayController: AppController = (c, next) => { return c.text('Please use a Nostr client to connect.', 400); } - const ip = c.req.header('x-real-ip'); + let ip = c.req.header('x-real-ip'); + + if (ip && Conf.ipWhitelist.includes(ip)) { + ip = undefined; + } + if (ip) { const remaining = Object .values(limiters) diff --git a/src/middleware/rateLimitMiddleware.ts b/src/middleware/rateLimitMiddleware.ts index e7a43328..4d243d2c 100644 --- a/src/middleware/rateLimitMiddleware.ts +++ b/src/middleware/rateLimitMiddleware.ts @@ -1,6 +1,8 @@ import { MiddlewareHandler } from '@hono/hono'; import { rateLimiter } from 'hono-rate-limiter'; +import { Conf } from '@/config.ts'; + /** * Rate limit middleware for Hono, based on [`hono-rate-limiter`](https://github.com/rhinobase/hono-rate-limiter). */ @@ -14,7 +16,10 @@ export function rateLimitMiddleware(limit: number, windowMs: number, includeHead c.header('Cache-Control', 'no-store'); return c.text('Too many requests, please try again later.', 429); }, - skip: (c) => !c.req.header('x-real-ip'), + skip: (c) => { + const ip = c.req.header('x-real-ip'); + return !ip || Conf.ipWhitelist.includes(ip); + }, keyGenerator: (c) => c.req.header('x-real-ip')!, }); }