Merge remote-tracking branch 'upstream/develop' into aliases
authorAlex Gleason <alex@alexgleason.me>
Wed, 14 Oct 2020 00:25:18 +0000 (19:25 -0500)
committerAlex Gleason <alex@alexgleason.me>
Wed, 14 Oct 2020 00:25:18 +0000 (19:25 -0500)
CHANGELOG.md
docs/API/differences_in_mastoapi_responses.md
lib/pleroma/user.ex
lib/pleroma/web/api_spec/operations/account_operation.ex
lib/pleroma/web/api_spec/schemas/account.ex
lib/pleroma/web/mastodon_api/controllers/account_controller.ex
lib/pleroma/web/mastodon_api/views/account_view.ex
lib/pleroma/web/web_finger.ex
test/pleroma/web/mastodon_api/update_credentials_test.exs
test/pleroma/web/mastodon_api/views/account_view_test.exs
test/pleroma/web/web_finger/web_finger_controller_test.exs

index 8fc1750d181088c9476145faa312b42ae8d3c939..6107ac07eb2cde634efd2124782920c9b28f9bfd 100644 (file)
@@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - Mix tasks for controlling user account confirmation status in bulk (`mix pleroma.user confirm_all` and `mix pleroma.user unconfirm_all`)
 - Mix task for sending confirmation emails to all unconfirmed users (`mix pleroma.email send_confirmation_mails`)
 - Mix task option for force-unfollowing relays
+- Ability to set ActivityPub aliases for follower migration.
 
 ### Changed
 
index 38865dc68a8b4393a7c40d23eceacebf1a7bf434..3cb2183bdda74f0dcaeaf894fab1d2587622b98c 100644 (file)
@@ -184,6 +184,7 @@ Additional parameters can be added to the JSON body/Form data:
 - `pleroma_settings_store` - Opaque user settings to be saved on the backend.
 - `skip_thread_containment` - if true, skip filtering out broken threads
 - `allow_following_move` - if true, allows automatically follow moved following accounts
+- `also_known_as` - array of ActivityPub IDs, needed for following move
 - `pleroma_background_image` - sets the background image of the user. Can be set to "" (an empty string) to reset.
 - `discoverable` - if true, discovery of this account in search results and other services is allowed.
 - `actor_type` - the type of this account.
index 09ea8079391b6b8c7c882ee7d19778e58c1bce42..d66c92b14916b2a537b9553559c8ef25b8cccbd7 100644 (file)
@@ -51,6 +51,7 @@ defmodule Pleroma.User do
 
   # credo:disable-for-next-line Credo.Check.Readability.MaxLineLength
   @email_regex ~r/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
+  @url_regex ~r/^https?:\/\/[^\s]{1,256}$/
 
   @strict_local_nickname_regex ~r/^[a-zA-Z\d]+$/
   @extended_local_nickname_regex ~r/^[a-zA-Z\d_-]+$/
@@ -489,6 +490,7 @@ defmodule Pleroma.User do
         :hide_follows_count,
         :hide_favorites,
         :allow_following_move,
+        :also_known_as,
         :background,
         :show_role,
         :skip_thread_containment,
@@ -497,12 +499,12 @@ defmodule Pleroma.User do
         :pleroma_settings_store,
         :discoverable,
         :actor_type,
-        :also_known_as,
         :accepts_chat_messages
       ]
     )
     |> unique_constraint(:nickname)
     |> validate_format(:nickname, local_nickname_regex())
+    |> validate_also_known_as()
     |> validate_length(:bio, max: bio_limit)
     |> validate_length(:name, min: 1, max: name_limit)
     |> validate_inclusion(:actor_type, ["Person", "Service"])
@@ -2396,4 +2398,13 @@ defmodule Pleroma.User do
     |> Map.put(:bio, HTML.filter_tags(user.bio, filter))
     |> Map.put(:fields, fields)
   end
+
+  defp validate_also_known_as(changeset) do
+    validate_change(changeset, :also_known_as, fn :also_known_as, also_known_as ->
+      case Enum.all?(also_known_as, fn a -> Regex.match?(@url_regex, a) end) do
+        true -> []
+        false -> [also_known_as: "Invalid ap_id format. Must be a URL."]
+      end
+    end)
+  end
 end
index d90ddb78714151d513b798bc99e11e1db275dca0..51f0e5ef824b2fe69c930672315b7875c294f91a 100644 (file)
@@ -600,6 +600,12 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
           nullable: true,
           description: "Allows automatically follow moved following accounts"
         },
+        also_known_as: %Schema{
+          type: :array,
+          items: %Schema{type: :string},
+          nullable: true,
+          description: "List of alternate ActivityPub IDs"
+        },
         pleroma_background_image: %Schema{
           type: :string,
           nullable: true,
@@ -630,6 +636,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
         pleroma_settings_store: %{"pleroma-fe" => %{"key" => "val"}},
         skip_thread_containment: false,
         allow_following_move: false,
+        also_known_as: ["https://foo.bar/users/foo"],
         discoverable: false,
         actor_type: "Person"
       }
index ca79f0747861b93bb63e5d40022878369ffad247..cf743932cae8561028a1fabf89d8209e6a7e18e2 100644 (file)
@@ -40,6 +40,8 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
       pleroma: %Schema{
         type: :object,
         properties: %{
+          ap_id: %Schema{type: :string},
+          also_known_as: %Schema{type: :array, items: %Schema{type: :string}},
           allow_following_move: %Schema{
             type: :boolean,
             description: "whether the user allows automatically follow moved following accounts"
index 4f9696d5265b65a57bb57a4f339adb9a8425652b..2b981a86467458c167dcc9ab228c029b3f8c46eb 100644 (file)
@@ -186,6 +186,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
         :show_role,
         :skip_thread_containment,
         :allow_following_move,
+        :also_known_as,
         :discoverable,
         :accepts_chat_messages
       ]
@@ -210,6 +211,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
         if bot, do: {:ok, "Service"}, else: {:ok, "Person"}
       end)
       |> Maps.put_if_present(:actor_type, params[:actor_type])
+      |> Maps.put_if_present(:also_known_as, params[:also_known_as])
 
     # What happens here:
     #
index 121ba1693155adf30f4c17b9be4d0c9b111bf001..f17c5a2397a417019595ee843ab55e74895bff61 100644 (file)
@@ -269,6 +269,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
       # Pleroma extension
       pleroma: %{
         ap_id: user.ap_id,
+        also_known_as: user.also_known_as,
         confirmation_pending: user.confirmation_pending,
         tags: user.tags,
         hide_followers_count: user.hide_followers_count,
index 6629f5356fb9038ae389aee5beeded159cbd2803..2de945ae514b42d3c0dd0fad80fb1234eaeba3ea 100644 (file)
@@ -58,12 +58,16 @@ defmodule Pleroma.Web.WebFinger do
     ] ++ Publisher.gather_webfinger_links(user)
   end
 
+  defp gather_aliases(%User{} = user) do
+    [user.ap_id] ++ user.also_known_as
+  end
+
   def represent_user(user, "JSON") do
     {:ok, user} = User.ensure_keys_present(user)
 
     %{
       "subject" => "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host()}",
-      "aliases" => [user.ap_id],
+      "aliases" => gather_aliases(user),
       "links" => gather_links(user)
     }
   end
@@ -71,6 +75,10 @@ defmodule Pleroma.Web.WebFinger do
   def represent_user(user, "XML") do
     {:ok, user} = User.ensure_keys_present(user)
 
+    aliases =
+      gather_aliases(user)
+      |> Enum.map(fn the_alias -> {:Alias, the_alias} end)
+
     links =
       gather_links(user)
       |> Enum.map(fn link -> {:Link, link} end)
@@ -79,9 +87,8 @@ defmodule Pleroma.Web.WebFinger do
       :XRD,
       %{xmlns: "http://docs.oasis-open.org/ns/xri/xrd-1.0"},
       [
-        {:Subject, "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host()}"},
-        {:Alias, user.ap_id}
-      ] ++ links
+        {:Subject, "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host()}"}
+      ] ++ aliases ++ links
     }
     |> XmlBuilder.to_doc()
   end
index fe462caa38c07739e182c264093c2ab774280c51..0d49eb3343fff793805c8008e98325c239cf4f2d 100644 (file)
@@ -220,6 +220,16 @@ defmodule Pleroma.Web.MastodonAPI.UpdateCredentialsTest do
       assert update_activity.data["object"]["name"] == "markorepairs"
     end
 
+    test "updates the user's AKAs", %{conn: conn} do
+      conn =
+        patch(conn, "/api/v1/accounts/update_credentials", %{
+          "also_known_as" => ["https://mushroom.kingdom/users/mario"]
+        })
+
+      assert user_data = json_response_and_validate_schema(conn, 200)
+      assert user_data["pleroma"]["also_known_as"] == ["https://mushroom.kingdom/users/mario"]
+    end
+
     test "updates the user's avatar", %{user: user, conn: conn} do
       new_avatar = %Plug.Upload{
         content_type: "image/jpg",
index a5f39b215dd6e5ad92ba2962b49506ed21abaa60..20e4d50709a71c61e4570d45ce9ebf606c99f9b2 100644 (file)
@@ -35,7 +35,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
           "<script src=\"invalid-html\"></script><span>valid html</span>. a<br>b<br/>c<br >d<br />f '&<>\"",
         inserted_at: ~N[2017-08-15 15:47:06.597036],
         emoji: %{"karjalanpiirakka" => "/file.png"},
-        raw_bio: "valid html. a\nb\nc\nd\nf '&<>\""
+        raw_bio: "valid html. a\nb\nc\nd\nf '&<>\"",
+        also_known_as: ["https://shitposter.zone/users/shp"]
       })
 
     expected = %{
@@ -75,6 +76,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
       },
       pleroma: %{
         ap_id: user.ap_id,
+        also_known_as: ["https://shitposter.zone/users/shp"],
         background_image: "https://example.com/images/asuka_hospital.png",
         favicon: nil,
         confirmation_pending: false,
@@ -173,6 +175,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
       },
       pleroma: %{
         ap_id: user.ap_id,
+        also_known_as: [],
         background_image: nil,
         favicon: nil,
         confirmation_pending: false,
index 0023f1e810e4cee2bed55d0cc49f73b51fe9f334..ce9eb0650a7d05050847da2f0df4f02a8a25392b 100644 (file)
@@ -30,14 +30,24 @@ defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do
   end
 
   test "Webfinger JRD" do
-    user = insert(:user)
+    user =
+      insert(:user,
+        ap_id: "https://hyrule.world/users/zelda",
+        also_known_as: ["https://mushroom.kingdom/users/toad"]
+      )
 
     response =
       build_conn()
       |> put_req_header("accept", "application/jrd+json")
       |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost")
+      |> json_response(200)
+
+    assert response["subject"] == "acct:#{user.nickname}@localhost"
 
-    assert json_response(response, 200)["subject"] == "acct:#{user.nickname}@localhost"
+    assert response["aliases"] == [
+             "https://hyrule.world/users/zelda",
+             "https://mushroom.kingdom/users/toad"
+           ]
   end
 
   test "it returns 404 when user isn't found (JSON)" do
@@ -51,14 +61,20 @@ defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do
   end
 
   test "Webfinger XML" do
-    user = insert(:user)
+    user =
+      insert(:user,
+        ap_id: "https://hyrule.world/users/zelda",
+        also_known_as: ["https://mushroom.kingdom/users/toad"]
+      )
 
     response =
       build_conn()
       |> put_req_header("accept", "application/xrd+xml")
       |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost")
+      |> response(200)
 
-    assert response(response, 200)
+    assert response =~ "<Alias>https://hyrule.world/users/zelda</Alias>"
+    assert response =~ "<Alias>https://mushroom.kingdom/users/toad</Alias>"
   end
 
   test "it returns 404 when user isn't found (XML)" do