logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma

publisher_test.exs (11641B)


  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. defmodule Pleroma.Web.ActivityPub.PublisherTest do
  5. use Pleroma.Web.ConnCase
  6. import ExUnit.CaptureLog
  7. import Pleroma.Factory
  8. import Tesla.Mock
  9. import Mock
  10. alias Pleroma.Activity
  11. alias Pleroma.Instances
  12. alias Pleroma.Object
  13. alias Pleroma.Web.ActivityPub.Publisher
  14. alias Pleroma.Web.CommonAPI
  15. @as_public "https://www.w3.org/ns/activitystreams#Public"
  16. setup do
  17. mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
  18. :ok
  19. end
  20. setup_all do: clear_config([:instance, :federating], true)
  21. describe "gather_webfinger_links/1" do
  22. test "it returns links" do
  23. user = insert(:user)
  24. expected_links = [
  25. %{"href" => user.ap_id, "rel" => "self", "type" => "application/activity+json"},
  26. %{
  27. "href" => user.ap_id,
  28. "rel" => "self",
  29. "type" => "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
  30. },
  31. %{
  32. "rel" => "http://ostatus.org/schema/1.0/subscribe",
  33. "template" => "#{Pleroma.Web.base_url()}/ostatus_subscribe?acct={uri}"
  34. }
  35. ]
  36. assert expected_links == Publisher.gather_webfinger_links(user)
  37. end
  38. end
  39. describe "determine_inbox/2" do
  40. test "it returns sharedInbox for messages involving as:Public in to" do
  41. user = insert(:user, %{shared_inbox: "http://example.com/inbox"})
  42. activity = %Activity{
  43. data: %{"to" => [@as_public], "cc" => [user.follower_address]}
  44. }
  45. assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
  46. end
  47. test "it returns sharedInbox for messages involving as:Public in cc" do
  48. user = insert(:user, %{shared_inbox: "http://example.com/inbox"})
  49. activity = %Activity{
  50. data: %{"cc" => [@as_public], "to" => [user.follower_address]}
  51. }
  52. assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
  53. end
  54. test "it returns sharedInbox for messages involving multiple recipients in to" do
  55. user = insert(:user, %{shared_inbox: "http://example.com/inbox"})
  56. user_two = insert(:user)
  57. user_three = insert(:user)
  58. activity = %Activity{
  59. data: %{"cc" => [], "to" => [user.ap_id, user_two.ap_id, user_three.ap_id]}
  60. }
  61. assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
  62. end
  63. test "it returns sharedInbox for messages involving multiple recipients in cc" do
  64. user = insert(:user, %{shared_inbox: "http://example.com/inbox"})
  65. user_two = insert(:user)
  66. user_three = insert(:user)
  67. activity = %Activity{
  68. data: %{"to" => [], "cc" => [user.ap_id, user_two.ap_id, user_three.ap_id]}
  69. }
  70. assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
  71. end
  72. test "it returns sharedInbox for messages involving multiple recipients in total" do
  73. user =
  74. insert(:user, %{
  75. shared_inbox: "http://example.com/inbox",
  76. inbox: "http://example.com/personal-inbox"
  77. })
  78. user_two = insert(:user)
  79. activity = %Activity{
  80. data: %{"to" => [user_two.ap_id], "cc" => [user.ap_id]}
  81. }
  82. assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
  83. end
  84. test "it returns inbox for messages involving single recipients in total" do
  85. user =
  86. insert(:user, %{
  87. shared_inbox: "http://example.com/inbox",
  88. inbox: "http://example.com/personal-inbox"
  89. })
  90. activity = %Activity{
  91. data: %{"to" => [user.ap_id], "cc" => []}
  92. }
  93. assert Publisher.determine_inbox(activity, user) == "http://example.com/personal-inbox"
  94. end
  95. end
  96. describe "publish_one/1" do
  97. test "publish to url with with different ports" do
  98. inbox80 = "http://42.site/users/nick1/inbox"
  99. inbox42 = "http://42.site:42/users/nick1/inbox"
  100. mock(fn
  101. %{method: :post, url: "http://42.site:42/users/nick1/inbox"} ->
  102. {:ok, %Tesla.Env{status: 200, body: "port 42"}}
  103. %{method: :post, url: "http://42.site/users/nick1/inbox"} ->
  104. {:ok, %Tesla.Env{status: 200, body: "port 80"}}
  105. end)
  106. actor = insert(:user)
  107. assert {:ok, %{body: "port 42"}} =
  108. Publisher.publish_one(%{
  109. inbox: inbox42,
  110. json: "{}",
  111. actor: actor,
  112. id: 1,
  113. unreachable_since: true
  114. })
  115. assert {:ok, %{body: "port 80"}} =
  116. Publisher.publish_one(%{
  117. inbox: inbox80,
  118. json: "{}",
  119. actor: actor,
  120. id: 1,
  121. unreachable_since: true
  122. })
  123. end
  124. test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is not specified",
  125. Instances,
  126. [:passthrough],
  127. [] do
  128. actor = insert(:user)
  129. inbox = "http://200.site/users/nick1/inbox"
  130. assert {:ok, _} = Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
  131. assert called(Instances.set_reachable(inbox))
  132. end
  133. test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is set",
  134. Instances,
  135. [:passthrough],
  136. [] do
  137. actor = insert(:user)
  138. inbox = "http://200.site/users/nick1/inbox"
  139. assert {:ok, _} =
  140. Publisher.publish_one(%{
  141. inbox: inbox,
  142. json: "{}",
  143. actor: actor,
  144. id: 1,
  145. unreachable_since: NaiveDateTime.utc_now()
  146. })
  147. assert called(Instances.set_reachable(inbox))
  148. end
  149. test_with_mock "does NOT call `Instances.set_reachable` on successful federation if `unreachable_since` is nil",
  150. Instances,
  151. [:passthrough],
  152. [] do
  153. actor = insert(:user)
  154. inbox = "http://200.site/users/nick1/inbox"
  155. assert {:ok, _} =
  156. Publisher.publish_one(%{
  157. inbox: inbox,
  158. json: "{}",
  159. actor: actor,
  160. id: 1,
  161. unreachable_since: nil
  162. })
  163. refute called(Instances.set_reachable(inbox))
  164. end
  165. test_with_mock "calls `Instances.set_unreachable` on target inbox on non-2xx HTTP response code",
  166. Instances,
  167. [:passthrough],
  168. [] do
  169. actor = insert(:user)
  170. inbox = "http://404.site/users/nick1/inbox"
  171. assert {:error, _} = Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
  172. assert called(Instances.set_unreachable(inbox))
  173. end
  174. test_with_mock "it calls `Instances.set_unreachable` on target inbox on request error of any kind",
  175. Instances,
  176. [:passthrough],
  177. [] do
  178. actor = insert(:user)
  179. inbox = "http://connrefused.site/users/nick1/inbox"
  180. assert capture_log(fn ->
  181. assert {:error, _} =
  182. Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
  183. end) =~ "connrefused"
  184. assert called(Instances.set_unreachable(inbox))
  185. end
  186. test_with_mock "does NOT call `Instances.set_unreachable` if target is reachable",
  187. Instances,
  188. [:passthrough],
  189. [] do
  190. actor = insert(:user)
  191. inbox = "http://200.site/users/nick1/inbox"
  192. assert {:ok, _} = Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
  193. refute called(Instances.set_unreachable(inbox))
  194. end
  195. test_with_mock "does NOT call `Instances.set_unreachable` if target instance has non-nil `unreachable_since`",
  196. Instances,
  197. [:passthrough],
  198. [] do
  199. actor = insert(:user)
  200. inbox = "http://connrefused.site/users/nick1/inbox"
  201. assert capture_log(fn ->
  202. assert {:error, _} =
  203. Publisher.publish_one(%{
  204. inbox: inbox,
  205. json: "{}",
  206. actor: actor,
  207. id: 1,
  208. unreachable_since: NaiveDateTime.utc_now()
  209. })
  210. end) =~ "connrefused"
  211. refute called(Instances.set_unreachable(inbox))
  212. end
  213. end
  214. describe "publish/2" do
  215. test_with_mock "publishes an activity with BCC to all relevant peers.",
  216. Pleroma.Web.Federator.Publisher,
  217. [:passthrough],
  218. [] do
  219. follower =
  220. insert(:user, %{
  221. local: false,
  222. inbox: "https://domain.com/users/nick1/inbox",
  223. ap_enabled: true
  224. })
  225. actor = insert(:user, follower_address: follower.ap_id)
  226. user = insert(:user)
  227. {:ok, _follower_one} = Pleroma.User.follow(follower, actor)
  228. actor = refresh_record(actor)
  229. note_activity =
  230. insert(:note_activity,
  231. recipients: [follower.ap_id],
  232. data_attrs: %{"bcc" => [user.ap_id]}
  233. )
  234. res = Publisher.publish(actor, note_activity)
  235. assert res == :ok
  236. assert called(
  237. Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{
  238. inbox: "https://domain.com/users/nick1/inbox",
  239. actor_id: actor.id,
  240. id: note_activity.data["id"]
  241. })
  242. )
  243. end
  244. test_with_mock "publishes a delete activity to peers who signed fetch requests to the create acitvity/object.",
  245. Pleroma.Web.Federator.Publisher,
  246. [:passthrough],
  247. [] do
  248. fetcher =
  249. insert(:user,
  250. local: false,
  251. inbox: "https://domain.com/users/nick1/inbox",
  252. ap_enabled: true
  253. )
  254. another_fetcher =
  255. insert(:user,
  256. local: false,
  257. inbox: "https://domain2.com/users/nick1/inbox",
  258. ap_enabled: true
  259. )
  260. actor = insert(:user)
  261. note_activity = insert(:note_activity, user: actor)
  262. object = Object.normalize(note_activity)
  263. activity_path = String.trim_leading(note_activity.data["id"], Pleroma.Web.Endpoint.url())
  264. object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url())
  265. build_conn()
  266. |> put_req_header("accept", "application/activity+json")
  267. |> assign(:user, fetcher)
  268. |> get(object_path)
  269. |> json_response(200)
  270. build_conn()
  271. |> put_req_header("accept", "application/activity+json")
  272. |> assign(:user, another_fetcher)
  273. |> get(activity_path)
  274. |> json_response(200)
  275. {:ok, delete} = CommonAPI.delete(note_activity.id, actor)
  276. res = Publisher.publish(actor, delete)
  277. assert res == :ok
  278. assert called(
  279. Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{
  280. inbox: "https://domain.com/users/nick1/inbox",
  281. actor_id: actor.id,
  282. id: delete.data["id"]
  283. })
  284. )
  285. assert called(
  286. Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{
  287. inbox: "https://domain2.com/users/nick1/inbox",
  288. actor_id: actor.id,
  289. id: delete.data["id"]
  290. })
  291. )
  292. end
  293. end
  294. end