Phase 1 — Foundation: - Constant-time token comparison via subtle::ConstantTimeEq (Fix 11) - Structured error codes E001–E020 in new error_codes.rs (Fix 15) - Remove dead envelope.capnp code and related types (Fix 16) Phase 2 — Auth Hardening: - Registration collision check via has_user_record() (Fix 5) - Auth required on uploadHybridKey/fetchHybridKey RPCs (Fix 1) - Identity-token binding at registration and login (Fix 2) - Session token expiry with 24h TTL and background reaper (Fix 3) - Bounded pending logins with 5-minute timeout (Fix 4) Phase 3 — Resource Limits: - Rate limiting: 100 enqueues/60s per token (Fix 6) - Queue depth cap at 1000 + 7-day message TTL/GC (Fix 7) - Partial queue drain via limit param on fetch/fetchWait (Fix 8) Phase 4 — Crypto Fixes: - OPAQUE KSF switched from Identity to Argon2id (Fix 10) - Random AEAD nonce in hybrid KEM instead of HKDF-derived (Fix 12) - Zeroize secret fields in HybridKeypairBytes (Fix 13) - Encrypted client state files via QPCE format (Fix 9) Phase 5 — Protocol: - Commit fan-out to all existing members on invite (Fix 14) - Add member_identities() to GroupMember Breaking: existing OPAQUE registrations invalidated (Argon2 KSF). Schema: added auth to hybrid key ops, identityKey to OPAQUE finish RPCs, limit to fetch/fetchWait. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
63 lines
2.5 KiB
Rust
63 lines
2.5 KiB
Rust
//! Cap'n Proto schemas, generated types, and serialisation helpers for quicnprotochat.
|
|
//!
|
|
//! # Design constraints
|
|
//!
|
|
//! This crate is intentionally restricted:
|
|
//! - **No crypto** — key material never enters this crate.
|
|
//! - **No I/O** — callers own transport; this crate only converts bytes ↔ types.
|
|
//! - **No async** — pure synchronous data-layer code.
|
|
//!
|
|
//! # Generated code
|
|
//!
|
|
//! `build.rs` invokes `capnpc` at compile time and writes generated Rust source
|
|
//! into `$OUT_DIR`. The `include!` macros below splice that code in as a module.
|
|
|
|
// ── Generated types ───────────────────────────────────────────────────────────
|
|
|
|
/// Cap'n Proto generated types for `schemas/auth.capnp`.
|
|
///
|
|
/// Do not edit this module by hand — it is entirely machine-generated.
|
|
pub mod auth_capnp {
|
|
include!(concat!(env!("OUT_DIR"), "/auth_capnp.rs"));
|
|
}
|
|
|
|
/// Cap'n Proto generated types for `schemas/delivery.capnp`.
|
|
///
|
|
/// Do not edit this module by hand — it is entirely machine-generated.
|
|
pub mod delivery_capnp {
|
|
include!(concat!(env!("OUT_DIR"), "/delivery_capnp.rs"));
|
|
}
|
|
|
|
/// Cap'n Proto generated types for `schemas/node.capnp`.
|
|
///
|
|
/// Do not edit this module by hand — it is entirely machine-generated.
|
|
pub mod node_capnp {
|
|
include!(concat!(env!("OUT_DIR"), "/node_capnp.rs"));
|
|
}
|
|
|
|
// ── Low-level byte ↔ message conversions ──────────────────────────────────────
|
|
|
|
/// Serialise a Cap'n Proto message builder to unpacked wire bytes.
|
|
///
|
|
/// The output includes the segment table header. For transport, the
|
|
/// `quicnprotochat-core` frame codec prepends a 4-byte little-endian length field.
|
|
pub fn to_bytes<A: capnp::message::Allocator>(
|
|
msg: &capnp::message::Builder<A>,
|
|
) -> Result<Vec<u8>, capnp::Error> {
|
|
let mut buf = Vec::new();
|
|
capnp::serialize::write_message(&mut buf, msg)?;
|
|
Ok(buf)
|
|
}
|
|
|
|
/// Deserialise unpacked wire bytes into a message with owned segments.
|
|
///
|
|
/// Uses `ReaderOptions::new()` (default limits: 64 MiB, 512 nesting levels).
|
|
/// Callers that receive data from untrusted peers should consider tightening
|
|
/// the traversal limit via `ReaderOptions::traversal_limit_in_words`.
|
|
pub fn from_bytes(
|
|
bytes: &[u8],
|
|
) -> Result<capnp::message::Reader<capnp::serialize::OwnedSegments>, capnp::Error> {
|
|
let mut cursor = std::io::Cursor::new(bytes);
|
|
capnp::serialize::read_message(&mut cursor, capnp::message::ReaderOptions::new())
|
|
}
|