ActivityPub: Handle clashing nicknames for the same ap id
authorlain <lain@soykaf.club>
Wed, 1 Jul 2020 10:26:07 +0000 (12:26 +0200)
committerlain <lain@soykaf.club>
Wed, 1 Jul 2020 10:26:07 +0000 (12:26 +0200)
If we get a new user (identified by ap_id) that would have the same
nickname as an existing user, give the existing user a nickname that
is prepended with the user id, as this will never clash.

This can happen when a user switches server software and that soft-
ware generates ap ids in a different way.

lib/pleroma/web/activity_pub/activity_pub.ex
test/user_test.exs

index 05bd824f58d2edef836f1fdc18a7f6361b386b2f..94117202c25a003d6db769b2be48c159e9a17d56 100644 (file)
@@ -1371,6 +1371,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     end
   end
 
+  def maybe_handle_clashing_nickname(nickname) do
+    with %User{} = old_user <- User.get_by_nickname(nickname) do
+      Logger.info("Found an old user for #{nickname}, ap id is #{old_user.ap_id}, renaming.")
+
+      old_user
+      |> User.remote_user_changeset(%{nickname: "#{old_user.id}.#{old_user.nickname}"})
+      |> User.update_and_set_cache()
+    end
+  end
+
   def make_user_from_ap_id(ap_id) do
     user = User.get_cached_by_ap_id(ap_id)
 
@@ -1383,6 +1393,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
           |> User.remote_user_changeset(data)
           |> User.update_and_set_cache()
         else
+          maybe_handle_clashing_nickname(data[:nickname])
+
           data
           |> User.remote_user_changeset()
           |> Repo.insert()
index 9b66f3f51db7cb2672b6f6680b59b26a0c3234ad..7126bb539adbbdd78abe84e3010e7ffcf6f83d3b 100644 (file)
@@ -597,6 +597,31 @@ defmodule Pleroma.UserTest do
       refute user.last_refreshed_at == orig_user.last_refreshed_at
     end
 
+    test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
+      a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
+
+      orig_user =
+        insert(
+          :user,
+          local: false,
+          nickname: "admin@mastodon.example.org",
+          ap_id: "http://mastodon.example.org/users/harinezumigari",
+          last_refreshed_at: a_week_ago
+        )
+
+      assert orig_user.last_refreshed_at == a_week_ago
+
+      {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
+
+      assert user.inbox
+
+      refute user.id == orig_user.id
+
+      orig_user = User.get_by_id(orig_user.id)
+
+      assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
+    end
+
     @tag capture_log: true
     test "it returns the old user if stale, but unfetchable" do
       a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)