本連載では第一線の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:argrath@actub.ub32.org",
  "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 



