tsafe-collab 0.1.0

Collaboration service integration for tsafe — membership directory, DEK delivery, and recovery-share transport.
Documentation
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

/// A member of a team, identified by their age X25519 public key.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemberEntry {
    /// The age X25519 bech32 public key for this member.
    pub pubkey: String,
    /// UTC timestamp when this member joined the team.
    pub joined_at: DateTime<Utc>,
}

/// An age-encrypted DEK envelope.  The server stores and returns this blob
/// opaquely — it cannot decrypt it because it holds no private key material.
///
/// JSON schema: `tsafe/collab-dek/v1`
///
/// ```json
/// {
///   "schema": "tsafe/collab-dek/v1",
///   "team_id": "<uuid>",
///   "recipient_pubkey": "<age X25519 bech32 pubkey>",
///   "age_ciphertext_b64": "<base64(age-armored ciphertext of 32-byte DEK)>",
///   "delivered_at": "<ISO-8601 UTC>"
/// }
/// ```
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DekEnvelope {
    /// Always `"tsafe/collab-dek/v1"`.
    pub schema: String,
    /// The team this envelope belongs to.
    pub team_id: String,
    /// The age bech32 public key of the intended recipient.
    pub recipient_pubkey: String,
    /// Base64-encoded age-armored ciphertext of the 32-byte DEK, encrypted to
    /// `recipient_pubkey`.  The server never decrypts this.
    pub age_ciphertext_b64: String,
    /// UTC timestamp when the envelope was delivered to the server.
    pub delivered_at: DateTime<Utc>,
}

impl DekEnvelope {
    /// Canonical schema identifier for envelope v1.
    pub const SCHEMA: &'static str = "tsafe/collab-dek/v1";
}

/// An opaque invite token produced by `CollabRemote::create_invite`.
///
/// The token carries the team ID and the invitee's expected public key so that
/// the confirm step can enforce the TOFU binding (ADR-028).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InviteToken {
    /// Unique token string delivered to the invitee out-of-band.
    pub token: String,
    /// Team the invite is for.
    pub team_id: String,
    /// The age public key the invite was bound to.
    pub bound_pubkey: String,
}

/// Server-side record for a pending invite.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InviteRecord {
    /// The unique token string.
    pub token: String,
    /// Team the invite targets.
    pub team_id: String,
    /// The age public key of the intended invitee, bound at creation time.
    pub invitee_pubkey: String,
    /// UTC timestamp when the invite expires.
    pub expires_at: DateTime<Utc>,
}