Merge branch 'features/validators-note' into 'develop'

Pipeline Ingestion: Note

Closes #290

See merge request pleroma/pleroma!2984
This commit is contained in:
Haelwenn 2021-06-01 01:51:38 +00:00
commit c4b4258374
31 changed files with 389 additions and 318 deletions

View file

@ -13,21 +13,33 @@ defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.Recipients do
cast([object]) cast([object])
end end
def cast(data) when is_list(data) do def cast(object) when is_map(object) do
data case ObjectID.cast(object) do
|> Enum.reduce_while({:ok, []}, fn element, {:ok, list} -> {:ok, data} -> {:ok, [data]}
case ObjectID.cast(element) do _ -> :error
{:ok, id} -> end
{:cont, {:ok, [id | list]}}
_ ->
{:halt, :error}
end
end)
end end
def cast(_) do def cast(data) when is_list(data) do
:error 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 end
def dump(data) do def dump(data) do

View file

@ -12,4 +12,10 @@ defmodule Pleroma.Maps do
_ -> map _ -> map
end end
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 end

View file

@ -4,6 +4,7 @@
defmodule Pleroma.Object.Fetcher do defmodule Pleroma.Object.Fetcher do
alias Pleroma.HTTP alias Pleroma.HTTP
alias Pleroma.Maps
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.Object.Containment alias Pleroma.Object.Containment
alias Pleroma.Repo alias Pleroma.Repo
@ -101,6 +102,9 @@ defmodule Pleroma.Object.Fetcher do
{:transmogrifier, {:error, {:reject, e}}} -> {:transmogrifier, {:error, {:reject, e}}} ->
{:reject, e} {:reject, e}
{:transmogrifier, {:reject, e}} ->
{:reject, e}
{:transmogrifier, _} = e -> {:transmogrifier, _} = e ->
{:error, e} {:error, e}
@ -124,12 +128,14 @@ defmodule Pleroma.Object.Fetcher do
defp prepare_activity_params(data) do defp prepare_activity_params(data) do
%{ %{
"type" => "Create", "type" => "Create",
"to" => data["to"] || [],
"cc" => data["cc"] || [],
# Should we seriously keep this attributedTo thing? # Should we seriously keep this attributedTo thing?
"actor" => data["actor"] || data["attributedTo"], "actor" => data["actor"] || data["attributedTo"],
"object" => data "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 end
def fetch_object_from_id!(id, options \\ []) do def fetch_object_from_id!(id, options \\ []) do

View file

@ -88,7 +88,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp increase_replies_count_if_reply(_create_data), do: :noop 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 @impl true
def persist(%{"type" => type} = object, meta) when type in @object_types do def persist(%{"type" => type} = object, meta) when type in @object_types do
with {:ok, object} <- Object.create(object) do with {:ok, object} <- Object.create(object) do

View file

@ -102,7 +102,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
%{"type" => "Create", "object" => %{"type" => objtype} = object} = create_activity, %{"type" => "Create", "object" => %{"type" => objtype} = object} = create_activity,
meta 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), with {:ok, object_data} <- cast_and_apply(object),
meta = Keyword.put(meta, :object_data, object_data |> stringify_keys), meta = Keyword.put(meta, :object_data, object_data |> stringify_keys),
{:ok, create_activity} <- {:ok, create_activity} <-
@ -115,7 +115,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
end end
def validate(%{"type" => type} = object, meta) 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 = validator =
case type do case type do
"Event" -> EventValidator "Event" -> EventValidator
@ -123,6 +123,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
"Audio" -> AudioVideoValidator "Audio" -> AudioVideoValidator
"Video" -> AudioVideoValidator "Video" -> AudioVideoValidator
"Article" -> ArticleNoteValidator "Article" -> ArticleNoteValidator
"Note" -> ArticleNoteValidator
end end
with {:ok, object} <- with {:ok, object} <-
@ -194,7 +195,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
EventValidator.cast_and_apply(object) EventValidator.cast_and_apply(object)
end 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) ArticleNoteValidator.cast_and_apply(object)
end end

View file

@ -6,6 +6,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnswerValidator do
use Ecto.Schema use Ecto.Schema
alias Pleroma.EctoType.ActivityPub.ObjectValidators alias Pleroma.EctoType.ActivityPub.ObjectValidators
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
import Ecto.Changeset import Ecto.Changeset
@ -23,6 +24,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnswerValidator do
field(:name, :string) field(:name, :string)
field(:inReplyTo, ObjectValidators.ObjectID) field(:inReplyTo, ObjectValidators.ObjectID)
field(:attributedTo, ObjectValidators.ObjectID) field(:attributedTo, ObjectValidators.ObjectID)
field(:context, :string)
# TODO: Remove actor on objects # TODO: Remove actor on objects
field(:actor, ObjectValidators.ObjectID) field(:actor, ObjectValidators.ObjectID)
@ -46,6 +48,11 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnswerValidator do
end end
def changeset(struct, data) do def changeset(struct, data) do
data =
data
|> CommonFixes.fix_actor()
|> CommonFixes.fix_object_defaults()
struct struct
|> cast(data, __schema__(:fields)) |> cast(data, __schema__(:fields))
end end

View file

@ -50,6 +50,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNoteValidator do
field(:likes, {:array, ObjectValidators.ObjectID}, default: []) field(:likes, {:array, ObjectValidators.ObjectID}, default: [])
field(:announcements, {:array, ObjectValidators.ObjectID}, default: []) field(:announcements, {:array, ObjectValidators.ObjectID}, default: [])
field(:replies, {:array, ObjectValidators.ObjectID}, default: [])
end end
def cast_and_apply(data) do def cast_and_apply(data) do
@ -65,25 +67,39 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNoteValidator do
end end
def cast_data(data) do def cast_data(data) do
data = fix(data)
%__MODULE__{} %__MODULE__{}
|> changeset(data) |> changeset(data)
end end
defp fix_url(%{"url" => url} = data) when is_map(url) do defp fix_url(%{"url" => url} = data) when is_bitstring(url), do: data
Map.put(data, "url", url["href"]) defp fix_url(%{"url" => url} = data) when is_map(url), do: Map.put(data, "url", url["href"])
end
defp fix_url(data), do: data 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 defp fix(data) do
data data
|> CommonFixes.fix_defaults()
|> CommonFixes.fix_attribution()
|> CommonFixes.fix_actor() |> CommonFixes.fix_actor()
|> CommonFixes.fix_object_defaults()
|> fix_url() |> fix_url()
|> fix_tag()
|> fix_replies()
|> Transmogrifier.fix_emoji() |> Transmogrifier.fix_emoji()
|> Transmogrifier.fix_content_map()
end end
def changeset(struct, data) do def changeset(struct, data) do

View file

@ -119,9 +119,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator do
defp fix(data) do defp fix(data) do
data data
|> CommonFixes.fix_defaults()
|> CommonFixes.fix_attribution()
|> CommonFixes.fix_actor() |> CommonFixes.fix_actor()
|> CommonFixes.fix_object_defaults()
|> Transmogrifier.fix_emoji() |> Transmogrifier.fix_emoji()
|> fix_url() |> fix_url()
|> fix_content() |> fix_content()

View file

@ -3,26 +3,55 @@
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
alias Pleroma.EctoType.ActivityPub.ObjectValidators
alias Pleroma.Object.Containment alias Pleroma.Object.Containment
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
# based on Pleroma.Web.ActivityPub.Utils.lazy_put_objects_defaults def cast_and_filter_recipients(message, field, follower_collection, field_fallback \\ []) do
def fix_defaults(data) 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} = %{data: %{"id" => context}, id: context_id} =
Utils.create_context(data["context"] || data["conversation"]) Utils.create_context(data["context"] || data["conversation"])
%User{follower_address: follower_collection} = User.get_cached_by_ap_id(data["attributedTo"])
data data
|> Map.put("context", context) |> Map.put("context", context)
|> Map.put("context_id", context_id) |> 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 end
def fix_attribution(data) do def fix_activity_addressing(activity, _meta) do
data %User{follower_address: follower_collection} = User.get_cached_by_ap_id(activity["actor"])
|> Map.put_new("actor", data["attributedTo"])
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 end
def fix_actor(data) do def fix_actor(data) do
actor = Containment.get_actor(data) actor =
data
|> Map.put_new("actor", data["attributedTo"])
|> Containment.get_actor()
data data
|> Map.put("actor", actor) |> Map.put("actor", actor)

View file

@ -15,6 +15,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations do
fields fields
|> Enum.map(fn field -> get_field(cng, field) end) |> Enum.map(fn field -> get_field(cng, field) end)
|> Enum.any?(fn |> Enum.any?(fn
nil -> false
[] -> false [] -> false
_ -> true _ -> true
end) end)

View file

@ -10,8 +10,10 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator do
alias Pleroma.EctoType.ActivityPub.ObjectValidators alias Pleroma.EctoType.ActivityPub.ObjectValidators
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
alias Pleroma.Web.ActivityPub.Transmogrifier
import Ecto.Changeset import Ecto.Changeset
@ -23,6 +25,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator do
field(:type, :string) field(:type, :string)
field(:to, ObjectValidators.Recipients, default: []) field(:to, ObjectValidators.Recipients, default: [])
field(:cc, ObjectValidators.Recipients, default: []) field(:cc, ObjectValidators.Recipients, default: [])
field(:bto, ObjectValidators.Recipients, default: [])
field(:bcc, ObjectValidators.Recipients, default: [])
field(:object, ObjectValidators.ObjectID) field(:object, ObjectValidators.ObjectID)
field(:expires_at, ObjectValidators.DateTime) field(:expires_at, ObjectValidators.DateTime)
@ -54,39 +58,37 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator do
|> cast(data, __schema__(:fields)) |> cast(data, __schema__(:fields))
end end
defp fix_context(data, meta) do # CommonFixes.fix_activity_addressing adapted for Create specific behavior
if object = meta[:object_data] do defp fix_addressing(data, object) do
Map.put_new(data, "context", object["context"]) %User{follower_address: follower_collection} = User.get_cached_by_ap_id(data["actor"])
else
data data
end |> CommonFixes.cast_and_filter_recipients("to", follower_collection, object["to"])
end |> 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 data
|> fix_context(meta)
|> fix_addressing(meta)
|> CommonFixes.fix_actor() |> CommonFixes.fix_actor()
|> Map.put_new("context", object["context"])
|> fix_addressing(object)
end end
defp validate_data(cng, meta) do defp validate_data(cng, meta) do
object = meta[:object_data]
cng cng
|> validate_required([:actor, :type, :object]) |> validate_required([:actor, :type, :object, :to, :cc])
|> validate_inclusion(:type, ["Create"]) |> validate_inclusion(:type, ["Create"])
|> CommonValidations.validate_actor_presence() |> CommonValidations.validate_actor_presence()
|> CommonValidations.validate_any_presence([:to, :cc]) |> validate_actors_match(object)
|> validate_actors_match(meta) |> validate_context_match(object)
|> validate_context_match(meta) |> validate_addressing_match(object)
|> validate_object_nonexistence() |> validate_object_nonexistence()
|> validate_object_containment() |> validate_object_containment()
end end
@ -118,8 +120,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator do
end) end)
end end
def validate_actors_match(cng, meta) do def validate_actors_match(cng, object) do
attributed_to = meta[:object_data]["attributedTo"] || meta[:object_data]["actor"] attributed_to = object["attributedTo"] || object["actor"]
cng cng
|> validate_change(:actor, fn :actor, actor -> |> validate_change(:actor, fn :actor, actor ->
@ -131,7 +133,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator do
end) end)
end end
def validate_context_match(cng, %{object_data: %{"context" => object_context}}) do def validate_context_match(cng, %{"context" => object_context}) do
cng cng
|> validate_change(:context, fn :context, context -> |> validate_change(:context, fn :context, context ->
if context == object_context do if context == object_context do
@ -142,5 +144,18 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator do
end) end)
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 end

View file

@ -1,29 +0,0 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateNoteValidator do
use Ecto.Schema
alias Pleroma.EctoType.ActivityPub.ObjectValidators
alias Pleroma.Web.ActivityPub.ObjectValidators.NoteValidator
import Ecto.Changeset
@primary_key false
embedded_schema do
field(:id, ObjectValidators.ObjectID, primary_key: true)
field(:actor, ObjectValidators.ObjectID)
field(:type, :string)
field(:to, ObjectValidators.Recipients, default: [])
field(:cc, ObjectValidators.Recipients, default: [])
field(:bto, ObjectValidators.Recipients, default: [])
field(:bcc, ObjectValidators.Recipients, default: [])
embeds_one(:object, NoteValidator)
end
def cast_data(data) do
cast(%__MODULE__{}, data, __schema__(:fields))
end
end

View file

@ -72,8 +72,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EventValidator do
defp fix(data) do defp fix(data) do
data data
|> CommonFixes.fix_defaults() |> CommonFixes.fix_actor()
|> CommonFixes.fix_attribution() |> CommonFixes.fix_object_defaults()
|> Transmogrifier.fix_emoji() |> Transmogrifier.fix_emoji()
end end

View file

@ -83,8 +83,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator do
defp fix(data) do defp fix(data) do
data data
|> CommonFixes.fix_defaults() |> CommonFixes.fix_actor()
|> CommonFixes.fix_attribution() |> CommonFixes.fix_object_defaults()
|> Transmogrifier.fix_emoji() |> Transmogrifier.fix_emoji()
|> fix_closed() |> fix_closed()
end end

View file

@ -203,6 +203,19 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
Object.increase_replies_count(in_reply_to) Object.increase_replies_count(in_reply_to)
end 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 -> ConcurrentLimiter.limit(Pleroma.Web.RichMedia.Helpers, fn ->
Task.start(fn -> Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) end) Task.start(fn -> Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) end)
end) end)
@ -423,7 +436,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
end end
def handle_object_creation(%{"type" => objtype} = object, meta) 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 with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
{:ok, object, meta} {:ok, object, meta}
end end

View file

@ -43,7 +43,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> fix_content_map() |> fix_content_map()
|> fix_addressing() |> fix_addressing()
|> fix_summary() |> fix_summary()
|> fix_type(options)
end end
def fix_summary(%{"summary" => nil} = object) do def fix_summary(%{"summary" => nil} = object) do
@ -72,17 +71,21 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end end
end end
def fix_explicit_addressing( # if directMessage flag is set to true, leave the addressing alone
%{"to" => to, "cc" => cc} = object, def fix_explicit_addressing(%{"directMessage" => true} = object, _follower_collection),
explicit_mentions, do: object
follower_collection
) do
explicit_to = Enum.filter(to, fn x -> x in explicit_mentions end)
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) explicit_cc = Enum.filter(to, fn x -> x not in explicit_mentions end)
final_cc = final_cc =
(cc ++ explicit_cc) (cc ++ explicit_cc)
|> Enum.filter(& &1)
|> Enum.reject(fn x -> String.ends_with?(x, "/followers") and x != follower_collection end) |> Enum.reject(fn x -> String.ends_with?(x, "/followers") and x != follower_collection end)
|> Enum.uniq() |> Enum.uniq()
@ -91,29 +94,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> Map.put("cc", final_cc) |> Map.put("cc", final_cc)
end 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 # if as:Public is addressed, then make sure the followers collection is also addressed
# so that the activities will be delivered to local users. # so that the activities will be delivered to local users.
def fix_implicit_addressing(%{"to" => to, "cc" => cc} = object, followers_collection) do def fix_implicit_addressing(%{"to" => to, "cc" => cc} = object, followers_collection) do
@ -137,19 +117,19 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end end
end end
def fix_implicit_addressing(object, _), do: object
def fix_addressing(object) do def fix_addressing(object) do
{:ok, %User{} = user} = User.get_or_fetch_by_ap_id(object["actor"]) {:ok, %User{follower_address: follower_collection}} =
followers_collection = User.ap_followers(user) object
|> Containment.get_actor()
|> User.get_or_fetch_by_ap_id()
object object
|> fix_addressing_list("to") |> fix_addressing_list("to")
|> fix_addressing_list("cc") |> fix_addressing_list("cc")
|> fix_addressing_list("bto") |> fix_addressing_list("bto")
|> fix_addressing_list("bcc") |> fix_addressing_list("bcc")
|> fix_explicit_addressing() |> fix_explicit_addressing(follower_collection)
|> fix_implicit_addressing(followers_collection) |> fix_implicit_addressing(follower_collection)
end end
def fix_actor(%{"attributedTo" => actor} = object) do 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_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) with %Object{data: %{"type" => "Question"}} <- Object.normalize(reply_id, options) do
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
Map.put(object, "type", "Answer") Map.put(object, "type", "Answer")
else else
_ -> object _ -> object
end end
end end
def fix_type(object, _), do: object defp fix_type(object, _options), do: object
# Reduce the object list to find the reported user. # Reduce the object list to find the reported user.
defp get_reported(objects) do defp get_reported(objects) do
@ -425,10 +404,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
# - tags # - tags
# - emoji # - emoji
def handle_incoming( def handle_incoming(
%{"type" => "Create", "object" => %{"type" => objtype} = object} = data, %{"type" => "Create", "object" => %{"type" => "Page"} = object} = data,
options options
) ) do
when objtype in ~w{Note Page} do
actor = Containment.get_actor(data) actor = Containment.get_actor(data)
with nil <- Activity.get_create_by_object_ap_id(object["id"]), with nil <- Activity.get_create_by_object_ap_id(object["id"]),
@ -520,14 +498,23 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def handle_incoming( def handle_incoming(
%{"type" => "Create", "object" => %{"type" => objtype, "id" => obj_id}} = data, %{"type" => "Create", "object" => %{"type" => objtype, "id" => obj_id}} = data,
_options options
) )
when objtype in ~w{Question Answer ChatMessage Audio Video Event Article} do when objtype in ~w{Question Answer ChatMessage Audio Video Event Article Note} do
data = Map.put(data, "object", strip_internal_fields(data["object"])) 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), with {:ok, %User{}} <- ObjectValidator.fetch_actor(data),
nil <- Activity.get_create_by_object_ap_id(obj_id), 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} {:ok, activity}
else else
%Activity{} = activity -> {:ok, activity} %Activity{} = activity -> {:ok, activity}

View file

@ -96,8 +96,11 @@ defmodule Pleroma.Web.ActivityPub.Utils do
!label_in_collection?(ap_id, params["cc"]) !label_in_collection?(ap_id, params["cc"])
if need_splice? do if need_splice? do
cc_list = extract_list(params["cc"]) cc = [ap_id | extract_list(params["cc"])]
Map.put(params, "cc", [ap_id | cc_list])
params
|> Map.put("cc", cc)
|> Maps.safe_put_in(["object", "cc"], cc)
else else
params params
end end

View file

@ -96,6 +96,11 @@ defmodule Pleroma.Web.Federator do
Logger.debug("Unhandled actor #{actor}, #{inspect(e)}") Logger.debug("Unhandled actor #{actor}, #{inspect(e)}")
{:error, 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 -> e ->
# Just drop those for now # Just drop those for now
Logger.debug(fn -> "Unhandled activity\n" <> Jason.encode!(params, pretty: true) end) Logger.debug(fn -> "Unhandled activity\n" <> Jason.encode!(params, pretty: true) end)

View file

@ -3,6 +3,7 @@
"type": "Create", "type": "Create",
"object": { "object": {
"type": "Note", "type": "Note",
"to": ["https://www.w3.org/ns/activitystreams#Public"],
"content": "It's a note" "content": "It's a note"
}, },
"to": ["https://www.w3.org/ns/activitystreams#Public"] "to": ["https://www.w3.org/ns/activitystreams#Public"]

View file

@ -123,7 +123,8 @@ defmodule Pleroma.ActivityTest do
"type" => "Note", "type" => "Note",
"content" => "find me!", "content" => "find me!",
"id" => "http://mastodon.example.org/users/admin/objects/1", "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"] "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, japanese_activity} = Pleroma.Web.CommonAPI.post(user, %{status: "更新情報"})
{:ok, job} = Pleroma.Web.Federator.incoming_ap_doc(params) {:ok, job} = Pleroma.Web.Federator.incoming_ap_doc(params)
{:ok, remote_activity} = ObanHelpers.perform(job) {:ok, remote_activity} = ObanHelpers.perform(job)
remote_activity = Activity.get_by_id_with_object(remote_activity.id)
%{ %{
japanese_activity: japanese_activity, japanese_activity: japanese_activity,

View file

@ -6,10 +6,10 @@ defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.RecipientsTest do
alias Pleroma.EctoType.ActivityPub.ObjectValidators.Recipients alias Pleroma.EctoType.ActivityPub.ObjectValidators.Recipients
use Pleroma.DataCase, async: true 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"] list = ["https://lain.com/users/lain", "invalid"]
assert :error == Recipients.cast(list) assert {:ok, ["https://lain.com/users/lain"]} == Recipients.cast(list)
end end
test "it works with a list" do test "it works with a list" do

View file

@ -624,6 +624,8 @@ defmodule Pleroma.NotificationTest do
"actor" => user.ap_id, "actor" => user.ap_id,
"object" => %{ "object" => %{
"type" => "Note", "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", "content" => "message with a Mention tag, but no explicit tagging",
"tag" => [ "tag" => [
%{ %{
@ -655,6 +657,9 @@ defmodule Pleroma.NotificationTest do
"actor" => user.ap_id, "actor" => user.ap_id,
"object" => %{ "object" => %{
"type" => "Note", "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", "content" => "hi everyone",
"attributedTo" => user.ap_id "attributedTo" => user.ap_id
} }
@ -951,6 +956,7 @@ defmodule Pleroma.NotificationTest do
"cc" => [], "cc" => [],
"object" => %{ "object" => %{
"type" => "Note", "type" => "Note",
"id" => remote_user.ap_id <> "/objects/test",
"content" => "Hello!", "content" => "Hello!",
"tag" => [ "tag" => [
%{ %{

View file

@ -66,6 +66,14 @@ defmodule Pleroma.Object.FetcherTest do
%Tesla.Env{ %Tesla.Env{
status: 500 status: 500
} }
%{
method: :get,
url: "https://stereophonic.space/objects/02997b83-3ea7-4b63-94af-ef3aa2d4ed17"
} ->
%Tesla.Env{
status: 500
}
end) end)
:ok :ok
@ -124,8 +132,7 @@ defmodule Pleroma.Object.FetcherTest do
{:ok, object} = {:ok, object} =
Fetcher.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367") 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 = Activity.get_create_by_object_ap_id(object.data["id"])
assert activity.data["id"]
{:ok, object_again} = {:ok, object_again} =
Fetcher.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367") Fetcher.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367")

View file

@ -539,7 +539,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
File.read!("test/fixtures/mastodon-post-activity.json") File.read!("test/fixtures/mastodon-post-activity.json")
|> Jason.decode!() |> Jason.decode!()
|> Map.put("actor", user.ap_id) |> Map.put("actor", user.ap_id)
|> put_in(["object", "attridbutedTo"], user.ap_id) |> put_in(["object", "attributedTo"], user.ap_id)
conn = conn =
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 test "it inserts an incoming activity into the database", %{conn: conn, data: data} do
user = insert(:user) 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 =
conn conn
@ -846,8 +850,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
user = insert(:user) user = insert(:user)
data = data =
Map.put(data, "to", user.ap_id) data
|> Map.delete("cc") |> Map.put("to", user.ap_id)
|> Map.put("cc", [])
|> Kernel.put_in(["object", "to"], user.ap_id)
|> Kernel.put_in(["object", "cc"], [])
conn = conn =
conn conn
@ -864,8 +871,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
user = insert(:user) user = insert(:user)
data = data =
Map.put(data, "cc", user.ap_id) data
|> Map.delete("to") |> Map.put("to", [])
|> Map.put("cc", user.ap_id)
|> Kernel.put_in(["object", "to"], [])
|> Kernel.put_in(["object", "cc"], user.ap_id)
conn = conn =
conn conn
@ -883,9 +893,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
user = insert(:user) user = insert(:user)
data = data =
Map.put(data, "bcc", user.ap_id) data
|> Map.delete("to") |> Map.put("to", [])
|> Map.delete("cc") |> 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 =
conn conn
@ -1000,29 +1014,34 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert Instances.reachable?(sender_host) assert Instances.reachable?(sender_host)
end end
@tag capture_log: true
test "it removes all follower collections but actor's", %{conn: conn} do test "it removes all follower collections but actor's", %{conn: conn} do
[actor, recipient] = insert_pair(:user) [actor, recipient] = insert_pair(:user)
data = to = [
File.read!("test/fixtures/activitypub-client-post-activity.json") recipient.ap_id,
|> Jason.decode!() 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 = %{
data "@context" => ["https://www.w3.org/ns/activitystreams"],
|> Map.put("id", Utils.generate_object_id()) "type" => "Create",
|> Map.put("actor", actor.ap_id) "id" => Utils.generate_activity_id(),
|> Map.put("object", object) "to" => to,
|> Map.put("cc", [ "cc" => cc,
recipient.follower_address, "actor" => actor.ap_id,
actor.follower_address "object" => %{
]) "type" => "Note",
|> Map.put("to", [ "to" => to,
recipient.ap_id, "cc" => cc,
recipient.follower_address, "content" => "It's a note",
"https://www.w3.org/ns/activitystreams#Public" "attributedTo" => actor.ap_id,
]) "id" => Utils.generate_object_id()
}
}
conn conn
|> assign(:valid_signature, true) |> assign(:valid_signature, true)
@ -1032,7 +1051,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) 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 activity.id
assert actor.follower_address in activity.recipients assert actor.follower_address in activity.recipients
@ -1164,7 +1183,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
"actor" => remote_actor, "actor" => remote_actor,
"content" => "test report", "content" => "test report",
"id" => "https://#{remote_domain}/e3b12fd1-948c-446e-b93b-a5e67edbe1d8", "id" => "https://#{remote_domain}/e3b12fd1-948c-446e-b93b-a5e67edbe1d8",
"nickname" => reported_user.nickname,
"object" => [ "object" => [
reported_user.ap_id, reported_user.ap_id,
note.data["object"] note.data["object"]

View file

@ -24,6 +24,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AudioHandlingTest do
"actor" => "http://mastodon.example.org/users/admin", "actor" => "http://mastodon.example.org/users/admin",
"object" => %{ "object" => %{
"type" => "Audio", "type" => "Audio",
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
"cc" => [],
"id" => "http://mastodon.example.org/users/admin/listens/1234", "id" => "http://mastodon.example.org/users/admin/listens/1234",
"attributedTo" => "http://mastodon.example.org/users/admin", "attributedTo" => "http://mastodon.example.org/users/admin",
"title" => "lain radio episode 1", "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["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" assert object.data["url"] == "https://channels.tests.funkwhale.audio/library/tracks/74"

View file

@ -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["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"] == assert object.data["url"] ==
"https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39" "https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39"

View file

@ -10,11 +10,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.CommonAPI alias Pleroma.Web.CommonAPI
import Mock import Mock
import Pleroma.Factory import Pleroma.Factory
import ExUnit.CaptureLog
setup_all do setup_all do
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) 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"] assert Object.hashtags(object) == ["test"]
end 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 test "it ignores an incoming notice if we already have it" do
activity = insert(:note_activity) activity = insert(:note_activity)
@ -147,9 +117,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do
data data
|> Map.put("object", object) |> Map.put("object", object)
assert capture_log(fn -> assert {:ok, _returned_activity} = Transmogrifier.handle_incoming(data)
{:ok, _returned_activity} = Transmogrifier.handle_incoming(data)
end) =~ "[warn] Couldn't fetch \"https://404.site/whatever\", error: nil"
end end
test "it does not work for deactivated users" do 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["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
assert data["cc"] == [ 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" 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["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
assert object_data["cc"] == [ 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" 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) {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
object = Object.normalize(data["object"], fetch: false) object = Object.normalize(data["object"], fetch: false)
assert Enum.at(Object.tags(object), 2) == "moo" assert match?(
assert Object.hashtags(object) == ["moo"] %{
"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 end
test "it works for incoming notices with contentMap" do 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") File.read!("test/fixtures/mastodon-post-activity.json")
|> Jason.decode!() |> Jason.decode!()
|> Map.put("actor", user.ap_id) |> Map.put("actor", user.ap_id)
|> Map.put("to", nil)
|> Map.put("cc", nil) |> Map.put("cc", nil)
object = object =
data["object"] data["object"]
|> Map.put("attributedTo", user.ap_id) |> Map.put("attributedTo", user.ap_id)
|> Map.put("to", nil)
|> Map.put("cc", nil) |> Map.put("cc", nil)
|> Map.put("id", user.ap_id <> "/activities/12345678") |> 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) {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert !is_nil(data["to"]) refute is_nil(data["cc"])
assert !is_nil(data["cc"])
end end
test "it strips internal likes" do test "it strips internal likes" do
@ -310,9 +292,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do
object = Map.put(data["object"], "likes", likes) object = Map.put(data["object"], "likes", likes)
data = Map.put(data, "object", object) 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 end
test "it strips internal reactions" do test "it strips internal reactions" do
@ -330,70 +314,46 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do
end end
test "it correctly processes messages with non-array to field" do 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 = %{ assert {:ok, activity} = Transmogrifier.handle_incoming(data)
"@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(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"] assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"]
end end
test "it correctly processes messages with non-array cc field" do 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 = %{ assert {:ok, activity} = Transmogrifier.handle_incoming(data)
"@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(message) assert ["http://mastodon.example.org/users/admin/followers"] == activity.data["cc"]
assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"]
assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["cc"]
assert [user.follower_address] == activity.data["to"]
end end
test "it correctly processes messages with weirdness in address fields" do 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 = %{ assert {:ok, activity} = Transmogrifier.handle_incoming(data)
"@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(message) assert ["http://mastodon.example.org/users/admin/followers"] == activity.data["cc"]
assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"]
assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["cc"]
assert [user.follower_address] == activity.data["to"]
end end
end end
@ -419,7 +379,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do
} do } do
clear_config([:instance, :federation_incoming_replies_max_depth], 10) 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 for id <- items do
job_args = %{"op" => "fetch_remote", "id" => id, "depth" => 1} 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: clear_config([:instance, :federation_incoming_replies_max_depth])
setup do 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} = %{activity: activity}
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}
end end
test "schedules background fetching of `replies` items if max thread depth limit allows", %{ test "schedules background fetching of `replies` items if max thread depth limit allows", %{
federation_output: federation_output, activity: activity
replies_uris: replies_uris
} do } do
clear_config([:instance, :federation_incoming_replies_max_depth], 1) 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} job_args = %{"op" => "fetch_remote", "id" => id, "depth" => 1}
assert_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker, args: job_args) assert_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker, args: job_args)
end end
end end
test "does NOT schedule background fetching of `replies` beyond max thread depth limit allows", 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) 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) == [] assert all_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker) == []
end end
@ -498,6 +455,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do
"object" => %{ "object" => %{
"to" => ["https://www.w3.org/ns/activitystreams#Public"], "to" => ["https://www.w3.org/ns/activitystreams#Public"],
"cc" => [], "cc" => [],
"id" => Utils.generate_object_id(),
"type" => "Note", "type" => "Note",
"content" => "Hi", "content" => "Hi",
"inReplyTo" => nil, "inReplyTo" => nil,
@ -522,6 +480,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do
"object" => %{ "object" => %{
"to" => ["https://www.w3.org/ns/activitystreams#Public"], "to" => ["https://www.w3.org/ns/activitystreams#Public"],
"cc" => [], "cc" => [],
"id" => Utils.generate_object_id(),
"type" => "Note", "type" => "Note",
"content" => "Hi", "content" => "Hi",
"inReplyTo" => nil, "inReplyTo" => nil,

View file

@ -11,6 +11,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
alias Pleroma.Tests.ObanHelpers alias Pleroma.Tests.ObanHelpers
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.AdminAPI.AccountView alias Pleroma.Web.AdminAPI.AccountView
alias Pleroma.Web.CommonAPI alias Pleroma.Web.CommonAPI
@ -159,8 +160,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
{:ok, activity} = CommonAPI.post(user, %{status: "hey"}) {:ok, activity} = CommonAPI.post(user, %{status: "hey"})
{:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
assert modified["@context"] == assert modified["@context"] == Utils.make_json_ld_header()["@context"]
Pleroma.Web.ActivityPub.Utils.make_json_ld_header()["@context"]
assert modified["object"]["conversation"] == modified["context"] assert modified["object"]["conversation"] == modified["context"]
end end
@ -446,7 +446,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
end) 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"])) assert Enum.all?(explicitly_mentioned_actors, &(&1 in fixed_object["to"]))
refute "https://social.beepboop.ga/users/dirb" 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"] assert "https://social.beepboop.ga/users/dirb" in fixed_object["cc"]
@ -459,7 +459,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
"cc" => [] "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"] assert user.follower_address in fixed_object["to"]
refute user.follower_address in fixed_object["cc"] refute user.follower_address in fixed_object["cc"]
end end
@ -473,7 +473,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
"cc" => [user.follower_address, recipient.follower_address] "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"] assert user.follower_address in fixed_object["cc"]
refute recipient.follower_address in fixed_object["cc"] refute recipient.follower_address in fixed_object["cc"]

View file

@ -539,8 +539,8 @@ defmodule Pleroma.Web.CommonAPITest do
spoiler_text: ":joker_smile:" spoiler_text: ":joker_smile:"
}) })
assert Object.normalize(reply_activity).data["emoji"][":joker_smile:"] assert Object.normalize(reply_activity).data["emoji"]["joker_smile"]
refute Object.normalize(reply_activity).data["emoji"][":joker_disapprove:"] refute Object.normalize(reply_activity).data["emoji"]["joker_disapprove"]
end end
test "deactivated users can't post" do test "deactivated users can't post" do

View file

@ -123,7 +123,8 @@ defmodule Pleroma.Web.FederatorTest do
"type" => "Note", "type" => "Note",
"content" => "hi world!", "content" => "hi world!",
"id" => "http://mastodon.example.org/users/admin/objects/1", "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"] "to" => ["https://www.w3.org/ns/activitystreams#Public"]
} }
@ -145,7 +146,8 @@ defmodule Pleroma.Web.FederatorTest do
"type" => "Note", "type" => "Note",
"content" => "hi world!", "content" => "hi world!",
"id" => "http://mastodon.example.org/users/admin/objects/1", "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"] "to" => ["https://www.w3.org/ns/activitystreams#Public"]
} }

View file

@ -7,6 +7,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.CommonAPI alias Pleroma.Web.CommonAPI
import Pleroma.Factory import Pleroma.Factory
@ -185,16 +186,16 @@ defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do
test "302 for remote cached status", %{conn: conn, user: user} do test "302 for remote cached status", %{conn: conn, user: user} do
message = %{ message = %{
"@context" => "https://www.w3.org/ns/activitystreams", "@context" => "https://www.w3.org/ns/activitystreams",
"to" => user.follower_address,
"cc" => "https://www.w3.org/ns/activitystreams#Public",
"type" => "Create", "type" => "Create",
"actor" => user.ap_id,
"object" => %{ "object" => %{
"to" => user.follower_address,
"cc" => "https://www.w3.org/ns/activitystreams#Public",
"id" => Utils.generate_object_id(),
"content" => "blah blah blah", "content" => "blah blah blah",
"type" => "Note", "type" => "Note",
"attributedTo" => user.ap_id, "attributedTo" => user.ap_id
"inReplyTo" => nil }
},
"actor" => user.ap_id
} }
assert {:ok, activity} = Transmogrifier.handle_incoming(message) assert {:ok, activity} = Transmogrifier.handle_incoming(message)