Files
82cea2a60e fix(plugins): harden the zip entry listing for file handlers (#3320)
* fix(plugins): validate the zip end record and decode CP437 entry names

The scan from the end took the first end-record signature it found, so an
archive comment containing the signature broke the listing. Accept a record
only when its comment fits the remaining bytes and the central directory ends
where the record (or the ZIP64 record) begins, otherwise keep scanning.

Names without general purpose flag bit 11 are now decoded as CP437, the zip
default, instead of UTF-8.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(plugins): note on reading archives safely and folder file paths

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(plugins): accept a zip end record by where the directory starts

Requiring the directory to end exactly at the end record rejected valid
archives with bytes in front of them (self-extractors). A candidate is now
accepted when a central directory entry signature sits at the declared offset,
or, for a non-ZIP64 record, at the offset implied by the directory size. ZIP64
checks the signature at its own directory offset. An empty archive is accepted
only when its record sits at the declared offset. At most 16 candidates are
tried so a comment full of signatures stays cheap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(plugins): move the archive note to the dropped-files section

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(plugins): rank zip end records, keep unflagged UTF-8 names, skip spanned archives

Prefer an end record whose directory also ends where the record begins over
one that merely points at a directory start; try records with a fitting
comment first and fall back to a truncated comment. Read unflagged names as
UTF-8 when valid, CP437 otherwise. Accept empty classic (also shifted) and
empty ZIP64 archives. Do not list spanned archives.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(plugins): try the end record that closes the file first, handle signature records

Order end-record candidates without extra reads: the one whose comment ends at
the end of the file first, then other fitting ones. The cap now bounds only
range reads, and a directory inside the tail is checked in memory, so a comment
full of fake records no longer hides the real one. A digital signature record
between the directory and the end record is accounted for when the offsets are
shifted. The UTF-8 decoders are module constants.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(plugins): keep the real zip end record reachable, read signature records before the tail

Rank candidates without reads (directory visibly ends at the record, exact
comment fit, fitting, overrunning), evaluate every group within the read cap and
stop only on a record the layout fully backs. Keep every signature record that
ends at an end record, and read one bounded window when it starts before the
tail. Reject ZIP64 records and locators that name a nonzero disk.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(plugins): reduce the zip entry listing to the announced scope

Keep the end record that closes the file first, then scan back through at most
16 candidates, accepting one only when a central directory entry really starts
at its declared offset (or it is an empty archive). Drop the ranking, the
prepended-data shift and the signature-record handling, and document in the
code that such archives (and spanned ones) are deliberately not listed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(plugins): accept an empty zip only when its directory sits at its end record

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(plugins): tighten zip end-record checks and docs

Reject ZIP64 archives whose locator or ZIP64 record names more than one
disk, and reject a classic record whose directory-disk field is set, so
spanned archives are not listed. Reject a directory shorter than one
central entry before probing it, so a lone entry signature cannot stop
the end-record search. Restore an explicit bounds check on the directory
before it is read.

Drop the digital-signature clause from listZipEntryPaths' doc comment:
the signature record sits after the declared directory, so signed zips
list normally. Add regression tests for the ZIP64 disk checks and the
short directory.

Applied by the claude-autofix workflow.

* refactor(plugins): collect zip end-record candidates without unshift

Split the end-record candidates into exact and other arrays and
concatenate them once, instead of prepending each exact match. The
order is unchanged: exact records still come first, lowest offset
first.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>

Applied by the claude-autofix workflow.

* fix(plugins): harden zip listing reads and tighten its tests

Check the ZIP64 end record read for a short read and return no listing
instead of throwing a RangeError. Read a central directory signature
from the tail already in memory when it falls inside it, so a comment
full of candidates costs fewer IPC round trips on desktop.

Add regression tests for a zero-length directory that does not sit at
the end record, and for a short ZIP64 read.

Applied by the claude-autofix workflow.

* Address Claude review feedback

- Pass ignoreBOM to both UTF-8 name decoders so a leading U+FEFF in an
  entry name is kept rather than silently stripped.
- Rename the fake empty-archive test: the record carries a signature, so
  "all-zero" did not describe it.

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: giswqs <5016453+giswqs@users.noreply.github.com>
Co-authored-by: giswqs <giswqs@gmail.com>
2026-11-03 12:12:25 -05:00
..
…
2026-10-31 02:53:41 -04:00
2026-11-02 16:47:58 -05:00
…