Merge branch 'from/upstream-develop/tusooa/report-anon' into 'develop'

Anonymize reports

Closes #2661 and #1024

See merge request pleroma/pleroma!3806
This commit is contained in:
lain 2025-09-05 12:15:19 +00:00
commit d1d7dd1827
19 changed files with 376 additions and 73 deletions

View file

@ -0,0 +1 @@
Fix reports being rejected when the activity had an empty CC or TO field (instead of not having them at all)

View file

@ -0,0 +1 @@
Allow anonymizing reports sent to remote servers

View file

@ -364,7 +364,9 @@ config :pleroma, :activitypub,
note_replies_output_limit: 5, note_replies_output_limit: 5,
sign_object_fetches: true, sign_object_fetches: true,
authorized_fetch_mode: false, authorized_fetch_mode: false,
client_api_enabled: false client_api_enabled: false,
anonymize_reporter: false,
anonymize_reporter_local_nickname: ""
config :pleroma, :streamer, config :pleroma, :streamer,
workers: 3, workers: 3,

View file

@ -1797,6 +1797,23 @@ config :pleroma, :config_description, [
key: :client_api_enabled, key: :client_api_enabled,
type: :boolean, type: :boolean,
description: "Allow client to server ActivityPub interactions" description: "Allow client to server ActivityPub interactions"
},
%{
key: :anonymize_reporter,
type: :boolean,
label: "Anonymize local reports",
description:
"If true, replace local reporters with the designated local user for the copy to be sent to remote servers"
},
%{
key: :anonymize_reporter_local_nickname,
type: :string,
label: "Anonymized reporter",
description:
"The nickname of the designated local user that replaces the actual reporter in the copy to be sent to remote servers",
suggestions: [
"lain"
]
} }
] ]
}, },

View file

@ -170,6 +170,10 @@ config :pleroma, Pleroma.Upload.Filter.Mogrify, config_impl: Pleroma.StaticStubb
config :pleroma, Pleroma.Upload.Filter.Mogrify, mogrify_impl: Pleroma.MogrifyMock config :pleroma, Pleroma.Upload.Filter.Mogrify, mogrify_impl: Pleroma.MogrifyMock
config :pleroma, Pleroma.Signature, http_signatures_impl: Pleroma.StubbedHTTPSignaturesMock config :pleroma, Pleroma.Signature, http_signatures_impl: Pleroma.StubbedHTTPSignaturesMock
config :pleroma, Pleroma.Web.ActivityPub.Publisher, signature_impl: Pleroma.SignatureMock
config :pleroma, Pleroma.Web.ActivityPub.Publisher,
transmogrifier_impl: Pleroma.Web.ActivityPub.TransmogrifierMock
peer_module = peer_module =
if String.to_integer(System.otp_release()) >= 25 do if String.to_integer(System.otp_release()) >= 25 do

View file

@ -3,6 +3,7 @@
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Signature do defmodule Pleroma.Signature do
@behaviour Pleroma.Signature.API
@behaviour HTTPSignatures.Adapter @behaviour HTTPSignatures.Adapter
alias Pleroma.EctoType.ActivityPub.ObjectValidators alias Pleroma.EctoType.ActivityPub.ObjectValidators

View file

@ -0,0 +1,14 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Signature.API do
@moduledoc """
Behaviour for signing requests and producing HTTP Date headers.
This is used to allow tests to replace the signing implementation with Mox.
"""
@callback sign(user :: Pleroma.User.t(), headers :: map()) :: String.t()
@callback signed_date() :: String.t()
end

View file

@ -414,10 +414,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
with flag_data <- make_flag_data(params, additional), with flag_data <- make_flag_data(params, additional),
{:ok, activity} <- insert(flag_data, local), {:ok, activity} <- insert(flag_data, local),
{:ok, stripped_activity} <- strip_report_status_data(activity),
_ <- notify_and_stream(activity), _ <- notify_and_stream(activity),
:ok <- :ok <- maybe_federate(activity) do
maybe_federate(stripped_activity) do
User.all_users_with_privilege(:reports_manage_reports) User.all_users_with_privilege(:reports_manage_reports)
|> Enum.filter(fn user -> user.ap_id != actor end) |> Enum.filter(fn user -> user.ap_id != actor end)
|> Enum.filter(fn user -> not is_nil(user.email) end) |> Enum.filter(fn user -> not is_nil(user.email) end)

View file

@ -13,7 +13,6 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.Publisher.Prepared alias Pleroma.Web.ActivityPub.Publisher.Prepared
alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Workers.PublisherWorker alias Pleroma.Workers.PublisherWorker
require Pleroma.Constants require Pleroma.Constants
@ -26,6 +25,18 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
ActivityPub outgoing federation module. ActivityPub outgoing federation module.
""" """
@signature_impl Application.compile_env(
:pleroma,
[__MODULE__, :signature_impl],
Pleroma.Signature
)
@transmogrifier_impl Application.compile_env(
:pleroma,
[__MODULE__, :transmogrifier_impl],
Pleroma.Web.ActivityPub.Transmogrifier
)
@doc """ @doc """
Enqueue publishing a single activity. Enqueue publishing a single activity.
""" """
@ -68,7 +79,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
Determine if an activity can be represented by running it through Transmogrifier. Determine if an activity can be represented by running it through Transmogrifier.
""" """
def representable?(%Activity{} = activity) do def representable?(%Activity{} = activity) do
with {:ok, _data} <- Transmogrifier.prepare_outgoing(activity.data) do with {:ok, _data} <- @transmogrifier_impl.prepare_outgoing(activity.data) do
true true
else else
_e -> _e ->
@ -91,7 +102,17 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
Logger.debug("Federating #{ap_id} to #{inbox}") Logger.debug("Federating #{ap_id} to #{inbox}")
uri = %{path: path} = URI.parse(inbox) uri = %{path: path} = URI.parse(inbox)
{:ok, data} = Transmogrifier.prepare_outgoing(activity.data) {:ok, data} = @transmogrifier_impl.prepare_outgoing(activity.data)
{actor, data} =
with {_, false} <- {:actor_changed?, data["actor"] != activity.data["actor"]} do
{actor, data}
else
{:actor_changed?, true} ->
# If prepare_outgoing changes the actor, re-get it from the db
new_actor = User.get_cached_by_ap_id(data["actor"])
{new_actor, data}
end
param_cc = Map.get(params, :cc, []) param_cc = Map.get(params, :cc, [])
@ -115,10 +136,10 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
digest = "SHA-256=" <> (:crypto.hash(:sha256, json) |> Base.encode64()) digest = "SHA-256=" <> (:crypto.hash(:sha256, json) |> Base.encode64())
date = Pleroma.Signature.signed_date() date = @signature_impl.signed_date()
signature = signature =
Pleroma.Signature.sign(actor, %{ @signature_impl.sign(actor, %{
"(request-target)": "post #{path}", "(request-target)": "post #{path}",
host: signature_host(uri), host: signature_host(uri),
"content-length": byte_size(json), "content-length": byte_size(json),

View file

@ -6,6 +6,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
@moduledoc """ @moduledoc """
A module to handle coding from internal to wire ActivityPub and back. A module to handle coding from internal to wire ActivityPub and back.
""" """
@behaviour Pleroma.Web.ActivityPub.Transmogrifier.API
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.EctoType.ActivityPub.ObjectValidators alias Pleroma.EctoType.ActivityPub.ObjectValidators
alias Pleroma.Maps alias Pleroma.Maps
@ -909,6 +910,14 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end end
end end
def prepare_outgoing(%{"type" => "Flag"} = data) do
with {:ok, stripped_activity} <- Utils.strip_report_status_data(data),
stripped_activity <- Utils.maybe_anonymize_reporter(stripped_activity),
stripped_activity <- Map.merge(stripped_activity, Utils.make_json_ld_header()) do
{:ok, stripped_activity}
end
end
def prepare_outgoing(%{"type" => _type} = data) do def prepare_outgoing(%{"type" => _type} = data) do
data = data =
data data

View file

@ -0,0 +1,11 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Transmogrifier.API do
@moduledoc """
Behaviour for the subset of Transmogrifier used by Publisher.
"""
@callback prepare_outgoing(map()) :: {:ok, map()} | {:error, term()}
end

View file

@ -82,7 +82,11 @@ defmodule Pleroma.Web.ActivityPub.Utils do
def unaddressed_message?(params), def unaddressed_message?(params),
do: do:
[params["to"], params["cc"], params["bto"], params["bcc"]] [params["to"], params["cc"], params["bto"], params["bcc"]]
|> Enum.all?(&is_nil(&1)) |> Enum.all?(fn
nil -> true
[] -> true
_ -> false
end)
@spec recipient_in_message(User.t(), User.t(), map()) :: boolean() @spec recipient_in_message(User.t(), User.t(), map()) :: boolean()
def recipient_in_message(%User{ap_id: ap_id} = recipient, %User{} = actor, params), def recipient_in_message(%User{ap_id: ap_id} = recipient, %User{} = actor, params),
@ -859,8 +863,14 @@ defmodule Pleroma.Web.ActivityPub.Utils do
def update_report_state(_, _), do: {:error, "Unsupported state"} def update_report_state(_, _), do: {:error, "Unsupported state"}
def strip_report_status_data(activity) do def strip_report_status_data(%Activity{} = activity) do
[actor | reported_activities] = activity.data["object"] with {:ok, new_data} <- strip_report_status_data(activity.data) do
{:ok, %{activity | data: new_data}}
end
end
def strip_report_status_data(data) do
[actor | reported_activities] = data["object"]
stripped_activities = stripped_activities =
Enum.reduce(reported_activities, [], fn act, acc -> Enum.reduce(reported_activities, [], fn act, acc ->
@ -870,9 +880,36 @@ defmodule Pleroma.Web.ActivityPub.Utils do
end end
end) end)
new_data = put_in(activity.data, ["object"], [actor | stripped_activities]) new_data = put_in(data, ["object"], [actor | stripped_activities])
{:ok, %{activity | data: new_data}} {:ok, new_data}
end
def get_anonymized_reporter do
with true <- Pleroma.Config.get([:activitypub, :anonymize_reporter]),
nickname when is_binary(nickname) <-
Pleroma.Config.get([:activitypub, :anonymize_reporter_local_nickname]),
%User{ap_id: ap_id, local: true} <- User.get_cached_by_nickname(nickname) do
ap_id
else
_ -> nil
end
end
def maybe_anonymize_reporter(%Activity{data: data} = activity) do
new_data = maybe_anonymize_reporter(data)
%Activity{activity | actor: new_data["actor"], data: new_data}
end
def maybe_anonymize_reporter(activity) do
ap_id = get_anonymized_reporter()
if is_binary(ap_id) do
activity
|> Map.put("actor", ap_id)
else
activity
end
end end
def update_activity_visibility(activity, visibility) when visibility in @valid_visibilities do def update_activity_visibility(activity, visibility) when visibility in @valid_visibilities do

View file

@ -1152,9 +1152,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
} }
], ],
"actor" => actor.ap_id, "actor" => actor.ap_id,
"cc" => [ # CC and TO might either not exist at all, or be empty. We should be able to handle either.
reported_user.ap_id # "cc" => [],
],
"content" => "test", "content" => "test",
"context" => "context", "context" => "context",
"id" => "http://#{remote_domain}/activities/02be56cf-35e3-46b4-b2c6-47ae08dfee9e", "id" => "http://#{remote_domain}/activities/02be56cf-35e3-46b4-b2c6-47ae08dfee9e",

View file

@ -1691,32 +1691,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
} = activity } = activity
end end
test_with_mock "strips status data from Flag, before federating it",
%{
reporter: reporter,
context: context,
target_account: target_account,
reported_activity: reported_activity,
object_ap_id: object_ap_id,
content: content
},
Utils,
[:passthrough],
[] do
{:ok, activity} =
ActivityPub.flag(%{
actor: reporter,
context: context,
account: target_account,
statuses: [reported_activity],
content: content
})
new_data = put_in(activity.data, ["object"], [target_account.ap_id, object_ap_id])
assert_called(Utils.maybe_federate(%{activity | data: new_data}))
end
test_with_mock "reverts on error", test_with_mock "reverts on error",
%{ %{
reporter: reporter, reporter: reporter,

View file

@ -8,12 +8,13 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
import Pleroma.Factory import Pleroma.Factory
import Tesla.Mock import Tesla.Mock
import Mock
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.Tests.ObanHelpers alias Pleroma.Tests.ObanHelpers
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Publisher alias Pleroma.Web.ActivityPub.Publisher
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.CommonAPI alias Pleroma.Web.CommonAPI
@as_public "https://www.w3.org/ns/activitystreams#Public" @as_public "https://www.w3.org/ns/activitystreams#Public"
@ -168,10 +169,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
end end
describe "publish/2" do describe "publish/2" do
test_with_mock "doesn't publish a non-public activity to quarantined instances.", test "doesn't publish a non-public activity to quarantined instances." do
Pleroma.Web.ActivityPub.Publisher,
[:passthrough],
[] do
Config.put([:instance, :quarantined_instances], [{"domain.com", "some reason"}]) Config.put([:instance, :quarantined_instances], [{"domain.com", "some reason"}])
follower = follower =
@ -206,10 +204,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
) )
end end
test_with_mock "Publishes a non-public activity to non-quarantined instances.", test "Publishes a non-public activity to non-quarantined instances." do
Pleroma.Web.ActivityPub.Publisher,
[:passthrough],
[] do
Config.put([:instance, :quarantined_instances], [{"somedomain.com", "some reason"}]) Config.put([:instance, :quarantined_instances], [{"somedomain.com", "some reason"}])
follower = follower =
@ -245,10 +240,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
) )
end end
test_with_mock "Publishes to directly addressed actors with higher priority.", test "Publishes to directly addressed actors with higher priority." do
Pleroma.Web.ActivityPub.Publisher,
[:passthrough],
[] do
note_activity = insert(:direct_note_activity) note_activity = insert(:direct_note_activity)
actor = Pleroma.User.get_by_ap_id(note_activity.data["actor"]) actor = Pleroma.User.get_by_ap_id(note_activity.data["actor"])
@ -257,21 +249,58 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
assert res == :ok assert res == :ok
assert called( assert_enqueued(
Publisher.enqueue_one( worker: "Pleroma.Workers.PublisherWorker",
%{ args: %{
inbox: :_, "op" => "publish_one",
activity_id: note_activity.id "params" => %{"activity_id" => note_activity.id}
}, },
priority: 0 priority: 0
) )
)
end end
test_with_mock "publishes an activity with BCC to all relevant peers.", test "Publishes with the new actor if prepare_outgoing changes the actor." do
Pleroma.Web.ActivityPub.Publisher, mock(fn
[:passthrough], %{method: :post, url: "https://domain.com/users/nick1/inbox", body: body} ->
[] do {:ok, %Tesla.Env{status: 200, body: body}}
end)
other_user =
insert(:user, %{
local: false,
inbox: "https://domain.com/users/nick1/inbox"
})
actor = insert(:user)
replaced_actor = insert(:user)
note_activity =
insert(:note_activity,
user: actor,
data_attrs: %{"to" => [other_user.ap_id]}
)
Pleroma.Web.ActivityPub.TransmogrifierMock
|> Mox.expect(:prepare_outgoing, fn data ->
{:ok, Map.put(data, "actor", replaced_actor.ap_id)}
end)
prepared =
Publisher.prepare_one(%{
inbox: "https://domain.com/users/nick1/inbox",
activity_id: note_activity.id,
cc: ["https://domain.com/users/nick2/inbox"]
})
{:ok, decoded} = Jason.decode(prepared.json)
assert decoded["actor"] == replaced_actor.ap_id
{:ok, published} = Publisher.publish_one(prepared)
sent_activity = Jason.decode!(published.body)
assert sent_activity["actor"] == replaced_actor.ap_id
end
test "publishes an activity with BCC to all relevant peers." do
follower = follower =
insert(:user, %{ insert(:user, %{
local: false, local: false,
@ -303,10 +332,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
) )
end end
test_with_mock "publishes a delete activity to peers who signed fetch requests to the create acitvity/object.", test "publishes a delete activity to peers who signed fetch requests to the create acitvity/object." do
Pleroma.Web.ActivityPub.Publisher,
[:passthrough],
[] do
fetcher = fetcher =
insert(:user, insert(:user,
local: false, local: false,
@ -510,4 +536,43 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
assert decoded["cc"] == ["https://example.com/specific/user"] assert decoded["cc"] == ["https://example.com/specific/user"]
end end
describe "prepare_one/1 with reporter anonymization" do
test "signs with the anonymized actor keys when Transmogrifier changes actor" do
Pleroma.SignatureMock
|> Mox.stub(:signed_date, fn -> Pleroma.Signature.signed_date() end)
|> Mox.expect(:sign, fn %Pleroma.User{} = user, _headers ->
send(self(), {:signed_as, user.ap_id})
"TESTSIG"
end)
placeholder = insert(:user)
reporter = insert(:user)
target_account = insert(:user)
clear_config([:activitypub, :anonymize_reporter], true)
clear_config([:activitypub, :anonymize_reporter_local_nickname], placeholder.nickname)
{:ok, reported} = CommonAPI.post(target_account, %{status: "content"})
context = Utils.generate_context_id()
{:ok, activity} =
ActivityPub.flag(%{
actor: reporter,
context: context,
account: target_account,
statuses: [reported],
content: "reason"
})
_prepared =
Publisher.prepare_one(%{
inbox: "http://remote.example/users/alice/inbox",
activity_id: activity.id
})
assert_received {:signed_as, ap_id}
assert ap_id == placeholder.ap_id
end
end
end end

View file

@ -642,6 +642,69 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert [_, _, %{"@language" => "pl"}] = modified["@context"] assert [_, _, %{"@language" => "pl"}] = modified["@context"]
end end
test "it strips report data" do
reporter = insert(:user)
target_account = insert(:user)
content = "foobar"
{:ok, reported_activity} = CommonAPI.post(target_account, %{status: content})
context = Utils.generate_context_id()
object_ap_id = reported_activity.object.data["id"]
assert {:ok, activity} =
Pleroma.Web.ActivityPub.ActivityPub.flag(%{
actor: reporter,
context: context,
account: target_account,
statuses: [reported_activity],
content: content
})
{:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
expected_data =
activity.data
|> put_in(["object"], [target_account.ap_id, object_ap_id])
|> Map.put("actor", reporter.ap_id)
|> Map.merge(Utils.make_json_ld_header())
assert data == expected_data
end
test "it strips report data and anonymize" do
placeholder = insert(:user)
reporter = insert(:user)
target_account = insert(:user)
content = "foobar"
{:ok, reported_activity} = CommonAPI.post(target_account, %{status: content})
context = Utils.generate_context_id()
object_ap_id = reported_activity.object.data["id"]
assert {:ok, activity} =
Pleroma.Web.ActivityPub.ActivityPub.flag(%{
actor: reporter,
context: context,
account: target_account,
statuses: [reported_activity],
content: content
})
clear_config([:activitypub, :anonymize_reporter], true)
clear_config([:activitypub, :anonymize_reporter_local_nickname], placeholder.nickname)
{:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
expected_data =
activity.data
|> put_in(["object"], [target_account.ap_id, object_ap_id])
|> Map.put("actor", placeholder.ap_id)
|> Map.merge(Utils.make_json_ld_header())
assert data == expected_data
end
end end
describe "actor rewriting" do describe "actor rewriting" do

View file

@ -670,4 +670,78 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
) )
end end
end end
describe "maybe_anonymize_reporter/1" do
setup do
reporter = insert(:user)
report = %{"actor" => reporter.ap_id}
%{
placeholder: insert(:user),
reporter: reporter,
report: report
}
end
test "anonymize when configured correctly", %{
placeholder: placeholder,
report: report
} do
clear_config([:activitypub, :anonymize_reporter], true)
clear_config([:activitypub, :anonymize_reporter_local_nickname], placeholder.nickname)
assert %{"actor" => placeholder.ap_id} == Utils.maybe_anonymize_reporter(report)
end
test "anonymize Activity", %{
placeholder: placeholder,
reporter: reporter,
report: report
} do
clear_config([:activitypub, :anonymize_reporter], true)
clear_config([:activitypub, :anonymize_reporter_local_nickname], placeholder.nickname)
report_activity = %Activity{actor: reporter, data: report}
anon_id = placeholder.ap_id
assert %Activity{actor: ^anon_id, data: %{"actor" => ^anon_id}} =
Utils.maybe_anonymize_reporter(report_activity)
end
test "do not anonymize when disabled", %{
placeholder: placeholder,
reporter: reporter,
report: report
} do
clear_config([:activitypub, :anonymize_reporter], false)
clear_config([:activitypub, :anonymize_reporter_local_nickname], placeholder.nickname)
assert %{"actor" => reporter.ap_id} == Utils.maybe_anonymize_reporter(report)
end
test "do not anonymize when user does not exist", %{
placeholder: placeholder,
reporter: reporter,
report: report
} do
clear_config([:activitypub, :anonymize_reporter], true)
clear_config(
[:activitypub, :anonymize_reporter_local_nickname],
placeholder.nickname <> "MewMew"
)
assert %{"actor" => reporter.ap_id} == Utils.maybe_anonymize_reporter(report)
end
test "do not anonymize when user is not local", %{
reporter: reporter,
report: report
} do
placeholder = insert(:user, local: false)
clear_config([:activitypub, :anonymize_reporter], true)
clear_config([:activitypub, :anonymize_reporter_local_nickname], placeholder.nickname)
assert %{"actor" => reporter.ap_id} == Utils.maybe_anonymize_reporter(report)
end
end
end end

View file

@ -119,6 +119,12 @@ defmodule Pleroma.DataCase do
Mox.stub_with(Pleroma.StubbedHTTPSignaturesMock, Pleroma.Test.HTTPSignaturesProxy) Mox.stub_with(Pleroma.StubbedHTTPSignaturesMock, Pleroma.Test.HTTPSignaturesProxy)
Mox.stub_with(Pleroma.DateTimeMock, Pleroma.DateTime.Impl) Mox.stub_with(Pleroma.DateTimeMock, Pleroma.DateTime.Impl)
Mox.stub_with(Pleroma.SignatureMock, Pleroma.Signature)
Mox.stub_with(
Pleroma.Web.ActivityPub.TransmogrifierMock,
Pleroma.Web.ActivityPub.Transmogrifier
)
end end
def ensure_local_uploader(context) do def ensure_local_uploader(context) do

View file

@ -40,3 +40,9 @@ Mox.defmock(Pleroma.Language.LanguageDetectorMock,
Mox.defmock(Pleroma.DateTimeMock, for: Pleroma.DateTime) Mox.defmock(Pleroma.DateTimeMock, for: Pleroma.DateTime)
Mox.defmock(Pleroma.MogrifyMock, for: Pleroma.MogrifyBehaviour) Mox.defmock(Pleroma.MogrifyMock, for: Pleroma.MogrifyBehaviour)
Mox.defmock(Pleroma.SignatureMock, for: Pleroma.Signature.API)
Mox.defmock(Pleroma.Web.ActivityPub.TransmogrifierMock,
for: Pleroma.Web.ActivityPub.Transmogrifier.API
)