diff --git a/controller/websocket.js b/controller/websocket.js index 927fb33..3142707 100644 --- a/controller/websocket.js +++ b/controller/websocket.js @@ -1,4 +1,6 @@ const fs = require('node:fs') +const crypto = require('node:crypto') +const { RedisRateLimiter } = require('rolling-rate-limiter') const upload = require('../utils/upload.js') const ytdlp = require('../utils/ytdlp.js') @@ -13,6 +15,13 @@ const logger = require("../utils/logger.js") const { PrismaClient } = require('@prisma/client') const prisma = new PrismaClient() +const limiter = new RedisRateLimiter({ + client: redis, + namespace: 'autodownload:', + interval: 24 * 60 * 60 * 1000, + maxInInterval: 5 +}) + exports.save = async (ws, req) => { logger.info({ message: `${req.path} ${JSON.stringify(req.query)}` }) @@ -310,6 +319,13 @@ exports.addAutodownload = async (req, res) => { if (already) { res.status(500).send(`This channel is already being automatically downloaded...`) } else { + const ipHash = crypto.createHash('sha256').update(req.headers['x-forwarded-for'] || req.connection.remoteAddress).digest('hex') + const isLimited = await limiter.limit(ipHash) + + if (isLimited) return res.status(420).send(`Hey! You have reached the limit of 5 queued auto-download channels per day. Sadly, hard drives don't grow on trees, so rate limits are necessary. The "Save Channel" feature has no limits, so feel free to use that.

+ +Are you planning something awesome? Feel free to email me at admin[@]preservetube.com.`) + await prisma.autodownload.create({ data: { channel: channelId diff --git a/package.json b/package.json index 41ab246..023d01a 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "ioredis": "^5.3.1", "isomorphic-dompurify": "^1.0.0", "node-fetch": "2", + "rolling-rate-limiter": "^0.4.2", "winston": "^3.8.2" }, "devDependencies": { diff --git a/yarn.lock b/yarn.lock index b4545a5..6a3d347 100644 --- a/yarn.lock +++ b/yarn.lock @@ -825,6 +825,14 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== +microtime@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/microtime/-/microtime-3.1.1.tgz#f3ce12f4091c55fb2982c87205e2e7698afdcd0c" + integrity sha512-to1r7o24cDsud9IhN6/8wGmMx5R2kT0w2Xwm5okbYI3d1dk6Xv0m+Z+jg2vS9pt+ocgQHTCtgs/YuyJhySzxNg== + dependencies: + node-addon-api "^5.0.0" + node-gyp-build "^4.4.0" + mime-db@1.52.0: version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" @@ -869,6 +877,11 @@ negotiator@0.6.3: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== +node-addon-api@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.1.0.tgz#49da1ca055e109a23d537e9de43c09cca21eb762" + integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA== + node-fetch@2: version "2.6.9" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" @@ -883,6 +896,11 @@ node-fetch@^2.6.12: dependencies: whatwg-url "^5.0.0" +node-gyp-build@^4.4.0: + version "4.6.1" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.1.tgz#24b6d075e5e391b8d5539d98c7fc5c210cac8a3e" + integrity sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ== + nwsapi@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.2.tgz#e5418863e7905df67d51ec95938d67bf801f0bb0" @@ -1034,6 +1052,14 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== +rolling-rate-limiter@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/rolling-rate-limiter/-/rolling-rate-limiter-0.4.2.tgz#19204ceabf4e4e421681bfe876a779d5b0d2282b" + integrity sha512-4lKCwwuINmfPvyfLtvAHn+SiwXisH8fmmEvTSHYAenAfKF0p6IErkUEIS+9dvWAslU+97WtX000ne26RAToo2w== + dependencies: + microtime "^3.0.0" + uuid "^9.0.0" + safe-buffer@5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -1241,6 +1267,11 @@ uuid@3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== +uuid@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"