Misskey 系と Mastodon 系の違い
- アクター名と アクターの ID が違う
- HTTP 署名で求められるヘッダが多い
アクター名とアクターの ID が違うというのは、例えばアクター名が foobar の場合、Mastodon 系ならばアクターの ID はそのまま foobar だが、Misskey 系はそれとは別にある程度ランダムな英数字の文字列が ID として割り振られている。アドレスとして
https://Misskey系インスタンス/@foobar
は
https://Misskey系インスタンス/users/ある程度ランダムな英数字の文字列
のエイリアス、というか、下のアドレスは上へリダイレクトされる。
なので webfinger を使って rel => self の href の値を求め、そのアドレスへヘッダに "Accept: application/activity+json" を加えて GET リクエストを送り、返ってくる json の inbox タグの値を求める必要がある。
URL=$(curl https://Misskey系インスタンス/.well-known/webfinger?resource=acct:foobar@Misskey系インスタンス | jq -r '.links[] | select (.rel == "self")'.href)
INBOX=$(curl -H "Accept: application/activity+json" $URL | jq .inbox)
Mastodon 系は(現時点では)ヘッダの Date Digest だけを \n で繋げて署名すれば良かったが、Misskey 系は request-target (POST タグの2番めまでの値。POST /users/foobar/inbox HTTP/1.1 ならば、"post /users/foobar/inbox") と Host も求められるようである。
やること
それ以外は前回とほぼ同じである。前回と違うのは上述の通り。
- webfinger にリクエストを送り、ID (URL) と inbox のアドレスを取得し
- request-target date host digest を \n で繋げたものに署名する
前回は引数で like する ID と、その投稿者の inbox を与えていたが、今回は上述の理由(インスタンスとアクター名を webfinger に入れてアクターの ID を取得しなければならない)のため、対話的に投稿者のインスタンスとアクター名、投稿の ID を入力することにする。ついでに自分のインスタンスとアクター名もここで指定することにする。
#!/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
# like したい投稿の ID を入力
read -p "which id do you wanna like?: " target_post
echo
unixtime=$(date "+%s")
# 投稿者のインスタンス・アクター名から URL と inbox を取得。また " を外しておく
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 は https://インスタンス 以下である(よって最初に "/" を付ける)
REQUEST_TARGET=$(echo "/"$(sed -E 's/^.*(https):\/\/([^/]+).([^/]+)/\3/g' <<< $INBOX))
sed -e "s/{id}/$unixtime/g" like.json > live
sed -i "s/{myself}/$myself/g" live
sed -i "s/{my_instance}/$my_instance/g" live
sed -i "s|{target_post}|$target_post|g" live
body=$(cat live | jq -c .)
digest_val=$(echo -n "$body" | sha256sum | xxd -r -p | base64)
date_now=$(date -uR | head -c -6 | sed -e 's/$/GMT/')
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"
基本は前回と変わらないが、微細な違いはコードとコメントを読んでいただきたい。
もちろん Mastodon 系の投稿にもこれで like できるので、以降このスクリプトを基本として他のアクティビティも書く。