logo

pleroma

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

utils_test.exs (20684B)


  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.UtilsTest do
  5. use Pleroma.DataCase, async: true
  6. alias Pleroma.Activity
  7. alias Pleroma.Object
  8. alias Pleroma.Repo
  9. alias Pleroma.User
  10. alias Pleroma.Web.ActivityPub.Utils
  11. alias Pleroma.Web.AdminAPI.AccountView
  12. alias Pleroma.Web.CommonAPI
  13. import Pleroma.Factory
  14. require Pleroma.Constants
  15. describe "strip_report_status_data/1" do
  16. test "does not break on issues with the reported activities" do
  17. reporter = insert(:user)
  18. target_account = insert(:user)
  19. {:ok, activity} = CommonAPI.post(target_account, %{status: "foobar"})
  20. context = Utils.generate_context_id()
  21. content = "foobar"
  22. post_id = activity.data["id"]
  23. res =
  24. Utils.make_flag_data(
  25. %{
  26. actor: reporter,
  27. context: context,
  28. account: target_account,
  29. statuses: [%{"id" => post_id}],
  30. content: content
  31. },
  32. %{}
  33. )
  34. res =
  35. res
  36. |> Map.put("object", res["object"] ++ [nil, 1, 5, "123"])
  37. {:ok, activity} = Pleroma.Web.ActivityPub.ActivityPub.insert(res)
  38. [user_id, object | _] = activity.data["object"]
  39. {:ok, stripped} = Utils.strip_report_status_data(activity)
  40. assert stripped.data["object"] == [user_id, object["id"]]
  41. end
  42. end
  43. describe "fetch the latest Follow" do
  44. test "fetches the latest Follow activity" do
  45. %Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity)
  46. follower = User.get_cached_by_ap_id(activity.data["actor"])
  47. followed = User.get_cached_by_ap_id(activity.data["object"])
  48. assert activity == Utils.fetch_latest_follow(follower, followed)
  49. end
  50. end
  51. describe "determine_explicit_mentions()" do
  52. test "works with an object that has mentions" do
  53. object = %{
  54. "tag" => [
  55. %{
  56. "type" => "Mention",
  57. "href" => "https://example.com/~alyssa",
  58. "name" => "Alyssa P. Hacker"
  59. }
  60. ]
  61. }
  62. assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"]
  63. end
  64. test "works with an object that does not have mentions" do
  65. object = %{
  66. "tag" => [
  67. %{"type" => "Hashtag", "href" => "https://example.com/tag/2hu", "name" => "2hu"}
  68. ]
  69. }
  70. assert Utils.determine_explicit_mentions(object) == []
  71. end
  72. test "works with an object that has mentions and other tags" do
  73. object = %{
  74. "tag" => [
  75. %{
  76. "type" => "Mention",
  77. "href" => "https://example.com/~alyssa",
  78. "name" => "Alyssa P. Hacker"
  79. },
  80. %{"type" => "Hashtag", "href" => "https://example.com/tag/2hu", "name" => "2hu"}
  81. ]
  82. }
  83. assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"]
  84. end
  85. test "works with an object that has no tags" do
  86. object = %{}
  87. assert Utils.determine_explicit_mentions(object) == []
  88. end
  89. test "works with an object that has only IR tags" do
  90. object = %{"tag" => ["2hu"]}
  91. assert Utils.determine_explicit_mentions(object) == []
  92. end
  93. test "works with an object has tags as map" do
  94. object = %{
  95. "tag" => %{
  96. "type" => "Mention",
  97. "href" => "https://example.com/~alyssa",
  98. "name" => "Alyssa P. Hacker"
  99. }
  100. }
  101. assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"]
  102. end
  103. end
  104. describe "make_like_data" do
  105. setup do
  106. user = insert(:user)
  107. other_user = insert(:user)
  108. third_user = insert(:user)
  109. [user: user, other_user: other_user, third_user: third_user]
  110. end
  111. test "addresses actor's follower address if the activity is public", %{
  112. user: user,
  113. other_user: other_user,
  114. third_user: third_user
  115. } do
  116. expected_to = Enum.sort([user.ap_id, other_user.follower_address])
  117. expected_cc = Enum.sort(["https://www.w3.org/ns/activitystreams#Public", third_user.ap_id])
  118. {:ok, activity} =
  119. CommonAPI.post(user, %{
  120. status:
  121. "hey @#{other_user.nickname}, @#{third_user.nickname} how about beering together this weekend?"
  122. })
  123. %{"to" => to, "cc" => cc} = Utils.make_like_data(other_user, activity, nil)
  124. assert Enum.sort(to) == expected_to
  125. assert Enum.sort(cc) == expected_cc
  126. end
  127. test "does not address actor's follower address if the activity is not public", %{
  128. user: user,
  129. other_user: other_user,
  130. third_user: third_user
  131. } do
  132. expected_to = Enum.sort([user.ap_id])
  133. expected_cc = [third_user.ap_id]
  134. {:ok, activity} =
  135. CommonAPI.post(user, %{
  136. status: "@#{other_user.nickname} @#{third_user.nickname} bought a new swimsuit!",
  137. visibility: "private"
  138. })
  139. %{"to" => to, "cc" => cc} = Utils.make_like_data(other_user, activity, nil)
  140. assert Enum.sort(to) == expected_to
  141. assert Enum.sort(cc) == expected_cc
  142. end
  143. end
  144. describe "make_json_ld_header/1" do
  145. test "makes jsonld header" do
  146. assert Utils.make_json_ld_header() == %{
  147. "@context" => [
  148. "https://www.w3.org/ns/activitystreams",
  149. "http://localhost:4001/schemas/litepub-0.1.jsonld",
  150. %{
  151. "@language" => "und"
  152. }
  153. ]
  154. }
  155. end
  156. test "includes language if specified" do
  157. assert Utils.make_json_ld_header(%{"language" => "pl"}) == %{
  158. "@context" => [
  159. "https://www.w3.org/ns/activitystreams",
  160. "http://localhost:4001/schemas/litepub-0.1.jsonld",
  161. %{
  162. "@language" => "pl"
  163. }
  164. ]
  165. }
  166. end
  167. end
  168. describe "get_existing_votes" do
  169. test "fetches existing votes" do
  170. user = insert(:user)
  171. other_user = insert(:user)
  172. {:ok, activity} =
  173. CommonAPI.post(user, %{
  174. status: "How do I pronounce LaTeX?",
  175. poll: %{
  176. options: ["laytekh", "lahtekh", "latex"],
  177. expires_in: 20,
  178. multiple: true
  179. }
  180. })
  181. object = Object.normalize(activity, fetch: false)
  182. {:ok, votes, object} = CommonAPI.vote(object, other_user, [0, 1])
  183. assert Enum.sort(Utils.get_existing_votes(other_user.ap_id, object)) == Enum.sort(votes)
  184. end
  185. test "fetches only Create activities" do
  186. user = insert(:user)
  187. other_user = insert(:user)
  188. {:ok, activity} =
  189. CommonAPI.post(user, %{
  190. status: "Are we living in a society?",
  191. poll: %{
  192. options: ["yes", "no"],
  193. expires_in: 20
  194. }
  195. })
  196. object = Object.normalize(activity, fetch: false)
  197. {:ok, [vote], object} = CommonAPI.vote(object, other_user, [0])
  198. {:ok, _activity} = CommonAPI.favorite(activity.id, user)
  199. [fetched_vote] = Utils.get_existing_votes(other_user.ap_id, object)
  200. assert fetched_vote.id == vote.id
  201. end
  202. end
  203. describe "update_follow_state_for_all/2" do
  204. test "updates the state of all Follow activities with the same actor and object" do
  205. user = insert(:user, is_locked: true)
  206. follower = insert(:user)
  207. {:ok, _, _, follow_activity} = CommonAPI.follow(user, follower)
  208. {:ok, _, _, follow_activity_two} = CommonAPI.follow(user, follower)
  209. data =
  210. follow_activity_two.data
  211. |> Map.put("state", "accept")
  212. cng = Ecto.Changeset.change(follow_activity_two, data: data)
  213. {:ok, follow_activity_two} = Repo.update(cng)
  214. {:ok, follow_activity_two} =
  215. Utils.update_follow_state_for_all(follow_activity_two, "accept")
  216. assert refresh_record(follow_activity).data["state"] == "accept"
  217. assert refresh_record(follow_activity_two).data["state"] == "accept"
  218. end
  219. test "also updates the state of accepted follows" do
  220. user = insert(:user)
  221. follower = insert(:user)
  222. {:ok, _, _, follow_activity} = CommonAPI.follow(user, follower)
  223. {:ok, _, _, follow_activity_two} = CommonAPI.follow(user, follower)
  224. {:ok, follow_activity_two} =
  225. Utils.update_follow_state_for_all(follow_activity_two, "reject")
  226. assert refresh_record(follow_activity).data["state"] == "reject"
  227. assert refresh_record(follow_activity_two).data["state"] == "reject"
  228. end
  229. end
  230. describe "update_follow_state/2" do
  231. test "updates the state of the given follow activity" do
  232. user = insert(:user, is_locked: true)
  233. follower = insert(:user)
  234. {:ok, _, _, follow_activity} = CommonAPI.follow(user, follower)
  235. {:ok, _, _, follow_activity_two} = CommonAPI.follow(user, follower)
  236. data =
  237. follow_activity_two.data
  238. |> Map.put("state", "accept")
  239. cng = Ecto.Changeset.change(follow_activity_two, data: data)
  240. {:ok, follow_activity_two} = Repo.update(cng)
  241. {:ok, follow_activity_two} = Utils.update_follow_state(follow_activity_two, "reject")
  242. assert refresh_record(follow_activity).data["state"] == "pending"
  243. assert refresh_record(follow_activity_two).data["state"] == "reject"
  244. end
  245. end
  246. describe "update_element_in_object/3" do
  247. test "updates likes" do
  248. user = insert(:user)
  249. activity = insert(:note_activity)
  250. object = Object.normalize(activity, fetch: false)
  251. assert {:ok, updated_object} =
  252. Utils.update_element_in_object(
  253. "like",
  254. [user.ap_id],
  255. object
  256. )
  257. assert updated_object.data["likes"] == [user.ap_id]
  258. assert updated_object.data["like_count"] == 1
  259. end
  260. end
  261. describe "add_like_to_object/2" do
  262. test "add actor to likes" do
  263. user = insert(:user)
  264. user2 = insert(:user)
  265. object = insert(:note)
  266. assert {:ok, updated_object} =
  267. Utils.add_like_to_object(
  268. %Activity{data: %{"actor" => user.ap_id}},
  269. object
  270. )
  271. assert updated_object.data["likes"] == [user.ap_id]
  272. assert updated_object.data["like_count"] == 1
  273. assert {:ok, updated_object2} =
  274. Utils.add_like_to_object(
  275. %Activity{data: %{"actor" => user2.ap_id}},
  276. updated_object
  277. )
  278. assert updated_object2.data["likes"] == [user2.ap_id, user.ap_id]
  279. assert updated_object2.data["like_count"] == 2
  280. end
  281. end
  282. describe "remove_like_from_object/2" do
  283. test "removes ap_id from likes" do
  284. user = insert(:user)
  285. user2 = insert(:user)
  286. object = insert(:note, data: %{"likes" => [user.ap_id, user2.ap_id], "like_count" => 2})
  287. assert {:ok, updated_object} =
  288. Utils.remove_like_from_object(
  289. %Activity{data: %{"actor" => user.ap_id}},
  290. object
  291. )
  292. assert updated_object.data["likes"] == [user2.ap_id]
  293. assert updated_object.data["like_count"] == 1
  294. end
  295. end
  296. describe "get_existing_like/2" do
  297. test "fetches existing like" do
  298. note_activity = insert(:note_activity)
  299. assert object = Object.normalize(note_activity, fetch: false)
  300. user = insert(:user)
  301. refute Utils.get_existing_like(user.ap_id, object)
  302. {:ok, like_activity} = CommonAPI.favorite(note_activity.id, user)
  303. assert ^like_activity = Utils.get_existing_like(user.ap_id, object)
  304. end
  305. end
  306. describe "get_get_existing_announce/2" do
  307. test "returns nil if announce not found" do
  308. actor = insert(:user)
  309. refute Utils.get_existing_announce(actor.ap_id, %{data: %{"id" => "test"}})
  310. end
  311. test "fetches existing announce" do
  312. note_activity = insert(:note_activity)
  313. assert object = Object.normalize(note_activity, fetch: false)
  314. actor = insert(:user)
  315. {:ok, announce} = CommonAPI.repeat(note_activity.id, actor)
  316. assert Utils.get_existing_announce(actor.ap_id, object) == announce
  317. end
  318. end
  319. describe "fetch_latest_block/2" do
  320. test "fetches last block activities" do
  321. user1 = insert(:user)
  322. user2 = insert(:user)
  323. assert {:ok, %Activity{} = _} = CommonAPI.block(user2, user1)
  324. assert {:ok, %Activity{} = _} = CommonAPI.block(user2, user1)
  325. assert {:ok, %Activity{} = activity} = CommonAPI.block(user2, user1)
  326. assert Utils.fetch_latest_block(user1, user2) == activity
  327. end
  328. end
  329. describe "recipient_in_message/3" do
  330. test "returns true when recipient in `to`" do
  331. recipient = insert(:user)
  332. actor = insert(:user)
  333. assert Utils.recipient_in_message(recipient, actor, %{"to" => recipient.ap_id})
  334. assert Utils.recipient_in_message(
  335. recipient,
  336. actor,
  337. %{"to" => [recipient.ap_id], "cc" => ""}
  338. )
  339. end
  340. test "returns true when recipient in `cc`" do
  341. recipient = insert(:user)
  342. actor = insert(:user)
  343. assert Utils.recipient_in_message(recipient, actor, %{"cc" => recipient.ap_id})
  344. assert Utils.recipient_in_message(
  345. recipient,
  346. actor,
  347. %{"cc" => [recipient.ap_id], "to" => ""}
  348. )
  349. end
  350. test "returns true when recipient in `bto`" do
  351. recipient = insert(:user)
  352. actor = insert(:user)
  353. assert Utils.recipient_in_message(recipient, actor, %{"bto" => recipient.ap_id})
  354. assert Utils.recipient_in_message(
  355. recipient,
  356. actor,
  357. %{"bcc" => "", "bto" => [recipient.ap_id]}
  358. )
  359. end
  360. test "returns true when recipient in `bcc`" do
  361. recipient = insert(:user)
  362. actor = insert(:user)
  363. assert Utils.recipient_in_message(recipient, actor, %{"bcc" => recipient.ap_id})
  364. assert Utils.recipient_in_message(
  365. recipient,
  366. actor,
  367. %{"bto" => "", "bcc" => [recipient.ap_id]}
  368. )
  369. end
  370. test "returns true when message without addresses fields" do
  371. recipient = insert(:user)
  372. actor = insert(:user)
  373. assert Utils.recipient_in_message(recipient, actor, %{"bccc" => recipient.ap_id})
  374. assert Utils.recipient_in_message(
  375. recipient,
  376. actor,
  377. %{"btod" => "", "bccc" => [recipient.ap_id]}
  378. )
  379. end
  380. test "returns false" do
  381. recipient = insert(:user)
  382. actor = insert(:user)
  383. refute Utils.recipient_in_message(recipient, actor, %{"to" => "ap_id"})
  384. end
  385. end
  386. describe "lazy_put_activity_defaults/2" do
  387. test "returns map with id and published data" do
  388. note_activity = insert(:note_activity)
  389. object = Object.normalize(note_activity, fetch: false)
  390. res = Utils.lazy_put_activity_defaults(%{"context" => object.data["id"]})
  391. assert res["context"] == object.data["id"]
  392. assert res["id"]
  393. assert res["published"]
  394. end
  395. test "returns map with fake id and published data" do
  396. assert %{
  397. "context" => "pleroma:fakecontext",
  398. "id" => "pleroma:fakeid",
  399. "published" => _
  400. } = Utils.lazy_put_activity_defaults(%{}, true)
  401. end
  402. test "returns activity data with object" do
  403. note_activity = insert(:note_activity)
  404. object = Object.normalize(note_activity, fetch: false)
  405. res =
  406. Utils.lazy_put_activity_defaults(%{
  407. "context" => object.data["id"],
  408. "object" => %{}
  409. })
  410. assert res["context"] == object.data["id"]
  411. assert res["id"]
  412. assert res["published"]
  413. assert res["object"]["id"]
  414. assert res["object"]["published"]
  415. assert res["object"]["context"] == object.data["id"]
  416. end
  417. end
  418. describe "make_flag_data" do
  419. test "returns empty map when params is invalid" do
  420. assert Utils.make_flag_data(%{}, %{}) == %{}
  421. end
  422. test "returns map with Flag object" do
  423. reporter = insert(:user)
  424. target_account = insert(:user)
  425. {:ok, activity} = CommonAPI.post(target_account, %{status: "foobar"})
  426. context = Utils.generate_context_id()
  427. content = "foobar"
  428. target_ap_id = target_account.ap_id
  429. object_ap_id = activity.object.data["id"]
  430. res =
  431. Utils.make_flag_data(
  432. %{
  433. actor: reporter,
  434. context: context,
  435. account: target_account,
  436. statuses: [%{"id" => activity.data["id"]}],
  437. content: content
  438. },
  439. %{}
  440. )
  441. note_obj = %{
  442. "type" => "Note",
  443. "id" => object_ap_id,
  444. "content" => content,
  445. "published" => activity.object.data["published"],
  446. "actor" =>
  447. AccountView.render("show.json", %{user: target_account, skip_visibility_check: true})
  448. }
  449. assert %{
  450. "type" => "Flag",
  451. "content" => ^content,
  452. "context" => ^context,
  453. "object" => [^target_ap_id, ^note_obj],
  454. "state" => "open"
  455. } = res
  456. end
  457. test "returns map with Flag object with a non-Create Activity" do
  458. reporter = insert(:user)
  459. posting_account = insert(:user)
  460. target_account = insert(:user)
  461. {:ok, activity} = CommonAPI.post(posting_account, %{status: "foobar"})
  462. {:ok, like} = CommonAPI.favorite(activity.id, target_account)
  463. context = Utils.generate_context_id()
  464. content = "foobar"
  465. target_ap_id = target_account.ap_id
  466. object_ap_id = activity.object.data["id"]
  467. res =
  468. Utils.make_flag_data(
  469. %{
  470. actor: reporter,
  471. context: context,
  472. account: target_account,
  473. statuses: [%{"id" => like.data["id"]}],
  474. content: content
  475. },
  476. %{}
  477. )
  478. note_obj = %{
  479. "type" => "Note",
  480. "id" => object_ap_id,
  481. "content" => content,
  482. "published" => activity.object.data["published"],
  483. "actor" =>
  484. AccountView.render("show.json", %{user: posting_account, skip_visibility_check: true})
  485. }
  486. assert %{
  487. "type" => "Flag",
  488. "content" => ^content,
  489. "context" => ^context,
  490. "object" => [^target_ap_id, ^note_obj],
  491. "state" => "open"
  492. } = res
  493. end
  494. end
  495. describe "add_announce_to_object/2" do
  496. test "adds actor to announcement" do
  497. user = insert(:user)
  498. object = insert(:note)
  499. activity =
  500. insert(:note_activity,
  501. data: %{
  502. "actor" => user.ap_id,
  503. "cc" => [Pleroma.Constants.as_public()]
  504. }
  505. )
  506. assert {:ok, updated_object} = Utils.add_announce_to_object(activity, object)
  507. assert updated_object.data["announcements"] == [user.ap_id]
  508. assert updated_object.data["announcement_count"] == 1
  509. end
  510. end
  511. describe "remove_announce_from_object/2" do
  512. test "removes actor from announcements" do
  513. user = insert(:user)
  514. user2 = insert(:user)
  515. object =
  516. insert(:note,
  517. data: %{"announcements" => [user.ap_id, user2.ap_id], "announcement_count" => 2}
  518. )
  519. activity = insert(:note_activity, data: %{"actor" => user.ap_id})
  520. assert {:ok, updated_object} = Utils.remove_announce_from_object(activity, object)
  521. assert updated_object.data["announcements"] == [user2.ap_id]
  522. assert updated_object.data["announcement_count"] == 1
  523. end
  524. end
  525. describe "get_cached_emoji_reactions/1" do
  526. test "returns the normalized data or an empty list" do
  527. object = insert(:note)
  528. assert Utils.get_cached_emoji_reactions(object) == []
  529. object = insert(:note, data: %{"reactions" => [["x", ["lain"]]]})
  530. assert Utils.get_cached_emoji_reactions(object) == [["x", ["lain"], nil]]
  531. object = insert(:note, data: %{"reactions" => %{}})
  532. assert Utils.get_cached_emoji_reactions(object) == []
  533. end
  534. end
  535. describe "add_emoji_reaction_to_object/1" do
  536. test "works with legacy 2-tuple format" do
  537. user = insert(:user)
  538. other_user = insert(:user)
  539. third_user = insert(:user)
  540. note =
  541. insert(:note,
  542. user: user,
  543. data: %{
  544. "reactions" => [["😿", [other_user.ap_id]]]
  545. }
  546. )
  547. _activity = insert(:note_activity, user: user, note: note)
  548. Utils.add_emoji_reaction_to_object(
  549. %Activity{data: %{"content" => "😿", "actor" => third_user.ap_id}},
  550. note
  551. )
  552. end
  553. end
  554. end