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
+9
-6
@@ -160,7 +160,7 @@ function looksLikeFileName(value: string): boolean {
|
||||
return /\.(?:part\d+\.rar|r\d{2}|rar|zip|7z|tar|gz|bz2|xz|iso|mkv|mp4|avi|mov|wmv|m4v|m2ts|ts|webm|mp3|flac|aac|srt|ass|sub)$/i.test(value);
|
||||
}
|
||||
|
||||
function normalizeResolvedFilename(value: string): string {
|
||||
export function normalizeResolvedFilename(value: string): string {
|
||||
const candidate = decodeHtmlEntities(String(value || ""))
|
||||
.replace(/<[^>]*>/g, " ")
|
||||
.replace(/\s+/g, " ")
|
||||
@@ -174,7 +174,7 @@ function normalizeResolvedFilename(value: string): string {
|
||||
return candidate;
|
||||
}
|
||||
|
||||
function filenameFromRapidgatorUrlPath(link: string): string {
|
||||
export function filenameFromRapidgatorUrlPath(link: string): string {
|
||||
try {
|
||||
const parsed = new URL(link);
|
||||
const pathParts = parsed.pathname.split("/").filter(Boolean);
|
||||
@@ -191,10 +191,10 @@ function filenameFromRapidgatorUrlPath(link: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
function extractRapidgatorFilenameFromHtml(html: string): string {
|
||||
export function extractRapidgatorFilenameFromHtml(html: string): string {
|
||||
const patterns = [
|
||||
/<meta[^>]+property=["']og:title["'][^>]+content=["']([^"']+)["']/i,
|
||||
/<meta[^>]+name=["']title["'][^>]+content=["']([^"']+)["']/i,
|
||||
/<meta[^>]+(?:property=["']og:title["'][^>]+content=["']([^"']+)["']|content=["']([^"']+)["'][^>]+property=["']og:title["'])/i,
|
||||
/<meta[^>]+(?:name=["']title["'][^>]+content=["']([^"']+)["']|content=["']([^"']+)["'][^>]+name=["']title["'])/i,
|
||||
/<title>([^<]+)<\/title>/i,
|
||||
/(?:Dateiname|File\s*name)\s*[:\-]\s*<[^>]*>\s*([^<]+)\s*</i,
|
||||
/(?:Dateiname|File\s*name)\s*[:\-]\s*([^<\r\n]+)/i,
|
||||
@@ -204,7 +204,10 @@ function extractRapidgatorFilenameFromHtml(html: string): string {
|
||||
|
||||
for (const pattern of patterns) {
|
||||
const match = html.match(pattern);
|
||||
const normalized = normalizeResolvedFilename(match?.[1] || "");
|
||||
// Some patterns have multiple capture groups for attribute-order independence;
|
||||
// pick the first non-empty group.
|
||||
const raw = match?.[1] || match?.[2] || "";
|
||||
const normalized = normalizeResolvedFilename(raw);
|
||||
if (normalized) {
|
||||
return normalized;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user