From 455c7360b898fd2459d34ac678f6bf0b87869046 Mon Sep 17 00:00:00 2001 From: TheBeastLT Date: Wed, 31 Dec 2025 11:05:50 +0200 Subject: [PATCH] use redis store for rate-limit --- .github/workflows/deploy_addon.yml | 2 +- addon/package-lock.json | 129 +++++++++++++++++++++++++++-- addon/package.json | 4 +- addon/serverless.js | 18 +++- 4 files changed, 141 insertions(+), 12 deletions(-) diff --git a/.github/workflows/deploy_addon.yml b/.github/workflows/deploy_addon.yml index 1a0635e..9d26320 100644 --- a/.github/workflows/deploy_addon.yml +++ b/.github/workflows/deploy_addon.yml @@ -50,5 +50,5 @@ jobs: docker load -i /tmp/docker/torrentio_addon_latest.tar docker stop torrentio-addon docker rm torrentio-addon - docker run -p ${{ secrets.PORT }}:7000 -d --name torrentio-addon --restart always --log-opt max-size=100m --network host -e PORT=${{ secrets.PORT }} -e MONGODB_URI=${{ secrets.MONGODB_URI }} -e DATABASE_URI=${{ secrets.DATABASE_URI }} -e PROXY_HOSTS=${{ secrets.PROXY_HOSTS }} -e PROXY_USERNAME=${{ secrets.PROXY_USERNAME }} -e PROXY_PASSWORD=${{ secrets.PROXY_PASSWORD }} -e METRICS_USER=${{ secrets.METRICS_USER }} -e METRICS_PASSWORD=${{ secrets.METRICS_PASSWORD }} torrentio-addon:latest + docker run -p ${{ secrets.PORT }}:7000 -d --name torrentio-addon --restart always --log-opt max-size=100m --network host -e PORT=${{ secrets.PORT }} -e MONGODB_URI=${{ secrets.MONGODB_URI }} -e DATABASE_URI=${{ secrets.DATABASE_URI }} -e REDIS_URL=${{ secrets.REDIS_URL }} -e METRICS_USER=${{ secrets.METRICS_USER }} -e METRICS_PASSWORD=${{ secrets.METRICS_PASSWORD }} torrentio-addon:latest docker image prune -f diff --git a/addon/package-lock.json b/addon/package-lock.json index b205e30..504ba85 100644 --- a/addon/package-lock.json +++ b/addon/package-lock.json @@ -17,7 +17,7 @@ "cacheable": "^1.8.10", "cors": "^2.8.5", "debrid-link-api": "^1.0.1", - "express-rate-limit": "^6.7.0", + "express-rate-limit": "^8.2.1", "magnet-uri": "^6.2.0", "name-to-imdb": "^3.0.4", "named-queue": "^2.2.1", @@ -27,7 +27,9 @@ "pg": "^8.16.3", "premiumize-api": "^1.0.3", "prom-client": "^14.2.0", + "rate-limit-redis": "^4.3.1", "real-debrid-api": "git://github.com/TheBeastLT/node-real-debrid.git#d1f7eaa8593b947edbfbc8a92a176448b48ef445", + "redis": "^5.10.0", "request-ip": "^3.3.0", "router": "^1.3.8", "sequelize": "^6.37.7", @@ -99,6 +101,67 @@ "follow-redirects": "^1.14.0" } }, + "node_modules/@redis/bloom": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-5.10.0.tgz", + "integrity": "sha512-doIF37ob+l47n0rkpRNgU8n4iacBlKM9xLiP1LtTZTvz8TloJB8qx/MgvhMhKdYG+CvCY2aPBnN2706izFn/4A==", + "license": "MIT", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@redis/client": "^5.10.0" + } + }, + "node_modules/@redis/client": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-5.10.0.tgz", + "integrity": "sha512-JXmM4XCoso6C75Mr3lhKA3eNxSzkYi3nCzxDIKY+YOszYsJjuKbFgVtguVPbLMOttN4iu2fXoc2BGhdnYhIOxA==", + "license": "MIT", + "peer": true, + "dependencies": { + "cluster-key-slot": "1.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@redis/json": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-5.10.0.tgz", + "integrity": "sha512-B2G8XlOmTPUuZtD44EMGbtoepQG34RCDXLZbjrtON1Djet0t5Ri7/YPXvL9aomXqP8lLTreaprtyLKF4tmXEEA==", + "license": "MIT", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@redis/client": "^5.10.0" + } + }, + "node_modules/@redis/search": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-5.10.0.tgz", + "integrity": "sha512-3SVcPswoSfp2HnmWbAGUzlbUPn7fOohVu2weUQ0S+EMiQi8jwjL+aN2p6V3TI65eNfVsJ8vyPvqWklm6H6esmg==", + "license": "MIT", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@redis/client": "^5.10.0" + } + }, + "node_modules/@redis/time-series": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-5.10.0.tgz", + "integrity": "sha512-cPkpddXH5kc/SdRhF0YG0qtjL+noqFT0AcHbQ6axhsPsO7iqPi1cjxgdkE9TNeKiBUUdCaU1DbqkR/LzbzPBhg==", + "license": "MIT", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@redis/client": "^5.10.0" + } + }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -416,6 +479,15 @@ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -755,14 +827,22 @@ } }, "node_modules/express-rate-limit": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-6.7.0.tgz", - "integrity": "sha512-vhwIdRoqcYB/72TK3tRZI+0ttS8Ytrk24GfmsxDXK9o9IhHNO5bXRiXQSExPQ4GbaE5tvIS7j1SGrxsuWs+sGA==", + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.2.1.tgz", + "integrity": "sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==", + "license": "MIT", + "peer": true, + "dependencies": { + "ip-address": "10.0.1" + }, "engines": { - "node": ">= 12.9.0" + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" }, "peerDependencies": { - "express": "^4 || ^5" + "express": ">= 4.11" } }, "node_modules/ext": { @@ -1116,6 +1196,15 @@ "node": ">=6.0.0" } }, + "node_modules/ip-address": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", + "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -1849,6 +1938,18 @@ "node": ">= 0.6" } }, + "node_modules/rate-limit-redis": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/rate-limit-redis/-/rate-limit-redis-4.3.1.tgz", + "integrity": "sha512-+a1zU8+D7L8siDK9jb14refQXz60vq427VuiplgnaLk9B2LnvGe/APLTfhwb4uNIL7eWVknh8GnRp/unCj+lMA==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "peerDependencies": { + "express-rate-limit": ">= 6" + } + }, "node_modules/raw-body": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", @@ -1872,6 +1973,22 @@ "request": "^2.83.0" } }, + "node_modules/redis": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/redis/-/redis-5.10.0.tgz", + "integrity": "sha512-0/Y+7IEiTgVGPrLFKy8oAEArSyEJkU0zvgV5xyi9NzNQ+SLZmyFbUsWIbgPcd4UdUh00opXGKlXJwMmsis5Byw==", + "license": "MIT", + "dependencies": { + "@redis/bloom": "5.10.0", + "@redis/client": "5.10.0", + "@redis/json": "5.10.0", + "@redis/search": "5.10.0", + "@redis/time-series": "5.10.0" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", diff --git a/addon/package.json b/addon/package.json index 2cad621..f3cb187 100644 --- a/addon/package.json +++ b/addon/package.json @@ -17,7 +17,7 @@ "cacheable": "^1.8.10", "cors": "^2.8.5", "debrid-link-api": "^1.0.1", - "express-rate-limit": "^6.7.0", + "express-rate-limit": "^8.2.1", "magnet-uri": "^6.2.0", "name-to-imdb": "^3.0.4", "named-queue": "^2.2.1", @@ -27,7 +27,9 @@ "pg": "^8.16.3", "premiumize-api": "^1.0.3", "prom-client": "^14.2.0", + "rate-limit-redis": "^4.3.1", "real-debrid-api": "git://github.com/TheBeastLT/node-real-debrid.git#d1f7eaa8593b947edbfbc8a92a176448b48ef445", + "redis": "^5.10.0", "request-ip": "^3.3.0", "router": "^1.3.8", "sequelize": "^6.37.7", diff --git a/addon/serverless.js b/addon/serverless.js index 6a66a06..bff9270 100644 --- a/addon/serverless.js +++ b/addon/serverless.js @@ -3,6 +3,8 @@ import cors from 'cors'; import rateLimit from "express-rate-limit"; import requestIp from 'request-ip'; import userAgentParser from 'ua-parser-js'; +import { createClient } from 'redis' +import { RedisStore } from 'rate-limit-redis' import addonInterface from './addon.js'; import qs from 'querystring'; import { manifest } from './lib/manifest.js'; @@ -11,11 +13,19 @@ import landingTemplate from './lib/landingTemplate.js'; import * as moch from './moch/moch.js'; const router = new Router(); +const client = createClient({ + url: process.env.REDIS_URL, +}) +await client.connect() const limiter = rateLimit({ - windowMs: 60 * 60 * 1000, // 1 hour - max: 300, // limit each IP to 300 requests per windowMs - headers: false, - keyGenerator: (req) => requestIp.getClientIp(req) + windowMs: 24 * 60 * 60 * 1000, // 1 day + limit: 5000, + legacyHeaders: false, + passOnStoreError: true, + keyGenerator: (req) => requestIp.getClientIp(req), + store: new RedisStore({ + sendCommand: (...args) => client.sendCommand(args), + }), }) router.use(cors())