Skip to content

Prepare still photos before attachment uploads - #179

Closed
morgmart wants to merge 1 commit into
mainfrom
morganm/photo-preparation
Closed

morgmart wants to merge 1 commit into
mainfrom
morganm/photo-preparation

Conversation

@morgmart

Copy link
Copy Markdown
Contributor

What this does

Adds still-photo privacy preparation to the attachment upload groundwork from #176. JPEG, PNG, and static WebP photos are decoded and exported without hidden location or descriptive metadata before they leave the browser. This does not add attachment controls or change the composer.

Part of BOT-2008, not completion of its full media scope.

Why it matters

Ordinary camera photos often carry metadata that the relay rejects. This prepares supported still photos while preserving their displayed orientation, transparency, and tested color appearance. Buzz agent/team image manifests remain intact; unrelated image text is removed.

How it works

Preparation sits inside the existing upload capability, surrounded by the current session permissions and cancellation checks. Completed uploads still use the existing message outbox and retry behavior. Ordinary files only receive a small signature check and otherwise remain unchanged.

JPEG remains JPEG; PNG and static WebP export as PNG. WebP conversion avoids another lossy encode, but can increase size beyond the existing 20 MiB upload cap and fail. Unsafe dimensions, failed decoding or encoding, and cancellation never fall back to uploading the original still photo. No new queue, native adapter, or shared session contract is added.

Animated images, HEIC conversion, and video preparation remain separate work. Their existing server-validated upload path is unchanged, not newly supported or privacy-prepared by this PR. Installed-app upload connectivity and UI design remain separate dependencies.

Verification

  • At a258b8ff64cb70345e773b80a6e16bf1bbee29e4, mandatory pre-push checks passed: TypeScript, 414 related tests across 31 files, and design-system types/guards. Pre-commit formatting, lint, and security scanning passed.
  • Added 13 low-level boundary tests for size, geometry, byte sniffing, malformed inputs, cancellation, resource cleanup, unchanged generic files, and animation deferral.
  • Added one browser codec contract per engine, Chromium and WebKit: both passed at the committed head. Seven real inputs per engine exercise GPS/orientation/XMP/comment JPEG, alpha PNG/WebP, genuine Display-P3 fixtures, and both Buzz manifest types through the real transport connector, captured upload bytes, and receiving-message projection. Browser execution is necessary to prove actual decoding, orientation, color conversion, transparency, and encoder output. No browser cases removed.
  • Temporarily removing the production preparation connection made both browser cases fail specifically because EXIF survived; restoring it made both pass.
  • Upload responses are controlled fixtures. These tests do not prove acceptance by the real relay validator or deployed service. Live upload/download acceptance, packaged-native behavior, and broader hosted checks remain unverified.

Originating conversation: buzz://message?channel=72d6edc1-3d68-43d1-a359-004c37902b25&id=fe47787c18fca6228cafe449ef6642780de00ade042f94f69f29f7541ae425a0

Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com>
Co-authored-by: Carl <c217fe6b9d958f41c3a5e030dccc7f626775a923089cb6491305eade75ea1f1b@buzz.block.builderlab.xyz>
@zrmarley

Copy link
Copy Markdown
Contributor

🤖 Posted by Zach's agent on his behalf.

Drive-by evidence that looks directly relevant to this PR, from manual live-broker testing of an unrelated change (#223, BOT-2015 upload-on-Send).

What happened: pasted a macOS screenshot PNG into an existing channel against the live dev broker with a real relay. The upload was rejected and the client surfaced the metadata failure — "This file needs metadata cleanup before it can be uploaded. Choose an exported copy without metadata, or remove it for now." (src/features/relay/attachments.ts:36).

Why, as far as I could trace it read-only on main:

  • prepareMedia (src/features/relay/attachments.ts:103-165) only routes HEIC, video and voice notes to /prepare-media. A PNG isn't matched, so it returns the file unchanged and no sanitation happens.
  • The raw PNG goes to /upload, the relay rejects it, and the broker maps any error body matching /metadata/i to code metadata (dev/attachment-upload.mjs:118-119).
  • macOS screenshots carry iTXt/tEXt/eXIf chunks, which is presumably why screenshots specifically trip this.

This looks like exactly what photo-preparation.ts here addresses — PNG chunk walking plus the canvas re-encode. Mostly flagging it as a real-relay repro that unit and browser fixtures can't easily produce, in case it's useful as an acceptance case. Screenshot-paste is likely a very common path.

One sequencing note, no action needed unless it surprises you: #223 moves attachment preparation and upload from attach-time to the explicit Send action for existing conversations and threads. Since this PR hooks transport.ts, below the composer, I'd expect it to be unaffected — but worth a glance if #223 merges first. No file overlap between the two branches.

Evidence limits: one sample, one screenshot PNG, local dev broker, no captured trace. I did not confirm the relay's exact error-body text, only the broker's mapping of it, and I made no changes to any of this code.

@morgmart morgmart closed this Sep 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants