# zkac-node CLI Install the `zkac` wheel from the repo root first (`maturin develop` or `pip install .`), then: ```bash pip install -e ./cli zkac-node --help zkac-node-i2p-server --help ``` ## Quick start ```bash # 1. Create identities (one directory per user under ~/.zkac//) zkac-node user create alice zkac-node user create bob # Bob shares one contact string with Alice out-of-band: # zkac-node user show bob --peer 127.0.0.1:9810 # 2. Alice runs a server; pin its public key for clients zkac-node serve alice --port 9800 & zkac-node server pin alice localhost:9800 --key zkac-node server pin bob localhost:9800 --key # 3. Alice creates a registry and grants Bob a role directly (needs Bob's contact string) zkac-node registry create alice localhost:9800 --roles analyst,operator zkac-node grant alice --server localhost:9800 \ --registry --role analyst --to "$BOB_CONTACT" # 4. Bob listens for direct p2p delivery zkac-node p2p-listen bob --host 127.0.0.1 --port 9810 # 5. Bob lists local creds zkac-node credentials list bob # 6. Bob authenticates zkac-node auth bob --registry --role analyst --server localhost:9800 ``` ## Commands | Command | Description | |---------|-------------| | `user create ` | Generate issuance keypair under `~/.zkac//` | | `user list` | List all local user ids | | `user show ` | Show issuance pk + owned registries + credentials | | `serve [--data-dir D]` | Run server; default data dir is `~/.zkac//server/` (loopback-only unless `--allow-non-loopback`) | | `zkac-node-i2p-server [--host H --port P]` | Same as `serve`, for I2P server-tunnel exposure (see below) | | `server pin --key ` | Pin server public key for that user | | `registry create --roles …` | Create registry on server | | `registry update --registry R --add-roles …` | Add roles | | `registry get --registry R` | Fetch registry state | | `registry list ` | List registries this user owns locally | | `grant --server S --registry R --role X --to ` | Admin direct p2p grant (recipient contact bundle must include peer endpoint) | | `p2p-listen [--host H --port P]` | Receive one direct p2p grant and store credential (loopback-only unless `--allow-non-loopback`) | | `credentials list ` | List local credentials | | `auth --registry R --role X [--server S]` | Authenticated session | ## Protocol & threat model See [docs/SECURITY.md](../docs/SECURITY.md) in the repo root for the direct p2p grant model. ## Admin debug web UI (demo) For a **fully transparent** HTTP dashboard (registry rows, live TCP sessions, data-dir listing), run **`demo/zkac_admin_serve.py`** from the repo with **`uv sync --extra demo`**. See [demo/README.md](../demo/README.md). ## Running over I2P ### Inbound: `zkac-node-i2p-server` Run the node on a loopback TCP port and forward it from an **I2P server tunnel** (I2P or i2pd). Clients use your published **`*.b32.i2p:port`** as the server string in all `zkac-node` commands. ```bash zkac-node-i2p-server alice --host 127.0.0.1 --port 9800 ``` They should **pin** that same `host:port` string (the `.b32.i2p` form), not `localhost`. ### Outbound clients Outbound client connections can be proxied through an I2P SOCKS tunnel. 1. Start I2P/i2pd SOCKS proxy (commonly `127.0.0.1:4447`). 2. Export: ```bash export ZKAC_SOCKS5_PROXY=127.0.0.1:4447 ``` If the destination ends in `.i2p` and `ZKAC_SOCKS5_PROXY` is not set, `zkac-node` fails fast instead of attempting a direct clearnet connect. 3. Use `.b32.i2p:port` endpoints with normal commands: ```bash zkac-node registry get alice exampledestination.b32.i2p:9800 --registry zkac-node auth bob --registry --role analyst --server exampledestination.b32.i2p:9800 ``` For inbound direct grants, run `p2p-listen` on a local port and expose it via an I2P inbound tunnel. Peers dial your published I2P destination/port; your tunnel forwards to local `host:port`. `p2p-listen` now refuses non-loopback binds by default (use `--allow-non-loopback` only when intentional). Connectivity sanity check: ```bash zkac-node net check exampledestination.b32.i2p:9800 zkac-node net check exampledestination.b32.i2p:9800 --handshake --key # or use an existing pin: zkac-node net check exampledestination.b32.i2p:9800 --handshake --userid alice ``` With proxy: ```bash export ZKAC_SOCKS5_PROXY=127.0.0.1:4447 zkac-node net check exampledestination.b32.i2p:9800 ``` ## Storage layout Per user `~/.zkac//`: ``` identity.json issuance keypair p2p transport keypair admin/.json BBS+ admin material for owned registries credentials/_.json received credentials servers/sha256_<...>.json pinned server public keys (includes original server string) server/ (only if you run `serve `) server_key.json, registries/ ```