v2.8.28
What's Changed
This release contains an unusually large number of fixes resulting from an in-depth audit of the codebase, along with several new features. All fixes are covered by new regression tests, and the produced archives were validated against external tools (7z, unzip, ditto, Python).
New features
- Add the
checkAmbiguityoption toZipReaderto detect and reject ambiguous archives: concatenated archives, trailing central directory records, mismatched zip64 records, duplicate filenames, and local file headers contradicting the central directory - Add the
fetchoption toHttpReaderandHttpRangeReaderin #655 - Add the
workerStarvationTimeoutoption toconfigure()and run starved codecs without worker to prevent deadlocks - Support the
offsetoption with split archives - Support the
rawPasswordoption with ZipCrypto - Add
index.cjs/index-native.cjssubpath exports and areact-nativecondition inpackage.jsonin #651 - Add the
ERR_AMBIGUOUS_ARCHIVE,ERR_INVALID_COMPRESSED_DATAandERR_UNDEFINED_READERerror constants
Deflate64
- Fix decompression of entries containing matches longer than 258 bytes (length code 285) in #661 — the wasm fix was contributed by @Chagrins in gildas-lormeau/zlib-streams#1
- Add the
deflate64option to the reserved properties of inline web workers (web workers silently decompressed Deflate64 entries with the deflate32 codec)
Security
- Always verify the AES authentication code when decrypting entries
- Compare the ZipCrypto password verification byte in constant time
- Throw
ERR_UNSUPPORTED_CRYPTO_APIinstead of falling back to an insecure pseudo-random generator when the Web Crypto API is unavailable, and remove the unused pseudo-random fallback from sjcl.js - Detect overlapping entries regardless of check order, and when reading entries multiple times
- Throw zip.js errors instead of
RangeErroron malformed archives
Behavior changes
No API was removed or changed, but some intentional behavior changes are worth noting:
dataDescriptorSignaturenow defaults totrue: archives grow by 4 bytes per entry when data descriptors are used, and output bytes differ (fixes extraction with macOSditto)add()withpassThroughset and no reader throwsERR_UNDEFINED_READERinstead of silently producing corrupt outputadd()with an unsupportedcompressionMethodthrows instead of producing an unreadable entry- Extra fields totaling over 64KB throw instead of writing a corrupt header
add(name)without reader now writes a well-defined empty stored entry- Extended timestamps outside the signed 32-bit range are omitted (the NTFS field carries the exact value); reads treat the field as signed per the spec
FS.getById()no longer returns detached entries, and options objects passed toadd(),addFile(),exportZip()andHttpRangeReaderare no longer mutated- The
FStype declaration no longer pretends to extendZipDirectoryEntry(the runtime never did); TypeScript code relying on the incorrect declaration may need adjusting
ZipReader fixes
- Fix reading split zip files with a central directory spanning multiple segments (zip32 and zip64)
- Fix reading prepended data with zip64 offsets
- Fix extracting prepended data with multiple entries
- Fix CRC-32 and AES compression method in prepended entries
- Read the entry count from the total field in the end of central directory record
- Fix
getData()resettinglastAccessDateandcreationDateon entries - Derive the directory flag from the final filename after unicode path override
- Propagate entry data errors in
ZipReaderStream - Fix AES decryption buffering
- Fix cp437/BOM text decoding and harden crypto helpers
- Fix central directory, encrypted flag and timestamp handling
- Support readers returning subarray views
- Avoid mutating caller options in
checkPassword
ZipWriter fixes
- Fix zip64 detection for encrypted entries
- Fix the "version needed" field for zip64 offset entries
- Throw an error when sizes overflow without zip64
- Use zip64 when values equal the 32-bit/16-bit sentinels
- Write the local zip64 extra field for streamed zip64 entries
- Fix the local zip64 compressed size for encrypted STORE and passthrough entries
- Account for the zip64 trailer in the central directory length
- Fix crash and offsets when headers cross split segment boundaries
- Fix double-counted size in the split data writer and exact-fill handling in
SplitDataWriter - Fix duplicate filename check after a failed
add() - Fix offset tracking after failed entry writes
- Advance the offset by the bytes actually flushed on aborted buffered writes
- Preserve
add()call order for concurrently added entries - Fix deadlock between concurrent
add()calls andcreateTempStream - Propagate close errors in
ZipWriterStreamtransform - Fix directory name duplicates, comment validation and
ZipWriterStreamerrors - Fix
prependZipcompression level bits andcompressionMethod/levelconsistency - Fix USDZ extra field length off by 2
- Write the Info-ZIP Unix (0x7855) extra field per spec (fixed 2-byte uid/gid)
- Write extra field type and length as 16-bit little-endian
- Harden entry metadata written by
ZipWriter
Web workers fixes
- Release the writable lock when a worker task fails
- Fix worker slot double-release and stale messages on task failure
- Fix variable shadowing breaking
error.outputSizein web workers - Handle worker loading errors and honor
workerURIconfiguration changes - Reset the terminated flag when creating a new worker
- Fix codec stream issues with small chunk sizes, opaque errors and wasm memory leaks
Filesystem (zip.fs) fixes
- Fix
exportZip()silently dropping entries when a reader fails - Fix
importZip()directory metadata, name collisions and read options - Reset the filesystem tree in
FS.importZip()like other imports - Fix
remove()leaving descendant entries registered in the filesystem - Register entries only when they are attached to the tree
- Avoid stack overflows when exporting deeply nested trees
find(): fall back to exact full-name match for verbatim slash namesgetArrayBuffer(): read viagetUint8Arrayso all entry data types work- Do not mutate the options object passed to
exportZip() - Add
FS.exportZip()delegation and default its options - Fix the
FStype declaration to match its actual runtime surface
I/O fixes
- Fix byte order in
Data64URIWriterwith sub-3-byte writes - Fix HTTP, split disk and blob I/O issues, including
HttpReaderend-of-central-directory caching
Performance
- Make
ChunkStreamiterative and tolerate invalid chunk sizes (supersedes #660 — reading a 50MB file with a small chunk size went from ~4900ms to ~80ms) - Avoid copying the entry map on each
add()
Documentation
- Document that entry filenames must use forward slashes as separator in #654
- Fix dash/dot switchup in README by @KTibow in #650
Credits
- Most of the bugs fixed in this release were found and fixed by Claude (Fable) during several in-depth reviews of the codebase, which also produced the new regression tests
- @Chagrins fixed the length-code extra bits bug in the Inflate wasm implementation (gildas-lormeau/zlib-streams#1), part of the fix for #661
Full Changelog: v2.8.26...v2.8.28