公開後に報告されたエラーや問題については、正誤表をご確認ください。
また、 翻訳もご覧ください。
Copyright © 2018 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark and permissive document license rules apply.
ActivityPubプロトコルは、[ActivityStreams] 2.0データフォーマットに基づく分散型ソーシャルネットワーキングプロトコルです。 このプロトコルはコンテンツの作成・更新・削除のためのクライアントからサーバーへのAPIに加え、通知やコンテンツを配信する連合サーバー間APIも提供します。
このセクションでは、本書が公開された時点での文書のステータスについて説明します。ほかの文書が本書に取って代わる可能性があります。現在のW3Cの出版物一覧や、この技術報告書の最新版は、W3C 技術報告一覧(https://www.w3.org/TR/)で確認できます。
本書はSocial Web Working Groupによって勧告として発行されました。
興味のある方はどなたでも、ワーキンググループのIssue tracker で実装やバグ報告、その他コメントを提供できます。 これらはSocial Web Community Group で議論され、将来のこの仕様のバージョンで考慮されます。
ワーキンググループの 実装レポート も参照してください。
この文書はW3Cのメンバー、ソフトウェア開発者、その他W3Cグループや関係者によってレビューされ、ディレクターによりW3C勧告として承認されています。 安定した文書であり、参考資料として利用したり他の文書から引用したりできます。W3Cが勧告を発行する役割は、仕様に注目を集め、その広範な導入を促進する点にあります。これによりWebの機能と相互運用性が向上します。
この文書はW3C パテントポリシーのもとで運営されているグループによって作成されました。 W3Cは、グループの納品物に関連して公開特許開示リストを管理しています。 そのページには、特許開示の方法についての案内も記載されています。自らが実際に把握する特許が 必須クレームに含まれると考える場合は、 W3Cパテントポリシー第6節 に従い情報を開示しなければなりません。
この文書は、2017年3月1日 W3C プロセス文書に従って管理されています。
ActivityPubは2つのレイヤーを提供します:
ActivityPubの実装はこれらのいずれか一方、または両方を実装することができます。 ただし一方を実装したなら他方を実装するのもそれほど多くの手順はなく、どちらも実装することで(サイトを分散型ソーシャルウェブの一部とし、さまざまなソーシャルサービスに共通するクライアントやクライアントライブラリが利用できるなど)多くのメリットがあります。
ActivityPubにおいてユーザーはサーバ上のアカウントを通じて "アクター" として表現されます。 異なるサーバ上のユーザーアカウントは異なるアクターに対応します。 すべてのアクターは以下を持ちます:
inbox:外部からメッセージを受け取るためのものoutbox:他者にメッセージを送信するためのもの
これらはエンドポイント、つまり実体としてはActivityPubアクターのActivityStreams記述にリストされるURLです。 (ActivityStreamsについては後述)
以下は友人Alyssa P. Hackerのレコード例です:
{"@context": "https://www.w3.org/ns/activitystreams",
"type": "Person",
"id": "https://social.example/alyssa/",
"name": "Alyssa P. Hacker",
"preferredUsername": "alyssa",
"summary": "Lisp愛好家、MIT出身",
"inbox": "https://social.example/alyssa/inbox/",
"outbox": "https://social.example/alyssa/outbox/",
"followers": "https://social.example/alyssa/followers/",
"following": "https://social.example/alyssa/following/",
"liked": "https://social.example/alyssa/liked/"}
ActivityPubは語彙として[ActivityStreams]を利用します。 これはとても便利で、ActivityStreamsはソーシャルネットワークを流れる全てのアクションやコンテンツを表現するために必要な共通用語を網羅しています。 おそらくActivityStreamsは必要な語彙を既に持っていますが、もしそうでなくても[JSON-LD]を使ってActivityStreamsを拡張できます。 JSON-LDを知っていれば、そのリンクドデータのアプローチの利点を活かせます。 知らなくても大丈夫です、JSON-LD文書やActivityStreamsは普通のシンプルなJSONとして理解できます。 (拡張したい場合にはJSON-LDが強力な助けとなります)
さて、Alyssaは友達とやりとりしたいし、友達もAlyssaとやりとりしたい! そんな時「inbox」と「outbox」が活躍します。 これらはGETとPOSTで動作が異なります。 どのように動くか見てみましょう:
では要点をまとめます:
もちろん、もし最後の(他人のoutboxからGETするだけ)が唯一のメッセージ閲覧手段だったら、これは効率のよい連合プロトコルになりません。 実際には、連合は通常サーバがアクターのメッセージを他サーバ上のアクターのinboxにPOSTすることで成立します。
例を見てみましょう! Alyssaが友人Ben Bitdiddleと連絡を取りたいとします。 彼女は最近Benに本を貸したので、返してほしいと思っています。 彼女が作成したActivityStreamsオブジェクトは次のようになります:
{"@context": "https://www.w3.org/ns/activitystreams",
"type": "Note",
"to": ["https://chatty.example/ben/"],
"attributedTo": "https://social.example/alyssa/",
"content": "ねえ、貸した本はもう読み終わった?"}
これはBen宛てのNoteです。 彼女はこれを自分のoutboxへPOSTします。
これはアクティビティ系オブジェクトではないので、サーバはこれは新規作成されたオブジェクトだと認識し、Createアクティビティでラップしてくれます。 (ActivityPubで送受信されるアクティビティはおおむね「誰かアクターが、何かオブジェクトについて、何らかの行為を行う」というパターンをたどります。ここではPersonがNoteオブジェクトをCreateするアクティビティです。)
{"@context": "https://www.w3.org/ns/activitystreams",
"type": "Create",
"id": "https://social.example/alyssa/posts/a29a6843-9feb-4c74-a7f7-081b9c9201d3",
"to": ["https://chatty.example/ben/"],
"actor": "https://social.example/alyssa/",
"object": {"type": "Note",
"id": "https://social.example/alyssa/posts/49e2d03d-b53a-4c4c-a95c-94a6abf45a19",
"attributedTo": "https://social.example/alyssa/",
"to": ["https://chatty.example/ben/"],
"content": "ねえ、貸した本はもう読み終わった?"}}
AlyssaのサーバはBenのActivityStreamsアクターオブジェクトとそのinboxエンドポイントを探し、BenのinboxへこのオブジェクトをPOSTします。
技術的にはこれは2つの独立したステップです……ひとつはクライアントからサーバへの通信、もうひとつはサーバ間の通信(連合)。 ですが、この例では両方使っているので、「outboxからinboxへのスムーズな流れ」と抽象化して考えられます:
やったね! しばらくしてAlyssaは新着メッセージを確認します。 彼女のスマホがinboxをGETしてチェックすると、友人たちの猫動画や妹が投稿した甥っ子の写真と一緒に、こんなレスが届いています:
{"@context": "https://www.w3.org/ns/activitystreams",
"type": "Create",
"id": "https://chatty.example/ben/p/51086",
"to": ["https://social.example/alyssa/"],
"actor": "https://chatty.example/ben/",
"object": {"type": "Note",
"id": "https://chatty.example/ben/p/51085",
"attributedTo": "https://chatty.example/ben/",
"to": ["https://social.example/alyssa/"],
"inReplyTo": "https://social.example/alyssa/posts/49e2d03d-b53a-4c4c-a95c-94a6abf45a19",
"content": "<p>あー、ごめん!明日返すよ。</p>
<p>最近レジスタマシンのセクションを見直してたんだ。作ったのは久しぶりだったからさ。</p>"}}
Alyssaはホッとして、Benの投稿に「Like」します:
{"@context": "https://www.w3.org/ns/activitystreams",
"type": "Like",
"id": "https://social.example/alyssa/posts/5312e10e-5110-42e5-a09b-934882b3ecec",
"to": ["https://chatty.example/ben/"],
"actor": "https://social.example/alyssa/",
"object": "https://chatty.example/ben/p/51086"}
Alyssaはこのメッセージを自分のoutboxへPOSTします。 (これはアクティビティなので、サーバ側はCreateでラップする必要がないと判断します。)
満足したAlyssaは、フォロワー全員に向けて公開メッセージを投稿することにします。 まもなく彼女のfollowersコレクション全員に加え、特別なPublicグループも宛先に含まれているため、基本的に誰でも読める形で次のメッセージが配信されます。
{"@context": "https://www.w3.org/ns/activitystreams",
"type": "Create",
"id": "https://social.example/alyssa/posts/9282e9cc-14d0-42b3-a758-d6aeca6c876b",
"to": ["https://social.example/alyssa/followers/",
"https://www.w3.org/ns/activitystreams#Public"],
"actor": "https://social.example/alyssa/",
"object": {"type": "Note",
"id": "https://social.example/alyssa/posts/d18c55d4-8a63-4181-9745-4e6cf7938fa1",
"attributedTo": "https://social.example/alyssa/",
"to": ["https://social.example/alyssa/followers/",
"https://www.w3.org/ns/activitystreams#Public"],
"content": "友達に本を貸すのは良いこと。返してもらえるともっと良い! :)"}}
非規範的と明記されたセクション以外にも、この仕様のすべての著述ガイドライン、図、例、および注記は非規範的です。それ以外のこの仕様の内容はすべて規範的です。
この仕様内の MAY, MUST, MUST NOT, SHOULD, SHOULD NOT というキーワードは[RFC2119]で示される意味として解釈されます。
この仕様は2つの密接に関連し相互に作用するプロトコルを定義します:
ActivityPub仕様は、このいずれか片方を実装した後で、もう一方もほとんど手間なく追加できるよう設計されています。 ただしサーバは片方だけ実装しても問題ありません。 このため、以下の3つの適合クラスが定義されます:
仕様の一部が連合プロトコルの実装時のみに適用される場合、このことが明確に示されます。 また要件指定時は、それがクライアント/サーバ(クライアントからサーバプロトコル)に該当するのか、 サーバ間プロトコルの送信サーバ/受信サーバに該当するのか明示されます。
オブジェクトは、[ActivityStreams]および ActivityPubが構築される中心概念です。 オブジェクトは多くの場合アクティビティでラップされ、ストリームとしてコレクションに含まれます。そしてコレクション自体もオブジェクトのサブクラスです。 詳細は[Activity-Vocabulary]ドキュメント、特に コアクラスを参照してください。 ActivityPubはこの語彙の割り当てを忠実に踏襲しています。
ActivityPubはActivityStreamsで提供される用語に加えて、いくつかの用語を定義します。
それらはActivityPub
JSON-LDコンテキスト
https://www.w3.org/ns/activitystreams
で提供されます。
実装者はオブジェクト定義にActivityPubコンテキストを含めるべきです。
必要に応じて追加のコンテキストを含めても構いません。
ActivityPubは ActivityStreamsと同じURI/IRI慣例 を共有します。
サーバは受信したコンテンツの検証を行うべきです。これはコンテンツのなりすまし攻撃を避けるためです。 (サーバは少なくとも、オブジェクトが送信元で受信時と同じものであるかチェックすべきですが、署名検証などが利用できるなら、そちらの方がより堅牢です。) この文書では検証メカニズムは明示的に定めませんが、セキュリティの考慮事項に良い手法例がありますので参照ください。
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Like",
"actor": "https://example.net/~mallory",
"to": ["https://hatchat.example/sarah/",
"https://example.com/peeps/john/"],
"object": {
"@context": {"@language": "en"},
"id": "https://example.org/~alice/note/23",
"type": "Note",
"attributedTo": "https://example.org/~alice",
"content": "I'm a goat"
}
}
idの参照先にアクセスし、それが存在し有効なオブジェクトか、また内容が偽装されていないかも確認すべきです。
(この例ではMalloryがAliceの名前でオブジェクトを偽装しようとしている可能性があります。)
[ActivityStreams]の全オブジェクトはグローバルに一意な識別子を持つべきです。 ActivityPubはこの要件を拡張し、ActivityPubプロトコルで配信される全オブジェクトは、意図的に一時的なもの(チャットやゲーム通知のように参照を意図しない短命アクティビティ)を除き、グローバルに一意な識別子が必須となります。 識別子は以下のいずれかに該当する必要があります:
nullとして明示的に指定されたID、つまり匿名オブジェクト(親コンテキストの一部)
サーバ間連携で配信されるアクティビティには、意図的に一時的でない限り識別子が必須です。 ただしクライアントからサーバへの通信では、outboxにID指定無しで投稿されたオブジェクトを受信するサーバは、アクターの名前空間内でIDを割り当ててオブジェクトに付与すべきです。
全オブジェクトは次のプロパティを持ちます:
HTTP GETメソッドは、オブジェクトのidプロパティに対して発行することで、そのアクティビティを取得できます。
サーバは、[RFC7231]で定義されるHTTPコンテンツネゴシエーションを利用してもよいですが、
application/ld+json; profile="https://www.w3.org/ns/activitystreams"
でリクエストされた場合は必ず
ActivityStreamsオブジェクト表現を返す必要があります。
またapplication/activity+jsonでもActivityStreams表現を返すべきです。
クライアントはアクティビティを取得するため、Acceptヘッダーで
application/ld+json; profile="https://www.w3.org/ns/activitystreams"
メディアタイプを必ず指定しなければなりません。
上記要件に従わないリクエストへの対処として、サーバはその他動作も実装できます。 (例:追加のレガシープロトコルの実装や、同一URIでHTMLとActivityStreamsの両方の表現を使い分ける場合など)
サーバは認可をB.1 認証と認可に従って要求することもできますし、独自の認可ルールも実装可能です。 認可チェック不合格のリクエストは適切なHTTPエラーコード、または存在自体を秘匿したい場合は403 Forbiddenエラーで拒否すべきです。 存在自体が秘匿されるべきとサーバが判断した場合は、404 Not Foundでレスポンスしてもよいです。
[Activity-Vocabulary]で定義されたすべてのプロパティに加えて、ActivityPubはObjectにsourceプロパティを拡張します。
sourceは、contentマークアップの由来を示す情報や証跡、将来の編集機能サポートなどを伝える用途のためのものです。
一般に、source→contentへの変換はクライアントが担い、逆は行いません。
sourceの値はオブジェクトで、content および mediaType フィールドを使い元情報を与えます。
{
"@context": ["https://www.w3.org/ns/activitystreams",
{"@language": "en"}],
"type": "Note",
"id": "http://postparty.example/p/2415",
"content": "<p>I <em>really</em> like strawberries!</p>",
"source": {
"content": "I *really* like strawberries!",
"mediaType": "text/markdown"}
}
一般的には、ユーザーが最初に作成した元の投稿を、それと同じソース形式で編集できるのが最適です。
ただし全てのクライアントがあらゆるソースタイプに対して良いUIを提供できるわけではありません。
クライアントはsource→contentの変換を担う前提なので、あるクライアントが対応しているmediaTypeでも他のクライアントが扱えない場合があります。
クライアントがcontentマークアップのみ編集用に提供しsourceを無視することも可能ですが、その場合、将来の修正時に元のsource形式が失われてしまうことになります。
こうした場合、クライアントは元のソース形式を認識できず無視する旨、できるだけ控えめな警告を表示するのが望ましいです。
例として、Alyssa P. Hackerは自作のEmacsクライアントと
Org modeを使い、ActivityPub対応ブログへ投稿しています。
後日、スマホクライアントから編集しようとしますが、そのクライアントはtext/x-orgを知らずHTMLへの変換にも対応していないので、元のcontent編集用テキストボックスのみ表示されます。
編集画面の上部には「この投稿は元々対応していないマークアップ形式で書かれています。編集すると元のソースが失われます」といった警告が表示されます。
Alyssaは小さなタイプミスを直すためだけにorg-modeマークアップを失うのは惜しいと考え、自宅で修正することにしました。
ActivityPubのアクターは一般的には
ActivityStreams アクター型
のいずれかですが、必ずしもそうである必要はありません。例えば
Profileオブジェクト
をアクターとして使ってもいいですし、ActivityStreamsの拡張タイプを使っても構いません。
アクターは、ActivityPub内の他のオブジェクト同様に取得されます。
他のActivityStreamsオブジェクトと同じように、アクターもid(URI)を持ちます。
このidを(例えばログインフォームのようなUIで)直接入力する場合、より簡易な名前表記のサポートが望ましいです。
このため、IDの正規化を以下のように推奨します:
example.org/alice/ など)で、
通常であれば有効URIとなりうる場合、クライアントはデフォルトスキーム(できればhttps)の自動補完を試みてもよい。
アクターのURIが特定できたら、それをデリファレンス(参照)すべきです。
アクターオブジェクトは3.1 オブジェクト識別子の必須プロパティに加えて、以下のプロパティを必ず持たなければなりません:
OrderedCollection
への参照。詳しくは
5.2 Inbox
を参照。
OrderedCollection
への参照。詳しくは
5.1 Outbox
を参照。
実装は、さらに次のプロパティも提供することが望ましいです:
実装は、さらに次のプロパティも任意で提供できます:
{
"@context": ["https://www.w3.org/ns/activitystreams",
{"@language": "ja"}],
"type": "Person",
"id": "https://kenzoishii.example.com/",
"following": "https://kenzoishii.example.com/following.json",
"followers": "https://kenzoishii.example.com/followers.json",
"liked": "https://kenzoishii.example.com/liked.json",
"inbox": "https://kenzoishii.example.com/inbox.json",
"outbox": "https://kenzoishii.example.com/feed.json",
"preferredUsername": "kenzoishii",
"name": "石井健蔵",
"summary": "この方はただの例です",
"icon": [
"https://kenzoishii.example.com/image/165987aklre4"
]
}
実装は、さらに次のプロパティも任意で提供できます:
endpointsマッピングには、以下のプロパティを含めてもよいです:
x-www-form-urlencodedのidパラメータに、取得したいActivityStreamsオブジェクトのidを指定してPOSTします。
sharedInboxエンドポイントは、Public特別コレクション宛のオブジェクトを収めた
公開読み取り可能なOrderedCollectionオブジェクトとしてもあるべきです。
sharedInboxへのGETでは、Public宛でないオブジェクトは絶対に表示してはいけません。
ActivityPubの上流語彙である [ActivityStreams] の あらゆるプロパティはActivityPubアクターにも利用可能です。 とくにActivityPub実装でどのように使われるか示す目的で、いくつかのActivityStreamsプロパティは強調して紹介されます。
idと異なる場合)。
name、preferredUsername、summary など
自然言語値を含むプロパティは
ActivityStreamsで定義された自然言語サポートを利用します。
[ActivityStreams] はコレクションという概念を定義していますが、ActivityPubは特別な振る舞いを持ついくつかのコレクションも定義します。 ActivityPubは ActivityStreamsのページング を利用して大量のオブジェクトを巡回することができます。
これらコレクションの一部は
OrderedCollection
型である必要が明記されていますが、他は
Collection
または
OrderedCollection
のいずれかでも構いません。
OrderedCollection
は常に逆時系列(新しいものが先)で一貫して提示されなければなりません。
どのプロパティで逆時系列順を判定するかは実装詳細として意図的に規定しません。 多くのSQL型データベースではインクリメントする整数IDを利用し、たいていの場面で挿入順の管理に用いられます。 他のデータベースでは挿入時タイムスタンプの方が好まれるかもしれません。 何を使うかは重要ではありませんが、要素の順序は必ず新しいものが先に来るよう維持しなければなりません。 「最終更新時刻」など頻繁に変化するプロパティは使用しないで下さい。
Outboxはアクターのプロフィールのoutboxプロパティによって発見されます。
outboxは必ず
OrderedCollectionでなければなりません。
Outboxストリームはユーザーが公開したアクティビティを含みますが、これはリクエスタがそのアクティビティを取得できる権限を持っている場合に限ります(つまり、Outboxの内容は閲覧者の権限によってフィルタされます)。 ユーザーが認可無しでリクエストした場合、サーバはすべての公開宛の投稿を返すべきです。 これは当該ユーザーによる公開済みオブジェクトの全てとなる可能性もありますが、何件返すかはサーバ実装者の裁量に委ねられます。
OutboxはHTTP POSTリクエストも受け付け、その挙動はクライアントとサーバーのやりとりセクションで説明されています。
Inboxはアクターのプロフィールのinboxプロパティによって発見されます。
inboxは必ず
OrderedCollectionでなければなりません。
Inboxストリームはアクターが受信したすべてのアクティビティを含みます。 サーバはリクエスタの権限に応じて内容をフィルタするべきです。 一般的にInbox所有者はInboxの内容全てにアクセス可能ですが、アクセス制御によって他者には公開/非公開が分かれ、認証無しの利用者にはアクセスできない場合もあります。
サーバはInbox内で返すアクティビティの重複排除を必ず行う必要があります。たとえば1つのアクティビティがアクターのフォロワー全員ならびに特定のアクター(そのアクターもフォロワーである)の両方に宛てられた場合で、サーバが受取人リストの重複排除に失敗した場合などです。
この重複排除は、アクティビティのidを比較し、すでに見たものは除外することで必ず 行います。
連合サーバ上のアクターのInboxはHTTP POSTリクエストも受け付け、その挙動は配信セクションで説明されています。 非連合サーバはPOSTリクエストを受け取った場合405 Method Not Allowedを返すべきです。
すべてのアクターはフォロワーコレクションfollowersを持つべきです。
これは、そのアクターにFollowアクティビティを送信した全ての人の一覧であり、
副作用として追加されます。
ここでアクターをフォローしている全アクターのリストが取得できます。
followersコレクションは必ず
OrderedCollection
または
Collection
でなければならず、さらに認証ユーザの特権や認証なしの場合の適宜な条件でフィルタ可能です。
Followアクティビティは一般的にアクターの作成したオブジェクトを見るリクエストとして扱われます。したがって、Followersコレクションは通知配信時のデフォルトターゲットとして適切です。
各アクターはfollowingコレクションを持つべきです。
これはアクターがフォローした全員のリストであり、副作用として追加されます。
followingコレクションは必ず
OrderedCollection
または
Collection
でなければならず、必要に応じて認証ユーザの特権によるフィルタや認証無し時の適切な制限が施されてもよいです。
各アクターはlikedコレクションを持ってもよいです。
これは、アクターが行った全てのLikeアクティビティの対象オブジェクトのリストであり、
副作用として追加されます。
likedコレクションは必ず
OrderedCollection
または
Collection
でなければならず、必要に応じて認証ユーザの特権によるフィルタや認証無し時の制限が加わってもよいです。
[ActivityStreams]コレクションやオブジェクトに加え、
アクティビティは特別な「公開(public)」コレクションhttps://www.w3.org/ns/activitystreams#Public宛てにも送ることができます。
例:
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://www.w3.org/ns/activitystreams#Public",
"type": "Collection"
}
この特別なURI宛てのアクティビティは、すべてのユーザーが認証無しでアクセス可能でなければなりません。
実装は「public」特別コレクションへの配信を行ってはいけません;
ここは実際のアクティビティを受理できません。
ただし、アクターは
sharedInboxエンドポイントを持てます。
これは公開投稿やフォロワー宛投稿の効率的な共有配信用であり、詳しくは
7.1.3 共有Inbox配信 を参照してください。
ActivityStreamsオブジェクトをActivityStreamsのJSON-LDコンテキストでコンパクト化すると、
https://www.w3.org/ns/activitystreams#Public
が単にPublicまたはas:Publicと表現される場合もあります。これらも公開コレクションの有効な表現です。
ActivityStreamsオブジェクトをJSONとして直接扱う実装は、これら3表現すべてに対応できるようにしておくべきです。
すべてのオブジェクトはlikesコレクションを持ってもよいです。
これは、本オブジェクトをobjectとする全てのLikeアクティビティのリストであり、
副作用として 追加されます。
likesコレクションは必ず
OrderedCollection
または
Collection
でなければならず、必要に応じて認証ユーザの特権や認証無し時の制限などのフィルタがかかる可能性もあります。
likesコレクションと
よく似ているが異なるlikedコレクションを混同しないようご注意ください。
要点をまとめると:
[ActivityStreams]で定義されたアクティビティは、ソーシャルグラフ内でコンテンツを作成・変更・共有するための中核的な仕組みです。
クライアントからサーバへのやりとりは、クライアントがアクターのoutboxにアクティビティを投稿することで行われます。
これを行うため、クライアントはアクターのプロフィールからoutboxのURLを必ず発見し、そのURLに対して
application/ld+json; profile="https://www.w3.org/ns/activitystreams"
のContent-TypeでHTTPPOSTリクエストを投げる必要があります。
サーバーは任意で
application/activity+jsonというContent-TypeまたはAcceptヘッダーも
application/ld+json; profile="https://www.w3.org/ns/activitystreams"と同等として扱っても構いません。
このリクエストは、outboxの所有ユーザーの認証情報を用いた認証を必ず通す必要があります。
POSTリクエストのボディは1つのアクティビティ(埋め込みオブジェクトを含んでいてもよい)または、
サーバーによってCreate activityでラップされる単一の非アクティビティオブジェクトでなければなりません。
POST /outbox/ HTTP/1.1
Host: dustycloud.org
Authorization: Bearer XXXXXXXXXXX
Content-Type: application/ld+json; profile="https://www.w3.org/ns/activitystreams"
{
"@context": ["https://www.w3.org/ns/activitystreams",
{"@language": "en"}],
"type": "Like",
"actor": "https://dustycloud.org/chris/",
"name": "Chris liked 'Minimal ActivityPub update client'",
"object": "https://rhiaro.co.uk/2016/05/minimal-activitypub",
"to": ["https://rhiaro.co.uk/#amy",
"https://dustycloud.org/followers",
"https://rhiaro.co.uk/followers/"],
"cc": "https://e14n.com/evan"
}
アクティビティがidプロパティ付きで投稿された場合、サーバーはこれを無視し、新たなidを必ず生成しなければなりません。
サーバーは必ず201 CreatedのHTTPコードを返し、アクティビティが一時的なものでない限り、新しいidをLocationヘッダーに含める必要があります。
HTTP/1.1 201 Created
Location: https://dustycloud.org/likes/345
サーバーは配信前に、ActivityStreamsオブジェクトに存在すればbtoおよびbccプロパティを削除しなければなりません。ただし配信先判定には元々bto/bccプロパティに保存されていた宛先指定を必ず用います(配信参照)。
サーバーはその新たなアクティビティをoutboxコレクションへ追加しなければなりません。 アクティビティの種別次第で、さらに副作用的な処理をサーバーが実施する場合があります。 (ただし、アクティビティがoutboxに出現するタイミングは保証されません。遅延後に現れる場合や、逆に消える場合もあります。) こうした副作用は、各アクティビティごとに下記で説明します。
クライアントからサーバ連携未対応サーバーにオブジェクト送信を試みた場合、405 Method Not Allowed応答を返すべきです。
HTTPキャッシュ機構 [RFC7234] は、クライアントがサーバからの応答を受け取る場合もサーバがクライアントへ応答を返す場合も、適切なら尊重すべきです。
クライアントは新しいアクティビティの宛先指定を適切に行う責任が有ります。
どのように宛て先を決定するかはクライアントの実装によりますが、サーバーが新しいアクティビティを転送するのはto、bto、cc、bcc、audienceフィールド内の宛先だけである、ということをクライアントは理解しておかなければなりません。
フォロワーコレクションや公開コレクションは、新規アクティビティのデフォルトの宛先として適切な選択肢です。
クライアントは新しいアクティビティのobject、target、inReplyTo、tagフィールドに付いているオブジェクトを調べ、それぞれのactorまたはattributedToプロパティや、さらに各オブジェクトの宛先指定プロパティを取得し、新しく作るアクティビティのtoやccフィールドに追加することが望ましいです。
クライアントは再帰的にオブジェクトをたどっても構いませんが、その際は再帰の深さ制限を設けるべきです。
(ただし、「宛先アクターのコレクション」をリスト内で個別に分解して受信者とする必要がある、という意味ではありません。)
クライアントはUIでユーザーが宛名を修正する機会を与えても構いません。
例えば、ChrisがAmyの記事に「いいね」した場合は:
{
"@context": ["https://www.w3.org/ns/activitystreams",
{"@language": "en-GB"}],
"id": "https://rhiaro.co.uk/2016/05/minimal-activitypub",
"type": "Article",
"name": "Minimal ActivityPub update client",
"content": "Today I finished morph, a client for posting ActivityStreams2...",
"attributedTo": "https://rhiaro.co.uk/#amy",
"to": "https://rhiaro.co.uk/followers/",
"cc": "https://e14n.com/evan"
}
クライアントが生成するLikeは:
{
"@context": ["https://www.w3.org/ns/activitystreams",
{"@language": "en"}],
"type": "Like",
"actor": "https://dustycloud.org/chris/",
"summary": "Chris liked 'Minimal ActivityPub update client'",
"object": "https://rhiaro.co.uk/2016/05/minimal-activitypub",
"to": ["https://rhiaro.co.uk/#amy",
"https://dustycloud.org/followers",
"https://rhiaro.co.uk/followers/"],
"cc": "https://e14n.com/evan"
}
受信したoutboxは配信時に、Chris(Likeした本人)のフォロワーに加え、Amy本人、Amyのフォロワー、また元記事を受信したEvanにもdeliveryできます。
クライアントがoutboxへ以下のアクティビティを投稿する際はobjectプロパティを必ず指定しなければなりません:
Create, Update, Delete,
Follow, Add, Remove,
Like, Block, Undo。
またAdd、Remove投稿時はtargetプロパティの指定も必須です。
Createアクティビティは新しいオブジェクトを投稿するときに用います。
これには、そのアクティビティに埋め込まれた(objectプロパティ内の)オブジェクトを新規作成する副作用があります。
Createアクティビティを投稿した際は、そのactorフィールドを
objectのattributedToフィールドにコピーすべきです。
Createアクティビティとそのobjectの宛先指定が一致していないと混乱のもとになります。
そのため、サーバーは初回配信時にCreateアクティビティの宛先指定をobjectにコピーしたり、逆にobjectからラップしているCreateアクティビティへコピーすべきです。
ただし、objectの宛て先が後で変更されてもCreate側の宛て先指定は変更される必要はありません(例:Updateアクティビティによる場合)。
クライアントからサーバーへオブジェクトを投稿する際、アクティビティでラップせずにオブジェクト単体を投稿することも可能です。
サーバーは、POSTされた内容がActivityのサブタイプでない有効な[ActivityStreams]オブジェクトの場合は必ず受け付けなければなりません。
その場合、サーバーはこのオブジェクトをCreateアクティビティのobjectとしてラップし、非一時的オブジェクトなら
Create自体とラップされたObject両方へidを必ず付与します。
サーバーが返すLocationの値は新しく生成されたCreateアクティビティ(オブジェクトそのものではない)のURLであるべきです。
オブジェクトに指定されたto、bto、cc、bcc、audience各プロパティは、サーバーが新しいCreateアクティビティへコピーしなければなりません。
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Note",
"content": "This is a note",
"published": "2015-02-10T15:04:55Z",
"to": ["https://example.org/~john/"],
"cc": ["https://example.com/~erik/followers",
"https://www.w3.org/ns/activitystreams#Public"]
}
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Create",
"id": "https://example.net/~mallory/87374",
"actor": "https://example.net/~mallory",
"object": {
"id": "https://example.com/~mallory/note/72",
"type": "Note",
"attributedTo": "https://example.net/~mallory",
"content": "This is a note",
"published": "2015-02-10T15:04:55Z",
"to": ["https://example.org/~john/"],
"cc": ["https://example.com/~erik/followers",
"https://www.w3.org/ns/activitystreams#Public"]
},
"published": "2015-02-10T15:04:55Z",
"to": ["https://example.org/~john/"],
"cc": ["https://example.com/~erik/followers",
"https://www.w3.org/ns/activitystreams#Public"]
}
Updateアクティビティは、既存のオブジェクトを更新する際に使います。
これにより、objectは、更新アクティビティが定義する新しい構造で必ず書き換えられます(そのアクターに更新権限がある場合)。
クライアントからサーバーのやりとりでは、更新は部分的なフィールドごとに行われます。
すなわち、ドキュメント全体を置き換えるのではなく、指定されたキー値ペアのみ既存の値が新しい値に置換されます。
これは更新対象オブジェクトのトップレベルフィールドのみに適用されます。
例外として、jsonのnull型が指定されている場合、そのフィールドはサーバ側のオブジェクト表現から除去します。
ただし、この動作は「クライアント→サーバ通信」(クライアントがサーバへ投稿するだけの場合)のものです。 サーバ間通信やサーバからクライアントへの更新では、部分更新後の完全な新オブジェクト表現が含まれるべきです。 詳しくはサーバ間やりとりでのUpdateアクティビティ説明を参照してください。
Deleteアクティビティは既存オブジェクトを削除するために使います。
この副作用として、サーバはobjectを、そのオブジェクトのTombstoneで置き換えても構いません(他のアクティビティが削除済みオブジェクトを参照する際に表示されます)。
削除済みオブジェクトがリクエストされた場合、サーバはTombstoneオブジェクトをレスポンスボディに返すならHTTP 410 Goneで返すべき、それ以外は404 Not Foundで返します。
削除済みオブジェクトの例:
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://example.com/~alice/note/72",
"type": "Tombstone",
"published": "2015-02-10T15:04:55Z",
"updated": "2015-02-10T15:04:55Z",
"deleted": "2015-02-10T15:04:55Z"
}
Followアクティビティは他のアクターのアクティビティ購読時に使用します。
outboxでこれを受信した場合、
サーバーはAcceptアクティビティが、このFollowアクティビティをobjectとして受信するまでは
objectをactorのfollowingコレクションに追加すべきでありません。
outboxにAddアクティビティが届いたら、サーバーは
objectをtargetで指定されたコレクションに追加すべきですが、以下の場合は除きます:
targetの所有者が受信サーバでない場合(よって更新権限が無い場合)。
objectをtargetコレクションに追加するのが受信サーバの裁量で許可されない場合。
outboxにRemoveアクティビティが届いたら、サーバーは
objectをtargetで指定されたコレクションから削除すべきですが、以下の場合は除きます:
targetの所有者が受信サーバでない場合(よって更新権限が無い場合)。
objectをそのtargetコレクションから削除するのが受信サーバの裁量で許可されない場合。
Likeアクティビティはactorがobjectを「いいね」したことを示します。
outboxでこれを受信した場合、
サーバーはobjectをactorのlikedコレクションに追加すべきです。
Blockアクティビティは、投稿者アクターが(objectフィールドで指定する)他のアクターに対し、自分の投稿したオブジェクトとやり取りできないようにしたい時に使います。
サーバーはブロックされたユーザーが投稿者アクターのオブジェクトとやり取りできないように防ぐべきです。
サーバーはBlockアクティビティをそのobjectで指定された相手へ配信すべきでありません。
Undoアクティビティは以前のアクティビティを取り消すために使われます。
詳細はActivity Vocabularyの
逆アクティビティと「Undo」を参照。
例えばLike、Follow、Blockなどを取り消すのに使います。
Undoアクティビティも元アクティビティも必ず同じアクターでなければなりません。
副作用は出来る限り元に戻してください。
例えばLikeのUndoであれば、以前インクリメントされたカウンターは適切にデクリメントするなど。
ただし、明示的な「逆アクティビティ」がある場合はそちらを用いるべきです。
CreateベースアクティビティならDelete、
AddアクティビティならRemoveを使ってください。
連合型サーバーはoutboxに投稿されたすべてのアクティビティについて、 outbox配信に従い必ず配信しなければなりません。
このセクションは規範的ではありません。
サーバーは画像・動画などのバイナリデータを活動で参照できるようアップロード機能を提供しても構いませんが、その具体的な仕組みはこのActivityPubバージョンの範囲外です。 Social Web Community Groupは ActivityPubメディアアップロード報告書 でプロトコル改訂議論を行っています。
サーバーは他のサーバーと通信し、アクターのinboxエンドポイントにアクティビティを投稿することで、ソーシャルグラフ全体に情報を伝播させます。 ネットワーク上で送信されるアクティビティは、意図的に一時的でない限りidを持つべきですが、一時的な場合はid省略可能です。
POSTリクエスト(例:inbox宛)は必ず
application/ld+json; profile="https://www.w3.org/ns/activitystreams"
をContent-Typeとして送信し、GETリクエスト(3.2 オブジェクトの取得も参照)
はAcceptヘッダーでapplication/ld+json; profile="https://www.w3.org/ns/activitystreams"を付けます。
サーバーは、サーバー間通信において
application/activity+jsonのContent-TypeまたはAcceptヘッダーを
application/ld+json; profile="https://www.w3.org/ns/activitystreams"と同等に扱うべきです。
ソーシャルグラフ全体に更新を伝播するため、アクティビティは適切な受信者へ送信されます。 まず、該当オブジェクト間のリンクをたどってアクターまで到達し、そのアクターのinboxにアクティビティが挿入されます(配信)。 これにより受信サーバーは以下のことができます:
配信は通常、例えば次の場合にトリガされます:
Followers Collectionが宛先の場合
他サーバー上のアクターのinboxまたはsharedInboxプロパティへ配信を行うサーバーは、
以下のアクティビティにobjectプロパティを必ず含める必要があります:
Create、Update、Delete、
Follow、Add、Remove、
Like、Block、Undo。
加えて、サーバー間でAdd、Removeアクティビティの配信を行う場合はtargetプロパティも必要です。
HTTPキャッシュ機構 [RFC7234] は、他サーバーからの応答受信・他サーバーへの応答送信どちらでも、適切なら尊重すべきです。
以降は連合型サーバー間の通信についてのみ必要となる規定です。
アクティビティはそのターゲット(アクター)のinboxを参照し、
そのinboxへ投稿することで届けられます。
ターゲットは
ActivityStreamsの宛先指定
、つまりアクティビティのto、bto、cc、bcc、audienceフィールドで決定します。
inboxはまず
ターゲットアクターのJSON-LD表現を取得し
、そのinboxプロパティを参照することで特定されます。
受信者がCollectionまたはOrderedCollectionの場合、サーバーは必ず(ユーザーの認証情報で)そのコレクションをデリファレンスし、各アイテムのinboxを探します。
サーバーはコレクションを通じた間接的なたどりの階層数に上限を設ける必要があり、その上限は1階層でもかまいません。
サーバーは最終的な受信者リストを重複排除しなければならず、配信対象アクティビティのactor自身はリストから除外する必要があります。すなわち、アクターは自身のアクティビティを自分自身に配信しないで下さい。
宛先が指定されていない場合の動作は未規定ですが、推奨としては、宛先がなければそのオブジェクトは完全非公開としアクセス制御で保護すべきです。 単に「public」コレクション宛の場合、そのオブジェクトはアクターのoutboxで公開表示されますが、いずれのアクターにも届けられません。
その後、(送信者認証つきで)inboxへHTTP POSTリクエストが発行され、ボディにアクティビティが含まれます。
このアクティビティは受信側によりinboxのOrderedCollectionのitemとして追加されます。
非連合サーバーのinboxに配信しようとした場合は405 Method Not Allowed が返るべきです。
連合サーバーが第三者サーバーへ配信を行う場合、配信は非同期で実施すべきです。またネットワークエラーなどで失敗した場合には配信を再試行すべきです。
注: 同一オリジン間のアクター同士の配信は任意の内部メカニズムを用いても良く、HTTPを使う必要はありません。
この仕様の理解に必須ではありませんが、ActivityPubの宛先指定・配信機構は
Linked Data Notifications
仕様と重複します。両者は相互運用可能です。
特にinboxプロパティは両者共通であり、本仕様書で記述される宛先指定・配信はLDNでもサポートされています。
また、JSON-LDでコンパクト化されたActivityStreams文書に加え、Linked Data
NotificationsはActivityPub実装で必須でない様々なRDFシリアライゼーションもサポートします。
より広範な互換性を目指すActivityPub実装は、他のRDF表現のサポートも検討できます。
(クライアントからサーバー、サーバー間双方をサポートするサーバの)outboxでオブジェクトを受信した場合、 サーバは以下の宛先へ配信しなければなりません:
to、bto、cc、
bcc、audienceのいずれかのフィールドの値が、そのアクター自身の所有する個人またはコレクションの場合
これらのフィールドは クライアントにより適切に設定されているはずです。
この節は、連合ネットワーク上で時折問題となる「ゴーストリプライ」問題の対策です。 この問題は例を使うと最もよく分かります。
Alyssaが学会発表成功の投稿をfollowersコレクションに送り、その中にはBenも入っています。 BenはAlyssaへ返信し、そのフォロワーコレクションも宛先に含めます。 しかしBenはAlyssaのfollowersコレクションの中身にアクセスできず、自身のサーバからfollowersメンバーのinboxへは転送できません。 この転送機構が無いと、AlyssaがBenに再返信した場合、Alyssaのフォロワー達はAlyssaが突然Benに返事しているように見え、Benの発言を見ないままになるので混乱します。
inboxでアクティビティを受信したサーバーは、元サーバーが配信できなかった受信者に対してこれを転送する必要があります。これを行うには、サーバーは以下の全てを満たすときに限り、
to、cc、audience値をターゲットとし配信しなければなりません:
to、cc、audienceの値内に、サーバ自身が所有するコレクションが含まれている
inReplyTo、object、target、tag
の値がサーバ所有のオブジェクトの場合。
サーバはこれら値を再帰的に辿り自分の所有オブジェクトか調べすべき、ただし再帰の深さには上限有り。
但し新しい宛先は拾わず、元オブジェクトのto、cc、audienceのみ配信ターゲットとする(クライアントorユーザーで意図的に宛先を追加・修正している場合があるため)。
サーバは実装固有のルール(例:スパムフィルタ等)で配信ターゲットをフィルタしてもよいです。
inboxでCreateを受信した際の副作用は意外と少なく、そのアクティビティはアクターのinboxに現れるべきですが、サーバー側でそのアクティビティや付随オブジェクトのローカル表現を保存したくなる可能性が高いです。
ただし、このことは全般的にinboxに配信されたアクティビティを処理する際には常に行われます。
サーバー間通信では、Updateアクティビティを受信したサーバーは、そのidが一致する
objectのコピーをUpdateで送られてきた内容で上書きすべきです。
なお、
クライアント→サーバでのUpdateアクティビティ
と違い、サーバ間では部分更新ではなくオブジェクト全体が置き換えられます。
受信サーバはこのUpdateが対象objectの更新権限を持つことを厳重に確認すべきです。
最低でもUpdateとobjectが同じオリジンであることを確認しましょう。
これを受信した場合の副作用は、(objectが送信アクター/サーバー所有である場合)受信側サーバは
id一致のobject表現を削除すべきであり、Tombstoneオブジェクトに置換しても構いません。
(なお、ActivityPubで発信元サーバからリモートサーバにアクティビティが送信された後は、オブジェクトの表現のリモート削除強制を義務付けるものはありません。)
inboxでこれを受信した場合、
サーバーはobjectにこのFollowアクティビティを指定した
AcceptまたはRejectアクティビティを生成し、そのFollowのactorに配信すべきです。
受理Acceptも拒否Rejectも自動生成またはユーザー操作で生成できます(レビュー後の遅延発行も可)。
サーバーはFollowリクエストに明示的なRejectの送信をしない
選択も可能ですが、リクエスト送信側サーバが中間状態に留まるリスクには注意しましょう。
(例:ユーザー保護のためRejectedの通知を控える…など)
AcceptでこのFollowアクティビティがobjectとなっている場合、サーバーは
actorを目的アクターのFollowers Collectionに追加すべきです。
Rejectの場合は絶対に目的アクターのFollowers
Collectionに追加してはいけません。
Follow購読が一度成功したとしても、将来長期間にわたりフォロワーへの配信が失敗することがあります。
実装者はネットワーク上のアクターが常に到達可能と限らないことを想定し、適切な対策を施してください。
例えば半年等、配信に何度も失敗しフォロワーが長期間到達不能となれば、
配信側サーバーはその購読者をfollowersリストから除外しても合理的です。
到達不能アクターへの対応方針と期限は配信サーバー実装側の裁量に委ねます。
inboxでこれを受信した際の副作用はobjectの種別によって決まります。
本書で述べていない型(例: Offer)も受理可能です。
inbox宛Acceptのobjectが、以前受信者から送信されたFollowアクティビティであれば、
サーバーはactorを受信者のFollowing Collectionに追加すべきです。
inboxでこれを受信した際の副作用はobjectの種別によって決まります。
本書で述べていない型(例: Offer)も拒否可能です。
inbox宛のRejectのobjectが、以前受信者から送信されたFollowアクティビティであった場合、
これは受信者がFollow要求を認可しなかったことを意味します。サーバーはactorを受信者のFollowing
Collectionに絶対に追加してはいけません。
inboxでAddアクティビティを受信した際は、サーバーは
objectをtargetプロパティのコレクションに追加すべきですが、以下の場合を除きます:
targetが受信サーバの所有物でなく、更新権限が無い場合
objectが他理由でtargetコレクションに追加されるべきでないと、受信側が判断する場合
inboxでRemoveアクティビティを受信した場合、サーバーは
objectをtargetプロパティのコレクションから削除すべきですが、以下の場合を除きます:
targetが受信サーバ所有でなく、更新権限が無い場合
objectのtargetコレクション削除が認められないと判断した場合
inboxでこれを受信した副作用として、サーバーは
likesコレクションが有る場合は
アクティビティを追加しobjectのLike数をインクリメントすべきです。
inboxでAnnounceアクティビティを受信した際は、サーバーは
sharesコレクションが有る場合は
アクティビティを追加しobjectの共有数をインクリメントすべきです。
Announceアクティビティは、他のSNSで言うところの「共有」「リポスト」「ブースト」にあたります。
Undoアクティビティは直前のアクティビティ副作用を取り消すために利用されます。
詳細はActivityStreamsの
逆アクティビティと「Undo」
を参照してください。
Undoアクティビティの効力および制約範囲は
クライアントからサーバー時のUndoアクティビティ
と同様ですが、ここでは連合サーバー間で適用されます。
このセクションは規範的ではありません。
連合ネットワークで国際的なユーザーベースを築くことは重要です。
ActivityStreamsはコンテンツの国際化対応ツールを提供しており、
可能な限りこれを利用すべきです。
しかし、実装でユーザー投稿コンテンツにどの
@languageプロパティ
を指定すべきか判断するのは難しい場合もあります。
W3C
国際化グループ
は、
言語検出に関するガイドラインを提供しています。
このセクションは規範的ではありません。
サーバーは、クライアントから投稿されたコンテンツを信用すべきではありませんし、 連合サーバーも、そのコンテンツの発信元でない別サーバーから受け取ったものは、なんらかの検証無しに信用すべきではありません。
サーバーは、新規コンテンツが本当にその主張するアクターから投稿されたものか、またアクターが主張するリソースを更新する権限があるか、慎重に検証すべきです。 詳しくは 3. オブジェクト および B.1 認証と認可も参照してください。
開発中はlocalhostで動作するプロセスへテストアクセスするのが便利ですが、本番クライアントやサーバーでlocalhostへのリクエストを許可するのは危険な場合があります。 認証が不要なlocalhostのURIへリクエストを投げると思わぬリソースにアクセスしたり、localhost専用の想定だったリソースが操作されてしまうことがあります。
ActivityPubサーバーやクライアントが開発目的でlocalhost URIへのリクエストを許可する場合、デフォルトでオフになる設定項目とすることを検討してください。
httpやhttps以外にも多様なURIタイプがあります。
URIスキームごとにリクエスト処理するようなライブラリの中には、望ましくないスキーム、例えばfileを参照しようとするものもあるかもしれません。
クライアント・サーバー実装者は、自分のライブラリがどのようなリクエスト動作になるか十分検証し、httpやhttpsなど安全なスキームだけをホワイトリストすることも検討すべきです。
サーバーは、オブジェクト解決時の再帰の深さ上限を設けたり、再帰参照を持つActivityStreamsオブジェクトを特別に処理するよう工夫すべきです。 これを怠るとDoS(サービス拒否)セキュリティ脆弱性につながる恐れがあります。
スパムはどんなネットワークでも問題ですが、連合型ネットワークでは特に問題が顕著になります。 ActivityPub自体はスパム対策の具体的仕組みは提供しませんが、サーバーは信頼できないローカルユーザーやリモートユーザーからの受信コンテンツを、何らかのスパムフィルターで検査することが推奨されます。
サーバーは、他の連合サーバーからのDoS攻撃対策を実装すべきです。 たとえばレート制限機構を使うなどの方法があります。 とくに副作用を伴うアクティビティではこの対策を厳重に実装すべきです。 サーバーはまた自身が提出するリクエストで他のサーバーを過負荷にしないよう、指数バックオフなどの戦略で抑制すべきです。
サーバーはAPIクライアントからの投稿をレート制限すべきです。 その目的は2つあります:
大きすぎるコレクションの返却でクライアントが過負荷にならないよう、サーバーは返すコレクションページサイズを制限すべきです。 クライアントもまた、悪意ある/乗っ取られたサーバーに接続した場合に備えて、処理可能な応答のサイズを制限する備えが必要です(たとえばタイムアウトやエラー生成など)。
ブラウザやリッチテキスト対応アプリ向けにアクティビティのフィールドを描画する場合、マークアップを含むフィールドのクロスサイトスクリプティング(XSS)対策としてサニタイズ処理を必ず行ってください。
btoおよびbccは配信時に削除すべきですが、
サーバーが自身のストレージ上でどう表現するかは自由です。
ただしbtoやbccはオブジェクト/アクティビティの元作成者のみに知れている/見えている前提なので、表示時にもこれらプロパティは省略すべきです。
このセクションは規範的ではありません。
この仕様はWeb連合分野を探究する多くのコミュニティの長年の努力と経験から生まれました。 特に本仕様の多くは OStatus および Pump API (StatusNet(現GNU Social)およびPump.ioが先駆)に影響を受けています。 これらイニシアチブはいずれも多くの開発者の貢献から生まれましたが、なかでもEvan Prodromou氏はこの分野で一貫したリーダーであり、彼の情熱がなければ現在のActivityPubが存在していたかどうか分かりません。
Erin Shepherdは最初期の仕様バージョンを構築しました。これは Pump API ドキュメントのアイデアを元に、ほとんどを完全新規に書き下ろしたものですが、主要なアイデアを共有しつつActivityStreams 1から2へ切り替えています。
Jessica TallonとChristine Lemmer-Webberは標準化がW3C Social Working Groupに移った際に編集を引き継ぎ、Erin Shepherdのドキュメントから現在のActivityPubへの移行の大半を担いました。 この文書の多くはSocial Working Groupの長いフィードバックプロセスの中で書き換えや再編成が行われています。
ActivityPubはW3C Social Working Groupの多くのメンバーの丁寧な意見を元に作られています。 なかでもAmy Guyには特大の感謝があります。彼女は[Social-Web-Protocols]により、 異なるSocial Working Group文書の内容を調和的に体系化してくれました。 またAmyはChristopher Allan Webberと4日間のスプリントでActivityPub仕様の重要なリファクタ案を作成し、 そのおかげでクライアント・サーバー・連合間の構造がより明確になり、[LDN]との関係もわかりやすくなりました。 Benjamin Goeringには実装レポートテンプレート作成への特別な感謝があります。 またmrayには本仕様のチュートリアル図(本ドキュメントと同じライセンス)の制作に感謝いたします。
多くの方々が細やかなレビューでActivityPubを支えてくれました。 特に感謝します: Aaron Parecki、 AJ Jordan、 Benjamin Goering、 Caleb Langeslag、 Elsa Balderrama、 elf Pavlik、 Eugen Rochko、 Erik Wilde、 Jason Robinson、 Manu Sporny、 Michael Vogel、 Mike Macgirvin、 nightpool、 Puck Meerburg、 Sandro Hawke、 Sarven Capadisli、 Tantek Çelik、 Yuri Volkov。
本書は地球上すべての市民への献辞です。 あなたたちはコミュニケーションの自由を享受する権利があります。私たちの活動が、その目的・権利のために微力ながら寄与できたことを願います。
1.1 Social Web Working Group
ActivityPubは、Social Web Working Groupが策定する複数の関連仕様の1つです。 他の手法や補完的プロトコルに関心のある実装者は [Micropub] や 概要ドキュメント [Social-Web-Protocols] を確認するとよいでしょう。