From b0f7303f133ca76af4a978b88322543106fb6289 Mon Sep 17 00:00:00 2001 From: Sivert Date: Wed, 7 Oct 2026 18:35:40 +0200 Subject: [PATCH] Document the sealed push preview (GRYT-1688) `push:register` takes a `previewKey`, and pushes then carry a preview only the phone can open. This writes down the format the server, the relay and the phone's extension all follow. Co-Authored-By: Claude Opus 5.5 --- content/docs/build/server-api.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/content/docs/build/server-api.mdx b/content/docs/build/server-api.mdx index 188e6c9..8bf9b18 100644 --- a/content/docs/build/server-api.mdx +++ b/content/docs/build/server-api.mdx @@ -533,6 +533,8 @@ The phone gets a capability from the push relay at `push.gryt.chat` and hands it `push:register` also carries the phone's notification settings for that server, since the server decides what to send. `muted` and `all` are lists of conversation ids, and `everyone` says whether @everyone and @here get through. A DM pushes unless it's muted. A channel in `all` pushes for every message, any other channel only for a mention of you or one of your roles, and @everyone and @here only when `everyone` is true. A muted conversation never pushes. A phone that sends none of these gets DMs and direct mentions only. +`previewKey` is 32 random bytes, base64url, that the phone made for this server. With it, each push carries a preview the relay can't read: the server seals `{"t": title, "s": subtitle, "b": body}` with AES-256-GCM, and sends `0x01`, a 12-byte nonce, the ciphertext and the 16-byte tag as base64url. The additional data is `gryt-push-1|` followed by the capability's tag, the first 16 hex characters of its SHA-256. Title is the sender, subtitle is `#channel · server` (just the server for a DM), and body is the first line. An MLS DM's body stays "New direct message", since the server can't read it. + | Event | Direction | |-------|-----------| | `push:register`, `push:unregister` | client → server |