GNU socialのバグ修正(2023年8月20日)

コミット
5f5b422f8e
パッチ
git patch コマンド用(bugfix_20230820.git.patch.txt)
通常の patch コマンド用(bugfix_20230820.patch.txt)
修正ファイル
plugins/ActivityPub/ActivityPubPlugin.php
plugins/ActivityPub/lib/models/Activitypub_notice.php

修正内容

連合の無いサーバーからの「いいね」は表示されない様ですが、増殖を修正する前から同様なため、これは一旦そのままです。

修正の詳細

上記コミットの内容や issue もご参照ください。

(1.1)返信される時に増殖する原因

(1.2)返信された時に増殖しなくなる修正

(2023-08-22)この修正はうまく機能してゐない可能性があります。

「uriを元にローカルのDBから投稿を探す」箇所に『「AP向け」のuriを元に「ローカル向け」uriの投稿を探す。』処理を追加する事で、 「ローカル向け」投稿がみつかれば、それが返信と結びつく様にしました。

具体的には「ActivityPubPlugin.php」のメソッド「grab_notice_from_url」で投稿IDを元に「Notice::getByID($id)」を呼び出します。この戻り値は「ローカル向け」のURLになります。メソッド「grab_notice_from_url」は、リモートから返信などのアクティビティを受けた際に、アクティビティとローカル投稿とを結びつけるために呼び出されます。

ActivityPubPlugin.php:

- $candidate = Notice::getByID((int)substr($url, (strlen(Activitypub_notice::note_uri(0))-1)));
+ $id = (int)substr($url, (strlen(Activitypub_notice::note_uri(0))-1));
+ if ($id <= 0) {
+    $id = (int)basename($url);
+ }
+ $candidate = Notice::getByID($id);
if (Activitypub_notice::note_uri($candidate->getID()) === $url) { // Sanity check
    return $candidate;
+ } elseif ($candidate->getLocalUrl() === $url) { // Sanity check (url starts with 'tag:')
+     return $candidate;
} else {
    common_debug('ActivityPubPlugin Notice Grabber: '.$candidate->getUrl(). ' is different of '.$url);
}

(1.3)外部に返信した時に増殖する原因

「返信された」側のログ「ActivityPub Inbox: Request contents:」を観察。(異なる投稿への返信のためid 256,209 の差はどうでもいい)

[gs->gs]
$ grep 'res-58' public/gnusocial.log
"inReplyTo":"https://gs.bibi.moe/notice/254"
(前後略)
[mastodon->gs]
$ grep 'mstdn.jpから'
public/gnusocial.log
"inReplyTo":"httpps://gs.bibi.moe/object/note/209"
(前後略)

(1.4)外部に返信した時に増殖しなくなる修正

GNU social から外部サーバーに返信する際に、inReplyTo の値に「url(/notice/xxx)」ではなく「uri(/object/note/xxx)」を指定します。これで mastodon と同じ挙動になります。

具体的には「Activitypub_notice.php」のメソッド「getUri」を編集して返却値を変更します。メソッド「getUri」の戻り値は inReplyTo に代入されます。

Activitypub_notice.php:

+ $uri = $notice->getUri();
+ if (common_valid_http_url($uri)) {
+     return $uri;
+ }
return $notice->getUrl();

(2) リモートの会話のツリーをつなげる修正

GNU socialの同じサーバー同士会話を、別サーバーから取得すると、ツリーが正しく繋がらず、返信が孤立する事がありました。

リモートの会話を取得する時は、返信元の投稿がすでにデータベースにあるのに、もう1度保存を試みて失敗し、返信が繋がりませんでした。

これを修正するには「ActivityPubPlugin.php」のメソッド「grab_notice_from_url」で、投稿がすでにデータベースにある場合、データベースから投稿の URL を取得します。

ActivityPubPlugin.php:

+    try {
+        return Notice::getByUri($object['id']);
+    } catch (Exception $e) {
+        // NOOP
+    }
return Activitypub_notice::create_notice($object, $acclaimed_actor_profile);

ローカルの会話をリモートに通知する時は、返信先の投稿 URL が「ドメイン/activity/xxx」の形式で指定され、リモートのサーバーはこれをうまく紐付けられませんでした。

これを修正するには、「Activitypub_notice.php」のメソッド「getUri」を修正して「'ドメイン/object/note/xxx'」の形式が返却される様にします。

Activitypub_notice.php:

if ($notice->isLocal()) {
-    return common_local_url('apNotice', ['id' => $notice->getID()]);
+    return self::note_uri($notice->getID());
 } else {
+    $uri = $notice->getUri();
+    if (common_valid_http_url($uri)) {
+        return $uri;
+    }
     return $notice->getUrl();
 }