Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

539 lines
17KB

  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. defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
  5. use Pleroma.DataCase
  6. import Pleroma.Factory
  7. alias Pleroma.Web.ActivityPub.MRF.SimplePolicy
  8. alias Pleroma.Web.CommonAPI
  9. setup do:
  10. clear_config(:mrf_simple,
  11. media_removal: [],
  12. media_nsfw: [],
  13. federated_timeline_removal: [],
  14. report_removal: [],
  15. reject: [],
  16. followers_only: [],
  17. accept: [],
  18. avatar_removal: [],
  19. banner_removal: [],
  20. reject_deletes: []
  21. )
  22. describe "when :media_removal" do
  23. test "is empty" do
  24. clear_config([:mrf_simple, :media_removal], [])
  25. media_message = build_media_message()
  26. local_message = build_local_message()
  27. assert SimplePolicy.filter(media_message) == {:ok, media_message}
  28. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  29. end
  30. test "has a matching host" do
  31. clear_config([:mrf_simple, :media_removal], ["remote.instance"])
  32. media_message = build_media_message()
  33. local_message = build_local_message()
  34. assert SimplePolicy.filter(media_message) ==
  35. {:ok,
  36. media_message
  37. |> Map.put("object", Map.delete(media_message["object"], "attachment"))}
  38. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  39. end
  40. test "match with wildcard domain" do
  41. clear_config([:mrf_simple, :media_removal], ["*.remote.instance"])
  42. media_message = build_media_message()
  43. local_message = build_local_message()
  44. assert SimplePolicy.filter(media_message) ==
  45. {:ok,
  46. media_message
  47. |> Map.put("object", Map.delete(media_message["object"], "attachment"))}
  48. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  49. end
  50. end
  51. describe "when :media_nsfw" do
  52. test "is empty" do
  53. clear_config([:mrf_simple, :media_nsfw], [])
  54. media_message = build_media_message()
  55. local_message = build_local_message()
  56. assert SimplePolicy.filter(media_message) == {:ok, media_message}
  57. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  58. end
  59. test "has a matching host" do
  60. clear_config([:mrf_simple, :media_nsfw], ["remote.instance"])
  61. media_message = build_media_message()
  62. local_message = build_local_message()
  63. assert SimplePolicy.filter(media_message) ==
  64. {:ok,
  65. media_message
  66. |> put_in(["object", "tag"], ["foo", "nsfw"])
  67. |> put_in(["object", "sensitive"], true)}
  68. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  69. end
  70. test "match with wildcard domain" do
  71. clear_config([:mrf_simple, :media_nsfw], ["*.remote.instance"])
  72. media_message = build_media_message()
  73. local_message = build_local_message()
  74. assert SimplePolicy.filter(media_message) ==
  75. {:ok,
  76. media_message
  77. |> put_in(["object", "tag"], ["foo", "nsfw"])
  78. |> put_in(["object", "sensitive"], true)}
  79. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  80. end
  81. end
  82. defp build_media_message do
  83. %{
  84. "actor" => "https://remote.instance/users/bob",
  85. "type" => "Create",
  86. "object" => %{
  87. "attachment" => [%{}],
  88. "tag" => ["foo"],
  89. "sensitive" => false
  90. }
  91. }
  92. end
  93. describe "when :report_removal" do
  94. test "is empty" do
  95. clear_config([:mrf_simple, :report_removal], [])
  96. report_message = build_report_message()
  97. local_message = build_local_message()
  98. assert SimplePolicy.filter(report_message) == {:ok, report_message}
  99. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  100. end
  101. test "has a matching host" do
  102. clear_config([:mrf_simple, :report_removal], ["remote.instance"])
  103. report_message = build_report_message()
  104. local_message = build_local_message()
  105. assert {:reject, _} = SimplePolicy.filter(report_message)
  106. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  107. end
  108. test "match with wildcard domain" do
  109. clear_config([:mrf_simple, :report_removal], ["*.remote.instance"])
  110. report_message = build_report_message()
  111. local_message = build_local_message()
  112. assert {:reject, _} = SimplePolicy.filter(report_message)
  113. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  114. end
  115. end
  116. defp build_report_message do
  117. %{
  118. "actor" => "https://remote.instance/users/bob",
  119. "type" => "Flag"
  120. }
  121. end
  122. describe "when :federated_timeline_removal" do
  123. test "is empty" do
  124. clear_config([:mrf_simple, :federated_timeline_removal], [])
  125. {_, ftl_message} = build_ftl_actor_and_message()
  126. local_message = build_local_message()
  127. assert SimplePolicy.filter(ftl_message) == {:ok, ftl_message}
  128. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  129. end
  130. test "has a matching host" do
  131. {actor, ftl_message} = build_ftl_actor_and_message()
  132. ftl_message_actor_host =
  133. ftl_message
  134. |> Map.fetch!("actor")
  135. |> URI.parse()
  136. |> Map.fetch!(:host)
  137. clear_config([:mrf_simple, :federated_timeline_removal], [ftl_message_actor_host])
  138. local_message = build_local_message()
  139. assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
  140. assert actor.follower_address in ftl_message["to"]
  141. refute actor.follower_address in ftl_message["cc"]
  142. refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"]
  143. assert "https://www.w3.org/ns/activitystreams#Public" in ftl_message["cc"]
  144. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  145. end
  146. test "match with wildcard domain" do
  147. {actor, ftl_message} = build_ftl_actor_and_message()
  148. ftl_message_actor_host =
  149. ftl_message
  150. |> Map.fetch!("actor")
  151. |> URI.parse()
  152. |> Map.fetch!(:host)
  153. clear_config([:mrf_simple, :federated_timeline_removal], ["*." <> ftl_message_actor_host])
  154. local_message = build_local_message()
  155. assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
  156. assert actor.follower_address in ftl_message["to"]
  157. refute actor.follower_address in ftl_message["cc"]
  158. refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"]
  159. assert "https://www.w3.org/ns/activitystreams#Public" in ftl_message["cc"]
  160. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  161. end
  162. test "has a matching host but only as:Public in to" do
  163. {_actor, ftl_message} = build_ftl_actor_and_message()
  164. ftl_message_actor_host =
  165. ftl_message
  166. |> Map.fetch!("actor")
  167. |> URI.parse()
  168. |> Map.fetch!(:host)
  169. ftl_message = Map.put(ftl_message, "cc", [])
  170. clear_config([:mrf_simple, :federated_timeline_removal], [ftl_message_actor_host])
  171. assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
  172. refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"]
  173. assert "https://www.w3.org/ns/activitystreams#Public" in ftl_message["cc"]
  174. end
  175. end
  176. defp build_ftl_actor_and_message do
  177. actor = insert(:user)
  178. {actor,
  179. %{
  180. "actor" => actor.ap_id,
  181. "to" => ["https://www.w3.org/ns/activitystreams#Public", "http://foo.bar/baz"],
  182. "cc" => [actor.follower_address, "http://foo.bar/qux"]
  183. }}
  184. end
  185. describe "when :reject" do
  186. test "is empty" do
  187. clear_config([:mrf_simple, :reject], [])
  188. remote_message = build_remote_message()
  189. assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
  190. end
  191. test "activity has a matching host" do
  192. clear_config([:mrf_simple, :reject], ["remote.instance"])
  193. remote_message = build_remote_message()
  194. assert {:reject, _} = SimplePolicy.filter(remote_message)
  195. end
  196. test "activity matches with wildcard domain" do
  197. clear_config([:mrf_simple, :reject], ["*.remote.instance"])
  198. remote_message = build_remote_message()
  199. assert {:reject, _} = SimplePolicy.filter(remote_message)
  200. end
  201. test "actor has a matching host" do
  202. clear_config([:mrf_simple, :reject], ["remote.instance"])
  203. remote_user = build_remote_user()
  204. assert {:reject, _} = SimplePolicy.filter(remote_user)
  205. end
  206. end
  207. describe "when :followers_only" do
  208. test "is empty" do
  209. clear_config([:mrf_simple, :followers_only], [])
  210. {_, ftl_message} = build_ftl_actor_and_message()
  211. local_message = build_local_message()
  212. assert SimplePolicy.filter(ftl_message) == {:ok, ftl_message}
  213. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  214. end
  215. test "has a matching host" do
  216. actor = insert(:user)
  217. following_user = insert(:user)
  218. non_following_user = insert(:user)
  219. {:ok, _, _, _} = CommonAPI.follow(following_user, actor)
  220. activity = %{
  221. "actor" => actor.ap_id,
  222. "to" => [
  223. "https://www.w3.org/ns/activitystreams#Public",
  224. following_user.ap_id,
  225. non_following_user.ap_id
  226. ],
  227. "cc" => [actor.follower_address, "http://foo.bar/qux"]
  228. }
  229. dm_activity = %{
  230. "actor" => actor.ap_id,
  231. "to" => [
  232. following_user.ap_id,
  233. non_following_user.ap_id
  234. ],
  235. "cc" => []
  236. }
  237. actor_domain =
  238. activity
  239. |> Map.fetch!("actor")
  240. |> URI.parse()
  241. |> Map.fetch!(:host)
  242. clear_config([:mrf_simple, :followers_only], [actor_domain])
  243. assert {:ok, new_activity} = SimplePolicy.filter(activity)
  244. assert actor.follower_address in new_activity["cc"]
  245. assert following_user.ap_id in new_activity["to"]
  246. refute "https://www.w3.org/ns/activitystreams#Public" in new_activity["to"]
  247. refute "https://www.w3.org/ns/activitystreams#Public" in new_activity["cc"]
  248. refute non_following_user.ap_id in new_activity["to"]
  249. refute non_following_user.ap_id in new_activity["cc"]
  250. assert {:ok, new_dm_activity} = SimplePolicy.filter(dm_activity)
  251. assert new_dm_activity["to"] == [following_user.ap_id]
  252. assert new_dm_activity["cc"] == []
  253. end
  254. end
  255. describe "when :accept" do
  256. test "is empty" do
  257. clear_config([:mrf_simple, :accept], [])
  258. local_message = build_local_message()
  259. remote_message = build_remote_message()
  260. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  261. assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
  262. end
  263. test "is not empty but activity doesn't have a matching host" do
  264. clear_config([:mrf_simple, :accept], ["non.matching.remote"])
  265. local_message = build_local_message()
  266. remote_message = build_remote_message()
  267. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  268. assert {:reject, _} = SimplePolicy.filter(remote_message)
  269. end
  270. test "activity has a matching host" do
  271. clear_config([:mrf_simple, :accept], ["remote.instance"])
  272. local_message = build_local_message()
  273. remote_message = build_remote_message()
  274. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  275. assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
  276. end
  277. test "activity matches with wildcard domain" do
  278. clear_config([:mrf_simple, :accept], ["*.remote.instance"])
  279. local_message = build_local_message()
  280. remote_message = build_remote_message()
  281. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  282. assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
  283. end
  284. test "actor has a matching host" do
  285. clear_config([:mrf_simple, :accept], ["remote.instance"])
  286. remote_user = build_remote_user()
  287. assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
  288. end
  289. end
  290. describe "when :avatar_removal" do
  291. test "is empty" do
  292. clear_config([:mrf_simple, :avatar_removal], [])
  293. remote_user = build_remote_user()
  294. assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
  295. end
  296. test "is not empty but it doesn't have a matching host" do
  297. clear_config([:mrf_simple, :avatar_removal], ["non.matching.remote"])
  298. remote_user = build_remote_user()
  299. assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
  300. end
  301. test "has a matching host" do
  302. clear_config([:mrf_simple, :avatar_removal], ["remote.instance"])
  303. remote_user = build_remote_user()
  304. {:ok, filtered} = SimplePolicy.filter(remote_user)
  305. refute filtered["icon"]
  306. end
  307. test "match with wildcard domain" do
  308. clear_config([:mrf_simple, :avatar_removal], ["*.remote.instance"])
  309. remote_user = build_remote_user()
  310. {:ok, filtered} = SimplePolicy.filter(remote_user)
  311. refute filtered["icon"]
  312. end
  313. end
  314. describe "when :banner_removal" do
  315. test "is empty" do
  316. clear_config([:mrf_simple, :banner_removal], [])
  317. remote_user = build_remote_user()
  318. assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
  319. end
  320. test "is not empty but it doesn't have a matching host" do
  321. clear_config([:mrf_simple, :banner_removal], ["non.matching.remote"])
  322. remote_user = build_remote_user()
  323. assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
  324. end
  325. test "has a matching host" do
  326. clear_config([:mrf_simple, :banner_removal], ["remote.instance"])
  327. remote_user = build_remote_user()
  328. {:ok, filtered} = SimplePolicy.filter(remote_user)
  329. refute filtered["image"]
  330. end
  331. test "match with wildcard domain" do
  332. clear_config([:mrf_simple, :banner_removal], ["*.remote.instance"])
  333. remote_user = build_remote_user()
  334. {:ok, filtered} = SimplePolicy.filter(remote_user)
  335. refute filtered["image"]
  336. end
  337. end
  338. describe "when :reject_deletes is empty" do
  339. setup do: clear_config([:mrf_simple, :reject_deletes], [])
  340. test "it accepts deletions even from rejected servers" do
  341. clear_config([:mrf_simple, :reject], ["remote.instance"])
  342. deletion_message = build_remote_deletion_message()
  343. assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
  344. end
  345. test "it accepts deletions even from non-whitelisted servers" do
  346. clear_config([:mrf_simple, :accept], ["non.matching.remote"])
  347. deletion_message = build_remote_deletion_message()
  348. assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
  349. end
  350. end
  351. describe "when :reject_deletes is not empty but it doesn't have a matching host" do
  352. setup do: clear_config([:mrf_simple, :reject_deletes], ["non.matching.remote"])
  353. test "it accepts deletions even from rejected servers" do
  354. clear_config([:mrf_simple, :reject], ["remote.instance"])
  355. deletion_message = build_remote_deletion_message()
  356. assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
  357. end
  358. test "it accepts deletions even from non-whitelisted servers" do
  359. clear_config([:mrf_simple, :accept], ["non.matching.remote"])
  360. deletion_message = build_remote_deletion_message()
  361. assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
  362. end
  363. end
  364. describe "when :reject_deletes has a matching host" do
  365. setup do: clear_config([:mrf_simple, :reject_deletes], ["remote.instance"])
  366. test "it rejects the deletion" do
  367. deletion_message = build_remote_deletion_message()
  368. assert {:reject, _} = SimplePolicy.filter(deletion_message)
  369. end
  370. end
  371. describe "when :reject_deletes match with wildcard domain" do
  372. setup do: clear_config([:mrf_simple, :reject_deletes], ["*.remote.instance"])
  373. test "it rejects the deletion" do
  374. deletion_message = build_remote_deletion_message()
  375. assert {:reject, _} = SimplePolicy.filter(deletion_message)
  376. end
  377. end
  378. defp build_local_message do
  379. %{
  380. "actor" => "#{Pleroma.Web.Endpoint.url()}/users/alice",
  381. "to" => [],
  382. "cc" => []
  383. }
  384. end
  385. defp build_remote_message do
  386. %{"actor" => "https://remote.instance/users/bob"}
  387. end
  388. defp build_remote_user do
  389. %{
  390. "id" => "https://remote.instance/users/bob",
  391. "icon" => %{
  392. "url" => "http://example.com/image.jpg",
  393. "type" => "Image"
  394. },
  395. "image" => %{
  396. "url" => "http://example.com/image.jpg",
  397. "type" => "Image"
  398. },
  399. "type" => "Person"
  400. }
  401. end
  402. defp build_remote_deletion_message do
  403. %{
  404. "type" => "Delete",
  405. "actor" => "https://remote.instance/users/bob"
  406. }
  407. end
  408. end