Merge branch 'tests/mrf_policy' into 'develop'
[akkoma] / lib / pleroma / web / activity_pub / mrf / tag_policy.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 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 @public "https://www.w3.org/ns/activitystreams#Public"
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, @public) do
74 to = List.delete(to, @public) ++ [user.follower_address]
75 cc = List.delete(cc, user.follower_address) ++ [@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, @public) or Enum.member?(cc, @public) do
107 to = List.delete(to, @public) ++ [user.follower_address]
108 cc = List.delete(cc, @public)
109
110 object =
111 object
112 |> Map.put("to", to)
113 |> Map.put("cc", cc)
114
115 message =
116 message
117 |> Map.put("to", to)
118 |> Map.put("cc", cc)
119 |> Map.put("object", object)
120
121 {:ok, message}
122 else
123 {:ok, message}
124 end
125 end
126
127 defp process_tag(
128 "mrf_tag:disable-remote-subscription",
129 %{"type" => "Follow", "actor" => actor} = message
130 ) do
131 user = User.get_cached_by_ap_id(actor)
132
133 if user.local == true do
134 {:ok, message}
135 else
136 {:reject, nil}
137 end
138 end
139
140 defp process_tag("mrf_tag:disable-any-subscription", %{"type" => "Follow"}),
141 do: {:reject, nil}
142
143 defp process_tag(_, message), do: {:ok, message}
144
145 def filter_message(actor, message) do
146 User.get_cached_by_ap_id(actor)
147 |> get_tags()
148 |> Enum.reduce({:ok, message}, fn
149 tag, {:ok, message} ->
150 process_tag(tag, message)
151
152 _, error ->
153 error
154 end)
155 end
156
157 @impl true
158 def filter(%{"object" => target_actor, "type" => "Follow"} = message),
159 do: filter_message(target_actor, message)
160
161 @impl true
162 def filter(%{"actor" => actor, "type" => "Create"} = message),
163 do: filter_message(actor, message)
164
165 @impl true
166 def filter(message), do: {:ok, message}
167 end