Merge remote-tracking branch 'origin/develop' into post-languages
This commit is contained in:
commit
3e5517e7bb
655 changed files with 2268 additions and 1748 deletions
|
|
@ -222,10 +222,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
%{data: %{"expires_at" => %DateTime{} = expires_at}} = activity
|
||||
) do
|
||||
with {:ok, _job} <-
|
||||
Pleroma.Workers.PurgeExpiredActivity.enqueue(%{
|
||||
activity_id: activity.id,
|
||||
expires_at: expires_at
|
||||
}) do
|
||||
Pleroma.Workers.PurgeExpiredActivity.enqueue(
|
||||
%{
|
||||
activity_id: activity.id
|
||||
},
|
||||
scheduled_at: expires_at
|
||||
) do
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
|
@ -446,10 +448,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
_ <- notify_and_stream(activity) do
|
||||
maybe_federate(activity)
|
||||
|
||||
BackgroundWorker.enqueue("move_following", %{
|
||||
BackgroundWorker.new(%{
|
||||
"op" => "move_following",
|
||||
"origin_id" => origin.id,
|
||||
"target_id" => target.id
|
||||
})
|
||||
|> Oban.insert()
|
||||
|
||||
{:ok, activity}
|
||||
else
|
||||
|
|
@ -1797,10 +1801,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
# enqueue a task to fetch all pinned objects
|
||||
Enum.each(pins, fn {ap_id, _} ->
|
||||
if is_nil(Object.get_cached_by_ap_id(ap_id)) do
|
||||
Pleroma.Workers.RemoteFetcherWorker.enqueue("fetch_remote", %{
|
||||
Pleroma.Workers.RemoteFetcherWorker.new(%{
|
||||
"op" => "fetch_remote",
|
||||
"id" => ap_id,
|
||||
"depth" => 1
|
||||
})
|
||||
|> Oban.insert()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -63,20 +63,20 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy do
|
|||
end
|
||||
|
||||
@impl true
|
||||
def filter(%{"type" => "Follow", "actor" => actor_id} = message) do
|
||||
def filter(%{"type" => "Follow", "actor" => actor_id} = activity) do
|
||||
%User{} = actor = normalize_by_ap_id(actor_id)
|
||||
|
||||
score = determine_if_followbot(actor)
|
||||
|
||||
if score < 0.8 || bot_allowed?(message, actor) do
|
||||
{:ok, message}
|
||||
if score < 0.8 || bot_allowed?(activity, actor) do
|
||||
{:ok, activity}
|
||||
else
|
||||
{:reject, "[AntiFollowbotPolicy] Scored #{actor_id} as #{score}"}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(message), do: {:ok, message}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
|
|
|
|||
|
|
@ -29,17 +29,17 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy do
|
|||
defp contains_links?(_), do: false
|
||||
|
||||
@impl true
|
||||
def filter(%{"type" => "Create", "actor" => actor, "object" => object} = message) do
|
||||
def filter(%{"type" => "Create", "actor" => actor, "object" => object} = activity) do
|
||||
with {:ok, %User{local: false} = u} <- User.get_or_fetch_by_ap_id(actor),
|
||||
{:contains_links, true} <- {:contains_links, contains_links?(object)},
|
||||
{:old_user, true} <- {:old_user, old_user?(u)} do
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
else
|
||||
{:ok, %User{local: true}} ->
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
|
||||
{:contains_links, false} ->
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
|
||||
{:old_user, false} ->
|
||||
{:reject, "[AntiLinkSpamPolicy] User has no posts nor followers"}
|
||||
|
|
@ -53,7 +53,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy do
|
|||
end
|
||||
|
||||
# in all other cases, pass through
|
||||
def filter(message), do: {:ok, message}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
|
|
|
|||
|
|
@ -22,11 +22,11 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiMentionSpamPolicy do
|
|||
end
|
||||
|
||||
# copied from HellthreadPolicy
|
||||
defp get_recipient_count(message) do
|
||||
recipients = (message["to"] || []) ++ (message["cc"] || [])
|
||||
defp get_recipient_count(activity) do
|
||||
recipients = (activity["to"] || []) ++ (activity["cc"] || [])
|
||||
|
||||
follower_collection =
|
||||
User.get_cached_by_ap_id(message["actor"] || message["attributedTo"]).follower_address
|
||||
User.get_cached_by_ap_id(activity["actor"] || activity["attributedTo"]).follower_address
|
||||
|
||||
if Enum.member?(recipients, Pleroma.Constants.as_public()) do
|
||||
recipients =
|
||||
|
|
@ -80,7 +80,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiMentionSpamPolicy do
|
|||
end
|
||||
|
||||
# in all other cases, pass through
|
||||
def filter(message), do: {:ok, message}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
|
|
|
|||
|
|
@ -38,18 +38,18 @@ defmodule Pleroma.Web.ActivityPub.MRF.DNSRBLPolicy do
|
|||
@query_timeout 500
|
||||
|
||||
@impl true
|
||||
def filter(%{"actor" => actor} = object) do
|
||||
def filter(%{"actor" => actor} = activity) do
|
||||
actor_info = URI.parse(actor)
|
||||
|
||||
with {:ok, object} <- check_rbl(actor_info, object) do
|
||||
{:ok, object}
|
||||
with {:ok, activity} <- check_rbl(actor_info, activity) do
|
||||
{:ok, activity}
|
||||
else
|
||||
_ -> {:reject, "[DNSRBLPolicy]"}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(object), do: {:ok, object}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe do
|
||||
|
|
@ -90,7 +90,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.DNSRBLPolicy do
|
|||
}
|
||||
end
|
||||
|
||||
defp check_rbl(%{host: actor_host}, object) do
|
||||
defp check_rbl(%{host: actor_host}, activity) do
|
||||
with false <- match?(^actor_host, Pleroma.Web.Endpoint.host()),
|
||||
zone when not is_nil(zone) <- Keyword.get(Config.get([:mrf_dnsrbl]), :zone) do
|
||||
query =
|
||||
|
|
@ -100,7 +100,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.DNSRBLPolicy do
|
|||
rbl_response = rblquery(query)
|
||||
|
||||
if Enum.empty?(rbl_response) do
|
||||
{:ok, object}
|
||||
{:ok, activity}
|
||||
else
|
||||
Task.start(fn ->
|
||||
reason =
|
||||
|
|
@ -117,7 +117,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.DNSRBLPolicy do
|
|||
:error
|
||||
end
|
||||
else
|
||||
_ -> {:ok, object}
|
||||
_ -> {:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.DropPolicy do
|
|||
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||
|
||||
@impl true
|
||||
def filter(object) do
|
||||
Logger.debug("REJECTING #{inspect(object)}")
|
||||
{:reject, object}
|
||||
def filter(activity) do
|
||||
Logger.debug("REJECTING #{inspect(activity)}")
|
||||
{:reject, activity}
|
||||
end
|
||||
|
||||
@impl true
|
||||
|
|
|
|||
|
|
@ -28,11 +28,11 @@ defmodule Pleroma.Web.ActivityPub.MRF.EmojiPolicy do
|
|||
Pleroma.Config.get([:mrf_emoji, :federated_timeline_removal_shortcode], [])
|
||||
end
|
||||
|
||||
@impl Pleroma.Web.ActivityPub.MRF.Policy
|
||||
@impl true
|
||||
def history_awareness, do: :manual
|
||||
|
||||
@impl Pleroma.Web.ActivityPub.MRF.Policy
|
||||
def filter(%{"type" => type, "object" => %{"type" => objtype} = object} = message)
|
||||
@impl true
|
||||
def filter(%{"type" => type, "object" => %{"type" => objtype} = object} = activity)
|
||||
when type in ["Create", "Update"] and objtype in Pleroma.Constants.status_object_types() do
|
||||
with {:ok, object} <-
|
||||
Updater.do_with_history(object, fn object ->
|
||||
|
|
@ -42,13 +42,13 @@ defmodule Pleroma.Web.ActivityPub.MRF.EmojiPolicy do
|
|||
Updater.do_with_history(object, fn object ->
|
||||
{:ok, process_remove(object, :shortcode, config_remove_shortcode())}
|
||||
end),
|
||||
activity <- Map.put(message, "object", object),
|
||||
activity <- Map.put(activity, "object", object),
|
||||
activity <- maybe_delist(activity) do
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
@impl Pleroma.Web.ActivityPub.MRF.Policy
|
||||
@impl true
|
||||
def filter(%{"type" => type} = object) when type in Pleroma.Constants.actor_types() do
|
||||
with object <- process_remove(object, :url, config_remove_url()),
|
||||
object <- process_remove(object, :shortcode, config_remove_shortcode()) do
|
||||
|
|
@ -56,7 +56,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.EmojiPolicy do
|
|||
end
|
||||
end
|
||||
|
||||
@impl Pleroma.Web.ActivityPub.MRF.Policy
|
||||
@impl true
|
||||
def filter(%{"type" => "EmojiReact"} = object) do
|
||||
with {:ok, _} <-
|
||||
matched_emoji_checker(config_remove_url(), config_remove_shortcode()).(object) do
|
||||
|
|
@ -67,9 +67,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.EmojiPolicy do
|
|||
end
|
||||
end
|
||||
|
||||
@impl Pleroma.Web.ActivityPub.MRF.Policy
|
||||
def filter(message) do
|
||||
{:ok, message}
|
||||
@impl true
|
||||
def filter(activity) do
|
||||
{:ok, activity}
|
||||
end
|
||||
|
||||
defp match_string?(string, pattern) when is_binary(pattern) do
|
||||
|
|
@ -214,7 +214,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.EmojiPolicy do
|
|||
)
|
||||
end
|
||||
|
||||
@impl Pleroma.Web.ActivityPub.MRF.Policy
|
||||
@impl true
|
||||
def describe do
|
||||
mrf_emoji =
|
||||
Pleroma.Config.get(:mrf_emoji, [])
|
||||
|
|
@ -226,7 +226,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.EmojiPolicy do
|
|||
{:ok, %{mrf_emoji: mrf_emoji}}
|
||||
end
|
||||
|
||||
@impl Pleroma.Web.ActivityPub.MRF.Policy
|
||||
@impl true
|
||||
def config_description do
|
||||
%{
|
||||
key: :mrf_emoji,
|
||||
|
|
@ -239,7 +239,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.EmojiPolicy do
|
|||
key: :remove_url,
|
||||
type: {:list, :string},
|
||||
description: """
|
||||
A list of patterns which result in emoji whose URL matches being removed from the message. This will apply to statuses, emoji reactions, and user profiles.
|
||||
A list of patterns which result in emoji whose URL matches being removed from the activity. This will apply to statuses, emoji reactions, and user profiles.
|
||||
|
||||
Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.
|
||||
""",
|
||||
|
|
@ -249,7 +249,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.EmojiPolicy do
|
|||
key: :remove_shortcode,
|
||||
type: {:list, :string},
|
||||
description: """
|
||||
A list of patterns which result in emoji whose shortcode matches being removed from the message. This will apply to statuses, emoji reactions, and user profiles.
|
||||
A list of patterns which result in emoji whose shortcode matches being removed from the activity. This will apply to statuses, emoji reactions, and user profiles.
|
||||
|
||||
Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.
|
||||
""",
|
||||
|
|
@ -259,7 +259,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.EmojiPolicy do
|
|||
key: :federated_timeline_removal_url,
|
||||
type: {:list, :string},
|
||||
description: """
|
||||
A list of patterns which result in message with emojis whose URLs match being removed from federated timelines (a.k.a unlisted). This will apply only to statuses.
|
||||
A list of patterns which result in activity with emojis whose URLs match being removed from federated timelines (a.k.a unlisted). This will apply only to statuses.
|
||||
|
||||
Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.
|
||||
""",
|
||||
|
|
@ -269,7 +269,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.EmojiPolicy do
|
|||
key: :federated_timeline_removal_shortcode,
|
||||
type: {:list, :string},
|
||||
description: """
|
||||
A list of patterns which result in message with emojis whose shortcodes match being removed from federated timelines (a.k.a unlisted). This will apply only to statuses.
|
||||
A list of patterns which result in activities with emojis whose shortcodes match being removed from federated timelines (a.k.a unlisted). This will apply only to statuses.
|
||||
|
||||
Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.
|
||||
""",
|
||||
|
|
|
|||
|
|
@ -29,19 +29,19 @@ defmodule Pleroma.Web.ActivityPub.MRF.EnsureRePrepended do
|
|||
|
||||
def filter_by_summary(_in_reply_to, child), do: child
|
||||
|
||||
def filter(%{"type" => type, "object" => child_object} = object)
|
||||
when type in ["Create", "Update"] and is_map(child_object) do
|
||||
def filter(%{"type" => type, "object" => object} = activity)
|
||||
when type in ["Create", "Update"] and is_map(object) do
|
||||
child =
|
||||
child_object["inReplyTo"]
|
||||
object["inReplyTo"]
|
||||
|> Object.normalize(fetch: false)
|
||||
|> filter_by_summary(child_object)
|
||||
|> filter_by_summary(object)
|
||||
|
||||
object = Map.put(object, "object", child)
|
||||
activity = Map.put(activity, "object", child)
|
||||
|
||||
{:ok, object}
|
||||
{:ok, activity}
|
||||
end
|
||||
|
||||
def filter(object), do: {:ok, object}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
def describe, do: {:ok, %{}}
|
||||
end
|
||||
|
|
|
|||
53
lib/pleroma/web/activity_pub/mrf/fo_direct_reply.ex
Normal file
53
lib/pleroma/web/activity_pub/mrf/fo_direct_reply.ex
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.MRF.FODirectReply do
|
||||
@moduledoc """
|
||||
FODirectReply alters the scope of replies to activities which are Followers Only to be Direct. The purpose of this policy is to prevent broken threads for followers of the reply author because their response was to a user that they are not also following.
|
||||
"""
|
||||
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.Visibility
|
||||
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||
|
||||
@impl true
|
||||
def filter(
|
||||
%{
|
||||
"type" => "Create",
|
||||
"to" => to,
|
||||
"object" => %{
|
||||
"actor" => actor,
|
||||
"type" => "Note",
|
||||
"inReplyTo" => in_reply_to
|
||||
}
|
||||
} = activity
|
||||
) do
|
||||
with true <- is_binary(in_reply_to),
|
||||
%User{follower_address: followers_collection, local: true} <- User.get_by_ap_id(actor),
|
||||
%Object{} = in_reply_to_object <- Object.get_by_ap_id(in_reply_to),
|
||||
"private" <- Visibility.get_visibility(in_reply_to_object) do
|
||||
direct_to = to -- [followers_collection]
|
||||
|
||||
updated_activity =
|
||||
activity
|
||||
|> Map.put("cc", [])
|
||||
|> Map.put("to", direct_to)
|
||||
|> Map.put("directMessage", true)
|
||||
|> put_in(["object", "cc"], [])
|
||||
|> put_in(["object", "to"], direct_to)
|
||||
|
||||
{:ok, updated_activity}
|
||||
else
|
||||
_ -> {:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
end
|
||||
|
|
@ -11,12 +11,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.FollowBotPolicy do
|
|||
require Logger
|
||||
|
||||
@impl true
|
||||
def filter(message) do
|
||||
def filter(activity) do
|
||||
with follower_nickname <- Config.get([:mrf_follow_bot, :follower_nickname]),
|
||||
%User{actor_type: "Service"} = follower <-
|
||||
User.get_cached_by_nickname(follower_nickname),
|
||||
%{"type" => "Create", "object" => %{"type" => "Note"}} <- message do
|
||||
try_follow(follower, message)
|
||||
%{"type" => "Create", "object" => %{"type" => "Note"}} <- activity do
|
||||
try_follow(follower, activity)
|
||||
else
|
||||
nil ->
|
||||
Logger.warning(
|
||||
|
|
@ -24,17 +24,17 @@ defmodule Pleroma.Web.ActivityPub.MRF.FollowBotPolicy do
|
|||
account does not exist, or the account is not correctly configured as a bot."
|
||||
)
|
||||
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
|
||||
_ ->
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
defp try_follow(follower, message) do
|
||||
to = Map.get(message, "to", [])
|
||||
cc = Map.get(message, "cc", [])
|
||||
actor = [message["actor"]]
|
||||
defp try_follow(follower, activity) do
|
||||
to = Map.get(activity, "to", [])
|
||||
cc = Map.get(activity, "cc", [])
|
||||
actor = [activity["actor"]]
|
||||
|
||||
Enum.concat([to, cc, actor])
|
||||
|> List.flatten()
|
||||
|
|
@ -53,7 +53,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.FollowBotPolicy do
|
|||
end
|
||||
end)
|
||||
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
end
|
||||
|
||||
@impl true
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ForceBotUnlistedPolicy do
|
|||
"cc" => cc,
|
||||
"actor" => actor,
|
||||
"object" => object
|
||||
} = message
|
||||
} = activity
|
||||
) do
|
||||
user = User.get_cached_by_ap_id(actor)
|
||||
isbot = check_if_bot(user)
|
||||
|
|
@ -36,20 +36,20 @@ defmodule Pleroma.Web.ActivityPub.MRF.ForceBotUnlistedPolicy do
|
|||
|> Map.put("to", to)
|
||||
|> Map.put("cc", cc)
|
||||
|
||||
message =
|
||||
message
|
||||
activity =
|
||||
activity
|
||||
|> Map.put("to", to)
|
||||
|> Map.put("cc", cc)
|
||||
|> Map.put("object", object)
|
||||
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
else
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(message), do: {:ok, message}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ForceMention do
|
|||
end
|
||||
|
||||
@impl true
|
||||
def filter(object), do: {:ok, object}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
|
|
|
|||
|
|
@ -79,18 +79,18 @@ defmodule Pleroma.Web.ActivityPub.MRF.ForceMentionsInContent do
|
|||
%{
|
||||
"type" => type,
|
||||
"object" => %{"type" => "Note", "to" => to, "inReplyTo" => in_reply_to}
|
||||
} = object
|
||||
} = activity
|
||||
)
|
||||
when type in ["Create", "Update"] and is_list(to) and is_binary(in_reply_to) do
|
||||
# image-only posts from pleroma apparently reach this MRF without the content field
|
||||
content = object["object"]["content"] || ""
|
||||
content = activity["object"]["content"] || ""
|
||||
|
||||
# Get the replied-to user for sorting
|
||||
replied_to_user = get_replied_to_user(object["object"])
|
||||
replied_to_user = get_replied_to_user(activity["object"])
|
||||
|
||||
mention_users =
|
||||
to
|
||||
|> clean_recipients(object)
|
||||
|> clean_recipients(activity)
|
||||
|> Enum.map(&User.get_cached_by_ap_id/1)
|
||||
|> Enum.reject(&is_nil/1)
|
||||
|> sort_replied_user(replied_to_user)
|
||||
|
|
@ -126,11 +126,11 @@ defmodule Pleroma.Web.ActivityPub.MRF.ForceMentionsInContent do
|
|||
content
|
||||
end
|
||||
|
||||
{:ok, put_in(object["object"]["content"], content)}
|
||||
{:ok, put_in(activity["object"]["content"], content)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(object), do: {:ok, object}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HashtagPolicy do
|
|||
alias Pleroma.Object
|
||||
|
||||
@moduledoc """
|
||||
Reject, TWKN-remove or Set-Sensitive messages with specific hashtags (without the leading #)
|
||||
Reject, TWKN-remove or Set-Sensitive activities with specific hashtags (without the leading #)
|
||||
|
||||
Note: This MRF Policy is always enabled, if you want to disable it you have to set empty lists.
|
||||
"""
|
||||
|
|
@ -19,40 +19,40 @@ defmodule Pleroma.Web.ActivityPub.MRF.HashtagPolicy do
|
|||
@impl true
|
||||
def history_awareness, do: :manual
|
||||
|
||||
defp check_reject(message, hashtags) do
|
||||
defp check_reject(activity, hashtags) do
|
||||
if Enum.any?(Config.get([:mrf_hashtag, :reject]), fn match -> match in hashtags end) do
|
||||
{:reject, "[HashtagPolicy] Matches with rejected keyword"}
|
||||
else
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
defp check_ftl_removal(%{"to" => to} = message, hashtags) do
|
||||
defp check_ftl_removal(%{"to" => to} = activity, hashtags) do
|
||||
if Pleroma.Constants.as_public() in to and
|
||||
Enum.any?(Config.get([:mrf_hashtag, :federated_timeline_removal]), fn match ->
|
||||
match in hashtags
|
||||
end) do
|
||||
to = List.delete(to, Pleroma.Constants.as_public())
|
||||
cc = [Pleroma.Constants.as_public() | message["cc"] || []]
|
||||
cc = [Pleroma.Constants.as_public() | activity["cc"] || []]
|
||||
|
||||
message =
|
||||
message
|
||||
activity =
|
||||
activity
|
||||
|> Map.put("to", to)
|
||||
|> Map.put("cc", cc)
|
||||
|> Kernel.put_in(["object", "to"], to)
|
||||
|> Kernel.put_in(["object", "cc"], cc)
|
||||
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
else
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
defp check_ftl_removal(message, _hashtags), do: {:ok, message}
|
||||
defp check_ftl_removal(activity, _hashtags), do: {:ok, activity}
|
||||
|
||||
defp check_sensitive(message) do
|
||||
defp check_sensitive(activity) do
|
||||
{:ok, new_object} =
|
||||
Object.Updater.do_with_history(message["object"], fn object ->
|
||||
Object.Updater.do_with_history(activity["object"], fn object ->
|
||||
hashtags = Object.hashtags(%Object{data: object})
|
||||
|
||||
if Enum.any?(Config.get([:mrf_hashtag, :sensitive]), fn match -> match in hashtags end) do
|
||||
|
|
@ -62,11 +62,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.HashtagPolicy do
|
|||
end
|
||||
end)
|
||||
|
||||
{:ok, Map.put(message, "object", new_object)}
|
||||
{:ok, Map.put(activity, "object", new_object)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(%{"type" => type, "object" => object} = message) when type in ["Create", "Update"] do
|
||||
def filter(%{"type" => type, "object" => object} = activity)
|
||||
when type in ["Create", "Update"] do
|
||||
history_items =
|
||||
with %{"formerRepresentations" => %{"orderedItems" => items}} <- object do
|
||||
items
|
||||
|
|
@ -82,23 +83,23 @@ defmodule Pleroma.Web.ActivityPub.MRF.HashtagPolicy do
|
|||
hashtags = Object.hashtags(%Object{data: object}) ++ historical_hashtags
|
||||
|
||||
if hashtags != [] do
|
||||
with {:ok, message} <- check_reject(message, hashtags),
|
||||
{:ok, message} <-
|
||||
with {:ok, activity} <- check_reject(activity, hashtags),
|
||||
{:ok, activity} <-
|
||||
(if type == "Create" do
|
||||
check_ftl_removal(message, hashtags)
|
||||
check_ftl_removal(activity, hashtags)
|
||||
else
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
end),
|
||||
{:ok, message} <- check_sensitive(message) do
|
||||
{:ok, message}
|
||||
{:ok, activity} <- check_sensitive(activity) do
|
||||
{:ok, activity}
|
||||
end
|
||||
else
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(message), do: {:ok, message}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe do
|
||||
|
|
@ -120,21 +121,21 @@ defmodule Pleroma.Web.ActivityPub.MRF.HashtagPolicy do
|
|||
%{
|
||||
key: :reject,
|
||||
type: {:list, :string},
|
||||
description: "A list of hashtags which result in message being rejected.",
|
||||
description: "A list of hashtags which result in the activity being rejected.",
|
||||
suggestions: ["foo"]
|
||||
},
|
||||
%{
|
||||
key: :federated_timeline_removal,
|
||||
type: {:list, :string},
|
||||
description:
|
||||
"A list of hashtags which result in message being removed from federated timelines (a.k.a unlisted).",
|
||||
"A list of hashtags which result in the activity being removed from federated timelines (a.k.a unlisted).",
|
||||
suggestions: ["foo"]
|
||||
},
|
||||
%{
|
||||
key: :sensitive,
|
||||
type: {:list, :string},
|
||||
description:
|
||||
"A list of hashtags which result in message being set as sensitive (a.k.a NSFW/R-18)",
|
||||
"A list of hashtags which result in the activity being set as sensitive (a.k.a NSFW/R-18)",
|
||||
suggestions: ["nsfw", "r18"]
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -7,54 +7,54 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do
|
|||
|
||||
require Pleroma.Constants
|
||||
|
||||
@moduledoc "Block messages with too much mentions (configurable)"
|
||||
@moduledoc "Block activities with too much mentions (configurable)"
|
||||
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||
|
||||
defp delist_message(message, threshold) when threshold > 0 do
|
||||
follower_collection = User.get_cached_by_ap_id(message["actor"]).follower_address
|
||||
to = message["to"] || []
|
||||
cc = message["cc"] || []
|
||||
defp delist_activity(activity, threshold) when threshold > 0 do
|
||||
follower_collection = User.get_cached_by_ap_id(activity["actor"]).follower_address
|
||||
to = activity["to"] || []
|
||||
cc = activity["cc"] || []
|
||||
|
||||
follower_collection? = Enum.member?(to ++ cc, follower_collection)
|
||||
|
||||
message =
|
||||
case get_recipient_count(message) do
|
||||
activity =
|
||||
case get_recipient_count(activity) do
|
||||
{:public, recipients}
|
||||
when follower_collection? and recipients > threshold ->
|
||||
message
|
||||
activity
|
||||
|> Map.put("to", [follower_collection])
|
||||
|> Map.put("cc", [Pleroma.Constants.as_public()])
|
||||
|
||||
{:public, recipients} when recipients > threshold ->
|
||||
message
|
||||
activity
|
||||
|> Map.put("to", [])
|
||||
|> Map.put("cc", [Pleroma.Constants.as_public()])
|
||||
|
||||
_ ->
|
||||
message
|
||||
activity
|
||||
end
|
||||
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
end
|
||||
|
||||
defp delist_message(message, _threshold), do: {:ok, message}
|
||||
defp delist_activity(activity, _threshold), do: {:ok, activity}
|
||||
|
||||
defp reject_message(message, threshold) when threshold > 0 do
|
||||
with {_, recipients} <- get_recipient_count(message) do
|
||||
defp reject_activity(activity, threshold) when threshold > 0 do
|
||||
with {_, recipients} <- get_recipient_count(activity) do
|
||||
if recipients > threshold do
|
||||
{:reject, "[HellthreadPolicy] #{recipients} recipients is over the limit of #{threshold}"}
|
||||
else
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp reject_message(message, _threshold), do: {:ok, message}
|
||||
defp reject_activity(activity, _threshold), do: {:ok, activity}
|
||||
|
||||
defp get_recipient_count(message) do
|
||||
recipients = (message["to"] || []) ++ (message["cc"] || [])
|
||||
follower_collection = User.get_cached_by_ap_id(message["actor"]).follower_address
|
||||
defp get_recipient_count(activity) do
|
||||
recipients = (activity["to"] || []) ++ (activity["cc"] || [])
|
||||
follower_collection = User.get_cached_by_ap_id(activity["actor"]).follower_address
|
||||
|
||||
if Enum.member?(recipients, Pleroma.Constants.as_public()) do
|
||||
recipients =
|
||||
|
|
@ -73,7 +73,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do
|
|||
end
|
||||
|
||||
@impl true
|
||||
def filter(%{"type" => "Create", "object" => %{"type" => object_type}} = message)
|
||||
def filter(%{"type" => "Create", "object" => %{"type" => object_type}} = activity)
|
||||
when object_type in ~w{Note Article} do
|
||||
reject_threshold =
|
||||
Pleroma.Config.get(
|
||||
|
|
@ -83,16 +83,16 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do
|
|||
|
||||
delist_threshold = Pleroma.Config.get([:mrf_hellthread, :delist_threshold])
|
||||
|
||||
with {:ok, message} <- reject_message(message, reject_threshold),
|
||||
{:ok, message} <- delist_message(message, delist_threshold) do
|
||||
{:ok, message}
|
||||
with {:ok, activity} <- reject_activity(activity, reject_threshold),
|
||||
{:ok, activity} <- delist_activity(activity, delist_threshold) do
|
||||
{:ok, activity}
|
||||
else
|
||||
e -> e
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(message), do: {:ok, message}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe,
|
||||
|
|
@ -104,13 +104,13 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do
|
|||
key: :mrf_hellthread,
|
||||
related_policy: "Pleroma.Web.ActivityPub.MRF.HellthreadPolicy",
|
||||
label: "MRF Hellthread",
|
||||
description: "Block messages with excessive user mentions",
|
||||
description: "Block activities with excessive user mentions",
|
||||
children: [
|
||||
%{
|
||||
key: :delist_threshold,
|
||||
type: :integer,
|
||||
description:
|
||||
"Number of mentioned users after which the message gets removed from timelines and" <>
|
||||
"Number of mentioned users after which the activity gets removed from timelines and" <>
|
||||
"disables notifications. Set to 0 to disable.",
|
||||
suggestions: [10]
|
||||
},
|
||||
|
|
@ -118,7 +118,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do
|
|||
key: :reject_threshold,
|
||||
type: :integer,
|
||||
description:
|
||||
"Number of mentioned users after which the messaged gets rejected. Set to 0 to disable.",
|
||||
"Number of mentioned users after which the activity gets rejected. Set to 0 to disable.",
|
||||
suggestions: [20]
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -48,12 +48,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy do
|
|||
end
|
||||
|
||||
@impl true
|
||||
def filter(object), do: {:ok, object}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
|
||||
@impl Pleroma.Web.ActivityPub.MRF.Policy
|
||||
@impl true
|
||||
def history_awareness, do: :auto
|
||||
|
||||
@impl true
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
|
|||
|
||||
alias Pleroma.Web.ActivityPub.MRF.Utils
|
||||
|
||||
@moduledoc "Reject or Word-Replace messages with a keyword or regex"
|
||||
@moduledoc "Reject or Word-Replace activities with a keyword or regex"
|
||||
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
|
|||
|> Enum.join("\n")
|
||||
end
|
||||
|
||||
defp check_reject(%{"object" => %{} = object} = message) do
|
||||
defp check_reject(%{"object" => %{} = object} = activity) do
|
||||
with {:ok, _new_object} <-
|
||||
Pleroma.Object.Updater.do_with_history(object, fn object ->
|
||||
payload = object_payload(object)
|
||||
|
|
@ -35,16 +35,16 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
|
|||
end) do
|
||||
{:reject, "[KeywordPolicy] Matches with rejected keyword"}
|
||||
else
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
end
|
||||
end) do
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
else
|
||||
e -> e
|
||||
end
|
||||
end
|
||||
|
||||
defp check_ftl_removal(%{"type" => "Create", "to" => to, "object" => %{} = object} = message) do
|
||||
defp check_ftl_removal(%{"type" => "Create", "to" => to, "object" => %{} = object} = activity) do
|
||||
check_keyword = fn object ->
|
||||
payload = object_payload(object)
|
||||
|
||||
|
|
@ -67,24 +67,24 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
|
|||
|
||||
if Pleroma.Constants.as_public() in to and should_delist?.(object) do
|
||||
to = List.delete(to, Pleroma.Constants.as_public())
|
||||
cc = [Pleroma.Constants.as_public() | message["cc"] || []]
|
||||
cc = [Pleroma.Constants.as_public() | activity["cc"] || []]
|
||||
|
||||
message =
|
||||
message
|
||||
activity =
|
||||
activity
|
||||
|> Map.put("to", to)
|
||||
|> Map.put("cc", cc)
|
||||
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
else
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
defp check_ftl_removal(message) do
|
||||
{:ok, message}
|
||||
defp check_ftl_removal(activity) do
|
||||
{:ok, activity}
|
||||
end
|
||||
|
||||
defp check_replace(%{"object" => %{} = object} = message) do
|
||||
defp check_replace(%{"object" => %{} = object} = activity) do
|
||||
replace_kw = fn object ->
|
||||
["content", "name", "summary"]
|
||||
|> Enum.filter(fn field -> Map.has_key?(object, field) && object[field] end)
|
||||
|
|
@ -103,18 +103,18 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
|
|||
|
||||
{:ok, object} = Pleroma.Object.Updater.do_with_history(object, replace_kw)
|
||||
|
||||
message = Map.put(message, "object", object)
|
||||
activity = Map.put(activity, "object", object)
|
||||
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(%{"type" => type, "object" => %{"content" => _content}} = message)
|
||||
def filter(%{"type" => type, "object" => %{"content" => _content}} = activity)
|
||||
when type in ["Create", "Update"] do
|
||||
with {:ok, message} <- check_reject(message),
|
||||
{:ok, message} <- check_ftl_removal(message),
|
||||
{:ok, message} <- check_replace(message) do
|
||||
{:ok, message}
|
||||
with {:ok, activity} <- check_reject(activity),
|
||||
{:ok, activity} <- check_ftl_removal(activity),
|
||||
{:ok, activity} <- check_replace(activity) do
|
||||
{:ok, activity}
|
||||
else
|
||||
{:reject, nil} -> {:reject, "[KeywordPolicy] "}
|
||||
{:reject, _} = e -> e
|
||||
|
|
@ -123,7 +123,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
|
|||
end
|
||||
|
||||
@impl true
|
||||
def filter(message), do: {:ok, message}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe do
|
||||
|
|
@ -154,13 +154,13 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
|
|||
related_policy: "Pleroma.Web.ActivityPub.MRF.KeywordPolicy",
|
||||
label: "MRF Keyword",
|
||||
description:
|
||||
"Reject or Word-Replace messages matching a keyword or [Regex](https://hexdocs.pm/elixir/Regex.html).",
|
||||
"Reject or Word-Replace activities matching a keyword or [Regex](https://hexdocs.pm/elixir/Regex.html).",
|
||||
children: [
|
||||
%{
|
||||
key: :reject,
|
||||
type: {:list, :string},
|
||||
description: """
|
||||
A list of patterns which result in message being rejected.
|
||||
A list of patterns which result in the activity being rejected.
|
||||
|
||||
Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.
|
||||
""",
|
||||
|
|
@ -170,7 +170,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
|
|||
key: :federated_timeline_removal,
|
||||
type: {:list, :string},
|
||||
description: """
|
||||
A list of patterns which result in message being removed from federated timelines (a.k.a unlisted).
|
||||
A list of patterns which result in the activity being removed from federated timelines (a.k.a unlisted).
|
||||
|
||||
Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.
|
||||
""",
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do
|
|||
HTTP.get(url, [], http_client_opts)
|
||||
end
|
||||
|
||||
defp preload(%{"object" => %{"attachment" => attachments}} = _message) do
|
||||
defp preload(%{"object" => %{"attachment" => attachments}} = _activity) do
|
||||
Enum.each(attachments, fn
|
||||
%{"url" => url} when is_list(url) ->
|
||||
url
|
||||
|
|
@ -49,15 +49,15 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do
|
|||
end
|
||||
|
||||
@impl true
|
||||
def filter(%{"type" => type, "object" => %{"attachment" => attachments} = _object} = message)
|
||||
def filter(%{"type" => type, "object" => %{"attachment" => attachments} = _object} = activity)
|
||||
when type in ["Create", "Update"] and is_list(attachments) and length(attachments) > 0 do
|
||||
preload(message)
|
||||
preload(activity)
|
||||
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(message), do: {:ok, message}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
|
|
|
|||
|
|
@ -3,25 +3,25 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicy do
|
||||
@moduledoc "Block messages which mention a user"
|
||||
@moduledoc "Block activities which mention a user"
|
||||
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||
|
||||
@impl true
|
||||
def filter(%{"type" => "Create"} = message) do
|
||||
def filter(%{"type" => "Create"} = activity) do
|
||||
reject_actors = Pleroma.Config.get([:mrf_mention, :actors], [])
|
||||
recipients = (message["to"] || []) ++ (message["cc"] || [])
|
||||
recipients = (activity["to"] || []) ++ (activity["cc"] || [])
|
||||
|
||||
if rejected_mention =
|
||||
Enum.find(recipients, fn recipient -> Enum.member?(reject_actors, recipient) end) do
|
||||
{:reject, "[MentionPolicy] Rejected for mention of #{rejected_mention}"}
|
||||
else
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(message), do: {:ok, message}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
|
|
@ -32,7 +32,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicy do
|
|||
key: :mrf_mention,
|
||||
related_policy: "Pleroma.Web.ActivityPub.MRF.MentionPolicy",
|
||||
label: "MRF Mention",
|
||||
description: "Block messages which mention a specific user",
|
||||
description: "Block activities which mention a specific user",
|
||||
children: [
|
||||
%{
|
||||
key: :actors,
|
||||
|
|
|
|||
|
|
@ -9,20 +9,20 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy do
|
|||
alias Pleroma.Web.Endpoint
|
||||
|
||||
@impl true
|
||||
def filter(%{"actor" => actor} = object) do
|
||||
def filter(%{"actor" => actor} = activity) do
|
||||
with true <- local?(actor),
|
||||
true <- eligible_type?(object),
|
||||
true <- note?(object),
|
||||
false <- has_attachment?(object),
|
||||
true <- only_mentions?(object) do
|
||||
true <- eligible_type?(activity),
|
||||
true <- note?(activity),
|
||||
false <- has_attachment?(activity),
|
||||
true <- only_mentions?(activity) do
|
||||
{:reject, "[NoEmptyPolicy]"}
|
||||
else
|
||||
_ ->
|
||||
{:ok, object}
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
def filter(object), do: {:ok, object}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
defp local?(actor) do
|
||||
if actor |> String.starts_with?("#{Endpoint.url()}") do
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoOpPolicy do
|
|||
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||
|
||||
@impl true
|
||||
def filter(object) do
|
||||
{:ok, object}
|
||||
def filter(activity) do
|
||||
{:ok, activity}
|
||||
end
|
||||
|
||||
@impl true
|
||||
|
|
|
|||
|
|
@ -13,15 +13,15 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoPlaceholderTextPolicy do
|
|||
def filter(
|
||||
%{
|
||||
"type" => type,
|
||||
"object" => %{"content" => content, "attachment" => _} = _child_object
|
||||
} = object
|
||||
"object" => %{"content" => content, "attachment" => _} = _object
|
||||
} = activity
|
||||
)
|
||||
when type in ["Create", "Update"] and content in [".", "<p>.</p>"] do
|
||||
{:ok, put_in(object, ["object", "content"], "")}
|
||||
{:ok, put_in(activity, ["object", "content"], "")}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(object), do: {:ok, object}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
|
|
|
|||
|
|
@ -12,20 +12,20 @@ defmodule Pleroma.Web.ActivityPub.MRF.NormalizeMarkup do
|
|||
def history_awareness, do: :auto
|
||||
|
||||
@impl true
|
||||
def filter(%{"type" => type, "object" => child_object} = object)
|
||||
def filter(%{"type" => type, "object" => object} = activity)
|
||||
when type in ["Create", "Update"] do
|
||||
scrub_policy = Pleroma.Config.get([:mrf_normalize_markup, :scrub_policy])
|
||||
|
||||
content =
|
||||
child_object["content"]
|
||||
object["content"]
|
||||
|> HTML.filter_tags(scrub_policy)
|
||||
|
||||
object = put_in(object, ["object", "content"], content)
|
||||
activity = put_in(activity, ["object", "content"], content)
|
||||
|
||||
{:ok, object}
|
||||
{:ok, activity}
|
||||
end
|
||||
|
||||
def filter(object), do: {:ok, object}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
|
|
|
|||
|
|
@ -122,52 +122,52 @@ defmodule Pleroma.Web.ActivityPub.MRF.NsfwApiPolicy do
|
|||
end
|
||||
end
|
||||
|
||||
def check_object_nsfw(%{"object" => %{} = child_object} = object) do
|
||||
case check_object_nsfw(child_object) do
|
||||
{:sfw, _} -> {:sfw, object}
|
||||
{:nsfw, _} -> {:nsfw, object}
|
||||
def check_object_nsfw(%{"object" => %{} = object} = activity) do
|
||||
case check_object_nsfw(object) do
|
||||
{:sfw, _} -> {:sfw, activity}
|
||||
{:nsfw, _} -> {:nsfw, activity}
|
||||
end
|
||||
end
|
||||
|
||||
def check_object_nsfw(object), do: {:sfw, object}
|
||||
|
||||
@impl true
|
||||
def filter(object) do
|
||||
with {:sfw, object} <- check_object_nsfw(object) do
|
||||
{:ok, object}
|
||||
def filter(activity) do
|
||||
with {:sfw, activity} <- check_object_nsfw(activity) do
|
||||
{:ok, activity}
|
||||
else
|
||||
{:nsfw, _data} -> handle_nsfw(object)
|
||||
{:nsfw, _data} -> handle_nsfw(activity)
|
||||
end
|
||||
end
|
||||
|
||||
defp handle_nsfw(object) do
|
||||
defp handle_nsfw(activity) do
|
||||
if Config.get([@policy, :reject]) do
|
||||
{:reject, object}
|
||||
{:reject, activity}
|
||||
else
|
||||
{:ok,
|
||||
object
|
||||
activity
|
||||
|> maybe_unlist()
|
||||
|> maybe_mark_sensitive()}
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_unlist(object) do
|
||||
defp maybe_unlist(activity) do
|
||||
if Config.get([@policy, :unlist]) do
|
||||
unlist(object)
|
||||
unlist(activity)
|
||||
else
|
||||
object
|
||||
activity
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_mark_sensitive(object) do
|
||||
defp maybe_mark_sensitive(activity) do
|
||||
if Config.get([@policy, :mark_sensitive]) do
|
||||
mark_sensitive(object)
|
||||
mark_sensitive(activity)
|
||||
else
|
||||
object
|
||||
activity
|
||||
end
|
||||
end
|
||||
|
||||
def unlist(%{"to" => to, "cc" => cc, "actor" => actor} = object) do
|
||||
def unlist(%{"to" => to, "cc" => cc, "actor" => actor} = activity) do
|
||||
with %User{} = user <- User.get_cached_by_ap_id(actor) do
|
||||
to =
|
||||
[user.follower_address | to]
|
||||
|
|
@ -179,7 +179,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.NsfwApiPolicy do
|
|||
|> List.delete(user.follower_address)
|
||||
|> Enum.uniq()
|
||||
|
||||
object
|
||||
activity
|
||||
|> Map.put("to", to)
|
||||
|> Map.put("cc", cc)
|
||||
else
|
||||
|
|
@ -187,14 +187,14 @@ defmodule Pleroma.Web.ActivityPub.MRF.NsfwApiPolicy do
|
|||
end
|
||||
end
|
||||
|
||||
def mark_sensitive(%{"object" => child_object} = object) when is_map(child_object) do
|
||||
Map.put(object, "object", mark_sensitive(child_object))
|
||||
def mark_sensitive(%{"object" => object} = activity) when is_map(object) do
|
||||
Map.put(activity, "object", mark_sensitive(object))
|
||||
end
|
||||
|
||||
def mark_sensitive(object) when is_map(object) do
|
||||
tags = (object["tag"] || []) ++ ["nsfw"]
|
||||
def mark_sensitive(activity) when is_map(activity) do
|
||||
tags = (activity["tag"] || []) ++ ["nsfw"]
|
||||
|
||||
object
|
||||
activity
|
||||
|> Map.put("tag", tags)
|
||||
|> Map.put("sensitive", true)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do
|
|||
@moduledoc "Filter activities depending on their age"
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||
|
||||
defp check_date(%{"object" => %{"published" => published}} = message) do
|
||||
defp check_date(%{"object" => %{"published" => published}} = activity) do
|
||||
with %DateTime{} = now <- DateTime.utc_now(),
|
||||
{:ok, %DateTime{} = then, _} <- DateTime.from_iso8601(published),
|
||||
max_ttl <- Config.get([:mrf_object_age, :threshold]),
|
||||
{:ttl, false} <- {:ttl, DateTime.diff(now, then) > max_ttl} do
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
else
|
||||
{:ttl, true} ->
|
||||
{:reject, nil}
|
||||
|
|
@ -26,73 +26,73 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do
|
|||
end
|
||||
end
|
||||
|
||||
defp check_reject(message, actions) do
|
||||
defp check_reject(activity, actions) do
|
||||
if :reject in actions do
|
||||
{:reject, "[ObjectAgePolicy]"}
|
||||
else
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
defp check_delist(message, actions) do
|
||||
defp check_delist(activity, actions) do
|
||||
if :delist in actions do
|
||||
with %User{} = user <- User.get_cached_by_ap_id(message["actor"]) do
|
||||
with %User{} = user <- User.get_cached_by_ap_id(activity["actor"]) do
|
||||
to =
|
||||
List.delete(message["to"] || [], Pleroma.Constants.as_public()) ++
|
||||
List.delete(activity["to"] || [], Pleroma.Constants.as_public()) ++
|
||||
[user.follower_address]
|
||||
|
||||
cc =
|
||||
List.delete(message["cc"] || [], user.follower_address) ++
|
||||
List.delete(activity["cc"] || [], user.follower_address) ++
|
||||
[Pleroma.Constants.as_public()]
|
||||
|
||||
message =
|
||||
message
|
||||
activity =
|
||||
activity
|
||||
|> Map.put("to", to)
|
||||
|> Map.put("cc", cc)
|
||||
|> Kernel.put_in(["object", "to"], to)
|
||||
|> Kernel.put_in(["object", "cc"], cc)
|
||||
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
else
|
||||
_e ->
|
||||
{:reject, "[ObjectAgePolicy] Unhandled error"}
|
||||
end
|
||||
else
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
defp check_strip_followers(message, actions) do
|
||||
defp check_strip_followers(activity, actions) do
|
||||
if :strip_followers in actions do
|
||||
with %User{} = user <- User.get_cached_by_ap_id(message["actor"]) do
|
||||
to = List.delete(message["to"] || [], user.follower_address)
|
||||
cc = List.delete(message["cc"] || [], user.follower_address)
|
||||
with %User{} = user <- User.get_cached_by_ap_id(activity["actor"]) do
|
||||
to = List.delete(activity["to"] || [], user.follower_address)
|
||||
cc = List.delete(activity["cc"] || [], user.follower_address)
|
||||
|
||||
message =
|
||||
message
|
||||
activity =
|
||||
activity
|
||||
|> Map.put("to", to)
|
||||
|> Map.put("cc", cc)
|
||||
|> Kernel.put_in(["object", "to"], to)
|
||||
|> Kernel.put_in(["object", "cc"], cc)
|
||||
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
else
|
||||
_e ->
|
||||
{:reject, "[ObjectAgePolicy] Unhandled error"}
|
||||
end
|
||||
else
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(%{"type" => "Create", "object" => %{"published" => _}} = message) do
|
||||
def filter(%{"type" => "Create", "object" => %{"published" => _}} = activity) do
|
||||
with actions <- Config.get([:mrf_object_age, :actions]),
|
||||
{:reject, _} <- check_date(message),
|
||||
{:ok, message} <- check_reject(message, actions),
|
||||
{:ok, message} <- check_delist(message, actions),
|
||||
{:ok, message} <- check_strip_followers(message, actions) do
|
||||
{:ok, message}
|
||||
{:reject, _} <- check_date(activity),
|
||||
{:ok, activity} <- check_reject(activity, actions),
|
||||
{:ok, activity} <- check_delist(activity, actions),
|
||||
{:ok, activity} <- check_strip_followers(activity, actions) do
|
||||
{:ok, activity}
|
||||
else
|
||||
# check_date() is allowed to short-circuit the pipeline
|
||||
e -> e
|
||||
|
|
@ -100,7 +100,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do
|
|||
end
|
||||
|
||||
@impl true
|
||||
def filter(message), do: {:ok, message}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe do
|
||||
|
|
@ -131,8 +131,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do
|
|||
type: {:list, :atom},
|
||||
description:
|
||||
"A list of actions to apply to the post. `:delist` removes the post from public timelines; " <>
|
||||
"`:strip_followers` removes followers from the ActivityPub recipient list ensuring they won't be delivered to home timelines, additionally for followers-only it degrades to a direct message; " <>
|
||||
"`:reject` rejects the message entirely",
|
||||
"`:strip_followers` removes followers from the ActivityPub recipient list ensuring they won't be delivered to home timelines, additionally for followers-only it degrades to a direct activity; " <>
|
||||
"`:reject` rejects the activity entirely",
|
||||
suggestions: [:delist, :strip_followers, :reject]
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.MRF.Policy do
|
||||
@callback filter(map()) :: {:ok | :reject, map()}
|
||||
@callback filter(Pleroma.Activity.t()) :: {:ok | :reject, Pleroma.Activity.t()}
|
||||
@callback describe() :: {:ok | :error, map()}
|
||||
@callback config_description() :: %{
|
||||
optional(:children) => [map()],
|
||||
|
|
|
|||
60
lib/pleroma/web/activity_pub/mrf/quiet_reply.ex
Normal file
60
lib/pleroma/web/activity_pub/mrf/quiet_reply.ex
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2023 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.MRF.QuietReply do
|
||||
@moduledoc """
|
||||
QuietReply alters the scope of activities from local users when replying by enforcing them to be "Unlisted" or "Quiet Public". This delivers the activity to all the expected recipients and instances, but it will not be published in the Federated / The Whole Known Network timelines. It will still be published to the Home timelines of the user's followers and visible to anyone who opens the thread.
|
||||
"""
|
||||
require Pleroma.Constants
|
||||
|
||||
alias Pleroma.User
|
||||
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||
|
||||
@impl true
|
||||
def history_awareness, do: :auto
|
||||
|
||||
@impl true
|
||||
def filter(
|
||||
%{
|
||||
"type" => "Create",
|
||||
"to" => to,
|
||||
"cc" => cc,
|
||||
"object" => %{
|
||||
"actor" => actor,
|
||||
"type" => "Note",
|
||||
"inReplyTo" => in_reply_to
|
||||
}
|
||||
} = activity
|
||||
) do
|
||||
with true <- is_binary(in_reply_to),
|
||||
false <- match?([], cc),
|
||||
%User{follower_address: followers_collection, local: true} <-
|
||||
User.get_by_ap_id(actor) do
|
||||
updated_to =
|
||||
to
|
||||
|> Kernel.++([followers_collection])
|
||||
|> Kernel.--([Pleroma.Constants.as_public()])
|
||||
|
||||
updated_cc = [Pleroma.Constants.as_public()]
|
||||
|
||||
updated_activity =
|
||||
activity
|
||||
|> Map.put("to", updated_to)
|
||||
|> Map.put("cc", updated_cc)
|
||||
|> put_in(["object", "to"], updated_to)
|
||||
|> put_in(["object", "cc"], updated_cc)
|
||||
|
||||
{:ok, updated_activity}
|
||||
else
|
||||
_ -> {:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
end
|
||||
|
|
@ -10,18 +10,18 @@ defmodule Pleroma.Web.ActivityPub.MRF.QuoteToLinkTagPolicy do
|
|||
|
||||
require Pleroma.Constants
|
||||
|
||||
@impl Pleroma.Web.ActivityPub.MRF.Policy
|
||||
@impl true
|
||||
def filter(%{"object" => %{"quoteUrl" => _} = object} = activity) do
|
||||
{:ok, Map.put(activity, "object", filter_object(object))}
|
||||
end
|
||||
|
||||
@impl Pleroma.Web.ActivityPub.MRF.Policy
|
||||
def filter(object), do: {:ok, object}
|
||||
@impl true
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl Pleroma.Web.ActivityPub.MRF.Policy
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
|
||||
@impl Pleroma.Web.ActivityPub.MRF.Policy
|
||||
@impl true
|
||||
def history_awareness, do: :auto
|
||||
|
||||
defp filter_object(%{"quoteUrl" => quote_url} = object) do
|
||||
|
|
|
|||
|
|
@ -13,20 +13,20 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
|||
|
||||
require Pleroma.Constants
|
||||
|
||||
defp check_accept(%{host: actor_host} = _actor_info, object) do
|
||||
defp check_accept(%{host: actor_host} = _actor_info, activity) do
|
||||
accepts =
|
||||
instance_list(:accept)
|
||||
|> MRF.subdomains_regex()
|
||||
|
||||
cond do
|
||||
accepts == [] -> {:ok, object}
|
||||
actor_host == Config.get([Pleroma.Web.Endpoint, :url, :host]) -> {:ok, object}
|
||||
MRF.subdomain_match?(accepts, actor_host) -> {:ok, object}
|
||||
accepts == [] -> {:ok, activity}
|
||||
actor_host == Config.get([Pleroma.Web.Endpoint, :url, :host]) -> {:ok, activity}
|
||||
MRF.subdomain_match?(accepts, actor_host) -> {:ok, activity}
|
||||
true -> {:reject, "[SimplePolicy] host not in accept list"}
|
||||
end
|
||||
end
|
||||
|
||||
defp check_reject(%{host: actor_host} = _actor_info, object) do
|
||||
defp check_reject(%{host: actor_host} = _actor_info, activity) do
|
||||
rejects =
|
||||
instance_list(:reject)
|
||||
|> MRF.subdomains_regex()
|
||||
|
|
@ -34,109 +34,109 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
|||
if MRF.subdomain_match?(rejects, actor_host) do
|
||||
{:reject, "[SimplePolicy] host in reject list"}
|
||||
else
|
||||
{:ok, object}
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
defp check_media_removal(
|
||||
%{host: actor_host} = _actor_info,
|
||||
%{"type" => type, "object" => %{"attachment" => child_attachment}} = object
|
||||
%{"type" => type, "object" => %{"attachment" => object_attachment}} = activity
|
||||
)
|
||||
when length(child_attachment) > 0 and type in ["Create", "Update"] do
|
||||
when length(object_attachment) > 0 and type in ["Create", "Update"] do
|
||||
media_removal =
|
||||
instance_list(:media_removal)
|
||||
|> MRF.subdomains_regex()
|
||||
|
||||
object =
|
||||
activity =
|
||||
if MRF.subdomain_match?(media_removal, actor_host) do
|
||||
child_object = Map.delete(object["object"], "attachment")
|
||||
Map.put(object, "object", child_object)
|
||||
object = Map.delete(activity["object"], "attachment")
|
||||
Map.put(activity, "object", object)
|
||||
else
|
||||
object
|
||||
activity
|
||||
end
|
||||
|
||||
{:ok, object}
|
||||
{:ok, activity}
|
||||
end
|
||||
|
||||
defp check_media_removal(_actor_info, object), do: {:ok, object}
|
||||
defp check_media_removal(_actor_info, activity), do: {:ok, activity}
|
||||
|
||||
defp check_media_nsfw(
|
||||
%{host: actor_host} = _actor_info,
|
||||
%{
|
||||
"type" => type,
|
||||
"object" => %{} = _child_object
|
||||
} = object
|
||||
"object" => %{} = _object
|
||||
} = activity
|
||||
)
|
||||
when type in ["Create", "Update"] do
|
||||
media_nsfw =
|
||||
instance_list(:media_nsfw)
|
||||
|> MRF.subdomains_regex()
|
||||
|
||||
object =
|
||||
activity =
|
||||
if MRF.subdomain_match?(media_nsfw, actor_host) do
|
||||
Kernel.put_in(object, ["object", "sensitive"], true)
|
||||
Kernel.put_in(activity, ["object", "sensitive"], true)
|
||||
else
|
||||
object
|
||||
activity
|
||||
end
|
||||
|
||||
{:ok, object}
|
||||
{:ok, activity}
|
||||
end
|
||||
|
||||
defp check_media_nsfw(_actor_info, object), do: {:ok, object}
|
||||
defp check_media_nsfw(_actor_info, activity), do: {:ok, activity}
|
||||
|
||||
defp check_ftl_removal(%{host: actor_host} = _actor_info, object) do
|
||||
defp check_ftl_removal(%{host: actor_host} = _actor_info, activity) do
|
||||
timeline_removal =
|
||||
instance_list(:federated_timeline_removal)
|
||||
|> MRF.subdomains_regex()
|
||||
|
||||
object =
|
||||
activity =
|
||||
with true <- MRF.subdomain_match?(timeline_removal, actor_host),
|
||||
user <- User.get_cached_by_ap_id(object["actor"]),
|
||||
true <- Pleroma.Constants.as_public() in object["to"] do
|
||||
to = List.delete(object["to"], Pleroma.Constants.as_public()) ++ [user.follower_address]
|
||||
user <- User.get_cached_by_ap_id(activity["actor"]),
|
||||
true <- Pleroma.Constants.as_public() in activity["to"] do
|
||||
to = List.delete(activity["to"], Pleroma.Constants.as_public()) ++ [user.follower_address]
|
||||
|
||||
cc = List.delete(object["cc"], user.follower_address) ++ [Pleroma.Constants.as_public()]
|
||||
cc = List.delete(activity["cc"], user.follower_address) ++ [Pleroma.Constants.as_public()]
|
||||
|
||||
object
|
||||
activity
|
||||
|> Map.put("to", to)
|
||||
|> Map.put("cc", cc)
|
||||
else
|
||||
_ -> object
|
||||
_ -> activity
|
||||
end
|
||||
|
||||
{:ok, object}
|
||||
{:ok, activity}
|
||||
end
|
||||
|
||||
defp intersection(list1, list2) do
|
||||
list1 -- list1 -- list2
|
||||
end
|
||||
|
||||
defp check_followers_only(%{host: actor_host} = _actor_info, object) do
|
||||
defp check_followers_only(%{host: actor_host} = _actor_info, activity) do
|
||||
followers_only =
|
||||
instance_list(:followers_only)
|
||||
|> MRF.subdomains_regex()
|
||||
|
||||
object =
|
||||
activity =
|
||||
with true <- MRF.subdomain_match?(followers_only, actor_host),
|
||||
user <- User.get_cached_by_ap_id(object["actor"]) do
|
||||
user <- User.get_cached_by_ap_id(activity["actor"]) do
|
||||
# Don't use Map.get/3 intentionally, these must not be nil
|
||||
fixed_to = object["to"] || []
|
||||
fixed_cc = object["cc"] || []
|
||||
fixed_to = activity["to"] || []
|
||||
fixed_cc = activity["cc"] || []
|
||||
|
||||
to = FollowingRelationship.followers_ap_ids(user, fixed_to)
|
||||
cc = FollowingRelationship.followers_ap_ids(user, fixed_cc)
|
||||
|
||||
object
|
||||
activity
|
||||
|> Map.put("to", intersection([user.follower_address | to], fixed_to))
|
||||
|> Map.put("cc", intersection([user.follower_address | cc], fixed_cc))
|
||||
else
|
||||
_ -> object
|
||||
_ -> activity
|
||||
end
|
||||
|
||||
{:ok, object}
|
||||
{:ok, activity}
|
||||
end
|
||||
|
||||
defp check_report_removal(%{host: actor_host} = _actor_info, %{"type" => "Flag"} = object) do
|
||||
defp check_report_removal(%{host: actor_host} = _actor_info, %{"type" => "Flag"} = activity) do
|
||||
report_removal =
|
||||
instance_list(:report_removal)
|
||||
|> MRF.subdomains_regex()
|
||||
|
|
@ -144,39 +144,39 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
|||
if MRF.subdomain_match?(report_removal, actor_host) do
|
||||
{:reject, "[SimplePolicy] host in report_removal list"}
|
||||
else
|
||||
{:ok, object}
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
defp check_report_removal(_actor_info, object), do: {:ok, object}
|
||||
defp check_report_removal(_actor_info, activity), do: {:ok, activity}
|
||||
|
||||
defp check_avatar_removal(%{host: actor_host} = _actor_info, %{"icon" => _icon} = object) do
|
||||
defp check_avatar_removal(%{host: actor_host} = _actor_info, %{"icon" => _icon} = activity) do
|
||||
avatar_removal =
|
||||
instance_list(:avatar_removal)
|
||||
|> MRF.subdomains_regex()
|
||||
|
||||
if MRF.subdomain_match?(avatar_removal, actor_host) do
|
||||
{:ok, Map.delete(object, "icon")}
|
||||
{:ok, Map.delete(activity, "icon")}
|
||||
else
|
||||
{:ok, object}
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
defp check_avatar_removal(_actor_info, object), do: {:ok, object}
|
||||
defp check_avatar_removal(_actor_info, activity), do: {:ok, activity}
|
||||
|
||||
defp check_banner_removal(%{host: actor_host} = _actor_info, %{"image" => _image} = object) do
|
||||
defp check_banner_removal(%{host: actor_host} = _actor_info, %{"image" => _image} = activity) do
|
||||
banner_removal =
|
||||
instance_list(:banner_removal)
|
||||
|> MRF.subdomains_regex()
|
||||
|
||||
if MRF.subdomain_match?(banner_removal, actor_host) do
|
||||
{:ok, Map.delete(object, "image")}
|
||||
{:ok, Map.delete(activity, "image")}
|
||||
else
|
||||
{:ok, object}
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
defp check_banner_removal(_actor_info, object), do: {:ok, object}
|
||||
defp check_banner_removal(_actor_info, activity), do: {:ok, activity}
|
||||
|
||||
defp check_object(%{"object" => object} = activity) do
|
||||
with {:ok, _object} <- filter(object) do
|
||||
|
|
@ -184,7 +184,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
|||
end
|
||||
end
|
||||
|
||||
defp check_object(object), do: {:ok, object}
|
||||
defp check_object(activity), do: {:ok, activity}
|
||||
|
||||
defp instance_list(config_key) do
|
||||
Config.get([:mrf_simple, config_key])
|
||||
|
|
@ -192,7 +192,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
|||
end
|
||||
|
||||
@impl true
|
||||
def filter(%{"type" => "Delete", "actor" => actor} = object) do
|
||||
def filter(%{"type" => "Delete", "actor" => actor} = activity) do
|
||||
%{host: actor_host} = URI.parse(actor)
|
||||
|
||||
reject_deletes =
|
||||
|
|
@ -202,54 +202,54 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
|||
if MRF.subdomain_match?(reject_deletes, actor_host) do
|
||||
{:reject, "[SimplePolicy] host in reject_deletes list"}
|
||||
else
|
||||
{:ok, object}
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(%{"actor" => actor} = object) do
|
||||
def filter(%{"actor" => actor} = activity) do
|
||||
actor_info = URI.parse(actor)
|
||||
|
||||
with {:ok, object} <- check_accept(actor_info, object),
|
||||
{:ok, object} <- check_reject(actor_info, object),
|
||||
{:ok, object} <- check_media_removal(actor_info, object),
|
||||
{:ok, object} <- check_media_nsfw(actor_info, object),
|
||||
{:ok, object} <- check_ftl_removal(actor_info, object),
|
||||
{:ok, object} <- check_followers_only(actor_info, object),
|
||||
{:ok, object} <- check_report_removal(actor_info, object),
|
||||
{:ok, object} <- check_object(object) do
|
||||
{:ok, object}
|
||||
with {:ok, activity} <- check_accept(actor_info, activity),
|
||||
{:ok, activity} <- check_reject(actor_info, activity),
|
||||
{:ok, activity} <- check_media_removal(actor_info, activity),
|
||||
{:ok, activity} <- check_media_nsfw(actor_info, activity),
|
||||
{:ok, activity} <- check_ftl_removal(actor_info, activity),
|
||||
{:ok, activity} <- check_followers_only(actor_info, activity),
|
||||
{:ok, activity} <- check_report_removal(actor_info, activity),
|
||||
{:ok, activity} <- check_object(activity) do
|
||||
{:ok, activity}
|
||||
else
|
||||
{:reject, _} = e -> e
|
||||
end
|
||||
end
|
||||
|
||||
def filter(%{"id" => actor, "type" => obj_type} = object)
|
||||
when obj_type in ["Application", "Group", "Organization", "Person", "Service"] do
|
||||
def filter(%{"id" => actor, "type" => actor_type} = activity)
|
||||
when actor_type in ["Application", "Group", "Organization", "Person", "Service"] do
|
||||
actor_info = URI.parse(actor)
|
||||
|
||||
with {:ok, object} <- check_accept(actor_info, object),
|
||||
{:ok, object} <- check_reject(actor_info, object),
|
||||
{:ok, object} <- check_avatar_removal(actor_info, object),
|
||||
{:ok, object} <- check_banner_removal(actor_info, object) do
|
||||
{:ok, object}
|
||||
with {:ok, activity} <- check_accept(actor_info, activity),
|
||||
{:ok, activity} <- check_reject(actor_info, activity),
|
||||
{:ok, activity} <- check_avatar_removal(actor_info, activity),
|
||||
{:ok, activity} <- check_banner_removal(actor_info, activity) do
|
||||
{:ok, activity}
|
||||
else
|
||||
{:reject, _} = e -> e
|
||||
end
|
||||
end
|
||||
|
||||
def filter(object) when is_binary(object) do
|
||||
uri = URI.parse(object)
|
||||
def filter(activity) when is_binary(activity) do
|
||||
uri = URI.parse(activity)
|
||||
|
||||
with {:ok, object} <- check_accept(uri, object),
|
||||
{:ok, object} <- check_reject(uri, object) do
|
||||
{:ok, object}
|
||||
with {:ok, activity} <- check_accept(uri, activity),
|
||||
{:ok, activity} <- check_reject(uri, activity) do
|
||||
{:ok, activity}
|
||||
else
|
||||
{:reject, _} = e -> e
|
||||
end
|
||||
end
|
||||
|
||||
def filter(object), do: {:ok, object}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe do
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy do
|
|||
end
|
||||
|
||||
@impl true
|
||||
def filter(%{"object" => %{"emoji" => foreign_emojis, "actor" => actor}} = message) do
|
||||
def filter(%{"object" => %{"emoji" => foreign_emojis, "actor" => actor}} = activity) do
|
||||
host = URI.parse(actor).host
|
||||
|
||||
if host != Pleroma.Web.Endpoint.host() and accept_host?(host) do
|
||||
|
|
@ -97,10 +97,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy do
|
|||
end
|
||||
end
|
||||
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
end
|
||||
|
||||
def filter(message), do: {:ok, message}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
@spec config_description :: %{
|
||||
|
|
|
|||
|
|
@ -20,20 +20,20 @@ defmodule Pleroma.Web.ActivityPub.MRF.SubchainPolicy do
|
|||
end
|
||||
|
||||
@impl true
|
||||
def filter(%{"actor" => actor} = message) do
|
||||
def filter(%{"actor" => actor} = activity) do
|
||||
with {:ok, match, subchain} <- lookup_subchain(actor) do
|
||||
Logger.debug(
|
||||
"[SubchainPolicy] Matched #{actor} against #{inspect(match)} with subchain #{inspect(subchain)}"
|
||||
)
|
||||
|
||||
MRF.filter(subchain, message)
|
||||
MRF.filter(subchain, activity)
|
||||
else
|
||||
_e -> {:ok, message}
|
||||
_e -> {:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(message), do: {:ok, message}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
|
|
@ -45,7 +45,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SubchainPolicy do
|
|||
related_policy: "Pleroma.Web.ActivityPub.MRF.SubchainPolicy",
|
||||
label: "MRF Subchain",
|
||||
description:
|
||||
"This policy processes messages through an alternate pipeline when a given message matches certain criteria." <>
|
||||
"This policy processes activities through an alternate pipeline when a given activity matches certain criteria." <>
|
||||
" All criteria are configured as a map of regular expressions to lists of policy modules.",
|
||||
children: [
|
||||
%{
|
||||
|
|
|
|||
|
|
@ -28,25 +28,25 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
|
|||
"mrf_tag:media-force-nsfw",
|
||||
%{
|
||||
"type" => type,
|
||||
"object" => %{"attachment" => child_attachment}
|
||||
} = message
|
||||
"object" => %{"attachment" => object_attachment}
|
||||
} = activity
|
||||
)
|
||||
when length(child_attachment) > 0 and type in ["Create", "Update"] do
|
||||
{:ok, Kernel.put_in(message, ["object", "sensitive"], true)}
|
||||
when length(object_attachment) > 0 and type in ["Create", "Update"] do
|
||||
{:ok, Kernel.put_in(activity, ["object", "sensitive"], true)}
|
||||
end
|
||||
|
||||
defp process_tag(
|
||||
"mrf_tag:media-strip",
|
||||
%{
|
||||
"type" => type,
|
||||
"object" => %{"attachment" => child_attachment} = object
|
||||
} = message
|
||||
"object" => %{"attachment" => object_attachment} = object
|
||||
} = activity
|
||||
)
|
||||
when length(child_attachment) > 0 and type in ["Create", "Update"] do
|
||||
when length(object_attachment) > 0 and type in ["Create", "Update"] do
|
||||
object = Map.delete(object, "attachment")
|
||||
message = Map.put(message, "object", object)
|
||||
activity = Map.put(activity, "object", object)
|
||||
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
end
|
||||
|
||||
defp process_tag(
|
||||
|
|
@ -57,7 +57,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
|
|||
"cc" => cc,
|
||||
"actor" => actor,
|
||||
"object" => object
|
||||
} = message
|
||||
} = activity
|
||||
) do
|
||||
user = User.get_cached_by_ap_id(actor)
|
||||
|
||||
|
|
@ -70,15 +70,15 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
|
|||
|> Map.put("to", to)
|
||||
|> Map.put("cc", cc)
|
||||
|
||||
message =
|
||||
message
|
||||
activity =
|
||||
activity
|
||||
|> Map.put("to", to)
|
||||
|> Map.put("cc", cc)
|
||||
|> Map.put("object", object)
|
||||
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
else
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
|
|||
"cc" => cc,
|
||||
"actor" => actor,
|
||||
"object" => object
|
||||
} = message
|
||||
} = activity
|
||||
) do
|
||||
user = User.get_cached_by_ap_id(actor)
|
||||
|
||||
|
|
@ -104,26 +104,26 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
|
|||
|> Map.put("to", to)
|
||||
|> Map.put("cc", cc)
|
||||
|
||||
message =
|
||||
message
|
||||
activity =
|
||||
activity
|
||||
|> Map.put("to", to)
|
||||
|> Map.put("cc", cc)
|
||||
|> Map.put("object", object)
|
||||
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
else
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
defp process_tag(
|
||||
"mrf_tag:disable-remote-subscription",
|
||||
%{"type" => "Follow", "actor" => actor} = message
|
||||
%{"type" => "Follow", "actor" => actor} = activity
|
||||
) do
|
||||
user = User.get_cached_by_ap_id(actor)
|
||||
|
||||
if user.local == true do
|
||||
{:ok, message}
|
||||
{:ok, activity}
|
||||
else
|
||||
{:reject,
|
||||
"[TagPolicy] Follow from #{actor} tagged with mrf_tag:disable-remote-subscription"}
|
||||
|
|
@ -133,14 +133,14 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
|
|||
defp process_tag("mrf_tag:disable-any-subscription", %{"type" => "Follow", "actor" => actor}),
|
||||
do: {:reject, "[TagPolicy] Follow from #{actor} tagged with mrf_tag:disable-any-subscription"}
|
||||
|
||||
defp process_tag(_, message), do: {:ok, message}
|
||||
defp process_tag(_, activity), do: {:ok, activity}
|
||||
|
||||
def filter_message(actor, message) do
|
||||
def filter_activity(actor, activity) do
|
||||
User.get_cached_by_ap_id(actor)
|
||||
|> get_tags()
|
||||
|> Enum.reduce({:ok, message}, fn
|
||||
tag, {:ok, message} ->
|
||||
process_tag(tag, message)
|
||||
|> Enum.reduce({:ok, activity}, fn
|
||||
tag, {:ok, activity} ->
|
||||
process_tag(tag, activity)
|
||||
|
||||
_, error ->
|
||||
error
|
||||
|
|
@ -148,15 +148,15 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
|
|||
end
|
||||
|
||||
@impl true
|
||||
def filter(%{"object" => target_actor, "type" => "Follow"} = message),
|
||||
do: filter_message(target_actor, message)
|
||||
def filter(%{"object" => target_actor, "type" => "Follow"} = activity),
|
||||
do: filter_activity(target_actor, activity)
|
||||
|
||||
@impl true
|
||||
def filter(%{"actor" => actor, "type" => type} = message) when type in ["Create", "Update"],
|
||||
do: filter_message(actor, message)
|
||||
def filter(%{"actor" => actor, "type" => type} = activity) when type in ["Create", "Update"],
|
||||
do: filter_activity(actor, activity)
|
||||
|
||||
@impl true
|
||||
def filter(message), do: {:ok, message}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
|
|
|
|||
|
|
@ -8,18 +8,18 @@ defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy do
|
|||
@moduledoc "Accept-list of users from specified instances"
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||
|
||||
defp filter_by_list(object, []), do: {:ok, object}
|
||||
defp filter_by_list(activity, []), do: {:ok, activity}
|
||||
|
||||
defp filter_by_list(%{"actor" => actor} = object, allow_list) do
|
||||
defp filter_by_list(%{"actor" => actor} = activity, allow_list) do
|
||||
if actor in allow_list do
|
||||
{:ok, object}
|
||||
{:ok, activity}
|
||||
else
|
||||
{:reject, "[UserAllowListPolicy] #{actor} not in the list"}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(%{"actor" => actor} = object) do
|
||||
def filter(%{"actor" => actor} = activity) do
|
||||
actor_info = URI.parse(actor)
|
||||
|
||||
allow_list =
|
||||
|
|
@ -28,10 +28,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy do
|
|||
[]
|
||||
)
|
||||
|
||||
filter_by_list(object, allow_list)
|
||||
filter_by_list(activity, allow_list)
|
||||
end
|
||||
|
||||
def filter(object), do: {:ok, object}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe do
|
||||
|
|
|
|||
|
|
@ -3,38 +3,38 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicy do
|
||||
@moduledoc "Filter messages which belong to certain activity vocabularies"
|
||||
@moduledoc "Filter activities which belong to certain activity vocabularies"
|
||||
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||
|
||||
@impl true
|
||||
def filter(%{"type" => "Undo", "object" => child_message} = message) do
|
||||
with {:ok, _} <- filter(child_message) do
|
||||
{:ok, message}
|
||||
def filter(%{"type" => "Undo", "object" => object} = activity) do
|
||||
with {:ok, _} <- filter(object) do
|
||||
{:ok, activity}
|
||||
else
|
||||
{:reject, _} = e -> e
|
||||
end
|
||||
end
|
||||
|
||||
def filter(%{"type" => message_type} = message) do
|
||||
def filter(%{"type" => activity_type} = activity) do
|
||||
with accepted_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :accept]),
|
||||
rejected_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :reject]),
|
||||
{_, true} <-
|
||||
{:accepted,
|
||||
Enum.empty?(accepted_vocabulary) || Enum.member?(accepted_vocabulary, message_type)},
|
||||
Enum.empty?(accepted_vocabulary) || Enum.member?(accepted_vocabulary, activity_type)},
|
||||
{_, false} <-
|
||||
{:rejected,
|
||||
length(rejected_vocabulary) > 0 && Enum.member?(rejected_vocabulary, message_type)},
|
||||
{:ok, _} <- filter(message["object"]) do
|
||||
{:ok, message}
|
||||
length(rejected_vocabulary) > 0 && Enum.member?(rejected_vocabulary, activity_type)},
|
||||
{:ok, _} <- filter(activity["object"]) do
|
||||
{:ok, activity}
|
||||
else
|
||||
{:reject, _} = e -> e
|
||||
{:accepted, _} -> {:reject, "[VocabularyPolicy] #{message_type} not in accept list"}
|
||||
{:rejected, _} -> {:reject, "[VocabularyPolicy] #{message_type} in reject list"}
|
||||
{:accepted, _} -> {:reject, "[VocabularyPolicy] #{activity_type} not in accept list"}
|
||||
{:rejected, _} -> {:reject, "[VocabularyPolicy] #{activity_type} in reject list"}
|
||||
end
|
||||
end
|
||||
|
||||
def filter(message), do: {:ok, message}
|
||||
def filter(activity), do: {:ok, activity}
|
||||
|
||||
@impl true
|
||||
def describe,
|
||||
|
|
@ -46,20 +46,20 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicy do
|
|||
key: :mrf_vocabulary,
|
||||
related_policy: "Pleroma.Web.ActivityPub.MRF.VocabularyPolicy",
|
||||
label: "MRF Vocabulary",
|
||||
description: "Filter messages which belong to certain activity vocabularies",
|
||||
description: "Filter activities which belong to certain activity vocabularies",
|
||||
children: [
|
||||
%{
|
||||
key: :accept,
|
||||
type: {:list, :string},
|
||||
description:
|
||||
"A list of ActivityStreams terms to accept. If empty, all supported messages are accepted.",
|
||||
"A list of ActivityStreams terms to accept. If empty, all supported activities are accepted.",
|
||||
suggestions: ["Create", "Follow", "Mention", "Announce", "Like"]
|
||||
},
|
||||
%{
|
||||
key: :reject,
|
||||
type: {:list, :string},
|
||||
description:
|
||||
"A list of ActivityStreams terms to reject. If empty, no messages are rejected.",
|
||||
"A list of ActivityStreams terms to reject. If empty, no activities are rejected.",
|
||||
suggestions: ["Create", "Follow", "Mention", "Announce", "Like"]
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AcceptRejectValidator do
|
|||
|
||||
defp validate_data(cng) do
|
||||
cng
|
||||
|> validate_required([:id, :type, :actor, :to, :cc, :object])
|
||||
|> validate_required([:id, :type, :actor, :to, :object])
|
||||
|> validate_inclusion(:type, ["Accept", "Reject"])
|
||||
|> validate_actor_presence()
|
||||
|> validate_object_presence(allowed_types: ["Follow"])
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.BlockValidator do
|
|||
|
||||
defp validate_data(cng) do
|
||||
cng
|
||||
|> validate_required([:id, :type, :actor, :to, :cc, :object])
|
||||
|> validate_required([:id, :type, :actor, :to, :object])
|
||||
|> validate_inclusion(:type, ["Block"])
|
||||
|> CommonValidations.validate_actor_presence()
|
||||
|> CommonValidations.validate_actor_presence(field_name: :object)
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.FollowValidator do
|
|||
|
||||
defp validate_data(cng) do
|
||||
cng
|
||||
|> validate_required([:id, :type, :actor, :to, :cc, :object])
|
||||
|> validate_required([:id, :type, :actor, :to, :object])
|
||||
|> validate_inclusion(:type, ["Follow"])
|
||||
|> validate_inclusion(:state, ~w{pending reject accept})
|
||||
|> validate_actor_presence()
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
alias Pleroma.Object
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.Publisher.Prepared
|
||||
alias Pleroma.Web.ActivityPub.Relay
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
alias Pleroma.Workers.PublisherWorker
|
||||
|
|
@ -30,11 +31,11 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
"""
|
||||
@spec enqueue_one(map(), Keyword.t()) :: {:ok, %Oban.Job{}}
|
||||
def enqueue_one(%{} = params, worker_args \\ []) do
|
||||
PublisherWorker.enqueue(
|
||||
"publish_one",
|
||||
%{"params" => params},
|
||||
PublisherWorker.new(
|
||||
%{"op" => "publish_one", "params" => params},
|
||||
worker_args
|
||||
)
|
||||
|> Oban.insert()
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
|
@ -76,17 +77,29 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
end
|
||||
|
||||
@doc """
|
||||
Publish a single message to a peer. Takes a struct with the following
|
||||
parameters set:
|
||||
|
||||
Prepare an activity for publishing from an Oban job
|
||||
* `inbox`: the inbox to publish to
|
||||
* `json`: the JSON message body representing the ActivityPub message
|
||||
* `actor`: the actor which is signing the message
|
||||
* `id`: the ActivityStreams URI of the message
|
||||
* `activity_id`: the internal activity id
|
||||
* `cc`: the cc recipients relevant to this inbox (optional)
|
||||
"""
|
||||
def publish_one(%{inbox: inbox, json: json, actor: %User{} = actor, id: id} = params) do
|
||||
Logger.debug("Federating #{id} to #{inbox}")
|
||||
@spec prepare_one(map()) :: Prepared.t()
|
||||
def prepare_one(%{inbox: inbox, activity_id: activity_id} = params) do
|
||||
activity = Activity.get_by_id_with_user_actor(activity_id)
|
||||
actor = activity.user_actor
|
||||
|
||||
ap_id = activity.data["id"]
|
||||
Logger.debug("Federating #{ap_id} to #{inbox}")
|
||||
uri = %{path: path} = URI.parse(inbox)
|
||||
|
||||
{:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
|
||||
|
||||
cc = Map.get(params, :cc, [])
|
||||
|
||||
json =
|
||||
data
|
||||
|> Map.put("cc", cc)
|
||||
|> Jason.encode!()
|
||||
|
||||
digest = "SHA-256=" <> (:crypto.hash(:sha256, json) |> Base.encode64())
|
||||
|
||||
date = Pleroma.Signature.signed_date()
|
||||
|
|
@ -100,27 +113,54 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
date: date
|
||||
})
|
||||
|
||||
%Prepared{
|
||||
activity_id: activity_id,
|
||||
json: json,
|
||||
date: date,
|
||||
signature: signature,
|
||||
digest: digest,
|
||||
inbox: inbox,
|
||||
unreachable_since: params[:unreachable_since]
|
||||
}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Publish a single message to a peer. Takes a struct with the following
|
||||
parameters set:
|
||||
* `activity_id`: the activity id
|
||||
* `json`: the json payload
|
||||
* `date`: the signed date from Pleroma.Signature.signed_date()
|
||||
* `signature`: the signature from Pleroma.Signature.sign/2
|
||||
* `digest`: base64 encoded the hash of the json payload prefixed with "SHA-256="
|
||||
* `inbox`: the inbox URI of this delivery
|
||||
* `unreachable_since`: timestamp the instance was marked unreachable
|
||||
|
||||
"""
|
||||
def publish_one(%Prepared{} = p) do
|
||||
with {:ok, %{status: code}} = result when code in 200..299 <-
|
||||
HTTP.post(
|
||||
inbox,
|
||||
json,
|
||||
p.inbox,
|
||||
p.json,
|
||||
[
|
||||
{"Content-Type", "application/activity+json"},
|
||||
{"Date", date},
|
||||
{"signature", signature},
|
||||
{"digest", digest}
|
||||
{"Date", p.date},
|
||||
{"signature", p.signature},
|
||||
{"digest", p.digest}
|
||||
]
|
||||
) do
|
||||
if not Map.has_key?(params, :unreachable_since) || params[:unreachable_since] do
|
||||
Instances.set_reachable(inbox)
|
||||
if not is_nil(p.unreachable_since) do
|
||||
Instances.set_reachable(p.inbox)
|
||||
end
|
||||
|
||||
result
|
||||
else
|
||||
{_post_result, %{status: code} = response} = e ->
|
||||
unless params[:unreachable_since], do: Instances.set_unreachable(inbox)
|
||||
Logger.metadata(activity: id, inbox: inbox, status: code)
|
||||
Logger.error("Publisher failed to inbox #{inbox} with status #{code}")
|
||||
if is_nil(p.unreachable_since) do
|
||||
Instances.set_unreachable(p.inbox)
|
||||
end
|
||||
|
||||
Logger.metadata(activity: p.activity_id, inbox: p.inbox, status: code)
|
||||
Logger.error("Publisher failed to inbox #{p.inbox} with status #{code}")
|
||||
|
||||
case response do
|
||||
%{status: 400} -> {:cancel, :bad_request}
|
||||
|
|
@ -130,26 +170,26 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
_ -> {:error, e}
|
||||
end
|
||||
|
||||
{:error, {:already_started, _}} ->
|
||||
Logger.debug("Publisher snoozing worker job due worker :already_started race condition")
|
||||
connection_pool_snooze()
|
||||
|
||||
{:error, :pool_full} ->
|
||||
Logger.debug("Publisher snoozing worker job due to full connection pool")
|
||||
{:snooze, 30}
|
||||
connection_pool_snooze()
|
||||
|
||||
e ->
|
||||
unless params[:unreachable_since], do: Instances.set_unreachable(inbox)
|
||||
Logger.metadata(activity: id, inbox: inbox)
|
||||
Logger.error("Publisher failed to inbox #{inbox} #{inspect(e)}")
|
||||
if is_nil(p.unreachable_since) do
|
||||
Instances.set_unreachable(p.inbox)
|
||||
end
|
||||
|
||||
Logger.metadata(activity: p.activity_id, inbox: p.inbox)
|
||||
Logger.error("Publisher failed to inbox #{p.inbox} #{inspect(e)}")
|
||||
{:error, e}
|
||||
end
|
||||
end
|
||||
|
||||
def publish_one(%{actor_id: actor_id} = params) do
|
||||
actor = User.get_cached_by_id(actor_id)
|
||||
|
||||
params
|
||||
|> Map.delete(:actor_id)
|
||||
|> Map.put(:actor, actor)
|
||||
|> publish_one()
|
||||
end
|
||||
defp connection_pool_snooze, do: {:snooze, 3}
|
||||
|
||||
defp signature_host(%URI{port: port, scheme: scheme, host: host}) do
|
||||
if port == URI.default_port(scheme) do
|
||||
|
|
@ -251,7 +291,6 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
def publish(%User{} = actor, %{data: %{"bcc" => bcc}} = activity)
|
||||
when is_list(bcc) and bcc != [] do
|
||||
public = public?(activity)
|
||||
{:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
|
||||
|
||||
[priority_recipients, recipients] = recipients(actor, activity)
|
||||
|
||||
|
|
@ -276,16 +315,10 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
# instance would only accept a first message for the first recipient and ignore the rest.
|
||||
cc = get_cc_ap_ids(ap_id, recipients)
|
||||
|
||||
json =
|
||||
data
|
||||
|> Map.put("cc", cc)
|
||||
|> Jason.encode!()
|
||||
|
||||
__MODULE__.enqueue_one(%{
|
||||
inbox: inbox,
|
||||
json: json,
|
||||
actor_id: actor.id,
|
||||
id: activity.data["id"],
|
||||
cc: cc,
|
||||
activity_id: activity.id,
|
||||
unreachable_since: unreachable_since
|
||||
})
|
||||
end)
|
||||
|
|
@ -302,9 +335,6 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
Relay.publish(activity)
|
||||
end
|
||||
|
||||
{:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
|
||||
json = Jason.encode!(data)
|
||||
|
||||
[priority_inboxes, inboxes] =
|
||||
recipients(actor, activity)
|
||||
|> Enum.map(fn recipients ->
|
||||
|
|
@ -326,9 +356,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
__MODULE__.enqueue_one(
|
||||
%{
|
||||
inbox: inbox,
|
||||
json: json,
|
||||
actor_id: actor.id,
|
||||
id: activity.data["id"],
|
||||
activity_id: activity.id,
|
||||
unreachable_since: unreachable_since
|
||||
},
|
||||
priority: priority
|
||||
|
|
|
|||
8
lib/pleroma/web/activity_pub/publisher/prepared.ex
Normal file
8
lib/pleroma/web/activity_pub/publisher/prepared.ex
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# 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.Publisher.Prepared do
|
||||
@type t :: %__MODULE__{}
|
||||
defstruct [:activity_id, :json, :date, :signature, :digest, :inbox, :unreachable_since]
|
||||
end
|
||||
|
|
@ -223,10 +223,12 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
|||
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", %{
|
||||
Pleroma.Workers.RemoteFetcherWorker.new(%{
|
||||
"op" => "fetch_remote",
|
||||
"id" => reply_id,
|
||||
"depth" => reply_depth
|
||||
})
|
||||
|> Oban.insert()
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -410,10 +412,12 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
|||
{:ok, expires_at} =
|
||||
Pleroma.EctoType.ActivityPub.ObjectValidators.DateTime.cast(meta[:expires_at])
|
||||
|
||||
Pleroma.Workers.PurgeExpiredActivity.enqueue(%{
|
||||
activity_id: meta[:activity_id],
|
||||
expires_at: expires_at
|
||||
})
|
||||
Pleroma.Workers.PurgeExpiredActivity.enqueue(
|
||||
%{
|
||||
activity_id: meta[:activity_id]
|
||||
},
|
||||
scheduled_at: expires_at
|
||||
)
|
||||
end
|
||||
|
||||
{:ok, object, meta}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
alias Pleroma.ModerationLog
|
||||
alias Pleroma.Stats
|
||||
alias Pleroma.User
|
||||
alias Pleroma.User.Backup
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.Web.AdminAPI
|
||||
alias Pleroma.Web.AdminAPI.AccountView
|
||||
|
|
@ -429,7 +430,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
|
||||
def create_backup(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do
|
||||
with %User{} = user <- User.get_by_nickname(nickname),
|
||||
{:ok, _} <- Pleroma.User.Backup.create(user, admin.id) do
|
||||
%Backup{} = backup <- Backup.new(user),
|
||||
{:ok, inserted_backup} <- Pleroma.Repo.insert(backup),
|
||||
{:ok, %Oban.Job{}} <- Backup.schedule_backup(inserted_backup) do
|
||||
ModerationLog.insert_log(%{actor: admin, subject: user, action: "create_backup"})
|
||||
|
||||
json(conn, "")
|
||||
|
|
|
|||
|
|
@ -498,22 +498,6 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
|
|||
}
|
||||
end
|
||||
|
||||
def identity_proofs_operation do
|
||||
%Operation{
|
||||
tags: ["Retrieve account information"],
|
||||
summary: "Identity proofs",
|
||||
operationId: "AccountController.identity_proofs",
|
||||
# Validators complains about unused path params otherwise
|
||||
parameters: [
|
||||
%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}
|
||||
],
|
||||
description: "Not implemented",
|
||||
responses: %{
|
||||
200 => empty_array_response()
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def familiar_followers_operation do
|
||||
%Operation{
|
||||
tags: ["Retrieve account information"],
|
||||
|
|
|
|||
|
|
@ -85,9 +85,11 @@ defmodule Pleroma.Web.ApiSpec.PleromaAccountOperation do
|
|||
|
||||
def subscribe_operation do
|
||||
%Operation{
|
||||
deprecated: true,
|
||||
tags: ["Account actions"],
|
||||
summary: "Subscribe",
|
||||
description: "Receive notifications for all statuses posted by the account.",
|
||||
description:
|
||||
"Receive notifications for all statuses posted by the account. Deprecated, use `notify: true` in follow operation instead.",
|
||||
operationId: "PleromaAPI.AccountController.subscribe",
|
||||
parameters: [id_param()],
|
||||
security: [%{"oAuth" => ["follow", "write:follows"]}],
|
||||
|
|
@ -100,9 +102,11 @@ defmodule Pleroma.Web.ApiSpec.PleromaAccountOperation do
|
|||
|
||||
def unsubscribe_operation do
|
||||
%Operation{
|
||||
deprecated: true,
|
||||
tags: ["Account actions"],
|
||||
summary: "Unsubscribe",
|
||||
description: "Stop receiving notifications for all statuses posted by the account.",
|
||||
description:
|
||||
"Stop receiving notifications for all statuses posted by the account. Deprecated, use `notify: false` in follow operation instead.",
|
||||
operationId: "PleromaAPI.AccountController.unsubscribe",
|
||||
parameters: [id_param()],
|
||||
security: [%{"oAuth" => ["follow", "write:follows"]}],
|
||||
|
|
|
|||
|
|
@ -65,12 +65,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaBackupOperation do
|
|||
file_name: %Schema{type: :string},
|
||||
file_size: %Schema{type: :integer},
|
||||
processed: %Schema{type: :boolean, description: "whether this backup has succeeded"},
|
||||
state: %Schema{
|
||||
type: :string,
|
||||
description: "the state of the backup",
|
||||
enum: ["pending", "running", "complete", "failed"]
|
||||
},
|
||||
processed_number: %Schema{type: :integer, description: "the number of records processed"}
|
||||
tempdir: %Schema{type: :string}
|
||||
},
|
||||
example: %{
|
||||
"content_type" => "application/zip",
|
||||
|
|
@ -79,8 +74,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaBackupOperation do
|
|||
"file_size" => 4105,
|
||||
"inserted_at" => "2020-09-08T16:42:07.000Z",
|
||||
"processed" => true,
|
||||
"state" => "complete",
|
||||
"processed_number" => 20
|
||||
"tempdir" => "/tmp/PZIMw40vmpM"
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -31,11 +31,17 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
|
|||
security: [%{"oAuth" => ["read:statuses"]}],
|
||||
parameters: [
|
||||
Operation.parameter(
|
||||
:ids,
|
||||
:id,
|
||||
:query,
|
||||
%Schema{type: :array, items: FlakeID},
|
||||
"Array of status IDs"
|
||||
),
|
||||
Operation.parameter(
|
||||
:ids,
|
||||
:query,
|
||||
%Schema{type: :array, items: FlakeID},
|
||||
"Deprecated, use `id` instead"
|
||||
),
|
||||
Operation.parameter(
|
||||
:with_muted,
|
||||
:query,
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
if activity.data["state"] == "reject" do
|
||||
{:error, :rejected}
|
||||
else
|
||||
{:ok, follower, followed, activity}
|
||||
{:ok, followed, follower, activity}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -559,11 +559,11 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
with {:ok, _} <- ThreadMute.add_mute(user.id, activity.data["context"]),
|
||||
_ <- Pleroma.Notification.mark_context_as_read(user, activity.data["context"]) do
|
||||
if expires_in > 0 do
|
||||
Pleroma.Workers.MuteExpireWorker.enqueue(
|
||||
"unmute_conversation",
|
||||
%{"user_id" => user.id, "activity_id" => activity.id},
|
||||
Pleroma.Workers.MuteExpireWorker.new(
|
||||
%{"op" => "unmute_conversation", "user_id" => user.id, "activity_id" => activity.id},
|
||||
schedule_in: expires_in
|
||||
)
|
||||
|> Oban.insert()
|
||||
end
|
||||
|
||||
{:ok, activity}
|
||||
|
|
@ -714,11 +714,11 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
end
|
||||
end
|
||||
|
||||
defp maybe_cancel_jobs(%Activity{data: %{"id" => ap_id}}) do
|
||||
defp maybe_cancel_jobs(%Activity{id: activity_id}) do
|
||||
Oban.Job
|
||||
|> where([j], j.worker == "Pleroma.Workers.PublisherWorker")
|
||||
|> where([j], j.args["op"] == "publish_one")
|
||||
|> where([j], j.args["params"]["id"] == ^ap_id)
|
||||
|> where([j], j.args["params"]["activity_id"] == ^activity_id)
|
||||
|> Oban.cancel_all_jobs()
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -35,22 +35,30 @@ defmodule Pleroma.Web.Federator do
|
|||
end
|
||||
|
||||
# Client API
|
||||
def incoming_ap_doc(%{params: _params, req_headers: _req_headers} = args) do
|
||||
job_args = Enum.into(args, %{}, fn {k, v} -> {Atom.to_string(k), v} end)
|
||||
|
||||
ReceiverWorker.enqueue(
|
||||
"incoming_ap_doc",
|
||||
Map.put(job_args, "timeout", :timer.seconds(20)),
|
||||
def incoming_ap_doc(%{params: params, req_headers: req_headers}) do
|
||||
ReceiverWorker.new(
|
||||
%{
|
||||
"op" => "incoming_ap_doc",
|
||||
"req_headers" => req_headers,
|
||||
"params" => params,
|
||||
"timeout" => :timer.seconds(20)
|
||||
},
|
||||
priority: 2
|
||||
)
|
||||
|> Oban.insert()
|
||||
end
|
||||
|
||||
def incoming_ap_doc(%{"type" => "Delete"} = params) do
|
||||
ReceiverWorker.enqueue("incoming_ap_doc", %{"params" => params}, priority: 3, queue: :slow)
|
||||
ReceiverWorker.new(%{"op" => "incoming_ap_doc", "params" => params},
|
||||
priority: 3,
|
||||
queue: :slow
|
||||
)
|
||||
|> Oban.insert()
|
||||
end
|
||||
|
||||
def incoming_ap_doc(params) do
|
||||
ReceiverWorker.enqueue("incoming_ap_doc", %{"params" => params})
|
||||
ReceiverWorker.new(%{"op" => "incoming_ap_doc", "params" => params})
|
||||
|> Oban.insert()
|
||||
end
|
||||
|
||||
@impl true
|
||||
|
|
@ -60,9 +68,10 @@ defmodule Pleroma.Web.Federator do
|
|||
|
||||
@impl true
|
||||
def publish(%Pleroma.Activity{data: %{"type" => type}} = activity) do
|
||||
PublisherWorker.enqueue("publish", %{"activity_id" => activity.id},
|
||||
PublisherWorker.new(%{"op" => "publish", "activity_id" => activity.id},
|
||||
priority: publish_priority(type)
|
||||
)
|
||||
|> Oban.insert()
|
||||
end
|
||||
|
||||
defp publish_priority("Delete"), do: 3
|
||||
|
|
@ -71,7 +80,10 @@ defmodule Pleroma.Web.Federator do
|
|||
# Job Worker Callbacks
|
||||
|
||||
@spec perform(atom(), any()) :: {:ok, any()} | {:error, any()}
|
||||
def perform(:publish_one, params), do: Publisher.publish_one(params)
|
||||
def perform(:publish_one, params) do
|
||||
Publisher.prepare_one(params)
|
||||
|> Publisher.publish_one()
|
||||
end
|
||||
|
||||
def perform(:publish, activity) do
|
||||
Logger.debug(fn -> "Running publish for #{activity.data["id"]}" end)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
|||
alias Pleroma.Web.CommonAPI
|
||||
alias Pleroma.Web.MastodonAPI.ListView
|
||||
alias Pleroma.Web.MastodonAPI.MastodonAPI
|
||||
alias Pleroma.Web.MastodonAPI.MastodonAPIController
|
||||
alias Pleroma.Web.MastodonAPI.StatusView
|
||||
alias Pleroma.Web.OAuth.OAuthController
|
||||
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
||||
|
|
@ -51,7 +50,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
|||
plug(
|
||||
OAuthScopesPlug,
|
||||
%{scopes: ["read:accounts"]}
|
||||
when action in [:verify_credentials, :endorsements, :identity_proofs]
|
||||
when action in [:verify_credentials, :endorsements]
|
||||
)
|
||||
|
||||
plug(
|
||||
|
|
@ -660,7 +659,4 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
|||
defp get_familiar_followers(user, current_user) do
|
||||
User.get_familiar_followers(user, current_user)
|
||||
end
|
||||
|
||||
@doc "GET /api/v1/identity_proofs"
|
||||
def identity_proofs(conn, params), do: MastodonAPIController.empty_array(conn, params)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
defmodule Pleroma.Web.MastodonAPI.MarkerController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
||||
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||
|
|
@ -30,9 +31,16 @@ defmodule Pleroma.Web.MastodonAPI.MarkerController do
|
|||
def upsert(%{assigns: %{user: user}, body_params: params} = conn, _) do
|
||||
params = Map.new(params, fn {key, value} -> {to_string(key), value} end)
|
||||
|
||||
with {:ok, result} <- Pleroma.Marker.upsert(user, params),
|
||||
with {:ok, _} <- mark_notifications_read(user, params),
|
||||
{:ok, result} <- Pleroma.Marker.upsert(user, params),
|
||||
markers <- Map.values(result) do
|
||||
render(conn, "markers.json", %{markers: markers})
|
||||
end
|
||||
end
|
||||
|
||||
defp mark_notifications_read(user, %{"notifications" => %{last_read_id: last_read_id}}) do
|
||||
Pleroma.Notification.set_read_up_to(user, last_read_id)
|
||||
end
|
||||
|
||||
defp mark_notifications_read(_, _), do: {:ok, :noop}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -111,10 +111,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
|
|||
`ids` query param is required
|
||||
"""
|
||||
def index(
|
||||
%{assigns: %{user: user}, private: %{open_api_spex: %{params: %{ids: ids} = params}}} =
|
||||
%{assigns: %{user: user}, private: %{open_api_spex: %{params: params}}} =
|
||||
conn,
|
||||
_
|
||||
) do
|
||||
ids = Map.get(params, :id, Map.get(params, :ids))
|
||||
limit = 100
|
||||
|
||||
activities =
|
||||
|
|
|
|||
|
|
@ -18,10 +18,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
|
|||
if not User.following?(follower, followed) do
|
||||
CommonAPI.follow(followed, follower)
|
||||
else
|
||||
{:ok, follower, followed, nil}
|
||||
{:ok, followed, follower, nil}
|
||||
end
|
||||
|
||||
with {:ok, follower, _followed, _} <- result do
|
||||
with {:ok, _followed, follower, _} <- result do
|
||||
options = cast_params(params)
|
||||
set_reblogs_visibility(options[:reblogs], result)
|
||||
set_subscription(options[:notify], result)
|
||||
|
|
@ -29,19 +29,19 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
|
|||
end
|
||||
end
|
||||
|
||||
defp set_reblogs_visibility(false, {:ok, follower, followed, _}) do
|
||||
defp set_reblogs_visibility(false, {:ok, followed, follower, _}) do
|
||||
CommonAPI.hide_reblogs(followed, follower)
|
||||
end
|
||||
|
||||
defp set_reblogs_visibility(_, {:ok, follower, followed, _}) do
|
||||
defp set_reblogs_visibility(_, {:ok, followed, follower, _}) do
|
||||
CommonAPI.show_reblogs(followed, follower)
|
||||
end
|
||||
|
||||
defp set_subscription(true, {:ok, follower, followed, _}) do
|
||||
defp set_subscription(true, {:ok, followed, follower, _}) do
|
||||
User.subscribe(follower, followed)
|
||||
end
|
||||
|
||||
defp set_subscription(false, {:ok, follower, followed, _}) do
|
||||
defp set_subscription(false, {:ok, followed, follower, _}) do
|
||||
User.unsubscribe(follower, followed)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -100,11 +100,10 @@ defmodule Pleroma.Web.OAuth.Token do
|
|||
def create(%App{} = app, %User{} = user, attrs \\ %{}) do
|
||||
with {:ok, token} <- do_create(app, user, attrs) do
|
||||
if Pleroma.Config.get([:oauth2, :clean_expired_tokens]) do
|
||||
Pleroma.Workers.PurgeExpiredToken.enqueue(%{
|
||||
token_id: token.id,
|
||||
valid_until: DateTime.from_naive!(token.valid_until, "Etc/UTC"),
|
||||
mod: __MODULE__
|
||||
})
|
||||
Pleroma.Workers.PurgeExpiredToken.new(%{token_id: token.id, mod: __MODULE__},
|
||||
scheduled_at: DateTime.from_naive!(token.valid_until, "Etc/UTC")
|
||||
)
|
||||
|> Oban.insert()
|
||||
end
|
||||
|
||||
{:ok, token}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ defmodule Pleroma.Web.PleromaAPI.BackupController do
|
|||
end
|
||||
|
||||
def create(%{assigns: %{user: user}} = conn, _params) do
|
||||
with {:ok, _} <- Backup.create(user) do
|
||||
with {:ok, _} <- Backup.user(user) do
|
||||
backups = Backup.list(user)
|
||||
render(conn, "index.json", backups: backups)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -9,22 +9,12 @@ defmodule Pleroma.Web.PleromaAPI.BackupView do
|
|||
alias Pleroma.Web.CommonAPI.Utils
|
||||
|
||||
def render("show.json", %{backup: %Backup{} = backup}) do
|
||||
# To deal with records before the migration
|
||||
state =
|
||||
if backup.state == :invalid do
|
||||
if backup.processed, do: :complete, else: :failed
|
||||
else
|
||||
backup.state
|
||||
end
|
||||
|
||||
%{
|
||||
id: backup.id,
|
||||
content_type: backup.content_type,
|
||||
url: download_url(backup),
|
||||
file_size: backup.file_size,
|
||||
processed: backup.processed,
|
||||
state: to_string(state),
|
||||
processed_number: backup.processed_number,
|
||||
inserted_at: Utils.to_masto_date(backup.inserted_at)
|
||||
}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ defmodule Pleroma.Web.Plugs.OAuthPlug do
|
|||
where: t.token == ^token
|
||||
)
|
||||
|
||||
with %Token{user_id: user_id} = token_record <- Repo.one(token_query),
|
||||
with %Token{user_id: user_id} = token_record <- Repo.one(token_query) |> Repo.preload(:user),
|
||||
false <- is_nil(user_id),
|
||||
%User{} = user <- User.get_cached_by_id(user_id) do
|
||||
{:ok, user, token_record}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ defmodule Pleroma.Web.Push do
|
|||
@spec send(Pleroma.Notification.t()) ::
|
||||
{:ok, Oban.Job.t()} | {:error, Oban.Job.changeset() | term()}
|
||||
def send(notification) do
|
||||
WebPusherWorker.enqueue("web_push", %{"notification_id" => notification.id})
|
||||
WebPusherWorker.new(%{"op" => "web_push", "notification_id" => notification.id})
|
||||
|> Oban.insert()
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -648,7 +648,6 @@ defmodule Pleroma.Web.Router do
|
|||
get("/accounts/relationships", AccountController, :relationships)
|
||||
get("/accounts/familiar_followers", AccountController, :familiar_followers)
|
||||
get("/accounts/:id/lists", AccountController, :lists)
|
||||
get("/accounts/:id/identity_proofs", AccountController, :identity_proofs)
|
||||
get("/endorsements", AccountController, :endorsements)
|
||||
get("/blocks", AccountController, :blocks)
|
||||
get("/mutes", AccountController, :mutes)
|
||||
|
|
|
|||
|
|
@ -109,7 +109,25 @@ defmodule Pleroma.Web.StreamerView do
|
|||
|> Jason.encode!()
|
||||
end
|
||||
|
||||
def render("follow_relationships_update.json", item, topic) do
|
||||
def render(
|
||||
"follow_relationships_update.json",
|
||||
%{follower: follower, following: following} = item,
|
||||
topic
|
||||
) do
|
||||
following_follower_count =
|
||||
if Enum.any?([following.hide_followers_count, following.hide_followers]) do
|
||||
0
|
||||
else
|
||||
following.follower_count
|
||||
end
|
||||
|
||||
following_following_count =
|
||||
if Enum.any?([following.hide_follows_count, following.hide_follows]) do
|
||||
0
|
||||
else
|
||||
following.following_count
|
||||
end
|
||||
|
||||
%{
|
||||
stream: render("stream.json", %{topic: topic}),
|
||||
event: "pleroma:follow_relationships_update",
|
||||
|
|
@ -117,14 +135,14 @@ defmodule Pleroma.Web.StreamerView do
|
|||
%{
|
||||
state: item.state,
|
||||
follower: %{
|
||||
id: item.follower.id,
|
||||
follower_count: item.follower.follower_count,
|
||||
following_count: item.follower.following_count
|
||||
id: follower.id,
|
||||
follower_count: follower.follower_count,
|
||||
following_count: follower.following_count
|
||||
},
|
||||
following: %{
|
||||
id: item.following.id,
|
||||
follower_count: item.following.follower_count,
|
||||
following_count: item.following.following_count
|
||||
id: following.id,
|
||||
follower_count: following_follower_count,
|
||||
following_count: following_following_count
|
||||
}
|
||||
}
|
||||
|> Jason.encode!()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue