投稿する
Activity:Create
リモートサーバーにいるフォロワーのinboxに、CreateのActivity(JSON)を署名つきのリクエストでPOSTします。
POSTリクエストを投げる時はminetype
Content-type:application/activity+json
が必須です。
- 投稿文を作る
- 作った投稿文をデータベースに登録する
- 作った投稿文を配送するための箱に入れる
- 投稿文を入れた箱を配送する
わかったようなわからないような例えですみません、具体例を以下に並べます。
投稿文:「ちくしょお。鼻水があかん。抗ヒスタミン薬投入するしかないか…。」
- ローカルタイムライン(サーバーに登録したユーザーの投稿が流れるタイムライン)のために、投稿文をデータベースに登録します。
- フォロワーの所属するサーバーに投稿文を投げるための投稿文の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
|
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

