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:
2026-03-07 18:46:43 +01:00
parent a710037dde
commit 2e081ead8e
179 changed files with 1645 additions and 1645 deletions

View File

@@ -22,15 +22,15 @@ This compiles all nine crates in the workspace:
| Crate | Type | Purpose |
|---|---|---|
| `quicproquo-core` | library | Crypto primitives, MLS `GroupMember` state machine, hybrid KEM |
| `quicproquo-proto` | library | Protobuf schemas (prost), generated types, method ID constants |
| `quicproquo-kt` | library | Key Transparency Merkle log |
| `quicproquo-plugin-api` | library | `#![no_std]` C-ABI plugin interface (`HookVTable`) |
| `quicproquo-rpc` | library | QUIC RPC framing, server dispatcher, client, Tower middleware |
| `quicproquo-sdk` | library | `QpqClient`, event broadcast, `ConversationStore` |
| `quicproquo-server` | binary | Unified Authentication + Delivery Service (`qpq-server`) |
| `quicproquo-client` | binary | CLI client (`qpq`) with REPL and subcommands |
| `quicproquo-p2p` | library | iroh P2P layer (compiled when the `mesh` feature is enabled) |
| `quicprochat-core` | library | Crypto primitives, MLS `GroupMember` state machine, hybrid KEM |
| `quicprochat-proto` | library | Protobuf schemas (prost), generated types, method ID constants |
| `quicprochat-kt` | library | Key Transparency Merkle log |
| `quicprochat-plugin-api` | library | `#![no_std]` C-ABI plugin interface (`HookVTable`) |
| `quicprochat-rpc` | library | QUIC RPC framing, server dispatcher, client, Tower middleware |
| `quicprochat-sdk` | library | `QpqClient`, event broadcast, `ConversationStore` |
| `quicprochat-server` | binary | Unified Authentication + Delivery Service (`qpc-server`) |
| `quicprochat-client` | binary | CLI client (`qpc`) with REPL and subcommands |
| `quicprochat-p2p` | library | iroh P2P layer (compiled when the `mesh` feature is enabled) |
For a release build with LTO, symbol stripping, and single codegen unit:
@@ -61,11 +61,11 @@ A `justfile` at the repository root provides shortcuts for common tasks:
| `just lint` | `cargo clippy --workspace -- -D warnings` | Check for warnings (CI-strict) |
| `just fmt` | `cargo fmt --all -- --check` | Check formatting |
| `just fmt-fix` | `cargo fmt --all` | Auto-format |
| `just proto` | `cargo build -p quicproquo-proto` | Trigger Protobuf codegen |
| `just rpc` | `cargo build -p quicproquo-rpc` | Build RPC framework only |
| `just sdk` | `cargo build -p quicproquo-sdk` | Build client SDK only |
| `just server` | `cargo build -p quicproquo-server` | Build server only |
| `just client` | `cargo build -p quicproquo-client` | Build CLI client only |
| `just proto` | `cargo build -p quicprochat-proto` | Trigger Protobuf codegen |
| `just rpc` | `cargo build -p quicprochat-rpc` | Build RPC framework only |
| `just sdk` | `cargo build -p quicprochat-sdk` | Build client SDK only |
| `just server` | `cargo build -p quicprochat-server` | Build server only |
| `just client` | `cargo build -p quicprochat-client` | Build CLI client only |
| `just clean` | `cargo clean` | Remove build artifacts |
---
@@ -88,16 +88,16 @@ cargo test --workspace -- --test-threads 1
To run tests for a single crate:
```bash
cargo test -p quicproquo-core
cargo test -p quicproquo-server
cargo test -p quicproquo-rpc
cargo test -p quicprochat-core
cargo test -p quicprochat-server
cargo test -p quicprochat-rpc
```
---
## Protobuf code generation
The `quicproquo-proto` crate does not contain hand-written Rust types for wire messages. Instead, its `build.rs` script uses `prost-build` to generate Rust source from the `.proto` schema files in `proto/qpq/v1/`.
The `quicprochat-proto` crate does not contain hand-written Rust types for wire messages. Instead, its `build.rs` script uses `prost-build` to generate Rust source from the `.proto` schema files in `proto/qpc/v1/`.
### How it works
@@ -110,7 +110,7 @@ The `quicproquo-proto` crate does not contain hand-written Rust types for wire m
The `build.rs` script emits `cargo:rerun-if-changed` directives for each `.proto` file. Modifying a schema triggers automatic re-generation on the next `cargo build`.
### Design constraints of `quicproquo-proto`
### Design constraints of `quicprochat-proto`
The proto crate is intentionally restricted:
@@ -141,7 +141,7 @@ xcode-select --install
Run E2E tests with `--test-threads 1` to serialise the tests and avoid bind conflicts on the shared test port:
```bash
cargo test -p quicproquo-client --test e2e -- --test-threads 1
cargo test -p quicprochat-client --test e2e -- --test-threads 1
```
---

View File

@@ -1,6 +1,6 @@
# Certificate lifecycle and CA-signed TLS
This page describes how to use CA-issued certificates with quicproquo and how to think about certificate pinning, rotation, and lifecycle.
This page describes how to use CA-issued certificates with quicprochat and how to think about certificate pinning, rotation, and lifecycle.
For basic server TLS setup (self-signed certs, generation), see [Running the Server](running-the-server.md#tls-certificate-handling).
@@ -8,8 +8,8 @@ For basic server TLS setup (self-signed certs, generation), see [Running the Ser
## Current behaviour
- **Server:** Uses a single TLS certificate and private key (DER format). If the files are missing and the server is not in production mode, it generates a self-signed certificate. Production mode (`QPQ_PRODUCTION=1`) requires existing cert and key files.
- **Client:** Trusts exactly the roots in the file given by `--ca-cert` (or `QPQ_CA_CERT`). Typically this is the server's own certificate (pinning) or a CA that signed the server cert.
- **Server:** Uses a single TLS certificate and private key (DER format). If the files are missing and the server is not in production mode, it generates a self-signed certificate. Production mode (`QPC_PRODUCTION=1`) requires existing cert and key files.
- **Client:** Trusts exactly the roots in the file given by `--ca-cert` (or `QPC_CA_CERT`). Typically this is the server's own certificate (pinning) or a CA that signed the server cert.
---
@@ -20,7 +20,7 @@ To pin the server so the client only connects to that server:
1. Copy the server's certificate file (e.g. `data/server-cert.der`) from the server (or your deployment).
2. Use that file as the client's CA cert:
```bash
qpq --ca-cert /path/to/server-cert.der ...
qpc --ca-cert /path/to/server-cert.der ...
```
3. The client will only accept a connection if the server presents that exact certificate (or a chain ending in it). No separate CA bundle is required.
@@ -43,12 +43,12 @@ To use a certificate issued by a public CA (e.g. Let's Encrypt):
```
2. **Configure the server** to use those paths:
```bash
export QPQ_TLS_CERT=/etc/quicproquo/server-cert.der
export QPQ_TLS_KEY=/etc/quicproquo/server-key.der
export QPC_TLS_CERT=/etc/quicprochat/server-cert.der
export QPC_TLS_KEY=/etc/quicprochat/server-key.der
```
3. **Configure the client** to trust the CA that signed the server cert. Use the CAs certificate (or the CA bundle) as `--ca-cert`:
```bash
qpq --ca-cert /etc/ssl/certs/your-ca.der --server-name your.server.example ...
qpc --ca-cert /etc/ssl/certs/your-ca.der --server-name your.server.example ...
```
The `--server-name` must match the certificates SAN (e.g. DNS name).
@@ -60,7 +60,7 @@ To use a certificate issued by a public CA (e.g. Let's Encrypt):
- **Manual rotation:** Replace `server-cert.der` and `server-key.der` on disk, then restart the server. Clients that pin the new cert must be updated with the new cert file.
- **Lets Encrypt renewal:** After renewing (e.g. via certbot), convert the new cert and key to DER, replace the files, and restart the server. If clients use the CA cert (e.g. ISRG Root X1) as `--ca-cert`, they do not need updates when the server cert is renewed.
- **OCSP / CRL:** The quicproquo server does not currently perform OCSP stapling or CRL checks. Revocation is handled by the client or by operational procedures (e.g. short-lived certs, rotation on compromise).
- **OCSP / CRL:** The quicprochat server does not currently perform OCSP stapling or CRL checks. Revocation is handled by the client or by operational procedures (e.g. short-lived certs, rotation on compromise).
---
@@ -70,6 +70,6 @@ To use a certificate issued by a public CA (e.g. Let's Encrypt):
|------------------|-------------|--------------------|
| Pinned (single server) | Self-signed or any | Servers cert file |
| CA-issued | Lets Encrypt (or other CA) | CA cert (or bundle) |
| Production | Always use existing cert/key; set `QPQ_PRODUCTION=1` | CA or pinned server cert |
| Production | Always use existing cert/key; set `QPC_PRODUCTION=1` | CA or pinned server cert |
For production, prefer either (a) certificate pinning with the servers cert or (b) a CA-issued server cert with clients trusting the CA, and plan for rotation and restart (or future reload support).

View File

@@ -75,13 +75,13 @@ You will need **three terminal windows**: one for the server, one for Alice, and
In **Terminal 1** (Server):
```bash
cargo run -p quicproquo-server
cargo run -p quicprochat-server
```
Wait for the log line confirming it is accepting connections:
```
INFO quicproquo_server: accepting QUIC connections addr="0.0.0.0:7000"
INFO quicprochat_server: accepting QUIC connections addr="0.0.0.0:7000"
```
If this is the first run, you will also see a log line about generating the self-signed TLS certificate. The certificate is written to `data/server-cert.der`, which the client will use for TLS verification.
@@ -91,7 +91,7 @@ If this is the first run, you will also see a log line about generating the self
In **Terminal 2** (Alice):
```bash
cargo run -p quicproquo-client -- register-state \
cargo run -p quicprochat-client -- register-state \
--state alice.bin \
--server 127.0.0.1:7000
```
@@ -116,7 +116,7 @@ KeyPackage uploaded successfully.
In **Terminal 3** (Bob):
```bash
cargo run -p quicproquo-client -- register-state \
cargo run -p quicprochat-client -- register-state \
--state bob.bin \
--server 127.0.0.1:7000
```
@@ -137,7 +137,7 @@ In **Terminal 2** (Alice):
First, create the group:
```bash
cargo run -p quicproquo-client -- create-group \
cargo run -p quicprochat-client -- create-group \
--state alice.bin \
--group-id "demo-chat"
```
@@ -151,7 +151,7 @@ Alice is now the sole member of the group at epoch 0.
Next, invite Bob using his identity key from Step 3:
```bash
cargo run -p quicproquo-client -- invite \
cargo run -p quicprochat-client -- invite \
--state alice.bin \
--peer-key <BOB_KEY> \
--server 127.0.0.1:7000
@@ -173,7 +173,7 @@ Alice's group state has now advanced to epoch 1.
In **Terminal 3** (Bob):
```bash
cargo run -p quicproquo-client -- join \
cargo run -p quicprochat-client -- join \
--state bob.bin \
--server 127.0.0.1:7000
```
@@ -195,7 +195,7 @@ Bob is now a member of the group at epoch 1, sharing the same group secret as Al
In **Terminal 2** (Alice):
```bash
cargo run -p quicproquo-client -- send \
cargo run -p quicprochat-client -- send \
--state alice.bin \
--peer-key <BOB_KEY> \
--msg "Hello Bob, this is encrypted with MLS!" \
@@ -215,7 +215,7 @@ message sent
In **Terminal 3** (Bob):
```bash
cargo run -p quicproquo-client -- recv \
cargo run -p quicprochat-client -- recv \
--state bob.bin \
--server 127.0.0.1:7000
```
@@ -233,7 +233,7 @@ This command:
In **Terminal 3** (Bob):
```bash
cargo run -p quicproquo-client -- send \
cargo run -p quicprochat-client -- send \
--state bob.bin \
--peer-key <ALICE_KEY> \
--msg "Hi Alice, received loud and clear!" \
@@ -249,7 +249,7 @@ message sent
In **Terminal 2** (Alice):
```bash
cargo run -p quicproquo-client -- recv \
cargo run -p quicprochat-client -- recv \
--state alice.bin \
--server 127.0.0.1:7000
```
@@ -266,7 +266,7 @@ If you want to see the entire flow in a single command without managing three te
```bash
# Ensure the server is running, then:
cargo run -p quicproquo-client -- demo-group --server 127.0.0.1:7000
cargo run -p quicprochat-client -- demo-group --server 127.0.0.1:7000
```
```
@@ -327,7 +327,7 @@ Ensure the client has access to the server's TLS certificate. By default, both s
- [REPL Command Reference](repl-reference.md) -- complete list of 40+ slash commands
- [Rich Messaging](rich-messaging.md) -- reactions, typing indicators, edit/delete
- [File Transfer](file-transfer.md) -- chunked upload/download with SHA-256 verification
- [Go SDK](go-sdk.md) -- build Go applications against the qpq server
- [Go SDK](go-sdk.md) -- build Go applications against the qpc server
- [TypeScript SDK & Browser Demo](typescript-sdk.md) -- WASM crypto in the browser
- [Mesh Networking](mesh-networking.md) -- P2P, broadcast channels, store-and-forward
- [MLS (RFC 9420)](../protocol-layers/mls.md) -- how the MLS group operations work

View File

@@ -1,6 +1,6 @@
# Docker Deployment
quicproquo includes a multi-stage Dockerfile and a Docker Compose configuration for building and running the server in containers.
quicprochat includes a multi-stage Dockerfile and a Docker Compose configuration for building and running the server in containers.
---
@@ -40,11 +40,11 @@ services:
- "7000:7000/udp"
environment:
RUST_LOG: "info"
QPQ_LISTEN: "0.0.0.0:7000"
QPQ_DATA_DIR: "/var/lib/quicproquo"
QPQ_PRODUCTION: "true"
QPC_LISTEN: "0.0.0.0:7000"
QPC_DATA_DIR: "/var/lib/quicprochat"
QPC_PRODUCTION: "true"
volumes:
- server-data:/var/lib/quicproquo
- server-data:/var/lib/quicprochat
restart: unless-stopped
volumes:
@@ -74,7 +74,7 @@ WORKDIR /build
# Copy manifests first so dependency layers are cached independently of source.
COPY Cargo.toml Cargo.lock ./
COPY crates/quicproquo-core/Cargo.toml crates/quicproquo-core/Cargo.toml
COPY crates/quicprochat-core/Cargo.toml crates/quicprochat-core/Cargo.toml
# ... (all 9 crate manifests)
# Create dummy source files for dependency caching.
@@ -84,11 +84,11 @@ RUN mkdir -p ... && echo 'fn main() {}' > ...
COPY schemas/ schemas/
# Build dependencies only (cache layer).
RUN cargo build --release --bin qpq-server 2>/dev/null || true
RUN cargo build --release --bin qpc-server 2>/dev/null || true
# Copy real source and build for real.
COPY crates/ crates/
RUN cargo build --release --bin qpq-server
RUN cargo build --release --bin qpc-server
```
Key steps:
@@ -96,7 +96,7 @@ Key steps:
1. **Base image**: `rust:bookworm` (Debian Bookworm with the Rust toolchain pre-installed).
2. **No system compiler required**: Unlike v1, the builder stage does not install `capnproto`. The v2 Protobuf compiler is vendored by `protobuf-src` and compiled automatically as part of `cargo build`.
3. **Copy manifests first**: `Cargo.toml` and `Cargo.lock` are copied before source code with dummy stubs so that dependency compilation is cached in a separate Docker layer.
4. **Copy schemas**: The `schemas/` directory is copied before the dependency build because `quicproquo-proto/build.rs` references it.
4. **Copy schemas**: The `schemas/` directory is copied before the dependency build because `quicprochat-proto/build.rs` references it.
5. **Copy real source and build**: After the dependency cache layer, real source files are copied in and `cargo build --release` produces the final binary.
### Stage 2: Runtime (`debian:bookworm-slim`)
@@ -108,39 +108,39 @@ RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /build/target/release/qpq-server /usr/local/bin/qpq-server
COPY --from=builder /build/target/release/qpc-server /usr/local/bin/qpc-server
RUN groupadd --system qpq \
&& useradd --system --gid qpq --no-create-home --shell /usr/sbin/nologin qpq \
&& mkdir -p /var/lib/quicproquo \
&& chown qpq:qpq /var/lib/quicproquo
RUN groupadd --system qpc \
&& useradd --system --gid qpc --no-create-home --shell /usr/sbin/nologin qpc \
&& mkdir -p /var/lib/quicprochat \
&& chown qpc:qpc /var/lib/quicprochat
EXPOSE 7000
VOLUME ["/var/lib/quicproquo"]
VOLUME ["/var/lib/quicprochat"]
ENV RUST_LOG=info \
QPQ_LISTEN=0.0.0.0:7000 \
QPQ_DATA_DIR=/var/lib/quicproquo \
QPQ_TLS_CERT=/var/lib/quicproquo/server-cert.der \
QPQ_TLS_KEY=/var/lib/quicproquo/server-key.der \
QPQ_PRODUCTION=true
QPC_LISTEN=0.0.0.0:7000 \
QPC_DATA_DIR=/var/lib/quicprochat \
QPC_TLS_CERT=/var/lib/quicprochat/server-cert.der \
QPC_TLS_KEY=/var/lib/quicprochat/server-key.der \
QPC_PRODUCTION=true
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD test -f /var/lib/quicproquo/server-cert.der || exit 1
CMD test -f /var/lib/quicprochat/server-cert.der || exit 1
USER qpq
USER qpc
CMD ["qpq-server"]
CMD ["qpc-server"]
```
Key characteristics:
- **Minimal image**: No Rust toolchain, no build tools, no `protoc` binary.
- **`ca-certificates`**: Included for future HTTPS calls (e.g., ACME certificate provisioning).
- **Dedicated user**: The container runs as the `qpq` system user (not `root`) for defense in depth.
- **Named volume**: `/var/lib/quicproquo` is declared as a `VOLUME` for data persistence.
- **`QPQ_PRODUCTION=true`**: The runtime image defaults to production mode, requiring pre-existing TLS certificates and a strong auth token.
- **Dedicated user**: The container runs as the `qpc` system user (not `root`) for defense in depth.
- **Named volume**: `/var/lib/quicprochat` is declared as a `VOLUME` for data persistence.
- **`QPC_PRODUCTION=true`**: The runtime image defaults to production mode, requiring pre-existing TLS certificates and a strong auth token.
---
@@ -153,7 +153,7 @@ services:
server:
# ... existing config ...
volumes:
- server-data:/var/lib/quicproquo
- server-data:/var/lib/quicprochat
volumes:
server-data:
@@ -165,13 +165,13 @@ Or use a bind mount for easier inspection:
mkdir -p ./server-data
docker run -d \
--name quicproquo \
--name quicprochat \
-p 7000:7000/udp \
-v "$(pwd)/server-data:/var/lib/quicproquo" \
-e QPQ_ALLOW_INSECURE_AUTH=true \
-e QPQ_PRODUCTION=false \
-v "$(pwd)/server-data:/var/lib/quicprochat" \
-e QPC_ALLOW_INSECURE_AUTH=true \
-e QPC_PRODUCTION=false \
-e RUST_LOG=info \
qpq-server
qpc-server
```
Without a volume, all server state (including TLS certificates and message queues) is lost when the container is removed. The server will generate a new self-signed certificate on each fresh start, which means clients will need the new certificate to connect.
@@ -183,19 +183,19 @@ Without a volume, all server state (including TLS certificates and message queue
To build the Docker image without starting a container:
```bash
docker build -t qpq-server -f docker/Dockerfile .
docker build -t qpc-server -f docker/Dockerfile .
```
To run it in development mode (without production validation):
```bash
docker run -d \
--name quicproquo \
--name quicprochat \
-p 7000:7000/udp \
-e QPQ_ALLOW_INSECURE_AUTH=true \
-e QPQ_PRODUCTION=false \
-e QPC_ALLOW_INSECURE_AUTH=true \
-e QPC_PRODUCTION=false \
-e RUST_LOG=info \
qpq-server
qpc-server
```
---
@@ -206,15 +206,15 @@ When the server runs in Docker with `docker compose up`, the client can connect
```bash
# Extract the server's TLS cert from the container volume
docker compose cp server:/var/lib/quicproquo/server-cert.der ./data/server-cert.der
docker compose cp server:/var/lib/quicprochat/server-cert.der ./data/server-cert.der
# Connect
cargo run -p quicproquo-client -- ping \
cargo run -p quicprochat-client -- ping \
--ca-cert ./data/server-cert.der \
--server-name localhost
```
If you mounted a bind volume (e.g., `./server-data:/var/lib/quicproquo`), the certificate is directly accessible at `./server-data/server-cert.der`.
If you mounted a bind volume (e.g., `./server-data:/var/lib/quicprochat`), the certificate is directly accessible at `./server-data/server-cert.der`.
---

View File

@@ -1,7 +1,7 @@
# C FFI Bindings
The `quicproquo-ffi` crate provides a synchronous C API for the quicproquo
messaging client. It wraps the async `quicproquo-client` library behind an
The `quicprochat-ffi` crate provides a synchronous C API for the quicprochat
messaging client. It wraps the async `quicprochat-client` library behind an
opaque handle, so C, Python, Swift, or any language with C FFI support can
connect, authenticate, send messages, and receive messages.
@@ -13,26 +13,26 @@ internals.
```bash
# Shared library (.so / .dylib / .dll) + static archive (.a)
cargo build --release -p quicproquo-ffi
cargo build --release -p quicprochat-ffi
```
Output:
| Platform | Shared library | Static library |
|----------|---------------------------------------------|-----------------------------------------|
| Linux | `target/release/libquicproquo_ffi.so` | `target/release/libquicproquo_ffi.a` |
| macOS | `target/release/libquicproquo_ffi.dylib` | `target/release/libquicproquo_ffi.a` |
| Windows | `target/release/quicproquo_ffi.dll` | `target/release/quicproquo_ffi.lib` |
| Linux | `target/release/libquicprochat_ffi.so` | `target/release/libquicprochat_ffi.a` |
| macOS | `target/release/libquicprochat_ffi.dylib` | `target/release/libquicprochat_ffi.a` |
| Windows | `target/release/quicprochat_ffi.dll` | `target/release/quicprochat_ffi.lib` |
## Status Codes
| Code | Constant | Meaning |
|------|--------------------|------------------------------------------|
| 0 | `QPQ_OK` | Success |
| 1 | `QPQ_ERROR` | Generic error (check `qpq_last_error`) |
| 2 | `QPQ_AUTH_FAILED` | OPAQUE authentication failed |
| 3 | `QPQ_TIMEOUT` | Receive timed out with no messages |
| 4 | `QPQ_NOT_CONNECTED`| Handle is null or not logged in |
| 0 | `QPC_OK` | Success |
| 1 | `QPC_ERROR` | Generic error (check `qpc_last_error`) |
| 2 | `QPC_AUTH_FAILED` | OPAQUE authentication failed |
| 3 | `QPC_TIMEOUT` | Receive timed out with no messages |
| 4 | `QPC_NOT_CONNECTED`| Handle is null or not logged in |
## C API Reference
@@ -40,10 +40,10 @@ All functions use the `extern "C"` calling convention. All string parameters
must be valid, non-null, null-terminated UTF-8. The opaque handle type is
`QpqHandle *`.
### `qpq_connect`
### `qpc_connect`
```c
QpqHandle *qpq_connect(
QpqHandle *qpc_connect(
const char *server, /* "host:port", e.g. "127.0.0.1:7000" */
const char *ca_cert, /* path to CA certificate file (DER) */
const char *server_name /* TLS server name, e.g. "localhost" */
@@ -54,11 +54,11 @@ Creates a Tokio runtime, performs a health check against the server, and
returns a heap-allocated opaque handle. Returns `NULL` on failure (invalid
arguments, server unreachable, or runtime creation failed).
### `qpq_login`
### `qpc_login`
```c
int32_t qpq_login(
QpqHandle *handle, /* handle from qpq_connect */
int32_t qpc_login(
QpqHandle *handle, /* handle from qpc_connect */
const char *username, /* OPAQUE username */
const char *password /* OPAQUE password */
);
@@ -66,16 +66,16 @@ int32_t qpq_login(
Authenticates with the server using OPAQUE (password-authenticated key
exchange). On success the handle is marked as logged-in and subsequent
`qpq_send`/`qpq_receive` calls use the authenticated session.
`qpc_send`/`qpc_receive` calls use the authenticated session.
**Returns:** `QPQ_OK` on success, `QPQ_AUTH_FAILED` on bad credentials,
`QPQ_NOT_CONNECTED` if the handle is null, or `QPQ_ERROR` on other failures.
**Returns:** `QPC_OK` on success, `QPC_AUTH_FAILED` on bad credentials,
`QPC_NOT_CONNECTED` if the handle is null, or `QPC_ERROR` on other failures.
### `qpq_send`
### `qpc_send`
```c
int32_t qpq_send(
QpqHandle *handle, /* handle from qpq_connect */
int32_t qpc_send(
QpqHandle *handle, /* handle from qpc_connect */
const char *recipient, /* recipient username (null-terminated) */
const uint8_t *message, /* message bytes (UTF-8, not null-terminated) */
size_t message_len /* length of message in bytes */
@@ -86,14 +86,14 @@ Resolves the recipient by username, then sends an MLS-encrypted message
through the server. The `message` buffer must contain valid UTF-8 of at least
`message_len` bytes. The handle must be logged in.
**Returns:** `QPQ_OK` on success, `QPQ_NOT_CONNECTED` if not logged in, or
`QPQ_ERROR` on failure (recipient not found, network error, etc.).
**Returns:** `QPC_OK` on success, `QPC_NOT_CONNECTED` if not logged in, or
`QPC_ERROR` on failure (recipient not found, network error, etc.).
### `qpq_receive`
### `qpc_receive`
```c
int32_t qpq_receive(
QpqHandle *handle, /* handle from qpq_connect */
int32_t qpc_receive(
QpqHandle *handle, /* handle from qpc_connect */
uint32_t timeout_ms, /* maximum wait time in milliseconds */
char **out_json /* output: heap-allocated JSON string */
);
@@ -102,48 +102,48 @@ int32_t qpq_receive(
Blocks up to `timeout_ms` milliseconds waiting for pending messages. On
success, `*out_json` points to a null-terminated JSON string containing an
array of decrypted message strings (e.g., `["hello","world"]`). The caller
**must** free this string with `qpq_free_string`.
**must** free this string with `qpc_free_string`.
**Returns:** `QPQ_OK` on success (even if the array is empty),
`QPQ_TIMEOUT` if the wait expires with no messages, `QPQ_NOT_CONNECTED` if
not logged in, or `QPQ_ERROR` on failure.
**Returns:** `QPC_OK` on success (even if the array is empty),
`QPC_TIMEOUT` if the wait expires with no messages, `QPC_NOT_CONNECTED` if
not logged in, or `QPC_ERROR` on failure.
### `qpq_disconnect`
### `qpc_disconnect`
```c
void qpq_disconnect(QpqHandle *handle);
void qpc_disconnect(QpqHandle *handle);
```
Shuts down the Tokio runtime and frees the handle. After this call, the
handle must not be used again. Passing `NULL` is a safe no-op.
### `qpq_last_error`
### `qpc_last_error`
```c
const char *qpq_last_error(const QpqHandle *handle);
const char *qpc_last_error(const QpqHandle *handle);
```
Returns the last error message recorded on the handle, or `NULL` if no error
has occurred. The returned pointer is valid **only** until the next FFI call
on the same handle. Do **not** free this pointer -- it is owned by the handle.
### `qpq_free_string`
### `qpc_free_string`
```c
void qpq_free_string(char *ptr);
void qpc_free_string(char *ptr);
```
Frees a string previously returned by `qpq_receive` via the `out_json`
Frees a string previously returned by `qpc_receive` via the `out_json`
output parameter. Passing `NULL` is a safe no-op. Do **not** use this to
free strings from `qpq_last_error`.
free strings from `qpc_last_error`.
## Memory Management Rules
1. **`QpqHandle`** is heap-allocated by `qpq_connect` and freed by
`qpq_disconnect`. Do not use the handle after disconnecting.
2. **`out_json` from `qpq_receive`** is heap-allocated. Free it with
`qpq_free_string`.
3. **`qpq_last_error`** returns a pointer owned by the handle. Do not free
1. **`QpqHandle`** is heap-allocated by `qpc_connect` and freed by
`qpc_disconnect`. Do not use the handle after disconnecting.
2. **`out_json` from `qpc_receive`** is heap-allocated. Free it with
`qpc_free_string`.
3. **`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.
4. All `const char *` input parameters are borrowed for the duration of the
call and not stored beyond it.
@@ -154,11 +154,11 @@ Every function that returns `int32_t` uses the status codes above. The
recommended pattern is:
```c
int rc = qpq_login(handle, "alice", "password123");
if (rc != QPQ_OK) {
const char *err = qpq_last_error(handle);
int rc = qpc_login(handle, "alice", "password123");
if (rc != QPC_OK) {
const char *err = qpc_last_error(handle);
fprintf(stderr, "login failed (code %d): %s\n", rc, err ? err : "unknown");
qpq_disconnect(handle);
qpc_disconnect(handle);
return 1;
}
```
@@ -169,48 +169,48 @@ if (rc != QPQ_OK) {
#include <stdio.h>
#include <string.h>
/* Link with: -lquicproquo_ffi -lpthread -ldl -lm */
/* Link with: -lquicprochat_ffi -lpthread -ldl -lm */
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 *, unsigned long);
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 *, unsigned long);
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 *);
#define QPQ_OK 0
#define QPC_OK 0
int main(void) {
QpqHandle *h = qpq_connect("127.0.0.1:7000", "server-cert.der", "localhost");
QpqHandle *h = qpc_connect("127.0.0.1:7000", "server-cert.der", "localhost");
if (!h) {
fprintf(stderr, "connection failed\n");
return 1;
}
if (qpq_login(h, "alice", "secret") != QPQ_OK) {
fprintf(stderr, "login failed: %s\n", qpq_last_error(h));
qpq_disconnect(h);
if (qpc_login(h, "alice", "secret") != QPC_OK) {
fprintf(stderr, "login failed: %s\n", qpc_last_error(h));
qpc_disconnect(h);
return 1;
}
/* Send a message */
const char *msg = "hello from C";
if (qpq_send(h, "bob", (const unsigned char *)msg, strlen(msg)) != QPQ_OK) {
fprintf(stderr, "send failed: %s\n", qpq_last_error(h));
if (qpc_send(h, "bob", (const unsigned char *)msg, strlen(msg)) != QPC_OK) {
fprintf(stderr, "send failed: %s\n", qpc_last_error(h));
}
/* Receive messages (5 second timeout) */
char *json = NULL;
int rc = qpq_receive(h, 5000, &json);
if (rc == QPQ_OK && json) {
int rc = qpc_receive(h, 5000, &json);
if (rc == QPC_OK && json) {
printf("received: %s\n", json);
qpq_free_string(json);
qpc_free_string(json);
}
qpq_disconnect(h);
qpc_disconnect(h);
return 0;
}
```
@@ -218,26 +218,26 @@ int main(void) {
Compile and link:
```bash
gcc -o qpq_demo qpq_demo.c -L target/release -lquicproquo_ffi -lpthread -ldl -lm
LD_LIBRARY_PATH=target/release ./qpq_demo
gcc -o qpc_demo qpc_demo.c -L target/release -lquicprochat_ffi -lpthread -ldl -lm
LD_LIBRARY_PATH=target/release ./qpc_demo
```
## Python Bindings
A ready-made Python `ctypes` wrapper is provided in
[`examples/python/qpq_client.py`](https://github.com/nickvidal/quicproquo/tree/main/examples/python).
[`examples/python/qpc_client.py`](https://github.com/nickvidal/quicprochat/tree/main/examples/python).
```bash
# Build the FFI library first
cargo build --release -p quicproquo-ffi
cargo build --release -p quicprochat-ffi
# Run the Python client
python examples/python/qpq_client.py \
python examples/python/qpc_client.py \
--server 127.0.0.1:7000 \
--ca-cert server-cert.der \
--username alice --password secret \
--receive --timeout 5000
```
Set `QPQ_FFI_LIB=/path/to/libquicproquo_ffi.so` to override automatic
Set `QPC_FFI_LIB=/path/to/libquicprochat_ffi.so` to override automatic
library discovery.

View File

@@ -1,6 +1,6 @@
# File Transfer
quicproquo supports encrypted file transfer with chunked upload/download,
quicprochat supports encrypted file transfer with chunked upload/download,
SHA-256 content addressing, and automatic MIME type detection. Files up to
50 MB are supported.
@@ -109,6 +109,6 @@ file extension. For example:
## Implementation
- **Server:** `crates/quicproquo-server/src/node_service/blob_ops.rs`
- **Client REPL:** `/send-file` and `/download` in `crates/quicproquo-client/src/client/repl.rs`
- **Message type:** `FileRef` variant in `crates/quicproquo-core/src/app_message.rs`
- **Server:** `crates/quicprochat-server/src/node_service/blob_ops.rs`
- **Client REPL:** `/send-file` and `/download` in `crates/quicprochat-client/src/client/repl.rs`
- **Message type:** `FileRef` variant in `crates/quicprochat-core/src/app_message.rs`

View File

@@ -1,18 +1,18 @@
# Go SDK
The Go SDK (`sdks/go/`) provides a native QUIC + Cap'n Proto client for
quicproquo, giving Go applications full access to the messaging API without
quicprochat, giving Go applications full access to the messaging API without
any HTTP translation layer.
## Prerequisites
- Go 1.21+
- A running qpq server
- A running qpc server
## Installation
```go
import "quicproquo.dev/sdk/go/qpq"
import "quicprochat.dev/sdk/go/qpc"
```
## Quick start
@@ -25,14 +25,14 @@ import (
"fmt"
"log"
"quicproquo.dev/sdk/go/qpq"
"quicprochat.dev/sdk/go/qpc"
)
func main() {
ctx := context.Background()
// Connect to the server
client, err := qpq.Connect(ctx, qpq.Options{
client, err := qpc.Connect(ctx, qpc.Options{
Addr: "127.0.0.1:7000",
InsecureSkipVerify: true, // development only
})
@@ -130,7 +130,7 @@ type Options struct {
sdks/go/
├── proto/ # Generated Cap'n Proto types from node.capnp
├── transport/ # QUIC transport layer (quic-go + TLS 1.3)
├── qpq/ # High-level client API (QpqClient)
├── qpc/ # High-level client API (QpqClient)
├── cmd/example/ # Example CLI program
├── go.mod
└── README.md

View File

@@ -1,6 +1,6 @@
# Mesh Networking
quicproquo includes a mesh networking layer for decentralised, peer-to-peer
quicprochat includes a mesh networking layer for decentralised, peer-to-peer
messaging without central infrastructure. It is designed for community
networks (Freifunk, BATMAN-adv, Babel routing) and offline-capable
environments.
@@ -8,17 +8,17 @@ environments.
Mesh features are **feature-gated** — build the client with:
```bash
cargo build -p quicproquo-client --features mesh
cargo build -p quicprochat-client --features mesh
```
## Architecture
```
Client A ── mDNS discovery ──► nearby qpq node (LAN / mesh)
Client A ── mDNS discovery ──► nearby qpc node (LAN / mesh)
Cap'n Proto federation
remote qpq node (across mesh)
remote qpc node (across mesh)
Client B ── iroh P2P ──────► Client C (direct, NAT-traversed)
```
@@ -44,7 +44,7 @@ persisted in a local JSON file.
## mDNS discovery
Servers announce `_quicproquo._udp.local.` via mDNS on startup with TXT
Servers announce `_quicprochat._udp.local.` via mDNS on startup with TXT
records:
```
@@ -126,14 +126,14 @@ Servers relay messages for recipients on remote nodes:
```bash
# Environment variables
QPQ_FEDERATION_LISTEN=0.0.0.0:7001
QPQ_LOCAL_DOMAIN=node1.mesh.local
QPQ_FEDERATION_CERT=/path/to/cert.der
QPQ_FEDERATION_KEY=/path/to/key.der
QPQ_FEDERATION_CA=/path/to/ca.der
QPC_FEDERATION_LISTEN=0.0.0.0:7001
QPC_LOCAL_DOMAIN=node1.mesh.local
QPC_FEDERATION_CERT=/path/to/cert.der
QPC_FEDERATION_KEY=/path/to/key.der
QPC_FEDERATION_CA=/path/to/ca.der
```
Or in `qpq-server.toml`:
Or in `qpc-server.toml`:
```toml
federation_enabled = true
@@ -146,8 +146,8 @@ federation_listen = "0.0.0.0:7001"
| Protocol | ALPN |
|---|---|
| Client ↔ Server | `b"capnp"` |
| P2P transport | `b"quicproquo/p2p/1"` |
| Federation | `b"quicproquo/federation/1"` |
| P2P transport | `b"quicprochat/p2p/1"` |
| Federation | `b"quicprochat/federation/1"` |
## REPL command summary
@@ -164,12 +164,12 @@ federation_listen = "0.0.0.0:7001"
## Implementation
- **P2P node:** `crates/quicproquo-p2p/src/lib.rs``P2pNode` with iroh
- **P2P node:** `crates/quicprochat-p2p/src/lib.rs``P2pNode` with iroh
transport
- **Mesh identity:** `crates/quicproquo-p2p/src/identity.rs`
- **Store-and-forward:** `crates/quicproquo-p2p/src/store.rs` +
- **Mesh identity:** `crates/quicprochat-p2p/src/identity.rs`
- **Store-and-forward:** `crates/quicprochat-p2p/src/store.rs` +
`envelope.rs`
- **Broadcast:** `crates/quicproquo-p2p/src/broadcast.rs`
- **mDNS discovery:** `crates/quicproquo-client/src/client/mesh_discovery.rs`
- **Federation routing:** `crates/quicproquo-server/src/node_service/delivery.rs`
- **REPL commands:** mesh handlers in `crates/quicproquo-client/src/client/repl.rs`
- **Broadcast:** `crates/quicprochat-p2p/src/broadcast.rs`
- **mDNS discovery:** `crates/quicprochat-client/src/client/mesh_discovery.rs`
- **Federation routing:** `crates/quicprochat-server/src/node_service/delivery.rs`
- **REPL commands:** mesh handlers in `crates/quicprochat-client/src/client/repl.rs`

View File

@@ -1,6 +1,6 @@
# Prerequisites
Before building quicproquo you need a Rust toolchain. No other system tools are required — Protobuf compilation is handled automatically at build time by the `protobuf-src` crate, which vendors the `protoc` compiler. Docker is optional and useful for reproducible builds and deployment.
Before building quicprochat you need a Rust toolchain. No other system tools are required — Protobuf compilation is handled automatically at build time by the `protobuf-src` crate, which vendors the `protoc` compiler. Docker is optional and useful for reproducible builds and deployment.
---
@@ -8,7 +8,7 @@ Before building quicproquo you need a Rust toolchain. No other system tools are
**Minimum supported Rust version: 1.77+ (stable)**
quicproquo uses the 2021 edition and workspace resolver v2. Any stable Rust release from 1.77 onward should work. Install or update via [rustup](https://rustup.rs/):
quicprochat uses the 2021 edition and workspace resolver v2. Any stable Rust release from 1.77 onward should work. Install or update via [rustup](https://rustup.rs/):
```bash
# Install rustup (if not already present)
@@ -29,7 +29,7 @@ The workspace depends on several crates that use procedural macros (`serde_deriv
## No external compiler dependencies
In v2, all wire-format serialisation uses [Protobuf](https://protobuf.dev/) via the `prost` crate. The `quicproquo-proto` crate's `build.rs` script drives code generation through `prost-build`, which in turn uses the `protobuf-src` crate to compile and use a vendored copy of `protoc`. **You do not need to install `protoc` or any other system compiler.**
In v2, all wire-format serialisation uses [Protobuf](https://protobuf.dev/) via the `prost` crate. The `quicprochat-proto` crate's `build.rs` script drives code generation through `prost-build`, which in turn uses the `protobuf-src` crate to compile and use a vendored copy of `protoc`. **You do not need to install `protoc` or any other system compiler.**
The legacy Cap'n Proto schemas (`schemas/`) are still present for reference, but the v2 runtime and RPC framework use Protobuf exclusively.
@@ -37,7 +37,7 @@ The legacy Cap'n Proto schemas (`schemas/`) are still present for reference, but
## Optional: Docker and Docker Compose
If you prefer to build and run quicproquo in containers, you will need:
If you prefer to build and run quicprochat in containers, you will need:
- **Docker Engine** 20.10+ (or Docker Desktop)
- **Docker Compose** v2+ (the `docker compose` plugin, not the legacy `docker-compose` binary)

View File

@@ -1,11 +1,11 @@
# REPL Command Reference
The qpq interactive REPL provides 40+ slash commands for messaging, group
The qpc interactive REPL provides 40+ slash commands for messaging, group
management, file transfer, privacy controls, and mesh networking. Launch it
with:
```bash
cargo run --bin qpq -- repl --username alice --password mypass
cargo run --bin qpc -- repl --username alice --password mypass
```
Type any text without a leading `/` to send a message in the active
@@ -79,12 +79,12 @@ conversation.
These commands require the client to be built with mesh support:
```bash
cargo build -p quicproquo-client --features mesh
cargo build -p quicprochat-client --features mesh
```
| Command | Description |
|---|---|
| `/mesh peers` | Scan for nearby qpq nodes via mDNS (`_quicproquo._udp.local.`) |
| `/mesh peers` | Scan for nearby qpc nodes via mDNS (`_quicprochat._udp.local.`) |
| `/mesh server <host:port>` | Note a discovered server address for connection |
| `/mesh send <peer_id> <msg>` | Send a direct P2P message via iroh transport |
| `/mesh broadcast <topic> <msg>` | Publish a message to a broadcast channel |

View File

@@ -1,6 +1,6 @@
# Rich Messaging
quicproquo supports rich messaging features beyond basic text: reactions, read
quicprochat supports rich messaging features beyond basic text: reactions, read
receipts, typing indicators, message editing, and message deletion. All
message types are end-to-end encrypted inside MLS ciphertext — the server
only sees opaque bytes.
@@ -86,9 +86,9 @@ All rich message types use the same binary envelope inside the MLS ciphertext:
## Implementation
- **Core serialisation:** `crates/quicproquo-core/src/app_message.rs` — the
- **Core serialisation:** `crates/quicprochat-core/src/app_message.rs` — the
`AppMessage` enum with `serialize()` / `deserialize()` methods
- **REPL commands:** `crates/quicproquo-client/src/client/repl.rs` — slash
- **REPL commands:** `crates/quicprochat-client/src/client/repl.rs` — slash
command handlers
- **Display:** `crates/quicproquo-client/src/client/display.rs` — typing
- **Display:** `crates/quicprochat-client/src/client/display.rs` — typing
indicator rendering

View File

@@ -1,6 +1,6 @@
# Running the Client
The quicproquo CLI client provides subcommands for connectivity testing, identity registration, KeyPackage exchange, and persistent group messaging. All commands connect to the server over QUIC + TLS 1.3 and issue Cap'n Proto RPC calls against the `NodeService` endpoint.
The quicprochat CLI client provides subcommands for connectivity testing, identity registration, KeyPackage exchange, and persistent group messaging. All commands connect to the server over QUIC + TLS 1.3 and issue Cap'n Proto RPC calls against the `NodeService` endpoint.
---
@@ -10,8 +10,8 @@ These flags apply to every subcommand:
| Flag | Env var | Default | Purpose |
|---|---|---|---|
| `--ca-cert` | `QPQ_CA_CERT` | `data/server-cert.der` | Path to the server's TLS certificate (DER format). The client uses this to verify the server's identity during the TLS handshake. |
| `--server-name` | `QPQ_SERVER_NAME` | `localhost` | Expected TLS server name. Must match a SAN in the server's certificate. |
| `--ca-cert` | `QPC_CA_CERT` | `data/server-cert.der` | Path to the server's TLS certificate (DER format). The client uses this to verify the server's identity during the TLS handshake. |
| `--server-name` | `QPC_SERVER_NAME` | `localhost` | Expected TLS server name. Must match a SAN in the server's certificate. |
Most subcommands also accept `--server` (default `127.0.0.1:7000`) to specify the server address.
@@ -24,11 +24,11 @@ Most subcommands also accept `--server` (default `127.0.0.1:7000`) to specify th
Send a health probe to the server and print the round-trip time.
```bash
cargo run -p quicproquo-client -- ping
cargo run -p quicprochat-client -- ping
```
```bash
cargo run -p quicproquo-client -- ping --server 192.168.1.10:7000
cargo run -p quicprochat-client -- ping --server 192.168.1.10:7000
```
**Output:**
@@ -49,7 +49,7 @@ These commands generate a fresh identity keypair in memory each time they run. T
Generate a fresh Ed25519 identity, create an MLS KeyPackage, and upload it to the Authentication Service.
```bash
cargo run -p quicproquo-client -- register
cargo run -p quicprochat-client -- register
```
**Output:**
@@ -66,7 +66,7 @@ Share the `identity_key` value with peers who want to add you to a group. They w
Fetch a peer's KeyPackage from the Authentication Service by their Ed25519 public key.
```bash
cargo run -p quicproquo-client -- fetch-key a1b2c3d4e5f6...
cargo run -p quicprochat-client -- fetch-key a1b2c3d4e5f6...
```
The `identity_key` argument must be exactly 64 lowercase hex characters (32 bytes).
@@ -90,7 +90,7 @@ KeyPackages are single-use: fetching a KeyPackage atomically removes it from the
Run a complete Alice-and-Bob MLS round-trip against a live server. Both identities are created in-process; both communicate through the server's AS and DS.
```bash
cargo run -p quicproquo-client -- demo-group --server 127.0.0.1:7000
cargo run -p quicprochat-client -- demo-group --server 127.0.0.1:7000
```
**Output:**
@@ -106,21 +106,21 @@ This is the fastest way to verify that the entire stack (QUIC + TLS + Cap'n Prot
## Persistent group commands
These commands use a state file (`--state`, default `qpq-state.bin`) to persist the Ed25519 identity seed and MLS group state between invocations. A companion key store file (same path with `.ks` extension) holds HPKE init private keys.
These commands use a state file (`--state`, default `qpc-state.bin`) to persist the Ed25519 identity seed and MLS group state between invocations. A companion key store file (same path with `.ks` extension) holds HPKE init private keys.
All persistent commands share the `--state` flag:
| Flag | Env var | Default |
|---|---|---|
| `--state` | `QPQ_STATE` | `qpq-state.bin` |
| `--server` | `QPQ_SERVER` | `127.0.0.1:7000` |
| `--state` | `QPC_STATE` | `qpc-state.bin` |
| `--server` | `QPC_SERVER` | `127.0.0.1:7000` |
### `register-state`
Create or load a persistent identity, generate a KeyPackage, and upload it to the AS.
```bash
cargo run -p quicproquo-client -- register-state \
cargo run -p quicprochat-client -- register-state \
--state alice.bin \
--server 127.0.0.1:7000
```
@@ -141,10 +141,10 @@ Refresh the KeyPackage on the server using your **existing** state file. Does no
- Your KeyPackage has expired (server TTL, e.g. 24h).
- Your KeyPackage was consumed (someone invited you) and you want to be invitable again.
Run with the same `--access-token` (or `QPQ_ACCESS_TOKEN`) as for other commands.
Run with the same `--access-token` (or `QPC_ACCESS_TOKEN`) as for other commands.
```bash
cargo run -p quicproquo-client -- refresh-keypackage \
cargo run -p quicprochat-client -- refresh-keypackage \
--state alice.bin \
--server 127.0.0.1:7000
```
@@ -163,7 +163,7 @@ If you are told "no key" when someone tries to invite you, have them wait and ru
Create a new MLS group. The caller becomes the sole member at epoch 0.
```bash
cargo run -p quicproquo-client -- create-group \
cargo run -p quicprochat-client -- create-group \
--state alice.bin \
--group-id "project-chat"
```
@@ -180,7 +180,7 @@ The group state is saved to the state file. You can now invite peers with `invit
Fetch a peer's KeyPackage from the AS, add them to the group, and deliver the Welcome message via the DS.
```bash
cargo run -p quicproquo-client -- invite \
cargo run -p quicprochat-client -- invite \
--state alice.bin \
--peer-key b9a8c7d6e5f4... \
--server 127.0.0.1:7000
@@ -202,7 +202,7 @@ invited peer (welcome queued)
Join a group by consuming a Welcome message from the DS.
```bash
cargo run -p quicproquo-client -- join \
cargo run -p quicprochat-client -- join \
--state bob.bin \
--server 127.0.0.1:7000
```
@@ -219,7 +219,7 @@ joined group successfully
Encrypt and send an application message to a peer via the DS.
```bash
cargo run -p quicproquo-client -- send \
cargo run -p quicprochat-client -- send \
--state alice.bin \
--peer-key b9a8c7d6e5f4... \
--msg "hello from alice" \
@@ -238,7 +238,7 @@ message sent
Receive and decrypt all pending messages from the DS.
```bash
cargo run -p quicproquo-client -- recv \
cargo run -p quicprochat-client -- recv \
--state bob.bin \
--server 127.0.0.1:7000
```
@@ -257,12 +257,12 @@ Additional flags:
```bash
# Wait up to 5 seconds for messages
cargo run -p quicproquo-client -- recv \
cargo run -p quicprochat-client -- recv \
--state bob.bin \
--wait-ms 5000
# Stream messages continuously
cargo run -p quicproquo-client -- recv \
cargo run -p quicprochat-client -- recv \
--state bob.bin \
--stream --wait-ms 10000
```
@@ -271,7 +271,7 @@ cargo run -p quicproquo-client -- recv \
## HPKE init key lifecycle warning
The MLS protocol requires that the HPKE init private key generated during KeyPackage creation is available when processing the corresponding Welcome message. In quicproquo, this private key is stored in the key store file (`.ks` extension alongside the state file).
The MLS protocol requires that the HPKE init private key generated during KeyPackage creation is available when processing the corresponding Welcome message. In quicprochat, this private key is stored in the key store file (`.ks` extension alongside the state file).
**The same state file and key store must be used for both `register-state` and `join`.** If you:

View File

@@ -1,13 +1,13 @@
# Running the Server
The quicproquo server is a single binary (`qpq-server`) that exposes a unified **NodeService** endpoint combining Authentication Service (OPAQUE registration/login, KeyPackage management) and Delivery Service (message relay) operations over a single QUIC + TLS 1.3 connection.
The quicprochat server is a single binary (`qpc-server`) that exposes a unified **NodeService** endpoint combining Authentication Service (OPAQUE registration/login, KeyPackage management) and Delivery Service (message relay) operations over a single QUIC + TLS 1.3 connection.
---
## Quick start
```bash
cargo run -p quicproquo-server -- --allow-insecure-auth
cargo run -p quicprochat-server -- --allow-insecure-auth
```
On first launch the server will:
@@ -21,8 +21,8 @@ On first launch the server will:
You should see output similar to:
```
2026-01-01T00:00:00.000000Z INFO qpq_server: generated self-signed TLS certificate cert="data/server-cert.der" key="data/server-key.der"
2026-01-01T00:00:00.000000Z INFO qpq_server: accepting QUIC connections addr="0.0.0.0:7000"
2026-01-01T00:00:00.000000Z INFO qpc_server: generated self-signed TLS certificate cert="data/server-cert.der" key="data/server-key.der"
2026-01-01T00:00:00.000000Z INFO qpc_server: accepting QUIC connections addr="0.0.0.0:7000"
```
> **Development note:** `--allow-insecure-auth` bypasses the requirement for a static bearer token. Do not use this flag in production.
@@ -31,108 +31,108 @@ You should see output similar to:
## Configuration
All configuration is available via CLI flags, environment variables, or a TOML config file (`qpq-server.toml` by default, overridden with `--config`). CLI flags take precedence over the config file.
All configuration is available via CLI flags, environment variables, or a TOML config file (`qpc-server.toml` by default, overridden with `--config`). CLI flags take precedence over the config file.
### Core flags
| Purpose | CLI flag | Env var | Default |
|---|---|---|---|
| QUIC listen address | `--listen` | `QPQ_LISTEN` | `0.0.0.0:7000` |
| TLS certificate (DER) | `--tls-cert` | `QPQ_TLS_CERT` | `data/server-cert.der` |
| TLS private key (DER) | `--tls-key` | `QPQ_TLS_KEY` | `data/server-key.der` |
| Data directory | `--data-dir` | `QPQ_DATA_DIR` | `data` |
| TOML config file | `--config` | `QPQ_CONFIG` | `qpq-server.toml` |
| QUIC listen address | `--listen` | `QPC_LISTEN` | `0.0.0.0:7000` |
| TLS certificate (DER) | `--tls-cert` | `QPC_TLS_CERT` | `data/server-cert.der` |
| TLS private key (DER) | `--tls-key` | `QPC_TLS_KEY` | `data/server-key.der` |
| Data directory | `--data-dir` | `QPC_DATA_DIR` | `data` |
| TOML config file | `--config` | `QPC_CONFIG` | `qpc-server.toml` |
| Log level | -- | `RUST_LOG` | `info` |
### Authentication flags
| Purpose | CLI flag | Env var | Default |
|---|---|---|---|
| Static bearer token | `--auth-token` | `QPQ_AUTH_TOKEN` | (none) |
| Skip token requirement (dev only) | `--allow-insecure-auth` | `QPQ_ALLOW_INSECURE_AUTH` | `false` |
| Sealed sender mode | `--sealed-sender` | `QPQ_SEALED_SENDER` | `false` |
| Static bearer token | `--auth-token` | `QPC_AUTH_TOKEN` | (none) |
| Skip token requirement (dev only) | `--allow-insecure-auth` | `QPC_ALLOW_INSECURE_AUTH` | `false` |
| Sealed sender mode | `--sealed-sender` | `QPC_SEALED_SENDER` | `false` |
### Storage flags
| Purpose | CLI flag | Env var | Default |
|---|---|---|---|
| Storage backend | `--store-backend` | `QPQ_STORE_BACKEND` | `file` |
| SQLCipher DB path | `--db-path` | `QPQ_DB_PATH` | `data/qpq.db` |
| SQLCipher encryption key | `--db-key` | `QPQ_DB_KEY` | (empty = plaintext) |
| Storage backend | `--store-backend` | `QPC_STORE_BACKEND` | `file` |
| SQLCipher DB path | `--db-path` | `QPC_DB_PATH` | `data/qpc.db` |
| SQLCipher encryption key | `--db-key` | `QPC_DB_KEY` | (empty = plaintext) |
### Transport and timeout flags
| Purpose | CLI flag | Env var | Default |
|---|---|---|---|
| Drain timeout (graceful shutdown) | `--drain-timeout` | `QPQ_DRAIN_TIMEOUT` | `30` s |
| Per-RPC timeout | `--rpc-timeout` | `QPQ_RPC_TIMEOUT` | `30` s |
| Storage operation timeout | `--storage-timeout` | `QPQ_STORAGE_TIMEOUT` | `10` s |
| Drain timeout (graceful shutdown) | `--drain-timeout` | `QPC_DRAIN_TIMEOUT` | `30` s |
| Per-RPC timeout | `--rpc-timeout` | `QPC_RPC_TIMEOUT` | `30` s |
| Storage operation timeout | `--storage-timeout` | `QPC_STORAGE_TIMEOUT` | `10` s |
### Extension flags
| Purpose | CLI flag | Env var | Default |
|---|---|---|---|
| Plugin directory | `--plugin-dir` | `QPQ_PLUGIN_DIR` | (none) |
| WebSocket bridge address | `--ws-listen` | `QPQ_WS_LISTEN` | (none) |
| WebTransport address | `--webtransport-listen` | `QPQ_WEBTRANSPORT_LISTEN` | (none) |
| Federation | `--federation-enabled` | `QPQ_FEDERATION_ENABLED` | `false` |
| Federation domain | `--federation-domain` | `QPQ_FEDERATION_DOMAIN` | (none) |
| Federation listen address | `--federation-listen` | `QPQ_FEDERATION_LISTEN` | `0.0.0.0:7001` |
| Redact audit logs | `--redact-logs` | `QPQ_REDACT_LOGS` | `false` |
| Metrics listen address | `--metrics-listen` | `QPQ_METRICS_LISTEN` | (none) |
| Plugin directory | `--plugin-dir` | `QPC_PLUGIN_DIR` | (none) |
| WebSocket bridge address | `--ws-listen` | `QPC_WS_LISTEN` | (none) |
| WebTransport address | `--webtransport-listen` | `QPC_WEBTRANSPORT_LISTEN` | (none) |
| Federation | `--federation-enabled` | `QPC_FEDERATION_ENABLED` | `false` |
| Federation domain | `--federation-domain` | `QPC_FEDERATION_DOMAIN` | (none) |
| Federation listen address | `--federation-listen` | `QPC_FEDERATION_LISTEN` | `0.0.0.0:7001` |
| Redact audit logs | `--redact-logs` | `QPC_REDACT_LOGS` | `false` |
| Metrics listen address | `--metrics-listen` | `QPC_METRICS_LISTEN` | (none) |
### Examples
```bash
# Development: no auth token required
cargo run -p quicproquo-server -- --allow-insecure-auth
cargo run -p quicprochat-server -- --allow-insecure-auth
# Listen on a custom port
cargo run -p quicproquo-server -- --allow-insecure-auth --listen 0.0.0.0:5001
cargo run -p quicprochat-server -- --allow-insecure-auth --listen 0.0.0.0:5001
# Use SQLCipher storage backend
cargo run -p quicproquo-server -- \
cargo run -p quicprochat-server -- \
--allow-insecure-auth \
--store-backend sql \
--db-path data/qpq.db \
--db-path data/qpc.db \
--db-key mysecretkey
# Load server plugins from a directory
cargo run -p quicproquo-server -- \
cargo run -p quicprochat-server -- \
--allow-insecure-auth \
--plugin-dir /path/to/plugins
# Enable WebSocket bridge for browser clients
cargo run -p quicproquo-server -- \
cargo run -p quicprochat-server -- \
--allow-insecure-auth \
--ws-listen 0.0.0.0:9000
# Via environment variables
QPQ_LISTEN=0.0.0.0:5001 \
QPQ_ALLOW_INSECURE_AUTH=true \
QPC_LISTEN=0.0.0.0:5001 \
QPC_ALLOW_INSECURE_AUTH=true \
RUST_LOG=debug \
cargo run -p quicproquo-server
cargo run -p quicprochat-server
```
---
## Production deployment
Set `QPQ_PRODUCTION=true` to enable production validation. The server enforces:
Set `QPC_PRODUCTION=true` to enable production validation. The server enforces:
- `--allow-insecure-auth` is **prohibited**.
- `QPQ_AUTH_TOKEN` must be set, non-empty, at least 16 characters, and not equal to `devtoken`.
- `QPC_AUTH_TOKEN` must be set, non-empty, at least 16 characters, and not equal to `devtoken`.
- TLS cert and key files must already exist (auto-generation is disabled).
- When `--store-backend=sql`, `QPQ_DB_KEY` must be non-empty.
- When `--store-backend=sql`, `QPC_DB_KEY` must be non-empty.
```bash
QPQ_PRODUCTION=true \
QPQ_AUTH_TOKEN=<strong-token> \
QPQ_TLS_CERT=/etc/quicproquo/cert.der \
QPQ_TLS_KEY=/etc/quicproquo/key.der \
QPQ_STORE_BACKEND=sql \
QPQ_DB_KEY=<strong-db-key> \
qpq-server
QPC_PRODUCTION=true \
QPC_AUTH_TOKEN=<strong-token> \
QPC_TLS_CERT=/etc/quicprochat/cert.der \
QPC_TLS_KEY=/etc/quicprochat/key.der \
QPC_STORE_BACKEND=sql \
QPC_DB_KEY=<strong-db-key> \
qpc-server
```
---
@@ -160,7 +160,7 @@ To use a certificate issued by a CA or a custom self-signed certificate:
```
2. Point the server at them:
```bash
cargo run -p quicproquo-server -- \
cargo run -p quicprochat-server -- \
--allow-insecure-auth \
--tls-cert cert.der \
--tls-key key.der
@@ -171,7 +171,7 @@ To use a certificate issued by a CA or a custom self-signed certificate:
- **Protocol versions**: TLS 1.3 only. TLS 1.2 and below are rejected.
- **Client authentication**: Disabled. Client identity is established at the MLS/OPAQUE layer, not at the TLS layer.
- **ALPN**: The server advertises `b"qpq/1"` as the application-layer protocol.
- **ALPN**: The server advertises `b"qpc/1"` as the application-layer protocol.
---
@@ -201,13 +201,13 @@ The server uses `tracing` with `tracing-subscriber` and respects the `RUST_LOG`
```bash
# Default: info level
RUST_LOG=info cargo run -p quicproquo-server -- --allow-insecure-auth
RUST_LOG=info cargo run -p quicprochat-server -- --allow-insecure-auth
# Debug level for detailed RPC tracing
RUST_LOG=debug cargo run -p quicproquo-server -- --allow-insecure-auth
RUST_LOG=debug cargo run -p quicprochat-server -- --allow-insecure-auth
# Filter to specific crates
RUST_LOG=quicproquo_server=debug,quinn=warn cargo run -p quicproquo-server -- --allow-insecure-auth
RUST_LOG=quicprochat_server=debug,quinn=warn cargo run -p quicprochat-server -- --allow-insecure-auth
```
---

View File

@@ -1,10 +1,10 @@
# TLS in quicproquo
# TLS in quicprochat
quicproquo uses QUIC (RFC 9000) for all client-server communication. QUIC mandates TLS 1.3, so every connection is encrypted and authenticated at the transport layer — there is no plaintext mode.
quicprochat uses QUIC (RFC 9000) for all client-server communication. QUIC mandates TLS 1.3, so every connection is encrypted and authenticated at the transport layer — there is no plaintext mode.
## How it works
The server holds a TLS certificate and private key (DER format). On startup it either loads existing files or, in development mode, generates a self-signed certificate automatically. The client authenticates the server by verifying its certificate against a trusted root provided via `--ca-cert` (or `QPQ_CA_CERT`).
The server holds a TLS certificate and private key (DER format). On startup it either loads existing files or, in development mode, generates a self-signed certificate automatically. The client authenticates the server by verifying its certificate against a trusted root provided via `--ca-cert` (or `QPC_CA_CERT`).
The TLS handshake negotiates the ALPN protocol `capnp`, after which the QUIC bi-directional stream carries Cap'n Proto RPC traffic.
@@ -13,29 +13,29 @@ The TLS handshake negotiates the ALPN protocol `capnp`, after which the QUIC bi-
By default the client trusts exactly the certificate (or CA) in the file given by `--ca-cert`:
```bash
qpq --ca-cert data/server-cert.der --server-name localhost health --server 127.0.0.1:7000
qpc --ca-cert data/server-cert.der --server-name localhost health --server 127.0.0.1:7000
```
This is a form of **certificate pinning**: the client will only connect to a server whose certificate chains to the provided root. For single-server deployments, pass the server's own self-signed certificate. For CA-issued certificates, pass the CA's root certificate instead.
| Flag / Env var | Purpose |
|---|---|
| `--ca-cert` / `QPQ_CA_CERT` | Path to trusted root certificate (DER) |
| `--server-name` / `QPQ_SERVER_NAME` | Expected TLS server name (must match certificate SAN) |
| `--ca-cert` / `QPC_CA_CERT` | Path to trusted root certificate (DER) |
| `--server-name` / `QPC_SERVER_NAME` | Expected TLS server name (must match certificate SAN) |
## The `--danger-accept-invalid-certs` flag
For local development and testing you can skip certificate verification entirely:
```bash
qpq --danger-accept-invalid-certs health --server 127.0.0.1:7000
qpc --danger-accept-invalid-certs health --server 127.0.0.1:7000
```
Or via the environment:
```bash
export QPQ_DANGER_ACCEPT_INVALID_CERTS=true
qpq health --server 127.0.0.1:7000
export QPC_DANGER_ACCEPT_INVALID_CERTS=true
qpc health --server 127.0.0.1:7000
```
When active, the client prints a warning to stderr:
@@ -50,7 +50,7 @@ WARNING: TLS verification disabled — insecure mode
### Using rcgen (Rust)
The server generates a self-signed certificate automatically when the cert/key files are missing (unless `QPQ_PRODUCTION=1` is set). The generated files are written to:
The server generates a self-signed certificate automatically when the cert/key files are missing (unless `QPC_PRODUCTION=1` is set). The generated files are written to:
- `data/server-cert.der` — DER-encoded certificate
- `data/server-key.der` — DER-encoded PKCS#8 private key
@@ -66,7 +66,7 @@ openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 \
-subj "/CN=localhost" \
-addext "subjectAltName=DNS:localhost,IP:127.0.0.1"
# Convert to DER format (required by quicproquo)
# Convert to DER format (required by quicprochat)
openssl x509 -in cert.pem -outform DER -out data/server-cert.der
openssl pkcs8 -topk8 -inform PEM -outform DER -in key.pem -out data/server-key.der -nocrypt
```
@@ -74,15 +74,15 @@ openssl pkcs8 -topk8 -inform PEM -outform DER -in key.pem -out data/server-key.d
Point the server at the DER files:
```bash
export QPQ_TLS_CERT=data/server-cert.der
export QPQ_TLS_KEY=data/server-key.der
cargo run -p quicproquo-server
export QPC_TLS_CERT=data/server-cert.der
export QPC_TLS_KEY=data/server-key.der
cargo run -p quicprochat-server
```
And the client at the certificate:
```bash
qpq --ca-cert data/server-cert.der --server-name localhost repl
qpc --ca-cert data/server-cert.der --server-name localhost repl
```
## CA-issued certificates
@@ -94,7 +94,7 @@ For production deployments with a public CA (e.g. Let's Encrypt):
3. Configure the client to trust the CA root rather than the server certificate directly:
```bash
qpq --ca-cert /etc/ssl/certs/isrg-root-x1.der --server-name chat.example.com repl
qpc --ca-cert /etc/ssl/certs/isrg-root-x1.der --server-name chat.example.com repl
```
See [Certificate Lifecycle and CA-Signed TLS](certificate-lifecycle.md) for rotation, OCSP, and operational details.

View File

@@ -1,6 +1,6 @@
# TypeScript SDK and Browser Demo
The TypeScript SDK (`sdks/typescript/`) provides `@quicproquo/client` — a
The TypeScript SDK (`sdks/typescript/`) provides `@quicprochat/client` — a
browser-ready client with WASM-powered crypto operations and WebSocket
transport.
@@ -8,7 +8,7 @@ transport.
- **WASM crypto bundle** (175 KB) — Ed25519 signatures, X25519 + ML-KEM-768
hybrid encryption, safety numbers, sealed sender, and message padding,
compiled from the Rust `quicproquo-core` crate
compiled from the Rust `quicprochat-core` crate
- **`QpqClient` class** — high-level API for server connectivity and crypto
- **Offline mode** — all crypto operations work without a server connection
- **Browser demo** — interactive HTML page for trying every crypto operation
@@ -33,7 +33,7 @@ cd sdks/typescript/wasm-crypto
wasm-pack build --target web --out-dir ../pkg
```
This compiles `quicproquo-core`'s crypto modules to WebAssembly and produces
This compiles `quicprochat-core`'s crypto modules to WebAssembly and produces
JavaScript + TypeScript bindings in `sdks/typescript/pkg/`.
### 2. Build the TypeScript SDK
@@ -75,7 +75,7 @@ The crypto operations work entirely offline — no server connection needed.
### Server connectivity
The Chat section of the demo connects via WebSocket. Since the native qpq
The Chat section of the demo connects via WebSocket. Since the native qpc
server speaks Cap'n Proto RPC over QUIC/TCP + Noise_XX, a WebSocket bridge
proxy is required for browser connectivity. The demo sends JSON-framed
requests over WebSocket.
@@ -85,7 +85,7 @@ requests over WebSocket.
### Offline crypto (no server)
```typescript
import { QpqClient } from "@quicproquo/client";
import { QpqClient } from "@quicprochat/client";
const client = await QpqClient.offline();

View File

@@ -1,6 +1,6 @@
# WASM Integration
The `quicproquo-core` crate supports compilation to `wasm32-unknown-unknown`
The `quicprochat-core` crate supports compilation to `wasm32-unknown-unknown`
when the `native` feature is disabled. This exposes the pure-crypto subset of
the library for use in browsers or other WASM runtimes.
@@ -9,7 +9,7 @@ the library for use in browsers or other WASM runtimes.
```bash
rustup target add wasm32-unknown-unknown
cargo build -p quicproquo-core \
cargo build -p quicprochat-core \
--target wasm32-unknown-unknown \
--no-default-features
```
@@ -43,13 +43,13 @@ The following require the `native` feature and will not compile to WASM:
- `keystore` -- OpenMLS key store with disk persistence
- `opaque_auth` -- OPAQUE cipher suite configuration
Networking (`quicproquo-client`, `quicproquo-server`) is not available in WASM.
Networking (`quicprochat-client`, `quicprochat-server`) is not available in WASM.
## Random number generation
On `wasm32`, the `getrandom` crate is configured with the `js` feature to
use the browser's `crypto.getRandomValues()` API. This is set automatically
in `quicproquo-core/Cargo.toml`:
in `quicprochat-core/Cargo.toml`:
```toml
[target.'cfg(target_arch = "wasm32")'.dependencies]
@@ -71,7 +71,7 @@ cd sdks/typescript/wasm-crypto
wasm-pack build --target web --out-dir ../pkg
```
The resulting 175 KB WASM bundle is used by the `@quicproquo/client`
The resulting 175 KB WASM bundle is used by the `@quicprochat/client`
TypeScript SDK and the interactive browser demo.
See the [TypeScript SDK and Browser Demo](typescript-sdk.md) guide for