4.9 KiB
zkac-node CLI
Install the zkac wheel from the repo root first (maturin develop or pip install .), then:
pip install -e ./cli
zkac-node --help
zkac-node-i2p-server --help
Quick start
# 1. Create identities (one directory per user under ~/.zkac/<userid>/)
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 <SERVER_PK_HEX>
zkac-node server pin bob localhost:9800 --key <SERVER_PK_HEX>
# 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 <REGISTRY_ID> --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 <REGISTRY_ID> --role analyst --server localhost:9800
Commands
| Command | Description |
|---|---|
user create <id> |
Generate issuance keypair under ~/.zkac/<id>/ |
user list |
List all local user ids |
user show <id> |
Show issuance pk + owned registries + credentials |
serve <id> [--data-dir D] |
Run server; default data dir is ~/.zkac/<id>/server/ (loopback-only unless --allow-non-loopback) |
zkac-node-i2p-server <id> [--host H --port P] |
Same as serve, for I2P server-tunnel exposure (see below) |
server pin <id> <host:port> --key <hex> |
Pin server public key for that user |
registry create <id> <server> --roles … |
Create registry on server |
registry update <id> <server> --registry R --add-roles … |
Add roles |
registry get <id> <server> --registry R |
Fetch registry state |
registry list <id> |
List registries this user owns locally |
grant <id> --server S --registry R --role X --to <blob> |
Admin direct p2p grant (recipient contact bundle must include peer endpoint) |
p2p-listen <id> [--host H --port P] |
Receive one direct p2p grant and store credential (loopback-only unless --allow-non-loopback) |
credentials list <id> |
List local credentials |
auth <id> --registry R --role X [--server S] |
Authenticated session |
Protocol & threat model
See 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.
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.
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.
- Start I2P/i2pd SOCKS proxy (commonly
127.0.0.1:4447). - Export:
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.
- Use
.b32.i2p:portendpoints with normal commands:
zkac-node registry get alice exampledestination.b32.i2p:9800 --registry <REGISTRY_ID>
zkac-node auth bob --registry <REGISTRY_ID> --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:
zkac-node net check exampledestination.b32.i2p:9800
zkac-node net check exampledestination.b32.i2p:9800 --handshake --key <SERVER_PK_HEX>
# or use an existing pin:
zkac-node net check exampledestination.b32.i2p:9800 --handshake --userid alice
With proxy:
export ZKAC_SOCKS5_PROXY=127.0.0.1:4447
zkac-node net check exampledestination.b32.i2p:9800
Storage layout
Per user ~/.zkac/<userid>/:
identity.json issuance keypair
p2p transport keypair
admin/<registry_id>.json BBS+ admin material for owned registries
credentials/<rid>_<role>.json received credentials
servers/sha256_<...>.json pinned server public keys (includes original server string)
server/ (only if you run `serve <userid>`) server_key.json, registries/