~james/core

core/localinfra/scripts/lib.sh -rw-r--r-- 3.5 KiB
452f17b7 — james chore(import): snapshot james.dad.town/core at f70c71c7696a 15 hours ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#!/bin/sh
# shared helpers for the dev bootstrap scripts. source, don't run.

: "${PDS_URL:?PDS_URL must be set}"
PASSWORD="${PASSWORD:-password}"
CREATED_AT="${CREATED_AT:-2025-09-22T11:14:35+01:00}"

# fail LINE... -> every line on stderr, then abort
fail() {
  printf '%s\n' "$@" >&2
  exit 1
}

# resolve_handle HANDLE → DID on stdout
resolve_handle() {
  rh_resp=$(curl -sS -w '\n%{http_code}' \
    "${PDS_URL}/xrpc/com.atproto.identity.resolveHandle?handle=$1")
  rh_body=$(printf '%s\n' "$rh_resp" | sed '$d')
  rh_status=$(printf '%s\n' "$rh_resp" | tail -n1)
  case "$rh_status" in
    200) printf '%s\n' "$rh_body" | jq -er '.did' ;;
    400) : ;;  # not found — expected
    *)   fail "resolveHandle $1: HTTP $rh_status: $rh_body" ;;
  esac
}

require_handle() {
  rq_did=$(resolve_handle "$1")
  [ -n "$rq_did" ] || fail "resolveHandle $1: the pds doesn't know that handle." \
    '  init-data.sh creates the seed accounts, so it either never ran or failed.'
  printf '%s\n' "$rq_did"
}

# login DID/Handle → access JWT on stdout
# each login costs ~0.4s of password hashing on the pds, so LOGIN_CACHE skips it
login() {
  if [ -n "${LOGIN_CACHE:-}" ] && [ -s "$LOGIN_CACHE/$1" ]; then
    cat "$LOGIN_CACHE/$1"
    return 0
  fi
  lg_jwt=$(curl -fsS -H "Content-Type: application/json" \
    -d "{\"identifier\":\"$1\",\"password\":\"${PASSWORD}\"}" \
    "${PDS_URL}/xrpc/com.atproto.server.createSession" \
    | jq -er '.accessJwt') || return 1
  [ -z "${LOGIN_CACHE:-}" ] || printf '%s\n' "$lg_jwt" > "$LOGIN_CACHE/$1"
  printf '%s\n' "$lg_jwt"
}

# service_token JWT LXM [AUD] → service auth JWT for the knot, on stdout.
# AUD defaults to the did:web of $KNOT_HOSTNAME.
service_token() {
  st_aud=${3:-"did:web:$(printf '%s' "${KNOT_HOSTNAME:?KNOT_HOSTNAME must be set}" | sed 's/:/%3A/g')"}

  curl -fsS -H "Authorization: Bearer $1" \
    "${PDS_URL}/xrpc/com.atproto.server.getServiceAuth?aud=${st_aud}&lxm=$2&exp=$(( $(date +%s) + 240 ))" \
    | jq -er '.token'
}

# put_record at://DID/COLLECTION/RKEY CID
# → puts /fixtures/records/DID/COLLECTION/RKEY/CID.json, fails unless the pds returns CID.
put_record() {
  case "$1" in
    at://did:*/*/?*) ;;
    *) fail "put_record: expected at://DID/COLLECTION/RKEY, got $1" ;;
  esac

  pr_rest=${1#at://}
  pr_did=${pr_rest%%/*}
  pr_rest=${pr_rest#*/}
  pr_collection=${pr_rest%%/*}
  pr_rkey=${pr_rest#*/}
  pr_record=$(cat "${FIXTURES:-/fixtures}/records/$pr_did/$pr_collection/$pr_rkey/$2.json")

  pr_jwt=$(login "$pr_did")

  pr_payload=$(jq -nc \
    --arg repo "$pr_did" \
    --arg collection "$pr_collection" \
    --arg rkey "$pr_rkey" \
    --argjson record "$pr_record" \
    '{repo:$repo, collection:$collection, rkey:$rkey, record:$record}')

  pr_resp=$(curl -fsS \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer ${pr_jwt}" \
    -d "$pr_payload" \
    "${PDS_URL}/xrpc/com.atproto.repo.putRecord")

  printf '[record] %s\n' "$1" >&2
  pr_cid=$(printf '%s\n' "$pr_resp" | jq -er '.cid') # -e: fail loudly if the cid is absent
  [ "$pr_cid" = "$2" ] || fail "put_record $1: cid is $pr_cid, expected $2"
}

# upload_blob DID CID MIME_TYPE
# → uploads /fixtures/blobs/DID/CID, fails unless the pds returns CID.
upload_blob() {
  ub_cid=$(curl -fsS --data-binary "@${FIXTURES:-/fixtures}/blobs/$1/$2" \
    -H "Content-Type: $3" \
    -H "Authorization: Bearer $(login "$1")" \
    "${PDS_URL}/xrpc/com.atproto.repo.uploadBlob" \
    | jq -er '.blob.ref."$link"')
  [ "$ub_cid" = "$2" ] || fail "upload_blob $1/$2: cid is $ub_cid, expected $2"
  printf '[blob] %s/%s\n' "$1" "$2" >&2
}