tsafe-collab
Team collaboration service skeleton for tsafe.
Provides the CollabRemote trait and an in-memory stub server for sharing
encrypted vault DEKs (data encryption keys) between team members using
age encryption + Shamir secret sharing for recovery.
Status: Early / Experimental
The collaboration service protocol and wire format are defined; production server infrastructure is not yet included. The stub server (for testing) is.
Key types
CollabRemote— trait for membership directory, DEK delivery, invite flow, and recovery-share transport; synchronous HTTP viaureqfor production implementationsStubServer— thread-safe in-memoryCollabRemoteimplementation backed byHashMapstate; enforces the membership gate on every callMemberEntry— team member identified by an age X25519 bech32 public keyDekEnvelope— age-encrypted DEK blob; the server stores it opaquely and cannot decrypt it (schema: "tsafe/collab-dek/v1")InviteToken/InviteRecord— TOFU-bound invite flow (ADR-028): an invite is bound to a specific invitee pubkey at creation time;confirm_inviteenforces the binding and consumes the token (one-use, 48-hour TTL)split_recovery_key/reconstruct_recovery_key— Shamir N-of-M sharing
Wire format
Recovery shares produced by split_recovery_key are serialized as:
[ threshold: u8 ][ blahaj_share_bytes: x || y[0..31] ]
The leading threshold byte lets reconstruct_recovery_key operate without
the caller tracking the threshold separately. Total per-share size: 33 bytes.
Base64-encode for transport. See docs/decisions/shamir-crate-selection.md
(ADR-032) for crate-selection rationale (blahaj 0.6 as the maintained
successor to sharks 0.5).
Architectural boundary
tsafe-core MUST NOT import this crate (ADR-027). The dependency direction is:
tsafe-collab → (ureq, age, serde, thiserror, uuid, chrono, blahaj)
tsafe-cli → tsafe-collab [feature = "collab"]
Add --features collab to the CLI build to pull this crate in. The crate
compiles and all tests pass without a live collab-service.
Security properties
- The server (stub or production) stores only age-encrypted ciphertext — it holds no plaintext key material (ADR-027 "Service NEVER holds").
- DEK envelopes are age-encrypted to the recipient's X25519 public key; a non-member who obtains the envelope bytes cannot decrypt them.
fetch_dekandfetch_recovery_shareenforce membership before returning any data; the adversarial proof is intests/non_member_dek_isolation.rs(D3.4).