Skip to content

Every chat picture and video goes through the worker, and readers see a loader until it has (GRYT-1669) - #277

Merged
sivert-io merged 1 commit into
mainfrom
claude/GRYT-1669-quarantine-all-attachments
Oct 5, 2026
Merged

sivert-io merged 1 commit into
mainfrom
claude/GRYT-1669-quarantine-all-attachments

Conversation

@sivert-io

Copy link
Copy Markdown
Member

Sivert's call on GRYT-1669: all attachments through quarantine, quick and easy, with a loader in the client while the worker works.

What goes through the worker now

  • Chat pictures already did. Now also a picture or video sent with any other label: sniffMedia reads the first 16 bytes, so a PNG sent as application/octet-stream is treated as a PNG. An HLS playlist named .mp4 is not a video by its bytes, so it stays a plain file.
  • Chat videos, when the worker says chatvideo-v1 (image-worker PR alongside). Without it they keep today's path: stored as sent, with a poster.
  • Sealed (end-to-end encrypted) uploads are left alone, because the server can't read them.
  • Everything else (zip, pdf…) stays a download, served with attachment, a sandbox CSP and nosniff, as before.

The loader

  • Enriched attachments get processing while in quarantine, and refused once the worker has given up. A refused file is never served, and the message says so rather than being pruned.
  • settleChatAttachment waits for the worker's verdict, then sends chat:attachments { conversation_id, message_id, enriched_attachments } for every message carrying the file. It goes only to the people who can read that conversation, using the same recipients as an edit, so nothing about a private channel or DM goes anywhere else.
  • POST /api/uploads answers processing.

Tested live: server and worker in Docker, the web client from the client PR, real uploads through the composer. The loader showed at 0.25 s and cleared at 0.75 s. The 3 s video with sound came back as 640×360 AV1 + AAC, played in the client, and decoded audio. A fake HLS "video" showed "couldn't be processed". Unit tests: sniffMedia, the mislabelled picture, chat video following the capability, and processing → refused. Full suite: 1968 pass, and the one runner hiccup (voiceRecovery.test.ts, a deserialize error) passes 14/14 on its own.

What to look at:

  • listMessagesWithFile in src/db/sqlite/messages.ts reads message_attachments. It's review-required, and a read only.
  • If the worker finishes before the message is sent, there's nothing to update, and the message goes out with the file already done. If the server restarts mid-way, a message stays "processing" until it's reloaded after the worker is done.
  • Thread panels don't listen for chat:attachments yet, so a thread reply's loader clears on reopen.

🤖 Generated with Claude Code

… a loader until it has (GRYT-1669)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
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.

1 participant