Release v1.4.17 with security fixes, stability hardening and retry improvements
- Fix ZIP path traversal vulnerability (reject entries escaping target dir) - Add single instance lock (prevent data corruption from multiple instances) - Add unhandled exception/rejection handlers (prevent silent crashes) - Fix mainWindow reference cleanup on close - Add second-instance handler to focus existing window - Fix claimTargetPath infinite loop (add 10k iteration bound) - Add duplicate startItem guard (prevent concurrent downloads of same item) - Clone session in getSnapshot to prevent live-reference mutation bugs - Clear stateEmitTimer on clearAll to prevent dangling timer emissions - Add extraction timeout safety (4h deadline with logging) - Add dedicated unrestrict retry system with longer backoff for Mega-Debrid errors - Add log rotation (10MB max, keeps one .old backup) - Fix writeExtractResumeState missing mkdir (prevents crash on deleted dirs) - Fix saveSessionAsync EXDEV cross-device rename with copy fallback Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
ea6301d326
commit
d4dd266f6b
@@ -5,6 +5,8 @@ let logFilePath = path.resolve(process.cwd(), "rd_downloader.log");
|
||||
let fallbackLogFilePath: string | null = null;
|
||||
const LOG_FLUSH_INTERVAL_MS = 120;
|
||||
const LOG_BUFFER_LIMIT_CHARS = 1_000_000;
|
||||
const LOG_MAX_FILE_BYTES = 10 * 1024 * 1024;
|
||||
let lastRotateCheckAt = 0;
|
||||
|
||||
let pendingLines: string[] = [];
|
||||
let pendingChars = 0;
|
||||
@@ -90,6 +92,29 @@ function scheduleFlush(immediate = false): void {
|
||||
}, LOG_FLUSH_INTERVAL_MS);
|
||||
}
|
||||
|
||||
function rotateIfNeeded(filePath: string): void {
|
||||
try {
|
||||
const now = Date.now();
|
||||
if (now - lastRotateCheckAt < 60_000) {
|
||||
return;
|
||||
}
|
||||
lastRotateCheckAt = now;
|
||||
const stat = fs.statSync(filePath);
|
||||
if (stat.size < LOG_MAX_FILE_BYTES) {
|
||||
return;
|
||||
}
|
||||
const backup = `${filePath}.old`;
|
||||
try {
|
||||
fs.rmSync(backup, { force: true });
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
fs.renameSync(filePath, backup);
|
||||
} catch {
|
||||
// ignore - file may not exist yet
|
||||
}
|
||||
}
|
||||
|
||||
async function flushAsync(): Promise<void> {
|
||||
if (flushInFlight || pendingLines.length === 0) {
|
||||
return;
|
||||
@@ -101,6 +126,7 @@ async function flushAsync(): Promise<void> {
|
||||
pendingChars = 0;
|
||||
|
||||
try {
|
||||
rotateIfNeeded(logFilePath);
|
||||
const primary = await appendChunk(logFilePath, chunk);
|
||||
if (fallbackLogFilePath) {
|
||||
const fallback = await appendChunk(fallbackLogFilePath, chunk);
|
||||
|
||||
Reference in New Issue
Block a user