diff options
Diffstat (limited to 'lib/pleroma/web')
-rw-r--r-- | lib/pleroma/web/activity_pub/activity_pub.ex | 60 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/mrf.ex | 7 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/mrf/activity_expiration_policy.ex | 43 | ||||
-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/common_api/activity_draft.ex | 9 | ||||
-rw-r--r-- | lib/pleroma/web/common_api/common_api.ex | 12 | ||||
-rw-r--r-- | lib/pleroma/web/controller_helper.ex | 49 | ||||
-rw-r--r-- | lib/pleroma/web/mastodon_api/controllers/search_controller.ex | 1 | ||||
-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 |
16 files changed, 175 insertions, 138 deletions
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index aeec4beae..c9dc6135c 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do alias Pleroma.Activity alias Pleroma.Activity.Ir.Topics + alias Pleroma.ActivityExpiration alias Pleroma.Config alias Pleroma.Constants alias Pleroma.Conversation @@ -31,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", []) @@ -146,12 +128,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do {:containment, :ok} <- {:containment, Containment.contain_child(map)}, {:ok, map, object} <- insert_full_object(map) do {:ok, activity} = - Repo.insert(%Activity{ + %Activity{ data: map, local: local, actor: map["actor"], recipients: recipients - }) + } + |> Repo.insert() + |> maybe_create_activity_expiration() # Splice in the child object if we have one. activity = Maps.put_if_present(activity, :object, object) @@ -189,6 +173,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do stream_out_participations(participations) end + defp maybe_create_activity_expiration({:ok, %{data: %{"expires_at" => expires_at}} = activity}) do + with {:ok, _} <- ActivityExpiration.create(activity, expires_at) do + {:ok, activity} + end + end + + defp maybe_create_activity_expiration(result), do: result + defp create_or_bump_conversation(activity, actor) do with {:ok, conversation} <- Conversation.create_or_bump_for(activity), %User{} = user <- User.get_cached_by_ap_id(actor) do @@ -710,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 @@ -1133,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) @@ -1159,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.ex b/lib/pleroma/web/activity_pub/mrf.ex index a0b3af432..5a4a76085 100644 --- a/lib/pleroma/web/activity_pub/mrf.ex +++ b/lib/pleroma/web/activity_pub/mrf.ex @@ -8,11 +8,8 @@ defmodule Pleroma.Web.ActivityPub.MRF do def filter(policies, %{} = object) do policies |> Enum.reduce({:ok, object}, fn - policy, {:ok, object} -> - policy.filter(object) - - _, error -> - error + policy, {:ok, object} -> policy.filter(object) + _, error -> error end) end diff --git a/lib/pleroma/web/activity_pub/mrf/activity_expiration_policy.ex b/lib/pleroma/web/activity_pub/mrf/activity_expiration_policy.ex new file mode 100644 index 000000000..8e47f1e02 --- /dev/null +++ b/lib/pleroma/web/activity_pub/mrf/activity_expiration_policy.ex @@ -0,0 +1,43 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy do + @moduledoc "Adds expiration to all local Create activities" + @behaviour Pleroma.Web.ActivityPub.MRF + + @impl true + def filter(activity) do + activity = + if note?(activity) and local?(activity) do + maybe_add_expiration(activity) + else + activity + end + + {:ok, activity} + end + + @impl true + def describe, do: {:ok, %{}} + + defp local?(%{"id" => id}) do + String.starts_with?(id, Pleroma.Web.Endpoint.url()) + end + + defp note?(activity) do + match?(%{"type" => "Create", "object" => %{"type" => "Note"}}, activity) + end + + defp maybe_add_expiration(activity) do + days = Pleroma.Config.get([:mrf_activity_expiration, :days], 365) + expires_at = NaiveDateTime.utc_now() |> Timex.shift(days: days) + + with %{"expires_at" => existing_expires_at} <- activity, + :lt <- NaiveDateTime.compare(existing_expires_at, expires_at) do + activity + else + _ -> Map.put(activity, "expires_at", expires_at) + end + end +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/common_api/activity_draft.ex b/lib/pleroma/web/common_api/activity_draft.ex index 3f1a50b96..9bcb9f587 100644 --- a/lib/pleroma/web/common_api/activity_draft.ex +++ b/lib/pleroma/web/common_api/activity_draft.ex @@ -197,6 +197,13 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do defp changes(draft) do direct? = draft.visibility == "direct" + additional = %{"cc" => draft.cc, "directMessage" => direct?} + + additional = + case draft.expires_at do + %NaiveDateTime{} = expires_at -> Map.put(additional, "expires_at", expires_at) + _ -> additional + end changes = %{ @@ -204,7 +211,7 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do actor: draft.user, context: draft.context, object: draft.object, - additional: %{"cc" => draft.cc, "directMessage" => direct?} + additional: additional } |> Utils.maybe_add_list_data(draft.user, draft.visibility) diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 5a194910d..04e081a8e 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -423,20 +423,10 @@ defmodule Pleroma.Web.CommonAPI do def post(user, %{status: _} = data) do with {:ok, draft} <- Pleroma.Web.CommonAPI.ActivityDraft.create(user, data) do - draft.changes - |> ActivityPub.create(draft.preview?) - |> maybe_create_activity_expiration(draft.expires_at) + ActivityPub.create(draft.changes, draft.preview?) end end - defp maybe_create_activity_expiration({:ok, activity}, %NaiveDateTime{} = expires_at) do - with {:ok, _} <- ActivityExpiration.create(activity, expires_at) do - {:ok, activity} - end - end - - defp maybe_create_activity_expiration(result, _), do: result - def pin(id, %{ap_id: user_ap_id} = user) do with %Activity{ actor: ^user_ap_id, 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/search_controller.ex b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex index 46bcf4228..3be0ca095 100644 --- a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex @@ -152,6 +152,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do defp preprocess_uri_query(query) do if query =~ ~r/https?:\/\// do query + |> String.trim_trailing("/") |> URI.parse() |> Map.get(:path) |> String.split("/") 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 40980def8..d9b5068b1 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 ae0f36702..2762b5902 100644 --- a/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex +++ b/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex @@ -29,19 +29,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 8f32bf91b..db8ccf15d 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 {:ok, 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 |