logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma git clone https://hacktivis.me/git/pleroma.git

simple_policy_test.exs (19312B)


  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. 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", "Some reason"}])
  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", "Whatever reason"}])
  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. test "works with Updates" do
  51. clear_config([:mrf_simple, :media_removal], [{"remote.instance", "Some reason"}])
  52. media_message = build_media_message(type: "Update")
  53. assert SimplePolicy.filter(media_message) ==
  54. {:ok,
  55. media_message
  56. |> Map.put("object", Map.delete(media_message["object"], "attachment"))}
  57. end
  58. end
  59. describe "when :media_nsfw" do
  60. test "is empty" do
  61. clear_config([:mrf_simple, :media_nsfw], [])
  62. media_message = build_media_message()
  63. local_message = build_local_message()
  64. assert SimplePolicy.filter(media_message) == {:ok, media_message}
  65. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  66. end
  67. test "has a matching host" do
  68. clear_config([:mrf_simple, :media_nsfw], [{"remote.instance", "Whetever"}])
  69. media_message = build_media_message()
  70. local_message = build_local_message()
  71. assert SimplePolicy.filter(media_message) ==
  72. {:ok, put_in(media_message, ["object", "sensitive"], true)}
  73. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  74. end
  75. test "match with wildcard domain" do
  76. clear_config([:mrf_simple, :media_nsfw], [{"*.remote.instance", "yeah yeah"}])
  77. media_message = build_media_message()
  78. local_message = build_local_message()
  79. assert SimplePolicy.filter(media_message) ==
  80. {:ok, put_in(media_message, ["object", "sensitive"], true)}
  81. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  82. end
  83. test "works with Updates" do
  84. clear_config([:mrf_simple, :media_nsfw], [{"remote.instance", "Whetever"}])
  85. media_message = build_media_message(type: "Update")
  86. assert SimplePolicy.filter(media_message) ==
  87. {:ok, put_in(media_message, ["object", "sensitive"], true)}
  88. end
  89. end
  90. defp build_media_message(opts \\ []) do
  91. %{
  92. "actor" => "https://remote.instance/users/bob",
  93. "type" => opts[:type] || "Create",
  94. "object" => %{
  95. "attachment" => [%{}],
  96. "tag" => ["foo"],
  97. "sensitive" => false
  98. }
  99. }
  100. end
  101. describe "when :report_removal" do
  102. test "is empty" do
  103. clear_config([:mrf_simple, :report_removal], [])
  104. report_message = build_report_message()
  105. local_message = build_local_message()
  106. assert SimplePolicy.filter(report_message) == {:ok, report_message}
  107. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  108. end
  109. test "has a matching host" do
  110. clear_config([:mrf_simple, :report_removal], [{"remote.instance", "muh"}])
  111. report_message = build_report_message()
  112. local_message = build_local_message()
  113. assert {:reject, _} = SimplePolicy.filter(report_message)
  114. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  115. end
  116. test "match with wildcard domain" do
  117. clear_config([:mrf_simple, :report_removal], [{"*.remote.instance", "suya"}])
  118. report_message = build_report_message()
  119. local_message = build_local_message()
  120. assert {:reject, _} = SimplePolicy.filter(report_message)
  121. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  122. end
  123. end
  124. defp build_report_message do
  125. %{
  126. "actor" => "https://remote.instance/users/bob",
  127. "type" => "Flag"
  128. }
  129. end
  130. describe "when :federated_timeline_removal" do
  131. test "is empty" do
  132. clear_config([:mrf_simple, :federated_timeline_removal], [])
  133. {_, ftl_message} = build_ftl_actor_and_message()
  134. local_message = build_local_message()
  135. assert SimplePolicy.filter(ftl_message) == {:ok, ftl_message}
  136. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  137. end
  138. test "has a matching host" do
  139. {actor, ftl_message} = build_ftl_actor_and_message()
  140. ftl_message_actor_host =
  141. ftl_message
  142. |> Map.fetch!("actor")
  143. |> URI.parse()
  144. |> Map.fetch!(:host)
  145. clear_config([:mrf_simple, :federated_timeline_removal], [{ftl_message_actor_host, "uwu"}])
  146. local_message = build_local_message()
  147. assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
  148. assert actor.follower_address in ftl_message["to"]
  149. refute actor.follower_address in ftl_message["cc"]
  150. refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"]
  151. assert "https://www.w3.org/ns/activitystreams#Public" in ftl_message["cc"]
  152. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  153. end
  154. test "match with wildcard domain" do
  155. {actor, ftl_message} = build_ftl_actor_and_message()
  156. ftl_message_actor_host =
  157. ftl_message
  158. |> Map.fetch!("actor")
  159. |> URI.parse()
  160. |> Map.fetch!(:host)
  161. clear_config([:mrf_simple, :federated_timeline_removal], [
  162. {"*." <> ftl_message_actor_host, "owo"}
  163. ])
  164. local_message = build_local_message()
  165. assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
  166. assert actor.follower_address in ftl_message["to"]
  167. refute actor.follower_address in ftl_message["cc"]
  168. refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"]
  169. assert "https://www.w3.org/ns/activitystreams#Public" in ftl_message["cc"]
  170. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  171. end
  172. test "has a matching host but only as:Public in to" do
  173. {_actor, ftl_message} = build_ftl_actor_and_message()
  174. ftl_message_actor_host =
  175. ftl_message
  176. |> Map.fetch!("actor")
  177. |> URI.parse()
  178. |> Map.fetch!(:host)
  179. ftl_message = Map.put(ftl_message, "cc", [])
  180. clear_config([:mrf_simple, :federated_timeline_removal], [
  181. {ftl_message_actor_host, "spiderwaifu goes 88w88"}
  182. ])
  183. assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
  184. refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"]
  185. assert "https://www.w3.org/ns/activitystreams#Public" in ftl_message["cc"]
  186. end
  187. end
  188. defp build_ftl_actor_and_message do
  189. actor = insert(:user)
  190. {actor,
  191. %{
  192. "actor" => actor.ap_id,
  193. "to" => ["https://www.w3.org/ns/activitystreams#Public", "http://foo.bar/baz"],
  194. "cc" => [actor.follower_address, "http://foo.bar/qux"]
  195. }}
  196. end
  197. describe "when :reject" do
  198. test "is empty" do
  199. clear_config([:mrf_simple, :reject], [])
  200. remote_message = build_remote_message()
  201. assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
  202. assert SimplePolicy.id_filter(remote_message["actor"])
  203. end
  204. test "activity has a matching host" do
  205. clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
  206. remote_message = build_remote_message()
  207. assert {:reject, _} = SimplePolicy.filter(remote_message)
  208. refute SimplePolicy.id_filter(remote_message["actor"])
  209. end
  210. test "activity matches with wildcard domain" do
  211. clear_config([:mrf_simple, :reject], [{"*.remote.instance", ""}])
  212. remote_message = build_remote_message()
  213. assert {:reject, _} = SimplePolicy.filter(remote_message)
  214. refute SimplePolicy.id_filter(remote_message["actor"])
  215. end
  216. test "actor has a matching host" do
  217. clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
  218. remote_user = build_remote_user()
  219. assert {:reject, _} = SimplePolicy.filter(remote_user)
  220. refute SimplePolicy.id_filter(remote_user["id"])
  221. end
  222. test "reject Announce when object would be rejected" do
  223. clear_config([:mrf_simple, :reject], [{"blocked.tld", ""}])
  224. announce = %{
  225. "type" => "Announce",
  226. "actor" => "https://okay.tld/users/alice",
  227. "object" => %{"type" => "Note", "actor" => "https://blocked.tld/users/bob"}
  228. }
  229. assert {:reject, _} = SimplePolicy.filter(announce)
  230. # Note: Non-Applicable for id_filter/1
  231. end
  232. test "reject by URI object" do
  233. clear_config([:mrf_simple, :reject], [{"blocked.tld", ""}])
  234. announce = %{
  235. "type" => "Announce",
  236. "actor" => "https://okay.tld/users/alice",
  237. "object" => "https://blocked.tld/activities/1"
  238. }
  239. assert {:reject, _} = SimplePolicy.filter(announce)
  240. # Note: Non-Applicable for id_filter/1
  241. end
  242. end
  243. describe "when :followers_only" do
  244. test "is empty" do
  245. clear_config([:mrf_simple, :followers_only], [])
  246. {_, ftl_message} = build_ftl_actor_and_message()
  247. local_message = build_local_message()
  248. assert SimplePolicy.filter(ftl_message) == {:ok, ftl_message}
  249. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  250. end
  251. test "has a matching host" do
  252. actor = insert(:user)
  253. following_user = insert(:user)
  254. non_following_user = insert(:user)
  255. {:ok, _, _, _} = CommonAPI.follow(following_user, actor)
  256. activity = %{
  257. "actor" => actor.ap_id,
  258. "to" => [
  259. "https://www.w3.org/ns/activitystreams#Public",
  260. following_user.ap_id,
  261. non_following_user.ap_id
  262. ],
  263. "cc" => [actor.follower_address, "http://foo.bar/qux"]
  264. }
  265. dm_activity = %{
  266. "actor" => actor.ap_id,
  267. "to" => [
  268. following_user.ap_id,
  269. non_following_user.ap_id
  270. ],
  271. "cc" => []
  272. }
  273. actor_domain =
  274. activity
  275. |> Map.fetch!("actor")
  276. |> URI.parse()
  277. |> Map.fetch!(:host)
  278. clear_config([:mrf_simple, :followers_only], [{actor_domain, ""}])
  279. assert {:ok, new_activity} = SimplePolicy.filter(activity)
  280. assert actor.follower_address in new_activity["cc"]
  281. assert following_user.ap_id in new_activity["to"]
  282. refute "https://www.w3.org/ns/activitystreams#Public" in new_activity["to"]
  283. refute "https://www.w3.org/ns/activitystreams#Public" in new_activity["cc"]
  284. refute non_following_user.ap_id in new_activity["to"]
  285. refute non_following_user.ap_id in new_activity["cc"]
  286. assert {:ok, new_dm_activity} = SimplePolicy.filter(dm_activity)
  287. assert new_dm_activity["to"] == [following_user.ap_id]
  288. assert new_dm_activity["cc"] == []
  289. end
  290. end
  291. describe "when :accept" do
  292. test "is empty" do
  293. clear_config([:mrf_simple, :accept], [])
  294. local_message = build_local_message()
  295. remote_message = build_remote_message()
  296. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  297. assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
  298. assert SimplePolicy.id_filter(local_message["actor"])
  299. assert SimplePolicy.id_filter(remote_message["actor"])
  300. end
  301. test "is not empty but activity doesn't have a matching host" do
  302. clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}])
  303. local_message = build_local_message()
  304. remote_message = build_remote_message()
  305. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  306. assert {:reject, _} = SimplePolicy.filter(remote_message)
  307. assert SimplePolicy.id_filter(local_message["actor"])
  308. refute SimplePolicy.id_filter(remote_message["actor"])
  309. end
  310. test "activity has a matching host" do
  311. clear_config([:mrf_simple, :accept], [{"remote.instance", ""}])
  312. local_message = build_local_message()
  313. remote_message = build_remote_message()
  314. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  315. assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
  316. assert SimplePolicy.id_filter(local_message["actor"])
  317. assert SimplePolicy.id_filter(remote_message["actor"])
  318. end
  319. test "activity matches with wildcard domain" do
  320. clear_config([:mrf_simple, :accept], [{"*.remote.instance", ""}])
  321. local_message = build_local_message()
  322. remote_message = build_remote_message()
  323. assert SimplePolicy.filter(local_message) == {:ok, local_message}
  324. assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
  325. assert SimplePolicy.id_filter(local_message["actor"])
  326. assert SimplePolicy.id_filter(remote_message["actor"])
  327. end
  328. test "actor has a matching host" do
  329. clear_config([:mrf_simple, :accept], [{"remote.instance", ""}])
  330. remote_user = build_remote_user()
  331. assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
  332. assert SimplePolicy.id_filter(remote_user["id"])
  333. end
  334. end
  335. describe "when :avatar_removal" do
  336. test "is empty" do
  337. clear_config([:mrf_simple, :avatar_removal], [])
  338. remote_user = build_remote_user()
  339. assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
  340. end
  341. test "is not empty but it doesn't have a matching host" do
  342. clear_config([:mrf_simple, :avatar_removal], [{"non.matching.remote", ""}])
  343. remote_user = build_remote_user()
  344. assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
  345. end
  346. test "has a matching host" do
  347. clear_config([:mrf_simple, :avatar_removal], [{"remote.instance", ""}])
  348. remote_user = build_remote_user()
  349. {:ok, filtered} = SimplePolicy.filter(remote_user)
  350. refute filtered["icon"]
  351. end
  352. test "match with wildcard domain" do
  353. clear_config([:mrf_simple, :avatar_removal], [{"*.remote.instance", ""}])
  354. remote_user = build_remote_user()
  355. {:ok, filtered} = SimplePolicy.filter(remote_user)
  356. refute filtered["icon"]
  357. end
  358. end
  359. describe "when :banner_removal" do
  360. test "is empty" do
  361. clear_config([:mrf_simple, :banner_removal], [])
  362. remote_user = build_remote_user()
  363. assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
  364. end
  365. test "is not empty but it doesn't have a matching host" do
  366. clear_config([:mrf_simple, :banner_removal], [{"non.matching.remote", ""}])
  367. remote_user = build_remote_user()
  368. assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
  369. end
  370. test "has a matching host" do
  371. clear_config([:mrf_simple, :banner_removal], [{"remote.instance", ""}])
  372. remote_user = build_remote_user()
  373. {:ok, filtered} = SimplePolicy.filter(remote_user)
  374. refute filtered["image"]
  375. end
  376. test "match with wildcard domain" do
  377. clear_config([:mrf_simple, :banner_removal], [{"*.remote.instance", ""}])
  378. remote_user = build_remote_user()
  379. {:ok, filtered} = SimplePolicy.filter(remote_user)
  380. refute filtered["image"]
  381. end
  382. end
  383. describe "when :reject_deletes is empty" do
  384. setup do: clear_config([:mrf_simple, :reject_deletes], [])
  385. test "it accepts deletions even from rejected servers" do
  386. clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
  387. deletion_message = build_remote_deletion_message()
  388. assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
  389. end
  390. test "it accepts deletions even from non-whitelisted servers" do
  391. clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}])
  392. deletion_message = build_remote_deletion_message()
  393. assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
  394. end
  395. end
  396. describe "when :reject_deletes is not empty but it doesn't have a matching host" do
  397. setup do: clear_config([:mrf_simple, :reject_deletes], [{"non.matching.remote", ""}])
  398. test "it accepts deletions even from rejected servers" do
  399. clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
  400. deletion_message = build_remote_deletion_message()
  401. assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
  402. end
  403. test "it accepts deletions even from non-whitelisted servers" do
  404. clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}])
  405. deletion_message = build_remote_deletion_message()
  406. assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
  407. end
  408. end
  409. describe "when :reject_deletes has a matching host" do
  410. setup do: clear_config([:mrf_simple, :reject_deletes], [{"remote.instance", ""}])
  411. test "it rejects the deletion" do
  412. deletion_message = build_remote_deletion_message()
  413. assert {:reject, _} = SimplePolicy.filter(deletion_message)
  414. end
  415. end
  416. describe "when :reject_deletes match with wildcard domain" do
  417. setup do: clear_config([:mrf_simple, :reject_deletes], [{"*.remote.instance", ""}])
  418. test "it rejects the deletion" do
  419. deletion_message = build_remote_deletion_message()
  420. assert {:reject, _} = SimplePolicy.filter(deletion_message)
  421. end
  422. end
  423. defp build_local_message do
  424. %{
  425. "actor" => "#{Pleroma.Web.Endpoint.url()}/users/alice",
  426. "to" => [],
  427. "cc" => []
  428. }
  429. end
  430. defp build_remote_message do
  431. %{"actor" => "https://remote.instance/users/bob"}
  432. end
  433. defp build_remote_user do
  434. %{
  435. "id" => "https://remote.instance/users/bob",
  436. "icon" => %{
  437. "url" => "http://example.com/image.jpg",
  438. "type" => "Image"
  439. },
  440. "image" => %{
  441. "url" => "http://example.com/image.jpg",
  442. "type" => "Image"
  443. },
  444. "type" => "Person"
  445. }
  446. end
  447. defp build_remote_deletion_message do
  448. %{
  449. "type" => "Delete",
  450. "actor" => "https://remote.instance/users/bob"
  451. }
  452. end
  453. end