#!/usr/bin/env python3
"""sandbroker-authz-check - show each session's authorization binding state.

The authz counterpart to claude-sandbox-check: it tells you which sessions are
BOUND to which vault right now, and how long until they idle out. Reads the
daemon's private session records, so on the production box run it as the daemon
user:

    sudo -u sandbroker SANDBROKER_BASE=/opt/sandbroker sandbroker-authz-check

A BOUND row means that session can currently USE its vault's confirm-tier
secrets without another biometric prompt (until it idles out). If you see a
binding you don't recognize, run `sandbroker-lock` to clear every session.
"""
import json
import os
import sys
import time

BASE = os.environ.get("SANDBROKER_BASE", "/opt/sandbroker")
SESSIONS_DIR = os.path.join(BASE, "var", "sessions")
PENDING_DIR = os.path.join(BASE, "var", "pending")
IDLE_TIMEOUT = 3600

green = "\033[32m"; yellow = "\033[33m"; red = "\033[31m"; dim = "\033[2m"; off = "\033[0m"


def fmt_age(secs):
    secs = int(secs)
    if secs < 60:
        return "%ds" % secs
    if secs < 3600:
        return "%dm" % (secs // 60)
    return "%dh%dm" % (secs // 3600, (secs % 3600) // 60)


def main():
    try:
        names = [n for n in os.listdir(SESSIONS_DIR) if n.endswith(".json")]
    except PermissionError:
        sys.stderr.write("sandbroker-authz-check: cannot read %s (run as the daemon "
                         "user: sudo -u sandbroker ... )\n" % SESSIONS_DIR)
        return 2
    except OSError:
        names = []

    pending = set()
    try:
        pending = {n[:-5] for n in os.listdir(PENDING_DIR) if n.endswith(".json")}
    except OSError:
        pass

    if not names:
        print("no registered sessions")
        return 0

    now = time.time()
    print("%-14s %-20s %-8s %-10s %s" % ("SID", "VAULT", "TIER", "STATE", "IDLE/INFO"))
    print("%-14s %-20s %-8s %-10s %s" % ("---", "-----", "----", "-----", "---------"))
    for n in sorted(names):
        sid = n[:-5]
        try:
            with open(os.path.join(SESSIONS_DIR, n)) as fh:
                s = json.load(fh)
        except (OSError, ValueError):
            continue
        vault = s.get("vault", "?")
        tier = s.get("tier", "?")
        state = s.get("state", "?")
        if state == "BOUND":
            idle = now - s.get("last_used", 0)
            if idle > IDLE_TIMEOUT:
                colored = "%sEXPIRED%s" % (yellow, off)
                info = "idle %s (re-auth)" % fmt_age(idle)
            else:
                colored = "%sBOUND%s" % (green, off)
                info = "idle %s / %s left" % (fmt_age(idle), fmt_age(IDLE_TIMEOUT - idle))
        else:
            colored = "%sUNBOUND%s" % (dim, off)
            info = "awaiting approval" if sid in pending else "registered, not bound"
        short = sid if len(sid) <= 14 else sid[:11] + "..."
        print("%-14s %-20s %-8s %-20s %s%s%s"
              % (short, vault, tier, colored, dim, info, off))
    print()
    print("%sBOUND = can use the vault's secrets now. `sandbroker-lock` clears all.%s" % (dim, off))
    return 0


if __name__ == "__main__":
    sys.exit(main())
