2026-10-03 11:42:03 +02:00
# Shared by interop.sh and the scenarios: check helpers, PrivaPub personas and tokens, the statistics check.
P = http://127.0.0.1:6971
work = $( mktemp -d) ; trap 'rm -rf "$work"' EXIT
pass = 0; fail = 0; expected = 0
ok() { echo " ok $* " ; pass = $(( pass+1)) ; }
ko() { echo " FAIL $* " ; fail = $(( fail+1)) ; }
xf() { echo " xf $* (expected to fail until a later phase)" ; expected = $(( expected+1)) ; }
j() { python3 -c "import sys,json
try: d=json.load(sys.stdin)
except Exception: d=None
$1 " 2>/dev/null; }
until_true() { local tries = $1 ; shift; for _ in $( seq 1 " $tries " ) ; do if eval " $@ " ; then return 0; fi ; sleep 2; done ; return 1; }
site() { curl -k --resolve " $1 :6443:127.0.0.1" " ${ @: 2 } " ; }
2026-10-03 12:30:05 +02:00
# fetches one of PrivaPub's own https URIs (ids, scribbles) from the workstation, through Caddy
pfetch() { curl -sk --connect-to privapub.test:443:127.0.0.1:6443 " $@ " ; }
2026-10-03 11:42:03 +02:00
2026-10-03 12:54:01 +02:00
# make_png <path>: an 8x8 red PNG, for uploads
make_png() { python3 -c "
import struct,zlib
w=h=8
raw=b''.join(b'\x00'+bytes([200,60,60])*w for _ in range(h))
png=b'\x89PNG\r\n\x1a\n'+b''.join(struct.pack('>I',len(c))+t+c+struct.pack('>I',zlib.crc32(t+c)&0xffffffff) for t,c in [(b'IHDR',struct.pack('>IIBBBBB',w,h,8,2,0,0,0)),(b'IDAT',zlib.compress(raw)),(b'IEND',b'')])
open(' $1 ','wb').write(png)" ; }
2026-10-03 11:42:03 +02:00
ROOT_USER = pastureroot; ROOT_PASS = 'Pasture-Pass-1!'
privapub_root() {
local root
root = $( curl -s -X POST $P /clientapi/user/signup -H 'Content-Type: application/json' -d "{\"userName\":\" $ROOT_USER \",\"password\":\" $ROOT_PASS \"}" )
[ -n " $( echo " $root " | j "print(d['token'])" ) " ] || root = $( curl -s -X POST $P /clientapi/user/login -H 'Content-Type: application/json' -d "{\"userName\":\" $ROOT_USER \",\"password\":\" $ROOT_PASS \"}" )
echo " $root " | j "print(d['token'])"
}
2026-10-04 02:37:38 +02:00
# privapub_token <persona>: creates the persona under the pasture root if needed and returns a Mastodon token for it,
# through the same OAuth flow the deploy's smoke check uses (tools/smoke/oauth.sh).
2026-10-03 11:42:03 +02:00
privapub_token() {
2026-10-04 02:37:38 +02:00
local persona = $1 jwt
2026-10-03 11:42:03 +02:00
jwt = $( privapub_root)
curl -s -o /dev/null -X POST $P /clientapi/avatar/private/insert -H 'Content-Type: application/json' -H "Authorization: Bearer $jwt " \
-d "{\"userName\":\" $persona \",\"name\":\" $persona of PrivaPub\",\"biography\":\"testing federation\"}"
2026-10-04 02:37:38 +02:00
" $here /../smoke/oauth.sh" " $P " " $ROOT_USER " " $ROOT_PASS " " $persona " "read write follow" | cut -d' ' -f1
2026-10-03 11:42:03 +02:00
}
# stats_check <host> <software>: the admin statistics name the peer's software and count traffic both ways.
stats_check() {
local host = $1 software = $2 admin found
podman exec -w /app pasture-privapub /app/PrivaPub admin promote " $ROOT_USER " >/dev/null 2>& 1 || true
admin = $( curl -s -X POST $P /clientapi/user/login -H 'Content-Type: application/json' -d "{\"userName\":\" $ROOT_USER \",\"password\":\" $ROOT_PASS \"}" | j "print(d['token'])" )
until_true 30 'found=$(curl -s -H "Authorization: Bearer $admin" "$P/clientapi/admin/statistics/hosts/$host?days=1"); [ "$(echo "$found" | j "print((d[\"instance\"] or {}).get(\"software\"))")" = "$software" ]' \
&& ok "statistics describe $host as $software " || ko "statistics do not describe $host as $software "
found = $( curl -s -H "Authorization: Bearer $admin " " $P /clientapi/admin/statistics/hosts/ $host ?days=1" )
[ " $( echo " $found " | j "print(any(k.startswith('in:') for day in d['days'] for k in day['counters']))" ) " = "True" ] \
&& ok "statistics count what $host sent" || ko "no inbound statistics for $host "
[ " $( echo " $found " | j "print(any(k.startswith('out:') and ':ok' in k for day in d['days'] for k in day['counters']))" ) " = "True" ] \
&& ok "statistics count what we delivered to $host " || ko "no outbound statistics for $host "
[ " $( echo " $found " | j "print(' $ROOT_USER ' not in json.dumps(d['events']) and 'alice' not in json.dumps(d['events']))" ) " = "True" ] \
&& ok "statistics for $host name no account" || ko "statistics for $host name an account"
}