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
Backend contract: authenticated owner PUT/DELETE + GET by unguessable name. No ACLs, no LIST, no conditional writes (content-addressed chunks; per-device signed head manifests; readers merge). Admits S3-anything, consumer drives as dumb stores, static hosts, CDNs, IPFS.
Cryptographic pull layer: per (doc × epoch) name-keys; object name = HMAC(name-key, cref); optional outer AEAD hiding keyhive envelope metadata. Name-keys travel over the E2E channel as capabilities; Access::Relay ≈ name-key possession, uniform with the realtime pull tier. Read keys stay in keyhive's op stream (also stored as blobs).
Cooperative fetch revocation (K_p): per-recipient-device wrapped name-key at a pairwise-derived location, deleted on revocation ingest; honest clients never persist pull-layer material. Four-layer revocation: BeeKEM rotation (read, hard) / name-key rotation (pull-forward, hard) / K_p deletion (pull-now, cooperative) / compaction relocation (pull-past, hard, eventual) — plus storage-credential rotation for the owner's own devices.
Motivating scenario: stolen device cracked offline after revocation — compromise narrows from everything the device could reach to everything it had reached; the layers act at revocation time, independent of when the crack lands.
Accepted losses (threat-model entries): no retroactive fetch-denial against modified clients until relocation; HNDL surface widens to name-holders (bounded by rotation; expiring-URL minting as leak hygiene where cheap); egress abuse on paid-egress backends (private buckets + minted URLs there); provider sees recipient counts via K_p objects.
Pull layer in the framework core (backend-independent): name-key derivation, per-device manifests, K_p wrap/pickup/delete, rotation hooks into the existing revocation path, relocation folded into compaction
S3-compatible provider spike (first): SigV4 via polymorph:webcrypto HMAC in-guest, network grant scoped to the backend host; R2 + B2 as documented defaults, MinIO for self-host; scenario = two devices converge through the bucket, a recipient fetches via name-keys with no backend account, K_p deletion goes dark for a stock client
Google Drive provider as a dumb store (fast follow): drive.file scope, appDataFolder; start the OAuth-verification clock early (wall-time dependency)
Provider-config conformance notes: object-versioning off for the K_p prefix (non-load-bearing; see NOTES), CORS recipe per backend
Related: #8 (data services; the storage path is its non-realtime half), #11 (recovery bundle), #1 (threat model), #6/#7 (provider confinement is the dogfooded plugin model).
Design recorded in NOTES.md — Storage backends and the cryptographic pull layer (from the 2026-08-16 design discussion; leaning, not ruling). Summary of what this issue tracks:
The design
Access::Relay≈ name-key possession, uniform with the realtime pull tier. Read keys stay in keyhive's op stream (also stored as blobs).Deliverables
polymorph:blobstore-shaped WIT: core dumb-blob interface (put/get/delete by name); optionalshare-mint(expiring URL) capability interface, class-D-style declareddrive.filescope, appDataFolder; start the OAuth-verification clock early (wall-time dependency)Related: #8 (data services; the storage path is its non-realtime half), #11 (recovery bundle), #1 (threat model), #6/#7 (provider confinement is the dogfooded plugin model).