fix(sharing): invitations need a fresh proof and end with sign out everywhere

Offering access to the record took a live session alone, and an
invitation outlives the session that sent it: whoever held a stolen
session could invite their own account and keep a way into the record
after the owner signed everything out. POST /api/account/grants now takes
the recent-proof gate at every level (a sign-in or re-proof within five
minutes on the browser, with the second factor on an account that has one;
a step-up elevation on a token, which no shipped client uses here), and
the invite form opens the re-proof dialog and sends again.

Sign out everywhere now withdraws every invitation the account offered
that nobody has accepted. Accepted grants are left standing on purpose:
each is a person the owner chose, often a carer who still needs the
record, and a sign-out button must not quietly cut them off. The response
lists them as grantsKept and the sessions card shows each with a one-click
End access.
This commit is contained in:
Marc-André Bombeck committed 2026-09-26 22:34:21 +02:00
1 parent a4d27c618e
commit a294d7f684
22 files changed
+585 -65

No files matched your search

@@ -73,6 +73,8 @@ function callers(exportName: string): string[] {
/** Routes that resolve their own caller and take the recent-proof gate. */
const RECENT_PROOF_ROUTES: Record<string, string> = {
// Offering access to the record. No shipped client calls it on a token.
"app/api/account/grants/route.ts": "elevation",
// `type=all` only; the single-type exports stay on `requireAuth`.
"app/api/export/route.ts": "elevation",
"app/api/export/full-backup/route.ts": "elevation",