Repository navigation
Reports: publish a photo without its metadata, even as sent - #543
Conversation
A photo published as sent was the original's bytes, EXIF and all, so a phone's GPS reached the public: on 2026-11-01, 15 published photos from two reports carried their sender's coordinates (mitigated by hand with a one-pixel blur, whose re-encode drops everything). StripPhoto walks a JPEG's segments, a PNG's chunks or a WebP's, and drops EXIF, XMP, IPTC, MPF, comments, text chunks and a JPEG's trailer (a second picture with EXIF of its own), keeping the picture's bytes untouched and the orientation as a one-tag EXIF. Every public copy of a photo is made by it: at upload, by a reviewer's as_sent, and by `openipc reports redact`, which now makes the photos published before over. A photo it cannot walk is refused at upload (415): what it carries cannot be told. What the sender is told follows the photo's last review (blurred or not), no longer whether the public copy is the original's bytes. Checked against the 156 photos stored in production: every one walks and decodes the same; 65 had metadata to drop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PR Summary by QodoStrip metadata from public report photos
AI Description
Diagram
High-Level Assessment
Files changed (11)
|
Code Review by Qodo
1.
|
…(Qodo, #543) PNG and WebP keep only the chunks that draw them, so an application's own chunk goes too; a JPEG keeps JFIF's header without its thumbnail and drops a JFXX thumbnail, which can carry EXIF of its own. A plain WebP's RIFF size is told after a chunk is dropped. At upload the stripped copy is made again from the stored original when placed, not held in memory for every photo. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Published report photos kept their EXIF, so phone GPS was public: 15 photos from r-yqmjaqfm and r-wegm9rhs served exact coordinates (e.g.
/api/v1/reports/r-wegm9rhs/files/2). Those were mitigated by hand on 2026-11-01 with a one-pixel blur (its re-encode drops all metadata). This fixes the cause.What changes
reports.StripPhoto(new,strip.go): a lossless walk of JPEG segments / PNG chunks / WebP chunks. It drops EXIF, XMP, IPTC, MPF, COM,tEXt/zTXt/iTXt/tIME/eXIf, and anything after the end of image (phones append a second picture with its own EXIF). It keeps the scans, tables, JFIF, the ICC profile and Adobe APP14, and keeps a non-upright orientation as a one-tag EXIF. A photo with nothing to drop comes back unchanged, sopublic_sha256 == sha256as before.prepare)as_sent(SetPhotoPublic)openipc reports redact, which now also re-makes photos published as sent and lists any it cannot walk underunreadable.as_sent/blurredlabel comes from the last photo review, because a stripped copy also differs from the original.reportsandclubtests are now walkable (JFIF, a scan, EOI).Checked
service/run.sh test: all packages pass. New tests cover a phone JPEG with GPS, XMP, MPF, a trailer and orientation 6; PNG; WebP's VP8X flags and RIFF size; restart markers inside a scan; unreadable input; and the whole path of upload → serve → legacy row →Redo→ blur →as_sent.StripPhotoover all 156 stored photo originals. All of them walk, they decode with the same bounds, and 65 had metadata to drop.After deploy: run
openipc reports redact --dry-run, thenopenipc reports redact. Then runreports photo … as_senton the 15 photos blurred on 2026-11-01, so their senders see "as sent" again.