Skip to content

Emoji, server and group icons, and webhook pictures are decoded by the worker, not the server (GRYT-1664) - #278

Merged
sivert-io merged 1 commit into
mainfrom
claude/GRYT-1664-rest-through-worker
Oct 5, 2026
Merged

sivert-io merged 1 commit into
mainfrom
claude/GRYT-1664-rest-through-worker

Conversation

@sivert-io

Copy link
Copy Markdown
Member

The last places the server decoded a picture itself, with sharp in its own process. They were found by GPT's #269, which this replaces. Each now goes through the image worker's jail when the worker can clear quarantine. Without one (the Windows zip, a source install) they keep today's path.

  • Emoji: every path (upload, the queue, the BTTV import) goes through processEmojiToOptimizedImage. When the worker is there, it hands the bytes over with reencodeThroughWorker, waits for the worker's copy (two minutes at most), returns it, and drops the temporary file. The caller stores it under its own key as before. A refusal fails the upload with the existing "Failed to process image."
  • Server icon: the same helper, at the avatar profile's 256px square. The worker's frame cap (300) applies instead of MAX_ICON_FRAMES, since the frames can't be counted without decoding.
  • Group pictures and webhook avatars (/group-icon, /webhook-avatar): quarantined like avatars. The pointer is set by the caller as before, and the file is only served once the worker has written it out.
  • Webhook pictures fetched by URL: no validateImage here any more. Card pictures are stored in quarantine, and the loader push from Every chat picture and video goes through the worker, and readers see a loader until it has (GRYT-1669) #277 tells readers when they're ready. The webhook's avatar goes through quarantineUpload.
  • Link previews: imageHeaderSize reads PNG, GIF, JPEG and WebP sizes from the header bytes. sharp is no longer used on a remote picture at all. These are layout hints only.

Tested live with server and worker in Docker: a GIF emoji came out 171×128 animated WebP, a PNG emoji AVIF, the server icon and a group picture 256×256 AVIF, all in the worker's log. HTML named .png as an emoji was refused in the jail and the upload answered 400. Unit tests cover the group picture through quarantine, the emoji round trip against a stand-in worker (only its copy comes back, no temporary file left), and the header reader for each format. Full suite: 1982 pass.

What to look at:

  • The emoji upload now waits on the worker, usually well under a second. A worker that's down makes emoji uploads fail after two minutes, rather than being decoded here.
  • reencodeThroughWorker writes a temporary files row, which is deleted afterwards whatever happens.

Closes #269. Not review-required (no db, auth, middleware or storage changes), but it's the security path, so read it if you can.

🤖 Generated with Claude Code

…e worker, not the server (GRYT-1664)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@sivert-io
sivert-io merged commit ca5bcdb into main Oct 5, 2026
6 checks passed
@sivert-io
sivert-io deleted the claude/GRYT-1664-rest-through-worker branch October 5, 2026 14:44
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