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>,
|
||||
},
|
||||
|
||||
/// 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.
|
||||
Chat {
|
||||
#[arg(
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//! 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
|
||||
//! success or a negative error code on failure. Unused slots remain null and
|
||||
//! the server treats them as no-ops.
|
||||
@@ -27,9 +27,9 @@
|
||||
//!
|
||||
//! # Return values
|
||||
//!
|
||||
//! Hooks that can reject an operation return [`HookResult`]. The server maps
|
||||
//! `HOOK_CONTINUE` to `HookAction::Continue` and any other value to
|
||||
//! `HookAction::Reject` with the reason string from [`HookVTable::error_message`].
|
||||
//! Hooks that can reject an operation return an `i32` result code. The server maps
|
||||
//! [`HOOK_CONTINUE`] to allow and any other value to reject, reading the reason
|
||||
//! string from [`HookVTable::error_message`].
|
||||
|
||||
#![no_std]
|
||||
|
||||
@@ -105,7 +105,7 @@ pub struct CFetchEvent {
|
||||
|
||||
// ── 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
|
||||
/// pointer is non-null. The `user_data` field is passed as the first argument
|
||||
|
||||
@@ -1,9 +1,43 @@
|
||||
//! QUIC RPC framework for quicprochat v2.
|
||||
//!
|
||||
//! Wire format per QUIC stream:
|
||||
//! - Request: `[method_id: u16][request_id: u32][payload_len: u32][protobuf bytes]`
|
||||
//! - Response: `[status: u8][request_id: u32][payload_len: u32][protobuf bytes]`
|
||||
//! - Push: `[event_type: u16][payload_len: u32][protobuf bytes]` (uni-stream)
|
||||
//! This crate implements a lightweight, binary-framed RPC protocol over QUIC.
|
||||
//! Each RPC call opens a new QUIC bi-directional stream, sends a request frame,
|
||||
//! and reads a response frame. Server-initiated push events use uni-streams.
|
||||
//!
|
||||
//! # 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 framing;
|
||||
|
||||
@@ -1,7 +1,44 @@
|
||||
//! Client SDK for quicprochat v2.
|
||||
//!
|
||||
//! Provides `QpqClient` — a single entry point for connecting, authenticating,
|
||||
//! sending/receiving messages, and subscribing to real-time events.
|
||||
//! Provides [`QpqClient`](client::QpqClient) — a single entry point for
|
||||
//! 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 client;
|
||||
|
||||
@@ -15,6 +15,7 @@ pub struct 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> {
|
||||
self.store.delete_account(caller_identity_key)?;
|
||||
|
||||
|
||||
@@ -31,6 +31,9 @@ impl BlobService {
|
||||
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(
|
||||
&self,
|
||||
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(
|
||||
&self,
|
||||
req: DownloadBlobReq,
|
||||
|
||||
@@ -12,6 +12,10 @@ pub struct 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(
|
||||
&self,
|
||||
req: CreateChannelReq,
|
||||
|
||||
@@ -14,6 +14,7 @@ pub struct DeviceService {
|
||||
}
|
||||
|
||||
impl DeviceService {
|
||||
/// Register a new device for the caller's identity. Enforces a per-identity device limit.
|
||||
pub fn register_device(
|
||||
&self,
|
||||
req: RegisterDeviceReq,
|
||||
@@ -37,6 +38,7 @@ impl DeviceService {
|
||||
Ok(RegisterDeviceResp { success })
|
||||
}
|
||||
|
||||
/// List all registered devices for the caller's identity.
|
||||
pub fn list_devices(
|
||||
&self,
|
||||
caller_identity_key: &[u8],
|
||||
@@ -53,6 +55,7 @@ impl DeviceService {
|
||||
Ok(ListDevicesResp { devices })
|
||||
}
|
||||
|
||||
/// Revoke (remove) a registered device. Returns an error if the device is not found.
|
||||
pub fn revoke_device(
|
||||
&self,
|
||||
req: RevokeDeviceReq,
|
||||
|
||||
@@ -16,6 +16,7 @@ pub struct KeyService {
|
||||
}
|
||||
|
||||
impl KeyService {
|
||||
/// Upload an MLS KeyPackage for the given identity. Returns a SHA-256 fingerprint.
|
||||
pub fn upload_key_package(
|
||||
&self,
|
||||
req: UploadKeyPackageReq,
|
||||
@@ -40,6 +41,7 @@ impl KeyService {
|
||||
Ok(UploadKeyPackageResp { fingerprint })
|
||||
}
|
||||
|
||||
/// Fetch the stored MLS KeyPackage for an identity. Returns empty if none exists.
|
||||
pub fn fetch_key_package(
|
||||
&self,
|
||||
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(
|
||||
&self,
|
||||
req: UploadHybridKeyReq,
|
||||
@@ -70,6 +73,7 @@ impl KeyService {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Fetch the hybrid public key for a single identity. Returns empty if none exists.
|
||||
pub fn fetch_hybrid_key(
|
||||
&self,
|
||||
req: FetchHybridKeyReq,
|
||||
@@ -82,6 +86,7 @@ impl KeyService {
|
||||
Ok(FetchHybridKeyResp { hybrid_public_key })
|
||||
}
|
||||
|
||||
/// Batch-fetch hybrid public keys for multiple identities. Missing keys return empty.
|
||||
pub fn fetch_hybrid_keys(
|
||||
&self,
|
||||
req: FetchHybridKeysReq,
|
||||
|
||||
@@ -12,6 +12,7 @@ pub struct P2pService {
|
||||
}
|
||||
|
||||
impl P2pService {
|
||||
/// Publish a P2P endpoint (iroh node address) for the caller's identity.
|
||||
pub fn publish_endpoint(
|
||||
&self,
|
||||
req: PublishEndpointReq,
|
||||
@@ -26,6 +27,7 @@ impl P2pService {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Resolve a P2P endpoint for an identity key. Returns empty if none published.
|
||||
pub fn resolve_endpoint(
|
||||
&self,
|
||||
req: ResolveEndpointReq,
|
||||
@@ -42,6 +44,7 @@ impl P2pService {
|
||||
Ok(ResolveEndpointResp { node_addr })
|
||||
}
|
||||
|
||||
/// Return a health-check response (always "ok").
|
||||
pub fn health() -> HealthResp {
|
||||
HealthResp {
|
||||
status: "ok".into(),
|
||||
|
||||
@@ -74,6 +74,7 @@ pub struct RegisterStartReq {
|
||||
pub request_bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
/// OPAQUE registration start response.
|
||||
pub struct RegisterStartResp {
|
||||
pub response_bytes: Vec<u8>,
|
||||
}
|
||||
@@ -85,6 +86,7 @@ pub struct RegisterFinishReq {
|
||||
pub identity_key: Vec<u8>,
|
||||
}
|
||||
|
||||
/// OPAQUE registration finish response.
|
||||
pub struct RegisterFinishResp {
|
||||
pub success: bool,
|
||||
}
|
||||
@@ -95,6 +97,7 @@ pub struct LoginStartReq {
|
||||
pub request_bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
/// OPAQUE login start response.
|
||||
pub struct LoginStartResp {
|
||||
pub response_bytes: Vec<u8>,
|
||||
}
|
||||
@@ -106,6 +109,7 @@ pub struct LoginFinishReq {
|
||||
pub identity_key: Vec<u8>,
|
||||
}
|
||||
|
||||
/// OPAQUE login finish response containing the session token.
|
||||
pub struct LoginFinishResp {
|
||||
pub session_token: Vec<u8>,
|
||||
}
|
||||
@@ -119,6 +123,7 @@ pub struct Envelope {
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Request to enqueue a message for delivery to a recipient.
|
||||
pub struct EnqueueReq {
|
||||
pub recipient_key: Vec<u8>,
|
||||
pub payload: Vec<u8>,
|
||||
@@ -126,37 +131,44 @@ pub struct EnqueueReq {
|
||||
pub ttl_secs: u32,
|
||||
}
|
||||
|
||||
/// Response from enqueue with the assigned sequence number.
|
||||
pub struct EnqueueResp {
|
||||
pub seq: u64,
|
||||
pub delivery_proof: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Request to fetch (and drain) queued messages.
|
||||
pub struct FetchReq {
|
||||
pub recipient_key: Vec<u8>,
|
||||
pub channel_id: Vec<u8>,
|
||||
pub limit: u32,
|
||||
}
|
||||
|
||||
/// Response containing fetched message envelopes.
|
||||
pub struct FetchResp {
|
||||
pub payloads: Vec<Envelope>,
|
||||
}
|
||||
|
||||
/// Request to peek at queued messages without draining.
|
||||
pub struct PeekReq {
|
||||
pub recipient_key: Vec<u8>,
|
||||
pub channel_id: Vec<u8>,
|
||||
pub limit: u32,
|
||||
}
|
||||
|
||||
/// Response containing peeked message envelopes.
|
||||
pub struct PeekResp {
|
||||
pub payloads: Vec<Envelope>,
|
||||
}
|
||||
|
||||
/// Request to acknowledge messages up to a sequence number.
|
||||
pub struct AckReq {
|
||||
pub recipient_key: Vec<u8>,
|
||||
pub channel_id: Vec<u8>,
|
||||
pub seq_up_to: u64,
|
||||
}
|
||||
|
||||
/// Request to enqueue a message to multiple recipients at once.
|
||||
pub struct BatchEnqueueReq {
|
||||
pub recipient_keys: Vec<Vec<u8>>,
|
||||
pub payload: Vec<u8>,
|
||||
@@ -164,83 +176,100 @@ pub struct BatchEnqueueReq {
|
||||
pub ttl_secs: u32,
|
||||
}
|
||||
|
||||
/// Response from batch enqueue with one sequence number per recipient.
|
||||
pub struct BatchEnqueueResp {
|
||||
pub seqs: Vec<u64>,
|
||||
}
|
||||
|
||||
// ── Keys ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Request to upload an MLS KeyPackage.
|
||||
pub struct UploadKeyPackageReq {
|
||||
pub identity_key: Vec<u8>,
|
||||
pub package: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Response containing the SHA-256 fingerprint of the uploaded KeyPackage.
|
||||
#[derive(Debug)]
|
||||
pub struct UploadKeyPackageResp {
|
||||
pub fingerprint: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Request to fetch a stored MLS KeyPackage.
|
||||
pub struct FetchKeyPackageReq {
|
||||
pub identity_key: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Response containing the MLS KeyPackage (empty if not found).
|
||||
pub struct FetchKeyPackageResp {
|
||||
pub package: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Request to upload a hybrid (ML-KEM-768) public key.
|
||||
pub struct UploadHybridKeyReq {
|
||||
pub identity_key: Vec<u8>,
|
||||
pub hybrid_public_key: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Request to fetch a single hybrid public key.
|
||||
pub struct FetchHybridKeyReq {
|
||||
pub identity_key: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Response containing a hybrid public key (empty if not found).
|
||||
pub struct FetchHybridKeyResp {
|
||||
pub hybrid_public_key: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Request to batch-fetch hybrid public keys for multiple identities.
|
||||
pub struct FetchHybridKeysReq {
|
||||
pub identity_keys: Vec<Vec<u8>>,
|
||||
}
|
||||
|
||||
/// Response containing hybrid keys in the same order as the request.
|
||||
pub struct FetchHybridKeysResp {
|
||||
pub keys: Vec<Vec<u8>>,
|
||||
}
|
||||
|
||||
// ── Key Transparency / Revocation ────────────────────────────────────
|
||||
|
||||
/// Request to revoke an identity key in the Key Transparency log.
|
||||
pub struct RevokeKeyReq {
|
||||
pub identity_key: Vec<u8>,
|
||||
pub reason: String,
|
||||
}
|
||||
|
||||
/// Response from key revocation with the leaf index in the KT log.
|
||||
pub struct RevokeKeyResp {
|
||||
pub success: bool,
|
||||
pub leaf_index: u64,
|
||||
}
|
||||
|
||||
/// Request to check if an identity key has been revoked.
|
||||
pub struct CheckRevocationReq {
|
||||
pub identity_key: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Response with revocation status, reason, and timestamp.
|
||||
pub struct CheckRevocationResp {
|
||||
pub revoked: bool,
|
||||
pub reason: String,
|
||||
pub timestamp_ms: u64,
|
||||
}
|
||||
|
||||
/// Request for a range of Key Transparency audit log entries.
|
||||
pub struct AuditKeyTransparencyReq {
|
||||
pub start: u64,
|
||||
pub end: u64,
|
||||
}
|
||||
|
||||
/// A single entry in the KT audit log.
|
||||
pub struct AuditLogEntry {
|
||||
pub index: u64,
|
||||
pub leaf_hash: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Response containing KT audit log entries, tree size, and root hash.
|
||||
pub struct AuditKeyTransparencyResp {
|
||||
pub entries: Vec<AuditLogEntry>,
|
||||
pub tree_size: u64,
|
||||
@@ -249,10 +278,12 @@ pub struct AuditKeyTransparencyResp {
|
||||
|
||||
// ── Channel ──────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Request to create a 1:1 DM channel with a peer.
|
||||
pub struct CreateChannelReq {
|
||||
pub peer_key: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Response with the channel ID and whether it was newly created.
|
||||
#[derive(Debug)]
|
||||
pub struct CreateChannelResp {
|
||||
pub channel_id: Vec<u8>,
|
||||
@@ -261,25 +292,30 @@ pub struct CreateChannelResp {
|
||||
|
||||
// ── User ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Request to resolve a username to an identity key.
|
||||
pub struct ResolveUserReq {
|
||||
pub username: String,
|
||||
}
|
||||
|
||||
/// Response with the identity key and KT inclusion proof.
|
||||
pub struct ResolveUserResp {
|
||||
pub identity_key: Vec<u8>,
|
||||
pub inclusion_proof: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Request to reverse-resolve an identity key to a username.
|
||||
pub struct ResolveIdentityReq {
|
||||
pub identity_key: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Response with the resolved username (empty if unknown).
|
||||
pub struct ResolveIdentityResp {
|
||||
pub username: String,
|
||||
}
|
||||
|
||||
// ── Blob ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Request to upload a blob chunk. The blob is identified by its SHA-256 hash.
|
||||
pub struct UploadBlobReq {
|
||||
pub blob_hash: Vec<u8>,
|
||||
pub chunk: Vec<u8>,
|
||||
@@ -288,16 +324,19 @@ pub struct UploadBlobReq {
|
||||
pub mime_type: String,
|
||||
}
|
||||
|
||||
/// Response from blob upload containing the blob ID (same as hash).
|
||||
pub struct UploadBlobResp {
|
||||
pub blob_id: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Request to download a chunk of a stored blob.
|
||||
pub struct DownloadBlobReq {
|
||||
pub blob_id: Vec<u8>,
|
||||
pub offset: u64,
|
||||
pub length: u32,
|
||||
}
|
||||
|
||||
/// Response containing the requested blob chunk and metadata.
|
||||
pub struct DownloadBlobResp {
|
||||
pub chunk: Vec<u8>,
|
||||
pub total_size: u64,
|
||||
@@ -306,35 +345,42 @@ pub struct DownloadBlobResp {
|
||||
|
||||
// ── Device ───────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Request to register a new device for the caller's identity.
|
||||
pub struct RegisterDeviceReq {
|
||||
pub device_id: Vec<u8>,
|
||||
pub device_name: String,
|
||||
}
|
||||
|
||||
/// Response from device registration.
|
||||
pub struct RegisterDeviceResp {
|
||||
pub success: bool,
|
||||
}
|
||||
|
||||
/// Metadata about a registered device.
|
||||
pub struct DeviceInfo {
|
||||
pub device_id: Vec<u8>,
|
||||
pub device_name: String,
|
||||
pub registered_at: u64,
|
||||
}
|
||||
|
||||
/// Response listing all registered devices.
|
||||
pub struct ListDevicesResp {
|
||||
pub devices: Vec<DeviceInfo>,
|
||||
}
|
||||
|
||||
/// Request to revoke (remove) a registered device.
|
||||
pub struct RevokeDeviceReq {
|
||||
pub device_id: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Response from device revocation.
|
||||
pub struct RevokeDeviceResp {
|
||||
pub success: bool,
|
||||
}
|
||||
|
||||
// ── Group metadata ───────────────────────────────────────────────────
|
||||
|
||||
/// Server-side group metadata.
|
||||
pub struct GroupMetadata {
|
||||
pub group_id: Vec<u8>,
|
||||
pub name: String,
|
||||
@@ -344,6 +390,7 @@ pub struct GroupMetadata {
|
||||
pub created_at: u64,
|
||||
}
|
||||
|
||||
/// Request to update group metadata (name, description, avatar).
|
||||
pub struct UpdateGroupMetadataReq {
|
||||
pub group_id: Vec<u8>,
|
||||
pub name: String,
|
||||
@@ -351,55 +398,66 @@ pub struct UpdateGroupMetadataReq {
|
||||
pub avatar_hash: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Request to list members of a group.
|
||||
pub struct ListGroupMembersReq {
|
||||
pub group_id: Vec<u8>,
|
||||
}
|
||||
|
||||
/// A group member with resolved username.
|
||||
pub struct GroupMemberInfo {
|
||||
pub identity_key: Vec<u8>,
|
||||
pub username: String,
|
||||
pub joined_at: u64,
|
||||
}
|
||||
|
||||
/// Response listing group members.
|
||||
pub struct ListGroupMembersResp {
|
||||
pub members: Vec<GroupMemberInfo>,
|
||||
}
|
||||
|
||||
// ── Moderation ───────────────────────────────────────────────────────────────
|
||||
|
||||
/// Request to submit an encrypted abuse report.
|
||||
pub struct ReportMessageReq {
|
||||
pub encrypted_report: Vec<u8>,
|
||||
pub conversation_id: Vec<u8>,
|
||||
pub reporter_identity: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Response from report submission.
|
||||
pub struct ReportMessageResp {
|
||||
pub accepted: bool,
|
||||
}
|
||||
|
||||
/// Request to ban a user. `duration_secs = 0` means permanent.
|
||||
pub struct BanUserReq {
|
||||
pub identity_key: Vec<u8>,
|
||||
pub reason: String,
|
||||
pub duration_secs: u64,
|
||||
}
|
||||
|
||||
/// Response from ban operation.
|
||||
pub struct BanUserResp {
|
||||
pub success: bool,
|
||||
}
|
||||
|
||||
/// Request to unban a user.
|
||||
pub struct UnbanUserReq {
|
||||
pub identity_key: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Response from unban operation.
|
||||
pub struct UnbanUserResp {
|
||||
pub success: bool,
|
||||
}
|
||||
|
||||
/// Request to list abuse reports with pagination.
|
||||
pub struct ListReportsReq {
|
||||
pub limit: u32,
|
||||
pub offset: u32,
|
||||
}
|
||||
|
||||
/// A stored abuse report entry.
|
||||
pub struct ReportEntry {
|
||||
pub id: u64,
|
||||
pub encrypted_report: Vec<u8>,
|
||||
@@ -408,10 +466,12 @@ pub struct ReportEntry {
|
||||
pub timestamp: u64,
|
||||
}
|
||||
|
||||
/// Response containing paginated abuse reports.
|
||||
pub struct ListReportsResp {
|
||||
pub reports: Vec<ReportEntry>,
|
||||
}
|
||||
|
||||
/// A banned user entry with expiration info.
|
||||
pub struct BannedUserEntry {
|
||||
pub identity_key: Vec<u8>,
|
||||
pub reason: String,
|
||||
@@ -419,25 +479,30 @@ pub struct BannedUserEntry {
|
||||
pub expires_at: u64,
|
||||
}
|
||||
|
||||
/// Response listing all currently banned users.
|
||||
pub struct ListBannedResp {
|
||||
pub users: Vec<BannedUserEntry>,
|
||||
}
|
||||
|
||||
// ── P2P ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Request to publish a P2P endpoint (iroh node address).
|
||||
pub struct PublishEndpointReq {
|
||||
pub identity_key: Vec<u8>,
|
||||
pub node_addr: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Request to resolve a P2P endpoint for an identity.
|
||||
pub struct ResolveEndpointReq {
|
||||
pub identity_key: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Response with the resolved P2P node address (empty if not published).
|
||||
pub struct ResolveEndpointResp {
|
||||
pub node_addr: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Health-check response.
|
||||
pub struct HealthResp {
|
||||
pub status: String,
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ pub struct 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> {
|
||||
if req.username.is_empty() {
|
||||
return Err(DomainError::EmptyUsername);
|
||||
@@ -46,6 +47,7 @@ impl UserService {
|
||||
})
|
||||
}
|
||||
|
||||
/// Reverse-resolve an identity key to its username.
|
||||
pub fn resolve_identity(
|
||||
&self,
|
||||
req: ResolveIdentityReq,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//! When federation is enabled, the server binds a second QUIC endpoint on a
|
||||
//! dedicated port (default 7001) that only accepts connections from known peers
|
||||
//! 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 client;
|
||||
|
||||
Reference in New Issue
Block a user