An encrypted personal cloud built on the AT Protocol.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Main-thread authenticatedXrpc calls share session with worker #6

open opened by sans-self.org

Summary#

Several components make authenticated PDS calls via authenticatedXrpc on the main thread, loading session directly from IndexedDB. If a main-thread XRPC call overlaps with a worker PDS call, both read/write the same OAuthSession in IndexedDB — same DPoP nonce field, same last-writer-wins race as the worker-internal issue.

Affected call sites#

High risk (can race with cabinet operations)#

File Function What it does
lib/preview.ts decryptDocumentBlob Authenticated blob fetch for file previews
components/cabinet/DirectoryReadme.tsx fetchAndDecryptReadme Same pattern for README previews
components/cabinet/ShareDialog.tsx handleShare Fetches document record + creates grant
routes/cabinet/shared.tsx fetchGrants Lists outgoing grants via listOutgoingGrants
routes/cabinet/shared.tsx handleRevoke Revokes grant via revokeGrant

Low risk (user-initiated, not concurrent with cabinet)#

File Function What it does
routes/cabinet/settings.tsx save handler Reads/writes account config
lib/pairing.ts all functions Device pairing protocol
stores/auth.ts checkIdentity, publishIdentityKey Identity setup

Root cause#

authenticatedXrpc in lib/api.ts loads session from IndexedDB, creates a DPoP proof, makes the request, and handles token refresh — all on the main thread. The worker's session gate does the same thing independently. Both compete for the same IndexedDB session record.

Proposed fix#

Migrate high-risk call sites to worker PDS methods (most already have WASM equivalents):

  • revokeGrantworker.grantRevoke() (exists)
  • listOutgoingGrantsworker.listGrantsRaw() + client-side filtering
  • ShareDialog grant creation → worker.documentFetchContentKey() + worker.grantCreate() (both exist)
  • Preview blob fetch → worker.documentFetchContentKey() through gate + unauthenticated getBlob (blobs are public in atproto), or add a WASM export that returns full metadata
  • createPendingShare → needs new WASM export (no equivalent yet)

Low-risk call sites can remain on main thread for now.

Note on blob fetch#

com.atproto.sync.getBlob may or may not require authentication depending on the PDS implementation. The Rust opake-core attaches auth headers to getBlob calls. The sharing.ts incoming grant flow fetches blobs without auth and it works for cross-PDS access. Testing needed to confirm whether the user's own PDS requires auth for getBlob.

sign up or login to add to the discussion
Labels

None yet.

assignee

None yet.

Participants 1
AT URI
at://did:plc:wydyrngmxbcsqdvhmd7whmye/sh.tangled.repo.issue/3mhjnuwzhkw22