本連載では第一線のPerlハッカーが回替わりで執筆していきます。今回のハッカーは白方健太郎さんで、
本稿のサンプルコードは、
Fediverse──非中央集権型ソーシャルネットワーク
2017年春に日本でブームとなったMastodonが構成するような非中央集権型ソーシャルネットワークは、
本稿では、
Fediverseを構成する仕様群
Fediverseは複数の仕様を組み合わせることで実現されています。本節では、
ActivityPub──Fediverseを実現するための中心プロトコル
ActivityPubは、
ActivityPubでやりとりされるデータのMIMEapplication/
を使います。HTTPSリクエストのAccept
ヘッダやレスポンスのContent-Type
ヘッダには、
Activity Streams 2.0──ActivityPubのデータモデル
AS2は、
AS2およびそのベースとなったJSON-LDは非常に大きな仕様ですが、
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://example.com/users/foobar#follow/1",
"type": "Follow",
"actor": "https://example.com/users/foobar",
"object": "https://actub.ub32.org/argrath"
}
@context
属性はJSON-LDに特有の属性で、https://
です。この属性には、
id
属性はネットワーク全体でユニークとなるURL形式の文字列、type
属性はオブジェクトの型を示します。そのほかの属性はオブジェクトの型によって異なるので都度説明します。
HTTP Signatures──ActivityPub通信の検証プロトコル
ActivityPubでは、
ActivityPubではどのような手法を用いるかは定めていませんが、Signature
フィールドに指定してリクエストを送信します。受信側は送信アクターの公開鍵を取得して署名を検証し、
Fediverse参加に必要な機能の実装
前述のとおりFediverseは連合と呼ばれるゆるいネットワークを構成していますが、
- ユーザー名からアクター情報URLへの変換
- フォローリクエストの処理
- 更新通知の送付
以降でそれぞれの処理での具体的な方法を説明します。
ユーザー名からアクター情報URLへの変換
Fediverse上でのユーザー名は、argrath@actub.
のように

Web Host MetadataプロトコルによるWebFingerエントリポイント検索
最初に、https://サーバ名/.well-known/
にGETアクセスすることで情報を得ます。したがってargrath@actub.
の場合は、https://
にアクセスします。ここで返される情報は次の形になります。
<XRD>
<Link rel="lrdd" type="application/xrd+xml"
template="https://actub.ub32.org/.well-known/webfinger
?resource={uri}"/>
</XRD>
ここで得られたhttps://
が、
WebFingerプロトコルによるアクター情報検索
次に、{uri}
の部分をユーザー名に置換したhttps://
にGETアクセスすると、
{
"subject": "acct:[email protected]",
"aliases": [
"https://actub.ub32.org/argrath"
],
"links": [
{
"rel": "http://webfinger.net/rel/profile-page",
"type": "text/html",
"href": "https://actub.ub32.org/argrath"
},
{
"rel": "self",
"type": "application/activity+json",
"href": "https://actub.ub32.org/argrath"
}
]
}
この情報のうち、rel
属性がself
であるブロックのhref
属性の値がアクター情報のURLとなります。したがって、argrath@actub.
のアクター情報のURLは、https://
となります。
フォローリクエストの処理
購読アクターは、

アクター情報の取得
先ほど入手した発信アクターのURLにHTTPS GETリクエストすることで、
発信アクターが返却する必要があるアクター情報は、Person
クラスを使った次のようなものになります。
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1"
],
"id": "https://actub.ub32.org/argrath",
"type": "Person",
"url": "https://actub.ub32.org/argrath",
"inbox":
"https://actub.ub32.org/argrath/inbox",
"outbox":
"https://actub.ub32.org/argrath/outbox",
"followers":
"https://actub.ub32.org/argrath/followers",
"following":
"https://actub.ub32.org/argrath/following",
"preferredUsername": "argrath",
"publicKey": {
"publicKeyPem":
"-----BEGIN PUBLIC KEY-----\nMIIB(省略)",
"id": "https://actub.ub32.org/argrath",
"owner": "https://actub.ub32.org/argrath"
}
}
本稿で示す処理で用いるのは、inbox
属性と、publicKey
属性です。
フォローリクエストの送信
次に、inbox
エントリに次のようなFollow
オブジェクトを送信することで行われます。
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://example.com/users/foobar#follow/1",
"type": "Follow",
"actor": "https://example.com/users/foobar",
"object": "https://actub.ub32.org/argrath"
}
actor
属性はこのオブジェクトの送信元である購読アクターのURL、object
属性は送信先である発信アクターのURLを示します。
フォローリクエストを承認する場合
発信アクターが受け取ったFollow
オブジェクトを承認する場合、inbox
エントリにAccept
オブジェクトを送信します。
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://actub.ub32.org/argrath/accept/1",
"type": "Accept",
"actor": "https://actub.ub32.org/argrath",
"object": {
"id": "https://example.com/users/foobar#follow/1",
"type": "Follow",
"actor": "https://example.com/users/foobar",
"object": "https://actub.ub32.org/argrath"
}
}
actor
属性はこのオブジェクトの送信元である発信アクターのURLを示し、object
属性には受け取ったFollow
オブジェクトをそのまま設定します。
フォローリクエストを拒否する場合
何らかの理由でフォローリクエストを拒否することを明示的に通知したい場合は、Accept
オブジェクトの代わりにReject
オブジェクトを送信します。Reject
オブジェクトの構造は、type
属性がReject
になる以外はAccept
オブジェクトと同じです。
なお、Reject
オブジェクトを返さずにフォローリクエストを暗黙に拒否してよいことになっています。
アンフォロー処理
フォロー処理を実装すればFediverseに参加できますが、
購読アクターがフォローしているアクターをアンフォローするとき、Undo
オブジェクトを送信します。
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://example.com/users/foobar#undo/1",
"type": "Undo",
"actor": "https://example.com/users/foobar",
"object": {
"id": "https://example.com/users/foobar#follow/1",
"type": "Follow",
"actor": "https://example.com/users/foobar",
"object": "https://actub.ub32.org/argrath"
}
}
actor
属性はこのオブジェクトの送信元である購読アクターのURL、object
属性にはフォロー時に送信したオブジェクトをそのまま設定します。
アンフォロー処理は自動的に成功するため、
更新通知
続いて、
Noteオブジェクトの作成
まず、Note
オブジェクトを作成します。
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://actub.ub32.org/argrath/123",
"type": "Note",
"url": "https://actub.ub32.org/argrath/123",
"published": "2018-03-03T09:54:50Z",
"content": "はいさーい",
"attributedTo": "https://actub.ub32.org/argrath",
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"cc": [
"https://actub.ub32.org/argrath/followers"
]
}
to
属性に指定されているhttps://
は、cc
属性に指定されているhttps://
はアクター情報のfollowers
属性で示されているURLで、
Createアクティビティの送信
次に、Note
オブジェクトを入れ子として含んだCreate
オブジェクトを作成します。
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://actub.ub32.org/argrath/123/activity",
"type": "Create",
"actor": "https://actub.ub32.org/argrath",
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"cc": [
"https://actub.ub32.org/argrath/followers"
],
"object": {
"id": "https://actub.ub32.org/argrath/123",
"type": "Note",
"url": "https://actub.ub32.org/argrath/123",
"published": "2018-03-03T09:54:50Z",
"content": "はいさーい",
"attributedTo": "https://actub.ub32.org/argrath",
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"cc": [
"https://actub.ub32.org/argrath/followers"
]
}
}
to
属性とcc
属性はもとのNote
オブジェクトの内容をコピーし、object
属性にはもとのNote
オブジェクトそのものを指定します。
こうして作成したオブジェクトを、inbox
エントリにPOSTします。
<続きの
本誌最新号をチェック!
WEB+DB PRESS Vol.130
2022年8月24日発売
B5判/
定価1,628円
ISBN978-4-297-13000-8
- 特集1
イミュータブルデータモデルで始める
実践データモデリング
業務の複雑さをシンプルに表現! - 特集2
いまはじめるFlutter
iOS/Android両対応アプリを開発してみよう - 特集3
作って学ぶWeb3
ブロックチェーン、スマートコントラクト、 NFT