From 720f2b6acb39fa7f6d1149f79e46c2dbc591af7a Mon Sep 17 00:00:00 2001 From: httpjamesm Date: Mon, 31 Oct 2022 18:05:19 -0400 Subject: [PATCH] feat: IP ratelimit for media proxy --- src/pages/api/media_proxy.ts | 47 ++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/pages/api/media_proxy.ts b/src/pages/api/media_proxy.ts index 4e6e2d0..1cffb04 100644 --- a/src/pages/api/media_proxy.ts +++ b/src/pages/api/media_proxy.ts @@ -9,6 +9,50 @@ export default async function handler( req: NextApiRequest, res: NextApiResponse ) { + const userIp = + (req.headers['cf-connecting-ip'] as string) || + (req.headers['x-real-ip'] as string) || + req.socket.remoteAddress || + null + + if (!userIp) { + res.status(500) + res.json({ + success: false, + message: 'Unable to enforce ratelimit', + }) + return + } + + // hash ip with md5 (for speed) + const ipHash = crypto.createHash('md5').update(userIp).digest('hex') + + const key = `ip_ratelimit:${ipHash}` + + // check if ip is in redis + let ipInRedis = await redis.get(key) + + if (!ipInRedis) { + // if not, set it to 1 + await redis.setex(key, 30, '1') + ipInRedis = '1' + } + + const ipReqNumber = Number(ipInRedis) + + if (ipReqNumber > 60) { + res.status(429) + res.setHeader('x-cringe', 'stop abusing a FOSS service') + res.json({ + success: false, + message: 'Too many requests', + }) + return + } + + // increment ip in redis + await redis.set(key, String(ipReqNumber + 1)) + // get query param const mediaUrl = (req.query as { url: string }).url @@ -89,10 +133,13 @@ export default async function handler( if (cachedMedia) { res.status(302) + res.setHeader('x-cached', 'true') res.send(cachedMedia) return } + res.setHeader('x-cached', 'false') + // download media const mediaRes = await fetch(mediaUrl)