4.4 KiB
Architecture
Archive Tools is a relocatable static React application. It has no backend, persistence, telemetry or runtime network dependency.
Layers
src/archive/paths.tsowns cross-platform path assessment and collision keys. It rejects traversal, absolute/drive/UNC paths, controls, ambiguous segments, Windows devices, alternate streams and excessive depth/length.src/archive/zip.tsuses exactly pinned@zip.js/zip.jsfor ZIP/ZIP64 inventory, CRC/authentication-checked ZipCrypto and WinZip AES reads, and deterministic unencrypted writing. Listing uses bounded entry iteration. Content reads request strict local/central-header agreement and overlapping-entry checks. Passwords are caller-owned strings held only in component memory.src/archive/tar.tsis a checked-offset TAR/USTAR/PAX reader and deterministic writer. Every header checksum is validated. PAX and GNU long-name/long-link metadata are capped before strict UTF-8 decoding; links remain inventory-only.src/archive/gzip.tsuses the shared bounded byte cursor for headers and footers, streams compressed input through fflate in small chunks, updates the shared incremental CRC-32 state as output arrives, stops at the expanded-byte ceiling and checks every member's CRC-32 and ISIZE footer independently. Concatenation is capped at 256 members and exposed in inspection diagnostics.src/archive/sevenzip.tsis a structural parser, not a decompressor. It validates the 7z signature, safe start-header arithmetic and both header CRC-32 values. It distinguishes empty, plain and encoded next headers. For a bounded plain Header it walks StreamsInfo framing and accepts only bounded, inline FilesInfo names and empty-entry maps; codec streams are never opened.src/archive/rar.tswalks RAR4/RAR5 headers using Blob slices, so packed data is skipped rather than retained. It validates every accepted block-header CRC, checked header/data ranges, required main/end framing and bounded counts. Plaintext file headers provide inventory evidence. Header encryption stops the walk and all RAR entries remain non-extractable.src/archive/service.tsdetects formats, applies aggregate policies and exposes inspection, reading, safe repackaging, creation and reports.src/archive/preview.tsrecognizes only bounded plain text, bytes and static raster images. Nested archives are never recursively expanded.src/archive/compare.tscompares normalized inventories without interpreting content.src/components/workspacescontains React views. Imported text is rendered through React text nodes; there is nodangerouslySetInnerHTML.
Data flow
Inspection checks the source size and format before parsing. ZIP inventory reads only archive metadata. 7z reads only its fixed start header and bounded next header; RAR reads bounded headers through Blob slices and seeks over packed data. TAR and gzip inputs are held in memory only after the source ceiling is satisfied and gzip expansion is stopped at its output ceiling. TAR/gzip payloads remain in the current React document solely to support later previews and selection; replacing the document releases those references.
Preview and extraction never write source paths to the local filesystem. A selected entry is decoded into a bounded in-memory buffer, verified, and passed to a new deterministic ZIP writer using its already-assessed normalized path.
Determinism
Creation sorts normalized paths by code-unit order. Unencrypted ZIP uses zip.js's bundled DEFLATE implementation at level 6 with native compression streams and workers disabled, fixed DOS dates, normalized regular-file modes, no extended timestamps and no data descriptors. AES/ZipCrypto output necessarily uses fresh random encryption material and is not byte-deterministic. TAR uses zero timestamps/IDs, regular mode 0644, USTAR when possible and deterministic PAX path headers otherwise. gzip uses level 6 and mtime zero.
Memory model
The parser refuses unsafe declared sizes before entry decompression. 7z/RAR offsets use safe checked addition, individual metadata headers are capped at 16 MiB and RAR walks at most 40,000 blocks. A bounded writable collects ZIP output and stops when actual output crosses the operation ceiling. gzip is pushed in 32 KiB source chunks and output is counted before retention. Creation and TAR parsing are deliberately capped because they currently use in-memory output/payloads.