diff options
Diffstat (limited to 'lib')
118 files changed, 978 insertions, 490 deletions
diff --git a/lib/pleroma/activity/html.ex b/lib/pleroma/activity/html.ex new file mode 100644 index 000000000..0bf393836 --- /dev/null +++ b/lib/pleroma/activity/html.ex @@ -0,0 +1,45 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Activity.HTML do +  alias Pleroma.HTML +  alias Pleroma.Object + +  @cachex Pleroma.Config.get([:cachex, :provider], Cachex) + +  def get_cached_scrubbed_html_for_activity( +        content, +        scrubbers, +        activity, +        key \\ "", +        callback \\ fn x -> x end +      ) do +    key = "#{key}#{generate_scrubber_signature(scrubbers)}|#{activity.id}" + +    @cachex.fetch!(:scrubber_cache, key, fn _key -> +      object = Object.normalize(activity, fetch: false) +      HTML.ensure_scrubbed_html(content, scrubbers, object.data["fake"] || false, callback) +    end) +  end + +  def get_cached_stripped_html_for_activity(content, activity, key) do +    get_cached_scrubbed_html_for_activity( +      content, +      FastSanitize.Sanitizer.StripTags, +      activity, +      key, +      &HtmlEntities.decode/1 +    ) +  end + +  defp generate_scrubber_signature(scrubber) when is_atom(scrubber) do +    generate_scrubber_signature([scrubber]) +  end + +  defp generate_scrubber_signature(scrubbers) do +    Enum.reduce(scrubbers, "", fn scrubber, signature -> +      "#{signature}#{to_string(scrubber)}" +    end) +  end +end diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 06d399b2e..9824e0a4a 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -25,7 +25,7 @@ defmodule Pleroma.Application do      if Process.whereis(Pleroma.Web.Endpoint) do        case Config.get([:http, :user_agent], :default) do          :default -> -          info = "#{Pleroma.Web.base_url()} <#{Config.get([:instance, :email], "")}>" +          info = "#{Pleroma.Web.Endpoint.url()} <#{Config.get([:instance, :email], "")}>"            named_version() <> "; " <> info          custom -> @@ -102,7 +102,7 @@ defmodule Pleroma.Application do          ] ++          task_children(@mix_env) ++          dont_run_in_test(@mix_env) ++ -        chat_child(chat_enabled?()) ++ +        shout_child(shout_enabled?()) ++          [Pleroma.Gopher.Server]      # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html @@ -216,7 +216,7 @@ defmodule Pleroma.Application do        type: :worker      } -  defp chat_enabled?, do: Config.get([:chat, :enabled]) +  defp shout_enabled?, do: Config.get([:shout, :enabled])    defp dont_run_in_test(env) when env in [:test, :benchmark], do: [] @@ -237,14 +237,14 @@ defmodule Pleroma.Application do      ]    end -  defp chat_child(true) do +  defp shout_child(true) do      [ -      Pleroma.Web.ChatChannel.ChatChannelState, +      Pleroma.Web.ShoutChannel.ShoutChannelState,        {Phoenix.PubSub, [name: Pleroma.PubSub, adapter: Phoenix.PubSub.PG2]}      ]    end -  defp chat_child(_), do: [] +  defp shout_child(_), do: []    defp task_children(:test) do      [ diff --git a/lib/pleroma/application_requirements.ex b/lib/pleroma/application_requirements.ex index c412dec5e..ee6ee9516 100644 --- a/lib/pleroma/application_requirements.ex +++ b/lib/pleroma/application_requirements.ex @@ -164,9 +164,11 @@ defmodule Pleroma.ApplicationRequirements do    defp check_system_commands!(:ok) do      filter_commands_statuses = [ -      check_filter(Pleroma.Upload.Filters.Exiftool, "exiftool"), -      check_filter(Pleroma.Upload.Filters.Mogrify, "mogrify"), -      check_filter(Pleroma.Upload.Filters.Mogrifun, "mogrify") +      check_filter(Pleroma.Upload.Filter.Exiftool, "exiftool"), +      check_filter(Pleroma.Upload.Filter.Mogrify, "mogrify"), +      check_filter(Pleroma.Upload.Filter.Mogrifun, "mogrify"), +      check_filter(Pleroma.Upload.Filter.AnalyzeMetadata, "mogrify"), +      check_filter(Pleroma.Upload.Filter.AnalyzeMetadata, "convert")      ]      preview_proxy_commands_status = diff --git a/lib/pleroma/config/deprecation_warnings.ex b/lib/pleroma/config/deprecation_warnings.ex index 24aa5993b..fedd58a7e 100644 --- a/lib/pleroma/config/deprecation_warnings.ex +++ b/lib/pleroma/config/deprecation_warnings.ex @@ -41,7 +41,8 @@ defmodule Pleroma.Config.DeprecationWarnings do           :ok <- check_gun_pool_options(),           :ok <- check_activity_expiration_config(),           :ok <- check_remote_ip_plug_name(), -         :ok <- check_uploders_s3_public_endpoint() do +         :ok <- check_uploders_s3_public_endpoint(), +         :ok <- check_old_chat_shoutbox() do        :ok      else        _ -> @@ -215,4 +216,27 @@ defmodule Pleroma.Config.DeprecationWarnings do        :ok      end    end + +  @spec check_old_chat_shoutbox() :: :ok | nil +  def check_old_chat_shoutbox do +    instance_config = Pleroma.Config.get([:instance]) +    chat_config = Pleroma.Config.get([:chat]) || [] + +    use_old_config = +      Keyword.has_key?(instance_config, :chat_limit) or +        Keyword.has_key?(chat_config, :enabled) + +    if use_old_config do +      Logger.error(""" +      !!!DEPRECATION WARNING!!! +      Your config is using the old namespace for the Shoutbox configuration. You need to convert to the new namespace. e.g., +      \n* `config :pleroma, :chat, enabled` and `config :pleroma, :instance, chat_limit` are now equal to: +      \n* `config :pleroma, :shout, enabled` and `config :pleroma, :shout, limit` +      """) + +      :error +    else +      :ok +    end +  end  end diff --git a/lib/pleroma/config/loader.ex b/lib/pleroma/config/loader.ex index b64d06707..9489f58c4 100644 --- a/lib/pleroma/config/loader.ex +++ b/lib/pleroma/config/loader.ex @@ -3,19 +3,21 @@  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Config.Loader do -  @reject_keys [ -    Pleroma.Repo, -    Pleroma.Web.Endpoint, -    :env, -    :configurable_from_database, -    :database, -    :swarm -  ] - -  @reject_groups [ -    :postgrex, -    :tesla -  ] +  defp reject_keys, +    do: [ +      Pleroma.Repo, +      Pleroma.Web.Endpoint, +      :env, +      :configurable_from_database, +      :database, +      :swarm +    ] + +  defp reject_groups, +    do: [ +      :postgrex, +      :tesla +    ]    if Code.ensure_loaded?(Config.Reader) do      @reader Config.Reader @@ -52,7 +54,7 @@ defmodule Pleroma.Config.Loader do    @spec filter_group(atom(), keyword()) :: keyword()    def filter_group(group, configs) do      Enum.reject(configs[group], fn {key, _v} -> -      key in @reject_keys or group in @reject_groups or +      key in reject_keys() or group in reject_groups() or          (group == :phoenix and key == :serve_endpoints)      end)    end diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex index aad45aab8..d5c6081a2 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -13,23 +13,25 @@ defmodule Pleroma.Config.TransferTask do    @type env() :: :test | :benchmark | :dev | :prod -  @reboot_time_keys [ -    {:pleroma, :hackney_pools}, -    {:pleroma, :chat}, -    {:pleroma, Oban}, -    {:pleroma, :rate_limit}, -    {:pleroma, :markup}, -    {:pleroma, :streamer}, -    {:pleroma, :pools}, -    {:pleroma, :connections_pool} -  ] - -  @reboot_time_subkeys [ -    {:pleroma, Pleroma.Captcha, [:seconds_valid]}, -    {:pleroma, Pleroma.Upload, [:proxy_remote]}, -    {:pleroma, :instance, [:upload_limit]}, -    {:pleroma, :gopher, [:enabled]} -  ] +  defp reboot_time_keys, +    do: [ +      {:pleroma, :hackney_pools}, +      {:pleroma, :shout}, +      {:pleroma, Oban}, +      {:pleroma, :rate_limit}, +      {:pleroma, :markup}, +      {:pleroma, :streamer}, +      {:pleroma, :pools}, +      {:pleroma, :connections_pool} +    ] + +  defp reboot_time_subkeys, +    do: [ +      {:pleroma, Pleroma.Captcha, [:seconds_valid]}, +      {:pleroma, Pleroma.Upload, [:proxy_remote]}, +      {:pleroma, :instance, [:upload_limit]}, +      {:pleroma, :gopher, [:enabled]} +    ]    def start_link(restart_pleroma? \\ true) do      load_and_update_env([], restart_pleroma?) @@ -165,12 +167,12 @@ defmodule Pleroma.Config.TransferTask do    end    defp group_and_key_need_reboot?(group, key) do -    Enum.any?(@reboot_time_keys, fn {g, k} -> g == group and k == key end) +    Enum.any?(reboot_time_keys(), fn {g, k} -> g == group and k == key end)    end    defp group_and_subkey_need_reboot?(group, key, value) do      Keyword.keyword?(value) and -      Enum.any?(@reboot_time_subkeys, fn {g, k, subkeys} -> +      Enum.any?(reboot_time_subkeys(), fn {g, k, subkeys} ->          g == group and k == key and            Enum.any?(Keyword.keys(value), &(&1 in subkeys))        end) diff --git a/lib/pleroma/constants.ex b/lib/pleroma/constants.ex index b24338cc6..bf92f65cb 100644 --- a/lib/pleroma/constants.ex +++ b/lib/pleroma/constants.ex @@ -27,6 +27,4 @@ defmodule Pleroma.Constants do      do:        ~w(index.html robots.txt static static-fe finmoji emoji packs sounds images instance sw.js sw-pleroma.js favicon.png schemas doc embed.js embed.css)    ) - -  def as_local_public, do: Pleroma.Web.base_url() <> "/#Public"  end diff --git a/lib/pleroma/ecto_type/activity_pub/object_validators/recipients.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/recipients.ex index af4b0e527..06fed8fb3 100644 --- a/lib/pleroma/ecto_type/activity_pub/object_validators/recipients.ex +++ b/lib/pleroma/ecto_type/activity_pub/object_validators/recipients.ex @@ -13,21 +13,33 @@ defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.Recipients do      cast([object])    end +  def cast(object) when is_map(object) do +    case ObjectID.cast(object) do +      {:ok, data} -> {:ok, [data]} +      _ -> :error +    end +  end +    def cast(data) when is_list(data) do -    data -    |> Enum.reduce_while({:ok, []}, fn element, {:ok, list} -> -      case ObjectID.cast(element) do -        {:ok, id} -> -          {:cont, {:ok, [id | list]}} - -        _ -> -          {:halt, :error} -      end -    end) +    data = +      data +      |> Enum.reduce_while([], fn element, list -> +        case ObjectID.cast(element) do +          {:ok, id} -> +            {:cont, [id | list]} + +          _ -> +            {:cont, list} +        end +      end) +      |> Enum.sort() +      |> Enum.uniq() + +    {:ok, data}    end -  def cast(_) do -    :error +  def cast(data) do +    {:error, data}    end    def dump(data) do diff --git a/lib/pleroma/emails/admin_email.ex b/lib/pleroma/emails/admin_email.ex index 5fe74e2f7..88bc78aec 100644 --- a/lib/pleroma/emails/admin_email.ex +++ b/lib/pleroma/emails/admin_email.ex @@ -73,7 +73,7 @@ defmodule Pleroma.Emails.AdminEmail do      #{comment_html}      #{statuses_html}      <p> -    <a href="#{Pleroma.Web.base_url()}/pleroma/admin/#/reports/index">View Reports in AdminFE</a> +    <a href="#{Pleroma.Web.Endpoint.url()}/pleroma/admin/#/reports/index">View Reports in AdminFE</a>      """      new() @@ -87,7 +87,7 @@ defmodule Pleroma.Emails.AdminEmail do      html_body = """      <p>New account for review: <a href="#{account.ap_id}">@#{account.nickname}</a></p>      <blockquote>#{HTML.strip_tags(account.registration_reason)}</blockquote> -    <a href="#{Pleroma.Web.base_url()}/pleroma/admin/#/users/#{account.id}/">Visit AdminFE</a> +    <a href="#{Pleroma.Web.Endpoint.url()}/pleroma/admin/#/users/#{account.id}/">Visit AdminFE</a>      """      new() diff --git a/lib/pleroma/emails/user_email.ex b/lib/pleroma/emails/user_email.ex index 52f3d419d..e38c681ba 100644 --- a/lib/pleroma/emails/user_email.ex +++ b/lib/pleroma/emails/user_email.ex @@ -5,15 +5,22 @@  defmodule Pleroma.Emails.UserEmail do    @moduledoc "User emails" -  use Phoenix.Swoosh, view: Pleroma.Web.EmailView, layout: {Pleroma.Web.LayoutView, :email} -    alias Pleroma.Config    alias Pleroma.User    alias Pleroma.Web.Endpoint    alias Pleroma.Web.Router +  import Swoosh.Email +  import Phoenix.Swoosh, except: [render_body: 3]    import Pleroma.Config.Helpers, only: [instance_name: 0, sender: 0] +  def render_body(email, template, assigns \\ %{}) do +    email +    |> put_new_layout({Pleroma.Web.LayoutView, :email}) +    |> put_new_view(Pleroma.Web.EmailView) +    |> Phoenix.Swoosh.render_body(template, assigns) +  end +    defp recipient(email, nil), do: email    defp recipient(email, name), do: {name, email}    defp recipient(%User{} = user), do: recipient(user.email, user.name) diff --git a/lib/pleroma/emoji/formatter.ex b/lib/pleroma/emoji/formatter.ex index 50150e951..191451952 100644 --- a/lib/pleroma/emoji/formatter.ex +++ b/lib/pleroma/emoji/formatter.ex @@ -5,7 +5,7 @@  defmodule Pleroma.Emoji.Formatter do    alias Pleroma.Emoji    alias Pleroma.HTML -  alias Pleroma.Web +  alias Pleroma.Web.Endpoint    alias Pleroma.Web.MediaProxy    def emojify(text) do @@ -44,7 +44,7 @@ defmodule Pleroma.Emoji.Formatter do      Emoji.get_all()      |> Enum.filter(fn {emoji, %Emoji{}} -> String.contains?(text, ":#{emoji}:") end)      |> Enum.reduce(%{}, fn {name, %Emoji{file: file}}, acc -> -      Map.put(acc, name, to_string(URI.merge(Web.base_url(), file))) +      Map.put(acc, name, to_string(URI.merge(Endpoint.url(), file)))      end)    end diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex index 764e347ec..ae37946ab 100644 --- a/lib/pleroma/formatter.ex +++ b/lib/pleroma/formatter.ex @@ -62,7 +62,7 @@ defmodule Pleroma.Formatter do    def hashtag_handler("#" <> tag = tag_text, _buffer, _opts, acc) do      tag = String.downcase(tag) -    url = "#{Pleroma.Web.base_url()}/tag/#{tag}" +    url = "#{Pleroma.Web.Endpoint.url()}/tag/#{tag}"      link =        Phoenix.HTML.Tag.content_tag(:a, tag_text, diff --git a/lib/pleroma/gun.ex b/lib/pleroma/gun.ex index f9c828fac..bef1c9872 100644 --- a/lib/pleroma/gun.ex +++ b/lib/pleroma/gun.ex @@ -11,9 +11,7 @@ defmodule Pleroma.Gun do    @callback await(pid(), reference()) :: {:response, :fin, 200, []}    @callback set_owner(pid(), pid()) :: :ok -  @api Pleroma.Config.get([Pleroma.Gun], Pleroma.Gun.API) - -  defp api, do: @api +  defp api, do: Pleroma.Config.get([Pleroma.Gun], Pleroma.Gun.API)    def open(host, port, opts), do: api().open(host, port, opts) diff --git a/lib/pleroma/gun/connection_pool/reclaimer.ex b/lib/pleroma/gun/connection_pool/reclaimer.ex index c37b62bf2..4c643d7cb 100644 --- a/lib/pleroma/gun/connection_pool/reclaimer.ex +++ b/lib/pleroma/gun/connection_pool/reclaimer.ex @@ -5,11 +5,11 @@  defmodule Pleroma.Gun.ConnectionPool.Reclaimer do    use GenServer, restart: :temporary -  @registry Pleroma.Gun.ConnectionPool +  defp registry, do: Pleroma.Gun.ConnectionPool    def start_monitor do      pid = -      case :gen_server.start(__MODULE__, [], name: {:via, Registry, {@registry, "reclaimer"}}) do +      case :gen_server.start(__MODULE__, [], name: {:via, Registry, {registry(), "reclaimer"}}) do          {:ok, pid} ->            pid @@ -46,7 +46,7 @@ defmodule Pleroma.Gun.ConnectionPool.Reclaimer do      #   {worker_pid, crf, last_reference} end)      unused_conns =        Registry.select( -        @registry, +        registry(),          [            {{:_, :"$1", {:_, :"$2", :"$3", :"$4"}}, [{:==, :"$2", []}], [{{:"$1", :"$3", :"$4"}}]}          ] diff --git a/lib/pleroma/gun/connection_pool/worker.ex b/lib/pleroma/gun/connection_pool/worker.ex index 02bfff274..a3fa75386 100644 --- a/lib/pleroma/gun/connection_pool/worker.ex +++ b/lib/pleroma/gun/connection_pool/worker.ex @@ -6,10 +6,10 @@ defmodule Pleroma.Gun.ConnectionPool.Worker do    alias Pleroma.Gun    use GenServer, restart: :temporary -  @registry Pleroma.Gun.ConnectionPool +  defp registry, do: Pleroma.Gun.ConnectionPool    def start_link([key | _] = opts) do -    GenServer.start_link(__MODULE__, opts, name: {:via, Registry, {@registry, key}}) +    GenServer.start_link(__MODULE__, opts, name: {:via, Registry, {registry(), key}})    end    @impl true @@ -24,7 +24,7 @@ defmodule Pleroma.Gun.ConnectionPool.Worker do        time = :erlang.monotonic_time(:millisecond)        {_, _} = -        Registry.update_value(@registry, key, fn _ -> +        Registry.update_value(registry(), key, fn _ ->            {conn_pid, [client_pid], 1, time}          end) @@ -65,7 +65,7 @@ defmodule Pleroma.Gun.ConnectionPool.Worker do      time = :erlang.monotonic_time(:millisecond)      {{conn_pid, used_by, _, _}, _} = -      Registry.update_value(@registry, key, fn {conn_pid, used_by, crf, last_reference} -> +      Registry.update_value(registry(), key, fn {conn_pid, used_by, crf, last_reference} ->          {conn_pid, [client_pid | used_by], crf(time - last_reference, crf), time}        end) @@ -92,7 +92,7 @@ defmodule Pleroma.Gun.ConnectionPool.Worker do    @impl true    def handle_call(:remove_client, {client_pid, _}, %{key: key} = state) do      {{_conn_pid, used_by, _crf, _last_reference}, _} = -      Registry.update_value(@registry, key, fn {conn_pid, used_by, crf, last_reference} -> +      Registry.update_value(registry(), key, fn {conn_pid, used_by, crf, last_reference} ->          {conn_pid, List.delete(used_by, client_pid), crf, last_reference}        end) diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index 2dfdca693..bee66169d 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -49,31 +49,6 @@ defmodule Pleroma.HTML do    def filter_tags(html), do: filter_tags(html, nil)    def strip_tags(html), do: filter_tags(html, FastSanitize.Sanitizer.StripTags) -  def get_cached_scrubbed_html_for_activity( -        content, -        scrubbers, -        activity, -        key \\ "", -        callback \\ fn x -> x end -      ) do -    key = "#{key}#{generate_scrubber_signature(scrubbers)}|#{activity.id}" - -    @cachex.fetch!(:scrubber_cache, key, fn _key -> -      object = Pleroma.Object.normalize(activity, fetch: false) -      ensure_scrubbed_html(content, scrubbers, object.data["fake"] || false, callback) -    end) -  end - -  def get_cached_stripped_html_for_activity(content, activity, key) do -    get_cached_scrubbed_html_for_activity( -      content, -      FastSanitize.Sanitizer.StripTags, -      activity, -      key, -      &HtmlEntities.decode/1 -    ) -  end -    def ensure_scrubbed_html(          content,          scrubbers, @@ -92,16 +67,6 @@ defmodule Pleroma.HTML do      end    end -  defp generate_scrubber_signature(scrubber) when is_atom(scrubber) do -    generate_scrubber_signature([scrubber]) -  end - -  defp generate_scrubber_signature(scrubbers) do -    Enum.reduce(scrubbers, "", fn scrubber, signature -> -      "#{signature}#{to_string(scrubber)}" -    end) -  end -    def extract_first_external_url_from_object(%{data: %{"content" => content}} = object)        when is_binary(content) do      unless object.data["fake"] do diff --git a/lib/pleroma/http/adapter_helper/gun.ex b/lib/pleroma/http/adapter_helper/gun.ex index 82c7fd654..251539f34 100644 --- a/lib/pleroma/http/adapter_helper/gun.ex +++ b/lib/pleroma/http/adapter_helper/gun.ex @@ -54,8 +54,8 @@ defmodule Pleroma.HTTP.AdapterHelper.Gun do      Config.get([:pools, pool, :recv_timeout], default)    end -  @prefix Pleroma.Gun.ConnectionPool    def limiter_setup do +    prefix = Pleroma.Gun.ConnectionPool      wait = Config.get([:connections_pool, :connection_acquisition_wait])      retries = Config.get([:connections_pool, :connection_acquisition_retries]) @@ -66,7 +66,7 @@ defmodule Pleroma.HTTP.AdapterHelper.Gun do        max_waiting = Keyword.get(opts, :max_waiting, 10)        result = -        ConcurrentLimiter.new(:"#{@prefix}.#{name}", max_running, max_waiting, +        ConcurrentLimiter.new(:"#{prefix}.#{name}", max_running, max_waiting,            wait: wait,            max_retries: retries          ) diff --git a/lib/pleroma/http/web_push.ex b/lib/pleroma/http/web_push.ex index 51f72fbf8..16bbe6e8c 100644 --- a/lib/pleroma/http/web_push.ex +++ b/lib/pleroma/http/web_push.ex @@ -5,8 +5,8 @@  defmodule Pleroma.HTTP.WebPush do    @moduledoc false -  def post(url, payload, headers) do +  def post(url, payload, headers, options \\ []) do      list_headers = Map.to_list(headers) -    Pleroma.HTTP.post(url, payload, list_headers) +    Pleroma.HTTP.post(url, payload, list_headers, options)    end  end diff --git a/lib/pleroma/maps.ex b/lib/pleroma/maps.ex index 0d2e94248..b08b83305 100644 --- a/lib/pleroma/maps.ex +++ b/lib/pleroma/maps.ex @@ -12,4 +12,10 @@ defmodule Pleroma.Maps do        _ -> map      end    end + +  def safe_put_in(data, keys, value) when is_map(data) and is_list(keys) do +    Kernel.put_in(data, keys, value) +  rescue +    _ -> data +  end  end diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 3ba749d1a..c3ea1b98b 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -366,7 +366,7 @@ defmodule Pleroma.Object do    end    def local?(%Object{data: %{"id" => id}}) do -    String.starts_with?(id, Pleroma.Web.base_url() <> "/") +    String.starts_with?(id, Pleroma.Web.Endpoint.url() <> "/")    end    def replies(object, opts \\ []) do diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index bcccf1c4c..4ca67f0fd 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -4,6 +4,7 @@  defmodule Pleroma.Object.Fetcher do    alias Pleroma.HTTP +  alias Pleroma.Maps    alias Pleroma.Object    alias Pleroma.Object.Containment    alias Pleroma.Repo @@ -101,6 +102,9 @@ defmodule Pleroma.Object.Fetcher do        {:transmogrifier, {:error, {:reject, e}}} ->          {:reject, e} +      {:transmogrifier, {:reject, e}} -> +        {:reject, e} +        {:transmogrifier, _} = e ->          {:error, e} @@ -124,12 +128,14 @@ defmodule Pleroma.Object.Fetcher do    defp prepare_activity_params(data) do      %{        "type" => "Create", -      "to" => data["to"] || [], -      "cc" => data["cc"] || [],        # Should we seriously keep this attributedTo thing?        "actor" => data["actor"] || data["attributedTo"],        "object" => data      } +    |> Maps.put_if_present("to", data["to"]) +    |> Maps.put_if_present("cc", data["cc"]) +    |> Maps.put_if_present("bto", data["bto"]) +    |> Maps.put_if_present("bcc", data["bcc"])    end    def fetch_object_from_id!(id, options \\ []) do diff --git a/lib/pleroma/reverse_proxy.ex b/lib/pleroma/reverse_proxy.ex index 406f7e2b8..ec69a1779 100644 --- a/lib/pleroma/reverse_proxy.ex +++ b/lib/pleroma/reverse_proxy.ex @@ -411,7 +411,7 @@ defmodule Pleroma.ReverseProxy do      {:ok, :no_duration_limit, :no_duration_limit}    end -  defp client, do: Pleroma.ReverseProxy.Client +  defp client, do: Pleroma.ReverseProxy.Client.Wrapper    defp track_failed_url(url, error, opts) do      ttl = diff --git a/lib/pleroma/reverse_proxy/client.ex b/lib/pleroma/reverse_proxy/client.ex index 8698fa2e1..75243d2dc 100644 --- a/lib/pleroma/reverse_proxy/client.ex +++ b/lib/pleroma/reverse_proxy/client.ex @@ -17,22 +17,4 @@ defmodule Pleroma.ReverseProxy.Client do    @callback stream_body(map()) :: {:ok, binary(), map()} | :done | {:error, atom() | String.t()}    @callback close(reference() | pid() | map()) :: :ok - -  def request(method, url, headers, body \\ "", opts \\ []) do -    client().request(method, url, headers, body, opts) -  end - -  def stream_body(ref), do: client().stream_body(ref) - -  def close(ref), do: client().close(ref) - -  defp client do -    :tesla -    |> Application.get_env(:adapter) -    |> client() -  end - -  defp client(Tesla.Adapter.Hackney), do: Pleroma.ReverseProxy.Client.Hackney -  defp client(Tesla.Adapter.Gun), do: Pleroma.ReverseProxy.Client.Tesla -  defp client(_), do: Pleroma.Config.get!(Pleroma.ReverseProxy.Client)  end diff --git a/lib/pleroma/reverse_proxy/client/wrapper.ex b/lib/pleroma/reverse_proxy/client/wrapper.ex new file mode 100644 index 000000000..06dd29fea --- /dev/null +++ b/lib/pleroma/reverse_proxy/client/wrapper.ex @@ -0,0 +1,29 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.ReverseProxy.Client.Wrapper do +  @moduledoc "Meta-client that calls the appropriate client from the config." +  @behaviour Pleroma.ReverseProxy.Client + +  @impl true +  def request(method, url, headers, body \\ "", opts \\ []) do +    client().request(method, url, headers, body, opts) +  end + +  @impl true +  def stream_body(ref), do: client().stream_body(ref) + +  @impl true +  def close(ref), do: client().close(ref) + +  defp client do +    :tesla +    |> Application.get_env(:adapter) +    |> client() +  end + +  defp client(Tesla.Adapter.Hackney), do: Pleroma.ReverseProxy.Client.Hackney +  defp client(Tesla.Adapter.Gun), do: Pleroma.ReverseProxy.Client.Tesla +  defp client(_), do: Pleroma.Config.get!(Pleroma.ReverseProxy.Client) +end diff --git a/lib/pleroma/upload.ex b/lib/pleroma/upload.ex index 654711351..17822dc5e 100644 --- a/lib/pleroma/upload.ex +++ b/lib/pleroma/upload.ex @@ -23,6 +23,9 @@ defmodule Pleroma.Upload do      is once created permanent and changing it (especially in uploaders) is probably a bad idea!    * `:tempfile` - path to the temporary file. Prefer in-place changes on the file rather than changing the    path as the temporary file is also tracked by `Plug.Upload{}` and automatically deleted once the request is over. +  * `:width` - width of the media in pixels +  * `:height` - height of the media in pixels +  * `:blurhash` - string hash of the image encoded with the blurhash algorithm (https://blurha.sh/)    Related behaviors: @@ -32,6 +35,7 @@ defmodule Pleroma.Upload do    """    alias Ecto.UUID    alias Pleroma.Config +  alias Pleroma.Maps    require Logger    @type source :: @@ -53,9 +57,12 @@ defmodule Pleroma.Upload do            name: String.t(),            tempfile: String.t(),            content_type: String.t(), +          width: integer(), +          height: integer(), +          blurhash: String.t(),            path: String.t()          } -  defstruct [:id, :name, :tempfile, :content_type, :path] +  defstruct [:id, :name, :tempfile, :content_type, :width, :height, :blurhash, :path]    defp get_description(opts, upload) do      case {opts[:description], Pleroma.Config.get([Pleroma.Upload, :default_description])} do @@ -89,9 +96,12 @@ defmodule Pleroma.Upload do               "mediaType" => upload.content_type,               "href" => url_from_spec(upload, opts.base_url, url_spec)             } +           |> Maps.put_if_present("width", upload.width) +           |> Maps.put_if_present("height", upload.height)           ],           "name" => description -       }} +       } +       |> Maps.put_if_present("blurhash", upload.blurhash)}      else        {:description_limit, _} ->          {:error, :description_too_long} @@ -225,7 +235,7 @@ defmodule Pleroma.Upload do      case uploader do        Pleroma.Uploaders.Local -> -        upload_base_url || Pleroma.Web.base_url() <> "/media/" +        upload_base_url || Pleroma.Web.Endpoint.url() <> "/media/"        Pleroma.Uploaders.S3 ->          bucket = Config.get([Pleroma.Uploaders.S3, :bucket]) @@ -251,7 +261,7 @@ defmodule Pleroma.Upload do          end        _ -> -        public_endpoint || upload_base_url || Pleroma.Web.base_url() <> "/media/" +        public_endpoint || upload_base_url || Pleroma.Web.Endpoint.url() <> "/media/"      end    end  end diff --git a/lib/pleroma/upload/filter/analyze_metadata.ex b/lib/pleroma/upload/filter/analyze_metadata.ex new file mode 100644 index 000000000..8c23076d4 --- /dev/null +++ b/lib/pleroma/upload/filter/analyze_metadata.ex @@ -0,0 +1,45 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Upload.Filter.AnalyzeMetadata do +  @moduledoc """ +  Extracts metadata about the upload, such as width/height +  """ +  require Logger + +  @behaviour Pleroma.Upload.Filter + +  @spec filter(Pleroma.Upload.t()) :: +          {:ok, :filtered, Pleroma.Upload.t()} | {:ok, :noop} | {:error, String.t()} +  def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _} = upload) do +    try do +      image = +        file +        |> Mogrify.open() +        |> Mogrify.verbose() + +      upload = +        upload +        |> Map.put(:width, image.width) +        |> Map.put(:height, image.height) +        |> Map.put(:blurhash, get_blurhash(file)) + +      {:ok, :filtered, upload} +    rescue +      e in ErlangError -> +        Logger.warn("#{__MODULE__}: #{inspect(e)}") +        {:ok, :noop} +    end +  end + +  def filter(_), do: {:ok, :noop} + +  defp get_blurhash(file) do +    with {:ok, blurhash} <- :eblurhash.magick(file) do +      blurhash +    else +      _ -> nil +    end +  end +end diff --git a/lib/pleroma/uploaders/uploader.ex b/lib/pleroma/uploaders/uploader.ex index 0be878ca2..deba548b7 100644 --- a/lib/pleroma/uploaders/uploader.ex +++ b/lib/pleroma/uploaders/uploader.ex @@ -35,7 +35,7 @@ defmodule Pleroma.Uploaders.Uploader do    """    @type file_spec :: {:file | :url, String.t()} -  @callback put_file(Pleroma.Upload.t()) :: +  @callback put_file(upload :: struct()) ::                :ok | {:ok, file_spec()} | {:error, String.t()} | :wait_callback    @callback delete_file(file :: String.t()) :: :ok | {:error, String.t()} @@ -46,7 +46,7 @@ defmodule Pleroma.Uploaders.Uploader do                | {:error, Plug.Conn.t(), String.t()}    @optional_callbacks http_callback: 2 -  @spec put_file(module(), Pleroma.Upload.t()) :: {:ok, file_spec()} | {:error, String.t()} +  @spec put_file(module(), upload :: struct()) :: {:ok, file_spec()} | {:error, String.t()}    def put_file(uploader, upload) do      case uploader.put_file(upload) do        :ok -> {:ok, {:file, upload.path}} diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index b78777141..9365fae2b 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -27,13 +27,13 @@ defmodule Pleroma.User do    alias Pleroma.Repo    alias Pleroma.User    alias Pleroma.UserRelationship -  alias Pleroma.Web    alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.ActivityPub.Builder    alias Pleroma.Web.ActivityPub.Pipeline    alias Pleroma.Web.ActivityPub.Utils    alias Pleroma.Web.CommonAPI    alias Pleroma.Web.CommonAPI.Utils, as: CommonUtils +  alias Pleroma.Web.Endpoint    alias Pleroma.Web.OAuth    alias Pleroma.Web.RelMe    alias Pleroma.Workers.BackgroundWorker @@ -360,7 +360,7 @@ defmodule Pleroma.User do        _ ->          unless options[:no_default] do -          Config.get([:assets, :default_user_avatar], "#{Web.base_url()}/images/avi.png") +          Config.get([:assets, :default_user_avatar], "#{Endpoint.url()}/images/avi.png")          end      end    end @@ -368,13 +368,13 @@ defmodule Pleroma.User do    def banner_url(user, options \\ []) do      case user.banner do        %{"url" => [%{"href" => href} | _]} -> href -      _ -> !options[:no_default] && "#{Web.base_url()}/images/banner.png" +      _ -> !options[:no_default] && "#{Endpoint.url()}/images/banner.png"      end    end    # Should probably be renamed or removed    @spec ap_id(User.t()) :: String.t() -  def ap_id(%User{nickname: nickname}), do: "#{Web.base_url()}/users/#{nickname}" +  def ap_id(%User{nickname: nickname}), do: "#{Endpoint.url()}/users/#{nickname}"    @spec ap_followers(User.t()) :: String.t()    def ap_followers(%User{follower_address: fa}) when is_binary(fa), do: fa diff --git a/lib/pleroma/web.ex b/lib/pleroma/web.ex index 8630f244b..d26931af9 100644 --- a/lib/pleroma/web.ex +++ b/lib/pleroma/web.ex @@ -35,9 +35,10 @@ defmodule Pleroma.Web do        import Plug.Conn        import Pleroma.Web.Gettext -      import Pleroma.Web.Router.Helpers        import Pleroma.Web.TranslationHelpers +      alias Pleroma.Web.Router.Helpers, as: Routes +        plug(:set_put_layout)        defp set_put_layout(conn, _) do @@ -131,7 +132,8 @@ defmodule Pleroma.Web do        import Pleroma.Web.ErrorHelpers        import Pleroma.Web.Gettext -      import Pleroma.Web.Router.Helpers + +      alias Pleroma.Web.Router.Helpers, as: Routes        require Logger @@ -229,20 +231,4 @@ defmodule Pleroma.Web do    defmacro __using__(which) when is_atom(which) do      apply(__MODULE__, which, [])    end - -  def base_url do -    Pleroma.Web.Endpoint.url() -  end - -  # TODO: Change to Phoenix.Router.routes/1 for Phoenix 1.6.0+ -  def get_api_routes do -    Pleroma.Web.Router.__routes__() -    |> Enum.reject(fn r -> r.plug == Pleroma.Web.Fallback.RedirectController end) -    |> Enum.map(fn r -> -      r.path -      |> String.split("/", trim: true) -      |> List.first() -    end) -    |> Enum.uniq() -  end  end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index d0051d1cb..18368943d 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -88,7 +88,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do    defp increase_replies_count_if_reply(_create_data), do: :noop -  @object_types ~w[ChatMessage Question Answer Audio Video Event Article] +  @object_types ~w[ChatMessage Question Answer Audio Video Event Article Note]    @impl true    def persist(%{"type" => type} = object, meta) when type in @object_types do      with {:ok, object} <- Object.create(object) do diff --git a/lib/pleroma/web/activity_pub/activity_pub/persisting.ex b/lib/pleroma/web/activity_pub/activity_pub/persisting.ex index 5ec8b7bab..f39cd000a 100644 --- a/lib/pleroma/web/activity_pub/activity_pub/persisting.ex +++ b/lib/pleroma/web/activity_pub/activity_pub/persisting.ex @@ -3,5 +3,5 @@  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.ActivityPub.ActivityPub.Persisting do -  @callback persist(map(), keyword()) :: {:ok, Activity.t() | Object.t()} +  @callback persist(map(), keyword()) :: {:ok, struct()}  end diff --git a/lib/pleroma/web/activity_pub/activity_pub/streaming.ex b/lib/pleroma/web/activity_pub/activity_pub/streaming.ex index 983168bff..33c7bf2bc 100644 --- a/lib/pleroma/web/activity_pub/activity_pub/streaming.ex +++ b/lib/pleroma/web/activity_pub/activity_pub/streaming.ex @@ -3,10 +3,6 @@  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.ActivityPub.ActivityPub.Streaming do -  alias Pleroma.Activity -  alias Pleroma.Object -  alias Pleroma.User - -  @callback stream_out(Activity.t()) :: any() -  @callback stream_out_participations(Object.t(), User.t()) :: any() +  @callback stream_out(struct()) :: any() +  @callback stream_out_participations(struct(), struct()) :: any()  end diff --git a/lib/pleroma/web/activity_pub/builder.ex b/lib/pleroma/web/activity_pub/builder.ex index 91a45836f..cde477710 100644 --- a/lib/pleroma/web/activity_pub/builder.ex +++ b/lib/pleroma/web/activity_pub/builder.ex @@ -223,7 +223,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do            [actor.follower_address]          public? and Visibility.is_local_public?(object) -> -          [actor.follower_address, object.data["actor"], Pleroma.Constants.as_local_public()] +          [actor.follower_address, object.data["actor"], Utils.as_local_public()]          public? ->            [actor.follower_address, object.data["actor"], Pleroma.Constants.as_public()] diff --git a/lib/pleroma/web/activity_pub/mrf/no_empty_policy.ex b/lib/pleroma/web/activity_pub/mrf/no_empty_policy.ex index 32bb1b645..f4c5db05c 100644 --- a/lib/pleroma/web/activity_pub/mrf/no_empty_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/no_empty_policy.ex @@ -6,7 +6,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy do    @moduledoc "Filter local activities which have no content"    @behaviour Pleroma.Web.ActivityPub.MRF -  alias Pleroma.Web +  alias Pleroma.Web.Endpoint    @impl true    def filter(%{"actor" => actor} = object) do @@ -24,7 +24,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy do    def filter(object), do: {:ok, object}    defp is_local?(actor) do -    if actor |> String.starts_with?("#{Web.base_url()}") do +    if actor |> String.starts_with?("#{Endpoint.url()}") do        true      else        false diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex index 62024c58c..d40348cb1 100644 --- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -177,6 +177,14 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do    defp check_banner_removal(_actor_info, object), do: {:ok, object} +  defp check_object(%{"object" => object} = activity) do +    with {:ok, _object} <- filter(object) do +      {:ok, activity} +    end +  end + +  defp check_object(object), do: {:ok, object} +    @impl true    def filter(%{"type" => "Delete", "actor" => actor} = object) do      %{host: actor_host} = URI.parse(actor) @@ -202,7 +210,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do           {:ok, object} <- check_media_nsfw(actor_info, object),           {:ok, object} <- check_ftl_removal(actor_info, object),           {:ok, object} <- check_followers_only(actor_info, object), -         {:ok, object} <- check_report_removal(actor_info, object) do +         {:ok, object} <- check_report_removal(actor_info, object), +         {:ok, object} <- check_object(object) do        {:ok, object}      else        {:reject, nil} -> {:reject, "[SimplePolicy]"} @@ -227,6 +236,19 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do      end    end +  def filter(object) when is_binary(object) do +    uri = URI.parse(object) + +    with {:ok, object} <- check_accept(uri, object), +         {:ok, object} <- check_reject(uri, object) do +      {:ok, object} +    else +      {:reject, nil} -> {:reject, "[SimplePolicy]"} +      {:reject, _} = e -> e +      _ -> {:reject, "[SimplePolicy]"} +    end +  end +    def filter(object), do: {:ok, object}    @impl true diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex index 1dce33f1a..248a12a36 100644 --- a/lib/pleroma/web/activity_pub/object_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validator.ex @@ -102,7 +102,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do          %{"type" => "Create", "object" => %{"type" => objtype} = object} = create_activity,          meta        ) -      when objtype in ~w[Question Answer Audio Video Event Article] do +      when objtype in ~w[Question Answer Audio Video Event Article Note] do      with {:ok, object_data} <- cast_and_apply(object),           meta = Keyword.put(meta, :object_data, object_data |> stringify_keys),           {:ok, create_activity} <- @@ -115,7 +115,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do    end    def validate(%{"type" => type} = object, meta) -      when type in ~w[Event Question Audio Video Article] do +      when type in ~w[Event Question Audio Video Article Note] do      validator =        case type do          "Event" -> EventValidator @@ -123,6 +123,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do          "Audio" -> AudioVideoValidator          "Video" -> AudioVideoValidator          "Article" -> ArticleNoteValidator +        "Note" -> ArticleNoteValidator        end      with {:ok, object} <- @@ -194,7 +195,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do      EventValidator.cast_and_apply(object)    end -  def cast_and_apply(%{"type" => "Article"} = object) do +  def cast_and_apply(%{"type" => type} = object) when type in ~w[Article Note] do      ArticleNoteValidator.cast_and_apply(object)    end diff --git a/lib/pleroma/web/activity_pub/object_validators/announce_validator.ex b/lib/pleroma/web/activity_pub/object_validators/announce_validator.ex index 576341790..a2f752ac3 100644 --- a/lib/pleroma/web/activity_pub/object_validators/announce_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/announce_validator.ex @@ -68,7 +68,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator do           false <- Visibility.is_public?(object) do        same_actor = object.data["actor"] == actor.ap_id        recipients = get_field(cng, :to) ++ get_field(cng, :cc) -      local_public = Pleroma.Constants.as_local_public() +      local_public = Utils.as_local_public()        is_public =          Enum.member?(recipients, Pleroma.Constants.as_public()) or diff --git a/lib/pleroma/web/activity_pub/object_validators/answer_validator.ex b/lib/pleroma/web/activity_pub/object_validators/answer_validator.ex index c9bd9e42d..3451e1ff8 100644 --- a/lib/pleroma/web/activity_pub/object_validators/answer_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/answer_validator.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnswerValidator do    use Ecto.Schema    alias Pleroma.EctoType.ActivityPub.ObjectValidators +  alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes    alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations    import Ecto.Changeset @@ -23,6 +24,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnswerValidator do      field(:name, :string)      field(:inReplyTo, ObjectValidators.ObjectID)      field(:attributedTo, ObjectValidators.ObjectID) +    field(:context, :string)      # TODO: Remove actor on objects      field(:actor, ObjectValidators.ObjectID) @@ -46,6 +48,11 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnswerValidator do    end    def changeset(struct, data) do +    data = +      data +      |> CommonFixes.fix_actor() +      |> CommonFixes.fix_object_defaults() +      struct      |> cast(data, __schema__(:fields))    end diff --git a/lib/pleroma/web/activity_pub/object_validators/article_note_validator.ex b/lib/pleroma/web/activity_pub/object_validators/article_note_validator.ex index 39ef6dc29..193f85f49 100644 --- a/lib/pleroma/web/activity_pub/object_validators/article_note_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/article_note_validator.ex @@ -50,6 +50,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNoteValidator do      field(:likes, {:array, ObjectValidators.ObjectID}, default: [])      field(:announcements, {:array, ObjectValidators.ObjectID}, default: []) + +    field(:replies, {:array, ObjectValidators.ObjectID}, default: [])    end    def cast_and_apply(data) do @@ -65,25 +67,39 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNoteValidator do    end    def cast_data(data) do -    data = fix(data) -      %__MODULE__{}      |> changeset(data)    end -  defp fix_url(%{"url" => url} = data) when is_map(url) do -    Map.put(data, "url", url["href"]) -  end - +  defp fix_url(%{"url" => url} = data) when is_bitstring(url), do: data +  defp fix_url(%{"url" => url} = data) when is_map(url), do: Map.put(data, "url", url["href"])    defp fix_url(data), do: data +  defp fix_tag(%{"tag" => tag} = data) when is_list(tag), do: data +  defp fix_tag(%{"tag" => tag} = data) when is_map(tag), do: Map.put(data, "tag", [tag]) +  defp fix_tag(data), do: Map.drop(data, ["tag"]) + +  defp fix_replies(%{"replies" => %{"first" => %{"items" => replies}}} = data) +       when is_list(replies), +       do: Map.put(data, "replies", replies) + +  defp fix_replies(%{"replies" => %{"items" => replies}} = data) when is_list(replies), +    do: Map.put(data, "replies", replies) + +  defp fix_replies(%{"replies" => replies} = data) when is_bitstring(replies), +    do: Map.drop(data, ["replies"]) + +  defp fix_replies(data), do: data +    defp fix(data) do      data -    |> CommonFixes.fix_defaults() -    |> CommonFixes.fix_attribution()      |> CommonFixes.fix_actor() +    |> CommonFixes.fix_object_defaults()      |> fix_url() +    |> fix_tag() +    |> fix_replies()      |> Transmogrifier.fix_emoji() +    |> Transmogrifier.fix_content_map()    end    def changeset(struct, data) do diff --git a/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex b/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex index 4a0d1473d..837787b9f 100644 --- a/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex @@ -20,6 +20,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator do        field(:type, :string)        field(:href, ObjectValidators.Uri)        field(:mediaType, :string, default: "application/octet-stream") +      field(:width, :integer) +      field(:height, :integer)      end    end @@ -51,7 +53,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator do      data = fix_media_type(data)      struct -    |> cast(data, [:type, :href, :mediaType]) +    |> cast(data, [:type, :href, :mediaType, :width, :height])      |> validate_inclusion(:type, ["Link"])      |> validate_required([:type, :href, :mediaType])    end @@ -59,7 +61,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator do    def fix_media_type(data) do      data = Map.put_new(data, "mediaType", data["mimeType"]) -    if MIME.valid?(data["mediaType"]) do +    if is_bitstring(data["mediaType"]) && MIME.extensions(data["mediaType"]) != [] do        data      else        Map.put(data, "mediaType", "application/octet-stream") diff --git a/lib/pleroma/web/activity_pub/object_validators/audio_video_validator.ex b/lib/pleroma/web/activity_pub/object_validators/audio_video_validator.ex index 27e14b16d..572687deb 100644 --- a/lib/pleroma/web/activity_pub/object_validators/audio_video_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/audio_video_validator.ex @@ -119,9 +119,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator do    defp fix(data) do      data -    |> CommonFixes.fix_defaults() -    |> CommonFixes.fix_attribution()      |> CommonFixes.fix_actor() +    |> CommonFixes.fix_object_defaults()      |> Transmogrifier.fix_emoji()      |> fix_url()      |> fix_content() diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex index 5f2c633bc..c958fcc5d 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex @@ -3,26 +3,55 @@  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do +  alias Pleroma.EctoType.ActivityPub.ObjectValidators    alias Pleroma.Object.Containment +  alias Pleroma.User +  alias Pleroma.Web.ActivityPub.Transmogrifier    alias Pleroma.Web.ActivityPub.Utils -  # based on Pleroma.Web.ActivityPub.Utils.lazy_put_objects_defaults -  def fix_defaults(data) do +  def cast_and_filter_recipients(message, field, follower_collection, field_fallback \\ []) do +    {:ok, data} = ObjectValidators.Recipients.cast(message[field] || field_fallback) + +    data = +      Enum.reject(data, fn x -> +        String.ends_with?(x, "/followers") and x != follower_collection +      end) + +    Map.put(message, field, data) +  end + +  def fix_object_defaults(data) do      %{data: %{"id" => context}, id: context_id} =        Utils.create_context(data["context"] || data["conversation"]) +    %User{follower_address: follower_collection} = User.get_cached_by_ap_id(data["attributedTo"]) +      data      |> Map.put("context", context)      |> Map.put("context_id", context_id) +    |> cast_and_filter_recipients("to", follower_collection) +    |> cast_and_filter_recipients("cc", follower_collection) +    |> cast_and_filter_recipients("bto", follower_collection) +    |> cast_and_filter_recipients("bcc", follower_collection) +    |> Transmogrifier.fix_implicit_addressing(follower_collection)    end -  def fix_attribution(data) do -    data -    |> Map.put_new("actor", data["attributedTo"]) +  def fix_activity_addressing(activity, _meta) do +    %User{follower_address: follower_collection} = User.get_cached_by_ap_id(activity["actor"]) + +    activity +    |> cast_and_filter_recipients("to", follower_collection) +    |> cast_and_filter_recipients("cc", follower_collection) +    |> cast_and_filter_recipients("bto", follower_collection) +    |> cast_and_filter_recipients("bcc", follower_collection) +    |> Transmogrifier.fix_implicit_addressing(follower_collection)    end    def fix_actor(data) do -    actor = Containment.get_actor(data) +    actor = +      data +      |> Map.put_new("actor", data["attributedTo"]) +      |> Containment.get_actor()      data      |> Map.put("actor", actor) diff --git a/lib/pleroma/web/activity_pub/object_validators/common_validations.ex b/lib/pleroma/web/activity_pub/object_validators/common_validations.ex index 940430588..be5074348 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_validations.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_validations.ex @@ -15,6 +15,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations do        fields        |> Enum.map(fn field -> get_field(cng, field) end)        |> Enum.any?(fn +        nil -> false          [] -> false          _ -> true        end) diff --git a/lib/pleroma/web/activity_pub/object_validators/create_generic_validator.ex b/lib/pleroma/web/activity_pub/object_validators/create_generic_validator.ex index e06e442f4..d2de53049 100644 --- a/lib/pleroma/web/activity_pub/object_validators/create_generic_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/create_generic_validator.ex @@ -10,8 +10,10 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator do    alias Pleroma.EctoType.ActivityPub.ObjectValidators    alias Pleroma.Object +  alias Pleroma.User    alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes    alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations +  alias Pleroma.Web.ActivityPub.Transmogrifier    import Ecto.Changeset @@ -23,6 +25,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator do      field(:type, :string)      field(:to, ObjectValidators.Recipients, default: [])      field(:cc, ObjectValidators.Recipients, default: []) +    field(:bto, ObjectValidators.Recipients, default: []) +    field(:bcc, ObjectValidators.Recipients, default: [])      field(:object, ObjectValidators.ObjectID)      field(:expires_at, ObjectValidators.DateTime) @@ -54,39 +58,37 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator do      |> cast(data, __schema__(:fields))    end -  defp fix_context(data, meta) do -    if object = meta[:object_data] do -      Map.put_new(data, "context", object["context"]) -    else -      data -    end -  end +  # CommonFixes.fix_activity_addressing adapted for Create specific behavior +  defp fix_addressing(data, object) do +    %User{follower_address: follower_collection} = User.get_cached_by_ap_id(data["actor"]) -  defp fix_addressing(data, meta) do -    if object = meta[:object_data] do -      data -      |> Map.put_new("to", object["to"] || []) -      |> Map.put_new("cc", object["cc"] || []) -    else -      data -    end +    data +    |> CommonFixes.cast_and_filter_recipients("to", follower_collection, object["to"]) +    |> CommonFixes.cast_and_filter_recipients("cc", follower_collection, object["cc"]) +    |> CommonFixes.cast_and_filter_recipients("bto", follower_collection, object["bto"]) +    |> CommonFixes.cast_and_filter_recipients("bcc", follower_collection, object["bcc"]) +    |> Transmogrifier.fix_implicit_addressing(follower_collection)    end -  defp fix(data, meta) do +  def fix(data, meta) do +    object = meta[:object_data] +      data -    |> fix_context(meta) -    |> fix_addressing(meta)      |> CommonFixes.fix_actor() +    |> Map.put_new("context", object["context"]) +    |> fix_addressing(object)    end    defp validate_data(cng, meta) do +    object = meta[:object_data] +      cng -    |> validate_required([:actor, :type, :object]) +    |> validate_required([:actor, :type, :object, :to, :cc])      |> validate_inclusion(:type, ["Create"])      |> CommonValidations.validate_actor_presence() -    |> CommonValidations.validate_any_presence([:to, :cc]) -    |> validate_actors_match(meta) -    |> validate_context_match(meta) +    |> validate_actors_match(object) +    |> validate_context_match(object) +    |> validate_addressing_match(object)      |> validate_object_nonexistence()      |> validate_object_containment()    end @@ -118,8 +120,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator do      end)    end -  def validate_actors_match(cng, meta) do -    attributed_to = meta[:object_data]["attributedTo"] || meta[:object_data]["actor"] +  def validate_actors_match(cng, object) do +    attributed_to = object["attributedTo"] || object["actor"]      cng      |> validate_change(:actor, fn :actor, actor -> @@ -131,7 +133,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator do      end)    end -  def validate_context_match(cng, %{object_data: %{"context" => object_context}}) do +  def validate_context_match(cng, %{"context" => object_context}) do      cng      |> validate_change(:context, fn :context, context ->        if context == object_context do @@ -142,5 +144,18 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator do      end)    end -  def validate_context_match(cng, _), do: cng +  def validate_addressing_match(cng, object) do +    [:to, :cc, :bcc, :bto] +    |> Enum.reduce(cng, fn field, cng -> +      object_data = object[to_string(field)] + +      validate_change(cng, field, fn field, data -> +        if data == object_data do +          [] +        else +          [{field, "field doesn't match with object (#{inspect(object_data)})"}] +        end +      end) +    end) +  end  end diff --git a/lib/pleroma/web/activity_pub/object_validators/create_note_validator.ex b/lib/pleroma/web/activity_pub/object_validators/create_note_validator.ex deleted file mode 100644 index a85a0298c..000000000 --- a/lib/pleroma/web/activity_pub/object_validators/create_note_validator.ex +++ /dev/null @@ -1,29 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateNoteValidator do -  use Ecto.Schema - -  alias Pleroma.EctoType.ActivityPub.ObjectValidators -  alias Pleroma.Web.ActivityPub.ObjectValidators.NoteValidator - -  import Ecto.Changeset - -  @primary_key false - -  embedded_schema do -    field(:id, ObjectValidators.ObjectID, primary_key: true) -    field(:actor, ObjectValidators.ObjectID) -    field(:type, :string) -    field(:to, ObjectValidators.Recipients, default: []) -    field(:cc, ObjectValidators.Recipients, default: []) -    field(:bto, ObjectValidators.Recipients, default: []) -    field(:bcc, ObjectValidators.Recipients, default: []) -    embeds_one(:object, NoteValidator) -  end - -  def cast_data(data) do -    cast(%__MODULE__{}, data, __schema__(:fields)) -  end -end diff --git a/lib/pleroma/web/activity_pub/object_validators/event_validator.ex b/lib/pleroma/web/activity_pub/object_validators/event_validator.ex index d42458ef5..fee2e997a 100644 --- a/lib/pleroma/web/activity_pub/object_validators/event_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/event_validator.ex @@ -72,8 +72,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EventValidator do    defp fix(data) do      data -    |> CommonFixes.fix_defaults() -    |> CommonFixes.fix_attribution() +    |> CommonFixes.fix_actor() +    |> CommonFixes.fix_object_defaults()      |> Transmogrifier.fix_emoji()    end diff --git a/lib/pleroma/web/activity_pub/object_validators/question_validator.ex b/lib/pleroma/web/activity_pub/object_validators/question_validator.ex index 7012e2e1d..083d08ec4 100644 --- a/lib/pleroma/web/activity_pub/object_validators/question_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/question_validator.ex @@ -83,8 +83,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator do    defp fix(data) do      data -    |> CommonFixes.fix_defaults() -    |> CommonFixes.fix_attribution() +    |> CommonFixes.fix_actor() +    |> CommonFixes.fix_object_defaults()      |> Transmogrifier.fix_emoji()      |> fix_closed()    end diff --git a/lib/pleroma/web/activity_pub/pipeline.ex b/lib/pleroma/web/activity_pub/pipeline.ex index a0f2e0312..0d6e8aad2 100644 --- a/lib/pleroma/web/activity_pub/pipeline.ex +++ b/lib/pleroma/web/activity_pub/pipeline.ex @@ -15,19 +15,19 @@ defmodule Pleroma.Web.ActivityPub.Pipeline do    alias Pleroma.Web.ActivityPub.Visibility    alias Pleroma.Web.Federator -  @side_effects Config.get([:pipeline, :side_effects], SideEffects) -  @federator Config.get([:pipeline, :federator], Federator) -  @object_validator Config.get([:pipeline, :object_validator], ObjectValidator) -  @mrf Config.get([:pipeline, :mrf], MRF) -  @activity_pub Config.get([:pipeline, :activity_pub], ActivityPub) -  @config Config.get([:pipeline, :config], Config) +  defp side_effects, do: Config.get([:pipeline, :side_effects], SideEffects) +  defp federator, do: Config.get([:pipeline, :federator], Federator) +  defp object_validator, do: Config.get([:pipeline, :object_validator], ObjectValidator) +  defp mrf, do: Config.get([:pipeline, :mrf], MRF) +  defp activity_pub, do: Config.get([:pipeline, :activity_pub], ActivityPub) +  defp config, do: Config.get([:pipeline, :config], Config)    @spec common_pipeline(map(), keyword()) ::            {:ok, Activity.t() | Object.t(), keyword()} | {:error, any()}    def common_pipeline(object, meta) do      case Repo.transaction(fn -> do_common_pipeline(object, meta) end, Utils.query_timeout()) do        {:ok, {:ok, activity, meta}} -> -        @side_effects.handle_after_transaction(meta) +        side_effects().handle_after_transaction(meta)          {:ok, activity, meta}        {:ok, value} -> @@ -44,10 +44,10 @@ defmodule Pleroma.Web.ActivityPub.Pipeline do    def do_common_pipeline(%{__struct__: _}, _meta), do: {:error, :is_struct}    def do_common_pipeline(message, meta) do -    with {_, {:ok, message, meta}} <- {:validate, @object_validator.validate(message, meta)}, -         {_, {:ok, message, meta}} <- {:mrf, @mrf.pipeline_filter(message, meta)}, -         {_, {:ok, message, meta}} <- {:persist, @activity_pub.persist(message, meta)}, -         {_, {:ok, message, meta}} <- {:side_effects, @side_effects.handle(message, meta)}, +    with {_, {:ok, message, meta}} <- {:validate, object_validator().validate(message, meta)}, +         {_, {:ok, message, meta}} <- {:mrf, mrf().pipeline_filter(message, meta)}, +         {_, {:ok, message, meta}} <- {:persist, activity_pub().persist(message, meta)}, +         {_, {:ok, message, meta}} <- {:side_effects, side_effects().handle(message, meta)},           {_, {:ok, _}} <- {:federation, maybe_federate(message, meta)} do        {:ok, message, meta}      else @@ -60,7 +60,7 @@ defmodule Pleroma.Web.ActivityPub.Pipeline do    defp maybe_federate(%Activity{} = activity, meta) do      with {:ok, local} <- Keyword.fetch(meta, :local) do -      do_not_federate = meta[:do_not_federate] || !@config.get([:instance, :federating]) +      do_not_federate = meta[:do_not_federate] || !config().get([:instance, :federating])        if !do_not_federate and local and not Visibility.is_local_public?(activity) do          activity = @@ -70,7 +70,7 @@ defmodule Pleroma.Web.ActivityPub.Pipeline do              activity            end -        @federator.publish(activity) +        federator().publish(activity)          {:ok, :federated}        else          {:ok, :not_federated} diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index b12b2fc24..590beef64 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -272,7 +272,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do        },        %{          "rel" => "http://ostatus.org/schema/1.0/subscribe", -        "template" => "#{Pleroma.Web.base_url()}/ostatus_subscribe?acct={uri}" +        "template" => "#{Pleroma.Web.Endpoint.url()}/ostatus_subscribe?acct={uri}"        }      ]    end diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index 5fe143c2b..674356d9a 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -203,6 +203,19 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do          Object.increase_replies_count(in_reply_to)        end +      reply_depth = (meta[:depth] || 0) + 1 + +      # FIXME: Force inReplyTo to replies +      if Pleroma.Web.Federator.allowed_thread_distance?(reply_depth) and +           object.data["replies"] != nil do +        for reply_id <- object.data["replies"] do +          Pleroma.Workers.RemoteFetcherWorker.enqueue("fetch_remote", %{ +            "id" => reply_id, +            "depth" => reply_depth +          }) +        end +      end +        ConcurrentLimiter.limit(Pleroma.Web.RichMedia.Helpers, fn ->          Task.start(fn -> Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) end)        end) @@ -423,7 +436,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do    end    def handle_object_creation(%{"type" => objtype} = object, meta) -      when objtype in ~w[Audio Video Question Event Article] do +      when objtype in ~w[Audio Video Question Event Article Note] do      with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do        {:ok, object, meta}      end diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index d27d0bed4..51c0cc860 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -43,7 +43,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do      |> fix_content_map()      |> fix_addressing()      |> fix_summary() -    |> fix_type(options)    end    def fix_summary(%{"summary" => nil} = object) do @@ -72,17 +71,21 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do      end    end -  def fix_explicit_addressing( -        %{"to" => to, "cc" => cc} = object, -        explicit_mentions, -        follower_collection -      ) do -    explicit_to = Enum.filter(to, fn x -> x in explicit_mentions end) +  # if directMessage flag is set to true, leave the addressing alone +  def fix_explicit_addressing(%{"directMessage" => true} = object, _follower_collection), +    do: object + +  def fix_explicit_addressing(%{"to" => to, "cc" => cc} = object, follower_collection) do +    explicit_mentions = +      Utils.determine_explicit_mentions(object) ++ +        [Pleroma.Constants.as_public(), follower_collection] +    explicit_to = Enum.filter(to, fn x -> x in explicit_mentions end)      explicit_cc = Enum.filter(to, fn x -> x not in explicit_mentions end)      final_cc =        (cc ++ explicit_cc) +      |> Enum.filter(& &1)        |> Enum.reject(fn x -> String.ends_with?(x, "/followers") and x != follower_collection end)        |> Enum.uniq() @@ -91,29 +94,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do      |> Map.put("cc", final_cc)    end -  def fix_explicit_addressing(object, _explicit_mentions, _followers_collection), do: object - -  # if directMessage flag is set to true, leave the addressing alone -  def fix_explicit_addressing(%{"directMessage" => true} = object), do: object - -  def fix_explicit_addressing(object) do -    explicit_mentions = Utils.determine_explicit_mentions(object) - -    %User{follower_address: follower_collection} = -      object -      |> Containment.get_actor() -      |> User.get_cached_by_ap_id() - -    explicit_mentions = -      explicit_mentions ++ -        [ -          Pleroma.Constants.as_public(), -          follower_collection -        ] - -    fix_explicit_addressing(object, explicit_mentions, follower_collection) -  end -    # if as:Public is addressed, then make sure the followers collection is also addressed    # so that the activities will be delivered to local users.    def fix_implicit_addressing(%{"to" => to, "cc" => cc} = object, followers_collection) do @@ -137,19 +117,19 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do      end    end -  def fix_implicit_addressing(object, _), do: object -    def fix_addressing(object) do -    {:ok, %User{} = user} = User.get_or_fetch_by_ap_id(object["actor"]) -    followers_collection = User.ap_followers(user) +    {:ok, %User{follower_address: follower_collection}} = +      object +      |> Containment.get_actor() +      |> User.get_or_fetch_by_ap_id()      object      |> fix_addressing_list("to")      |> fix_addressing_list("cc")      |> fix_addressing_list("bto")      |> fix_addressing_list("bcc") -    |> fix_explicit_addressing() -    |> fix_implicit_addressing(followers_collection) +    |> fix_explicit_addressing(follower_collection) +    |> fix_implicit_addressing(follower_collection)    end    def fix_actor(%{"attributedTo" => actor} = object) do @@ -223,10 +203,17 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do          media_type =            cond do -            is_map(url) && MIME.valid?(url["mediaType"]) -> url["mediaType"] -            MIME.valid?(data["mediaType"]) -> data["mediaType"] -            MIME.valid?(data["mimeType"]) -> data["mimeType"] -            true -> nil +            is_map(url) && MIME.extensions(url["mediaType"]) != [] -> +              url["mediaType"] + +            is_bitstring(data["mediaType"]) && MIME.extensions(data["mediaType"]) != [] -> +              data["mediaType"] + +            is_bitstring(data["mimeType"]) && MIME.extensions(data["mimeType"]) != [] -> +              data["mimeType"] + +            true -> +              nil            end          href = @@ -244,6 +231,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do                "type" => Map.get(url || %{}, "type", "Link")              }              |> Maps.put_if_present("mediaType", media_type) +            |> Maps.put_if_present("width", (url || %{})["width"] || data["width"]) +            |> Maps.put_if_present("height", (url || %{})["height"] || data["height"])            %{              "url" => [attachment_url], @@ -340,19 +329,18 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do    def fix_content_map(object), do: object -  def fix_type(object, options \\ []) +  defp fix_type(%{"type" => "Note", "inReplyTo" => reply_id, "name" => _} = object, options) +       when is_binary(reply_id) do +    options = Keyword.put(options, :fetch, true) -  def fix_type(%{"inReplyTo" => reply_id, "name" => _} = object, options) -      when is_binary(reply_id) do -    with true <- Federator.allowed_thread_distance?(options[:depth]), -         {:ok, %{data: %{"type" => "Question"} = _} = _} <- get_obj_helper(reply_id, options) do +    with %Object{data: %{"type" => "Question"}} <- Object.normalize(reply_id, options) do        Map.put(object, "type", "Answer")      else        _ -> object      end    end -  def fix_type(object, _), do: object +  defp fix_type(object, _options), do: object    # Reduce the object list to find the reported user.    defp get_reported(objects) do @@ -423,10 +411,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do    # - tags    # - emoji    def handle_incoming( -        %{"type" => "Create", "object" => %{"type" => objtype} = object} = data, +        %{"type" => "Create", "object" => %{"type" => "Page"} = object} = data,          options -      ) -      when objtype in ~w{Note Page} do +      ) do      actor = Containment.get_actor(data)      with nil <- Activity.get_create_by_object_ap_id(object["id"]), @@ -518,14 +505,23 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do    def handle_incoming(          %{"type" => "Create", "object" => %{"type" => objtype, "id" => obj_id}} = data, -        _options +        options        ) -      when objtype in ~w{Question Answer ChatMessage Audio Video Event Article} do -    data = Map.put(data, "object", strip_internal_fields(data["object"])) +      when objtype in ~w{Question Answer ChatMessage Audio Video Event Article Note} do +    fetch_options = Keyword.put(options, :depth, (options[:depth] || 0) + 1) + +    object = +      data["object"] +      |> strip_internal_fields() +      |> fix_type(fetch_options) +      |> fix_in_reply_to(fetch_options) + +    data = Map.put(data, "object", object) +    options = Keyword.put(options, :local, false)      with {:ok, %User{}} <- ObjectValidator.fetch_actor(data),           nil <- Activity.get_create_by_object_ap_id(obj_id), -         {:ok, activity, _} <- Pipeline.common_pipeline(data, local: false) do +         {:ok, activity, _} <- Pipeline.common_pipeline(data, options) do        {:ok, activity}      else        %Activity{} = activity -> {:ok, activity} @@ -949,7 +945,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do        object        |> Map.get("attachment", [])        |> Enum.map(fn data -> -        [%{"mediaType" => media_type, "href" => href} | _] = data["url"] +        [%{"mediaType" => media_type, "href" => href} = url | _] = data["url"]          %{            "url" => href, @@ -957,6 +953,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do            "name" => data["name"],            "type" => "Document"          } +        |> Maps.put_if_present("width", url["width"]) +        |> Maps.put_if_present("height", url["height"]) +        |> Maps.put_if_present("blurhash", data["blurhash"])        end)      Map.put(object, "attachment", attachments) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index a4dc469dc..1df53f79a 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -12,7 +12,6 @@ defmodule Pleroma.Web.ActivityPub.Utils do    alias Pleroma.Object    alias Pleroma.Repo    alias Pleroma.User -  alias Pleroma.Web    alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.ActivityPub.Visibility    alias Pleroma.Web.AdminAPI.AccountView @@ -38,6 +37,8 @@ defmodule Pleroma.Web.ActivityPub.Utils do    @supported_report_states ~w(open closed resolved)    @valid_visibilities ~w(public unlisted private direct) +  def as_local_public, do: Endpoint.url() <> "/#Public" +    # Some implementations send the actor URI as the actor field, others send the entire actor object,    # so figure out what the actor's URI is based on what we have.    def get_ap_id(%{"id" => id} = _), do: id @@ -96,8 +97,11 @@ defmodule Pleroma.Web.ActivityPub.Utils do          !label_in_collection?(ap_id, params["cc"])      if need_splice? do -      cc_list = extract_list(params["cc"]) -      Map.put(params, "cc", [ap_id | cc_list]) +      cc = [ap_id | extract_list(params["cc"])] + +      params +      |> Map.put("cc", cc) +      |> Maps.safe_put_in(["object", "cc"], cc)      else        params      end @@ -107,7 +111,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do      %{        "@context" => [          "https://www.w3.org/ns/activitystreams", -        "#{Web.base_url()}/schemas/litepub-0.1.jsonld", +        "#{Endpoint.url()}/schemas/litepub-0.1.jsonld",          %{            "@language" => "und"          } @@ -132,7 +136,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do    end    def generate_id(type) do -    "#{Web.base_url()}/#{type}/#{UUID.generate()}" +    "#{Endpoint.url()}/#{type}/#{UUID.generate()}"    end    def get_notified_from_object(%{"type" => type} = object) when type in @supported_object_types do diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 462f3b4a7..344da19d3 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -261,7 +261,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do      %{        "id" => featured_address,        "type" => "OrderedCollection", -      "orderedItems" => objects +      "orderedItems" => objects, +      "totalItems" => length(objects)      }      |> Map.merge(Utils.make_json_ld_header())    end diff --git a/lib/pleroma/web/activity_pub/visibility.ex b/lib/pleroma/web/activity_pub/visibility.ex index 00234c0b0..2be59144d 100644 --- a/lib/pleroma/web/activity_pub/visibility.ex +++ b/lib/pleroma/web/activity_pub/visibility.ex @@ -20,14 +20,14 @@ defmodule Pleroma.Web.ActivityPub.Visibility do    def is_public?(data) do      Utils.label_in_message?(Pleroma.Constants.as_public(), data) or -      Utils.label_in_message?(Pleroma.Constants.as_local_public(), data) +      Utils.label_in_message?(Utils.as_local_public(), data)    end    def is_local_public?(%Object{data: data}), do: is_local_public?(data)    def is_local_public?(%Activity{data: data}), do: is_local_public?(data)    def is_local_public?(data) do -    Utils.label_in_message?(Pleroma.Constants.as_local_public(), data) and +    Utils.label_in_message?(Utils.as_local_public(), data) and        not Utils.label_in_message?(Pleroma.Constants.as_public(), data)    end @@ -127,7 +127,7 @@ defmodule Pleroma.Web.ActivityPub.Visibility do        Pleroma.Constants.as_public() in cc ->          "unlisted" -      Pleroma.Constants.as_local_public() in to -> +      Utils.as_local_public() in to ->          "local"        # this should use the sql for the object's activity diff --git a/lib/pleroma/web/admin_api/controllers/o_auth_app_controller.ex b/lib/pleroma/web/admin_api/controllers/o_auth_app_controller.ex index 005fe67e2..51b17d392 100644 --- a/lib/pleroma/web/admin_api/controllers/o_auth_app_controller.ex +++ b/lib/pleroma/web/admin_api/controllers/o_auth_app_controller.ex @@ -13,7 +13,6 @@ defmodule Pleroma.Web.AdminAPI.OAuthAppController do    require Logger    plug(Pleroma.Web.ApiSpec.CastAndValidate) -  plug(:put_view, Pleroma.Web.MastodonAPI.AppView)    plug(      OAuthScopesPlug, diff --git a/lib/pleroma/web/admin_api/views/o_auth_app_view.ex b/lib/pleroma/web/admin_api/views/o_auth_app_view.ex new file mode 100644 index 000000000..af046f343 --- /dev/null +++ b/lib/pleroma/web/admin_api/views/o_auth_app_view.ex @@ -0,0 +1,10 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.OAuthAppView do +  use Pleroma.Web, :view +  alias Pleroma.Web.MastodonAPI + +  def render(view, opts), do: MastodonAPI.AppView.render(view, opts) +end diff --git a/lib/pleroma/web/api_spec/operations/media_operation.ex b/lib/pleroma/web/api_spec/operations/media_operation.ex index 85aa14869..1e245b291 100644 --- a/lib/pleroma/web/api_spec/operations/media_operation.ex +++ b/lib/pleroma/web/api_spec/operations/media_operation.ex @@ -105,6 +105,7 @@ defmodule Pleroma.Web.ApiSpec.MediaOperation do        responses: %{          200 => Operation.response("Media", "application/json", Attachment),          401 => Operation.response("Media", "application/json", ApiError), +        403 => Operation.response("Media", "application/json", ApiError),          422 => Operation.response("Media", "application/json", ApiError)        }      } diff --git a/lib/pleroma/web/api_spec/operations/timeline_operation.ex b/lib/pleroma/web/api_spec/operations/timeline_operation.ex index cae18c758..24d792916 100644 --- a/lib/pleroma/web/api_spec/operations/timeline_operation.ex +++ b/lib/pleroma/web/api_spec/operations/timeline_operation.ex @@ -115,7 +115,8 @@ defmodule Pleroma.Web.ApiSpec.TimelineOperation do        ],        operationId: "TimelineController.hashtag",        responses: %{ -        200 => Operation.response("Array of Status", "application/json", array_of_statuses()) +        200 => Operation.response("Array of Status", "application/json", array_of_statuses()), +        401 => Operation.response("Error", "application/json", ApiError)        }      }    end diff --git a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex new file mode 100644 index 000000000..0cafbc719 --- /dev/null +++ b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex @@ -0,0 +1,219 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do +  alias OpenApiSpex.Operation +  alias OpenApiSpex.Schema +  alias Pleroma.Web.ApiSpec.Schemas.ApiError +  alias Pleroma.Web.ApiSpec.Schemas.BooleanLike + +  def open_api_operation(action) do +    operation = String.to_existing_atom("#{action}_operation") +    apply(__MODULE__, operation, []) +  end + +  def emoji_operation do +    %Operation{ +      tags: ["Emojis"], +      summary: "List all custom emojis", +      operationId: "UtilController.emoji", +      parameters: [], +      responses: %{ +        200 => +          Operation.response("List", "application/json", %Schema{ +            type: :object, +            additionalProperties: %Schema{ +              type: :object, +              properties: %{ +                image_url: %Schema{type: :string}, +                tags: %Schema{type: :array, items: %Schema{type: :string}} +              } +            }, +            example: %{ +              "firefox" => %{ +                "image_url" => "/emoji/firefox.png", +                "tag" => ["Fun"] +              } +            } +          }) +      } +    } +  end + +  def frontend_configurations_operation do +    %Operation{ +      tags: ["Configuration"], +      summary: "Dump frontend configurations", +      operationId: "UtilController.frontend_configurations", +      parameters: [], +      responses: %{ +        200 => +          Operation.response("List", "application/json", %Schema{ +            type: :object, +            additionalProperties: %Schema{type: :object} +          }) +      } +    } +  end + +  def change_password_operation do +    %Operation{ +      tags: ["Account credentials"], +      summary: "Change account password", +      security: [%{"oAuth" => ["write:accounts"]}], +      operationId: "UtilController.change_password", +      parameters: [ +        Operation.parameter(:password, :query, :string, "Current password", required: true), +        Operation.parameter(:new_password, :query, :string, "New password", required: true), +        Operation.parameter( +          :new_password_confirmation, +          :query, +          :string, +          "New password, confirmation", +          required: true +        ) +      ], +      responses: %{ +        200 => +          Operation.response("Success", "application/json", %Schema{ +            type: :object, +            properties: %{status: %Schema{type: :string, example: "success"}} +          }), +        400 => Operation.response("Error", "application/json", ApiError), +        403 => Operation.response("Error", "application/json", ApiError) +      } +    } +  end + +  def change_email_operation do +    %Operation{ +      tags: ["Account credentials"], +      summary: "Change account email", +      security: [%{"oAuth" => ["write:accounts"]}], +      operationId: "UtilController.change_email", +      parameters: [ +        Operation.parameter(:password, :query, :string, "Current password", required: true), +        Operation.parameter(:email, :query, :string, "New email", required: true) +      ], +      requestBody: nil, +      responses: %{ +        200 => +          Operation.response("Success", "application/json", %Schema{ +            type: :object, +            properties: %{status: %Schema{type: :string, example: "success"}} +          }), +        400 => Operation.response("Error", "application/json", ApiError), +        403 => Operation.response("Error", "application/json", ApiError) +      } +    } +  end + +  def update_notificaton_settings_operation do +    %Operation{ +      tags: ["Accounts"], +      summary: "Update Notification Settings", +      security: [%{"oAuth" => ["write:accounts"]}], +      operationId: "UtilController.update_notificaton_settings", +      parameters: [ +        Operation.parameter( +          :block_from_strangers, +          :query, +          BooleanLike, +          "blocks notifications from accounts you do not follow" +        ), +        Operation.parameter( +          :hide_notification_contents, +          :query, +          BooleanLike, +          "removes the contents of a message from the push notification" +        ) +      ], +      requestBody: nil, +      responses: %{ +        200 => +          Operation.response("Success", "application/json", %Schema{ +            type: :object, +            properties: %{status: %Schema{type: :string, example: "success"}} +          }), +        400 => Operation.response("Error", "application/json", ApiError) +      } +    } +  end + +  def disable_account_operation do +    %Operation{ +      tags: ["Account credentials"], +      summary: "Disable Account", +      security: [%{"oAuth" => ["write:accounts"]}], +      operationId: "UtilController.disable_account", +      parameters: [ +        Operation.parameter(:password, :query, :string, "Password") +      ], +      responses: %{ +        200 => +          Operation.response("Success", "application/json", %Schema{ +            type: :object, +            properties: %{status: %Schema{type: :string, example: "success"}} +          }), +        403 => Operation.response("Error", "application/json", ApiError) +      } +    } +  end + +  def delete_account_operation do +    %Operation{ +      tags: ["Account credentials"], +      summary: "Delete Account", +      security: [%{"oAuth" => ["write:accounts"]}], +      operationId: "UtilController.delete_account", +      parameters: [ +        Operation.parameter(:password, :query, :string, "Password") +      ], +      responses: %{ +        200 => +          Operation.response("Success", "application/json", %Schema{ +            type: :object, +            properties: %{status: %Schema{type: :string, example: "success"}} +          }), +        403 => Operation.response("Error", "application/json", ApiError) +      } +    } +  end + +  def captcha_operation do +    %Operation{ +      summary: "Get a captcha", +      operationId: "UtilController.captcha", +      parameters: [], +      responses: %{ +        200 => Operation.response("Success", "application/json", %Schema{type: :object}) +      } +    } +  end + +  def healthcheck_operation do +    %Operation{ +      tags: ["Accounts"], +      summary: "Quick status check on the instance", +      security: [%{"oAuth" => ["write:accounts"]}], +      operationId: "UtilController.healthcheck", +      parameters: [], +      responses: %{ +        200 => Operation.response("Healthy", "application/json", %Schema{type: :object}), +        503 => +          Operation.response("Disabled or Unhealthy", "application/json", %Schema{type: :object}) +      } +    } +  end + +  def remote_subscribe_operation do +    %Operation{ +      tags: ["Accounts"], +      summary: "Remote Subscribe", +      operationId: "UtilController.remote_subscribe", +      parameters: [], +      responses: %{200 => Operation.response("Web Page", "test/html", %Schema{type: :string})} +    } +  end +end diff --git a/lib/pleroma/web/api_spec/operations/user_import_operation.ex b/lib/pleroma/web/api_spec/operations/user_import_operation.ex index 6292e2004..8df19f1fc 100644 --- a/lib/pleroma/web/api_spec/operations/user_import_operation.ex +++ b/lib/pleroma/web/api_spec/operations/user_import_operation.ex @@ -23,6 +23,7 @@ defmodule Pleroma.Web.ApiSpec.UserImportOperation do        requestBody: request_body("Parameters", import_request(), required: true),        responses: %{          200 => ok_response(), +        403 => Operation.response("Error", "application/json", ApiError),          500 => Operation.response("Error", "application/json", ApiError)        },        security: [%{"oAuth" => ["write:follow"]}] diff --git a/lib/pleroma/web/channels/user_socket.ex b/lib/pleroma/web/channels/user_socket.ex index 1c09b6768..043206835 100644 --- a/lib/pleroma/web/channels/user_socket.ex +++ b/lib/pleroma/web/channels/user_socket.ex @@ -8,7 +8,7 @@ defmodule Pleroma.Web.UserSocket do    ## Channels    # channel "room:*", Pleroma.Web.RoomChannel -  channel("chat:*", Pleroma.Web.ChatChannel) +  channel("chat:*", Pleroma.Web.ShoutChannel)    # Socket params are passed from the client and can    # be used to verify and authenticate a user. After @@ -22,7 +22,7 @@ defmodule Pleroma.Web.UserSocket do    # See `Phoenix.Token` documentation for examples in    # performing token verification on connect.    def connect(%{"token" => token}, socket) do -    with true <- Pleroma.Config.get([:chat, :enabled]), +    with true <- Pleroma.Config.get([:shout, :enabled]),           {:ok, user_id} <- Phoenix.Token.verify(socket, "user socket", token, max_age: 84_600),           %User{} = user <- Pleroma.User.get_cached_by_id(user_id) do        {:ok, assign(socket, :user_name, user.nickname)} diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 94a378e11..4cc34002d 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -69,7 +69,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do      to =        case visibility do          "public" -> [Pleroma.Constants.as_public() | draft.mentions] -        "local" -> [Pleroma.Constants.as_local_public() | draft.mentions] +        "local" -> [Utils.as_local_public() | draft.mentions]        end      cc = [draft.user.follower_address] diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index 8e274de88..7591d0ae5 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -102,7 +102,7 @@ defmodule Pleroma.Web.Endpoint do    plug(Plug.Parsers,      parsers: [        :urlencoded, -      {:multipart, length: {Config, :get, [[:instance, :upload_limit]]}}, +      {:multipart, length: Config.get([:instance, :upload_limit])},        :json      ],      pass: ["*/*"], diff --git a/lib/pleroma/web/federator.ex b/lib/pleroma/web/federator.ex index f5ef76d32..69cfc2d52 100644 --- a/lib/pleroma/web/federator.ex +++ b/lib/pleroma/web/federator.ex @@ -96,6 +96,11 @@ defmodule Pleroma.Web.Federator do          Logger.debug("Unhandled actor #{actor}, #{inspect(e)}")          {:error, e} +      {:error, {:validate_object, _}} = e -> +        Logger.error("Incoming AP doc validation error: #{inspect(e)}") +        Logger.debug(Jason.encode!(params, pretty: true)) +        e +        e ->          # Just drop those for now          Logger.debug(fn -> "Unhandled activity\n" <> Jason.encode!(params, pretty: true) end) diff --git a/lib/pleroma/web/feed/feed_view.ex b/lib/pleroma/web/feed/feed_view.ex index 66940f311..c0fb35e01 100644 --- a/lib/pleroma/web/feed/feed_view.ex +++ b/lib/pleroma/web/feed/feed_view.ex @@ -52,10 +52,10 @@ defmodule Pleroma.Web.Feed.FeedView do    def feed_logo do      case Pleroma.Config.get([:feed, :logo]) do        nil -> -        "#{Pleroma.Web.base_url()}/static/logo.svg" +        "#{Pleroma.Web.Endpoint.url()}/static/logo.svg"        logo -> -        "#{Pleroma.Web.base_url()}#{logo}" +        "#{Pleroma.Web.Endpoint.url()}#{logo}"      end      |> MediaProxy.url()    end diff --git a/lib/pleroma/web/feed/user_controller.ex b/lib/pleroma/web/feed/user_controller.ex index 58d35da1e..fa7879caf 100644 --- a/lib/pleroma/web/feed/user_controller.ex +++ b/lib/pleroma/web/feed/user_controller.ex @@ -28,7 +28,7 @@ defmodule Pleroma.Web.Feed.UserController do    def feed_redirect(conn, %{"nickname" => nickname}) do      with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do -      redirect(conn, external: "#{user_feed_url(conn, :feed, user.nickname)}.atom") +      redirect(conn, external: "#{Routes.user_feed_url(conn, :feed, user.nickname)}.atom")      end    end diff --git a/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex b/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex index eb6639fc5..4920d65da 100644 --- a/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex @@ -53,7 +53,7 @@ defmodule Pleroma.Web.MastodonAPI.AuthController do    defp redirect_to_oauth_form(conn, _params) do      with {:ok, app} <- local_mastofe_app() do        path = -        o_auth_path(conn, :authorize, +        Routes.o_auth_path(conn, :authorize,            response_type: "code",            client_id: app.client_id,            redirect_uri: ".", @@ -90,7 +90,7 @@ defmodule Pleroma.Web.MastodonAPI.AuthController do    defp local_mastodon_post_login_path(conn) do      case get_session(conn, :return_to) do        nil -> -        masto_fe_path(conn, :index, ["getting-started"]) +        Routes.masto_fe_path(conn, :index, ["getting-started"])        return_to ->          delete_session(conn, :return_to) diff --git a/lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex b/lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex index 63d0e2c35..d915298f1 100644 --- a/lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex @@ -9,7 +9,6 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestController do    alias Pleroma.Web.CommonAPI    alias Pleroma.Web.Plugs.OAuthScopesPlug -  plug(:put_view, Pleroma.Web.MastodonAPI.AccountView)    plug(Pleroma.Web.ApiSpec.CastAndValidate)    plug(:assign_follower when action != :index) diff --git a/lib/pleroma/web/mastodon_api/controllers/media_controller.ex b/lib/pleroma/web/mastodon_api/controllers/media_controller.ex index d6949ed80..5918b288d 100644 --- a/lib/pleroma/web/mastodon_api/controllers/media_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/media_controller.ex @@ -13,7 +13,6 @@ defmodule Pleroma.Web.MastodonAPI.MediaController do    action_fallback(Pleroma.Web.MastodonAPI.FallbackController)    plug(Majic.Plug, [pool: Pleroma.MajicPool] when action in [:create, :create2])    plug(Pleroma.Web.ApiSpec.CastAndValidate) -  plug(:put_view, Pleroma.Web.MastodonAPI.StatusView)    plug(OAuthScopesPlug, %{scopes: ["read:media"]} when action == :show)    plug(OAuthScopesPlug, %{scopes: ["write:media"]} when action != :show) diff --git a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex index af93e453d..64b177eb3 100644 --- a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex @@ -8,8 +8,8 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do    alias Pleroma.Activity    alias Pleroma.Repo    alias Pleroma.User -  alias Pleroma.Web    alias Pleroma.Web.ControllerHelper +  alias Pleroma.Web.Endpoint    alias Pleroma.Web.MastodonAPI.AccountView    alias Pleroma.Web.MastodonAPI.StatusView    alias Pleroma.Web.Plugs.OAuthScopesPlug @@ -108,7 +108,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do    end    defp resource_search(:v2, "hashtags", query, options) do -    tags_path = Web.base_url() <> "/tag/" +    tags_path = Endpoint.url() <> "/tag/"      query      |> prepare_tags(options) diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex index c611958be..845f546d4 100644 --- a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex @@ -37,8 +37,6 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do      when action in [:public, :hashtag]    ) -  plug(:put_view, Pleroma.Web.MastodonAPI.StatusView) -    defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.TimelineOperation    # GET /api/v1/timelines/home diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index ac25aefdd..9e9de33f6 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -292,6 +292,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do      |> maybe_put_allow_following_move(user, opts[:for])      |> maybe_put_unread_conversation_count(user, opts[:for])      |> maybe_put_unread_notification_count(user, opts[:for]) +    |> maybe_put_email_address(user, opts[:for])    end    defp username_from_nickname(string) when is_binary(string) do @@ -403,6 +404,16 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do    defp maybe_put_unread_notification_count(data, _, _), do: data +  defp maybe_put_email_address(data, %User{id: user_id}, %User{id: user_id} = user) do +    Kernel.put_in( +      data, +      [:pleroma, :email], +      user.email +    ) +  end + +  defp maybe_put_email_address(data, _, _), do: data +    defp image_url(%{"url" => [%{"href" => href} | _]}), do: href    defp image_url(_), do: nil  end diff --git a/lib/pleroma/web/mastodon_api/views/custom_emoji_view.ex b/lib/pleroma/web/mastodon_api/views/custom_emoji_view.ex index 40e314164..7d2d605e9 100644 --- a/lib/pleroma/web/mastodon_api/views/custom_emoji_view.ex +++ b/lib/pleroma/web/mastodon_api/views/custom_emoji_view.ex @@ -6,14 +6,14 @@ defmodule Pleroma.Web.MastodonAPI.CustomEmojiView do    use Pleroma.Web, :view    alias Pleroma.Emoji -  alias Pleroma.Web +  alias Pleroma.Web.Endpoint    def render("index.json", %{custom_emojis: custom_emojis}) do      render_many(custom_emojis, __MODULE__, "show.json")    end    def render("show.json", %{custom_emoji: {shortcode, %Emoji{file: relative_url, tags: tags}}}) do -    url = Web.base_url() |> URI.merge(relative_url) |> to_string() +    url = Endpoint.url() |> URI.merge(relative_url) |> to_string()      %{        "shortcode" => shortcode, diff --git a/lib/pleroma/web/mastodon_api/views/follow_request_view.ex b/lib/pleroma/web/mastodon_api/views/follow_request_view.ex new file mode 100644 index 000000000..4c7d9fc65 --- /dev/null +++ b/lib/pleroma/web/mastodon_api/views/follow_request_view.ex @@ -0,0 +1,10 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.FollowRequestView do +  use Pleroma.Web, :view +  alias Pleroma.Web.MastodonAPI + +  def render(view, opts), do: MastodonAPI.AccountView.render(view, opts) +end diff --git a/lib/pleroma/web/mastodon_api/views/instance_view.ex b/lib/pleroma/web/mastodon_api/views/instance_view.ex index dac68d8e6..3528185d5 100644 --- a/lib/pleroma/web/mastodon_api/views/instance_view.ex +++ b/lib/pleroma/web/mastodon_api/views/instance_view.ex @@ -14,7 +14,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do      instance = Config.get(:instance)      %{ -      uri: Pleroma.Web.base_url(), +      uri: Pleroma.Web.Endpoint.url(),        title: Keyword.get(instance, :name),        description: Keyword.get(instance, :description),        version: "#{@mastodon_api_level} (compatible; #{Pleroma.Application.named_version()})", @@ -24,7 +24,8 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do        },        stats: Pleroma.Stats.get_stats(),        thumbnail: -        URI.merge(Pleroma.Web.base_url(), Keyword.get(instance, :instance_thumbnail)) |> to_string, +        URI.merge(Pleroma.Web.Endpoint.url(), Keyword.get(instance, :instance_thumbnail)) +        |> to_string,        languages: ["en"],        registrations: Keyword.get(instance, :registrations_open),        approval_required: Keyword.get(instance, :account_approval_required), @@ -35,8 +36,8 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do        avatar_upload_limit: Keyword.get(instance, :avatar_upload_limit),        background_upload_limit: Keyword.get(instance, :background_upload_limit),        banner_upload_limit: Keyword.get(instance, :banner_upload_limit), -      background_image: Pleroma.Web.base_url() <> Keyword.get(instance, :background_image), -      chat_limit: Keyword.get(instance, :chat_limit), +      background_image: Pleroma.Web.Endpoint.url() <> Keyword.get(instance, :background_image), +      shout_limit: Config.get([:shout, :limit]),        description_limit: Keyword.get(instance, :description_limit),        pleroma: %{          metadata: %{ @@ -68,9 +69,13 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do        if Config.get([:gopher, :enabled]) do          "gopher"        end, -      if Config.get([:chat, :enabled]) do +      # backwards compat +      if Config.get([:shout, :enabled]) do          "chat"        end, +      if Config.get([:shout, :enabled]) do +        "shout" +      end,        if Config.get([:instance, :allow_relay]) do          "relay"        end, diff --git a/lib/pleroma/web/mastodon_api/views/media_view.ex b/lib/pleroma/web/mastodon_api/views/media_view.ex new file mode 100644 index 000000000..cf521887e --- /dev/null +++ b/lib/pleroma/web/mastodon_api/views/media_view.ex @@ -0,0 +1,10 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.MediaView do +  use Pleroma.Web, :view +  alias Pleroma.Web.MastodonAPI + +  def render(view, opts), do: MastodonAPI.StatusView.render(view, opts) +end diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 814b3d142..da44e0a74 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -9,6 +9,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do    alias Pleroma.Activity    alias Pleroma.HTML +  alias Pleroma.Maps    alias Pleroma.Object    alias Pleroma.Repo    alias Pleroma.User @@ -259,7 +260,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do      content_html =        content -      |> HTML.get_cached_scrubbed_html_for_activity( +      |> Activity.HTML.get_cached_scrubbed_html_for_activity(          User.html_filter_policy(opts[:for]),          activity,          "mastoapi:content" @@ -267,7 +268,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do      content_plaintext =        content -      |> HTML.get_cached_stripped_html_for_activity( +      |> Activity.HTML.get_cached_stripped_html_for_activity(          activity,          "mastoapi:content"        ) @@ -417,6 +418,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do      media_type = attachment_url["mediaType"] || attachment_url["mimeType"] || "image"      href = attachment_url["href"] |> MediaProxy.url()      href_preview = attachment_url["href"] |> MediaProxy.preview_url() +    meta = render("attachment_meta.json", %{attachment: attachment})      type =        cond do @@ -439,8 +441,24 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do        pleroma: %{mime_type: media_type},        blurhash: attachment["blurhash"]      } +    |> Maps.put_if_present(:meta, meta)    end +  def render("attachment_meta.json", %{ +        attachment: %{"url" => [%{"width" => width, "height" => height} | _]} +      }) +      when is_integer(width) and is_integer(height) do +    %{ +      original: %{ +        width: width, +        height: height, +        aspect: width / height +      } +    } +  end + +  def render("attachment_meta.json", _), do: nil +    def render("context.json", %{activity: activity, activities: activities, user: user}) do      %{ancestors: ancestors, descendants: descendants} =        activities @@ -496,7 +514,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do    def build_tags(object_tags) when is_list(object_tags) do      object_tags      |> Enum.filter(&is_binary/1) -    |> Enum.map(&%{name: &1, url: "#{Pleroma.Web.base_url()}/tag/#{URI.encode(&1)}"}) +    |> Enum.map(&%{name: &1, url: "#{Pleroma.Web.Endpoint.url()}/tag/#{URI.encode(&1)}"})    end    def build_tags(_), do: [] diff --git a/lib/pleroma/web/mastodon_api/views/timeline_view.ex b/lib/pleroma/web/mastodon_api/views/timeline_view.ex new file mode 100644 index 000000000..91226d78e --- /dev/null +++ b/lib/pleroma/web/mastodon_api/views/timeline_view.ex @@ -0,0 +1,10 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.TimelineView do +  use Pleroma.Web, :view +  alias Pleroma.Web.MastodonAPI + +  def render(view, opts), do: MastodonAPI.StatusView.render(view, opts) +end diff --git a/lib/pleroma/web/media_proxy.ex b/lib/pleroma/web/media_proxy.ex index d0d4bb4b3..0b232f14b 100644 --- a/lib/pleroma/web/media_proxy.ex +++ b/lib/pleroma/web/media_proxy.ex @@ -6,7 +6,7 @@ defmodule Pleroma.Web.MediaProxy do    alias Pleroma.Config    alias Pleroma.Helpers.UriHelper    alias Pleroma.Upload -  alias Pleroma.Web +  alias Pleroma.Web.Endpoint    alias Pleroma.Web.MediaProxy.Invalidation    @base64_opts [padding: false] @@ -69,7 +69,7 @@ defmodule Pleroma.Web.MediaProxy do    #   non-local non-whitelisted URLs through it and be sure that body size constraint is preserved.    def preview_enabled?, do: enabled?() and !!Config.get([:media_preview_proxy, :enabled]) -  def local?(url), do: String.starts_with?(url, Web.base_url()) +  def local?(url), do: String.starts_with?(url, Endpoint.url())    def whitelisted?(url) do      %{host: domain} = URI.parse(url) @@ -127,7 +127,7 @@ defmodule Pleroma.Web.MediaProxy do    end    defp signed_url(url) do -    :crypto.hmac(:sha, Config.get([Web.Endpoint, :secret_key_base]), url) +    :crypto.mac(:hmac, :sha, Config.get([Endpoint, :secret_key_base]), url)    end    def filename(url_or_path) do @@ -135,7 +135,7 @@ defmodule Pleroma.Web.MediaProxy do    end    def base_url do -    Config.get([:media_proxy, :base_url], Web.base_url()) +    Config.get([:media_proxy, :base_url], Endpoint.url())    end    defp proxy_url(path, sig_base64, url_base64, filename) do diff --git a/lib/pleroma/web/metadata/utils.ex b/lib/pleroma/web/metadata/utils.ex index de7195435..bc31d66b9 100644 --- a/lib/pleroma/web/metadata/utils.ex +++ b/lib/pleroma/web/metadata/utils.ex @@ -3,6 +3,7 @@  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.Metadata.Utils do +  alias Pleroma.Activity    alias Pleroma.Emoji    alias Pleroma.Formatter    alias Pleroma.HTML @@ -13,7 +14,7 @@ defmodule Pleroma.Web.Metadata.Utils do      # html content comes from DB already encoded, decode first and scrub after      |> HtmlEntities.decode()      |> String.replace(~r/<br\s?\/?>/, " ") -    |> HTML.get_cached_stripped_html_for_activity(object, "metadata") +    |> Activity.HTML.get_cached_stripped_html_for_activity(object, "metadata")      |> Emoji.Formatter.demojify()      |> HtmlEntities.decode()      |> Formatter.truncate() diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex index bca94d236..69ec27ba0 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex @@ -5,7 +5,7 @@  defmodule Pleroma.Web.Nodeinfo.NodeinfoController do    use Pleroma.Web, :controller -  alias Pleroma.Web +  alias Pleroma.Web.Endpoint    alias Pleroma.Web.Nodeinfo.Nodeinfo    def schemas(conn, _params) do @@ -13,11 +13,11 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do        links: [          %{            rel: "http://nodeinfo.diaspora.software/ns/schema/2.0", -          href: Web.base_url() <> "/nodeinfo/2.0.json" +          href: Endpoint.url() <> "/nodeinfo/2.0.json"          },          %{            rel: "http://nodeinfo.diaspora.software/ns/schema/2.1", -          href: Web.base_url() <> "/nodeinfo/2.1.json" +          href: Endpoint.url() <> "/nodeinfo/2.1.json"          }        ]      } diff --git a/lib/pleroma/web/o_auth/o_auth_controller.ex b/lib/pleroma/web/o_auth/o_auth_controller.ex index 215d97b3a..42f4d768f 100644 --- a/lib/pleroma/web/o_auth/o_auth_controller.ex +++ b/lib/pleroma/web/o_auth/o_auth_controller.ex @@ -427,7 +427,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do        |> Map.put("state", state)      # Handing the request to Ueberauth -    redirect(conn, to: o_auth_path(conn, :request, provider, params)) +    redirect(conn, to: Routes.o_auth_path(conn, :request, provider, params))    end    def request(%Plug.Conn{} = conn, params) do @@ -601,7 +601,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do    end    # Special case: Local MastodonFE -  defp redirect_uri(%Plug.Conn{} = conn, "."), do: auth_url(conn, :login) +  defp redirect_uri(%Plug.Conn{} = conn, "."), do: Routes.auth_url(conn, :login)    defp redirect_uri(%Plug.Conn{}, redirect_uri), do: redirect_uri diff --git a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex index 165afd3b4..6e01c5497 100644 --- a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex @@ -47,7 +47,6 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do    plug(RateLimiter, [name: :account_confirmation_resend] when action == :confirmation_resend)    plug(:assign_account_by_id when action in [:favourites, :subscribe, :unsubscribe]) -  plug(:put_view, Pleroma.Web.MastodonAPI.AccountView)    defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaAccountOperation diff --git a/lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex b/lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex index d285e4907..be2f4617d 100644 --- a/lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex @@ -13,7 +13,6 @@ defmodule Pleroma.Web.PleromaAPI.ConversationController do    alias Pleroma.Web.Plugs.OAuthScopesPlug    plug(Pleroma.Web.ApiSpec.CastAndValidate) -  plug(:put_view, Pleroma.Web.MastodonAPI.ConversationView)    plug(OAuthScopesPlug, %{scopes: ["read:statuses"]} when action in [:show, :statuses])    plug( diff --git a/lib/pleroma/web/pleroma_api/controllers/notification_controller.ex b/lib/pleroma/web/pleroma_api/controllers/notification_controller.ex index 257bcd550..bcb3a9ae1 100644 --- a/lib/pleroma/web/pleroma_api/controllers/notification_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/notification_controller.ex @@ -14,8 +14,6 @@ defmodule Pleroma.Web.PleromaAPI.NotificationController do      %{scopes: ["write:notifications"]} when action == :mark_as_read    ) -  plug(:put_view, Pleroma.Web.MastodonAPI.NotificationView) -    defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaNotificationOperation    def mark_as_read(%{assigns: %{user: user}, body_params: %{id: notification_id}} = conn, _) do diff --git a/lib/pleroma/web/pleroma_api/views/account_view.ex b/lib/pleroma/web/pleroma_api/views/account_view.ex new file mode 100644 index 000000000..28941f471 --- /dev/null +++ b/lib/pleroma/web/pleroma_api/views/account_view.ex @@ -0,0 +1,10 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.AccountView do +  use Pleroma.Web, :view +  alias Pleroma.Web.MastodonAPI + +  def render(view, opts), do: MastodonAPI.AccountView.render(view, opts) +end diff --git a/lib/pleroma/web/pleroma_api/views/conversation_view.ex b/lib/pleroma/web/pleroma_api/views/conversation_view.ex new file mode 100644 index 000000000..173006360 --- /dev/null +++ b/lib/pleroma/web/pleroma_api/views/conversation_view.ex @@ -0,0 +1,10 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.ConversationView do +  use Pleroma.Web, :view +  alias Pleroma.Web.MastodonAPI + +  def render(view, opts), do: MastodonAPI.ConversationView.render(view, opts) +end diff --git a/lib/pleroma/web/pleroma_api/views/notification_view.ex b/lib/pleroma/web/pleroma_api/views/notification_view.ex new file mode 100644 index 000000000..36b2fdfe8 --- /dev/null +++ b/lib/pleroma/web/pleroma_api/views/notification_view.ex @@ -0,0 +1,10 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.NotificationView do +  use Pleroma.Web, :view +  alias Pleroma.Web.MastodonAPI + +  def render(view, opts), do: MastodonAPI.NotificationView.render(view, opts) +end diff --git a/lib/pleroma/web/plugs/frontend_static.ex b/lib/pleroma/web/plugs/frontend_static.ex index eb385e94d..ebe7eaf86 100644 --- a/lib/pleroma/web/plugs/frontend_static.ex +++ b/lib/pleroma/web/plugs/frontend_static.ex @@ -10,8 +10,6 @@ defmodule Pleroma.Web.Plugs.FrontendStatic do    """    @behaviour Plug -  @api_routes Pleroma.Web.get_api_routes() -    def file_path(path, frontend_type \\ :primary) do      if configuration = Pleroma.Config.get([:frontends, frontend_type]) do        instance_static_path = Pleroma.Config.get([:instance, :static_dir], "instance/static") @@ -55,10 +53,13 @@ defmodule Pleroma.Web.Plugs.FrontendStatic do    defp invalid_path?([h | t], match), do: String.contains?(h, match) or invalid_path?(t)    defp invalid_path?([], _match), do: false -  defp api_route?([h | _]) when h in @api_routes, do: true -  defp api_route?([_ | t]), do: api_route?(t)    defp api_route?([]), do: false +  defp api_route?([h | t]) do +    api_routes = Pleroma.Web.Router.get_api_routes() +    if h in api_routes, do: true, else: api_route?(t) +  end +    defp call_static(conn, opts, from) do      opts = Map.put(opts, :from, from)      Plug.Static.call(conn, opts) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index ccf2ef796..efca7078a 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -140,6 +140,10 @@ defmodule Pleroma.Web.Router do      plug(Pleroma.Web.Plugs.MappedSignatureToIdentityPlug)    end +  pipeline :static_fe do +    plug(Pleroma.Web.Plugs.StaticFEPlug) +  end +    scope "/api/v1/pleroma", Pleroma.Web.TwitterAPI do      pipe_through(:pleroma_api) @@ -620,18 +624,12 @@ defmodule Pleroma.Web.Router do      get("/oauth_tokens", TwitterAPI.Controller, :oauth_tokens)      delete("/oauth_tokens/:id", TwitterAPI.Controller, :revoke_token) - -    post( -      "/qvitter/statuses/notifications/read", -      TwitterAPI.Controller, -      :mark_notifications_as_read -    )    end    scope "/", Pleroma.Web do      # Note: html format is supported only if static FE is enabled      # Note: http signature is only considered for json requests (no auth for non-json requests) -    pipe_through([:accepts_html_json, :http_signature, Pleroma.Web.Plugs.StaticFEPlug]) +    pipe_through([:accepts_html_json, :http_signature, :static_fe])      get("/objects/:uuid", OStatus.OStatusController, :object)      get("/activities/:uuid", OStatus.OStatusController, :activity) @@ -645,7 +643,7 @@ defmodule Pleroma.Web.Router do    scope "/", Pleroma.Web do      # Note: html format is supported only if static FE is enabled      # Note: http signature is only considered for json requests (no auth for non-json requests) -    pipe_through([:accepts_html_xml_json, :http_signature, Pleroma.Web.Plugs.StaticFEPlug]) +    pipe_through([:accepts_html_xml_json, :http_signature, :static_fe])      # Note: returns user _profile_ for json requests, redirects to user _feed_ for non-json ones      get("/users/:nickname", Feed.UserController, :feed_redirect, as: :user_feed) @@ -653,7 +651,7 @@ defmodule Pleroma.Web.Router do    scope "/", Pleroma.Web do      # Note: html format is supported only if static FE is enabled -    pipe_through([:accepts_html_xml, Pleroma.Web.Plugs.StaticFEPlug]) +    pipe_through([:accepts_html_xml, :static_fe])      get("/users/:nickname/feed", Feed.UserController, :feed, as: :user_feed)    end @@ -765,11 +763,11 @@ defmodule Pleroma.Web.Router do      get("/embed/:id", EmbedController, :show)    end -  scope "/proxy/", Pleroma.Web.MediaProxy do -    get("/preview/:sig/:url", MediaProxyController, :preview) -    get("/preview/:sig/:url/:filename", MediaProxyController, :preview) -    get("/:sig/:url", MediaProxyController, :remote) -    get("/:sig/:url/:filename", MediaProxyController, :remote) +  scope "/proxy/", Pleroma.Web do +    get("/preview/:sig/:url", MediaProxy.MediaProxyController, :preview) +    get("/preview/:sig/:url/:filename", MediaProxy.MediaProxyController, :preview) +    get("/:sig/:url", MediaProxy.MediaProxyController, :remote) +    get("/:sig/:url/:filename", MediaProxy.MediaProxyController, :remote)    end    if Pleroma.Config.get(:env) == :dev do @@ -822,4 +820,16 @@ defmodule Pleroma.Web.Router do      options("/*path", RedirectController, :empty)    end + +  # TODO: Change to Phoenix.Router.routes/1 for Phoenix 1.6.0+ +  def get_api_routes do +    __MODULE__.__routes__() +    |> Enum.reject(fn r -> r.plug == Pleroma.Web.Fallback.RedirectController end) +    |> Enum.map(fn r -> +      r.path +      |> String.split("/", trim: true) +      |> List.first() +    end) +    |> Enum.uniq() +  end  end diff --git a/lib/pleroma/web/chat_channel.ex b/lib/pleroma/web/shout_channel.ex index 4008129e9..17caecb1a 100644 --- a/lib/pleroma/web/chat_channel.ex +++ b/lib/pleroma/web/shout_channel.ex @@ -2,12 +2,12 @@  # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.ChatChannel do +defmodule Pleroma.Web.ShoutChannel do    use Phoenix.Channel    alias Pleroma.User -  alias Pleroma.Web.ChatChannel.ChatChannelState    alias Pleroma.Web.MastodonAPI.AccountView +  alias Pleroma.Web.ShoutChannel.ShoutChannelState    def join("chat:public", _message, socket) do      send(self(), :after_join) @@ -15,18 +15,18 @@ defmodule Pleroma.Web.ChatChannel do    end    def handle_info(:after_join, socket) do -    push(socket, "messages", %{messages: ChatChannelState.messages()}) +    push(socket, "messages", %{messages: ShoutChannelState.messages()})      {:noreply, socket}    end    def handle_in("new_msg", %{"text" => text}, %{assigns: %{user_name: user_name}} = socket) do      text = String.trim(text) -    if String.length(text) in 1..Pleroma.Config.get([:instance, :chat_limit]) do +    if String.length(text) in 1..Pleroma.Config.get([:shout, :limit]) do        author = User.get_cached_by_nickname(user_name)        author_json = AccountView.render("show.json", user: author, skip_visibility_check: true) -      message = ChatChannelState.add_message(%{text: text, author: author_json}) +      message = ShoutChannelState.add_message(%{text: text, author: author_json})        broadcast!(socket, "new_msg", message)      end @@ -35,7 +35,7 @@ defmodule Pleroma.Web.ChatChannel do    end  end -defmodule Pleroma.Web.ChatChannel.ChatChannelState do +defmodule Pleroma.Web.ShoutChannel.ShoutChannelState do    use Agent    @max_messages 20 diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index fe485d10d..50f0927a3 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -14,7 +14,6 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do    alias Pleroma.Web.Router.Helpers    plug(:put_layout, :static_fe) -  plug(:put_view, Pleroma.Web.StaticFE.StaticFEView)    plug(:assign_id)    @page_keys ["max_id", "min_id", "limit", "since_id", "order"] diff --git a/lib/pleroma/web/templates/feed/feed/_activity.atom.eex b/lib/pleroma/web/templates/feed/feed/_activity.atom.eex index 6688830ba..57bd92468 100644 --- a/lib/pleroma/web/templates/feed/feed/_activity.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/_activity.atom.eex @@ -38,7 +38,7 @@      <%= if id == Pleroma.Constants.as_public() do %>        <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>      <% else %> -      <%= unless Regex.match?(~r/^#{Pleroma.Web.base_url()}.+followers$/, id) do %> +      <%= unless Regex.match?(~r/^#{Pleroma.Web.Endpoint.url()}.+followers$/, id) do %>          <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="<%= id %>"/>        <% end %>      <% end %> diff --git a/lib/pleroma/web/templates/feed/feed/_activity.rss.eex b/lib/pleroma/web/templates/feed/feed/_activity.rss.eex index 592b9dcdc..279f2171d 100644 --- a/lib/pleroma/web/templates/feed/feed/_activity.rss.eex +++ b/lib/pleroma/web/templates/feed/feed/_activity.rss.eex @@ -38,7 +38,7 @@      <%= if id == Pleroma.Constants.as_public() do %>        <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection">http://activityschema.org/collection/public</link>      <% else %> -      <%= unless Regex.match?(~r/^#{Pleroma.Web.base_url()}.+followers$/, id) do %> +      <%= unless Regex.match?(~r/^#{Pleroma.Web.Endpoint.url()}.+followers$/, id) do %>          <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person"><%= id %></link>        <% end %>      <% end %> diff --git a/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex b/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex index c2de28fe4..aa3035bca 100644 --- a/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex @@ -33,7 +33,7 @@            ostatus:object-type="http://activitystrea.ms/schema/1.0/collection"            href="http://activityschema.org/collection/public"/>        <% else %> -        <%= unless Regex.match?(~r/^#{Pleroma.Web.base_url()}.+followers$/, id) do %> +        <%= unless Regex.match?(~r/^#{Pleroma.Web.Endpoint.url()}.+followers$/, id) do %>            <link rel="mentioned"              ostatus:object-type="http://activitystrea.ms/schema/1.0/person"              href="<%= id %>" /> diff --git a/lib/pleroma/web/templates/feed/feed/tag.atom.eex b/lib/pleroma/web/templates/feed/feed/tag.atom.eex index a288539ed..de0731085 100644 --- a/lib/pleroma/web/templates/feed/feed/tag.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/tag.atom.eex @@ -9,13 +9,13 @@        xmlns:ostatus="http://ostatus.org/schema/1.0"        xmlns:statusnet="http://status.net/schema/api/1/"> -    <id><%= '#{tag_feed_url(@conn, :feed, @tag)}.rss' %></id> +    <id><%= '#{Routes.tag_feed_url(@conn, :feed, @tag)}.rss' %></id>      <title>#<%= @tag %></title>      <subtitle>These are public toots tagged with #<%= @tag %>. You can interact with them if you have an account anywhere in the fediverse.</subtitle>      <logo><%= feed_logo() %></logo>      <updated><%= most_recent_update(@activities) %></updated> -    <link rel="self" href="<%= '#{tag_feed_url(@conn, :feed, @tag)}.atom'  %>" type="application/atom+xml"/> +    <link rel="self" href="<%= '#{Routes.tag_feed_url(@conn, :feed, @tag)}.atom'  %>" type="application/atom+xml"/>      <%= for activity <- @activities do %>      <%= render @view_module, "_tag_activity.atom", Map.merge(assigns, prepare_activity(activity, actor: true)) %>      <% end %> diff --git a/lib/pleroma/web/templates/feed/feed/tag.rss.eex b/lib/pleroma/web/templates/feed/feed/tag.rss.eex index eeda01a04..9c3613feb 100644 --- a/lib/pleroma/web/templates/feed/feed/tag.rss.eex +++ b/lib/pleroma/web/templates/feed/feed/tag.rss.eex @@ -5,7 +5,7 @@      <title>#<%= @tag %></title>      <description>These are public toots tagged with #<%= @tag %>. You can interact with them if you have an account anywhere in the fediverse.</description> -    <link><%= '#{tag_feed_url(@conn, :feed, @tag)}.rss' %></link> +    <link><%= '#{Routes.tag_feed_url(@conn, :feed, @tag)}.rss' %></link>      <webfeeds:logo><%= feed_logo() %></webfeeds:logo>      <webfeeds:accentColor>2b90d9</webfeeds:accentColor>      <%= for activity <- @activities do %> diff --git a/lib/pleroma/web/templates/feed/feed/user.atom.eex b/lib/pleroma/web/templates/feed/feed/user.atom.eex index c6acd848f..5c1f0ecbc 100644 --- a/lib/pleroma/web/templates/feed/feed/user.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/user.atom.eex @@ -6,16 +6,16 @@    xmlns:poco="http://portablecontacts.net/spec/1.0"    xmlns:ostatus="http://ostatus.org/schema/1.0"> -  <id><%= user_feed_url(@conn, :feed, @user.nickname) <> ".atom" %></id> +  <id><%= Routes.user_feed_url(@conn, :feed, @user.nickname) <> ".atom" %></id>    <title><%= @user.nickname <> "'s timeline" %></title>    <updated><%= most_recent_update(@activities, @user) %></updated>    <logo><%= logo(@user) %></logo> -  <link rel="self" href="<%= '#{user_feed_url(@conn, :feed, @user.nickname)}.atom' %>" type="application/atom+xml"/> +  <link rel="self" href="<%= '#{Routes.user_feed_url(@conn, :feed, @user.nickname)}.atom' %>" type="application/atom+xml"/>    <%= render @view_module, "_author.atom", assigns %>    <%= if last_activity(@activities) do %> -    <link rel="next" href="<%= '#{user_feed_url(@conn, :feed, @user.nickname)}.atom?max_id=#{last_activity(@activities).id}' %>" type="application/atom+xml"/> +    <link rel="next" href="<%= '#{Routes.user_feed_url(@conn, :feed, @user.nickname)}.atom?max_id=#{last_activity(@activities).id}' %>" type="application/atom+xml"/>    <% end %>    <%= for activity <- @activities do %> diff --git a/lib/pleroma/web/templates/feed/feed/user.rss.eex b/lib/pleroma/web/templates/feed/feed/user.rss.eex index d69120480..6b842a085 100644 --- a/lib/pleroma/web/templates/feed/feed/user.rss.eex +++ b/lib/pleroma/web/templates/feed/feed/user.rss.eex @@ -1,16 +1,16 @@  <?xml version="1.0" encoding="UTF-8" ?>  <rss version="2.0">    <channel> -    <guid><%= user_feed_url(@conn, :feed, @user.nickname) <> ".rss" %></guid> +    <guid><%= Routes.user_feed_url(@conn, :feed, @user.nickname) <> ".rss" %></guid>      <title><%= @user.nickname <> "'s timeline" %></title>      <updated><%= most_recent_update(@activities, @user) %></updated>      <image><%= logo(@user) %></image> -    <link><%= '#{user_feed_url(@conn, :feed, @user.nickname)}.rss' %></link> +    <link><%= '#{Routes.user_feed_url(@conn, :feed, @user.nickname)}.rss' %></link>      <%= render @view_module, "_author.rss", assigns %>      <%= if last_activity(@activities) do %> -      <link rel="next"><%= '#{user_feed_url(@conn, :feed, @user.nickname)}.rss?max_id=#{last_activity(@activities).id}' %></link> +      <link rel="next"><%= '#{Routes.user_feed_url(@conn, :feed, @user.nickname)}.rss?max_id=#{last_activity(@activities).id}' %></link>      <% end %>      <%= for activity <- @activities do %> diff --git a/lib/pleroma/web/templates/masto_fe/index.html.eex b/lib/pleroma/web/templates/masto_fe/index.html.eex index c330960fa..6f2b98957 100644 --- a/lib/pleroma/web/templates/masto_fe/index.html.eex +++ b/lib/pleroma/web/templates/masto_fe/index.html.eex @@ -7,7 +7,7 @@  <%= Config.get([:instance, :name]) %>  </title>  <link rel="icon" type="image/png" href="/favicon.png"/> -<link rel="manifest" type="applicaton/manifest+json" href="<%= masto_fe_path(Pleroma.Web.Endpoint, :manifest) %>" /> +<link rel="manifest" type="applicaton/manifest+json" href="<%= Routes.masto_fe_path(Pleroma.Web.Endpoint, :manifest) %>" />  <meta name="theme-color" content="<%= Config.get([:manifest, :theme_color]) %>" /> diff --git a/lib/pleroma/web/templates/o_auth/mfa/recovery.html.eex b/lib/pleroma/web/templates/o_auth/mfa/recovery.html.eex index 5ab59b57b..b9daa8d8b 100644 --- a/lib/pleroma/web/templates/o_auth/mfa/recovery.html.eex +++ b/lib/pleroma/web/templates/o_auth/mfa/recovery.html.eex @@ -7,7 +7,7 @@  <h2>Two-factor recovery</h2> -<%= form_for @conn, mfa_verify_path(@conn, :verify), [as: "mfa"], fn f -> %> +<%= form_for @conn, Routes.mfa_verify_path(@conn, :verify), [as: "mfa"], fn f -> %>  <div class="input">    <%= label f, :code, "Recovery code" %>    <%= text_input f, :code, [autocomplete: false, autocorrect: "off", autocapitalize: "off", autofocus: true, spellcheck: false] %> @@ -19,6 +19,6 @@  <%= submit "Verify" %>  <% end %> -<a href="<%= mfa_path(@conn, :show, %{challenge_type: "totp", mfa_token: @mfa_token, state: @state, redirect_uri: @redirect_uri}) %>"> +<a href="<%= Routes.mfa_path(@conn, :show, %{challenge_type: "totp", mfa_token: @mfa_token, state: @state, redirect_uri: @redirect_uri}) %>">    Enter a two-factor code  </a> diff --git a/lib/pleroma/web/templates/o_auth/mfa/totp.html.eex b/lib/pleroma/web/templates/o_auth/mfa/totp.html.eex index af85777eb..29ea7c5fb 100644 --- a/lib/pleroma/web/templates/o_auth/mfa/totp.html.eex +++ b/lib/pleroma/web/templates/o_auth/mfa/totp.html.eex @@ -7,7 +7,7 @@  <h2>Two-factor authentication</h2> -<%= form_for @conn, mfa_verify_path(@conn, :verify), [as: "mfa"], fn f -> %> +<%= form_for @conn, Routes.mfa_verify_path(@conn, :verify), [as: "mfa"], fn f -> %>  <div class="input">    <%= label f, :code, "Authentication code" %>    <%= text_input f, :code, [autocomplete: false, autocorrect: "off", autocapitalize: "off", autofocus: true, pattern: "[0-9]*", spellcheck: false] %> @@ -19,6 +19,6 @@  <%= submit "Verify" %>  <% end %> -<a href="<%= mfa_path(@conn, :show, %{challenge_type: "recovery", mfa_token: @mfa_token, state: @state, redirect_uri: @redirect_uri}) %>"> +<a href="<%= Routes.mfa_path(@conn, :show, %{challenge_type: "recovery", mfa_token: @mfa_token, state: @state, redirect_uri: @redirect_uri}) %>">    Enter a two-factor recovery code  </a> diff --git a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex index 4a0718851..dc4521a62 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex @@ -1,6 +1,6 @@  <h2>Sign in with external provider</h2> -<%= form_for @conn, o_auth_path(@conn, :prepare_request), [as: "authorization", method: "get"], fn f -> %> +<%= form_for @conn, Routes.o_auth_path(@conn, :prepare_request), [as: "authorization", method: "get"], fn f -> %>    <div style="display: none">      <%= render @view_module, "_scopes.html", Map.merge(assigns, %{form: f}) %>    </div> diff --git a/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex index facedc8db..99f900fb7 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex @@ -8,7 +8,7 @@  <h2>Registration Details</h2>  <p>If you'd like to register a new account, please provide the details below.</p> -<%= form_for @conn, o_auth_path(@conn, :register), [as: "authorization"], fn f -> %> +<%= form_for @conn, Routes.o_auth_path(@conn, :register), [as: "authorization"], fn f -> %>  <div class="input">    <%= label f, :nickname, "Nickname" %> diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex index 1a85818ec..2846ec7e7 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex @@ -5,7 +5,7 @@  <p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>  <% end %> -<%= form_for @conn, o_auth_path(@conn, :authorize), [as: "authorization"], fn f -> %> +<%= form_for @conn, Routes.o_auth_path(@conn, :authorize), [as: "authorization"], fn f -> %>  <%= if @user do %>    <div class="account-header"> diff --git a/lib/pleroma/web/templates/twitter_api/password/reset.html.eex b/lib/pleroma/web/templates/twitter_api/password/reset.html.eex index 7d3ef6b0d..fbcacdc14 100644 --- a/lib/pleroma/web/templates/twitter_api/password/reset.html.eex +++ b/lib/pleroma/web/templates/twitter_api/password/reset.html.eex @@ -1,5 +1,5 @@  <h2>Password Reset for <%= @user.nickname %></h2> -<%= form_for @conn, reset_password_path(@conn, :do_reset), [as: "data"], fn f -> %> +<%= form_for @conn, Routes.reset_password_path(@conn, :do_reset), [as: "data"], fn f -> %>    <div class="form-row">      <%= label f, :password, "Password" %>      <%= password_input f, :password %> diff --git a/lib/pleroma/web/templates/twitter_api/password/reset_failed.html.eex b/lib/pleroma/web/templates/twitter_api/password/reset_failed.html.eex index df037c01e..4ed4ac8bc 100644 --- a/lib/pleroma/web/templates/twitter_api/password/reset_failed.html.eex +++ b/lib/pleroma/web/templates/twitter_api/password/reset_failed.html.eex @@ -1,2 +1,2 @@  <h2>Password reset failed</h2> -<h3><a href="<%= Pleroma.Web.base_url() %>">Homepage</a></h3> +<h3><a href="<%= Pleroma.Web.Endpoint.url() %>">Homepage</a></h3> diff --git a/lib/pleroma/web/templates/twitter_api/password/reset_success.html.eex b/lib/pleroma/web/templates/twitter_api/password/reset_success.html.eex index f30ba3274..086d4e08b 100644 --- a/lib/pleroma/web/templates/twitter_api/password/reset_success.html.eex +++ b/lib/pleroma/web/templates/twitter_api/password/reset_success.html.eex @@ -1,2 +1,2 @@  <h2>Password changed!</h2> -<h3><a href="<%= Pleroma.Web.base_url() %>">Homepage</a></h3> +<h3><a href="<%= Pleroma.Web.Endpoint.url() %>">Homepage</a></h3> diff --git a/lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex b/lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex index 5ba192cd7..a7be53091 100644 --- a/lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex +++ b/lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex @@ -4,7 +4,7 @@      <h2>Remote follow</h2>      <img height="128" width="128" src="<%= avatar_url(@followee) %>">      <p><%= @followee.nickname %></p> -    <%= form_for @conn, remote_follow_path(@conn, :do_follow), [as: "user"], fn f -> %> +    <%= form_for @conn, Routes.remote_follow_path(@conn, :do_follow), [as: "user"], fn f -> %>      <%= hidden_input f, :id, value: @followee.id %>      <%= submit "Authorize" %>      <% end %> diff --git a/lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex b/lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex index df44988ee..a8026fa9d 100644 --- a/lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex +++ b/lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex @@ -4,7 +4,7 @@  <h2>Log in to follow</h2>  <p><%= @followee.nickname %></p>  <img height="128" width="128" src="<%= avatar_url(@followee) %>"> -<%= form_for @conn, remote_follow_path(@conn, :do_follow), [as: "authorization"], fn f -> %> +<%= form_for @conn, Routes.remote_follow_path(@conn, :do_follow), [as: "authorization"], fn f -> %>  <%= text_input f, :name, placeholder: "Username", required: true %>  <br>  <%= password_input f, :password, placeholder: "Password", required: true %> diff --git a/lib/pleroma/web/templates/twitter_api/remote_follow/follow_mfa.html.eex b/lib/pleroma/web/templates/twitter_api/remote_follow/follow_mfa.html.eex index adc3a3e3d..a54ed83b5 100644 --- a/lib/pleroma/web/templates/twitter_api/remote_follow/follow_mfa.html.eex +++ b/lib/pleroma/web/templates/twitter_api/remote_follow/follow_mfa.html.eex @@ -4,7 +4,7 @@  <h2>Two-factor authentication</h2>  <p><%= @followee.nickname %></p>  <img height="128" width="128" src="<%= avatar_url(@followee) %>"> -<%= form_for @conn, remote_follow_path(@conn, :do_follow), [as: "mfa"], fn f -> %> +<%= form_for @conn, Routes.remote_follow_path(@conn, :do_follow), [as: "mfa"], fn f -> %>  <%= text_input f, :code, placeholder: "Authentication code", required: true %>  <br>  <%= hidden_input f, :id, value: @followee.id %> diff --git a/lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex b/lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex index f60accebf..a6b313d8a 100644 --- a/lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex +++ b/lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex @@ -2,7 +2,7 @@    <h2>Error: <%= @error %></h2>  <% else %>    <h2>Remotely follow <%= @nickname %></h2> -  <%= form_for @conn, util_path(@conn, :remote_subscribe), [as: "user"], fn f -> %> +  <%= form_for @conn, Routes.util_path(@conn, :remote_subscribe), [as: "user"], fn f -> %>    <%= hidden_input f, :nickname, value: @nickname %>    <%= text_input f, :profile, placeholder: "Your account ID, e.g. lain@quitter.se" %>    <%= submit "Follow" %> diff --git a/lib/pleroma/web/twitter_api/controller.ex b/lib/pleroma/web/twitter_api/controller.ex index 077bfa70d..e32713311 100644 --- a/lib/pleroma/web/twitter_api/controller.ex +++ b/lib/pleroma/web/twitter_api/controller.ex @@ -5,7 +5,6 @@  defmodule Pleroma.Web.TwitterAPI.Controller do    use Pleroma.Web, :controller -  alias Pleroma.Notification    alias Pleroma.User    alias Pleroma.Web.OAuth.Token    alias Pleroma.Web.Plugs.EnsurePublicOrAuthenticatedPlug @@ -15,11 +14,6 @@ defmodule Pleroma.Web.TwitterAPI.Controller do    require Logger    plug( -    OAuthScopesPlug, -    %{scopes: ["write:notifications"]} when action == :mark_notifications_as_read -  ) - -  plug(      :skip_plug,      [OAuthScopesPlug, EnsurePublicOrAuthenticatedPlug] when action == :confirm_email    ) @@ -67,31 +61,4 @@ defmodule Pleroma.Web.TwitterAPI.Controller do      |> put_resp_content_type("application/json")      |> send_resp(status, json)    end - -  def mark_notifications_as_read( -        %{assigns: %{user: user}} = conn, -        %{"latest_id" => latest_id} = params -      ) do -    Notification.set_read_up_to(user, latest_id) - -    notifications = Notification.for_user(user, params) - -    conn -    # XXX: This is a hack because pleroma-fe still uses that API. -    |> put_view(Pleroma.Web.MastodonAPI.NotificationView) -    |> render("index.json", %{notifications: notifications, for: user}) -  end - -  def mark_notifications_as_read(%{assigns: %{user: _user}} = conn, _) do -    bad_request_reply(conn, "You need to specify latest_id") -  end - -  defp bad_request_reply(conn, error_message) do -    json = error_json(conn, error_message) -    json_reply(conn, 400, json) -  end - -  defp error_json(conn, error_message) do -    %{"error" => error_message, "request" => conn.request_path} |> Jason.encode!() -  end  end diff --git a/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex index 6ca02fbd7..9843cc362 100644 --- a/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex @@ -38,7 +38,7 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do    defp follow_status(conn, _user, acct) do      with {:ok, object} <- Fetcher.fetch_object_from_id(acct),           %Activity{id: activity_id} <- Activity.get_create_by_object_ap_id(object.data["id"]) do -      redirect(conn, to: o_status_path(conn, :notice, activity_id)) +      redirect(conn, to: Routes.o_status_path(conn, :notice, activity_id))      else        error ->          handle_follow_error(conn, error) diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 940a645bb..a2e69666e 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -10,12 +10,12 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do    alias Pleroma.Config    alias Pleroma.Emoji    alias Pleroma.Healthcheck -  alias Pleroma.Notification    alias Pleroma.User    alias Pleroma.Web.CommonAPI    alias Pleroma.Web.Plugs.OAuthScopesPlug    alias Pleroma.Web.WebFinger +  plug(Pleroma.Web.ApiSpec.CastAndValidate when action != :remote_subscribe)    plug(Pleroma.Web.Plugs.FederatingPlug when action == :remote_subscribe)    plug( @@ -30,7 +30,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do           ]    ) -  plug(OAuthScopesPlug, %{scopes: ["write:notifications"]} when action == :notifications_read) +  defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.TwitterUtilOperation    def remote_subscribe(conn, %{"nickname" => nick, "profile" => _}) do      with %User{} = user <- User.get_cached_by_nickname(nick), @@ -62,17 +62,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do      end    end -  def notifications_read(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do -    with {:ok, _} <- Notification.read_one(user, notification_id) do -      json(conn, %{status: "success"}) -    else -      {:error, message} -> -        conn -        |> put_resp_content_type("application/json") -        |> send_resp(403, Jason.encode!(%{"error" => message})) -    end -  end -    def frontend_configurations(conn, _params) do      render(conn, "frontend_configurations.json")    end @@ -92,13 +81,17 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do      end    end -  def change_password(%{assigns: %{user: user}} = conn, params) do -    case CommonAPI.Utils.confirm_current_password(user, params["password"]) do +  def change_password(%{assigns: %{user: user}} = conn, %{ +        password: password, +        new_password: new_password, +        new_password_confirmation: new_password_confirmation +      }) do +    case CommonAPI.Utils.confirm_current_password(user, password) do        {:ok, user} ->          with {:ok, _user} <-                 User.reset_password(user, %{ -                 password: params["new_password"], -                 password_confirmation: params["new_password_confirmation"] +                 password: new_password, +                 password_confirmation: new_password_confirmation                 }) do            json(conn, %{status: "success"})          else @@ -115,10 +108,10 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do      end    end -  def change_email(%{assigns: %{user: user}} = conn, params) do -    case CommonAPI.Utils.confirm_current_password(user, params["password"]) do +  def change_email(%{assigns: %{user: user}} = conn, %{password: password, email: email}) do +    case CommonAPI.Utils.confirm_current_password(user, password) do        {:ok, user} -> -        with {:ok, _user} <- User.change_email(user, params["email"]) do +        with {:ok, _user} <- User.change_email(user, email) do            json(conn, %{status: "success"})          else            {:error, changeset} -> @@ -135,7 +128,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do    end    def delete_account(%{assigns: %{user: user}} = conn, params) do -    password = params["password"] || "" +    password = params[:password] || ""      case CommonAPI.Utils.confirm_current_password(user, password) do        {:ok, user} -> @@ -148,7 +141,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do    end    def disable_account(%{assigns: %{user: user}} = conn, params) do -    case CommonAPI.Utils.confirm_current_password(user, params["password"]) do +    case CommonAPI.Utils.confirm_current_password(user, params[:password]) do        {:ok, user} ->          User.set_activation_async(user, false)          json(conn, %{status: "success"}) diff --git a/lib/pleroma/web/twitter_api/views/util_view.ex b/lib/pleroma/web/twitter_api/views/util_view.ex index 9b13c09b3..87cb79dd7 100644 --- a/lib/pleroma/web/twitter_api/views/util_view.ex +++ b/lib/pleroma/web/twitter_api/views/util_view.ex @@ -6,14 +6,14 @@ defmodule Pleroma.Web.TwitterAPI.UtilView do    use Pleroma.Web, :view    import Phoenix.HTML.Form    alias Pleroma.Config -  alias Pleroma.Web +  alias Pleroma.Web.Endpoint    def status_net_config(instance) do      """      <config>      <site>      <name>#{Keyword.get(instance, :name)}</name> -    <site>#{Web.base_url()}</site> +    <site>#{Endpoint.url()}</site>      <textlimit>#{Keyword.get(instance, :limit)}</textlimit>      <closed>#{!Keyword.get(instance, :registrations_open)}</closed>      </site> diff --git a/lib/pleroma/web/views/masto_fe_view.ex b/lib/pleroma/web/views/masto_fe_view.ex index b9055cb7f..63a9c8179 100644 --- a/lib/pleroma/web/views/masto_fe_view.ex +++ b/lib/pleroma/web/views/masto_fe_view.ex @@ -78,8 +78,8 @@ defmodule Pleroma.Web.MastoFEView do        theme_color: Config.get([:manifest, :theme_color]),        background_color: Config.get([:manifest, :background_color]),        display: "standalone", -      scope: Pleroma.Web.base_url(), -      start_url: masto_fe_path(Pleroma.Web.Endpoint, :index, ["getting-started"]), +      scope: Pleroma.Web.Endpoint.url(), +      start_url: Routes.masto_fe_path(Pleroma.Web.Endpoint, :index, ["getting-started"]),        categories: [          "social"        ], diff --git a/lib/pleroma/web/web_finger.ex b/lib/pleroma/web/web_finger.ex index 21b10e654..938fc09e3 100644 --- a/lib/pleroma/web/web_finger.ex +++ b/lib/pleroma/web/web_finger.ex @@ -5,7 +5,7 @@  defmodule Pleroma.Web.WebFinger do    alias Pleroma.HTTP    alias Pleroma.User -  alias Pleroma.Web +  alias Pleroma.Web.Endpoint    alias Pleroma.Web.Federator.Publisher    alias Pleroma.Web.XML    alias Pleroma.XmlBuilder @@ -13,7 +13,7 @@ defmodule Pleroma.Web.WebFinger do    require Logger    def host_meta do -    base_url = Web.base_url() +    base_url = Endpoint.url()      {        :XRD,  | 
