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:
@@ -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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -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 CA’s 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 certificate’s 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.
|
||||
- **Let’s 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 | Server’s cert file |
|
||||
| CA-issued | Let’s 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 server’s cert or (b) a CA-issued server cert with clients trusting the CA, and plan for rotation and restart (or future reload support).
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user