ActivityPub
W3C に勧告された仕様
分散型ソーシャル・ネットワークを実現するプロトコル
アクター間で Activity Streams 2.0 (AS2) 形式のデータを HTTPS プロトコルでやり取りする
MIME application/ld+json; profile="https://www.w3.org/ns/activitystreams"
HTTPS リクエストの Accept ヘッダやレスポンスの Content-Type ヘッダでは、この MIME 型を指定する
ActivityPub 仕様の読み方
1, 2 章が序論
3〜5 章がデータモデル
6 章が Client to Server Interactions
7 章が Server to Server Interactions
Fediverse に参加するサーバの作成が目的なら 6 章は飛ばしていい
7 章に連合プロトコルについて書かれている
AS2 は W3C に勧告された仕様で、ソーシャル・ネットワークで使われている様々な語彙を、JSON-LD という JSON ベースの仕様を利用して定めている
AS2, JSON-LD は大きな仕様だが、Fediverse に参加するために必須の要素は一部だけ
code: AS2で表現されたオブジェクトの例.json
{
"type": "follow",
}
@context 属性は JSON-LD に特有の属性
XML における名前空間とスキーマに相当する
id 属性:ネットワーク全体でユニークとなる URL 形式の文字列
type 属性:オブジェクトの型
HTTP Signatures
ActivityPub 通信の検証プロトコル
あるアクターから他のアクターへの通知は HTTPS プロトコルの POST メソッドを使う
アクターのなりすましを防ぐために、通知が正当なものであるかを検証する手法が必要
ActivityPub ではどのような手法を用いるか定めていない
各アクターは鍵ペアを持つ
オブジェクトの送信時には秘密鍵を使ってリクエストに署名し、それを HTTP ヘッダの Signature フィールドに指定してリクエストを送信する
受信側は送信アクターの公開鍵を取得して署名を検証し、成功したもののみを正当なリクエストとして受け取る
ユーザーはサーバ上のアカウントを通して actor として表現される
異なるサーバのユーザーアカウントはそれぞれ異なった actor に対応する
すべての actor は次のものをもつ:
inbox:世界中からメッセージを受け取る場所
outbox:他へメッセージを送る場所
inbox, outbox は、実際には ActivityStreams 記述にある単なる URL
code: example.json
{
"type": "Person",
"name": "Alyssa P. Hacker",
"preferredUsername": "alyssa",
"summary": "List enthusiast hailing from MIT",
}
ActivityStreams ソーシャル・ネットワークに関する様々な語彙を含んでいるが、足りなければ JSON-LD で拡張できる
actor ←(GET)⏤ inbox ←(POST)⏤ 他の世界
他の世界の actor はメッセージを送信する (連合)
actor は新着メッセージを取得する
actor ⏤(POST)→ outbox ⏤(GET)→ 他の世界
actor はメッセージを送信する
他の世界の actor はメッセージを取得できる
Alyssa は Ben に向けた note を自身の outbox に POST する
code: example2.json
{
"type": "Note",
"content": "Say, did you finish reading that book I lent you?"
}
これは非アクティビティ・オブジェクトなので、サーバはこれを新しく生成されたオブジェクトと認識し、Create アクティビティに wrap したうえで、Ben の inbox エンドポイントを見つけてそこに POST する
code:example3.json
{
"type": "Create",
"object": {
"type": "Note",
"content": "Say, did you finish reading that book I lent you?"
}
}
Alyssa's outbox → Ben's inbox
これは2ステップに分割されている
クライアントからサーバへの通信
サーバからサーバへの通信(連合)
Alyssa は新着メッセージをチェックするために自分の inbox を GET でポーリングしていて以下のメッセージを見つけた
code: example4.json
{
"type": "Create",
"object": {
"type": "Note",
"content": "Argh, yeah, sorry, I'll get it back to you tomorrow. I was reviewing the section on register machines, since it's been a while I wrote one."
}
}
Alyssa は Ben の投稿に「いいね」するために以下を自分の outbox に POST する
これはアクティビティなので、Create オブジェクトで wrap する必要はない
code:example5.json
{
"type": "Like",
}
Alyssa は自分のフォロワー全員に公開メッセージを投稿する
code: example6.json
{
"type": "Create",
"to": [
],
"object": {
"type": "Note",
"to": [
],
"content": "Lending books to friends is nice. Getting them back is even nicer! :)"
}
}
アクテビティを受信したら、その内容が不正確ではないことを署名検証等の方法で確認すべきである
オブジェクト識別子
ActivityStreams の全てのオブジェクトにはユニークなグローバル識別子を付けるべきとされている
ActivityPub はこの要求を拡張する
ActivityPub でプロトコルで配布される全てのオブジェクトは、意図的に一時的なものでない限り、ユニークなグローバル識別子を持たなければならない (MUST)
サーバからサーバへの通信で投稿するアクテビティでは、アクテビティが意図的に一時的なものでない限り、識別子を提供しなければならない (MUST)
クライアントからサーバへの通信では、id 指定なしに outbox に投稿されたサーバは、その actor の名前空間の ID を割り当てて、投稿されたオブジェクトにその id を添付すべきである (SHOULD)
オブジェクトの取得
HTTP GET メソッドは、アクテビティを取得するためのオブジェクトの id 属性として展開されることがある
リクエストに対するレスポンスのデータの種類を選択するために、HTTP content negotiation を使っても良い (MAY)
application/ld+json; profile="https://www.w3.org/ns/activitystreams" に ActivityStreams オブジェクトを返さなければならない (MUST)
application/activity+json にも ActivityStreams を返すべきである (SHOULD)
クライアントはアクティビティを取得するために Accept ヘッダに application/ld+json; profile="https://www.w3.org/ns/activitystreams" メディアタイプをしなければならない (MUST)
サーバは前述した要求に従わないリクエストに対して他の振る舞いを実装しても良い (MAY)
サーバは B.1 認証と認可 で指定された認証を要求したり、独自の認証規則を実装したりしても良い (MAY)
サーバは、認証チェックを通過しなかったリクエストに対して適切な HTTP エラーコードか、オブジェクトの存在がプライベートなものと考えられる場合は 403 Forbidden エラーコードで失敗すべきである (SHOULD)
プライベートターゲットの存在を公開したくない配信元サーバは、代わりに 404 Not Found のステータスコードを返してもいい (MAY)
Activity Streams では Linked Data Signature を用いたオブジェクトへの署名と検証を行うことが推奨されている
code:example8.json
{
"@context": [
{ "@language": "en" }
],
"type": "Note",
"content": "<p>I <em>really</em> like strawberries!</p>"
"source": {
"content": "I *really* like strawberries!",
"mediaType": "text/markdown"
}
}