Files
Claude 212916d8fd fix(emoji-packs): audit fixes for bulk import — crashes, zip bombs, speed
Bugs:
- A .zip that failed to read with anything but IllegalArgumentException
  (an IOException, a revoked permission, a full disk) escaped launchSigner
  and crashed the app; any read failure now lists it as "Could not open".
- The whole .zip was read into memory unchecked: archives over 128 MB and
  images over 10 MB are now refused before reading (new
  MediaUploader.fileSize, Android via OpenableColumns.SIZE).
- Zip-bomb limits could be bypassed: ZipInputStream inflates every entry
  it skips, and oversized images counted toward nothing. Every inflated
  byte now counts against a 512 MB budget.
- An archive over 2,000 images or 256 MB failed as a whole and showed as
  "Could not open"; it is now read up to the limit and reported as
  "Only partly imported".
- A private import decrypted the pack only after uploading everything, so
  a signer that could not decrypt stranded every upload. App and CLI now
  decrypt (and check the pack exists) first; amy fails with decrypt_failed.
- The Android picker greyed out .zip files that providers label
  application/x-zip or octet-stream.
- The desktop picker filtered image/svg+xml as *.xml.
- The success icon's pop never animated (it started at its target).

Performance:
- Uploads run 3 at a time in the app and 4 in amy, keeping the batch order.
- Each image's status is its own snapshot state: one upload redraws one
  tile instead of rebuilding the list and recomposing the grid.
- The grid is a height-capped lazy grid, so a 2,000-image archive composes
  and decodes only the visible thumbnails; it follows the uploads in flight.

amy now plans imports through the shared EmojiImport.plan, applies the
zip limits to folders and single images too, and reports `truncated`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BN6Wdpxj3hd1iJBswebfYb
2026-10-18 08:50:54 +00:00
..