fix: harden upload cancellation and audit logging
Preserve pre-start and batch cancellation requests, reject late upload success after cancellation, and wait for cancellation acknowledgements before removing queue entries. Separate formatted link logs from privacy-safe source cleanup and upload plan audits, persist audit fallback paths, redact support bundles, and expose audit diagnostics safely. Improve queue selection and destructive-action clarity, show the Settings save action only while changes are pending, and add regression coverage for all updated behavior.
This commit is contained in:
+15
-9
@@ -14,6 +14,14 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
function getRotatedLogPath(filePath, backup) {
|
||||
const index = Number(backup);
|
||||
if (!Number.isInteger(index) || index < 1) return filePath;
|
||||
const ext = path.extname(filePath);
|
||||
const base = filePath.slice(0, filePath.length - ext.length);
|
||||
return `${base}.${index}${ext}`;
|
||||
}
|
||||
|
||||
function maybeRotateLogFile(filePath, maxBytes, maxBackups = 3, log = () => {}) {
|
||||
if (!filePath || !Number.isFinite(maxBytes) || maxBytes <= 0) return false;
|
||||
let size = 0;
|
||||
@@ -29,24 +37,22 @@ function maybeRotateLogFile(filePath, maxBytes, maxBackups = 3, log = () => {})
|
||||
}
|
||||
if (size <= maxBytes) return false;
|
||||
|
||||
const ext = path.extname(filePath);
|
||||
const base = filePath.slice(0, filePath.length - ext.length);
|
||||
|
||||
// Drop the oldest backup if it exists, then shift each numbered backup up
|
||||
// one slot. Errors are ignored: missing intermediate backups are normal,
|
||||
// failed renames just mean we'll rotate again next time.
|
||||
try { fs.unlinkSync(`${base}.${maxBackups}${ext}`); } catch {}
|
||||
try { fs.unlinkSync(getRotatedLogPath(filePath, maxBackups)); } catch {}
|
||||
for (let i = maxBackups - 1; i >= 1; i--) {
|
||||
try { fs.renameSync(`${base}.${i}${ext}`, `${base}.${i + 1}${ext}`); } catch {}
|
||||
try { fs.renameSync(getRotatedLogPath(filePath, i), getRotatedLogPath(filePath, i + 1)); } catch {}
|
||||
}
|
||||
try {
|
||||
fs.renameSync(filePath, `${base}.1${ext}`);
|
||||
log(`logRotation: rotated ${filePath} (${(size / 1024 / 1024).toFixed(1)} MB) → ${base}.1${ext}`);
|
||||
const backupPath = getRotatedLogPath(filePath, 1);
|
||||
fs.renameSync(filePath, backupPath);
|
||||
log(`logRotation: rotated ${filePath} (${(size / 1024 / 1024).toFixed(1)} MB) → ${backupPath}`);
|
||||
return true;
|
||||
} catch (err) {
|
||||
log(`logRotation: rename ${filePath} → ${base}.1${ext} failed: ${err.message}`);
|
||||
log(`logRotation: rename ${filePath} → ${getRotatedLogPath(filePath, 1)} failed: ${err.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { maybeRotateLogFile };
|
||||
module.exports = { getRotatedLogPath, maybeRotateLogFile };
|
||||
|
||||
Reference in New Issue
Block a user