Validate alias IDs
[akkoma] / lib / pleroma / user.ex
index 9240e912d9a3db676b6f19a2a95e2b932a4bf661..66664235b09c29d6190b2cd9cfcbf12ca7e92865 100644 (file)
@@ -47,6 +47,8 @@ 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])?)*$/
+  # credo:disable-for-next-line Credo.Check.Readability.MaxLineLength
+  @url_regex ~r/https?:\/\/[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&\/=]*)/
 
   @strict_local_nickname_regex ~r/^[a-zA-Z\d]+$/
   @extended_local_nickname_regex ~r/^[a-zA-Z\d_-]+$/
@@ -89,6 +91,7 @@ defmodule Pleroma.User do
     field(:keys, :string)
     field(:public_key, :string)
     field(:ap_id, :string)
+    field(:ap_aliases, {:array, :string}, default: [])
     field(:avatar, :map, default: %{})
     field(:local, :boolean, default: true)
     field(:follower_address, :string)
@@ -2268,4 +2271,38 @@ defmodule Pleroma.User do
     |> Map.put(:bio, HTML.filter_tags(user.bio, filter))
     |> Map.put(:fields, fields)
   end
+
+  def add_aliases(%User{} = user, aliases) when is_list(aliases) do
+    alias_set =
+      (user.ap_aliases ++ aliases)
+      |> MapSet.new()
+      |> MapSet.to_list()
+
+    user
+    |> change(%{ap_aliases: alias_set})
+    |> validate_ap_aliases()
+    |> Repo.update()
+  end
+
+  def delete_aliases(%User{} = user, aliases) when is_list(aliases) do
+    alias_set =
+      user.ap_aliases
+      |> MapSet.new()
+      |> MapSet.difference(MapSet.new(aliases))
+      |> MapSet.to_list()
+
+    user
+    |> change(%{ap_aliases: alias_set})
+    |> validate_ap_aliases()
+    |> Repo.update()
+  end
+
+  defp validate_ap_aliases(changeset) do
+    validate_change(changeset, :ap_aliases, fn :ap_aliases, ap_aliases ->
+      case Enum.all?(ap_aliases, fn a -> Regex.match?(@url_regex, a) end) do
+        true -> []
+        false -> [ap_aliases: "Invalid ap_id format. Must be a URL."]
+      end
+    end)
+  end
 end