Relays: PrivaPub reads from the relays its configuration names
Federation:Relays names relays by their actor (or inbox) address; the instance actor follows Public at each, as Mastodon subscribes, a minute after start and every six hours (asked again a day after no answer or a refusal, undone when a relay is no longer named). What an accepted relay passes on comes to the federated timeline and nobody's home: a public post it forwards (Activity-Relay), read again from its origin like any forwarded post, and a post it announces (aode-relay), kept as its author's and never as the relay's boost. Nothing of a persona's is sent to a relay; sending public posts there waits for the owner. The pasture gains both relays (peers/relay.sh, peers/aoderelay.sh) and scenarios/relay.sh, 13 checks. The village backlog is clean: 2574 checks pass, one known gap (Misskey's). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
1 parent
1c7d1ece9c
commit
f6fc0c535c
22 files changed
+542
-24
No files matched your search
@@ -108,6 +108,16 @@ nodebb.test {
|
||||
reverse_proxy pasture-nodebb:4567
|
||||
}
|
||||
|
||||
aoderelay.test {
|
||||
tls internal
|
||||
reverse_proxy pasture-aoderelay:8080
|
||||
}
|
||||
|
||||
relay.test {
|
||||
tls internal
|
||||
reverse_proxy pasture-relay-server:8080
|
||||
}
|
||||
|
||||
smithereen.test {
|
||||
tls internal
|
||||
handle /i/* {
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
"Federation": {
|
||||
"AllowPrivateNetworks": true,
|
||||
"AllowPlainHttp": true,
|
||||
"AcceptAnyCertificate": true
|
||||
"AcceptAnyCertificate": true,
|
||||
"Relays": [ "https://relay.test/actor", "https://aoderelay.test/actor" ]
|
||||
},
|
||||
"Media": { "Root": "/tmp/privapub-media" },
|
||||
"RateLimits": { "AccountsPerMinute": 1000 },
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# aode-relay 0.3.129 (asonix): a relay that takes both kinds of subscription (Public, as Mastodon follows, or its actor,
|
||||
# as LitePub does) and passes posts on as its own Announce, as aoderelay.test. Unrestricted, so anyone may subscribe;
|
||||
# its state is in its own sled database. Its TLS client reads the system's roots, over which the pasture's bundle goes.
|
||||
AODERELAY_IMAGE=${AODERELAY_IMAGE:-docker.io/asonix/relay:0.3.129}
|
||||
|
||||
aoderelay_up() {
|
||||
podman volume exists pasture-aoderelay || podman volume create --label pasture=1 pasture-aoderelay >/dev/null
|
||||
podman run -d --replace --name pasture-aoderelay --label pasture=1 --network $net -v pasture-aoderelay:/var/lib/aode-relay:U \
|
||||
-v "$ca/bundle.pem:/etc/ssl/certs/ca-certificates.crt:z,ro" \
|
||||
-e HOSTNAME=aoderelay.test -e ADDR=0.0.0.0 -e PORT=8080 -e HTTPS=true -e RESTRICTED_MODE=false -e VALIDATE_SIGNATURES=true \
|
||||
-e SLED_PATH=/var/lib/aode-relay/sled -e API_TOKEN=pasture-aoderelay-token -e PRETTY_LOG=false \
|
||||
$AODERELAY_IMAGE >/dev/null
|
||||
for _ in $(seq 1 60); do
|
||||
site aoderelay.test -s -o /dev/null -w '%{http_code}' https://aoderelay.test:6443/actor 2>/dev/null | grep -q 200 && break
|
||||
sleep 1
|
||||
done
|
||||
echo "aoderelay: https://aoderelay.test:6443"
|
||||
}
|
||||
|
||||
# aoderelay_connected: the hosts subscribed to it, from its admin API
|
||||
aoderelay_connected() { site aoderelay.test -s https://aoderelay.test:6443/api/v1/admin/connected -H 'X-Api-Token: pasture-aoderelay-token' | j "print('\n'.join(d.get('connected_actors', d) if isinstance(d, dict) else d))"; }
|
||||
@@ -0,0 +1,37 @@
|
||||
# Activity-Relay 2.0.9 (yukimochi): a Mastodon-style relay as relay.test. A server subscribes by following Public from an
|
||||
# actor with a shared inbox; the relay then passes on, signed with its own key, every public activity another subscriber
|
||||
# sends it (a LitePub-style follower, whose actor ends in /relay, gets an Announce instead). Its state is in the shared
|
||||
# Redis (database 13); its actor key is made once. Go trusts the bundle the pasture mounts over the system one.
|
||||
RELAY_IMAGE=${RELAY_IMAGE:-docker.io/yukimochi/activity-relay:v2.0.9}
|
||||
. "$here/peers/shared.sh"
|
||||
|
||||
relay_up() {
|
||||
shared_redis_up
|
||||
local st="$here/.state/relay"
|
||||
mkdir -p "$st"
|
||||
[ -s "$st/actor.pem" ] || openssl genrsa -traditional -out "$st/actor.pem" 2048 2>/dev/null
|
||||
chmod 644 "$st/actor.pem"
|
||||
cat > "$st/config.yml" <<-EOF
|
||||
ACTOR_PEM: /var/lib/relay/actor.pem
|
||||
REDIS_URL: redis://redis:6379/13
|
||||
RELAY_BIND: 0.0.0.0:8080
|
||||
RELAY_DOMAIN: relay.test
|
||||
RELAY_SERVICENAME: Pasture Relay
|
||||
JOB_CONCURRENCY: 10
|
||||
RELAY_ICON: https://relay.test/icon.png
|
||||
RELAY_IMAGE: https://relay.test/image.png
|
||||
EOF
|
||||
for role in server worker; do
|
||||
podman run -d --replace --name pasture-relay-$role --label pasture=1 --network $net \
|
||||
-v "$st:/var/lib/relay:z,ro" -v "$ca/bundle.pem:/etc/ssl/certs/ca-certificates.crt:z,ro" \
|
||||
$RELAY_IMAGE relay --config /var/lib/relay/config.yml $role >/dev/null
|
||||
done
|
||||
for _ in $(seq 1 60); do
|
||||
site relay.test -s -o /dev/null -w '%{http_code}' https://relay.test:6443/actor 2>/dev/null | grep -q 200 && break
|
||||
sleep 1
|
||||
done
|
||||
echo "relay: https://relay.test:6443"
|
||||
}
|
||||
|
||||
# relay_subscribers: the hosts subscribed to the relay, from its Redis
|
||||
relay_subscribers() { podman exec pasture-redis redis-cli -n 13 --raw keys 'relay:subscription:*' | sed 's/relay:subscription://'; }
|
||||
@@ -0,0 +1,56 @@
|
||||
# Relays as PrivaPub reads them (Federation:Relays in appsettings.Pasture.json): Activity-Relay, which forwards what its
|
||||
# subscribers send, and aode-relay, which announces it. For each, the instance actor subscribes, Mastodon subscribes too,
|
||||
# and a public post of a Mastodon account nobody here follows reaches PrivaPub's federated timeline through the relay;
|
||||
# nothing of a persona's goes to a relay. Mastodon leaves each relay after, so the town sees no relayed posts. Needs the
|
||||
# relay, aoderelay and mastodon peers.
|
||||
M=https://mastodon.test:6443
|
||||
mcurl() { curl -sk --resolve mastodon.test:6443:127.0.0.1 "$@"; }
|
||||
. "$here/peers/mastodon.sh"
|
||||
. "$here/peers/relay.sh"
|
||||
. "$here/peers/aoderelay.sh"
|
||||
p_relay_state() { podman exec pasture-mongo mongosh --quiet PrivaPub --eval 'var s=db.RelaySubscription.findOne({ActorURI:"https://'$1'/actor"}); print(s ? s.State : "none")'; }
|
||||
m_relay() { podman exec pasture-mastodon bin/rails runner 'r = Relay.find_or_create_by!(inbox_url: "https://'$1'/inbox"); r.enable! unless r.accepted? || r.pending?' >/dev/null 2>&1; }
|
||||
m_unrelay() { podman exec pasture-mastodon bin/rails runner 'Relay.where(inbox_url: "https://'$1'/inbox").each { |r| r.disable!; r.destroy }' >/dev/null 2>&1; }
|
||||
p_public_has() { [ "$(curl -s -H "$PH" "$P/api/v1/timelines/public?remote=true&limit=40" | j "print(any(s['uri'] == '$1' for s in d))")" = "True" ]; }
|
||||
# relayed_post <tag>: a public post of a fresh Mastodon account nobody here follows, by its uri
|
||||
relayed_post() {
|
||||
local who="$1$run"
|
||||
mastodon_user "$who"
|
||||
mcurl -X POST -H "Authorization: Bearer $(mastodon_token "$who")" "$M/api/v1/statuses" -d "status=a post only the $1 brings $run&visibility=public" | j "print(d['uri'])"
|
||||
}
|
||||
|
||||
echo "relay"
|
||||
PT=$(privapub_token alice_relay)
|
||||
PH="Authorization: Bearer $PT"
|
||||
[ -n "$PT" ] && ok "PrivaPub token for alice_relay" || { ko "PrivaPub token for alice_relay"; return 1; }
|
||||
run=$(date +%s)
|
||||
|
||||
echo " Activity-Relay"
|
||||
# PrivaPub subscribes a minute after it starts (and again six hours later while unanswered)
|
||||
until_true 60 'relay_subscribers | grep -qx privapub.test' && ok "PrivaPub's instance actor subscribes to Activity-Relay" || ko "PrivaPub never subscribed ($(relay_subscribers | tr '\n' ' '))"
|
||||
# (1 = Accepted)
|
||||
until_true 30 '[ "$(p_relay_state relay.test)" = "1" ]' && ok "and takes its Accept" || ko "PrivaPub's subscription is $(p_relay_state relay.test)"
|
||||
m_relay relay.test
|
||||
until_true 45 'relay_subscribers | grep -qx mastodon.test' && ok "Mastodon subscribes too" || ko "Mastodon never subscribed"
|
||||
s_uri=$(relayed_post relay)
|
||||
until_true 60 'p_public_has "$s_uri"' && ok "a public post of an account nobody here follows reaches the federated timeline, forwarded" || ko "the forwarded post never arrived"
|
||||
[ "$(curl -s -H "$PH" "$P/api/v1/timelines/home?limit=40" | j "print(any(s['uri'] == '$s_uri' for s in d))")" = "False" ] \
|
||||
&& ok "and no one's home" || ko "the relayed post landed in alice's home"
|
||||
p_post=$(curl -s -X POST -H "$PH" "$P/api/v1/statuses" -d "status=a PrivaPub post the relay never sees $run&visibility=public" | j "print(d['uri'])")
|
||||
sleep 5
|
||||
[ "$(podman exec pasture-mongo mongosh --quiet PrivaPub --eval 'print(db.Job.countDocuments({Host:"relay.test", Payload:/Create/}))')" = "0" ] \
|
||||
&& ok "nothing of a persona's goes to the relay" || ko "PrivaPub sent the relay a post"
|
||||
|
||||
m_unrelay relay.test
|
||||
until_true 45 '! relay_subscribers | grep -qx mastodon.test' && ok "Mastodon leaves Activity-Relay" || ko "Mastodon is still subscribed to Activity-Relay"
|
||||
|
||||
echo " aode-relay"
|
||||
until_true 30 '[ "$(p_relay_state aoderelay.test)" = "1" ]' && ok "PrivaPub's instance actor subscribes to aode-relay, which accepts" || ko "PrivaPub's aode-relay subscription is $(p_relay_state aoderelay.test)"
|
||||
m_relay aoderelay.test
|
||||
until_true 45 'aoderelay_connected | grep -q mastodon.test' && ok "Mastodon subscribes too" || ko "Mastodon never subscribed to aode-relay ($(aoderelay_connected | tr '\n' ' '))"
|
||||
a_uri=$(relayed_post aoderelay)
|
||||
until_true 60 'p_public_has "$a_uri"' && ok "a post aode-relay announces reaches the federated timeline as its author's" || ko "the announced post never arrived"
|
||||
[ "$(curl -s -H "$PH" "$P/api/v1/timelines/public?remote=true&limit=40" | j "print(any((s.get('reblog') or {}).get('uri') == '$a_uri' for s in d))")" = "False" ] \
|
||||
&& ok "never as the relay's boost" || ko "the relay's announce shows as a boost"
|
||||
m_unrelay aoderelay.test
|
||||
until_true 45 '! aoderelay_connected | grep -q mastodon.test' && ok "Mastodon leaves aode-relay" || ko "Mastodon is still subscribed to aode-relay"
|
||||
Reference in new issue
Block a user