Bash と Caddy サーバで ActivityPub のインスタンス(11) アナウンス(ブースト)する

## アナウンス？
Mastodon で言うブースト。昔ツイッターと呼ばれてたアレでリツイートと呼ばれてたアレ。

## announce.json を作る
アナウンスしたい投稿の ID が
`https://あるインスタンス/users/foobar/statuses/11177839`
ならば
```json
{
  "@context": "https://www.w3.org/ns/activitystreams",
  "id": "https://ホニャララ/users/aktor/statuses/7836/activity",
  "type": "Announce",
  "actor": "https://ホニャララ/users/aktor",
  "published": "2024-01-17T14:27:18Z",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "cc": [
    "https://あるインスタンス/users/foobar",
    "https://ホニャララ/users/aktor/followers"
  ],
  "object": "https://あるインスタンス/users/foobar/statuses/11177839"
}
```

このようになる。"cc" タグから分かるように、アナウンスする投稿の投稿者と、自分のフォロワーに配送しなければならない。なので announce.json は
```json:announce.json
{
  "@context": "https://www.w3.org/ns/activitystreams",
  "id": "https://{my_instance}/users/{myself}/statuses/{id}/activity",
  "type": "Announce",
  "actor": "https://{my_instance}/users/{myself}",
  "published": "{date_now}",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "cc": [
    "{URL}",
    "https://{my_instance}/users/{myself}/followers"
  ],
  "object": "{id_of_announce}"
}
```

となる。{id_of_announce} にはアナウンスする投稿の ID を直接入れる。投稿の ID はブラウザから知りたい場合、 Mastodon ならばその投稿をクリックして現れる https://インスタンス/@アクター名/123456 に .json を付けた https://インスタンス/@アクター名/123456.json で表示される json の id タグの値であり、Misskey 系ならばその投稿の三点リーダーのようなマーク「もっと」をクリックして「共有」タブから「リンクをコピー」でコピーできる。

## announce.sh の作成
ほぼ reply.sh と同じである。というかそれより簡単。
```bash:reply.sh
#!/bin/bash


read -p "@myself@my_instance: " MY
MY_arry=(${MY//@/ })
myself=${MY_arry[0]}
my_instance=${MY_arry[1]}
echo

read -p "@to@to_instance: " TO
TO_arry=(${TO//@/ })
to=${TO_arry[0]}
to_instance=${TO_arry[1]}
echo

read -p "which id wanna announce?: " id_of_announce
echo


URL=$(curl https://$to_instance/.well-known/webfinger?resource=acct:$to@$to_instance | jq -r '.links[] | select (.rel == "self")'.href | tr -d "\"")
INBOX=$(curl -H "Accept: application/activity+json" $URL | jq .inbox | tr -d "\"")
REQUEST_TARGET=$(echo  "/"$(sed -E 's/^.*(https):\/\/([^/]+).([^/]+)/\3/g' <<< $INBOX))

unixtime=$(date "+%s")
date_now=$(date -uR  | head -c -6 | sed -e 's/$/GMT/')

sed -e "s/{id}/$unixtime/g" ./json_templates/announce.json > live
sed -i "s/{myself}/$myself/g" live
sed -i "s/{my_instance}/$my_instance/g" live
sed -i "s/{to}/$to/g" live
sed -i "s/{to_instance}/$to_instance/g" live
sed -i "s/{date_now}/$date_now/g" live
sed -i "s|{URL}|$URL|g" live
sed -i "s|{id_of_announce}|$id_of_announce|g" live

body=$(cat live | jq -c .)
digest_val=$(echo -n "$body" | sha256sum | xxd -r -p | base64)


while read -r line; do
	followers_inbox_URL+=( $(echo $line) )
done < followers

## followers_inbox_URL 配列に reply する相手がいなかったら追加
if echo "${followers_inbox_URL[*]}" | grep -qw "$INBOX"; then
	:
else
	followers_inbox_URL+=($INBOX)
fi

for INBOX in ${followers_inbox_URL[*]}; do

	to_instance=$(sed -E 's/^.*(http|https):\/\/([^/]+).*/\2/g' <<< $INBOX)
	REQUEST_TARGET=$(echo "/"$(sed -E 's/^.*(http|https):\/\/([^/]+).([^/]+)/\3/g' <<< $INBOX))

	signature_headers="(request-target): post ${REQUEST_TARGET}\ndate: ${date_now}\nhost: ${to_instance}\ndigest: SHA-256=${digest_val}"
	echo -e "$signature_headers" > 4_sig_headers # 後に見返すためにファイルに
	sig_val=$(echo -en $signature_headers | openssl dgst -binary -sign ./personal/private -sha256 | openssl enc -A -base64)
	signature="Signature: keyId=\"https://${my_instance}/users/${myself}#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) date host digest\",signature=\"$sig_val\""

	curl -H "Date: $date_now" -H "Digest: SHA-256=$digest_val" -H "$signature" $INBOX -d "$body"

done

echo $body > ./post/$unixtime
```
```
bash ./scripts/announce.sh
@myself@my_instance: @aktor@ホニャララ

@to@to_instance: @アナウンスしたい投稿者のインスタンス@投稿者

which id wanna announce?: https://アナウンスしたい投稿者のインスタンス/users/投稿者/statuses/111782670496639861(例)
```
と実行する。