ZKAC/docs/CLI.md
2026-05-06 18:12:31 +02:00

6.2 KiB

ZKAC CLI Guide

This guide documents the zkac-node CLI and the related zkac-node-i2p-server helper, with practical workflows for creating users, issuing credentials, and authenticating.

Install

From the repository root:

# Build/install the zkac Python extension first.
maturin develop

# Install CLI entrypoints.
pip install -e ./cli

Check installed commands:

zkac-node --help
zkac-node-i2p-server --help

Concepts

  • userid is your local identity name; each user is stored under ~/.zkac/<userid>/.
  • server is always a network endpoint string in host:port form.
  • Most management operations require pinning the server public key first.
  • Credentials are granted directly over authenticated P2P delivery (grant -> p2p-listen).

Command Groups

user

Manage local identities.

zkac-node user create <userid>
zkac-node user list
zkac-node user show <userid> [--peer host:port]
  • create generates issuance and transport keypairs.
  • show --peer host:port embeds your receiving endpoint into a shareable contact bundle, used by admins when granting.

serve

Run a ZKAC node server:

zkac-node serve <userid> [--data-dir DIR] [--host HOST] [--port PORT] \
  [--max-connections N] [--idle-timeout SECONDS] [--listen-backlog N] \
  [--allow-non-loopback]

Defaults: --host 127.0.0.1, --port 9800, data at ~/.zkac/<userid>/server/.

By default non-loopback binds are blocked unless you explicitly pass --allow-non-loopback.

server pin

Pin a server transport public key per user:

zkac-node server pin <userid> <host:port> --key <SERVER_PUBLIC_KEY_HEX>

Pins are exact string matches. If you connect with example.b32.i2p:9800, pin exactly that, not localhost:9800.

registry

Manage registries you own:

zkac-node registry create <userid> <server> --roles role1,role2
zkac-node registry update <userid> <server> --registry <REGISTRY_ID> --add-roles role3,role4
zkac-node registry get <userid> <server> --registry <REGISTRY_ID>
zkac-node registry list <userid>
zkac-node registry revoke <userid> <server> --registry <REGISTRY_ID> --role <ROLE>
zkac-node registry revoke <userid> <server> --registry <REGISTRY_ID> --all
  • create initializes a registry and stores local admin metadata.
  • update adds new roles.
  • revoke bumps role epoch(s), invalidating credentials for that role or all roles.

grant

Grant one credential directly to a recipient:

zkac-node grant <admin_userid> --server <host:port> --registry <REGISTRY_ID> \
  --role <ROLE> --to "<RECIPIENT_CONTACT_BUNDLE>"

The --to bundle must include both:

  • recipient issuance key and transport key
  • grant pairing token and peer endpoint (from user show --peer)

p2p-listen

Receive exactly one direct grant and store it locally:

zkac-node p2p-listen <userid> [--host HOST] [--port PORT] [--timeout SECONDS] \
  [--allow-non-loopback]

Default bind is 127.0.0.1:9810.

credentials list

Show locally stored credentials:

zkac-node credentials list <userid>

auth

Authenticate using a credential:

zkac-node auth <userid> --registry <REGISTRY_ID> --role <ROLE> [--server host:port]

If --server is omitted, the CLI tries to use server info from local admin metadata for that registry.

net check

Connectivity diagnostics:

zkac-node net check <host:port> [--timeout SECONDS] [--handshake] [--userid <id>] [--key <hex>]
  • Without --handshake, this verifies TCP reachability.
  • With --handshake, it additionally verifies anonymous ZKAC handshake.
  • For handshake mode, provide either --key or --userid (not both).

End-to-End Workflow: Create, Grant, Receive, Authenticate

Two users: alice (admin) and bob (recipient), one server on localhost:9800.

  1. Create users
zkac-node user create alice
zkac-node user create bob
  1. Start server (Alice host)
zkac-node serve alice --host 127.0.0.1 --port 9800
  1. Pin server key for both users
zkac-node server pin alice localhost:9800 --key <SERVER_PK_HEX>
zkac-node server pin bob localhost:9800 --key <SERVER_PK_HEX>
  1. Bob shares contact bundle with peer endpoint
zkac-node user show bob --peer 127.0.0.1:9810

Copy the emitted contact blob from Bob to Alice through an out-of-band channel.

  1. Alice creates registry
zkac-node registry create alice localhost:9800 --roles analyst,operator

Save the registry_id from command output.

  1. Bob starts one-shot receiver
zkac-node p2p-listen bob --host 127.0.0.1 --port 9810
  1. Alice grants Bob analyst
zkac-node grant alice --server localhost:9800 --registry <REGISTRY_ID> \
  --role analyst --to "<BOB_CONTACT_BUNDLE>"
  1. Bob verifies local credential
zkac-node credentials list bob
  1. Bob authenticates
zkac-node auth bob --registry <REGISTRY_ID> --role analyst --server localhost:9800

Workflow: Revoke a Role

Revoke only one role:

zkac-node registry revoke alice localhost:9800 --registry <REGISTRY_ID> --role analyst

Revoke all roles:

zkac-node registry revoke alice localhost:9800 --registry <REGISTRY_ID> --all

After revocation, existing credentials for bumped epoch(s) no longer authenticate.

Workflow: I2P Connectivity

Run server intended for I2P tunnel exposure:

zkac-node-i2p-server alice --host 127.0.0.1 --port 9800

For outbound client traffic to .i2p endpoints, configure SOCKS5:

export ZKAC_SOCKS5_PROXY=127.0.0.1:4447

Then use normal commands against *.b32.i2p:port:

zkac-node net check exampledestination.b32.i2p:9800
zkac-node net check exampledestination.b32.i2p:9800 --handshake --key <SERVER_PK_HEX>
zkac-node auth bob --registry <REGISTRY_ID> --role analyst --server exampledestination.b32.i2p:9800

Local Storage Layout

Per user directory (~/.zkac/<userid>/):

identity.json                 issuance + p2p transport identity data
admin/<registry_id>.json      local admin material for owned registries
credentials/<rid>_<role>.json received credentials
servers/sha256_*.json         pinned server public keys
server/                       server state if `serve` is run for this userid