""" `trust`: the node keys this machine pinned at first contact. A node presenting another key than the one pinned is refused outright (exit 6, docs/MESHBAY_DESIGN.md §5.2). `trust reset NODE` is the deliberate way out, for a rotation the node's operator has announced — the counterpart of the reset in the application's Settings. Nothing resets a pin by itself. """ import json import sys from ..client.account import Account, no_passphrase from ..errors import NOT_FOUND, USAGE, CliError from ..output import safe, sentence from .context import Context HELP = "the node keys pinned at first contact: list them, or forget one" def add_parser(sub, parent) -> None: p = sub.add_parser("trust", parents=[parent], help=HELP, description=sentence(HELP) + ". A node whose key changed is refused until its pin is reset.") p.add_argument("verb", choices=("list", "reset")) p.add_argument("node", nargs="?", help="the node's id, as the refusal names it") async def run(ctx: Context) -> int: a = ctx.args if not ctx.store.peek(): pins = {} account = None else: account = Account.open(ctx.hub, None, no_passphrase, ctx.store) pins = account.state.get("pins", {}) if account.remembered else {} if a.verb == "list": if a.json: json.dump(pins, sys.stdout, indent=1) print() else: for node_id, pk in sorted(pins.items()): print(f"{safe(node_id)} {safe(pk)}") return 0 if not a.node: raise CliError(USAGE, "Name the node: meshbay-cli trust reset NODE") if a.node not in pins: raise CliError(NOT_FOUND, f"No key is pinned for the node {safe(a.node)}.") def drop(state: dict, secrets: dict) -> None: state.get("pins", {}).pop(a.node, None) await account.update(drop) print(f"Forgot the key pinned for {safe(a.node)}; the next connection pins the key " "it presents.") return 0