"""Entry point for ``zkac-node-i2p-server``: same TCP node as ``zkac-node serve``, for I2P tunnels.""" from __future__ import annotations import argparse import sys from .paths import user_dir from .server import serve def main() -> None: epilog = """ I2P setup (typical): 1. Run this command so the node listens on the loopback address shown below. 2. In I2P or i2pd, create a server tunnel (TCP) that forwards inbound I2P connections to that host:port (e.g. 127.0.0.1:9800). 3. Note the published destination (…b32.i2p) and the tunnel’s virtual port. Clients use: .b32.i2p: as the server argument to zkac-node (registry, grant, auth, net check, etc.). 4. Clients must reach I2P (e.g. export ZKAC_SOCKS5_PROXY=127.0.0.1:4447). Pins are stored per host:port string — clients should pin the same address they use to connect (the .b32.i2p:port form, not localhost). """ p = argparse.ArgumentParser( prog="zkac-node-i2p-server", description=( "Run the ZKAC node (registry + anonymous handshake) on TCP for exposure " "through an I2P server tunnel. This is zkac-node serve with I2P-oriented " "defaults and setup hints." ), epilog=epilog, formatter_class=argparse.RawDescriptionHelpFormatter, ) p.add_argument( "userid", help="user whose ~/.zkac//server/ holds server state (unless --data-dir)", ) p.add_argument("--data-dir", default=None, help="override server data directory") p.add_argument( "--host", default="127.0.0.1", help="bind address (default: 127.0.0.1 — forward here from your I2P tunnel)", ) p.add_argument( "--port", type=int, default=9800, help="TCP port the node listens on (default: 9800)", ) p.add_argument( "--no-i2p-banner", action="store_true", help="suppress I2P tunnel reminder text", ) p.add_argument( "--allow-non-loopback", action="store_true", help="allow --host values outside loopback (default blocks non-loopback binds)", ) args = p.parse_args() data_dir = args.data_dir if data_dir is None: data_dir = str(user_dir(args.userid) / "server") if not args.no_i2p_banner: print( "zkac-node-i2p-server: listening for plain TCP (expose this with an I2P server tunnel).\n" f" bind: {args.host}:{args.port}\n" f" data: {data_dir}\n" "Clients on I2P: set ZKAC_SOCKS5_PROXY if needed, then use host:port like " "mydest.b32.i2p:9800 with zkac-node commands.\n", file=sys.stderr, ) serve(data_dir, args.host, args.port, allow_non_loopback=args.allow_non_loopback) if __name__ == "__main__": main()