Something went wrong. Try again.
fork of ozone with nix stuff
Something went wrong. Try again.
Shell
at customized
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221#!/usr/bin/env bash# Registers an atproto account as an Ozone labeler by adding the# `#atproto_labeler` service and `#atproto_label` verification method to the# account's DID document (via PLC).## This is the same `com.atproto.identity.signPlcOperation` /# `submitPlcOperation` flow that the Ozone UI's register-labeler screen uses,# driven from the shell with the `goat` CLI.## Existing entries in the DID document (the `atproto` key, the `atproto_pds`# service, `alsoKnownAs`) are preserved; the labeler entries are merged in.## Requires: curl, python3, and the `goat` CLI. goat is launched with# `nix run nixpkgs#atproto-goat --` unless the GOAT env var is set.## Usage:# ./scripts/register-labeler.sh --public-url <URL> [--handle H] [--meta-url U] [--only-op] [--force]
usage() { cat <<'EOF'Registers an atproto account as an Ozone labeler by adding the`#atproto_labeler` service and `#atproto_label` verification method to theaccount's DID document (via PLC).
Requires: curl, python3, and the `goat` CLI (nix run nixpkgs#atproto-goat).
Usage: ./scripts/register-labeler.sh --public-url <URL> [options]
Options: --public-url URL Public URL where Ozone will be reachable; written to the DID document as the `#atproto_labeler` endpoint. Required. --handle HANDLE atproto handle of the labeler account. Default: akshay.tngl.sh --meta-url URL Base URL of a running Ozone instance used to read the labeler signing key from `/.well-known/ozone-metadata.json`. Default: http://localhost:3001 --only-op Build and print the PLC operation JSON, then exit without touching goat or sending any email. --force Re-register even if `#atproto_labeler` already exists (e.g. to update the endpoint after moving the service).EOF exit 1}
set -euo pipefail
PUBLIC_URL=""HANDLE="akshay.tngl.sh"META_URL="http://localhost:3001"ONLY_OP=falseFORCE=false
while [[ $# -gt 0 ]]; do case "$1" in --public-url) PUBLIC_URL="${2:?}"; shift 2 ;; --handle) HANDLE="${2:?}"; shift 2 ;; --meta-url) META_URL="${2:?}"; shift 2 ;; --only-op) ONLY_OP=true; shift ;; --force) FORCE=true; shift ;; --help | -h) usage ;; *) usage ;; esacdone
[[ -n "$PUBLIC_URL" ]] || { echo "error: --public-url is required" >&2 usage}
# Run a goat subcommand. GOAT, if set, must be a single executable path.run_goat() { if [[ -n "${GOAT:-}" ]]; then "$GOAT" "$@" else nix run nixpkgs#atproto-goat -- "$@" fi}
# Run python3, falling back to a nix-built one when python3 is missing or is a# non-functional stub (e.g. macOS Xcode CLT placeholder).PY_CMD=(python3)if ! command -v python3 >/dev/null 2>&1 || ! python3 -c 'pass' >/dev/null 2>&1; then PY_CMD=(nix run nixpkgs#python3 --)firun_python() { "${PY_CMD[@]}" "$@"}
echo "== resolving $HANDLE"DID="$( curl -fsS \ "https://api.bsky.app/xrpc/com.atproto.identity.resolveHandle?handle=${HANDLE}" | run_python -c 'import sys, json; print(json.load(sys.stdin)["did"])')"echo " did: $DID"
echo "== fetching current DID document from plc.directory"DOC="$(curl -fsS "https://plc.directory/${DID}")"
echo "== reading labeler signing key from ${META_URL}"META="$(curl -fsS "${META_URL}/.well-known/ozone-metadata.json")"META_DID="$(printf '%s' "$META" | run_python -c 'import sys, json; print(json.load(sys.stdin).get("did"))')"if [[ -n "$META_DID" && "$META_DID" != "$DID" ]]; then echo " !! warning: ozone service DID ($META_DID) differs from the labeler" \ "account DID ($DID); double-check OZONE_SERVER_DID points at this account" >&2fi
OP_JSON="$( PUBLIC_URL="$PUBLIC_URL" \ DOC="$DOC" \ META="$META" \ FORCE="$FORCE" \ run_python - <<'PY'import json, os, sys
doc = json.loads(os.environ['DOC'])meta = json.loads(os.environ['META'])public_url = os.environ['PUBLIC_URL']force = os.environ['FORCE'] == 'true'
vm = {}for entry in doc.get('verificationMethod', []): key = entry['id'].rsplit('#', 1)[-1] # PLC operations carry `did:key:` strings, whereas the resolved DID document # splits them into `publicKeyMultibase` (the method-specific id) and a type. vm[key] = 'did:key:' + entry['publicKeyMultibase']
services = {}for entry in doc.get('service', []): key = entry['id'].lstrip('#') services[key] = {"type": entry['type'], "endpoint": entry['serviceEndpoint']}
public_key = meta.get('publicKey')if not public_key or not public_key.startswith('did:key:'): sys.stderr.write( "error: no valid publicKey in ozone metadata. Is Ozone running with" " OZONE_SIGNING_KEY_HEX set?\n" ) sys.exit(1)
if 'atproto_label' in vm and vm['atproto_label'] != public_key: sys.stderr.write( f"error: DID document already has an #atproto_label key ({vm['atproto_label']})\n" " that differs from the running Ozone key. Refusing to clobber it; align\n" " OZONE_SIGNING_KEY_HEX with that key or clear the entry manually.\n" ) sys.exit(2)if 'atproto_label' not in vm: vm['atproto_label'] = public_key
if 'atproto_labeler' in services: current = services['atproto_labeler'].get('endpoint') if not force: sys.stderr.write( f"error: DID document already has an #atproto_labeler entry pointing at {current!r}\n" " pass --force to update it\n" ) sys.exit(2) if current != public_url: sys.stderr.write(f" updating #atproto_labeler endpoint: {current!r} -> {public_url!r}\n")else: services['atproto_labeler'] = {"type": "AtprotoLabeler", "endpoint": public_url}
op = { "alsoKnownAs": doc.get('alsoKnownAs', []), "verificationMethods": vm, "services": services,}print(json.dumps(op, indent=2))PY)"
echoecho "== PLC operation to apply"printf '%s\n' "$OP_JSON"echo
if [[ "$ONLY_OP" == true ]]; then echo "(--only-op: not signing or submitting anything)" exit 0fi
# goat signs the operation for whatever account it holds a session for, so a# stale session for a *different* account would silently apply the labeler# entries to the wrong DID document. Require a session for $DID specifically.SESSION_DID="$(run_goat account check-auth 2>/dev/null | sed -n 's/^DID: //p' || true)"if [[ "$SESSION_DID" != "$DID" ]]; then if [[ -n "$SESSION_DID" ]]; then echo "== goat is logged in as $SESSION_DID, not $HANDLE ($DID); logging out" run_goat account logout || true fi echo "== logging in as $HANDLE" echo " (You MUST use the full account password, not an app password:" echo " PLC operations are refused for app-password sessions.)" run_goat account login -u "$HANDLE"fi
echo "== requesting a PLC update confirmation code (check your email)"run_goat account plc request-token
read -rp "Enter the confirmation code from the email: " TOKEN[[ -n "$TOKEN" ]] || { echo "error: empty token" >&2 exit 1}
TMPDIR_WS="$(mktemp -d)"echo "$OP_JSON" >"$TMPDIR_WS/op.json"
echo "== signing PLC operation"run_goat account plc sign --token "$TOKEN" "$TMPDIR_WS/op.json" >"$TMPDIR_WS/signed.json"
echo "== submitting PLC operation"run_goat account plc submit "$TMPDIR_WS/signed.json"
echo "== done"echo " signed op kept at: $TMPDIR_WS/signed.json"echo " Verify with: goat plc history $HANDLE"echo " Then restart Ozone so it re-resolves the DID document."