You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit e915cd5
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: docs/specs/pocket-app.md
+5-3Lines changed: 5 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -119,7 +119,7 @@ Installed means `navigator.standalone === true` (iOS) or the standard `(display-
119
119
120
120
**Enable registers, and the offer counts, only the signed-in account's paired Burrows its list still names**: another account's record is never a target, since the session's Relay holds none of that account's Burrows.
121
121
122
-
**Obsolete delivery mappings are retired, durably.** A `pairing-required` transition, a re-pair that mints a new id, and an explicit **Remove** each write the old `{ burrowId, accountId, deliveryId }` (the record's account) to `PendingDeliveryDeletionV1`*before* the record forgets it (rationale), then call the idempotent deletion route; tombstones retry until a Relay answer clears them. **Only a session of the tombstone's account sends or clears it** (rationale). **This deletes the delivery row alone** — never the scope's shared `PushSubscription`, and never another Burrow's row.
122
+
**Obsolete delivery mappings are retired, durably.** A `pairing-required` transition, a re-pair that mints a new id, and an explicit **Remove** each write the old `{ burrowId, accountId, deliveryId }` (the record's account) to `PendingDeliveryDeletionV1`*before* the record forgets it (rationale), then call the idempotent deletion route; tombstones retry until a Relay answer clears them. **Only a session of the tombstone's account sends or clears it** (rationale). **This deletes the delivery row alone** — never another Burrow's row, and never the scope's shared `PushSubscription`, which only forgetting this phone drops ([What Pocket stores](#what-pocket-stores)).
123
123
124
124
Source of truth: `getPushAvailability` / `subscribeToPushInBrowser` in `lib/src/remote/client/push-subscribe.ts`; `pushNoticeState` in `lib/src/remote/pocket-app/App.tsx`; `PocketClient.subscribeToPush` / `retirePendingDeletions` in `lib/src/remote/client/pocket-client.ts`; `pushEndpointFingerprint` in `remote-lib-common/src/security/push.ts`.
125
125
@@ -133,9 +133,11 @@ Source of truth: `getPushAvailability` / `subscribeToPushInBrowser` in `lib/src/
133
133
134
134
**One module owns the IndexedDB name, its version, its upgrade, and every open** (rationale). `dormouse-pocket` is at **v4**: `known-burrows` (`KnownBurrowV1`, keyed by `burrowId`) and `pending-deletions` (`PendingDeliveryDeletionV1`, keyed `burrowId:deliveryId`); every earlier version upgrades to that shape. **A version bump is a compatibility event: it must never empty `pending-deletions` for a store already at v4**, which would discard owed deletions. **`navigator.storage.persist()` is requested best-effort**: a browser that refuses gets ordinary eviction-prone storage, which re-pairing survives ([remote-security-model.md](./remote-security-model.md) → Client static loss).
135
135
136
-
**A `KnownBurrowV1` is this Client's whole authorization state** for one Burrow. **`localStorage` holds only the `:passkey:` cache, the `:push-endpoint` digest, and the Relay session** (`dormouse-pocket:session`: token, account, credential id, expiry; rationale). **A launch holding an unexpired session opens on the Burrows list once the capability gate passes and its first read answers**, which finds out whether the Relay still honors it. **Sign out forgets the session locally; nothing revokes it on the Relay.**
136
+
**A `KnownBurrowV1` is this Client's whole authorization state** for one Burrow. **`localStorage` holds only the `:passkey:` cache, the `:push-endpoint` digest, and the Relay session** (`dormouse-pocket:session`: token, account, credential id, expiry; rationale). **A launch holding an unexpired session opens on the Burrows list once the capability gate passes and its first read answers**, which finds out whether the Relay still honors it. **Sign out forgets the session locally; nothing revokes it on the Relay.****Sign out keeps every `KnownBurrowV1`, the `:passkey:` cache, and the push digest**, so signing in to the same account again restores access without pairing.
137
137
138
-
Source of truth: `requirePocketKeyStorage` in `lib/src/remote/client/pocket-db.ts`; `generatePocketKeyPair` in `lib/src/remote/client/pocket-private-key.ts`.
138
+
**Sign out and forget this phone asks first, then runs Remove for every record, of every account**, draining the deletion queue once; then it clears the `:passkey:` cache and the push digest, unsubscribes the scope's `PushSubscription` (rationale), and signs out, so the next launch is a first visit. **It reaches nothing on a Burrow**: each counts this phone among its paired phones until that Burrow's own Disconnect ([remote-security-model.md](./remote-security-model.md) → Revocation propagation).
139
+
140
+
Source of truth: `PocketClient.forgetThisPhone` in `lib/src/remote/client/pocket-client.ts`; `requirePocketKeyStorage` in `lib/src/remote/client/pocket-db.ts`; `generatePocketKeyPair` in `lib/src/remote/client/pocket-private-key.ts`.
Copy file name to clipboardExpand all lines: docs/specs/pocket-app.rationale.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -78,6 +78,8 @@ The phone subsequently reported `write-record / DataError` in the disposable dat
78
78
79
79
**Why the Relay session may sit in `localStorage`.** Without it every cold launch, and every relaunch of an installed app iOS evicted, cost a sign-in prompt before the Burrows list. The token is authentication-plane only: it reaches the Relay's routes and sockets for at most its 12 hours, and never stands in for a presence proof at a Burrow (remote-security-model, Presence proofs). Its exposure is the Client statics' class, which already live in the same origin's storage and are the stronger capability; script running in the Pocket origin is outside the model either way. It holds the credential id because pairing names the passkey a proof is built from, which a relaunch could not otherwise recover without a prompt.
80
80
81
+
**Why forgetting this phone also drops the browser's push subscription.** Another account's tombstone drains only under that account's session, which a leaving phone may never hold again. With the subscription gone, the push service answers that row's next delivery with a 410, and the Relay deletes it then.
82
+
81
83
**Why one module owns every IndexedDB open.** Two modules opening the same database can disagree about the version, and a connection held open across an upgrade blocks it indefinitely. Centralizing name, version, upgrade and open makes both states unreachable rather than merely unlikely.
Copy file name to clipboardExpand all lines: docs/specs/security.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -76,7 +76,7 @@ Gaps rather than accepted risks: we intend to close them.
76
76
-*One-time link, Hosted phone, Self-hosted Relay.***No independent third party has reviewed remote control's cryptography.** Dormouse's Noise integration, passkey (WebAuthn) channel binding, key storage, and push sealing are checked only by this project's own tests, lints, and nightly audits, which AI agents run ([Noise suite](./remote-security-model.md#noise-suite)).
77
77
-*Self-hosted Relay.***Anyone who can reach your Relay can hold off sign-in by flooding it**: unauthenticated requests share the capped pool of sign-in challenges, evicting a real one before its passkey prompt is answered. The default install admits only your tailnet ([Network posture (self-hosted)](./security-remote.md#network-posture-self-hosted)).
78
78
-*Hosted phone, Self-hosted Relay.***A user-verification demand raised after enrollment can be lost if this computer cannot save it.** The Burrow keeps the raise in memory and retries the save at each start, but a relaunch while saving keeps failing starts it at presence until the Relay repeats the demand ([Trust boundary](./security-remote.md#trust-boundary)).
79
-
-*Hosted phone, Self-hosted Relay.***Revocation has no mechanism**: nothing in the product revokes a paired phone ([Revocation propagation](./remote-security-model.md#revocation-propagation)).
79
+
-*Hosted phone, Self-hosted Relay.***Revocation has no mechanism**: nothing in the product revokes a paired phone ([Revocation propagation](./remote-security-model.md#revocation-propagation)); a phone can only forget its own pairings, with Pocket's Sign out and forget this phone.
80
80
-*One-time link, Hosted phone, Self-hosted Relay.***There is no structured audit trail** covering connects, attaches, denials, or writes, so a self-hoster cannot answer "did anyone connect to my laptop last night"; each pairing records its approval, and owner-local logs report some rejections ([Burrow Authorization](./remote-security-model.md#burrow-authorization), [Trust boundary](./security-remote.md#trust-boundary)).
81
81
-**A fork PR the bot checks out mid-run reaches it with that fork's instruction files.** The harness pins project-instruction paths to the base branch only for the checkouts it makes before the agent starts ([Automated Maintainer](./security-ci.md#automated-maintainer-tend)).
82
82
-**The workflow audit's window can be evaded.** A pusher-set committer date hides a commit from every later window, and a branch pushed, run with repo-level secrets in scope, and deleted before the nightly fetch is in none ([Automated Maintainer](./security-ci.md#automated-maintainer-tend)).
0 commit comments