docs: add crate-level documentation and public API doc comments
- Expand crate-level docs for quicprochat-rpc (architecture, wire format, module map) and quicprochat-sdk (connection lifecycle, event subscription, module descriptions). - Add /// doc comments to all undocumented pub fn/struct/enum items in server domain services (keys, channels, devices, users, account, p2p, blobs) and domain types. - Fix rustdoc broken intra-doc links in plugin-api (HookResult, qpc_plugin_init), federation/mod.rs (Store), and client main.rs (unescaped brackets).
This commit is contained in:
@@ -505,7 +505,7 @@ enum Command {
|
|||||||
password: Option<String>,
|
password: Option<String>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Interactive 1:1 chat: type to send, incoming messages printed as [peer] <msg>. Ctrl+D to exit.
|
/// Interactive 1:1 chat: type to send, incoming messages printed as \[peer\] msg. Ctrl+D to exit.
|
||||||
/// In a two-person group, peer is chosen automatically; use --peer-key only with 3+ members.
|
/// In a two-person group, peer is chosen automatically; use --peer-key only with 3+ members.
|
||||||
Chat {
|
Chat {
|
||||||
#[arg(
|
#[arg(
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
//! extern "C" int32_t qpc_plugin_init(HookVTable *vtable);
|
//! extern "C" int32_t qpc_plugin_init(HookVTable *vtable);
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! The server passes a zeroed [`HookVTable`] to `qpc_plugin_init`. The plugin
|
//! The server passes a zeroed [`HookVTable`] to the init function. The plugin
|
||||||
//! fills in whichever function pointers it cares about and returns `0` on
|
//! fills in whichever function pointers it cares about and returns `0` on
|
||||||
//! success or a negative error code on failure. Unused slots remain null and
|
//! success or a negative error code on failure. Unused slots remain null and
|
||||||
//! the server treats them as no-ops.
|
//! the server treats them as no-ops.
|
||||||
@@ -27,9 +27,9 @@
|
|||||||
//!
|
//!
|
||||||
//! # Return values
|
//! # Return values
|
||||||
//!
|
//!
|
||||||
//! Hooks that can reject an operation return [`HookResult`]. The server maps
|
//! Hooks that can reject an operation return an `i32` result code. The server maps
|
||||||
//! `HOOK_CONTINUE` to `HookAction::Continue` and any other value to
|
//! [`HOOK_CONTINUE`] to allow and any other value to reject, reading the reason
|
||||||
//! `HookAction::Reject` with the reason string from [`HookVTable::error_message`].
|
//! string from [`HookVTable::error_message`].
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ pub struct CFetchEvent {
|
|||||||
|
|
||||||
// ── HookVTable ────────────────────────────────────────────────────────────────
|
// ── HookVTable ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
/// C-ABI function-pointer table filled by [`qpc_plugin_init`].
|
/// C-ABI function-pointer table filled by the plugin's `qpc_plugin_init` export.
|
||||||
///
|
///
|
||||||
/// All fields default to null (no-op). The server only calls a slot when its
|
/// All fields default to null (no-op). The server only calls a slot when its
|
||||||
/// pointer is non-null. The `user_data` field is passed as the first argument
|
/// pointer is non-null. The `user_data` field is passed as the first argument
|
||||||
|
|||||||
@@ -1,9 +1,43 @@
|
|||||||
//! QUIC RPC framework for quicprochat v2.
|
//! QUIC RPC framework for quicprochat v2.
|
||||||
//!
|
//!
|
||||||
//! Wire format per QUIC stream:
|
//! This crate implements a lightweight, binary-framed RPC protocol over QUIC.
|
||||||
//! - Request: `[method_id: u16][request_id: u32][payload_len: u32][protobuf bytes]`
|
//! Each RPC call opens a new QUIC bi-directional stream, sends a request frame,
|
||||||
//! - Response: `[status: u8][request_id: u32][payload_len: u32][protobuf bytes]`
|
//! and reads a response frame. Server-initiated push events use uni-streams.
|
||||||
//! - Push: `[event_type: u16][payload_len: u32][protobuf bytes]` (uni-stream)
|
//!
|
||||||
|
//! # Wire format
|
||||||
|
//!
|
||||||
|
//! All integers are big-endian.
|
||||||
|
//!
|
||||||
|
//! **Request** (client → server, bi-stream):
|
||||||
|
//! ```text
|
||||||
|
//! [method_id: u16][request_id: u32][payload_len: u32][protobuf bytes]
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! **Response** (server → client, same bi-stream):
|
||||||
|
//! ```text
|
||||||
|
//! [status: u8][request_id: u32][payload_len: u32][protobuf bytes]
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! **Push** (server → client, uni-stream):
|
||||||
|
//! ```text
|
||||||
|
//! [event_type: u16][payload_len: u32][protobuf bytes]
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! # Architecture
|
||||||
|
//!
|
||||||
|
//! - [`framing`] — frame types ([`framing::RequestFrame`], [`framing::ResponseFrame`],
|
||||||
|
//! [`framing::PushFrame`]) and encode/decode logic.
|
||||||
|
//! - [`method`] — [`method::MethodRegistry`] maps `u16` method IDs to async handler
|
||||||
|
//! functions with optional per-method timeouts.
|
||||||
|
//! - [`server`] — [`server::RpcServer`] binds a QUIC endpoint, performs an auth
|
||||||
|
//! handshake on each connection, then dispatches RPC streams to registered handlers.
|
||||||
|
//! - [`client`] — [`client::RpcClient`] connects to the server with TLS, supports
|
||||||
|
//! auto-reconnect with exponential backoff, and multiplexes concurrent RPCs.
|
||||||
|
//! - [`push`] — [`push::PushBroker`] manages per-identity push connections and
|
||||||
|
//! fan-out to channel members.
|
||||||
|
//! - [`middleware`] — session validation, rate limiting, and structured audit logging.
|
||||||
|
//! - [`auth_handshake`] — initial session-token exchange on the first bi-stream.
|
||||||
|
//! - [`error`] — [`error::RpcError`] and [`error::RpcStatus`] types.
|
||||||
|
|
||||||
pub mod auth_handshake;
|
pub mod auth_handshake;
|
||||||
pub mod framing;
|
pub mod framing;
|
||||||
|
|||||||
@@ -1,7 +1,44 @@
|
|||||||
//! Client SDK for quicprochat v2.
|
//! Client SDK for quicprochat v2.
|
||||||
//!
|
//!
|
||||||
//! Provides `QpqClient` — a single entry point for connecting, authenticating,
|
//! Provides [`QpqClient`](client::QpqClient) — a single entry point for
|
||||||
//! sending/receiving messages, and subscribing to real-time events.
|
//! connecting to a quicprochat server, authenticating via OPAQUE, managing
|
||||||
|
//! conversations, and subscribing to real-time events.
|
||||||
|
//!
|
||||||
|
//! # Connection lifecycle
|
||||||
|
//!
|
||||||
|
//! 1. Create a [`QpqClient`](client::QpqClient) with a [`ClientConfig`](config::ClientConfig).
|
||||||
|
//! 2. Call [`connect()`](client::QpqClient::connect) to establish a QUIC connection
|
||||||
|
//! and open the local SQLCipher conversation store.
|
||||||
|
//! 3. [`register()`](client::QpqClient::register) or
|
||||||
|
//! [`login()`](client::QpqClient::login) via OPAQUE to authenticate.
|
||||||
|
//! 4. Optionally call [`start_heartbeat()`](client::QpqClient::start_heartbeat)
|
||||||
|
//! to enable proactive dead-connection detection.
|
||||||
|
//! 5. Use messaging, group, key, and device APIs through the client.
|
||||||
|
//! 6. Call [`disconnect()`](client::QpqClient::disconnect) to shut down gracefully.
|
||||||
|
//!
|
||||||
|
//! # Event subscription
|
||||||
|
//!
|
||||||
|
//! Call [`subscribe()`](client::QpqClient::subscribe) to get a
|
||||||
|
//! `tokio::sync::broadcast::Receiver<ClientEvent>` that emits connection state
|
||||||
|
//! changes, authentication events, and incoming message notifications.
|
||||||
|
//!
|
||||||
|
//! # Modules
|
||||||
|
//!
|
||||||
|
//! - [`client`] — [`QpqClient`](client::QpqClient) and connection management.
|
||||||
|
//! - [`auth`] — OPAQUE registration and login flows.
|
||||||
|
//! - [`config`] — [`ClientConfig`](config::ClientConfig) with server address, TLS, DB path.
|
||||||
|
//! - [`conversation`] — [`ConversationStore`](conversation::ConversationStore) for local
|
||||||
|
//! message persistence and user blocking.
|
||||||
|
//! - [`events`] — [`ClientEvent`](events::ClientEvent) enum for the event bus.
|
||||||
|
//! - [`groups`] — group membership management.
|
||||||
|
//! - [`keys`] — MLS KeyPackage and hybrid (PQ) key upload/fetch.
|
||||||
|
//! - [`messaging`] — send and receive encrypted messages.
|
||||||
|
//! - [`devices`] — multi-device registration, listing, and revocation.
|
||||||
|
//! - [`recovery`] — account recovery bundle upload/fetch.
|
||||||
|
//! - [`outbox`] — offline message queue with retry.
|
||||||
|
//! - [`state`] — client state persistence (identity key, session token).
|
||||||
|
//! - [`transcript`] — conversation transcript export.
|
||||||
|
//! - [`users`] — username/identity resolution.
|
||||||
|
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
pub mod client;
|
pub mod client;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ pub struct AccountService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AccountService {
|
impl AccountService {
|
||||||
|
/// Delete an account and append a KT tombstone entry for auditability.
|
||||||
pub fn delete_account(&self, caller_identity_key: &[u8]) -> Result<(), DomainError> {
|
pub fn delete_account(&self, caller_identity_key: &[u8]) -> Result<(), DomainError> {
|
||||||
self.store.delete_account(caller_identity_key)?;
|
self.store.delete_account(caller_identity_key)?;
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ impl BlobService {
|
|||||||
self.data_dir.join("blobs")
|
self.data_dir.join("blobs")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Upload a blob chunk. Chunks are written at the given offset. When the
|
||||||
|
/// final chunk completes the upload, the SHA-256 hash is verified and the
|
||||||
|
/// blob is finalized. Already-complete blobs return immediately.
|
||||||
pub fn upload_blob(
|
pub fn upload_blob(
|
||||||
&self,
|
&self,
|
||||||
req: UploadBlobReq,
|
req: UploadBlobReq,
|
||||||
@@ -136,6 +139,7 @@ impl BlobService {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Download a chunk of a stored blob. Reads at most 256 KB per call.
|
||||||
pub fn download_blob(
|
pub fn download_blob(
|
||||||
&self,
|
&self,
|
||||||
req: DownloadBlobReq,
|
req: DownloadBlobReq,
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ pub struct ChannelService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ChannelService {
|
impl ChannelService {
|
||||||
|
/// Create or look up a 1:1 DM channel between caller and peer.
|
||||||
|
///
|
||||||
|
/// The channel ID is deterministic and symmetric — `create(A, B)` returns
|
||||||
|
/// the same ID as `create(B, A)`. Returns `was_new = true` on first creation.
|
||||||
pub fn create_channel(
|
pub fn create_channel(
|
||||||
&self,
|
&self,
|
||||||
req: CreateChannelReq,
|
req: CreateChannelReq,
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ pub struct DeviceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DeviceService {
|
impl DeviceService {
|
||||||
|
/// Register a new device for the caller's identity. Enforces a per-identity device limit.
|
||||||
pub fn register_device(
|
pub fn register_device(
|
||||||
&self,
|
&self,
|
||||||
req: RegisterDeviceReq,
|
req: RegisterDeviceReq,
|
||||||
@@ -37,6 +38,7 @@ impl DeviceService {
|
|||||||
Ok(RegisterDeviceResp { success })
|
Ok(RegisterDeviceResp { success })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// List all registered devices for the caller's identity.
|
||||||
pub fn list_devices(
|
pub fn list_devices(
|
||||||
&self,
|
&self,
|
||||||
caller_identity_key: &[u8],
|
caller_identity_key: &[u8],
|
||||||
@@ -53,6 +55,7 @@ impl DeviceService {
|
|||||||
Ok(ListDevicesResp { devices })
|
Ok(ListDevicesResp { devices })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Revoke (remove) a registered device. Returns an error if the device is not found.
|
||||||
pub fn revoke_device(
|
pub fn revoke_device(
|
||||||
&self,
|
&self,
|
||||||
req: RevokeDeviceReq,
|
req: RevokeDeviceReq,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ pub struct KeyService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl KeyService {
|
impl KeyService {
|
||||||
|
/// Upload an MLS KeyPackage for the given identity. Returns a SHA-256 fingerprint.
|
||||||
pub fn upload_key_package(
|
pub fn upload_key_package(
|
||||||
&self,
|
&self,
|
||||||
req: UploadKeyPackageReq,
|
req: UploadKeyPackageReq,
|
||||||
@@ -40,6 +41,7 @@ impl KeyService {
|
|||||||
Ok(UploadKeyPackageResp { fingerprint })
|
Ok(UploadKeyPackageResp { fingerprint })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fetch the stored MLS KeyPackage for an identity. Returns empty if none exists.
|
||||||
pub fn fetch_key_package(
|
pub fn fetch_key_package(
|
||||||
&self,
|
&self,
|
||||||
req: FetchKeyPackageReq,
|
req: FetchKeyPackageReq,
|
||||||
@@ -53,6 +55,7 @@ impl KeyService {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Upload a hybrid (ML-KEM-768) public key for post-quantum key exchange.
|
||||||
pub fn upload_hybrid_key(
|
pub fn upload_hybrid_key(
|
||||||
&self,
|
&self,
|
||||||
req: UploadHybridKeyReq,
|
req: UploadHybridKeyReq,
|
||||||
@@ -70,6 +73,7 @@ impl KeyService {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fetch the hybrid public key for a single identity. Returns empty if none exists.
|
||||||
pub fn fetch_hybrid_key(
|
pub fn fetch_hybrid_key(
|
||||||
&self,
|
&self,
|
||||||
req: FetchHybridKeyReq,
|
req: FetchHybridKeyReq,
|
||||||
@@ -82,6 +86,7 @@ impl KeyService {
|
|||||||
Ok(FetchHybridKeyResp { hybrid_public_key })
|
Ok(FetchHybridKeyResp { hybrid_public_key })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Batch-fetch hybrid public keys for multiple identities. Missing keys return empty.
|
||||||
pub fn fetch_hybrid_keys(
|
pub fn fetch_hybrid_keys(
|
||||||
&self,
|
&self,
|
||||||
req: FetchHybridKeysReq,
|
req: FetchHybridKeysReq,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ pub struct P2pService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl P2pService {
|
impl P2pService {
|
||||||
|
/// Publish a P2P endpoint (iroh node address) for the caller's identity.
|
||||||
pub fn publish_endpoint(
|
pub fn publish_endpoint(
|
||||||
&self,
|
&self,
|
||||||
req: PublishEndpointReq,
|
req: PublishEndpointReq,
|
||||||
@@ -26,6 +27,7 @@ impl P2pService {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolve a P2P endpoint for an identity key. Returns empty if none published.
|
||||||
pub fn resolve_endpoint(
|
pub fn resolve_endpoint(
|
||||||
&self,
|
&self,
|
||||||
req: ResolveEndpointReq,
|
req: ResolveEndpointReq,
|
||||||
@@ -42,6 +44,7 @@ impl P2pService {
|
|||||||
Ok(ResolveEndpointResp { node_addr })
|
Ok(ResolveEndpointResp { node_addr })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return a health-check response (always "ok").
|
||||||
pub fn health() -> HealthResp {
|
pub fn health() -> HealthResp {
|
||||||
HealthResp {
|
HealthResp {
|
||||||
status: "ok".into(),
|
status: "ok".into(),
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ pub struct RegisterStartReq {
|
|||||||
pub request_bytes: Vec<u8>,
|
pub request_bytes: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// OPAQUE registration start response.
|
||||||
pub struct RegisterStartResp {
|
pub struct RegisterStartResp {
|
||||||
pub response_bytes: Vec<u8>,
|
pub response_bytes: Vec<u8>,
|
||||||
}
|
}
|
||||||
@@ -85,6 +86,7 @@ pub struct RegisterFinishReq {
|
|||||||
pub identity_key: Vec<u8>,
|
pub identity_key: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// OPAQUE registration finish response.
|
||||||
pub struct RegisterFinishResp {
|
pub struct RegisterFinishResp {
|
||||||
pub success: bool,
|
pub success: bool,
|
||||||
}
|
}
|
||||||
@@ -95,6 +97,7 @@ pub struct LoginStartReq {
|
|||||||
pub request_bytes: Vec<u8>,
|
pub request_bytes: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// OPAQUE login start response.
|
||||||
pub struct LoginStartResp {
|
pub struct LoginStartResp {
|
||||||
pub response_bytes: Vec<u8>,
|
pub response_bytes: Vec<u8>,
|
||||||
}
|
}
|
||||||
@@ -106,6 +109,7 @@ pub struct LoginFinishReq {
|
|||||||
pub identity_key: Vec<u8>,
|
pub identity_key: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// OPAQUE login finish response containing the session token.
|
||||||
pub struct LoginFinishResp {
|
pub struct LoginFinishResp {
|
||||||
pub session_token: Vec<u8>,
|
pub session_token: Vec<u8>,
|
||||||
}
|
}
|
||||||
@@ -119,6 +123,7 @@ pub struct Envelope {
|
|||||||
pub data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request to enqueue a message for delivery to a recipient.
|
||||||
pub struct EnqueueReq {
|
pub struct EnqueueReq {
|
||||||
pub recipient_key: Vec<u8>,
|
pub recipient_key: Vec<u8>,
|
||||||
pub payload: Vec<u8>,
|
pub payload: Vec<u8>,
|
||||||
@@ -126,37 +131,44 @@ pub struct EnqueueReq {
|
|||||||
pub ttl_secs: u32,
|
pub ttl_secs: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response from enqueue with the assigned sequence number.
|
||||||
pub struct EnqueueResp {
|
pub struct EnqueueResp {
|
||||||
pub seq: u64,
|
pub seq: u64,
|
||||||
pub delivery_proof: Vec<u8>,
|
pub delivery_proof: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request to fetch (and drain) queued messages.
|
||||||
pub struct FetchReq {
|
pub struct FetchReq {
|
||||||
pub recipient_key: Vec<u8>,
|
pub recipient_key: Vec<u8>,
|
||||||
pub channel_id: Vec<u8>,
|
pub channel_id: Vec<u8>,
|
||||||
pub limit: u32,
|
pub limit: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response containing fetched message envelopes.
|
||||||
pub struct FetchResp {
|
pub struct FetchResp {
|
||||||
pub payloads: Vec<Envelope>,
|
pub payloads: Vec<Envelope>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request to peek at queued messages without draining.
|
||||||
pub struct PeekReq {
|
pub struct PeekReq {
|
||||||
pub recipient_key: Vec<u8>,
|
pub recipient_key: Vec<u8>,
|
||||||
pub channel_id: Vec<u8>,
|
pub channel_id: Vec<u8>,
|
||||||
pub limit: u32,
|
pub limit: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response containing peeked message envelopes.
|
||||||
pub struct PeekResp {
|
pub struct PeekResp {
|
||||||
pub payloads: Vec<Envelope>,
|
pub payloads: Vec<Envelope>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request to acknowledge messages up to a sequence number.
|
||||||
pub struct AckReq {
|
pub struct AckReq {
|
||||||
pub recipient_key: Vec<u8>,
|
pub recipient_key: Vec<u8>,
|
||||||
pub channel_id: Vec<u8>,
|
pub channel_id: Vec<u8>,
|
||||||
pub seq_up_to: u64,
|
pub seq_up_to: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request to enqueue a message to multiple recipients at once.
|
||||||
pub struct BatchEnqueueReq {
|
pub struct BatchEnqueueReq {
|
||||||
pub recipient_keys: Vec<Vec<u8>>,
|
pub recipient_keys: Vec<Vec<u8>>,
|
||||||
pub payload: Vec<u8>,
|
pub payload: Vec<u8>,
|
||||||
@@ -164,83 +176,100 @@ pub struct BatchEnqueueReq {
|
|||||||
pub ttl_secs: u32,
|
pub ttl_secs: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response from batch enqueue with one sequence number per recipient.
|
||||||
pub struct BatchEnqueueResp {
|
pub struct BatchEnqueueResp {
|
||||||
pub seqs: Vec<u64>,
|
pub seqs: Vec<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Keys ─────────────────────────────────────────────────────────────────────
|
// ── Keys ─────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/// Request to upload an MLS KeyPackage.
|
||||||
pub struct UploadKeyPackageReq {
|
pub struct UploadKeyPackageReq {
|
||||||
pub identity_key: Vec<u8>,
|
pub identity_key: Vec<u8>,
|
||||||
pub package: Vec<u8>,
|
pub package: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response containing the SHA-256 fingerprint of the uploaded KeyPackage.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct UploadKeyPackageResp {
|
pub struct UploadKeyPackageResp {
|
||||||
pub fingerprint: Vec<u8>,
|
pub fingerprint: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request to fetch a stored MLS KeyPackage.
|
||||||
pub struct FetchKeyPackageReq {
|
pub struct FetchKeyPackageReq {
|
||||||
pub identity_key: Vec<u8>,
|
pub identity_key: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response containing the MLS KeyPackage (empty if not found).
|
||||||
pub struct FetchKeyPackageResp {
|
pub struct FetchKeyPackageResp {
|
||||||
pub package: Vec<u8>,
|
pub package: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request to upload a hybrid (ML-KEM-768) public key.
|
||||||
pub struct UploadHybridKeyReq {
|
pub struct UploadHybridKeyReq {
|
||||||
pub identity_key: Vec<u8>,
|
pub identity_key: Vec<u8>,
|
||||||
pub hybrid_public_key: Vec<u8>,
|
pub hybrid_public_key: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request to fetch a single hybrid public key.
|
||||||
pub struct FetchHybridKeyReq {
|
pub struct FetchHybridKeyReq {
|
||||||
pub identity_key: Vec<u8>,
|
pub identity_key: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response containing a hybrid public key (empty if not found).
|
||||||
pub struct FetchHybridKeyResp {
|
pub struct FetchHybridKeyResp {
|
||||||
pub hybrid_public_key: Vec<u8>,
|
pub hybrid_public_key: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request to batch-fetch hybrid public keys for multiple identities.
|
||||||
pub struct FetchHybridKeysReq {
|
pub struct FetchHybridKeysReq {
|
||||||
pub identity_keys: Vec<Vec<u8>>,
|
pub identity_keys: Vec<Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response containing hybrid keys in the same order as the request.
|
||||||
pub struct FetchHybridKeysResp {
|
pub struct FetchHybridKeysResp {
|
||||||
pub keys: Vec<Vec<u8>>,
|
pub keys: Vec<Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Key Transparency / Revocation ────────────────────────────────────
|
// ── Key Transparency / Revocation ────────────────────────────────────
|
||||||
|
|
||||||
|
/// Request to revoke an identity key in the Key Transparency log.
|
||||||
pub struct RevokeKeyReq {
|
pub struct RevokeKeyReq {
|
||||||
pub identity_key: Vec<u8>,
|
pub identity_key: Vec<u8>,
|
||||||
pub reason: String,
|
pub reason: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response from key revocation with the leaf index in the KT log.
|
||||||
pub struct RevokeKeyResp {
|
pub struct RevokeKeyResp {
|
||||||
pub success: bool,
|
pub success: bool,
|
||||||
pub leaf_index: u64,
|
pub leaf_index: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request to check if an identity key has been revoked.
|
||||||
pub struct CheckRevocationReq {
|
pub struct CheckRevocationReq {
|
||||||
pub identity_key: Vec<u8>,
|
pub identity_key: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response with revocation status, reason, and timestamp.
|
||||||
pub struct CheckRevocationResp {
|
pub struct CheckRevocationResp {
|
||||||
pub revoked: bool,
|
pub revoked: bool,
|
||||||
pub reason: String,
|
pub reason: String,
|
||||||
pub timestamp_ms: u64,
|
pub timestamp_ms: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request for a range of Key Transparency audit log entries.
|
||||||
pub struct AuditKeyTransparencyReq {
|
pub struct AuditKeyTransparencyReq {
|
||||||
pub start: u64,
|
pub start: u64,
|
||||||
pub end: u64,
|
pub end: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A single entry in the KT audit log.
|
||||||
pub struct AuditLogEntry {
|
pub struct AuditLogEntry {
|
||||||
pub index: u64,
|
pub index: u64,
|
||||||
pub leaf_hash: Vec<u8>,
|
pub leaf_hash: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response containing KT audit log entries, tree size, and root hash.
|
||||||
pub struct AuditKeyTransparencyResp {
|
pub struct AuditKeyTransparencyResp {
|
||||||
pub entries: Vec<AuditLogEntry>,
|
pub entries: Vec<AuditLogEntry>,
|
||||||
pub tree_size: u64,
|
pub tree_size: u64,
|
||||||
@@ -249,10 +278,12 @@ pub struct AuditKeyTransparencyResp {
|
|||||||
|
|
||||||
// ── Channel ──────────────────────────────────────────────────────────────────
|
// ── Channel ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/// Request to create a 1:1 DM channel with a peer.
|
||||||
pub struct CreateChannelReq {
|
pub struct CreateChannelReq {
|
||||||
pub peer_key: Vec<u8>,
|
pub peer_key: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response with the channel ID and whether it was newly created.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CreateChannelResp {
|
pub struct CreateChannelResp {
|
||||||
pub channel_id: Vec<u8>,
|
pub channel_id: Vec<u8>,
|
||||||
@@ -261,25 +292,30 @@ pub struct CreateChannelResp {
|
|||||||
|
|
||||||
// ── User ─────────────────────────────────────────────────────────────────────
|
// ── User ─────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/// Request to resolve a username to an identity key.
|
||||||
pub struct ResolveUserReq {
|
pub struct ResolveUserReq {
|
||||||
pub username: String,
|
pub username: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response with the identity key and KT inclusion proof.
|
||||||
pub struct ResolveUserResp {
|
pub struct ResolveUserResp {
|
||||||
pub identity_key: Vec<u8>,
|
pub identity_key: Vec<u8>,
|
||||||
pub inclusion_proof: Vec<u8>,
|
pub inclusion_proof: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request to reverse-resolve an identity key to a username.
|
||||||
pub struct ResolveIdentityReq {
|
pub struct ResolveIdentityReq {
|
||||||
pub identity_key: Vec<u8>,
|
pub identity_key: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response with the resolved username (empty if unknown).
|
||||||
pub struct ResolveIdentityResp {
|
pub struct ResolveIdentityResp {
|
||||||
pub username: String,
|
pub username: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Blob ─────────────────────────────────────────────────────────────────────
|
// ── Blob ─────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/// Request to upload a blob chunk. The blob is identified by its SHA-256 hash.
|
||||||
pub struct UploadBlobReq {
|
pub struct UploadBlobReq {
|
||||||
pub blob_hash: Vec<u8>,
|
pub blob_hash: Vec<u8>,
|
||||||
pub chunk: Vec<u8>,
|
pub chunk: Vec<u8>,
|
||||||
@@ -288,16 +324,19 @@ pub struct UploadBlobReq {
|
|||||||
pub mime_type: String,
|
pub mime_type: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response from blob upload containing the blob ID (same as hash).
|
||||||
pub struct UploadBlobResp {
|
pub struct UploadBlobResp {
|
||||||
pub blob_id: Vec<u8>,
|
pub blob_id: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request to download a chunk of a stored blob.
|
||||||
pub struct DownloadBlobReq {
|
pub struct DownloadBlobReq {
|
||||||
pub blob_id: Vec<u8>,
|
pub blob_id: Vec<u8>,
|
||||||
pub offset: u64,
|
pub offset: u64,
|
||||||
pub length: u32,
|
pub length: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response containing the requested blob chunk and metadata.
|
||||||
pub struct DownloadBlobResp {
|
pub struct DownloadBlobResp {
|
||||||
pub chunk: Vec<u8>,
|
pub chunk: Vec<u8>,
|
||||||
pub total_size: u64,
|
pub total_size: u64,
|
||||||
@@ -306,35 +345,42 @@ pub struct DownloadBlobResp {
|
|||||||
|
|
||||||
// ── Device ───────────────────────────────────────────────────────────────────
|
// ── Device ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/// Request to register a new device for the caller's identity.
|
||||||
pub struct RegisterDeviceReq {
|
pub struct RegisterDeviceReq {
|
||||||
pub device_id: Vec<u8>,
|
pub device_id: Vec<u8>,
|
||||||
pub device_name: String,
|
pub device_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response from device registration.
|
||||||
pub struct RegisterDeviceResp {
|
pub struct RegisterDeviceResp {
|
||||||
pub success: bool,
|
pub success: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Metadata about a registered device.
|
||||||
pub struct DeviceInfo {
|
pub struct DeviceInfo {
|
||||||
pub device_id: Vec<u8>,
|
pub device_id: Vec<u8>,
|
||||||
pub device_name: String,
|
pub device_name: String,
|
||||||
pub registered_at: u64,
|
pub registered_at: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response listing all registered devices.
|
||||||
pub struct ListDevicesResp {
|
pub struct ListDevicesResp {
|
||||||
pub devices: Vec<DeviceInfo>,
|
pub devices: Vec<DeviceInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request to revoke (remove) a registered device.
|
||||||
pub struct RevokeDeviceReq {
|
pub struct RevokeDeviceReq {
|
||||||
pub device_id: Vec<u8>,
|
pub device_id: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response from device revocation.
|
||||||
pub struct RevokeDeviceResp {
|
pub struct RevokeDeviceResp {
|
||||||
pub success: bool,
|
pub success: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Group metadata ───────────────────────────────────────────────────
|
// ── Group metadata ───────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/// Server-side group metadata.
|
||||||
pub struct GroupMetadata {
|
pub struct GroupMetadata {
|
||||||
pub group_id: Vec<u8>,
|
pub group_id: Vec<u8>,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -344,6 +390,7 @@ pub struct GroupMetadata {
|
|||||||
pub created_at: u64,
|
pub created_at: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request to update group metadata (name, description, avatar).
|
||||||
pub struct UpdateGroupMetadataReq {
|
pub struct UpdateGroupMetadataReq {
|
||||||
pub group_id: Vec<u8>,
|
pub group_id: Vec<u8>,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -351,55 +398,66 @@ pub struct UpdateGroupMetadataReq {
|
|||||||
pub avatar_hash: Vec<u8>,
|
pub avatar_hash: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request to list members of a group.
|
||||||
pub struct ListGroupMembersReq {
|
pub struct ListGroupMembersReq {
|
||||||
pub group_id: Vec<u8>,
|
pub group_id: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A group member with resolved username.
|
||||||
pub struct GroupMemberInfo {
|
pub struct GroupMemberInfo {
|
||||||
pub identity_key: Vec<u8>,
|
pub identity_key: Vec<u8>,
|
||||||
pub username: String,
|
pub username: String,
|
||||||
pub joined_at: u64,
|
pub joined_at: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response listing group members.
|
||||||
pub struct ListGroupMembersResp {
|
pub struct ListGroupMembersResp {
|
||||||
pub members: Vec<GroupMemberInfo>,
|
pub members: Vec<GroupMemberInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Moderation ───────────────────────────────────────────────────────────────
|
// ── Moderation ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/// Request to submit an encrypted abuse report.
|
||||||
pub struct ReportMessageReq {
|
pub struct ReportMessageReq {
|
||||||
pub encrypted_report: Vec<u8>,
|
pub encrypted_report: Vec<u8>,
|
||||||
pub conversation_id: Vec<u8>,
|
pub conversation_id: Vec<u8>,
|
||||||
pub reporter_identity: Vec<u8>,
|
pub reporter_identity: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response from report submission.
|
||||||
pub struct ReportMessageResp {
|
pub struct ReportMessageResp {
|
||||||
pub accepted: bool,
|
pub accepted: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request to ban a user. `duration_secs = 0` means permanent.
|
||||||
pub struct BanUserReq {
|
pub struct BanUserReq {
|
||||||
pub identity_key: Vec<u8>,
|
pub identity_key: Vec<u8>,
|
||||||
pub reason: String,
|
pub reason: String,
|
||||||
pub duration_secs: u64,
|
pub duration_secs: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response from ban operation.
|
||||||
pub struct BanUserResp {
|
pub struct BanUserResp {
|
||||||
pub success: bool,
|
pub success: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request to unban a user.
|
||||||
pub struct UnbanUserReq {
|
pub struct UnbanUserReq {
|
||||||
pub identity_key: Vec<u8>,
|
pub identity_key: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response from unban operation.
|
||||||
pub struct UnbanUserResp {
|
pub struct UnbanUserResp {
|
||||||
pub success: bool,
|
pub success: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request to list abuse reports with pagination.
|
||||||
pub struct ListReportsReq {
|
pub struct ListReportsReq {
|
||||||
pub limit: u32,
|
pub limit: u32,
|
||||||
pub offset: u32,
|
pub offset: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A stored abuse report entry.
|
||||||
pub struct ReportEntry {
|
pub struct ReportEntry {
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
pub encrypted_report: Vec<u8>,
|
pub encrypted_report: Vec<u8>,
|
||||||
@@ -408,10 +466,12 @@ pub struct ReportEntry {
|
|||||||
pub timestamp: u64,
|
pub timestamp: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response containing paginated abuse reports.
|
||||||
pub struct ListReportsResp {
|
pub struct ListReportsResp {
|
||||||
pub reports: Vec<ReportEntry>,
|
pub reports: Vec<ReportEntry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A banned user entry with expiration info.
|
||||||
pub struct BannedUserEntry {
|
pub struct BannedUserEntry {
|
||||||
pub identity_key: Vec<u8>,
|
pub identity_key: Vec<u8>,
|
||||||
pub reason: String,
|
pub reason: String,
|
||||||
@@ -419,25 +479,30 @@ pub struct BannedUserEntry {
|
|||||||
pub expires_at: u64,
|
pub expires_at: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response listing all currently banned users.
|
||||||
pub struct ListBannedResp {
|
pub struct ListBannedResp {
|
||||||
pub users: Vec<BannedUserEntry>,
|
pub users: Vec<BannedUserEntry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── P2P ──────────────────────────────────────────────────────────────────────
|
// ── P2P ──────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/// Request to publish a P2P endpoint (iroh node address).
|
||||||
pub struct PublishEndpointReq {
|
pub struct PublishEndpointReq {
|
||||||
pub identity_key: Vec<u8>,
|
pub identity_key: Vec<u8>,
|
||||||
pub node_addr: Vec<u8>,
|
pub node_addr: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request to resolve a P2P endpoint for an identity.
|
||||||
pub struct ResolveEndpointReq {
|
pub struct ResolveEndpointReq {
|
||||||
pub identity_key: Vec<u8>,
|
pub identity_key: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Response with the resolved P2P node address (empty if not published).
|
||||||
pub struct ResolveEndpointResp {
|
pub struct ResolveEndpointResp {
|
||||||
pub node_addr: Vec<u8>,
|
pub node_addr: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Health-check response.
|
||||||
pub struct HealthResp {
|
pub struct HealthResp {
|
||||||
pub status: String,
|
pub status: String,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ pub struct UserService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl UserService {
|
impl UserService {
|
||||||
|
/// Resolve a username to its identity key, with a KT inclusion proof if available.
|
||||||
pub fn resolve_user(&self, req: ResolveUserReq) -> Result<ResolveUserResp, DomainError> {
|
pub fn resolve_user(&self, req: ResolveUserReq) -> Result<ResolveUserResp, DomainError> {
|
||||||
if req.username.is_empty() {
|
if req.username.is_empty() {
|
||||||
return Err(DomainError::EmptyUsername);
|
return Err(DomainError::EmptyUsername);
|
||||||
@@ -46,6 +47,7 @@ impl UserService {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reverse-resolve an identity key to its username.
|
||||||
pub fn resolve_identity(
|
pub fn resolve_identity(
|
||||||
&self,
|
&self,
|
||||||
req: ResolveIdentityReq,
|
req: ResolveIdentityReq,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
//! When federation is enabled, the server binds a second QUIC endpoint on a
|
//! When federation is enabled, the server binds a second QUIC endpoint on a
|
||||||
//! dedicated port (default 7001) that only accepts connections from known peers
|
//! dedicated port (default 7001) that only accepts connections from known peers
|
||||||
//! authenticated via mTLS. Inbound requests are handled by [`service::FederationServiceImpl`],
|
//! authenticated via mTLS. Inbound requests are handled by [`service::FederationServiceImpl`],
|
||||||
//! which delegates to the local [`Store`]. Outbound relay uses [`client::FederationClient`].
|
//! which delegates to the local store. Outbound relay uses [`client::FederationClient`].
|
||||||
|
|
||||||
pub mod address;
|
pub mod address;
|
||||||
pub mod client;
|
pub mod client;
|
||||||
|
|||||||
Reference in New Issue
Block a user