#!/usr/bin/env python3 """ A hub action that sets this computer up to send you alerts — so the phone can do it with one tap instead of anyone opening a terminal. "actions": { "setup-link": {"run": "python3 ~/bin/setup_link.py", "description": "set this computer up to send me alerts"} } in {"code": "PT-GESN-NXPB", "name": "steve-laptop"} (name optional) out {"ok": true, "installed": "/home/you/.local/bin/palmtop-link", "name": "...", "already": false} The phone mints the enrolment code (Alerts → Add a server, or forge.alerts.addServer()) and hands it straight here, which is the whole trick: a code is the only thing that ever needs to travel, it is good once and for half an hour, and what this machine keeps afterwards is a credential of its own that the phone can revoke by name. What it does, in order: find palmtop-link, or download the build for this platform from priorstates.com and check it against the published SHA256SUMS; then spend the code. Nothing starts at boot, nothing listens, and no credential of yours is asked for. If the binary is already installed and enrolled with this phone, enrolling again simply replaces that one credential. Stdlib only, so it runs on a machine with nothing on it. """ import hashlib import json import os import platform import shutil import socket import stat import subprocess import sys import tempfile import urllib.error import urllib.request BASE = os.environ.get("PALMTOP_LINK_BASE", "https://priorstates.com/palmtop/link") TIMEOUT = 60 def asset() -> str: machine = platform.machine().lower() arch = "arm64" if machine in ("arm64", "aarch64") else "amd64" if machine in ("x86_64", "amd64") else "" system = platform.system().lower() if not arch: raise SystemExit(f"no Palmtop Link build for {machine}") if system == "linux": return f"palmtop-link-linux-{arch}" if system == "darwin": return f"palmtop-link-macos-{arch}" if system == "windows": return "palmtop-link-windows-amd64.exe" raise SystemExit(f"no Palmtop Link build for {system}") def fetch(url: str) -> bytes: with urllib.request.urlopen(url, timeout=TIMEOUT) as r: return r.read() def install() -> str: """Return the path to palmtop-link, downloading it if this machine has none.""" found = shutil.which("palmtop-link") if found: return found name = asset() blob = fetch(f"{BASE}/{name}") # The checksum is the point of downloading from us rather than anywhere else. sums = fetch(f"{BASE}/SHA256SUMS").decode() want = next((line.split()[0] for line in sums.splitlines() if line.strip().endswith(name)), "") got = hashlib.sha256(blob).hexdigest() if not want: raise SystemExit(f"{name} is not in the published checksums — refusing to install it") if want != got: raise SystemExit("the download does not match the published checksum — refusing to install it") target_dir = "/usr/local/bin" if os.access("/usr/local/bin", os.W_OK) else os.path.expanduser("~/.local/bin") os.makedirs(target_dir, exist_ok=True) target = os.path.join(target_dir, "palmtop-link" + (".exe" if platform.system() == "Windows" else "")) fd, tmp = tempfile.mkstemp(dir=target_dir) with os.fdopen(fd, "wb") as f: f.write(blob) os.chmod(tmp, os.stat(tmp).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) os.replace(tmp, target) # replace in one step: never a half-written binary on PATH return target def enroll(binary: str, code: str, name: str): r = subprocess.run([binary, "enroll", code, "--name", name], capture_output=True, text=True, timeout=TIMEOUT) if r.returncode != 0: return {"ok": False, "error": (r.stderr or r.stdout or "").strip()[:300]} return {"ok": True, "message": (r.stdout or "").strip().splitlines()[0]} def args_in(): """Arguments as JSON on stdin, without ever blocking — the lesson from every other action here: a scheduler hands its children an open, empty stdin.""" if sys.stdin.isatty(): return {} try: import select if not select.select([sys.stdin], [], [], 0.5)[0]: return {} except Exception: # noqa: BLE001 pass try: return json.load(sys.stdin) or {} except ValueError: return {} def main(): body = args_in() code = str(body.get("code") or (sys.argv[1] if len(sys.argv) > 1 else "")).strip() name = str(body.get("name") or socket.gethostname())[:60] if not code: json.dump({"ok": False, "error": "no enrolment code — make one on the phone: Alerts → Add a server"}, sys.stdout) sys.exit(2) try: binary = install() except (urllib.error.URLError, OSError, SystemExit) as e: json.dump({"ok": False, "error": f"could not install palmtop-link: {e}"}, sys.stdout) sys.exit(1) out = enroll(binary, code, name) out["installed"] = binary out["name"] = name json.dump(out, sys.stdout) sys.exit(0 if out.get("ok") else 1) if __name__ == "__main__": main()