Rename all project references from quicproquo/qpq to quicprochat/qpc across documentation, Docker configuration, CI workflows, packaging scripts, operational configs, and build tooling. - Docker: crate paths, binary names, user/group, data dirs, env vars - CI: workflow crate references, binary names, artifact names - Docs: all markdown files under docs/, SDK READMEs, book.toml - Packaging: OpenWrt Makefile, init script, UCI config (file renames) - Scripts: justfile, dev-shell, screenshot, cross-compile, ai_team - Operations: Prometheus config, alert rules, Grafana dashboard - Config: .env.example (QPQ_* → QPC_*), CODEOWNERS paths - Top-level: README, CONTRIBUTING, ROADMAP, CLAUDE.md
16 KiB
RPC Reference
Proto package: qpc.v1
Proto files: 14 files in proto/qpc/v1/
Total methods: 44
This page is the complete Protobuf definition reference for all 14 proto files in the v2 RPC protocol. For transport framing, see Wire Format Overview. For method ID assignments, see Method ID Reference.
Generated Rust types live in crates/quicprochat-proto/src/ (via prost).
auth.proto (IDs 100-103)
OPAQUE asymmetric PAKE for registration and login. See Auth Schema for field-level documentation and flow diagrams.
syntax = "proto3";
package qpc.v1;
message OpaqueRegisterStartRequest {
string username = 1;
bytes request = 2;
}
message OpaqueRegisterStartResponse {
bytes response = 1;
}
message OpaqueRegisterFinishRequest {
string username = 1;
bytes upload = 2;
bytes identity_key = 3;
}
message OpaqueRegisterFinishResponse {
bool success = 1;
}
message OpaqueLoginStartRequest {
string username = 1;
bytes request = 2;
}
message OpaqueLoginStartResponse {
bytes response = 1;
}
message OpaqueLoginFinishRequest {
string username = 1;
bytes finalization = 2;
bytes identity_key = 3;
}
message OpaqueLoginFinishResponse {
bytes session_token = 1;
}
common.proto
Shared types and account deletion.
syntax = "proto3";
package qpc.v1;
// Auth context for federation and internal use.
// In v2, session authentication is carried at the QUIC connection level
// (session token), not per-message.
message Auth {
bytes access_token = 1;
bytes device_id = 2;
}
// Account deletion (ID 950).
message DeleteAccountRequest {}
message DeleteAccountResponse {
bool success = 1;
}
DeleteAccountRequest is empty; the server derives the user identity from the authenticated QUIC session. On success, all user data is purged: OPAQUE record, identity keys, key packages, hybrid keys, queued deliveries, channel memberships, devices, and recovery bundles.
delivery.proto (IDs 200-205)
Store-and-forward message relay. See Delivery Schema for field-level documentation.
syntax = "proto3";
package qpc.v1;
message Envelope {
uint64 seq = 1;
bytes data = 2;
}
message EnqueueRequest {
bytes recipient_key = 1;
bytes payload = 2;
bytes channel_id = 3;
uint32 ttl_secs = 4;
bytes message_id = 5;
}
message EnqueueResponse {
uint64 seq = 1;
bytes delivery_proof = 2;
bool duplicate = 3;
}
message FetchRequest {
bytes recipient_key = 1;
bytes channel_id = 2;
uint32 limit = 3;
bytes device_id = 4;
}
message FetchResponse {
repeated Envelope payloads = 1;
}
message FetchWaitRequest {
bytes recipient_key = 1;
bytes channel_id = 2;
uint64 timeout_ms = 3;
uint32 limit = 4;
bytes device_id = 5;
}
message FetchWaitResponse {
repeated Envelope payloads = 1;
}
message PeekRequest {
bytes recipient_key = 1;
bytes channel_id = 2;
uint32 limit = 3;
bytes device_id = 4;
}
message PeekResponse {
repeated Envelope payloads = 1;
}
message AckRequest {
bytes recipient_key = 1;
bytes channel_id = 2;
uint64 seq_up_to = 3;
bytes device_id = 4;
}
message AckResponse {}
message BatchEnqueueRequest {
repeated bytes recipient_keys = 1;
bytes payload = 2;
bytes channel_id = 3;
uint32 ttl_secs = 4;
bytes message_id = 5;
}
message BatchEnqueueResponse {
repeated uint64 seqs = 1;
}
keys.proto (IDs 300-304, 510-520)
MLS KeyPackages, hybrid PQ keys, and key transparency. See Delivery Schema for field-level documentation.
syntax = "proto3";
package qpc.v1;
message UploadKeyPackageRequest {
bytes identity_key = 1;
bytes package = 2;
}
message UploadKeyPackageResponse {
bytes fingerprint = 1;
}
message FetchKeyPackageRequest {
bytes identity_key = 1;
}
message FetchKeyPackageResponse {
bytes package = 1;
}
message UploadHybridKeyRequest {
bytes identity_key = 1;
bytes hybrid_public_key = 2;
}
message UploadHybridKeyResponse {}
message FetchHybridKeyRequest {
bytes identity_key = 1;
}
message FetchHybridKeyResponse {
bytes hybrid_public_key = 1;
}
message FetchHybridKeysRequest {
repeated bytes identity_keys = 1;
}
message FetchHybridKeysResponse {
repeated bytes keys = 1;
}
// Key revocation (ID 510).
message RevokeKeyRequest {
bytes identity_key = 1;
string reason = 2;
}
message RevokeKeyResponse {
bool success = 1;
uint64 leaf_index = 2;
}
// Check revocation status (ID 511).
message CheckRevocationRequest {
bytes identity_key = 1;
}
message CheckRevocationResponse {
bool revoked = 1;
string reason = 2;
uint64 timestamp_ms = 3;
}
// KT audit log retrieval (ID 520).
message AuditKeyTransparencyRequest {
uint64 start = 1;
uint64 end = 2;
}
message AuditKeyTransparencyResponse {
repeated LogEntry entries = 1;
uint64 tree_size = 2;
bytes root = 3;
}
message LogEntry {
uint64 index = 1;
bytes leaf_hash = 2;
}
channel.proto (ID 400)
syntax = "proto3";
package qpc.v1;
// Channel create (1 method).
// Method ID: 400.
message CreateChannelRequest {
bytes peer_key = 1;
}
message CreateChannelResponse {
bytes channel_id = 1;
bool was_new = 2;
}
CreateChannel deterministically derives a channel ID from the calling user's identity key and peer_key, so repeated calls with the same peer return the same channel_id. was_new is true on the first creation.
group.proto (IDs 410-413)
Group management: member removal, metadata, member listing, and key rotation.
syntax = "proto3";
package qpc.v1;
// Group management (4 methods).
// Method IDs: 410-413.
message RemoveMemberRequest {
bytes group_id = 1;
bytes member_identity_key = 2;
}
message RemoveMemberResponse {
bytes commit = 1;
}
message UpdateGroupMetadataRequest {
bytes group_id = 1;
string name = 2;
string description = 3;
bytes avatar_hash = 4;
}
message UpdateGroupMetadataResponse {
bool success = 1;
}
message ListGroupMembersRequest {
bytes group_id = 1;
}
message ListGroupMembersResponse {
repeated GroupMemberInfo members = 1;
}
message GroupMemberInfo {
bytes identity_key = 1;
string username = 2;
uint64 joined_at = 3;
}
message RotateKeysRequest {
bytes group_id = 1;
}
message RotateKeysResponse {
bytes commit = 1;
}
// Server-side group metadata store.
message GroupMetadata {
bytes group_id = 1;
string name = 2;
string description = 3;
bytes avatar_hash = 4;
bytes creator_key = 5;
uint64 created_at = 6;
}
RemoveMember and RotateKeys return a commit field containing the MLS Commit message bytes that the caller must fan-out to the remaining group members via BatchEnqueue. joined_at in GroupMemberInfo is a Unix timestamp in milliseconds.
moderation.proto (IDs 420-424)
Content moderation: encrypted reports, bans, and audit lists.
syntax = "proto3";
package qpc.v1;
// Moderation service: report, ban, unban, list reports, list banned.
// Method IDs: 420-424.
message ReportMessageRequest {
bytes encrypted_report = 1;
bytes conversation_id = 2;
}
message ReportMessageResponse {
bool accepted = 1;
}
message BanUserRequest {
bytes identity_key = 1;
string reason = 2;
uint64 duration_secs = 3;
}
message BanUserResponse {
bool success = 1;
}
message UnbanUserRequest {
bytes identity_key = 1;
}
message UnbanUserResponse {
bool success = 1;
}
message ListReportsRequest {
uint32 limit = 1;
uint32 offset = 2;
}
message ReportEntry {
uint64 id = 1;
bytes encrypted_report = 2;
bytes conversation_id = 3;
bytes reporter_identity = 4;
uint64 timestamp = 5;
}
message ListReportsResponse {
repeated ReportEntry reports = 1;
}
message ListBannedRequest {}
message BannedUserEntry {
bytes identity_key = 1;
string reason = 2;
uint64 banned_at = 3;
uint64 expires_at = 4; // 0 = permanent ban.
}
message ListBannedResponse {
repeated BannedUserEntry users = 1;
}
ReportMessageRequest.encrypted_report is encrypted asymmetrically to the server's admin key; the server cannot read it without the admin private key. BanUserRequest.duration_secs = 0 is a permanent ban. BannedUserEntry.expires_at = 0 denotes a permanent ban.
user.proto (IDs 500-501)
Forward and reverse user resolution.
syntax = "proto3";
package qpc.v1;
// User resolve + identity (2 methods).
// Method IDs: 500-501.
message ResolveUserRequest {
string username = 1;
}
message ResolveUserResponse {
bytes identity_key = 1;
bytes inclusion_proof = 2;
}
message ResolveIdentityRequest {
bytes identity_key = 1;
}
message ResolveIdentityResponse {
string username = 1;
}
ResolveUser returns the user's Ed25519 identity key (32 bytes) along with a key-transparency inclusion proof. ResolveIdentity is the reverse lookup: given a key, return the username.
blob.proto (IDs 600-601)
Content-addressed binary object storage with chunked upload and ranged download.
syntax = "proto3";
package qpc.v1;
// Blob upload/download (2 methods).
// Method IDs: 600-601.
message UploadBlobRequest {
bytes blob_hash = 1;
bytes chunk = 2;
uint64 offset = 3;
uint64 total_size = 4;
string mime_type = 5;
}
message UploadBlobResponse {
bytes blob_id = 1;
}
message DownloadBlobRequest {
bytes blob_id = 1;
uint64 offset = 2;
uint32 length = 3;
}
message DownloadBlobResponse {
bytes chunk = 1;
uint64 total_size = 2;
string mime_type = 3;
}
UploadBlob accepts chunks; callers send multiple requests for large blobs using offset + total_size for reassembly. blob_hash is the SHA-256 of the entire blob (content addressing). DownloadBlob supports ranged reads via offset + length.
device.proto (IDs 700-702, 710)
Multi-device management and push notification token registration.
syntax = "proto3";
package qpc.v1;
// Device register/list/revoke (3 methods).
// Method IDs: 700-702.
message RegisterDeviceRequest {
bytes device_id = 1;
string device_name = 2;
}
message RegisterDeviceResponse {
bool success = 1;
}
message ListDevicesRequest {}
message ListDevicesResponse {
repeated Device devices = 1;
}
message Device {
bytes device_id = 1;
string device_name = 2;
uint64 registered_at = 3;
}
message RevokeDeviceRequest {
bytes device_id = 1;
}
message RevokeDeviceResponse {
bool success = 1;
}
// Push notification token registration (ID 710).
enum PushPlatform {
PUSH_PLATFORM_UNSPECIFIED = 0;
PUSH_PLATFORM_APNS = 1;
PUSH_PLATFORM_FCM = 2;
PUSH_PLATFORM_WEB_PUSH = 3;
}
message RegisterPushTokenRequest {
bytes device_id = 1;
PushPlatform platform = 2;
string token = 3;
}
message RegisterPushTokenResponse {
bool success = 1;
}
Device.registered_at is a Unix timestamp in milliseconds. Device.device_id is a client-generated UUID (16 bytes). RegisterPushToken associates a platform-specific push token with the device for server-initiated push notifications.
recovery.proto (IDs 750-752)
Encrypted account recovery bundle storage. The server stores an opaque blob indexed by SHA-256(recovery_token). The plaintext recovery token and bundle contents are never visible to the server.
syntax = "proto3";
package qpc.v1;
// Recovery service.
// Method IDs: 750-752.
message StoreRecoveryBundleRequest {
bytes token_hash = 1; // SHA-256(recovery_token)
bytes bundle = 2; // Encrypted recovery bundle (opaque to server).
uint64 ttl_secs = 3; // Default 90 days = 7776000.
}
message StoreRecoveryBundleResponse {
bool success = 1;
}
message FetchRecoveryBundleRequest {
bytes token_hash = 1; // SHA-256(recovery_token)
}
message FetchRecoveryBundleResponse {
bytes bundle = 1; // Empty if no bundle found.
}
message DeleteRecoveryBundleRequest {
bytes token_hash = 1; // SHA-256(recovery_token)
}
message DeleteRecoveryBundleResponse {
bool success = 1;
}
p2p.proto (IDs 800-802)
iroh P2P node address exchange and server health probe.
syntax = "proto3";
package qpc.v1;
// P2P endpoint publish/resolve + health (3 methods).
// Method IDs: 800-802.
message PublishEndpointRequest {
bytes identity_key = 1;
bytes node_addr = 2;
}
message PublishEndpointResponse {}
message ResolveEndpointRequest {
bytes identity_key = 1;
}
message ResolveEndpointResponse {
bytes node_addr = 1;
}
message HealthRequest {}
message HealthResponse {
string status = 1;
string node_id = 2;
string version = 3;
uint64 uptime_secs = 4;
string storage_backend = 5;
}
node_addr is an iroh NodeAddr serialised to bytes. HealthResponse.storage_backend is one of "sql", "file", or "postgres". HealthRequest requires no authentication and is suitable for infrastructure health checks.
federation.proto (IDs 900-905)
Cross-server relay and proxy operations. All federation methods include a FederationAuth struct carrying the origin server's domain for inter-server authentication.
syntax = "proto3";
package qpc.v1;
// Federation relay + proxy (6 methods).
// Method IDs: 900-905.
message FederationAuth {
string origin = 1;
}
message RelayEnqueueRequest {
bytes recipient_key = 1;
bytes payload = 2;
bytes channel_id = 3;
FederationAuth auth = 4;
}
message RelayEnqueueResponse {
uint64 seq = 1;
}
message RelayBatchEnqueueRequest {
repeated bytes recipient_keys = 1;
bytes payload = 2;
bytes channel_id = 3;
FederationAuth auth = 4;
}
message RelayBatchEnqueueResponse {
repeated uint64 seqs = 1;
}
message ProxyFetchKeyPackageRequest {
bytes identity_key = 1;
FederationAuth auth = 2;
}
message ProxyFetchKeyPackageResponse {
bytes package = 1;
}
message ProxyFetchHybridKeyRequest {
bytes identity_key = 1;
FederationAuth auth = 2;
}
message ProxyFetchHybridKeyResponse {
bytes hybrid_public_key = 1;
}
message ProxyResolveUserRequest {
string username = 1;
FederationAuth auth = 2;
}
message ProxyResolveUserResponse {
bytes identity_key = 1;
}
message FederationHealthRequest {}
message FederationHealthResponse {
string status = 1;
string server_domain = 2;
}
Federation relay methods (RelayEnqueue, RelayBatchEnqueue) are analogous to the client-facing delivery methods but originate from a peer server rather than a client. Proxy methods allow one server to fetch resources (key packages, hybrid keys, user identities) on behalf of a user whose home server is remote.
push.proto (Event IDs 1000-1003)
Server-push event types sent on QUIC uni-streams using the push frame format.
syntax = "proto3";
package qpc.v1;
// Server-push event types (sent on QUIC uni-streams).
// Event type IDs: 1000+.
message PushEvent {
oneof event {
NewMessage new_message = 1;
TypingIndicator typing = 2;
PresenceUpdate presence = 3;
GroupMembershipChange membership = 4;
}
}
message NewMessage {
bytes channel_id = 1;
bytes sender_key = 2;
uint64 seq = 3;
bytes payload = 4;
uint64 timestamp_ms = 5;
}
message TypingIndicator {
bytes channel_id = 1;
bytes sender_key = 2;
bool is_typing = 3;
}
message PresenceUpdate {
bytes identity_key = 1;
bool online = 2;
uint64 last_seen_ms = 3;
}
message GroupMembershipChange {
bytes channel_id = 1;
bytes actor_key = 2;
bytes target_key = 3;
MembershipAction action = 4;
}
enum MembershipAction {
MEMBERSHIP_ACTION_UNSPECIFIED = 0;
MEMBERSHIP_ACTION_ADDED = 1;
MEMBERSHIP_ACTION_REMOVED = 2;
MEMBERSHIP_ACTION_LEFT = 3;
}
Push events are sent by the server without a client request. The event_type field in the push frame header (see Wire Format Overview) determines which oneof variant is present. Clients must handle all event types and ignore unknown types gracefully.
Further reading
- Wire Format Overview -- frame format and transport parameters
- Method ID Reference -- complete method ID table
- Auth Schema -- OPAQUE flow documentation
- Delivery Schema -- delivery and key management documentation
- Authentication Service Internals -- server-side OPAQUE flow
- Storage Backend -- how data is persisted