fix: remediate audited defects (resolves #29, #30, #31, #32)
Build and Push Docker Image / build (push) Successful in 51s
Licence Check / Licence compatibility and copyright header verification (push) Failing after 1m48s
CI / Security audit (push) Successful in 2m27s
CI / Swagger Validation & Coverage (push) Successful in 2m27s
CI / Tests & coverage (push) Successful in 2m39s
Build and Push Docker Image / build (push) Successful in 51s
Licence Check / Licence compatibility and copyright header verification (push) Failing after 1m48s
CI / Security audit (push) Successful in 2m27s
CI / Swagger Validation & Coverage (push) Successful in 2m27s
CI / Tests & coverage (push) Successful in 2m39s
- Fix permanent qBittorrent fallback degradation by resetting fallback flags during group-by polling (resolves #29) - Fix Ombi webhook key mismatch in status endpoint and test mocks (resolves #30) - Prevent timingSafeEqual TypeErrors on multi-byte CSRF token length mismatches (resolves #31) - Eliminate duplicate write stream on server.log by delegating to index.js console override (resolves #32)
This commit is contained in:
@@ -26,13 +26,14 @@ function verifyCsrf(req, res, next) {
|
||||
return res.status(403).json({ error: 'CSRF token missing' });
|
||||
}
|
||||
|
||||
// Constant-time comparison to prevent timing attacks
|
||||
if (cookieToken.length !== headerToken.length) {
|
||||
const a = Buffer.from(cookieToken);
|
||||
const b = Buffer.from(headerToken);
|
||||
|
||||
// Constant-time comparison of underlying buffer lengths to prevent timing attacks
|
||||
if (a.length !== b.length) {
|
||||
return res.status(403).json({ error: 'CSRF token invalid' });
|
||||
}
|
||||
|
||||
const a = Buffer.from(cookieToken);
|
||||
const b = Buffer.from(headerToken);
|
||||
if (!require('crypto').timingSafeEqual(a, b)) {
|
||||
return res.status(403).json({ error: 'CSRF token invalid' });
|
||||
}
|
||||
|
||||
@@ -392,9 +392,9 @@ router.get('/webhook/status', requireAuth, async (req, res) => {
|
||||
requestProcessing: webhookConfig.enabled || false
|
||||
},
|
||||
stats: metrics ? {
|
||||
eventsReceived: metrics.eventCount || 0,
|
||||
eventsReceived: metrics.eventsReceived || 0,
|
||||
pollsSkipped: metrics.pollsSkipped || 0,
|
||||
lastWebhookTimestamp: metrics.lastEventTimestamp || null
|
||||
lastWebhookTimestamp: metrics.lastWebhookTimestamp || null
|
||||
} : null
|
||||
});
|
||||
} catch (error) {
|
||||
|
||||
@@ -156,6 +156,11 @@ class DownloadClientRegistry {
|
||||
result[type] = [];
|
||||
}
|
||||
|
||||
// Reset fallback flags for qBittorrent clients
|
||||
if (client.resetFallbackFlag) {
|
||||
client.resetFallbackFlag();
|
||||
}
|
||||
|
||||
try {
|
||||
const downloads = await client.getActiveDownloads();
|
||||
result[type].push(...downloads);
|
||||
|
||||
+1
-10
@@ -1,16 +1,7 @@
|
||||
// Copyright (c) 2026 Gordon Bolton. MIT License.
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Use DATA_DIR so the non-root container user (UID 1000) can write logs.
|
||||
// Falls back to ../../data/server.log (same directory index.js uses).
|
||||
const DATA_DIR = process.env.DATA_DIR || path.join(__dirname, '../../data');
|
||||
if (!fs.existsSync(DATA_DIR)) fs.mkdirSync(DATA_DIR, { recursive: true });
|
||||
|
||||
const logFile = fs.createWriteStream(path.join(DATA_DIR, 'server.log'), { flags: 'a' });
|
||||
|
||||
function logToFile(message) {
|
||||
logFile.write(`[${new Date().toISOString()}] ${message}\n`);
|
||||
console.log(message);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
Reference in New Issue
Block a user