#!/usr/bin/env python3 """Command line for Sigil. sigil.py seed one-time enrolment secret sigil.py keygen write an Ed25519 private key (0600) sigil.py enrol sigil.py challenge nonce to sign sigil.py sign signature, base64 sigil.py verify agent session token sigil.py code one-time code for a human to view sigil.py redeem human_via_agent session token sigil.py whoami describe a session sigil.py events [actor] audit trail Uses SIGIL_DB (default ./sigil.db) and SIGIL_KEY (default ./agent.key). """ from __future__ import annotations import base64 import json import os import sys from sigil import errors, identity, keys, sessions, viewcodes from sigil.store import Store DB = os.environ.get("SIGIL_DB", "./sigil.db") KEY = os.environ.get("SIGIL_KEY", "./agent.key") def out(obj) -> None: print(json.dumps(obj, indent=2, sort_keys=True)) def main(argv) -> int: if len(argv) < 2: print(__doc__) return 2 cmd = argv[1] store = Store(DB) try: if cmd == "seed": agent = argv[2] out({"agent": agent, "secret": identity.seed_bootstrap(store, agent)}) elif cmd == "keygen": path = argv[2] if len(argv) > 2 else KEY private, public = keys.generate() keys.save_private(private, path) out({ "private_key": path, "fingerprint": keys.fingerprint(public), "public_b64": keys.export_public_b64(public), }) elif cmd == "enrol": out({"fingerprint": identity.enrol(store, argv[2], argv[3], argv[4])}) elif cmd == "challenge": out(identity.challenge(store, argv[2])) elif cmd == "sign": private = keys.load_private(argv[2]) nonce = argv[3] out({"nonce": nonce, "signature": base64.b64encode( keys.sign(private, nonce.encode("utf-8"))).decode("ascii")}) elif cmd == "verify": out(identity.verify(store, argv[2], argv[3])) elif cmd == "code": out(viewcodes.issue_code(store, argv[2])) elif cmd == "redeem": out(viewcodes.redeem_code(store, argv[2])) elif cmd == "whoami": session = sessions.resolve(store, argv[2]) may_act = True try: sessions.assert_may_act_as_agent(session) except errors.AgentImpersonationDenied: may_act = False session["may_act_as_agent"] = may_act out(session) elif cmd == "events": out(store.events(argv[2] if len(argv) > 2 else None, int(argv[3]) if len(argv) > 3 else 50)) else: print(__doc__) return 2 except errors.SigilError as exc: print(json.dumps({"error": type(exc).__name__, "message": str(exc)})) return 1 return 0 if __name__ == "__main__": raise SystemExit(main(sys.argv))