Product direction: should cross-instance (peering) transfer be client-side E2E? (long-term) #238
Labels
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: Cordy/Cairn#238
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Spun out of the #237 deep-dive as the honest larger question, so it doesn't get conflated with the delivery bug fix.
Cairn today is deliberately server-side transparent encryption:
cairndresolves a principal's age identity per request and encrypts/decrypts in-process (the code states this plainly — "NOT client-side E2E … not protection against a compromised server", ARCHITECTURE §4.3). Per-user isolation is against other users and the storage provider, not against a compromised Cairn instance. #237 fixes peering delivery within that model (encrypt to the recipient's server-held key).The open question: for cross-instance transfer specifically, should the receiving instance ever see plaintext at all? A zero-trust alternative would have the sender encrypt to the recipient's published public key before it leaves the source instance, so the destination stores ciphertext it cannot read — closer to Signal/MLS/
age-to-published-recipient and to Proton/Tresorit's model.Weigh, long-term, no implementation-cost veto:
Not required for #106 (that's #237). This is a deliberate product-level fork to decide before peering is promoted past closed beta. Refs: #237, #106, #123; ARCHITECTURE.md §4.3; ENCRYPTION-COMPARISON.md.
How D relates to A — coexistence, the integration seam, and the real forks
Recording this so the decision can be taken later with the concrete integration point in hand.
A and D are two delivery modes, not either/or
The seam D plugs into already exists
The handshake already has the sender encrypt to an age recipient that the receiver supplies at PrepareTransfer — today a throwaway per-transfer keypair the receiver mints (
inbound.gomintAge) and later decrypts (deliver.go). The sender side is generic:client.goalready doesage.Encrypt(…, parseRecipient(prep.GetAgeRecipient())).So D is a natural evolution, not a teardown:
PrepareResponse.age_recipientinstead of a throwaway one; on CompleteTransfer, store the staged blob as-is (skip decrypt + re-encrypt).Where D is a genuine change (not a pure add-on)
The hard part, and the decisions to take
Net: ship A to make peering actually move files under the current model; adopt D later as the stricter mode built on A's resolution + the existing per-transfer-recipient seam, once (a)–(d) are decided. Refs: #237 (A), #106;
client.go,inbound.go,deliver.go,PrepareResponse.age_recipient.