use redis store for rate-limit
Some checks failed
Deploy Addon / build (SSH_HOST_2, SSH_KEY_2) (push) Has been cancelled
Deploy Addon / build (SSH_HOST_3, SSH_KEY_3) (push) Has been cancelled
Deploy Addon / build (SSH_HOST_4, SSH_KEY_4) (push) Has been cancelled
Deploy Catalogs / build (push) Has been cancelled

This commit is contained in:
TheBeastLT 2025-12-31 11:05:50 +02:00
parent a386ebcac0
commit 455c7360b8
4 changed files with 141 additions and 12 deletions

View file

@ -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

129
addon/package-lock.json generated
View file

@ -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",

View file

@ -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",

View file

@ -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())