chore: rename quicproquo → quicprochat in docs, Docker, CI, and packaging
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
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
# Build Your Own SDK
|
||||
|
||||
This guide explains how to implement a quicproquo client SDK in any language.
|
||||
This guide explains how to implement a quicprochat client SDK in any language.
|
||||
|
||||
## Two Approaches
|
||||
|
||||
### Approach 1: C FFI Wrapper (recommended)
|
||||
|
||||
The simplest path. Wrap `libquicproquo_ffi` using your language's FFI mechanism (e.g., Python CFFI, Ruby FFI, JNI, Swift C interop).
|
||||
The simplest path. Wrap `libquicprochat_ffi` using your language's FFI mechanism (e.g., Python CFFI, Ruby FFI, JNI, Swift C interop).
|
||||
|
||||
**Pros**: Full Rust crypto stack (MLS, OPAQUE, hybrid KEM) with zero reimplementation.
|
||||
**Cons**: Requires shipping a native library, synchronous API only.
|
||||
@@ -26,7 +26,7 @@ Implement the QUIC transport and protobuf serialization natively in your languag
|
||||
|
||||
Open a QUIC connection to the server:
|
||||
|
||||
- **ALPN**: `qpq`
|
||||
- **ALPN**: `qpc`
|
||||
- **TLS**: 1.3 with server certificate verification
|
||||
- **Port**: 5001 (default)
|
||||
|
||||
@@ -64,7 +64,7 @@ payload = data[10 : 10 + length]
|
||||
|
||||
### 3. Protobuf Messages
|
||||
|
||||
Generate or hand-write protobuf encode/decode for the message types in `proto/qpq/v1/*.proto`.
|
||||
Generate or hand-write protobuf encode/decode for the message types in `proto/qpc/v1/*.proto`.
|
||||
|
||||
Minimum required messages for a basic client:
|
||||
|
||||
@@ -96,7 +96,7 @@ Client Server
|
||||
|
||||
Core operations (implement in order):
|
||||
|
||||
- [ ] **Connect**: Open QUIC connection with TLS 1.3 + ALPN `qpq`
|
||||
- [ ] **Connect**: Open QUIC connection with TLS 1.3 + ALPN `qpc`
|
||||
- [ ] **Health**: Send `HealthRequest` (method 802), verify server is running
|
||||
- [ ] **Register**: OPAQUE registration (methods 100-101)
|
||||
- [ ] **Login**: OPAQUE login (methods 102-103), store session token
|
||||
@@ -146,7 +146,7 @@ Study these SDKs for patterns:
|
||||
- **Go** (`sdks/go/`): Native QUIC + Cap'n Proto, full OPAQUE flow
|
||||
- **Python** (`sdks/python/`): Native QUIC + Protobuf v2 wire format
|
||||
- **TypeScript** (`sdks/typescript/`): WebSocket bridge, WASM crypto
|
||||
- **C FFI** (`crates/quicproquo-ffi/`): Synchronous wrapper
|
||||
- **C FFI** (`crates/quicprochat-ffi/`): Synchronous wrapper
|
||||
|
||||
## Testing
|
||||
|
||||
@@ -154,7 +154,7 @@ Test your SDK against a local server:
|
||||
|
||||
```sh
|
||||
# Start the server
|
||||
cargo run -p quicproquo-server
|
||||
cargo run -p quicprochat-server
|
||||
|
||||
# Run your SDK's tests
|
||||
```
|
||||
|
||||
@@ -1,49 +1,49 @@
|
||||
# C FFI Bindings
|
||||
|
||||
The C FFI layer (`crates/quicproquo-ffi/`) provides synchronous C-callable functions that wrap the Rust client library. This is the foundation for language bindings in Python (CFFI), Swift, Kotlin/JNI, Java, and Ruby.
|
||||
The C FFI layer (`crates/quicprochat-ffi/`) provides synchronous C-callable functions that wrap the Rust client library. This is the foundation for language bindings in Python (CFFI), Swift, Kotlin/JNI, Java, and Ruby.
|
||||
|
||||
## Building
|
||||
|
||||
```sh
|
||||
cargo build --release -p quicproquo-ffi
|
||||
cargo build --release -p quicprochat-ffi
|
||||
```
|
||||
|
||||
This produces:
|
||||
- Linux: `target/release/libquicproquo_ffi.so`
|
||||
- macOS: `target/release/libquicproquo_ffi.dylib`
|
||||
- Windows: `target/release/quicproquo_ffi.dll`
|
||||
- Linux: `target/release/libquicprochat_ffi.so`
|
||||
- macOS: `target/release/libquicprochat_ffi.dylib`
|
||||
- Windows: `target/release/quicprochat_ffi.dll`
|
||||
|
||||
## API
|
||||
|
||||
### Status Codes
|
||||
|
||||
```c
|
||||
#define QPQ_OK 0
|
||||
#define QPQ_ERROR 1
|
||||
#define QPQ_AUTH_FAILED 2
|
||||
#define QPQ_TIMEOUT 3
|
||||
#define QPQ_NOT_CONNECTED 4
|
||||
#define QPC_OK 0
|
||||
#define QPC_ERROR 1
|
||||
#define QPC_AUTH_FAILED 2
|
||||
#define QPC_TIMEOUT 3
|
||||
#define QPC_NOT_CONNECTED 4
|
||||
```
|
||||
|
||||
### Functions
|
||||
|
||||
```c
|
||||
// Connect to a server. Returns opaque handle or NULL on failure.
|
||||
QpqHandle* qpq_connect(
|
||||
QpqHandle* qpc_connect(
|
||||
const char* server, // "host:port"
|
||||
const char* ca_cert, // path to CA certificate PEM
|
||||
const char* server_name // TLS SNI name
|
||||
);
|
||||
|
||||
// Authenticate with OPAQUE. Returns status code.
|
||||
int qpq_login(
|
||||
int qpc_login(
|
||||
QpqHandle* handle,
|
||||
const char* username,
|
||||
const char* password
|
||||
);
|
||||
|
||||
// Send a message to a recipient (by username).
|
||||
int qpq_send(
|
||||
int qpc_send(
|
||||
QpqHandle* handle,
|
||||
const char* recipient, // recipient username
|
||||
const uint8_t* message, // message bytes
|
||||
@@ -52,20 +52,20 @@ int qpq_send(
|
||||
|
||||
// Receive pending messages. Blocks up to timeout_ms.
|
||||
// On success, *out_json is a JSON array of strings.
|
||||
int qpq_receive(
|
||||
int qpc_receive(
|
||||
QpqHandle* handle,
|
||||
uint32_t timeout_ms,
|
||||
char** out_json // caller must free with qpq_free_string
|
||||
char** out_json // caller must free with qpc_free_string
|
||||
);
|
||||
|
||||
// Disconnect and free the handle.
|
||||
void qpq_disconnect(QpqHandle* handle);
|
||||
void qpc_disconnect(QpqHandle* handle);
|
||||
|
||||
// Get last error message (valid until next FFI call on this handle).
|
||||
const char* qpq_last_error(const QpqHandle* handle);
|
||||
const char* qpc_last_error(const QpqHandle* handle);
|
||||
|
||||
// Free a string returned by qpq_receive.
|
||||
void qpq_free_string(char* ptr);
|
||||
// Free a string returned by qpc_receive.
|
||||
void qpc_free_string(char* ptr);
|
||||
```
|
||||
|
||||
## Usage Example (C)
|
||||
@@ -76,53 +76,53 @@ void qpq_free_string(char* ptr);
|
||||
|
||||
// Forward declarations (or include a header).
|
||||
typedef struct QpqHandle QpqHandle;
|
||||
extern QpqHandle* qpq_connect(const char*, const char*, const char*);
|
||||
extern int qpq_login(QpqHandle*, const char*, const char*);
|
||||
extern int qpq_send(QpqHandle*, const char*, const unsigned char*, size_t);
|
||||
extern int qpq_receive(QpqHandle*, unsigned int, char**);
|
||||
extern void qpq_disconnect(QpqHandle*);
|
||||
extern const char* qpq_last_error(const QpqHandle*);
|
||||
extern void qpq_free_string(char*);
|
||||
extern QpqHandle* qpc_connect(const char*, const char*, const char*);
|
||||
extern int qpc_login(QpqHandle*, const char*, const char*);
|
||||
extern int qpc_send(QpqHandle*, const char*, const unsigned char*, size_t);
|
||||
extern int qpc_receive(QpqHandle*, unsigned int, char**);
|
||||
extern void qpc_disconnect(QpqHandle*);
|
||||
extern const char* qpc_last_error(const QpqHandle*);
|
||||
extern void qpc_free_string(char*);
|
||||
|
||||
int main(void) {
|
||||
QpqHandle* h = qpq_connect("127.0.0.1:5001", "ca.pem", "localhost");
|
||||
QpqHandle* h = qpc_connect("127.0.0.1:5001", "ca.pem", "localhost");
|
||||
if (!h) {
|
||||
fprintf(stderr, "connect failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rc = qpq_login(h, "alice", "password123");
|
||||
int rc = qpc_login(h, "alice", "password123");
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "login failed: %s\n", qpq_last_error(h));
|
||||
qpq_disconnect(h);
|
||||
fprintf(stderr, "login failed: %s\n", qpc_last_error(h));
|
||||
qpc_disconnect(h);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* msg = "hello from C!";
|
||||
qpq_send(h, "bob", (const unsigned char*)msg, strlen(msg));
|
||||
qpc_send(h, "bob", (const unsigned char*)msg, strlen(msg));
|
||||
|
||||
char* json = NULL;
|
||||
rc = qpq_receive(h, 5000, &json);
|
||||
rc = qpc_receive(h, 5000, &json);
|
||||
if (rc == 0 && json) {
|
||||
printf("received: %s\n", json);
|
||||
qpq_free_string(json);
|
||||
qpc_free_string(json);
|
||||
}
|
||||
|
||||
qpq_disconnect(h);
|
||||
qpc_disconnect(h);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Compile with:
|
||||
```sh
|
||||
gcc -o demo demo.c -L target/release -lquicproquo_ffi
|
||||
gcc -o demo demo.c -L target/release -lquicprochat_ffi
|
||||
```
|
||||
|
||||
## Memory Management
|
||||
|
||||
- `qpq_connect` returns a heap-allocated handle. The caller **must** call `qpq_disconnect` to free it.
|
||||
- `qpq_receive` writes a heap-allocated JSON string to `*out_json`. The caller **must** call `qpq_free_string` to free it.
|
||||
- `qpq_last_error` returns a pointer owned by the handle. Do **not** free it. It is valid until the next FFI call on the same handle.
|
||||
- `qpc_connect` returns a heap-allocated handle. The caller **must** call `qpc_disconnect` to free it.
|
||||
- `qpc_receive` writes a heap-allocated JSON string to `*out_json`. The caller **must** call `qpc_free_string` to free it.
|
||||
- `qpc_last_error` returns a pointer owned by the handle. Do **not** free it. It is valid until the next FFI call on the same handle.
|
||||
|
||||
## Thread Safety
|
||||
|
||||
@@ -133,7 +133,7 @@ Each `QpqHandle` owns its own Tokio runtime. Concurrent calls on the **same** ha
|
||||
The FFI layer bridges synchronous C callers to the async Rust client:
|
||||
|
||||
```
|
||||
C caller ─── qpq_login() ───► QpqHandle ─── runtime.block_on() ───► async Rust client
|
||||
C caller ─── qpc_login() ───► QpqHandle ─── runtime.block_on() ───► async Rust client
|
||||
```
|
||||
|
||||
Each handle contains:
|
||||
|
||||
@@ -7,7 +7,7 @@ Location: `sdks/go/`
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
go get quicproquo.dev/sdk/go
|
||||
go get quicprochat.dev/sdk/go
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
@@ -18,13 +18,13 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"quicproquo.dev/sdk/go/qpq"
|
||||
"quicprochat.dev/sdk/go/qpc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
|
||||
client, err := qpq.Connect(ctx, qpq.Options{
|
||||
client, err := qpc.Connect(ctx, qpc.Options{
|
||||
Addr: "127.0.0.1:5001",
|
||||
InsecureSkipVerify: true, // dev only
|
||||
})
|
||||
@@ -63,7 +63,7 @@ func main() {
|
||||
|
||||
| Method | Description |
|
||||
|---|---|
|
||||
| `qpq.Connect(ctx, opts)` | Connect to server |
|
||||
| `qpc.Connect(ctx, opts)` | Connect to server |
|
||||
| `client.Close()` | Disconnect |
|
||||
| `client.Health(ctx)` | Health check |
|
||||
| `client.SetSessionToken(token)` | Set pre-existing token |
|
||||
@@ -81,7 +81,7 @@ func main() {
|
||||
|
||||
## Structure
|
||||
|
||||
- `qpq/` -- High-level client API
|
||||
- `qpc/` -- High-level client API
|
||||
- `transport/` -- QUIC + TLS 1.3 transport, Cap'n Proto RPC framing
|
||||
- `proto/node/` -- Generated Cap'n Proto Go types
|
||||
- `cmd/example/` -- Example usage
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# quicproquo SDK Documentation
|
||||
# quicprochat SDK Documentation
|
||||
|
||||
This guide covers how to build clients for the quicproquo E2E encrypted messenger using the official SDKs or by implementing your own.
|
||||
This guide covers how to build clients for the quicprochat E2E encrypted messenger using the official SDKs or by implementing your own.
|
||||
|
||||
## Official SDKs
|
||||
|
||||
| Language | Location | Transport | Status |
|
||||
|---|---|---|---|
|
||||
| **Rust** | `crates/quicproquo-client` | QUIC + Cap'n Proto | Production |
|
||||
| **Rust** | `crates/quicprochat-client` | QUIC + Cap'n Proto | Production |
|
||||
| **Go** | `sdks/go/` | QUIC + Cap'n Proto | Production |
|
||||
| **TypeScript** | `sdks/typescript/` | WebSocket bridge + WASM crypto | Production |
|
||||
| **Python** | `sdks/python/` | QUIC + Protobuf (v2) / Rust FFI | Production |
|
||||
| **C** | `crates/quicproquo-ffi/` | Rust FFI (synchronous) | Production |
|
||||
| **C** | `crates/quicprochat-ffi/` | Rust FFI (synchronous) | Production |
|
||||
| **Swift** | `sdks/swift/` | C FFI wrapper | In progress |
|
||||
| **Kotlin** | `sdks/kotlin/` | JNI + C FFI | In progress |
|
||||
| **Java** | `sdks/java/` | JNI + C FFI | In progress |
|
||||
@@ -57,7 +57,7 @@ Each RPC call opens a new QUIC bidirectional stream. The request and response us
|
||||
|
||||
## Canonical Schemas
|
||||
|
||||
- **Protobuf** (v2): `proto/qpq/v1/*.proto` -- 14 service definitions
|
||||
- **Protobuf** (v2): `proto/qpc/v1/*.proto` -- 14 service definitions
|
||||
- **Cap'n Proto** (v1): `schemas/*.capnp` -- legacy RPC interface
|
||||
|
||||
The protobuf schemas in `proto/qpq/v1/` are the canonical API contract for the v2 protocol. New SDKs should implement against these definitions.
|
||||
The protobuf schemas in `proto/qpc/v1/` are the canonical API contract for the v2 protocol. New SDKs should implement against these definitions.
|
||||
|
||||
@@ -7,7 +7,7 @@ Location: `sdks/python/`
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
pip install quicproquo
|
||||
pip install quicprochat
|
||||
```
|
||||
|
||||
## Transport Backends
|
||||
@@ -18,7 +18,7 @@ Uses [aioquic](https://github.com/aiortc/aioquic) for native QUIC transport with
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from quicproquo import QpqClient, ConnectOptions
|
||||
from quicprochat import QpqClient, ConnectOptions
|
||||
|
||||
async def main():
|
||||
client = await QpqClient.connect(ConnectOptions(
|
||||
@@ -45,14 +45,14 @@ asyncio.run(main())
|
||||
|
||||
### Rust FFI (synchronous)
|
||||
|
||||
Wraps `libquicproquo_ffi` via CFFI for full Rust crypto stack at native speed.
|
||||
Wraps `libquicprochat_ffi` via CFFI for full Rust crypto stack at native speed.
|
||||
|
||||
```sh
|
||||
cargo build --release -p quicproquo-ffi
|
||||
cargo build --release -p quicprochat-ffi
|
||||
```
|
||||
|
||||
```python
|
||||
from quicproquo import QpqClient, ConnectOptions
|
||||
from quicprochat import QpqClient, ConnectOptions
|
||||
|
||||
client = QpqClient.connect_ffi(ConnectOptions(
|
||||
addr="127.0.0.1:5001",
|
||||
@@ -112,9 +112,9 @@ client.close_sync()
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `quicproquo/client.py` | High-level client API |
|
||||
| `quicproquo/transport.py` | QUIC transport (aioquic) |
|
||||
| `quicproquo/ffi.py` | Rust FFI transport (CFFI) |
|
||||
| `quicproquo/proto.py` | Protobuf encode/decode |
|
||||
| `quicproquo/wire.py` | v2 wire format framing |
|
||||
| `quicproquo/types.py` | Data types and exceptions |
|
||||
| `quicprochat/client.py` | High-level client API |
|
||||
| `quicprochat/transport.py` | QUIC transport (aioquic) |
|
||||
| `quicprochat/ffi.py` | Rust FFI transport (CFFI) |
|
||||
| `quicprochat/proto.py` | Protobuf encode/decode |
|
||||
| `quicprochat/wire.py` | v2 wire format framing |
|
||||
| `quicprochat/types.py` | Data types and exceptions |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Rust SDK
|
||||
|
||||
The Rust client is the reference implementation, located in `crates/quicproquo-client/`.
|
||||
The Rust client is the reference implementation, located in `crates/quicprochat-client/`.
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -8,7 +8,7 @@ Add to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
quicproquo-client = { path = "crates/quicproquo-client" }
|
||||
quicprochat-client = { path = "crates/quicprochat-client" }
|
||||
```
|
||||
|
||||
## Connection
|
||||
@@ -16,7 +16,7 @@ quicproquo-client = { path = "crates/quicproquo-client" }
|
||||
The Rust client connects directly over QUIC with Cap'n Proto RPC:
|
||||
|
||||
```rust
|
||||
use quicproquo_client::{cmd_health, cmd_login, cmd_send, connect_node};
|
||||
use quicprochat_client::{cmd_health, cmd_login, cmd_send, connect_node};
|
||||
|
||||
// Health check
|
||||
cmd_health("127.0.0.1:5001", &ca_cert_path, "localhost").await?;
|
||||
@@ -38,14 +38,14 @@ cmd_login(
|
||||
- OPAQUE authentication with zeroizing credential storage
|
||||
- SQLCipher local state with Argon2id key derivation
|
||||
- Sealed sender metadata protection
|
||||
- v2 QUIC + Protobuf transport (via `quicproquo-sdk` crate)
|
||||
- v2 QUIC + Protobuf transport (via `quicprochat-sdk` crate)
|
||||
|
||||
## v2 SDK Crate
|
||||
|
||||
The `quicproquo-sdk` crate provides the higher-level v2 API:
|
||||
The `quicprochat-sdk` crate provides the higher-level v2 API:
|
||||
|
||||
```rust
|
||||
use quicproquo_sdk::QpqClient;
|
||||
use quicprochat_sdk::QpqClient;
|
||||
|
||||
let client = QpqClient::connect("127.0.0.1:5001", &tls_config).await?;
|
||||
let health = client.health().await?;
|
||||
@@ -55,9 +55,9 @@ let health = client.health().await?;
|
||||
|
||||
| Crate | Purpose |
|
||||
|---|---|
|
||||
| `quicproquo-core` | Crypto primitives, MLS, hybrid KEM |
|
||||
| `quicproquo-proto` | Protobuf + Cap'n Proto generated types |
|
||||
| `quicproquo-rpc` | QUIC RPC framework (framing, dispatch) |
|
||||
| `quicproquo-sdk` | High-level client SDK |
|
||||
| `quicproquo-client` | CLI/TUI client application |
|
||||
| `quicproquo-ffi` | C FFI bindings |
|
||||
| `quicprochat-core` | Crypto primitives, MLS, hybrid KEM |
|
||||
| `quicprochat-proto` | Protobuf + Cap'n Proto generated types |
|
||||
| `quicprochat-rpc` | QUIC RPC framework (framing, dispatch) |
|
||||
| `quicprochat-sdk` | High-level client SDK |
|
||||
| `quicprochat-client` | CLI/TUI client application |
|
||||
| `quicprochat-ffi` | C FFI bindings |
|
||||
|
||||
@@ -7,13 +7,13 @@ Location: `sdks/typescript/`
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
npm install quicproquo
|
||||
npm install quicprochat
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```typescript
|
||||
import { QpqClient } from "quicproquo";
|
||||
import { QpqClient } from "quicprochat";
|
||||
|
||||
// Connect via WebSocket bridge
|
||||
const client = await QpqClient.connect({
|
||||
@@ -115,7 +115,7 @@ The TypeScript SDK uses a WebSocket bridge proxy because browsers cannot open ra
|
||||
Browser ─── WebSocket ───► Bridge Proxy ─── QUIC/capnp ───► Server
|
||||
```
|
||||
|
||||
Crypto operations (Ed25519, hybrid KEM, sealed sender) run entirely in WASM, compiled from the Rust `quicproquo-core` crate.
|
||||
Crypto operations (Ed25519, hybrid KEM, sealed sender) run entirely in WASM, compiled from the Rust `quicprochat-core` crate.
|
||||
|
||||
## Structure
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# v2 Wire Format
|
||||
|
||||
The quicproquo v2 protocol uses QUIC (RFC 9000) with TLS 1.3 as the transport layer and Protocol Buffers for message serialization.
|
||||
The quicprochat v2 protocol uses QUIC (RFC 9000) with TLS 1.3 as the transport layer and Protocol Buffers for message serialization.
|
||||
|
||||
## Connection
|
||||
|
||||
- **Protocol**: QUIC with TLS 1.3
|
||||
- **ALPN**: `qpq`
|
||||
- **ALPN**: `qpc`
|
||||
- **Port**: 5001 (default)
|
||||
- **Certificate**: Server presents a TLS certificate; clients verify against a CA cert
|
||||
|
||||
@@ -137,7 +137,7 @@ This allows concurrent RPCs without head-of-line blocking.
|
||||
|
||||
## Protobuf Definitions
|
||||
|
||||
All message types are defined in `proto/qpq/v1/*.proto`:
|
||||
All message types are defined in `proto/qpc/v1/*.proto`:
|
||||
|
||||
| File | Services |
|
||||
|---|---|
|
||||
|
||||
Reference in New Issue
Block a user