Skip to main content

max / goingson

2.6 KB · 45 lines History Blame Raw
1 -- The invitation half of the group-admin queue.
2 --
3 -- Migration 070 queued `create_group`, `add_member` and `remove_member` and
4 -- said in its own header that the kind column is not a CHECK constraint, so
5 -- five new kinds need no change to it. What they do need is somewhere to put
6 -- what they carry, and none of 070's four payload columns fits: an invitation
7 -- is addressed by its own id, a pasted code is neither a name nor a public key,
8 -- and an expiry is a number.
9 --
10 -- THE FIVE KINDS. `create_invite` reads `group_id` and `expires_in_hours`;
11 -- `revoke_invite` and `confirm_invite` read `group_id` and `invitation_id`;
12 -- `preview_invite` and `accept_invite` read `invite_token`. Columns rather than
13 -- a JSON blob, for migration 070's reason and by its precedent.
14 --
15 -- `invite_token` IS NOT THE ISSUED TOKEN, and the distinction is the reason
16 -- this comment is longer than the DDL. An invitation's code is returned once by
17 -- `create_invitation` and the server keeps only a hash, so the only copy that
18 -- will ever exist belongs in `sync_invitations.token`, written by
19 -- `directory::record_issued` at the moment the drainer receives it. It is never
20 -- a column here: a queue row is swept an hour after it lands, and sweeping the
21 -- only copy of a live invite code would issue an invitation nobody can use.
22 --
23 -- What this column holds is the opposite direction: a code the user was handed
24 -- by somebody else and pasted in, which they are holding anyway and which the
25 -- drainer has to be able to read a minute later. Nothing on this device is the
26 -- authority on it.
27 --
28 -- CONFIRM STORES NO FINGERPRINT. `confirm_invite` carries the group and the
29 -- invitation and stops there, so the drainer re-reads the server's current
30 -- answer rather than acting on a copy taken at queue time. That is how
31 -- `remove_member` is already stored, and here it is stronger than consistency:
32 -- the fingerprint is the thing being authorized, and authorizing a value copied
33 -- a minute ago is exactly the substitution the out-of-band comparison exists to
34 -- catch. The screen still names the fingerprint on the queued row -- it reads
35 -- it from the directory when it draws, which is a display and not a claim.
36 --
37 -- STILL LOCAL-ONLY, still absent from `syncstore::manifest`, and still in
38 -- `EXCLUDED_TABLES`. Adding a column to a table a backup does not carry needs
39 -- no registration on either side, and the storage version does not move:
40 -- nothing here crosses the wire.
41
42 ALTER TABLE group_admin_queue ADD COLUMN invitation_id TEXT;
43 ALTER TABLE group_admin_queue ADD COLUMN invite_token TEXT;
44 ALTER TABLE group_admin_queue ADD COLUMN expires_in_hours INTEGER;
45