ActivityPubサーバーで投稿の編集

フェディバースのタイムラインに定期的に流れてくる「投稿を編集したい」「編集できるの?」
これは
「サーバーが対応していれば」投稿の編集更新はできます。
ということになる。
自分のいるサーバーが
「投稿の編集」に対応しているなら「編集」して書き直した投稿はホームタイムライン、ローカルタイムラインに反映される。
「投稿の編集」に対応していなければ「編集」するリンクがなかったり「破棄して下書きに戻す」になってたりする、はず。
さらには、投稿の編集に対応している自分のいるサーバーで「編集」しても、フォロワーさんのいるサーバーが対応しているとは限らない。
自分は編集して、ホームタイムラインを見たら誤字も直ってるのに、編集更新未対応のサーバーにいるフォロワーさんのタイムラインでは誤字のまま、ということが起こる。
で、どうしてサーバーごとで対応が違うのかということになるんだけど。
(また、なんか前置きが長くなりそうな…)
ActivityPubの仕様に「Update」というActivityがある。
https://argrath.github.io/activitypub/#update-activity-inbox
これを使ってリクエストを投げれば、文字通り、投稿だけじゃなくてプロフィールなども「アップデート」=「編集更新」することができる。
仕様上できるとはいえ、投稿(Note)の編集更新(Update)はちょっと考えなきゃいけないこともある。
1)1つの投稿には1つのIDが振られる。
2)IDが(No.123)の投稿「タヌキそばとキツネうどん?そりゃタヌキそばに決まってるよ!」がタイムラインに流れてきたのを読んで「おれもだ!」と賛同の「イイネ」
3)後日、ID(No.123)の投稿を見てみたら「タヌキそば?ぷぷぷ、キツネうどんに決まってんじゃん」
4)え?なんで?おれの「イイネ」はたぬきそばにつけたんだが?
投稿の編集更新は、同じIDなのに、中身が全然違ってしまう、ということが起こるかもしれない。
なもんで、Update、投稿の編集の実装には慎重になるということもあるんじゃないかな。
「編集する」ではなくて「破棄して下書きに戻す」(改めて新規投稿する)
という方法で、別IDを振ることで上記の問題は回避できる。
投稿を編集したい・書き直したい、という要求の一番は「誤字脱字の修正」ぐらいだろうし、そんな神経質にならんでも?
とはいえ、不特定多数の参加するコミュニティだし、リスク回避最優先、てことかなあ。
とか、是非の分かれるところがあったりなかったり。
わたしは、ひとつのIDの中身が変わるのは気持ち悪いんで、削除&新規投稿の方がいいかなあ(誤字なんかは後からいくらでも湧いてきてキリがないので放置)
編集更新と違って、削除はだいたいすべてのサーバーが対応してるし。
とはいえ、NoteのUpdate実装は手間もないので実装済(送信)
(受信については、ウチはそもそも投稿の保存数が上限20個なので、Updateが流れてきた時にはすでに元の投稿は流れた後、ということもあるんで未実装)
UpdateのActivityが以下
{
"@context": [
"https://www.w3.org/ns/activitystreams",
{
"Hashtag": "as:Hashtag",
"toot": "http://joinmastodon.org/ns#",
"Emoji": "toot:Emoji",
"sensitive": "as:sensitive",
},
"https://w3id.org/security/v1"
],
"type": "Update",
"id": "https://tokoroten.doncha.net/t2aki/d378b480-a8b3-11f0-a5cb-d391bfe3cb70",
"url": "https://tokoroten.doncha.net/t2aki/d378b480-a8b3-11f0-a5cb-d391bfe3cb70",
"published": "2025-10-14T04:11:14Z",
"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/05976-20251014",
"url": "https://tokoroten.doncha.net/t2aki/items/05976-20251014",
"published": "2025-10-14T04:04:32Z",
"to": ["https://www.w3.org/ns/activitystreams#Public"],
"cc": ["https://tokoroten.doncha.net/t2aki/followers"],
"attributedTo": "https://tokoroten.doncha.net/t2aki",
"content": "編集更新対応の確認\u003cbr /\u003e→ここは対応している",
"updated": "2025-10-14T04:11:14Z",
}
}
Updateのオブジェクトに、編集したNoteのJSONに「updated」を追加して、リクエストを投げると受け取ったサーバーがUpdateに対応してれば、編集更新を反映してくれる。

↑mstdn.socialで受け取って編集が反映してるところを確認。
ちなみに「updated」の追加が必要なのはMastodonで、Misskey系iceshrimpは「updated」は不要だった。
サーバーごとで微妙に違うことが多いので、やっぱり現物合わせになる…
これもホームページの「おひとり様ActivityPubサーバーの自作実装」に追加しておこう。
元WINDOWS10のノパソにlinux mint

先日、Mac miniをlinux mintにしたのに続いて、今回は元WINDOWS10のノートパソコン、ASUSのvivobookにlinux mintを入れた。
Mac miniはすんなり特に問題もなかったんだけど、元WINDWOS10のノパソはハマりどころがあったのでメモ。
インストールに準備するものは前回と同じ
前回と違うのはインストールに使ったlinuxのバージョンがlinux mint Xfce22.1から22.2にひとつ新しくなったところ。
インストール用に作ったUSBメモリを挿して、F2を押しながら電源をONして、Bios画面を開く(Bios画面を開くやり方はメーカーごとで違う、かな)
BOOTでUSBを選んでlinux mint起動。
Macの時は画面の案内どおりに進めていけばOKだったけど、進めていくと今回はメディアコーデックを利用するにはセキュアなんちゃらが必要で、と言うところで固まった。確かMac miniの時にこんなことは起こらなかった。
ふりだしに戻る
まだ何もしてないんで、気楽に電源を落してやりなおし。
USBメモリを挿して再び電源ONしたらエラーメッセージを吐いて起動しなくなった。
ふりだしに戻る
エラーメッセージをうろ覚えでとりあえず検索したら同じ現象を解決したひとのサイトが見つかった。
「Linux mintインストール時に起こったエラーを解決」
めちゃくちゃ感謝するしかない。
エラーメッセージ:
Failed to open \EFI\BOOT\mmx64.efi - Not Found
Failed to load image : Not Found
Failed to start MokManager : Not Found
Something has gone seriously wrong : import_mok_state() failed: Not Found
解決方法:
インストール用USBメモリの中に「/EFI/boot/」にある「grubx64.efi」を「mmx64.efi」にリネーム
エラーメッセージ:
error: shim_lock protocol not found.
error: you need to load the kernel first.
Press any key to continue...
解決方法:
BIOSメニューでSecure BootをDisableにする
以上でインストール時のエラーは解決して無事linux mintが立ち上がった。
その後の設定でもハマりどころがあったのでメモ。
【その1】起動時にUSBメモリをマウントする
今回インストールしたノパソ
ストレージが32Gしかない。
WINDOWS10の大型アップデートに追随できず、8ヶ月ぐらいしか使えず、その後、CloudreadyというOSを入れて、さらにChromeOS Flexにして使ってきたもの。
ストレージが少ないので、外付けSDカードメモリやUSBメモリが必須。
linux mintでも当たり前に外付けのストレージを認識して使える。
んだけど、ちょっとクセがあった。
起動時にすでに挿さってるUSBやSDのメモリは
「認識するけどマウントしていない」
という状態。マウントしないとメモリの中のファイルにアクセスできない=使えない。
Thunarというファイラー(エクセスプローラー?)を開いて、認識されているメモリをクリックして開こうとして初めて、マウントされるようだ。
マウントするためだけにファイラーをいちいち開くのは面倒くさい。
「/media/username/」にマウントポイントのディレクトリを作成してコマンドラインでマウントできれば手っ取り早い。
sudo mount /dev/sda1 /media/username/usb
マウントはできてUSBの中を読むことはできる。でも、所有者もグループもrootで、書きこむにはroot権限が必要。
↑[10/08 16:38:31]追記
sudo mount -o defaults,uid=1000,gid=1000 /dev/sda1 /media/username/usb
手動でマウントする時にオプションを指定すればユーザー権限のファイルとしてマウントできるので問題はない。
検索しまくって
「/etc/fstab」にUSBメモリの情報を追加編集することでパソコン起動時にUSBメモリを認識&マウントできるようになった。
1)マウントポイントのディレクトリ
→「/media/username/usb」
2)認識されているデバイスを調べる
→lsblk

(すでにマウント済みの表示だけど)認識されている外付けメモリは「/dev/sda」と「/dev/sdb」。
「/dev/sda」にある「/dev/sda1」というパーティションを自動マウントの対象にする。
3)メモリのUUIDなどを調べる
→blkid /dev/sda1
/dev/sda1:
LABEL="USBDrive1" UUID="1880-4B4F"
BLOCK_SIZE="512" TYPE="exfat"
PARTUUID="21a0e8cc-01"
必要なのは「UUID」と「TYPE」
4)「/etc/fstab」に追加編集
→sudo vim /etc/fstab
※「/etc」以下にあるファイルは間違うとシステム全体にかかわるので取り扱い要注意。バックアップを取ってから作業するのが吉

UUID=1880-4B4F /media/t2akii/USBDrive1 exfat defaults,nofail,uid=1000,gid=1000 0 2
「UUID」「マウントポイント」「ファイルタイプ」「オプション」「ダンプ」「パス」をfstabの末尾に設定する。
マウントポイントは(1)、UUIDとファイルタイプは(2)で調べたもの。
オプションは「defaults」(だいたいデフォルト)「nofail」(マウントに失敗しても無視して起動)
uid(ユーザーID)gid(グループID)は一般ユーザーは1000ということでOKっぽい。
ダンプやパスは呪文でOK。
5)fstabにエラーがないか確認
→sudo findmnt --verify --verbose
エラーがあると最悪の場合、システムが起動しなくなるのでエラーのないことを必ず確認
sudo mount -a
さらにとりあえず手動でマウントしてみて問題がなれば、再起動。
以上で、起動時にマウントされて、USBメモリにフルアクセスできるようになっている、はず。
【その2】CapsキーとControlキーを入れかえる
HOMEディレクトリにふたつファイルを作ればOK
・「.Xmodmap」
clear lock
clear control
keycode 66 = Control_L
add control = Control_L Control_R
・「.xinitrc」
#!/bin/sh
usermodmap=$HOME/.Xmodmap
if [ -f $usermodmap ]; then
xmodmap "$usermodmap"
fi
「設定マネージャー」に「キーボード」というのがあって「レイアウト」変更もできるっぽいんだけど、試行錯誤してもうまくいかなかったんで、上記のファイルを作って解決しておいた。
その後の設定でハマったのは
ChromeOS Flexで使ってた時はマウントもキーの入れ替えもChromeOSでの設定で、ほぼ何も気にせず使えてたから。LinuxにしたMacはHDDもそこそこ大きいので外付けストレージは滅多に使わないし、キーボードはHHKBなのでそのまま使えたから。
自分で調べてゴソゴソやる必要もなかったんで、今回改めてハマってしまった。
仕事でMSやAdobeを要求されることも少なくなったし、パソコンまわりはlinuxで十分だなあ。
GBLシーズン「変わりゆく物語」でACE到達

今日、GOバトルリーグでACEに到達。
9/16に初期レート1812でレート戦に入って、レート1700台の沼に沈んだりしつつ、今日レート2024でACE。
今回はレート戦になって1700台に沈んでからパーティを固定してやってみた。
110戦66勝、勝率6割で2024まで上げられたので、パーティ構築はそれなりだったと思う。
どんなパーティを使ったところで苦手なポケモンはいるもんで、上手いひとなら劣勢を立ち回り(プレイング)でひっくり返したりできるんだけど、わたし程度だと無理。
わたしが取ることのできる対策はひとつだけ
「そのポケモンが出てきたら試合は諦める」
運が悪かった、マッチングに嫌われたということで、切りかえる。
そして、そのうち美味しいマッチングの波がくるに違いない、だ。
にしても、パーティを固定すると「覚えゲー」「作業ゲー」っぽくてマンネリ感。
…なもんで、5セット(フルセット)は飽きちゃって気力も続かない。一日3セットを目処にやるようにした。

ブログのアクセス制限

去年あたりから、たぶんAIがらみでのコンテンツ収集と思うんだけど、クローラーやBOT=人間以外のアクセスが増えている。
当ブログのエントリを秒刻みで地引き網してるんで、さすがにそれどうなの?ということで今月からアクセス制限することにした。
今日時点でブログのエントリ数は3000ちょっとで、さらに個別、年月日別、カテゴリ別等々、リンク数はエントリ数の何倍かは多い。同じエントリなのに、リンクが違うといちいちアクセスすることになる。
この程度のボリュームで負荷どうこうはないはずだけど、レンタルサーバーに間借りしてる立場だし、ちょっと意識したほうがいいよなあ、と。
てことで。
アクセスのremote addrからhostnameを引いて、ドメインが取得できないもの、ccTLD(国別のドメイン)で日本語話者ではなさそうな国のドメインなど、かなりがっつり制限をかけた。
それらのアクセスはすべてホームページ「On Golden Pond」へ、301リダイレクト。
ホームページの方は、各ページが全部ペラ一枚の静的ページだし、アクセスが集中したところで表示速度に影響が出るようなこともないだろうし。
AIにコンテンツを収集されることに対して、特に問題とは思ってなくて、むしろ、ウチのイイ加減なデタラメをどっさり食べて、元気に育っておくれ、なんだけど!
アクセス頻度というかアクセスのやりかたを考えていただけませんかねえ。

ActivityPubサーバーに引用を実装

自作実装のActivityPubサーバーに「引用」を実装した。
引用ってナニ?
気になる投稿を見かけて、その投稿についてコメントをつけたい、なんて思った時にその投稿を自分の投稿に埋めこむ、文字通り「引用」する機能。
XなどのSNSではすでに利用されていて、フェディバースでもMisskeyやFedibird、kmyblueなどのサーバーでは実装されている。
なんで今さら?
つい先日、フェディバースでもっともポピュラーなMastodonというサーバーがこの「引用」を実装して運用を始めたから。
「引用」はXなんかのSNSでよく見られる「どれどれ、おれさまがモノ申してやろう」によく使われている。
投稿主の意図とは関係なく「晒しあげ」に使われることが多い、という問題を抱えているんで、Mastodonは引用の導入に消極的だという話があった。
てこともあってのことだと思うけど、引用の導入については、引用する該当の投稿が引用を許可しているか、偽装されていないかなど、ハードルを設けている。
わたしの場合、「おれさまがモノ申す」するような、みっともないマネはしたくない、でも、自分の過去投稿を引用したいことは「言い足したい」などでけっこうある。
ということで、ウチに実装する「引用」は、自分の投稿を自分で引用する「自己完結型」引用とする。
という無駄に長い前置き…老人の特権で勘弁してください。
で、引用の実装。
https://codeberg.org/fediverse/fep/src/branch/main/fep/044f/fep-044f.md
↑Mastodonの引用について
これがすべて。
・引用の許可
投稿のJSONに「引用を許可します」を明記する
"interactionPolicy":{"canQuote":{"automaticApproval":["https://www.w3.org/ns/activitystreams#Public"]}}
「interactionPolicy」というそのまんまの要素に、「canQuote」というそのまんまのキー。この値に「public」が指定されていると誰でも引用できる投稿となる。
・投稿を引用する
引用が許可された投稿を引用する
"quote": "https://tokoroten.doncha.net/t2aki/items/05829-20250921",
"quoteUrl": "https://tokoroten.doncha.net/t2aki/items/05829-20250921",
"quoteUri": "https://tokoroten.doncha.net/t2aki/items/05829-20250921",
"_misskey_quote": "https://tokoroten.doncha.net/t2aki/items/05829-20250921",
引用する投稿をJSONに記載する。Mastodonは「quote」だけど、すでに実装済みのサーバーとの互換のために「_misskey_quote」なども記載しておく。
この投稿には引用がついていて、引用する投稿のURLを書いておくね、ということになる、かな。
・引用のチェック
引用を含んだ投稿を受け取ったサーバーは、その引用が「正しいのか/表示していいのか」を確認する必要がある。
引用を含んだ投稿には、引用する投稿のURLのほかに「quoteAuthorization」のURLを記載する。
"quoteAuthorization": "https://tokoroten.doncha.net/t2aki/quote_auth/05833",
このURLにGETでリクエストして、返ってくるJSONで引用の整合性を確認する。
以下が「quoteAuthorization」が返すJSON
{
"@context": [
"https://www.w3.org/ns/activitystreams",
{
"gts": "https://gotosocial.org/ns#",
"quoteAuthorization": {
"@id": "https://w3id.org/fep/044f#quoteAuthorization",
"@type": "@id"
},
"interactingObject": {
"@id": "gts:interactingObject"
},
"interactionTarget": {
"@id": "gts:interactionTarget"
}
}
],
"id": "https://tokoroten.doncha.net/t2aki/quote_auth/05833",
"type": "QuoteAuthorization",
"attributedTo": "https://tokoroten.doncha.net/t2aki",
"interactingObject": "https://tokoroten.doncha.net/t2aki/items/05833-20250921",
"interactionTarget": "https://tokoroten.doncha.net/t2aki/items/05829-20250921"
}
以下すべての一致が確認できたら引用として表示される。
・idと引用投稿の「quoteAuthorization」
・attributedToと引用される投稿のattributedTo
・interactionObjectと引用投稿のid
・interactionTargetと引用される投稿のid
以上で最低限、自己完結型引用を投稿できる

↑mastodon.socialで引用投稿を表示
上記はいろいろ省略してる。
contextに記載するものもそうだけど、自己完結じゃない場合、ひとさまの投稿を引用する時にはリクエストのキャッチボールが生じるので対応が必要となる。
その投稿を引用したい!
・「"type": "QuoteRequest"」のActivityを引用したい投稿の主にPOSTでリクエストする。
・リクエストを受けたら承認(Accept)/拒否(Reject)のリクエストを返す。
返事を見てから引用をする/しない。
とはいえ、自己完結型は承認もなにもないので、このへんはばっさりスルー。
引用したい側は、引用元に可否を問い合わせるのは「MUST」
引用される側は、返事する/しないはおまかせ
ということだし。
このブログはもともとコード掲載することを考えてなくて、めっちゃ見にくいんで、そのうちホームページの方に改めて掲載します。
「おひとり様ActivityPubサーバーの自作実装::On Golden Pond」
今日時点、引用にしても絵文字にしても、ActivityPubの仕様にはない(?)ので、サーバーごとで対応にバラつきがあって、現物合わせの手探り。
判じ物、当たるも八卦当たらぬも八卦(死語)の世界だなあ。
[09/22 09:50:38]追記
あれ?自己完結するなら、interactionPolicyは不要な気がする。
あとで検証してみよう
[09/23 23:09:35]追記
intractionPolicyは不要だった。
これは「引用しようとするひと向け」のもので、自己完結するなら不要。
intractionPolicyは本家Mastodonの引用制御
・誰でも引用できる
・followerまでが引用できる
・引用できるのは自分だけ
この選択のためにある。
引用を含んだ投稿を表示させる時に、引用されている投稿の引用ポリシーを確認にくるのでは、と疑ったんだけど、アクセスログを見てもそんな形跡もなかった。
ということはquoteAuthorizationの設定だけ約束どおり作っておけば、引用を含んだ投稿を意図通り表示してくれる。

