move to 2.5.5
[anni] / lib / pleroma / web / activity_pub / mrf / tag_policy.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
6   alias Pleroma.User
7   @behaviour Pleroma.Web.ActivityPub.MRF.Policy
8   @moduledoc """
9      Apply policies based on user tags
10
11      This policy applies policies on a user activities depending on their tags
12      on your instance.
13
14      - `mrf_tag:media-force-nsfw`: Mark as sensitive on presence of attachments
15      - `mrf_tag:media-strip`: Remove attachments
16      - `mrf_tag:force-unlisted`: Mark as unlisted (removes from the federated timeline)
17      - `mrf_tag:sandbox`: Remove from public (local and federated) timelines
18      - `mrf_tag:disable-remote-subscription`: Reject non-local follow requests
19      - `mrf_tag:disable-any-subscription`: Reject any follow requests
20   """
21
22   require Pleroma.Constants
23
24   defp get_tags(%User{tags: tags}) when is_list(tags), do: tags
25   defp get_tags(_), do: []
26
27   defp process_tag(
28          "mrf_tag:media-force-nsfw",
29          %{
30            "type" => type,
31            "object" => %{"attachment" => child_attachment}
32          } = message
33        )
34        when length(child_attachment) > 0 and type in ["Create", "Update"] do
35     {:ok, Kernel.put_in(message, ["object", "sensitive"], true)}
36   end
37
38   defp process_tag(
39          "mrf_tag:media-strip",
40          %{
41            "type" => type,
42            "object" => %{"attachment" => child_attachment} = object
43          } = message
44        )
45        when length(child_attachment) > 0 and type in ["Create", "Update"] do
46     object = Map.delete(object, "attachment")
47     message = Map.put(message, "object", object)
48
49     {:ok, message}
50   end
51
52   defp process_tag(
53          "mrf_tag:force-unlisted",
54          %{
55            "type" => "Create",
56            "to" => to,
57            "cc" => cc,
58            "actor" => actor,
59            "object" => object
60          } = message
61        ) do
62     user = User.get_cached_by_ap_id(actor)
63
64     if Enum.member?(to, Pleroma.Constants.as_public()) do
65       to = List.delete(to, Pleroma.Constants.as_public()) ++ [user.follower_address]
66       cc = List.delete(cc, user.follower_address) ++ [Pleroma.Constants.as_public()]
67
68       object =
69         object
70         |> Map.put("to", to)
71         |> Map.put("cc", cc)
72
73       message =
74         message
75         |> Map.put("to", to)
76         |> Map.put("cc", cc)
77         |> Map.put("object", object)
78
79       {:ok, message}
80     else
81       {:ok, message}
82     end
83   end
84
85   defp process_tag(
86          "mrf_tag:sandbox",
87          %{
88            "type" => "Create",
89            "to" => to,
90            "cc" => cc,
91            "actor" => actor,
92            "object" => object
93          } = message
94        ) do
95     user = User.get_cached_by_ap_id(actor)
96
97     if Enum.member?(to, Pleroma.Constants.as_public()) or
98          Enum.member?(cc, Pleroma.Constants.as_public()) do
99       to = List.delete(to, Pleroma.Constants.as_public()) ++ [user.follower_address]
100       cc = List.delete(cc, Pleroma.Constants.as_public())
101
102       object =
103         object
104         |> Map.put("to", to)
105         |> Map.put("cc", cc)
106
107       message =
108         message
109         |> Map.put("to", to)
110         |> Map.put("cc", cc)
111         |> Map.put("object", object)
112
113       {:ok, message}
114     else
115       {:ok, message}
116     end
117   end
118
119   defp process_tag(
120          "mrf_tag:disable-remote-subscription",
121          %{"type" => "Follow", "actor" => actor} = message
122        ) do
123     user = User.get_cached_by_ap_id(actor)
124
125     if user.local == true do
126       {:ok, message}
127     else
128       {:reject,
129        "[TagPolicy] Follow from #{actor} tagged with mrf_tag:disable-remote-subscription"}
130     end
131   end
132
133   defp process_tag("mrf_tag:disable-any-subscription", %{"type" => "Follow", "actor" => actor}),
134     do: {:reject, "[TagPolicy] Follow from #{actor} tagged with mrf_tag:disable-any-subscription"}
135
136   defp process_tag(_, message), do: {:ok, message}
137
138   def filter_message(actor, message) do
139     User.get_cached_by_ap_id(actor)
140     |> get_tags()
141     |> Enum.reduce({:ok, message}, fn
142       tag, {:ok, message} ->
143         process_tag(tag, message)
144
145       _, error ->
146         error
147     end)
148   end
149
150   @impl true
151   def filter(%{"object" => target_actor, "type" => "Follow"} = message),
152     do: filter_message(target_actor, message)
153
154   @impl true
155   def filter(%{"actor" => actor, "type" => type} = message) when type in ["Create", "Update"],
156     do: filter_message(actor, message)
157
158   @impl true
159   def filter(message), do: {:ok, message}
160
161   @impl true
162   def describe, do: {:ok, %{}}
163 end