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(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) + def cast(object) when is_map(object) do + case ObjectID.cast(object) do + {:ok, data} -> {:ok, [data]} + _ -> :error + end end - def cast(_) do - :error + def cast(data) when is_list(data) do + 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(data) do + {:error, data} end def dump(data) do 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/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/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/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/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/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"]) + + 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 + + def fix(data, meta) do + object = meta[:object_data] - 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 - end - - defp fix(data, meta) do 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 -# 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/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 a40d51c45..7da29b197 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 @@ -342,19 +322,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 @@ -425,10 +404,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"]), @@ -520,14 +498,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} diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index a4dc469dc..0d1a6d0f1 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -96,8 +96,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 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/test/fixtures/activitypub-client-post-activity.json b/test/fixtures/activitypub-client-post-activity.json index c985e072b..e592081bc 100644 --- a/test/fixtures/activitypub-client-post-activity.json +++ b/test/fixtures/activitypub-client-post-activity.json @@ -3,6 +3,7 @@ "type": "Create", "object": { "type": "Note", + "to": ["https://www.w3.org/ns/activitystreams#Public"], "content": "It's a note" }, "to": ["https://www.w3.org/ns/activitystreams#Public"] diff --git a/test/pleroma/activity_test.exs b/test/pleroma/activity_test.exs index 962bc7e45..4f9144f91 100644 --- a/test/pleroma/activity_test.exs +++ b/test/pleroma/activity_test.exs @@ -123,7 +123,8 @@ defmodule Pleroma.ActivityTest do "type" => "Note", "content" => "find me!", "id" => "http://mastodon.example.org/users/admin/objects/1", - "attributedTo" => "http://mastodon.example.org/users/admin" + "attributedTo" => "http://mastodon.example.org/users/admin", + "to" => ["https://www.w3.org/ns/activitystreams#Public"] }, "to" => ["https://www.w3.org/ns/activitystreams#Public"] } @@ -132,6 +133,7 @@ defmodule Pleroma.ActivityTest do {:ok, japanese_activity} = Pleroma.Web.CommonAPI.post(user, %{status: "更新情報"}) {:ok, job} = Pleroma.Web.Federator.incoming_ap_doc(params) {:ok, remote_activity} = ObanHelpers.perform(job) + remote_activity = Activity.get_by_id_with_object(remote_activity.id) %{ japanese_activity: japanese_activity, diff --git a/test/pleroma/ecto_type/activity_pub/object_validators/recipients_test.exs b/test/pleroma/ecto_type/activity_pub/object_validators/recipients_test.exs index d3a2fd13f..4cdafa898 100644 --- a/test/pleroma/ecto_type/activity_pub/object_validators/recipients_test.exs +++ b/test/pleroma/ecto_type/activity_pub/object_validators/recipients_test.exs @@ -6,10 +6,10 @@ defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.RecipientsTest do alias Pleroma.EctoType.ActivityPub.ObjectValidators.Recipients use Pleroma.DataCase, async: true - test "it asserts that all elements of the list are object ids" do + test "it only keeps elements that are valid object ids" do list = ["https://lain.com/users/lain", "invalid"] - assert :error == Recipients.cast(list) + assert {:ok, ["https://lain.com/users/lain"]} == Recipients.cast(list) end test "it works with a list" do diff --git a/test/pleroma/notification_test.exs b/test/pleroma/notification_test.exs index abf1b0410..85f895f0f 100644 --- a/test/pleroma/notification_test.exs +++ b/test/pleroma/notification_test.exs @@ -624,6 +624,8 @@ defmodule Pleroma.NotificationTest do "actor" => user.ap_id, "object" => %{ "type" => "Note", + "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(), + "to" => ["https://www.w3.org/ns/activitystreams#Public"], "content" => "message with a Mention tag, but no explicit tagging", "tag" => [ %{ @@ -655,6 +657,9 @@ defmodule Pleroma.NotificationTest do "actor" => user.ap_id, "object" => %{ "type" => "Note", + "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(), + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [other_user.ap_id], "content" => "hi everyone", "attributedTo" => user.ap_id } @@ -951,6 +956,7 @@ defmodule Pleroma.NotificationTest do "cc" => [], "object" => %{ "type" => "Note", + "id" => remote_user.ap_id <> "/objects/test", "content" => "Hello!", "tag" => [ %{ diff --git a/test/pleroma/object/fetcher_test.exs b/test/pleroma/object/fetcher_test.exs index a7ac90348..bd0a6e497 100644 --- a/test/pleroma/object/fetcher_test.exs +++ b/test/pleroma/object/fetcher_test.exs @@ -66,6 +66,14 @@ defmodule Pleroma.Object.FetcherTest do %Tesla.Env{ status: 500 } + + %{ + method: :get, + url: "https://stereophonic.space/objects/02997b83-3ea7-4b63-94af-ef3aa2d4ed17" + } -> + %Tesla.Env{ + status: 500 + } end) :ok @@ -124,8 +132,7 @@ defmodule Pleroma.Object.FetcherTest do {:ok, object} = Fetcher.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367") - assert activity = Activity.get_create_by_object_ap_id(object.data["id"]) - assert activity.data["id"] + assert _activity = Activity.get_create_by_object_ap_id(object.data["id"]) {:ok, object_again} = Fetcher.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367") diff --git a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs index c1e13c7cb..c7039d1f8 100644 --- a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs +++ b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs @@ -539,7 +539,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!() |> Map.put("actor", user.ap_id) - |> put_in(["object", "attridbutedTo"], user.ap_id) + |> put_in(["object", "attributedTo"], user.ap_id) conn = conn @@ -829,7 +829,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do test "it inserts an incoming activity into the database", %{conn: conn, data: data} do user = insert(:user) - data = Map.put(data, "bcc", [user.ap_id]) + + data = + data + |> Map.put("bcc", [user.ap_id]) + |> Kernel.put_in(["object", "bcc"], [user.ap_id]) conn = conn @@ -846,8 +850,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do user = insert(:user) data = - Map.put(data, "to", user.ap_id) - |> Map.delete("cc") + data + |> Map.put("to", user.ap_id) + |> Map.put("cc", []) + |> Kernel.put_in(["object", "to"], user.ap_id) + |> Kernel.put_in(["object", "cc"], []) conn = conn @@ -864,8 +871,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do user = insert(:user) data = - Map.put(data, "cc", user.ap_id) - |> Map.delete("to") + data + |> Map.put("to", []) + |> Map.put("cc", user.ap_id) + |> Kernel.put_in(["object", "to"], []) + |> Kernel.put_in(["object", "cc"], user.ap_id) conn = conn @@ -883,9 +893,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do user = insert(:user) data = - Map.put(data, "bcc", user.ap_id) - |> Map.delete("to") - |> Map.delete("cc") + data + |> Map.put("to", []) + |> Map.put("cc", []) + |> Map.put("bcc", user.ap_id) + |> Kernel.put_in(["object", "to"], []) + |> Kernel.put_in(["object", "cc"], []) + |> Kernel.put_in(["object", "bcc"], user.ap_id) conn = conn @@ -1000,29 +1014,34 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert Instances.reachable?(sender_host) end + @tag capture_log: true test "it removes all follower collections but actor's", %{conn: conn} do [actor, recipient] = insert_pair(:user) - data = - File.read!("test/fixtures/activitypub-client-post-activity.json") - |> Jason.decode!() + to = [ + recipient.ap_id, + recipient.follower_address, + "https://www.w3.org/ns/activitystreams#Public" + ] - object = Map.put(data["object"], "attributedTo", actor.ap_id) + cc = [recipient.follower_address, actor.follower_address] - data = - data - |> Map.put("id", Utils.generate_object_id()) - |> Map.put("actor", actor.ap_id) - |> Map.put("object", object) - |> Map.put("cc", [ - recipient.follower_address, - actor.follower_address - ]) - |> Map.put("to", [ - recipient.ap_id, - recipient.follower_address, - "https://www.w3.org/ns/activitystreams#Public" - ]) + data = %{ + "@context" => ["https://www.w3.org/ns/activitystreams"], + "type" => "Create", + "id" => Utils.generate_activity_id(), + "to" => to, + "cc" => cc, + "actor" => actor.ap_id, + "object" => %{ + "type" => "Note", + "to" => to, + "cc" => cc, + "content" => "It's a note", + "attributedTo" => actor.ap_id, + "id" => Utils.generate_object_id() + } + } conn |> assign(:valid_signature, true) @@ -1032,7 +1051,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) - activity = Activity.get_by_ap_id(data["id"]) + assert activity = Activity.get_by_ap_id(data["id"]) assert activity.id assert actor.follower_address in activity.recipients @@ -1164,7 +1183,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do "actor" => remote_actor, "content" => "test report", "id" => "https://#{remote_domain}/e3b12fd1-948c-446e-b93b-a5e67edbe1d8", - "nickname" => reported_user.nickname, "object" => [ reported_user.ap_id, note.data["object"] diff --git a/test/pleroma/web/activity_pub/transmogrifier/audio_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/audio_handling_test.exs index a21e9e3d3..a929f828d 100644 --- a/test/pleroma/web/activity_pub/transmogrifier/audio_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/audio_handling_test.exs @@ -24,6 +24,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AudioHandlingTest do "actor" => "http://mastodon.example.org/users/admin", "object" => %{ "type" => "Audio", + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [], "id" => "http://mastodon.example.org/users/admin/listens/1234", "attributedTo" => "http://mastodon.example.org/users/admin", "title" => "lain radio episode 1", @@ -61,7 +63,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AudioHandlingTest do assert object.data["to"] == ["https://www.w3.org/ns/activitystreams#Public"] - assert object.data["cc"] == [] + assert object.data["cc"] == [ + "https://channels.tests.funkwhale.audio/federation/actors/compositions/followers" + ] assert object.data["url"] == "https://channels.tests.funkwhale.audio/library/tracks/74" diff --git a/test/pleroma/web/activity_pub/transmogrifier/event_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/event_handling_test.exs index c4879fda1..14f5f704a 100644 --- a/test/pleroma/web/activity_pub/transmogrifier/event_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/event_handling_test.exs @@ -31,7 +31,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.EventHandlingTest do ) assert object.data["to"] == ["https://www.w3.org/ns/activitystreams#Public"] - assert object.data["cc"] == [] + assert object.data["cc"] == ["https://mobilizon.org/@tcit/followers"] assert object.data["url"] == "https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39" diff --git a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs index deb956410..1846b2291 100644 --- a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs @@ -10,11 +10,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do alias Pleroma.Object alias Pleroma.User alias Pleroma.Web.ActivityPub.Transmogrifier + alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.CommonAPI import Mock import Pleroma.Factory - import ExUnit.CaptureLog setup_all do Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) @@ -43,36 +43,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do assert Object.hashtags(object) == ["test"] end - test "it cleans up incoming notices which are not really DMs" do - user = insert(:user) - other_user = insert(:user) - - to = [user.ap_id, other_user.ap_id] - - data = - File.read!("test/fixtures/mastodon-post-activity.json") - |> Jason.decode!() - |> Map.put("to", to) - |> Map.put("cc", []) - - object = - data["object"] - |> Map.put("to", to) - |> Map.put("cc", []) - - data = Map.put(data, "object", object) - - {:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data) - - assert data["to"] == [] - assert data["cc"] == to - - object_data = Object.normalize(activity, fetch: false).data - - assert object_data["to"] == [] - assert object_data["cc"] == to - end - test "it ignores an incoming notice if we already have it" do activity = insert(:note_activity) @@ -147,9 +117,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do data |> Map.put("object", object) - assert capture_log(fn -> - {:ok, _returned_activity} = Transmogrifier.handle_incoming(data) - end) =~ "[warn] Couldn't fetch \"https://404.site/whatever\", error: nil" + assert {:ok, _returned_activity} = Transmogrifier.handle_incoming(data) end test "it does not work for deactivated users" do @@ -174,8 +142,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do assert data["to"] == ["https://www.w3.org/ns/activitystreams#Public"] assert data["cc"] == [ - "http://mastodon.example.org/users/admin/followers", - "http://localtesting.pleroma.lol/users/lain" + "http://localtesting.pleroma.lol/users/lain", + "http://mastodon.example.org/users/admin/followers" ] assert data["actor"] == "http://mastodon.example.org/users/admin" @@ -188,8 +156,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do assert object_data["to"] == ["https://www.w3.org/ns/activitystreams#Public"] assert object_data["cc"] == [ - "http://mastodon.example.org/users/admin/followers", - "http://localtesting.pleroma.lol/users/lain" + "http://localtesting.pleroma.lol/users/lain", + "http://mastodon.example.org/users/admin/followers" ] assert object_data["actor"] == "http://mastodon.example.org/users/admin" @@ -221,8 +189,25 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) object = Object.normalize(data["object"], fetch: false) - assert Enum.at(Object.tags(object), 2) == "moo" - assert Object.hashtags(object) == ["moo"] + assert match?( + %{ + "href" => "http://localtesting.pleroma.lol/users/lain", + "name" => "@lain@localtesting.pleroma.lol", + "type" => "Mention" + }, + Enum.at(object.data["tag"], 0) + ) + + assert match?( + %{ + "href" => "http://mastodon.example.org/tags/moo", + "name" => "#moo", + "type" => "Hashtag" + }, + Enum.at(object.data["tag"], 1) + ) + + assert "moo" == Enum.at(object.data["tag"], 2) end test "it works for incoming notices with contentMap" do @@ -276,13 +261,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!() |> Map.put("actor", user.ap_id) - |> Map.put("to", nil) |> Map.put("cc", nil) object = data["object"] |> Map.put("attributedTo", user.ap_id) - |> Map.put("to", nil) |> Map.put("cc", nil) |> Map.put("id", user.ap_id <> "/activities/12345678") @@ -290,8 +273,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - assert !is_nil(data["to"]) - assert !is_nil(data["cc"]) + refute is_nil(data["cc"]) end test "it strips internal likes" do @@ -310,9 +292,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do object = Map.put(data["object"], "likes", likes) data = Map.put(data, "object", object) - {:ok, %Activity{object: object}} = Transmogrifier.handle_incoming(data) + {:ok, %Activity{} = activity} = Transmogrifier.handle_incoming(data) - refute Map.has_key?(object.data, "likes") + object = Object.normalize(activity) + + assert object.data["likes"] == [] end test "it strips internal reactions" do @@ -330,70 +314,46 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do end test "it correctly processes messages with non-array to field" do - user = insert(:user) + data = + File.read!("test/fixtures/mastodon-post-activity.json") + |> Poison.decode!() + |> Map.put("to", "https://www.w3.org/ns/activitystreams#Public") + |> put_in(["object", "to"], "https://www.w3.org/ns/activitystreams#Public") - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "to" => "https://www.w3.org/ns/activitystreams#Public", - "type" => "Create", - "object" => %{ - "content" => "blah blah blah", - "type" => "Note", - "attributedTo" => user.ap_id, - "inReplyTo" => nil - }, - "actor" => user.ap_id - } + assert {:ok, activity} = Transmogrifier.handle_incoming(data) - assert {:ok, activity} = Transmogrifier.handle_incoming(message) + assert [ + "http://localtesting.pleroma.lol/users/lain", + "http://mastodon.example.org/users/admin/followers" + ] == activity.data["cc"] assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"] end test "it correctly processes messages with non-array cc field" do - user = insert(:user) + data = + File.read!("test/fixtures/mastodon-post-activity.json") + |> Poison.decode!() + |> Map.put("cc", "http://mastodon.example.org/users/admin/followers") + |> put_in(["object", "cc"], "http://mastodon.example.org/users/admin/followers") - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "to" => user.follower_address, - "cc" => "https://www.w3.org/ns/activitystreams#Public", - "type" => "Create", - "object" => %{ - "content" => "blah blah blah", - "type" => "Note", - "attributedTo" => user.ap_id, - "inReplyTo" => nil - }, - "actor" => user.ap_id - } + assert {:ok, activity} = Transmogrifier.handle_incoming(data) - assert {:ok, activity} = Transmogrifier.handle_incoming(message) - - assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["cc"] - assert [user.follower_address] == activity.data["to"] + assert ["http://mastodon.example.org/users/admin/followers"] == activity.data["cc"] + assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"] end test "it correctly processes messages with weirdness in address fields" do - user = insert(:user) + data = + File.read!("test/fixtures/mastodon-post-activity.json") + |> Poison.decode!() + |> Map.put("cc", ["http://mastodon.example.org/users/admin/followers", ["¿"]]) + |> put_in(["object", "cc"], ["http://mastodon.example.org/users/admin/followers", ["¿"]]) - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "to" => [nil, user.follower_address], - "cc" => ["https://www.w3.org/ns/activitystreams#Public", ["¿"]], - "type" => "Create", - "object" => %{ - "content" => "…", - "type" => "Note", - "attributedTo" => user.ap_id, - "inReplyTo" => nil - }, - "actor" => user.ap_id - } + assert {:ok, activity} = Transmogrifier.handle_incoming(data) - assert {:ok, activity} = Transmogrifier.handle_incoming(message) - - assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["cc"] - assert [user.follower_address] == activity.data["to"] + assert ["http://mastodon.example.org/users/admin/followers"] == activity.data["cc"] + assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"] end end @@ -419,7 +379,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do } do clear_config([:instance, :federation_incoming_replies_max_depth], 10) - {:ok, _activity} = Transmogrifier.handle_incoming(data) + {:ok, activity} = Transmogrifier.handle_incoming(data) + + object = Object.normalize(activity.data["object"]) + + assert object.data["replies"] == items for id <- items do job_args = %{"op" => "fetch_remote", "id" => id, "depth" => 1} @@ -442,45 +406,38 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do setup do: clear_config([:instance, :federation_incoming_replies_max_depth]) setup do - user = insert(:user) + replies = %{ + "type" => "Collection", + "items" => [Utils.generate_object_id(), Utils.generate_object_id()] + } - {:ok, activity} = CommonAPI.post(user, %{status: "post1"}) + activity = + File.read!("test/fixtures/mastodon-post-activity.json") + |> Poison.decode!() + |> Kernel.put_in(["object", "replies"], replies) - {:ok, reply1} = - CommonAPI.post(user, %{status: "reply1", in_reply_to_status_id: activity.id}) - - {:ok, reply2} = - CommonAPI.post(user, %{status: "reply2", in_reply_to_status_id: activity.id}) - - replies_uris = Enum.map([reply1, reply2], fn a -> a.object.data["id"] end) - - {:ok, federation_output} = Transmogrifier.prepare_outgoing(activity.data) - - Repo.delete(activity.object) - Repo.delete(activity) - - %{federation_output: federation_output, replies_uris: replies_uris} + %{activity: activity} end test "schedules background fetching of `replies` items if max thread depth limit allows", %{ - federation_output: federation_output, - replies_uris: replies_uris + activity: activity } do clear_config([:instance, :federation_incoming_replies_max_depth], 1) - {:ok, _activity} = Transmogrifier.handle_incoming(federation_output) + assert {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(activity) + object = Object.normalize(data["object"]) - for id <- replies_uris do + for id <- object.data["replies"] do job_args = %{"op" => "fetch_remote", "id" => id, "depth" => 1} assert_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker, args: job_args) end end test "does NOT schedule background fetching of `replies` beyond max thread depth limit allows", - %{federation_output: federation_output} do + %{activity: activity} do clear_config([:instance, :federation_incoming_replies_max_depth], 0) - {:ok, _activity} = Transmogrifier.handle_incoming(federation_output) + {:ok, _activity} = Transmogrifier.handle_incoming(activity) assert all_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker) == [] end @@ -498,6 +455,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do "object" => %{ "to" => ["https://www.w3.org/ns/activitystreams#Public"], "cc" => [], + "id" => Utils.generate_object_id(), "type" => "Note", "content" => "Hi", "inReplyTo" => nil, @@ -522,6 +480,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do "object" => %{ "to" => ["https://www.w3.org/ns/activitystreams#Public"], "cc" => [], + "id" => Utils.generate_object_id(), "type" => "Note", "content" => "Hi", "inReplyTo" => nil, diff --git a/test/pleroma/web/activity_pub/transmogrifier_test.exs b/test/pleroma/web/activity_pub/transmogrifier_test.exs index 4c3fcb44a..5a3b57acb 100644 --- a/test/pleroma/web/activity_pub/transmogrifier_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier_test.exs @@ -11,6 +11,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do alias Pleroma.Tests.ObanHelpers alias Pleroma.User alias Pleroma.Web.ActivityPub.Transmogrifier + alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.AdminAPI.AccountView alias Pleroma.Web.CommonAPI @@ -159,8 +160,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - assert modified["@context"] == - Pleroma.Web.ActivityPub.Utils.make_json_ld_header()["@context"] + assert modified["@context"] == Utils.make_json_ld_header()["@context"] assert modified["object"]["conversation"] == modified["context"] end @@ -446,7 +446,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do end) } - fixed_object = Transmogrifier.fix_explicit_addressing(object) + fixed_object = Transmogrifier.fix_explicit_addressing(object, user.follower_address) assert Enum.all?(explicitly_mentioned_actors, &(&1 in fixed_object["to"])) refute "https://social.beepboop.ga/users/dirb" in fixed_object["to"] assert "https://social.beepboop.ga/users/dirb" in fixed_object["cc"] @@ -459,7 +459,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do "cc" => [] } - fixed_object = Transmogrifier.fix_explicit_addressing(object) + fixed_object = Transmogrifier.fix_explicit_addressing(object, user.follower_address) assert user.follower_address in fixed_object["to"] refute user.follower_address in fixed_object["cc"] end @@ -473,7 +473,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do "cc" => [user.follower_address, recipient.follower_address] } - fixed_object = Transmogrifier.fix_explicit_addressing(object) + fixed_object = Transmogrifier.fix_explicit_addressing(object, user.follower_address) assert user.follower_address in fixed_object["cc"] refute recipient.follower_address in fixed_object["cc"] diff --git a/test/pleroma/web/common_api_test.exs b/test/pleroma/web/common_api_test.exs index be94c93c2..cc4ab213a 100644 --- a/test/pleroma/web/common_api_test.exs +++ b/test/pleroma/web/common_api_test.exs @@ -539,8 +539,8 @@ defmodule Pleroma.Web.CommonAPITest do spoiler_text: ":joker_smile:" }) - assert Object.normalize(reply_activity).data["emoji"][":joker_smile:"] - refute Object.normalize(reply_activity).data["emoji"][":joker_disapprove:"] + assert Object.normalize(reply_activity).data["emoji"]["joker_smile"] + refute Object.normalize(reply_activity).data["emoji"]["joker_disapprove"] end test "deactivated users can't post" do diff --git a/test/pleroma/web/federator_test.exs b/test/pleroma/web/federator_test.exs index 532ee6d30..372b6a73a 100644 --- a/test/pleroma/web/federator_test.exs +++ b/test/pleroma/web/federator_test.exs @@ -123,7 +123,8 @@ defmodule Pleroma.Web.FederatorTest do "type" => "Note", "content" => "hi world!", "id" => "http://mastodon.example.org/users/admin/objects/1", - "attributedTo" => "http://mastodon.example.org/users/admin" + "attributedTo" => "http://mastodon.example.org/users/admin", + "to" => ["https://www.w3.org/ns/activitystreams#Public"] }, "to" => ["https://www.w3.org/ns/activitystreams#Public"] } @@ -145,7 +146,8 @@ defmodule Pleroma.Web.FederatorTest do "type" => "Note", "content" => "hi world!", "id" => "http://mastodon.example.org/users/admin/objects/1", - "attributedTo" => "http://mastodon.example.org/users/admin" + "attributedTo" => "http://mastodon.example.org/users/admin", + "to" => ["https://www.w3.org/ns/activitystreams#Public"] }, "to" => ["https://www.w3.org/ns/activitystreams#Public"] } diff --git a/test/pleroma/web/static_fe/static_fe_controller_test.exs b/test/pleroma/web/static_fe/static_fe_controller_test.exs index 2af14dfeb..5752cffda 100644 --- a/test/pleroma/web/static_fe/static_fe_controller_test.exs +++ b/test/pleroma/web/static_fe/static_fe_controller_test.exs @@ -7,6 +7,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do alias Pleroma.Activity alias Pleroma.Web.ActivityPub.Transmogrifier + alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.CommonAPI import Pleroma.Factory @@ -185,16 +186,16 @@ defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do test "302 for remote cached status", %{conn: conn, user: user} do message = %{ "@context" => "https://www.w3.org/ns/activitystreams", - "to" => user.follower_address, - "cc" => "https://www.w3.org/ns/activitystreams#Public", "type" => "Create", + "actor" => user.ap_id, "object" => %{ + "to" => user.follower_address, + "cc" => "https://www.w3.org/ns/activitystreams#Public", + "id" => Utils.generate_object_id(), "content" => "blah blah blah", "type" => "Note", - "attributedTo" => user.ap_id, - "inReplyTo" => nil - }, - "actor" => user.ap_id + "attributedTo" => user.ap_id + } } assert {:ok, activity} = Transmogrifier.handle_incoming(message)