Fix tagpolicy to also work with Update
[akkoma] / lib / pleroma / web / activity_pub / mrf / tag_policy.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 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" => type,
56 "to" => to,
57 "cc" => cc,
58 "actor" => actor,
59 "object" => object
60 } = message
61 ) when type in ["Create", "Update"] 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" => type,
89 "to" => to,
90 "cc" => cc,
91 "actor" => actor,
92 "object" => object
93 } = message
94 ) when type in ["Create", "Update"] 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