Merge branch 'develop' into issue/1023
[akkoma] / lib / pleroma / web / activity_pub / mrf / tag_policy.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 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
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" => "Create",
31 "object" => %{"attachment" => child_attachment} = object
32 } = message
33 )
34 when length(child_attachment) > 0 do
35 tags = (object["tag"] || []) ++ ["nsfw"]
36
37 object =
38 object
39 |> Map.put("tag", tags)
40 |> Map.put("sensitive", true)
41
42 message = Map.put(message, "object", object)
43
44 {:ok, message}
45 end
46
47 defp process_tag(
48 "mrf_tag:media-strip",
49 %{
50 "type" => "Create",
51 "object" => %{"attachment" => child_attachment} = object
52 } = message
53 )
54 when length(child_attachment) > 0 do
55 object = Map.delete(object, "attachment")
56 message = Map.put(message, "object", object)
57
58 {:ok, message}
59 end
60
61 defp process_tag(
62 "mrf_tag:force-unlisted",
63 %{
64 "type" => "Create",
65 "to" => to,
66 "cc" => cc,
67 "actor" => actor,
68 "object" => object
69 } = message
70 ) do
71 user = User.get_cached_by_ap_id(actor)
72
73 if Enum.member?(to, Pleroma.Constants.as_public()) do
74 to = List.delete(to, Pleroma.Constants.as_public()) ++ [user.follower_address]
75 cc = List.delete(cc, user.follower_address) ++ [Pleroma.Constants.as_public()]
76
77 object =
78 object
79 |> Map.put("to", to)
80 |> Map.put("cc", cc)
81
82 message =
83 message
84 |> Map.put("to", to)
85 |> Map.put("cc", cc)
86 |> Map.put("object", object)
87
88 {:ok, message}
89 else
90 {:ok, message}
91 end
92 end
93
94 defp process_tag(
95 "mrf_tag:sandbox",
96 %{
97 "type" => "Create",
98 "to" => to,
99 "cc" => cc,
100 "actor" => actor,
101 "object" => object
102 } = message
103 ) do
104 user = User.get_cached_by_ap_id(actor)
105
106 if Enum.member?(to, Pleroma.Constants.as_public()) or
107 Enum.member?(cc, Pleroma.Constants.as_public()) do
108 to = List.delete(to, Pleroma.Constants.as_public()) ++ [user.follower_address]
109 cc = List.delete(cc, Pleroma.Constants.as_public())
110
111 object =
112 object
113 |> Map.put("to", to)
114 |> Map.put("cc", cc)
115
116 message =
117 message
118 |> Map.put("to", to)
119 |> Map.put("cc", cc)
120 |> Map.put("object", object)
121
122 {:ok, message}
123 else
124 {:ok, message}
125 end
126 end
127
128 defp process_tag(
129 "mrf_tag:disable-remote-subscription",
130 %{"type" => "Follow", "actor" => actor} = message
131 ) do
132 user = User.get_cached_by_ap_id(actor)
133
134 if user.local == true do
135 {:ok, message}
136 else
137 {:reject,
138 "[TagPolicy] Follow from #{actor} tagged with mrf_tag:disable-remote-subscription"}
139 end
140 end
141
142 defp process_tag("mrf_tag:disable-any-subscription", %{"type" => "Follow", "actor" => actor}),
143 do: {:reject, "[TagPolicy] Follow from #{actor} tagged with mrf_tag:disable-any-subscription"}
144
145 defp process_tag(_, message), do: {:ok, message}
146
147 def filter_message(actor, message) do
148 User.get_cached_by_ap_id(actor)
149 |> get_tags()
150 |> Enum.reduce({:ok, message}, fn
151 tag, {:ok, message} ->
152 process_tag(tag, message)
153
154 _, error ->
155 error
156 end)
157 end
158
159 @impl true
160 def filter(%{"object" => target_actor, "type" => "Follow"} = message),
161 do: filter_message(target_actor, message)
162
163 @impl true
164 def filter(%{"actor" => actor, "type" => "Create"} = message),
165 do: filter_message(actor, message)
166
167 @impl true
168 def filter(message), do: {:ok, message}
169
170 @impl true
171 def describe, do: {:ok, %{}}
172 end