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:
2026-03-09 20:46:54 +01:00
parent 416618f4cf
commit c256c38ffb
13 changed files with 171 additions and 13 deletions

View File

@@ -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(

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)?;

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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(),

View File

@@ -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,
} }

View File

@@ -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,

View File

@@ -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;