diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/pleroma/activity.ex | 4 | ||||
| -rw-r--r-- | lib/pleroma/config/deprecation_warnings.ex | 25 | ||||
| -rw-r--r-- | lib/pleroma/notification.ex | 19 | ||||
| -rw-r--r-- | lib/pleroma/user.ex | 8 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/activity_pub.ex | 45 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/mrf/user_allow_list_policy.ex | 2 | ||||
| -rw-r--r-- | lib/pleroma/web/api_spec/operations/status_operation.ex | 3 | ||||
| -rw-r--r-- | lib/pleroma/web/controller_helper.ex | 49 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex | 1 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/views/notification_view.ex | 68 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/views/status_view.ex | 14 | ||||
| -rw-r--r-- | lib/pleroma/web/rich_media/helpers.ex | 6 | ||||
| -rw-r--r-- | lib/pleroma/web/rich_media/parser.ex | 12 | ||||
| -rw-r--r-- | lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex | 8 | ||||
| -rw-r--r-- | lib/pleroma/web/rich_media/parsers/oembed_parser.ex | 18 | 
15 files changed, 160 insertions, 122 deletions
| diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index da1be20b3..c3cea8d2a 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -31,6 +31,10 @@ defmodule Pleroma.Activity do      field(:recipients, {:array, :string}, default: [])      field(:thread_muted?, :boolean, virtual: true) +    # A field that can be used if you need to join some kind of other +    # id to order / paginate this field by +    field(:pagination_id, :string, virtual: true) +      # This is a fake relation,      # do not use outside of with_preloaded_user_actor/with_joined_user_actor      has_one(:user_actor, User, on_delete: :nothing, foreign_key: :id) diff --git a/lib/pleroma/config/deprecation_warnings.ex b/lib/pleroma/config/deprecation_warnings.ex index c39a8984b..b68ded01f 100644 --- a/lib/pleroma/config/deprecation_warnings.ex +++ b/lib/pleroma/config/deprecation_warnings.ex @@ -4,9 +4,10 @@  defmodule Pleroma.Config.DeprecationWarnings do    require Logger +  alias Pleroma.Config    def check_hellthread_threshold do -    if Pleroma.Config.get([:mrf_hellthread, :threshold]) do +    if Config.get([:mrf_hellthread, :threshold]) do        Logger.warn("""        !!!DEPRECATION WARNING!!!        You are using the old configuration mechanism for the hellthread filter. Please check config.md. @@ -14,7 +15,29 @@ defmodule Pleroma.Config.DeprecationWarnings do      end    end +  def mrf_user_allowlist do +    config = Config.get(:mrf_user_allowlist) + +    if config && Enum.any?(config, fn {k, _} -> is_atom(k) end) do +      rewritten = +        Enum.reduce(Config.get(:mrf_user_allowlist), Map.new(), fn {k, v}, acc -> +          Map.put(acc, to_string(k), v) +        end) + +      Config.put(:mrf_user_allowlist, rewritten) + +      Logger.error(""" +      !!!DEPRECATION WARNING!!! +      As of Pleroma 2.0.7, the `mrf_user_allowlist` setting changed of format. +      Pleroma 2.1 will remove support for the old format. Please change your configuration to match this: + +      config :pleroma, :mrf_user_allowlist, #{inspect(rewritten, pretty: true)} +      """) +    end +  end +    def warn do      check_hellthread_threshold() +    mrf_user_allowlist()    end  end diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 3386a1933..9ee9606be 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -166,8 +166,16 @@ defmodule Pleroma.Notification do        query        |> join(:left, [n, a], mutated_activity in Pleroma.Activity,          on: -          fragment("?->>'context'", a.data) == -            fragment("?->>'context'", mutated_activity.data) and +          fragment( +            "COALESCE((?->'object')->>'id', ?->>'object')", +            a.data, +            a.data +          ) == +            fragment( +              "COALESCE((?->'object')->>'id', ?->>'object')", +              mutated_activity.data, +              mutated_activity.data +            ) and              fragment("(?->>'type' = 'Like' or ?->>'type' = 'Announce')", a.data, a.data) and              fragment("?->>'type'", mutated_activity.data) == "Create",          as: :mutated_activity @@ -541,6 +549,7 @@ defmodule Pleroma.Notification do    def skip?(%Activity{} = activity, %User{} = user) do      [        :self, +      :invisible,        :followers,        :follows,        :non_followers, @@ -557,6 +566,12 @@ defmodule Pleroma.Notification do      activity.data["actor"] == user.ap_id    end +  def skip?(:invisible, %Activity{} = activity, _) do +    actor = activity.data["actor"] +    user = User.get_cached_by_ap_id(actor) +    User.invisible?(user) +  end +    def skip?(          :followers,          %Activity{} = activity, diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index c5c74d132..52ac9052b 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1488,6 +1488,7 @@ defmodule Pleroma.User do      end)      delete_user_activities(user) +    delete_notifications_from_user_activities(user)      delete_outgoing_pending_follow_requests(user) @@ -1576,6 +1577,13 @@ defmodule Pleroma.User do      })    end +  def delete_notifications_from_user_activities(%User{ap_id: ap_id}) do +    Notification +    |> join(:inner, [n], activity in assoc(n, :activity)) +    |> where([n, a], fragment("? = ?", a.actor, ^ap_id)) +    |> Repo.delete_all() +  end +    def delete_user_activities(%User{ap_id: ap_id} = user) do      ap_id      |> Activity.Queries.by_actor() diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index a5f8ba40a..c9dc6135c 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -32,25 +32,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do    require Logger    require Pleroma.Constants -  # For Announce activities, we filter the recipients based on following status for any actors -  # that match actual users.  See issue #164 for more information about why this is necessary. -  defp get_recipients(%{"type" => "Announce"} = data) do -    to = Map.get(data, "to", []) -    cc = Map.get(data, "cc", []) -    bcc = Map.get(data, "bcc", []) -    actor = User.get_cached_by_ap_id(data["actor"]) - -    recipients = -      Enum.filter(Enum.concat([to, cc, bcc]), fn recipient -> -        case User.get_cached_by_ap_id(recipient) do -          nil -> true -          user -> User.following?(user, actor) -        end -      end) - -    {recipients, to, cc} -  end -    defp get_recipients(%{"type" => "Create"} = data) do      to = Map.get(data, "to", [])      cc = Map.get(data, "cc", []) @@ -721,6 +702,26 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do      end    end +  defp restrict_announce_object_actor(_query, %{announce_filtering_user: _, skip_preload: true}) do +    raise "Can't use the child object without preloading!" +  end + +  defp restrict_announce_object_actor(query, %{announce_filtering_user: %{ap_id: actor}}) do +    from( +      [activity, object] in query, +      where: +        fragment( +          "?->>'type' != ? or ?->>'actor' != ?", +          activity.data, +          "Announce", +          object.data, +          ^actor +        ) +    ) +  end + +  defp restrict_announce_object_actor(query, _), do: query +    defp restrict_since(query, %{since_id: ""}), do: query    defp restrict_since(query, %{since_id: since_id}) do @@ -1144,6 +1145,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do      |> restrict_pinned(opts)      |> restrict_muted_reblogs(restrict_muted_reblogs_opts)      |> restrict_instance(opts) +    |> restrict_announce_object_actor(opts)      |> Activity.restrict_deactivated_users()      |> exclude_poll_votes(opts)      |> exclude_chat_messages(opts) @@ -1170,12 +1172,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do      |> Activity.Queries.by_type("Like")      |> Activity.with_joined_object()      |> Object.with_joined_activity() -    |> select([_like, object, activity], %{activity | object: object}) +    |> select([like, object, activity], %{activity | object: object, pagination_id: like.id})      |> order_by([like, _, _], desc_nulls_last: like.id)      |> Pagination.fetch_paginated(        Map.merge(params, %{skip_order: true}), -      pagination, -      :object_activity +      pagination      )    end diff --git a/lib/pleroma/web/activity_pub/mrf/user_allow_list_policy.ex b/lib/pleroma/web/activity_pub/mrf/user_allow_list_policy.ex index a927a4ed8..651aed70f 100644 --- a/lib/pleroma/web/activity_pub/mrf/user_allow_list_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/user_allow_list_policy.ex @@ -24,7 +24,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy do      allow_list =        Config.get( -        [:mrf_user_allowlist, String.to_atom(actor_info.host)], +        [:mrf_user_allowlist, actor_info.host],          []        ) diff --git a/lib/pleroma/web/api_spec/operations/status_operation.ex b/lib/pleroma/web/api_spec/operations/status_operation.ex index ca9db01e5..0b7fad793 100644 --- a/lib/pleroma/web/api_spec/operations/status_operation.ex +++ b/lib/pleroma/web/api_spec/operations/status_operation.ex @@ -333,7 +333,8 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do      %Operation{        tags: ["Statuses"],        summary: "Favourited statuses", -      description: "Statuses the user has favourited", +      description: +        "Statuses the user has favourited. Please note that you have to use the link headers to paginate this. You can not build the query parameters yourself.",        operationId: "StatusController.favourites",        parameters: pagination_params(),        security: [%{"oAuth" => ["read:favourites"]}], diff --git a/lib/pleroma/web/controller_helper.ex b/lib/pleroma/web/controller_helper.ex index 5d67d75b5..69946fb81 100644 --- a/lib/pleroma/web/controller_helper.ex +++ b/lib/pleroma/web/controller_helper.ex @@ -57,35 +57,36 @@ defmodule Pleroma.Web.ControllerHelper do      end    end +  @id_keys Pagination.page_keys() -- ["limit", "order"] +  defp build_pagination_fields(conn, min_id, max_id, extra_params) do +    params = +      conn.params +      |> Map.drop(Map.keys(conn.path_params)) +      |> Map.merge(extra_params) +      |> Map.drop(@id_keys) + +    %{ +      "next" => current_url(conn, Map.put(params, :max_id, max_id)), +      "prev" => current_url(conn, Map.put(params, :min_id, min_id)), +      "id" => current_url(conn) +    } +  end +    def get_pagination_fields(conn, activities, extra_params \\ %{}) do      case List.last(activities) do -      %{id: max_id} -> -        params = -          conn.params -          |> Map.drop(Map.keys(conn.path_params)) -          |> Map.merge(extra_params) -          |> Map.drop(Pagination.page_keys() -- ["limit", "order"]) +      %{pagination_id: max_id} when not is_nil(max_id) -> +        %{pagination_id: min_id} = +          activities +          |> List.first() + +        build_pagination_fields(conn, min_id, max_id, extra_params) -        min_id = +      %{id: max_id} -> +        %{id: min_id} =            activities            |> List.first() -          |> Map.get(:id) - -        fields = %{ -          "next" => current_url(conn, Map.put(params, :max_id, max_id)), -          "prev" => current_url(conn, Map.put(params, :min_id, min_id)) -        } - -        #  Generating an `id` without already present pagination keys would -        # need a query-restriction with an `q.id >= ^id` or `q.id <= ^id` -        # instead of the `q.id > ^min_id` and `q.id < ^max_id`. -        #  This is because we only have ids present inside of the page, while -        # `min_id`, `since_id` and `max_id` requires to know one outside of it. -        if Map.take(conn.params, Pagination.page_keys() -- ["limit", "order"]) != [] do -          Map.put(fields, "id", current_url(conn, conn.params)) -        else -          fields -        end + +        build_pagination_fields(conn, min_id, max_id, extra_params)        _ ->          %{} diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex index 9270ca267..4bdd46d7e 100644 --- a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex @@ -48,6 +48,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do        |> Map.put(:blocking_user, user)        |> Map.put(:muting_user, user)        |> Map.put(:reply_filtering_user, user) +      |> Map.put(:announce_filtering_user, user)        |> Map.put(:user, user)      activities = diff --git a/lib/pleroma/web/mastodon_api/views/notification_view.ex b/lib/pleroma/web/mastodon_api/views/notification_view.ex index b11578623..3865be280 100644 --- a/lib/pleroma/web/mastodon_api/views/notification_view.ex +++ b/lib/pleroma/web/mastodon_api/views/notification_view.ex @@ -46,6 +46,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do              activities              |> Enum.filter(&(&1.data["type"] == "Move"))              |> Enum.map(&User.get_cached_by_ap_id(&1.data["target"])) +            |> Enum.filter(& &1)            actors =              activities @@ -84,50 +85,45 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do      # Note: :relationships contain user mutes (needed for :muted flag in :status)      status_render_opts = %{relationships: opts[:relationships]} -    with %{id: _} = account <- -           AccountView.render( -             "show.json", -             %{user: actor, for: reading_user} -           ) do -      response = %{ -        id: to_string(notification.id), -        type: notification.type, -        created_at: CommonAPI.Utils.to_masto_date(notification.inserted_at), -        account: account, -        pleroma: %{ -          is_seen: notification.seen -        } +    account = +      AccountView.render( +        "show.json", +        %{user: actor, for: reading_user} +      ) + +    response = %{ +      id: to_string(notification.id), +      type: notification.type, +      created_at: CommonAPI.Utils.to_masto_date(notification.inserted_at), +      account: account, +      pleroma: %{ +        is_seen: notification.seen        } +    } -      case notification.type do -        "mention" -> -          put_status(response, activity, reading_user, status_render_opts) +    case notification.type do +      "mention" -> +        put_status(response, activity, reading_user, status_render_opts) -        "favourite" -> -          put_status(response, parent_activity_fn.(), reading_user, status_render_opts) +      "favourite" -> +        put_status(response, parent_activity_fn.(), reading_user, status_render_opts) -        "reblog" -> -          put_status(response, parent_activity_fn.(), reading_user, status_render_opts) +      "reblog" -> +        put_status(response, parent_activity_fn.(), reading_user, status_render_opts) -        "move" -> -          put_target(response, activity, reading_user, %{}) +      "move" -> +        put_target(response, activity, reading_user, %{}) -        "pleroma:emoji_reaction" -> -          response -          |> put_status(parent_activity_fn.(), reading_user, status_render_opts) -          |> put_emoji(activity) +      "pleroma:emoji_reaction" -> +        response +        |> put_status(parent_activity_fn.(), reading_user, status_render_opts) +        |> put_emoji(activity) -        "pleroma:chat_mention" -> -          put_chat_message(response, activity, reading_user, status_render_opts) +      "pleroma:chat_mention" -> +        put_chat_message(response, activity, reading_user, status_render_opts) -        type when type in ["follow", "follow_request"] -> -          response - -        _ -> -          nil -      end -    else -      _ -> nil +      type when type in ["follow", "follow_request"] -> +        response      end    end diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 8e3715093..2c49bedb3 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -377,8 +377,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do      page_url_data = URI.parse(page_url)      page_url_data = -      if rich_media[:url] != nil do -        URI.merge(page_url_data, URI.parse(rich_media[:url])) +      if is_binary(rich_media["url"]) do +        URI.merge(page_url_data, URI.parse(rich_media["url"]))        else          page_url_data        end @@ -386,11 +386,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do      page_url = page_url_data |> to_string      image_url = -      if rich_media[:image] != nil do -        URI.merge(page_url_data, URI.parse(rich_media[:image])) +      if is_binary(rich_media["image"]) do +        URI.merge(page_url_data, URI.parse(rich_media["image"]))          |> to_string -      else -        nil        end      %{ @@ -399,8 +397,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do        provider_url: page_url_data.scheme <> "://" <> page_url_data.host,        url: page_url,        image: image_url |> MediaProxy.url(), -      title: rich_media[:title] || "", -      description: rich_media[:description] || "", +      title: rich_media["title"] || "", +      description: rich_media["description"] || "",        pleroma: %{          opengraph: rich_media        } diff --git a/lib/pleroma/web/rich_media/helpers.ex b/lib/pleroma/web/rich_media/helpers.ex index 9d3d7f978..1729141e9 100644 --- a/lib/pleroma/web/rich_media/helpers.ex +++ b/lib/pleroma/web/rich_media/helpers.ex @@ -9,7 +9,7 @@ defmodule Pleroma.Web.RichMedia.Helpers do    alias Pleroma.Object    alias Pleroma.Web.RichMedia.Parser -  @spec validate_page_url(any()) :: :ok | :error +  @spec validate_page_url(URI.t() | binary()) :: :ok | :error    defp validate_page_url(page_url) when is_binary(page_url) do      validate_tld = Application.get_env(:auto_linker, :opts)[:validate_tld] @@ -18,8 +18,8 @@ defmodule Pleroma.Web.RichMedia.Helpers do      |> parse_uri(page_url)    end -  defp validate_page_url(%URI{host: host, scheme: scheme, authority: authority}) -       when scheme == "https" and not is_nil(authority) do +  defp validate_page_url(%URI{host: host, scheme: "https", authority: authority}) +       when is_binary(authority) do      cond do        host in Config.get([:rich_media, :ignore_hosts], []) ->          :error diff --git a/lib/pleroma/web/rich_media/parser.ex b/lib/pleroma/web/rich_media/parser.ex index 78e9048f3..ef5ead2da 100644 --- a/lib/pleroma/web/rich_media/parser.ex +++ b/lib/pleroma/web/rich_media/parser.ex @@ -91,7 +91,7 @@ defmodule Pleroma.Web.RichMedia.Parser do        html        |> parse_html()        |> maybe_parse() -      |> Map.put(:url, url) +      |> Map.put("url", url)        |> clean_parsed_data()        |> check_parsed_data()      rescue @@ -111,8 +111,8 @@ defmodule Pleroma.Web.RichMedia.Parser do      end)    end -  defp check_parsed_data(%{title: title} = data) -       when is_binary(title) and byte_size(title) > 0 do +  defp check_parsed_data(%{"title" => title} = data) +       when is_binary(title) and title != "" do      {:ok, data}    end @@ -123,11 +123,7 @@ defmodule Pleroma.Web.RichMedia.Parser do    defp clean_parsed_data(data) do      data      |> Enum.reject(fn {key, val} -> -      with {:ok, _} <- Jason.encode(%{key => val}) do -        false -      else -        _ -> true -      end +      not match?({:ok, _}, Jason.encode(%{key => val}))      end)      |> Map.new()    end diff --git a/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex b/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex index c09b96eae..3d577e254 100644 --- a/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex +++ b/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex @@ -22,19 +22,19 @@ defmodule Pleroma.Web.RichMedia.Parsers.MetaTagsParser do      {_tag, attributes, _children} = html_node      data = -      Enum.into(attributes, %{}, fn {name, value} -> +      Map.new(attributes, fn {name, value} ->          {name, String.trim_leading(value, "#{prefix}:")}        end) -    %{String.to_atom(data[key_name]) => data[value_name]} +    %{data[key_name] => data[value_name]}    end -  defp maybe_put_title(%{title: _} = meta, _), do: meta +  defp maybe_put_title(%{"title" => _} = meta, _), do: meta    defp maybe_put_title(meta, html) when meta != %{} do      case get_page_title(html) do        "" -> meta -      title -> Map.put_new(meta, :title, title) +      title -> Map.put_new(meta, "title", title)      end    end diff --git a/lib/pleroma/web/rich_media/parsers/oembed_parser.ex b/lib/pleroma/web/rich_media/parsers/oembed_parser.ex index 5d87a90e9..6bdeac89c 100644 --- a/lib/pleroma/web/rich_media/parsers/oembed_parser.ex +++ b/lib/pleroma/web/rich_media/parsers/oembed_parser.ex @@ -5,7 +5,7 @@  defmodule Pleroma.Web.RichMedia.Parsers.OEmbed do    def parse(html, _data) do      with elements = [_ | _] <- get_discovery_data(html), -         {:ok, oembed_url} <- get_oembed_url(elements), +         oembed_url when is_binary(oembed_url) <- get_oembed_url(elements),           {:ok, oembed_data} <- get_oembed_data(oembed_url) do        oembed_data      else @@ -17,19 +17,13 @@ defmodule Pleroma.Web.RichMedia.Parsers.OEmbed do      html |> Floki.find("link[type='application/json+oembed']")    end -  defp get_oembed_url(nodes) do -    {"link", attributes, _children} = nodes |> hd() - -    {:ok, Enum.into(attributes, %{})["href"]} +  defp get_oembed_url([{"link", attributes, _children} | _]) do +    Enum.find_value(attributes, fn {k, v} -> if k == "href", do: v end)    end    defp get_oembed_data(url) do -    {:ok, %Tesla.Env{body: json}} = Pleroma.HTTP.get(url, [], adapter: [pool: :media]) - -    {:ok, data} = Jason.decode(json) - -    data = data |> Map.new(fn {k, v} -> {String.to_atom(k), v} end) - -    {:ok, data} +    with {:ok, %Tesla.Env{body: json}} <- Pleroma.HTTP.get(url, [], adapter: [pool: :media]) do +      Jason.decode(json) +    end    end  end | 
