投稿する

Activity:Create

私家版ActivityPub日本語訳

リモートサーバーにいるフォロワーのinboxに、CreateのActivity(JSON)を署名つきのリクエストでPOSTします。

POSTリクエストを投げる時はminetype
Content-type:application/activity+json
が必須です。

  1. 投稿文を作る
    • 作った投稿文をデータベースに登録する
    • 作った投稿文を配送するための箱に入れる
  2. 投稿文を入れた箱を配送する

わかったようなわからないような例えですみません、具体例を以下に並べます。

投稿文:「ちくしょお。鼻水があかん。抗ヒスタミン薬投入するしかないか…。」

  1. ローカルタイムライン(サーバーに登録したユーザーの投稿が流れるタイムライン)のために、投稿文をデータベースに登録します。
  2. フォロワーの所属するサーバーに投稿文を投げるための投稿文のJSONを作ります。

(ローカルタイムラインはデータベースから投稿文をひっぱりだして、整形加工して表示するだけです)

Note:投稿文のJSON


 {
  "type": "Note",
  "id": "https://tokoroten.doncha.net/t2aki/items/03166-20241111",
  "url": "https://tokoroten.doncha.net/t2aki/items/03166-20241111",
  "published": "2024-11-10T23:19:06Z",
  "to": [
      "https://www.w3.org/ns/activitystreams#Public"
  ],
  "cc": [
      "https://tokoroten.doncha.net/t2aki/followers"
  ],
  "attributedTo": "https://tokoroten.doncha.net/t2aki",
  "content": "ちくしょお。鼻水があかん。抗ヒスタミン薬投入するしかないか…。"
}
	

「type」は「Note

「id」と「url」は同じものでも大丈夫。「id」は投稿文のID。「url」はアクセスされるURL。
Acceptが、text/htmlはurlのhtmlを返す / application/activity+jsonはidのJSONを返す。
「https://tokoroten.doncha.net/t2aki/items/」
サーバー / ユーザー / 適当な判別用
「03166-20241111」は一意のID。ウチの場合はデータベースのID

「published」はUTC(世界標準時)

「to」「cc」は投稿文の宛先
「to」のPublicはすべてに公開する
「cc」で自分のフォロワーさん

この「to」と「cc」で、投稿の「公開範囲」を柔軟に指定できるのがActivityPubの良いところ。
(「公開範囲」については別途)

「attributedTo」はこの投稿文を作ったユーザー

「content」が投稿の本文

Create:投稿文を入れて送信するための箱のJSON


{
  "@context": [
      "https://www.w3.org/ns/activitystreams",
      {
          "Hashtag": "as:Hashtag"
      }
  ],
  "type": "Create",
  "id": "https://tokoroten.doncha.net/t2aki/activity/03166-20241111",
  "url": "https://tokoroten.doncha.net/t2aki/activity/03166-20241111",
  "published": "2024-11-10T23:19:06Z",
  "actor": "https://tokoroten.doncha.net/t2aki",
  "to": [
      "https://www.w3.org/ns/activitystreams#Public"
  ],
  "cc": [
      "https://tokoroten.doncha.net/t2aki/followers"
  ],
  "object": {
  }
}
	

「@context」は呪文。このままコピペしてるけど、これがたぶん最低限必須。

「type」は「Create
同じ「type」でも
「Note」は名詞。「Create」は動詞。「NoteをCreateする」という感じで、typeの属性みたいなものが違う。

「id」「url」はNoteと同じ。ここは一意であればなんでもかまわない、はず。
Noteと被らないように「items」を「activity」に変えただけ。
id部分は「03166-20241111」Noteと同じ。httpsから始まる文字列が一意ならいいので、このへん、わりとテキトー。

「published」はNoteと同でok

「to」「cc」はNoteと同じでok

「actor」はこのActivityを送ったユーザー。Noteの「attributedTo」と同じ、のはず。

「object」
ここがActivity:Createの箱というところ。(サンダーバード2号を例にあげてわかってもらえる?)
このCreateの「object」に、NoteのJSONをそのまま全部入れる。

こんなイメージ

Activity:Create
object:Note

NoteのJSONをCreateのJSONのobjectに入れる…て、ほんとそのまんま入れるだけ。

実際に飛ばすJSONが以下


{
  "@context": [
      "https://www.w3.org/ns/activitystreams",
      {
          "Hashtag": "as:Hashtag"
      }
  ],
  "type": "Create",
  "id": "https://tokoroten.doncha.net/t2aki/activity/03166-20241111",
  "url": "https://tokoroten.doncha.net/t2aki/activity/03166-20241111",
  "published": "2024-11-10T23:19:06Z",
  "actor": "https://tokoroten.doncha.net/t2aki",
  "to": [
      "https://www.w3.org/ns/activitystreams#Public"
  ],
  "cc": [
      "https://tokoroten.doncha.net/t2aki/followers"
  ],
  "object": {
      "type": "Note",
      "id": "https://tokoroten.doncha.net/t2aki/items/03166-20241111",
      "url": "https://tokoroten.doncha.net/t2aki/items/03166-20241111",
      "published": "2024-11-10T23:19:06Z",
      "to": [
          "https://www.w3.org/ns/activitystreams#Public"
      ],
      "cc": [
          "https://tokoroten.doncha.net/t2aki/followers"
      ],
      "attributedTo": "https://tokoroten.doncha.net/t2aki",
      "content": "ちくしょお。鼻水があかん。抗ヒスタミン薬投入するしかないか…。"
  }
}
	

perlでリクエスト

httpのリクエストのヘッダを作ってlwpに設定する(抜粋)


my $ua = LWP::UserAgent->new();
my $req = HTTP::Request->new(post=>$url);
my $content = $args->{content};
my $content_type = 'application/activity+json';
$req->content_type($content_type);
$req->headers->date(time);
my $digest = 'SHA-256=';
$digest .= encode_base64(sha256($content),"");
my $signature = sprintf qq{keyId="%s%s#main-key",algorithm="rsa-sha256",headers="%s",signature="%s"},
$self->{ap_url}, $self->{actor}, $header_item->{headers}, $self->sign({sign_key=>$header_item->{sign_key}});
$req->headers->push_header(Signature=>$signature);
$req->headers->push_header(Digest=>$digest);
$req->headers->push_header(host=>$host);
$req->content($content);
	

HTTPのリクエストヘッダに、content-type date Signature Digest hostなどもろもろ詰め込んで、CreateのJSONをcontentに入れて送信する。
rubyやphpでもたぶん同じような関数がある、かな。

HTTPでは、空行が現われる前をヘッダ、空行以降をコンテンツ本文ということらしいんで

---ヘッダ---
Content-type:text/html

---コンテンツ本文---

https://developer.mozilla.org/ja/docs/Web/HTTP/Headers

HTTP ヘッダーは、大文字小文字を区別しないヘッダー名とそれに続くコロン (:)、 値で構成されます。値の前にあるホワイトスペースは無視されます。

以下のようなヘッダになる、はず。


digest: SHA-256=AtA77pcxSLm5Icm4Y2qW6qZVi16r4azJkh9fyz35TaQ=
host: example.com
content-type: application/activity+json
signature: keyId="https://tokoroten.doncha.net/t2aki#main-key",algorithm="rsa-sha256",headers="(request-target) host date digest content-type",signature="xbtktsvtQKkpVp8tPMDwimCuuxTuHXAeBkaqibQ4XPmCJp30wq2nh5Iuc4/0fabiVsAER1peqUj9PRVZbu+4chywWXduYCN1GW9vVf70/0bcF+4sNKQpkj5om7iJMjhU/TBk5wcoUnmtpOotTz4FP0RpOuNc866vggtdZvd6LI/22iZ2sUuU6OpS8T9nU1xTl3iqY2/BbT+uL4OufIjb+Gw1bqQyCqstgX4HxvyjzVU64Cw7Lek534YCRu6Ea9L/X4XAfrwaTmQ+11CI0OijFOmuYXc6ovbbwZQaWlZuPK6Hw9mh+vli7pSAlUXCMW7Yr9DxAJh/xkUXENk4ZHXWCQ=="
date: Mon, 11 Nov 2024 22:59:41 GMT
	

[2024-11-12 08:29:22] v1.0.1

[2024-11-11 14:12:44] v1.0.0

Menu