fix(security #6): add rate limiting to POST /api/auth/login

Uses express-rate-limit@6 (pinned for Node 12 dev compat; Node 18
in prod container is unaffected). Limits each IP to 10 attempts per
15-minute window. Returns 429 with a safe error message on breach.
This commit is contained in:
2026-05-16 16:18:34 +01:00
parent 8f96a5f296
commit 1eadb30481
3 changed files with 38 additions and 13 deletions

26
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "media-download-dashboard",
"version": "1.0.0",
"name": "sofarr",
"version": "0.1.4",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "media-download-dashboard",
"version": "1.0.0",
"name": "sofarr",
"version": "0.1.4",
"license": "MIT",
"dependencies": {
"axios": "^1.6.0",
@@ -14,6 +14,7 @@
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"express-rate-limit": "^6.7.0",
"node-cron": "^3.0.3"
},
"devDependencies": {
@@ -623,6 +624,17 @@
"url": "https://opencollective.com/express"
}
},
"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==",
"engines": {
"node": ">= 12.9.0"
},
"peerDependencies": {
"express": "^4 || ^5"
}
},
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
@@ -2124,6 +2136,12 @@
"vary": "~1.1.2"
}
},
"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==",
"requires": {}
},
"fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",

View File

@@ -9,16 +9,17 @@
"install:all": "npm install"
},
"dependencies": {
"express": "^4.18.2",
"axios": "^1.6.0",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"axios": "^1.6.0",
"node-cron": "^3.0.3",
"cookie-parser": "^1.4.6"
"express": "^4.18.2",
"express-rate-limit": "^6.7.0",
"node-cron": "^3.0.3"
},
"devDependencies": {
"nodemon": "^2.0.22",
"concurrently": "^7.6.0"
"concurrently": "^7.6.0",
"nodemon": "^2.0.22"
},
"keywords": [
"sabnzbd",

View File

@@ -1,12 +1,18 @@
const express = require('express');
const axios = require('axios');
const rateLimit = require('express-rate-limit');
const router = express.Router();
const EMBY_URL = process.env.EMBY_URL;
const EMBY_API_KEY = process.env.EMBY_API_KEY;
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 10,
standardHeaders: true,
legacyHeaders: false,
message: { success: false, error: 'Too many login attempts, please try again later' }
});
// Authenticate user with Emby
router.post('/login', async (req, res) => {
router.post('/login', loginLimiter, async (req, res) => {
try {
const { username, password } = req.body;