The app never actually created a sealed group #30

Merged
paulhitt merged 1 commits from 3-sealed-groups-ui into main 2026-08-31 15:24:59 +00:00
paulhitt commented 2026-08-31 15:23:39 +00:00 (Migrated from gitlab.com)

Closes #3

Everything underneath was built and tested, and no screen called any of it — so
every group this app made still handed the relay one readable gid -> user_id
row per member. Production is 4 groups, 4 plaintext, 0 sealed.

Making a group createSealedGroup — a blob and one opaque tag per member
Old groups upgradeGroupToSealed, owner-only, a button in the group panel
Group list prefers the sealed roster, merges the unsealed ones
Edits / leaving route on whether the group is sealed

The list merge is the security-relevant half

A sealed group’s members come out of a blob the owner signed. GET /e2e/groups
carries no signature at all. Letting the relay’s answer for the same gid win — or
merely shadow it — puts the server back in charge of deciding who is in a group,
which is what sealing exists to stop.

Proven by reverting just that merge:

SealedGroupListTest > the relay cannot add a member to a sealed group FAILED
  AssertionError: the relay-s roster replaced the one out of the blob
    expected:<[1, 2]> but was:<[1, 2, 99]>
SealedGroupListTest > a sealed group is listed at all FAILED
  expected:<[1, 2]> but was:<[]>

Why edits route

Sending a sealed group down the plaintext route asks the relay to edit a table it
no longer has: the call returns fine and the member is not there. One entry
point in Session, so no screen has to branch to be correct — same shape as iOS
e90ba1b.

Copy

The button says what it does and does not buy: it protects the list if the
database is stolen or handed over; it does not hide the group from whoever runs
the server, because messages are addressed to each device and who receives a
group’s traffic still gives it away.

Verification

engine  273 tests, 0 failures
client  277 tests, 0 failures
app      54 tests, 0 failures
TOTAL   604 tests, 0 failures
:app:assembleDebug  BUILD SUCCESSFUL

What this unblocks

paulhitt/flamenet-relay#2 — four production rosters that can now actually be
sealed from a phone people already have, rather than waiting on Apple.

Closes #3 Everything underneath was built and tested, and no screen called any of it — so every group this app made still handed the relay one readable `gid -> user_id` row per member. Production is **4 groups, 4 plaintext, 0 sealed**. | | | |---|---| | Making a group | `createSealedGroup` — a blob and one opaque tag per member | | Old groups | `upgradeGroupToSealed`, owner-only, a button in the group panel | | Group list | prefers the sealed roster, merges the unsealed ones | | Edits / leaving | route on whether the group is sealed | ### The list merge is the security-relevant half A sealed group’s members come out of a blob **the owner signed**. `GET /e2e/groups` carries no signature at all. Letting the relay’s answer for the same gid win — or merely shadow it — puts the server back in charge of deciding who is in a group, which is what sealing exists to stop. Proven by reverting just that merge: ``` SealedGroupListTest > the relay cannot add a member to a sealed group FAILED AssertionError: the relay-s roster replaced the one out of the blob expected:<[1, 2]> but was:<[1, 2, 99]> SealedGroupListTest > a sealed group is listed at all FAILED expected:<[1, 2]> but was:<[]> ``` ### Why edits route Sending a sealed group down the plaintext route asks the relay to edit a table it no longer has: **the call returns fine and the member is not there.** One entry point in `Session`, so no screen has to branch to be correct — same shape as iOS `e90ba1b`. ### Copy The button says what it does *and does not* buy: it protects the list if the database is stolen or handed over; it does not hide the group from whoever runs the server, because messages are addressed to each device and who receives a group’s traffic still gives it away. ### Verification ``` engine 273 tests, 0 failures client 277 tests, 0 failures app 54 tests, 0 failures TOTAL 604 tests, 0 failures :app:assembleDebug BUILD SUCCESSFUL ``` ### What this unblocks paulhitt/flamenet-relay#2 — four production rosters that can now actually be sealed from a phone people already have, rather than waiting on Apple.
paulhitt commented 2026-08-31 15:25:00 +00:00 (Migrated from gitlab.com)

mentioned in commit 0034a57389

mentioned in commit 0034a573893999cdd7017ee66c71894cb2958f7a
paulhitt (Migrated from gitlab.com) merged commit 0034a57389 into main 2026-08-31 15:25:00 +00:00
paulhitt commented 2026-09-09 19:02:00 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
Sign in to join this conversation.