From fedfe8f7d6f78d77e9cbaf70fa8a9e8df38463f7 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 1 Jul 2020 12:26:07 +0200 Subject: [PATCH] ActivityPub: Handle clashing nicknames for the same ap id 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 | 12 ++++++++++ test/user_test.exs | 25 ++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 05bd824f5..94117202c 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1371,6 +1371,16 @@ def fetch_and_prepare_user_from_ap_id(ap_id) 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 @@ def make_user_from_ap_id(ap_id) 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() diff --git a/test/user_test.exs b/test/user_test.exs index 9b66f3f51..7126bb539 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -597,6 +597,31 @@ test "updates an existing user, if stale" 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)