docs: comprehensive ARCHITECTURE, DEPLOYMENT, API, and THREAT_MODEL

ARCHITECTURE.md
- Full component map with ASCII diagram
- Complete session lifecycle (init + heartbeat + failure path)
- Cryptographic protocol spec (hash chain formula, canonical JSON)
- Stack machine instruction set table with stack effects
- Behavioral validation thresholds
- SQLite schema, threat model summary, module reference

DEPLOYMENT.md
- Build instructions (WASM + server + convenience script)
- native binary, systemd (with hardened sandbox notes), Docker
- nginx, Nginx Proxy Manager, and HAProxy reverse proxy configs
- Integration options (sidecar vs proxy-only)
- Full configuration table with all constants
- Observability (RUST_LOG levels), health check, security checklist

API.md
- Full /init and /hb request/response schemas with field tables
- Canonical signing payload specification
- Complete validation rules table (all 13 rejection conditions)
- Hash chain byte-level specification
- WASM exported function reference

THREAT_MODEL.md
- Four attacker profiles (script kiddie → sophisticated adversary)
- Eight attack vectors with mitigations (replay, forgery, hijack, DoS…)
- Explicit out-of-scope limitations
- Operational security notes (CORS, TLS, log level, SQLite)
This commit is contained in:
thakares committed 2026-05-09 18:04:13 +05:30
1 parent 851d3b4876
commit 4b27a342d1
4 files changed
+1017 -256

No files matched your search

+326 -16
View File
@@ -1,36 +1,346 @@
# Deployment
# ChronoSeal — Deployment Guide
## Native
## Prerequisites
| Tool | Minimum version | Purpose |
|---|---|---|
| Rust | 1.87 stable | Server + WASM compilation |
| wasm-pack | 0.13 | WASM build and packaging |
| Docker + Compose | 24 / 2.x | Container deployment |
| nginx / NPM / HAProxy | any | TLS termination, reverse proxy |
Install Rust: https://rustup.rs
Install wasm-pack: `cargo install wasm-pack`
---
## Build
### 1. Build the WASM module
```bash
wasm-pack build wasm --target web --release
mv wasm/pkg frontend/pkg
```
This produces `frontend/pkg/antibot_wasm.js` and `frontend/pkg/antibot_wasm_bg.wasm`,
which are loaded by `frontend/main.js` at runtime.
### 2. Build the server
```bash
cargo build -p server --release
```
Binary output: `target/release/server`
### 3. Build both (convenience script)
```bash
bash scripts/build.sh
```
---
## Running
### Development
```bash
bash scripts/dev.sh
```
Runs the server with `cargo run --release`. The server serves the `frontend/`
directory statically at `/` via tower-http `ServeDir`.
Open `http://localhost:3000` in a browser. Open DevTools console — heartbeats
should appear every 12–25 seconds. No visible UI is rendered; the protection
is entirely silent.
### Production (native binary)
```bash
cargo build -p server --release
sudo cp target/release/server /usr/local/bin/chronoseal
```
## systemd
Set environment variables before running:
```bash
sudo cp chronoseal.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable chronoseal
sudo systemctl start chronoseal
export RUST_LOG=info # or warn for quieter output
chronoseal
```
The server binds to `0.0.0.0:3000` by default. Place behind a reverse proxy
for TLS — do not expose port 3000 directly.
---
## systemd
### Service file
The provided `chronoseal.service` includes hardened systemd sandboxing:
```
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
MemoryDenyWriteExecute=true
RestrictRealtime=true
RestrictSUIDSGID=true
LockPersonality=true
SystemCallArchitectures=native
```
### Install
```bash
# Create a dedicated system user
sudo useradd --system --no-create-home --shell /usr/sbin/nologin chronoseal
# Install binary and frontend
sudo cp target/release/server /usr/local/bin/chronoseal
sudo mkdir -p /opt/chronoseal/frontend
sudo cp -r frontend/ /opt/chronoseal/frontend/
sudo chown -R chronoseal:chronoseal /opt/chronoseal
# Install and enable service
sudo cp chronoseal.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now chronoseal
```
### Verify
```bash
sudo systemctl status chronoseal
journalctl -u chronoseal -f
```
---
## Docker
### Build and run
```bash
docker compose up -d --build
```
### docker-compose.yml overview
```yaml
services:
chronoseal:
build: .
restart: unless-stopped
ports:
- "3000:3000"
environment:
RUST_LOG: info
tmpfs:
- /tmp
```
The `tmpfs` mount ensures the in-memory SQLite database is never written to
disk, even if Docker's storage driver were to flush the container filesystem.
### Dockerfile stages
The Dockerfile uses a two-stage build:
1. `rust:1.87-bookworm` — compiles the server binary
2. `debian:bookworm-slim` — minimal runtime image with only `ca-certificates`
The WASM module and frontend must be built separately (wasm-pack requires a
browser toolchain not present in the server image) and mounted or copied into
the container at `/opt/chronoseal/frontend/`.
```bash
# Build WASM first
wasm-pack build wasm --target web --release
mv wasm/pkg frontend/pkg
# Then build and run the container
docker compose up -d --build
```
Or mount the pre-built frontend as a volume:
```yaml
volumes:
- ./frontend:/opt/chronoseal/frontend:ro
```
---
## Reverse Proxy
Recommended:
- nginx
- Nginx Proxy Manager
- HAProxy
ChronoSeal must be served over HTTPS. The heartbeat payload contains a
timestamp; if traffic is observable in plaintext, timing attacks become
easier. TLS 1.3 is strongly recommended.
Enable:
- HTTP/2
- TLS 1.3
- aggressive timeout policies
### nginx
```nginx
server {
listen 443 ssl http2;
server_name your.domain.com;
ssl_certificate /etc/letsencrypt/live/your.domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your.domain.com/privkey.pem;
ssl_protocols TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
# Tight timeouts — heartbeat interval is 12–25s
proxy_read_timeout 35s;
proxy_send_timeout 10s;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80;
server_name your.domain.com;
return 301 https://$host$request_uri;
}
```
### Nginx Proxy Manager
1. Add a new Proxy Host pointing to `http://chronoseal:3000`
2. Enable SSL, Request Let's Encrypt certificate
3. Enable HTTP/2, Force SSL
4. Under Advanced, add:
```
proxy_read_timeout 35s;
proxy_send_timeout 10s;
```
### HAProxy
```haproxy
frontend https_front
bind *:443 ssl crt /etc/haproxy/certs/your.domain.pem alpn h2,http/1.1
default_backend chronoseal_back
backend chronoseal_back
server chronoseal 127.0.0.1:3000 check
timeout connect 5s
timeout server 35s
```
---
## Integration into an Existing Site
ChronoSeal is designed to run as a sidecar — its `/init` and `/hb` endpoints
can be proxied from any existing web server. The frontend assets (`pkg/`) need
to be served from the same origin as the protected page (or CORS must be
configured).
### Option A — Serve everything from ChronoSeal
ChronoSeal serves `frontend/` statically. Put your protected HTML inside
`frontend/` and let ChronoSeal serve it directly.
### Option B — Proxy only the API endpoints
Keep your existing server. Proxy `/init` and `/hb` to ChronoSeal, and serve
the WASM and JS assets from your CDN or existing static file server.
```nginx
# On your existing server:
location ~ ^/(init|hb)$ {
proxy_pass http://127.0.0.1:3000;
}
```
Add to your protected pages:
```html
<script type="module" src="/pkg/antibot_wasm.js"></script>
<script type="module" src="/main.js"></script>
```
---
## Configuration
All parameters are in `shared/src/constants.rs`. Recompile after changes.
| Constant | Default | Notes |
|---|---|---|
| `SESSION_ID_LEN` | 32 bytes | 256-bit entropy — do not reduce |
| `SALT_LEN` | 16 bytes | Per-heartbeat salt |
| `HEARTBEAT_MIN_INTERVAL_MS` | 12 000 ms | Increase to reduce server load |
| `HEARTBEAT_MAX_INTERVAL_MS` | 25 000 ms | Jitter upper bound |
| `EXPIRATION_MINUTES` | 30 min | Session TTL after last heartbeat |
| `RATE_LIMIT_COUNT` | 5 | Max heartbeats per window per session |
| `RATE_LIMIT_WINDOW_SECS` | 10 s | Rate limit window |
| `MAX_TIMESTAMP_DRIFT_MS` | 30 000 ms | Anti-replay window; account for NTP skew |
| `MIN_MOUSE_TOTAL_DIST` | 10.0 px | Lower for low-activity pages |
| `MAX_MOUSE_AVG_SPEED` | 2.0 px/ms | Raise if legitimate users are rejected |
| `MIN_PAUSE_COUNT` | 1 | Minimum natural pause events |
---
## Observability
ChronoSeal uses `tracing` with `tracing-subscriber`. Log levels:
| Level | Events |
|---|---|
| `INFO` | Server start, request method + path + status |
| `WARN` | Heartbeat validation failures (with session ID and reason) |
| `DEBUG` | Rate limit hits |
```bash
RUST_LOG=info chronoseal # production
RUST_LOG=debug chronoseal # development
RUST_LOG=warn chronoseal # minimal output
```
Log format is plain text to stdout. Pipe to `journald`, `fluentd`, or any
log aggregator via stdout capture.
---
## Health Check
The server has no dedicated `/health` endpoint. Use a TCP check on port 3000,
or a lightweight HTTP check on `GET /` (which serves `index.html`).
```bash
# Docker health check (add to docker-compose.yml if needed)
healthcheck:
test: ["CMD", "curl", "-sf", "http://localhost:3000/"]
interval: 30s
timeout: 5s
retries: 3
```
---
## Security Checklist
- [ ] TLS 1.3 enabled, TLS 1.0/1.1 disabled
- [ ] HTTP/2 enabled
- [ ] Port 3000 not exposed to the public internet (only via reverse proxy)
- [ ] `RUST_LOG=warn` or `info` in production (not `debug` — session IDs appear in logs)
- [ ] systemd service running as `chronoseal` user with hardened sandbox
- [ ] `MemoryDenyWriteExecute=true` in service file (prevents JIT in process)
- [ ] CORS `CorsLayer::permissive()` replaced with origin-restricted policy for production
- [ ] Frontend assets served over the same HTTPS origin as protected pages