Release v1.4.20 with comprehensive audit fixes (140 issues) and expanded test coverage
- Speed calculation: raised minimum elapsed floor to 0.5s preventing unrealistic spikes - Reconnect: exponential backoff with consecutive counter, clock regression protection - Download engine: retry byte tracking (itemContributedBytes), mkdir before createWriteStream, content-length validation - Fire-and-forget promises: all void promises now have .catch() error handlers - Session recovery: normalize stale active statuses to queued on crash recovery, clear speedBps - Storage: config backup (.bak) before overwrite, EXDEV cross-device rename fallback with type guard - IPC security: input validation on all string/array IPC handlers, CSP headers in production - Main process: clipboard memory limit (50KB), installer timing increased to 800ms - Debrid: attribute-order-independent meta tag regex for Rapidgator filename extraction - Constants: named constants for magic numbers (MAX_MANIFEST_FILE_BYTES, MAX_LINK_ARTIFACT_BYTES, etc.) - Extractor/integrity: use shared constants, document password visibility and TOCTOU limitations - Tests: 103 tests total (55 new), covering utils, storage, integrity, cleanup, extractor, debrid, update Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
556f0672dc
commit
63fd402083
+42
-1
@@ -2,7 +2,7 @@ import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { parseHashLine, validateFileAgainstManifest } from "../src/main/integrity";
|
||||
import { parseHashLine, readHashManifest, validateFileAgainstManifest } from "../src/main/integrity";
|
||||
|
||||
const tempDirs: string[] = [];
|
||||
|
||||
@@ -29,4 +29,45 @@ describe("integrity", () => {
|
||||
const result = await validateFileAgainstManifest(filePath, dir);
|
||||
expect(result.ok).toBe(true);
|
||||
});
|
||||
|
||||
it("skips manifest files larger than 5MB", () => {
|
||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "rd-int-"));
|
||||
tempDirs.push(dir);
|
||||
|
||||
// Create a .md5 manifest that exceeds the 5MB limit
|
||||
const largeContent = "d41d8cd98f00b204e9800998ecf8427e sample.bin\n".repeat(200000);
|
||||
const manifestPath = path.join(dir, "hashes.md5");
|
||||
fs.writeFileSync(manifestPath, largeContent, "utf8");
|
||||
|
||||
// Verify the file is actually > 5MB
|
||||
const stat = fs.statSync(manifestPath);
|
||||
expect(stat.size).toBeGreaterThan(5 * 1024 * 1024);
|
||||
|
||||
// readHashManifest should skip the oversized file
|
||||
const manifest = readHashManifest(dir);
|
||||
expect(manifest.size).toBe(0);
|
||||
});
|
||||
|
||||
it("does not parse SHA256 (64-char hex) as valid hash", () => {
|
||||
// SHA256 is 64 chars - parseHashLine only supports 32 (MD5) and 40 (SHA1)
|
||||
const sha256Line = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 emptyfile.bin";
|
||||
const result = parseHashLine(sha256Line);
|
||||
// 64-char hex should not match the MD5 (32) or SHA1 (40) pattern
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it("parses SHA1 hash lines correctly", () => {
|
||||
const sha1Line = "da39a3ee5e6b4b0d3255bfef95601890afd80709 emptyfile.bin";
|
||||
const result = parseHashLine(sha1Line);
|
||||
expect(result).not.toBeNull();
|
||||
expect(result?.algorithm).toBe("sha1");
|
||||
expect(result?.digest).toBe("da39a3ee5e6b4b0d3255bfef95601890afd80709");
|
||||
expect(result?.fileName).toBe("emptyfile.bin");
|
||||
});
|
||||
|
||||
it("ignores comment lines in hash manifests", () => {
|
||||
expect(parseHashLine("; This is a comment")).toBeNull();
|
||||
expect(parseHashLine("")).toBeNull();
|
||||
expect(parseHashLine(" ")).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user