Apply account and key changes to active queues without a restart and isolate provider attempt cancellation so fallback accounts remain usable. Preserve pause ownership, bound persisted HTTP 416 recovery, reconcile resets with authoritative state, and stabilize package ordering and live update cadence. Correlate rotation, conversion, resume, disk, queue-control, clipboard, and support-export events while redacting sensitive data at every persistent boundary and again in generated bundles. Release as v2.0.31 with updated English documentation and regression coverage.
86 lines
3.3 KiB
TypeScript
86 lines
3.3 KiB
TypeScript
import fs from "node:fs";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { afterEach, describe, expect, it } from "vitest";
|
|
import { getAuditLogPath, initAuditLog, logAuditEvent, shutdownAuditLog } from "../src/main/audit-log";
|
|
|
|
const tempDirs: string[] = [];
|
|
|
|
afterEach(() => {
|
|
shutdownAuditLog();
|
|
for (const dir of tempDirs.splice(0)) {
|
|
fs.rmSync(dir, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
describe("audit-log", () => {
|
|
it("writes audit events to the audit log", () => {
|
|
const baseDir = fs.mkdtempSync(path.join(os.tmpdir(), "rd-alog-"));
|
|
tempDirs.push(baseDir);
|
|
|
|
initAuditLog(baseDir);
|
|
logAuditEvent("INFO", "Settings changed", { changedKeys: ["token", "autoExtract"] });
|
|
|
|
const logPath = getAuditLogPath();
|
|
expect(logPath).not.toBeNull();
|
|
expect(fs.existsSync(logPath!)).toBe(true);
|
|
const content = fs.readFileSync(logPath!, "utf8");
|
|
expect(content).toContain("Audit-Log Start");
|
|
expect(content).toContain("Settings changed");
|
|
expect(content).toContain("changedKeys");
|
|
});
|
|
|
|
it("rotates oversized audit logs on startup", () => {
|
|
const baseDir = fs.mkdtempSync(path.join(os.tmpdir(), "rd-alog-rotate-"));
|
|
tempDirs.push(baseDir);
|
|
|
|
const oversizedPath = path.join(baseDir, "audit.log");
|
|
fs.mkdirSync(baseDir, { recursive: true });
|
|
fs.writeFileSync(oversizedPath, "x".repeat(10 * 1024 * 1024 + 256), "utf8");
|
|
|
|
initAuditLog(baseDir);
|
|
|
|
expect(fs.existsSync(oversizedPath)).toBe(true);
|
|
expect(fs.existsSync(`${oversizedPath}.old`)).toBe(true);
|
|
const content = fs.readFileSync(oversizedPath, "utf8");
|
|
expect(content).toContain("Audit-Log Start");
|
|
});
|
|
|
|
it("redacts secrets, identities, direct links and local paths from audit logs", () => {
|
|
const baseDir = fs.mkdtempSync(path.join(os.tmpdir(), "rd-alog-sensitive-"));
|
|
tempDirs.push(baseDir);
|
|
|
|
initAuditLog(baseDir);
|
|
logAuditEvent(
|
|
"ERROR",
|
|
"Abruf https://rapidgator.net/file/private-id/archive.rar?token=url-secret für audit@example.com in C:\\Users\\Administrator\\Downloads\\archive.rar fehlgeschlagen",
|
|
{
|
|
directUrl: "https://rapidgator.net/file/private-id/archive.rar?token=url-secret",
|
|
authorization: "Bearer authorization-secret-value",
|
|
details: {
|
|
password: "password-secret-value",
|
|
cookie: "sid=cookie-secret-value",
|
|
email: "audit@example.com",
|
|
extractPath: "/var/lib/downloader/archive.rar"
|
|
}
|
|
}
|
|
);
|
|
|
|
const logPath = getAuditLogPath();
|
|
expect(logPath).not.toBeNull();
|
|
const content = fs.readFileSync(logPath!, "utf8");
|
|
expect(content).toMatch(/rapidgator\.net#[a-f0-9]{10}/);
|
|
expect(content).toContain("<redacted>");
|
|
expect(content).toContain("<redacted-account>");
|
|
expect(content).toContain("<redacted-path>");
|
|
expect(content).not.toContain("private-id");
|
|
expect(content).not.toContain("url-secret");
|
|
expect(content).not.toContain("authorization-secret-value");
|
|
expect(content).not.toContain("password-secret-value");
|
|
expect(content).not.toContain("cookie-secret-value");
|
|
expect(content).not.toContain("audit@example.com");
|
|
expect(content).not.toContain("C:\\Users\\Administrator");
|
|
expect(content).not.toContain("/var/lib/downloader");
|
|
});
|
|
});
|