Files
archive-tools/public/docs/ARCHITECTURE.md
T
zemion fe578f46bd
Verify / verify (push) Canceled after 0s
Release Archive Tools 0.2.0
2026-09-02 09:34:59 +02:00

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.ts owns 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.ts uses exactly pinned @zip.js/zip.js for 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.ts is 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.ts uses 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.ts is 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.ts walks 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.ts detects formats, applies aggregate policies and exposes inspection, reading, safe repackaging, creation and reports.
  • src/archive/preview.ts recognizes only bounded plain text, bytes and static raster images. Nested archives are never recursively expanded.
  • src/archive/compare.ts compares normalized inventories without interpreting content.
  • src/components/workspaces contains React views. Imported text is rendered through React text nodes; there is no dangerouslySetInnerHTML.

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.