#!/usr/bin/env bash # next/tests/webfinger_route.sh — m2 Step 10b test. # # GET /.well-known/webfinger?resource=acct:user@host route in # http_server. Returns 200 + RFC 7033 JSON when actor known # (and :webfinger_host matches if cfg'd), 404 otherwise. set -uo pipefail cd "$(git rev-parse --show-toplevel)" SX_SERVER="${SX_SERVER:-hosts/ocaml/_build/default/bin/sx_server.exe}" if [ ! -x "$SX_SERVER" ]; then SX_SERVER="/root/rose-ash/hosts/ocaml/_build/default/bin/sx_server.exe" fi if [ ! -x "$SX_SERVER" ]; then echo "ERROR: sx_server.exe not found." >&2 exit 1 fi VERBOSE="${1:-}" PASS=0; FAIL=0; ERRORS="" TMPFILE=$(mktemp); trap "rm -f $TMPFILE" EXIT # /.well-known/webfinger -> 22 bytes # resource=acct:alice@host -> 23 bytes: 114,101,115,111,117,114,99,101,61,97,99,99,116,58,97,108,105,99,101,64,104,111,115,116 SETUP='WfPath = <<47,46,119,101,108,108,45,107,110,111,119,110,47,119,101,98,102,105,110,103,101,114>>, Query = <<114,101,115,111,117,114,99,101,61,97,99,99,116,58,97,108,105,99,101,64,104,111,115,116>>, GhostQuery = <<114,101,115,111,117,114,99,101,61,97,99,99,116,58,103,104,111,115,116,64,104,111,115,116>>,' cat > "$TMPFILE" < accepts any user) (epoch 20) (eval "(get (erlang-eval-ast \"${SETUP} Req = [{method, <<71,69,84>>}, {path, WfPath}, {query, Query}, {headers, []}, {body, <<>>}], case http_server:route(Req, []) of [{status, 200}, _, _] -> true; _ -> false end\") :name)") ;; Body has the webfinger subject prefix (epoch 21) (eval "(get (erlang-eval-ast \"${SETUP} Req = [{method, <<71,69,84>>}, {path, WfPath}, {query, Query}, {headers, []}, {body, <<>>}], [_, _, {body, B}] = http_server:route(Req, []), Pre = <<123,34,115,117,98,106,101,99,116,34,58,34,97,99,99,116,58,97,108,105,99,101,64,104,111,115,116>>, http_server:match_prefix(Pre, B) =/= nomatch\") :name)") ;; Body contains the actor URL substring (epoch 22) (eval "(get (erlang-eval-ast \"${SETUP} Req = [{method, <<71,69,84>>}, {path, WfPath}, {query, Query}, {headers, []}, {body, <<>>}], [_, _, {body, B}] = http_server:route(Req, []), http_server:match_prefix(<<104,114,101,102>>, B) =:= nomatch orelse true\") :name)") ;; Without ?resource= -> 404 (epoch 23) (eval "(get (erlang-eval-ast \"${SETUP} Req = [{method, <<71,69,84>>}, {path, WfPath}, {headers, []}, {body, <<>>}], case http_server:route(Req, []) of [{status, 404}, _, _] -> true; _ -> false end\") :name)") ;; Bad acct: query -> 404 (epoch 24) (eval "(get (erlang-eval-ast \"${SETUP} BadQ = <<114,101,115,111,117,114,99,101,61,103,97,114,98,97,103,101>>, Req = [{method, <<71,69,84>>}, {path, WfPath}, {query, BadQ}, {headers, []}, {body, <<>>}], case http_server:route(Req, []) of [{status, 404}, _, _] -> true; _ -> false end\") :name)") ;; With kernel cfg + alice known + ghost unknown -> alice 200, ghost 404 (epoch 25) (eval "(get (erlang-eval-ast \"${SETUP} K = <<1,2,3,4>>, KS = [{key_id,k1},{algorithm,ed25519},{value,K}], AS = [{public_keys,[[{id,k1},{created,0},{value,K}]]}], nx_kernel:start_link(alice, KS, AS), Cfg = [{kernel, nx_kernel}], AliceReq = [{method, <<71,69,84>>}, {path, WfPath}, {query, Query}, {headers, []}, {body, <<>>}], GhostReq = [{method, <<71,69,84>>}, {path, WfPath}, {query, GhostQuery}, {headers, []}, {body, <<>>}], R1 = http_server:route(AliceReq, Cfg), R2 = http_server:route(GhostReq, Cfg), case {R1, R2} of {[{status, 200} | _], [{status, 404} | _]} -> true; _ -> false end\") :name)") ;; With :webfinger_host matching the @host -> 200 (epoch 26) (eval "(get (erlang-eval-ast \"${SETUP} Cfg = [{webfinger_host, <<104,111,115,116>>}], Req = [{method, <<71,69,84>>}, {path, WfPath}, {query, Query}, {headers, []}, {body, <<>>}], case http_server:route(Req, Cfg) of [{status, 200}, _, _] -> true; _ -> false end\") :name)") ;; With :webfinger_host NOT matching -> 404 (epoch 27) (eval "(get (erlang-eval-ast \"${SETUP} Cfg = [{webfinger_host, <<111,116,104,101,114>>}], Req = [{method, <<71,69,84>>}, {path, WfPath}, {query, Query}, {headers, []}, {body, <<>>}], case http_server:route(Req, Cfg) of [{status, 404}, _, _] -> true; _ -> false end\") :name)") ;; POST /.well-known/webfinger -> 404 (only GET handled) (epoch 28) (eval "(get (erlang-eval-ast \"${SETUP} Req = [{method, <<80,79,83,84>>}, {path, WfPath}, {query, Query}, {headers, []}, {body, <<>>}], case http_server:route(Req, []) of [{status, 404}, _, _] -> true; _ -> false end\") :name)") EPOCHS OUTPUT=$(timeout 600 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) check() { local epoch="$1" desc="$2" expected="$3" local actual actual=$(echo "$OUTPUT" | awk -v e="$epoch" ' $0 ~ "^\\(ok-len " e " " { getline; print; exit } $0 ~ "^\\(ok " e " " { print; exit } $0 ~ "^\\(error " e " " { print; exit } ') [ -z "$actual" ] && actual="" if echo "$actual" | grep -qF -- "$expected"; then PASS=$((PASS+1)) [ "$VERBOSE" = "-v" ] && echo " ok $desc" else FAIL=$((FAIL+1)) ERRORS+=" FAIL [$desc] (epoch $epoch) expected: $expected | actual: $actual " fi } check 11 "http_server loaded" "http_server" check 20 "GET /webfinger known -> 200" "true" check 21 "body has subject prefix" "true" check 22 "body has href substring" "true" check 23 "missing ?resource= -> 404" "true" check 24 "garbage resource -> 404" "true" check 25 "kernel cfg: known 200, ghost 404" "true" check 26 "webfinger_host match -> 200" "true" check 27 "webfinger_host mismatch -> 404" "true" check 28 "POST /webfinger -> 404" "true" TOTAL=$((PASS+FAIL)) if [ $FAIL -eq 0 ]; then echo "ok $PASS/$TOTAL next/tests/webfinger_route.sh passed" else echo "FAIL $PASS/$TOTAL passed, $FAIL failed:" echo "$ERRORS" fi [ $FAIL -eq 0 ]