Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1014 lines
29KB

  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. defmodule Pleroma.Web.ActivityPub.ActivityPub do
  5. alias Pleroma.Activity
  6. alias Pleroma.Conversation
  7. alias Pleroma.Notification
  8. alias Pleroma.Object
  9. alias Pleroma.Object.Fetcher
  10. alias Pleroma.Pagination
  11. alias Pleroma.Repo
  12. alias Pleroma.Upload
  13. alias Pleroma.User
  14. alias Pleroma.Web.ActivityPub.MRF
  15. alias Pleroma.Web.ActivityPub.Transmogrifier
  16. alias Pleroma.Web.WebFinger
  17. import Ecto.Query
  18. import Pleroma.Web.ActivityPub.Utils
  19. import Pleroma.Web.ActivityPub.Visibility
  20. require Logger
  21. # For Announce activities, we filter the recipients based on following status for any actors
  22. # that match actual users. See issue #164 for more information about why this is necessary.
  23. defp get_recipients(%{"type" => "Announce"} = data) do
  24. to = data["to"] || []
  25. cc = data["cc"] || []
  26. actor = User.get_cached_by_ap_id(data["actor"])
  27. recipients =
  28. (to ++ cc)
  29. |> Enum.filter(fn recipient ->
  30. case User.get_cached_by_ap_id(recipient) do
  31. nil ->
  32. true
  33. user ->
  34. User.following?(user, actor)
  35. end
  36. end)
  37. {recipients, to, cc}
  38. end
  39. defp get_recipients(%{"type" => "Create"} = data) do
  40. to = data["to"] || []
  41. cc = data["cc"] || []
  42. actor = data["actor"] || []
  43. recipients = (to ++ cc ++ [actor]) |> Enum.uniq()
  44. {recipients, to, cc}
  45. end
  46. defp get_recipients(data) do
  47. to = data["to"] || []
  48. cc = data["cc"] || []
  49. recipients = to ++ cc
  50. {recipients, to, cc}
  51. end
  52. defp check_actor_is_active(actor) do
  53. if not is_nil(actor) do
  54. with user <- User.get_cached_by_ap_id(actor),
  55. false <- user.info.deactivated do
  56. :ok
  57. else
  58. _e -> :reject
  59. end
  60. else
  61. :ok
  62. end
  63. end
  64. defp check_remote_limit(%{"object" => %{"content" => content}}) when not is_nil(content) do
  65. limit = Pleroma.Config.get([:instance, :remote_limit])
  66. String.length(content) <= limit
  67. end
  68. defp check_remote_limit(_), do: true
  69. def increase_note_count_if_public(actor, object) do
  70. if is_public?(object), do: User.increase_note_count(actor), else: {:ok, actor}
  71. end
  72. def decrease_note_count_if_public(actor, object) do
  73. if is_public?(object), do: User.decrease_note_count(actor), else: {:ok, actor}
  74. end
  75. def increase_replies_count_if_reply(%{
  76. "object" => %{"inReplyTo" => reply_ap_id} = object,
  77. "type" => "Create"
  78. }) do
  79. if is_public?(object) do
  80. Object.increase_replies_count(reply_ap_id)
  81. end
  82. end
  83. def increase_replies_count_if_reply(_create_data), do: :noop
  84. def decrease_replies_count_if_reply(%Object{
  85. data: %{"inReplyTo" => reply_ap_id} = object
  86. }) do
  87. if is_public?(object) do
  88. Object.decrease_replies_count(reply_ap_id)
  89. end
  90. end
  91. def decrease_replies_count_if_reply(_object), do: :noop
  92. def insert(map, local \\ true, fake \\ false) when is_map(map) do
  93. with nil <- Activity.normalize(map),
  94. map <- lazy_put_activity_defaults(map, fake),
  95. :ok <- check_actor_is_active(map["actor"]),
  96. {_, true} <- {:remote_limit_error, check_remote_limit(map)},
  97. {:ok, map} <- MRF.filter(map),
  98. {recipients, _, _} = get_recipients(map),
  99. {:fake, false, map, recipients} <- {:fake, fake, map, recipients},
  100. {:ok, map, object} <- insert_full_object(map) do
  101. {:ok, activity} =
  102. Repo.insert(%Activity{
  103. data: map,
  104. local: local,
  105. actor: map["actor"],
  106. recipients: recipients
  107. })
  108. # Splice in the child object if we have one.
  109. activity =
  110. if !is_nil(object) do
  111. Map.put(activity, :object, object)
  112. else
  113. activity
  114. end
  115. PleromaJobQueue.enqueue(:background, Pleroma.Web.RichMedia.Helpers, [:fetch, activity])
  116. Notification.create_notifications(activity)
  117. participations =
  118. activity
  119. |> Conversation.create_or_bump_for()
  120. |> get_participations()
  121. stream_out(activity)
  122. stream_out_participations(participations)
  123. {:ok, activity}
  124. else
  125. %Activity{} = activity ->
  126. {:ok, activity}
  127. {:fake, true, map, recipients} ->
  128. activity = %Activity{
  129. data: map,
  130. local: local,
  131. actor: map["actor"],
  132. recipients: recipients,
  133. id: "pleroma:fakeid"
  134. }
  135. Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
  136. {:ok, activity}
  137. error ->
  138. {:error, error}
  139. end
  140. end
  141. defp get_participations({:ok, %{participations: participations}}), do: participations
  142. defp get_participations(_), do: []
  143. def stream_out_participations(participations) do
  144. participations =
  145. participations
  146. |> Repo.preload(:user)
  147. Enum.each(participations, fn participation ->
  148. Pleroma.Web.Streamer.stream("participation", participation)
  149. end)
  150. end
  151. def stream_out(activity) do
  152. public = "https://www.w3.org/ns/activitystreams#Public"
  153. if activity.data["type"] in ["Create", "Announce", "Delete"] do
  154. Pleroma.Web.Streamer.stream("user", activity)
  155. Pleroma.Web.Streamer.stream("list", activity)
  156. if Enum.member?(activity.data["to"], public) do
  157. Pleroma.Web.Streamer.stream("public", activity)
  158. if activity.local do
  159. Pleroma.Web.Streamer.stream("public:local", activity)
  160. end
  161. if activity.data["type"] in ["Create"] do
  162. object = Object.normalize(activity)
  163. object.data
  164. |> Map.get("tag", [])
  165. |> Enum.filter(fn tag -> is_bitstring(tag) end)
  166. |> Enum.each(fn tag -> Pleroma.Web.Streamer.stream("hashtag:" <> tag, activity) end)
  167. if object.data["attachment"] != [] do
  168. Pleroma.Web.Streamer.stream("public:media", activity)
  169. if activity.local do
  170. Pleroma.Web.Streamer.stream("public:local:media", activity)
  171. end
  172. end
  173. end
  174. else
  175. # TODO: Write test, replace with visibility test
  176. if !Enum.member?(activity.data["cc"] || [], public) &&
  177. !Enum.member?(
  178. activity.data["to"],
  179. User.get_cached_by_ap_id(activity.data["actor"]).follower_address
  180. ),
  181. do: Pleroma.Web.Streamer.stream("direct", activity)
  182. end
  183. end
  184. end
  185. def create(%{to: to, actor: actor, context: context, object: object} = params, fake \\ false) do
  186. additional = params[:additional] || %{}
  187. # only accept false as false value
  188. local = !(params[:local] == false)
  189. published = params[:published]
  190. with create_data <-
  191. make_create_data(
  192. %{to: to, actor: actor, published: published, context: context, object: object},
  193. additional
  194. ),
  195. {:ok, activity} <- insert(create_data, local, fake),
  196. {:fake, false, activity} <- {:fake, fake, activity},
  197. _ <- increase_replies_count_if_reply(create_data),
  198. # Changing note count prior to enqueuing federation task in order to avoid
  199. # race conditions on updating user.info
  200. {:ok, _actor} <- increase_note_count_if_public(actor, activity),
  201. :ok <- maybe_federate(activity) do
  202. {:ok, activity}
  203. else
  204. {:fake, true, activity} ->
  205. {:ok, activity}
  206. end
  207. end
  208. def accept(%{to: to, actor: actor, object: object} = params) do
  209. # only accept false as false value
  210. local = !(params[:local] == false)
  211. with data <- %{"to" => to, "type" => "Accept", "actor" => actor.ap_id, "object" => object},
  212. {:ok, activity} <- insert(data, local),
  213. :ok <- maybe_federate(activity) do
  214. {:ok, activity}
  215. end
  216. end
  217. def reject(%{to: to, actor: actor, object: object} = params) do
  218. # only accept false as false value
  219. local = !(params[:local] == false)
  220. with data <- %{"to" => to, "type" => "Reject", "actor" => actor.ap_id, "object" => object},
  221. {:ok, activity} <- insert(data, local),
  222. :ok <- maybe_federate(activity) do
  223. {:ok, activity}
  224. end
  225. end
  226. def update(%{to: to, cc: cc, actor: actor, object: object} = params) do
  227. # only accept false as false value
  228. local = !(params[:local] == false)
  229. with data <- %{
  230. "to" => to,
  231. "cc" => cc,
  232. "type" => "Update",
  233. "actor" => actor,
  234. "object" => object
  235. },
  236. {:ok, activity} <- insert(data, local),
  237. :ok <- maybe_federate(activity) do
  238. {:ok, activity}
  239. end
  240. end
  241. # TODO: This is weird, maybe we shouldn't check here if we can make the activity.
  242. def like(
  243. %User{ap_id: ap_id} = user,
  244. %Object{data: %{"id" => _}} = object,
  245. activity_id \\ nil,
  246. local \\ true
  247. ) do
  248. with nil <- get_existing_like(ap_id, object),
  249. like_data <- make_like_data(user, object, activity_id),
  250. {:ok, activity} <- insert(like_data, local),
  251. {:ok, object} <- add_like_to_object(activity, object),
  252. :ok <- maybe_federate(activity) do
  253. {:ok, activity, object}
  254. else
  255. %Activity{} = activity -> {:ok, activity, object}
  256. error -> {:error, error}
  257. end
  258. end
  259. def unlike(
  260. %User{} = actor,
  261. %Object{} = object,
  262. activity_id \\ nil,
  263. local \\ true
  264. ) do
  265. with %Activity{} = like_activity <- get_existing_like(actor.ap_id, object),
  266. unlike_data <- make_unlike_data(actor, like_activity, activity_id),
  267. {:ok, unlike_activity} <- insert(unlike_data, local),
  268. {:ok, _activity} <- Repo.delete(like_activity),
  269. {:ok, object} <- remove_like_from_object(like_activity, object),
  270. :ok <- maybe_federate(unlike_activity) do
  271. {:ok, unlike_activity, like_activity, object}
  272. else
  273. _e -> {:ok, object}
  274. end
  275. end
  276. def announce(
  277. %User{ap_id: _} = user,
  278. %Object{data: %{"id" => _}} = object,
  279. activity_id \\ nil,
  280. local \\ true,
  281. public \\ true
  282. ) do
  283. with true <- is_public?(object),
  284. announce_data <- make_announce_data(user, object, activity_id, public),
  285. {:ok, activity} <- insert(announce_data, local),
  286. {:ok, object} <- add_announce_to_object(activity, object),
  287. :ok <- maybe_federate(activity) do
  288. {:ok, activity, object}
  289. else
  290. error -> {:error, error}
  291. end
  292. end
  293. def unannounce(
  294. %User{} = actor,
  295. %Object{} = object,
  296. activity_id \\ nil,
  297. local \\ true
  298. ) do
  299. with %Activity{} = announce_activity <- get_existing_announce(actor.ap_id, object),
  300. unannounce_data <- make_unannounce_data(actor, announce_activity, activity_id),
  301. {:ok, unannounce_activity} <- insert(unannounce_data, local),
  302. :ok <- maybe_federate(unannounce_activity),
  303. {:ok, _activity} <- Repo.delete(announce_activity),
  304. {:ok, object} <- remove_announce_from_object(announce_activity, object) do
  305. {:ok, unannounce_activity, object}
  306. else
  307. _e -> {:ok, object}
  308. end
  309. end
  310. def follow(follower, followed, activity_id \\ nil, local \\ true) do
  311. with data <- make_follow_data(follower, followed, activity_id),
  312. {:ok, activity} <- insert(data, local),
  313. :ok <- maybe_federate(activity) do
  314. {:ok, activity}
  315. end
  316. end
  317. def unfollow(follower, followed, activity_id \\ nil, local \\ true) do
  318. with %Activity{} = follow_activity <- fetch_latest_follow(follower, followed),
  319. {:ok, follow_activity} <- update_follow_state(follow_activity, "cancelled"),
  320. unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id),
  321. {:ok, activity} <- insert(unfollow_data, local),
  322. :ok <- maybe_federate(activity) do
  323. {:ok, activity}
  324. end
  325. end
  326. def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ true) do
  327. user = User.get_cached_by_ap_id(actor)
  328. to = (object.data["to"] || []) ++ (object.data["cc"] || [])
  329. with {:ok, object, activity} <- Object.delete(object),
  330. data <- %{
  331. "type" => "Delete",
  332. "actor" => actor,
  333. "object" => id,
  334. "to" => to,
  335. "deleted_activity_id" => activity && activity.id
  336. },
  337. {:ok, activity} <- insert(data, local),
  338. _ <- decrease_replies_count_if_reply(object),
  339. # Changing note count prior to enqueuing federation task in order to avoid
  340. # race conditions on updating user.info
  341. {:ok, _actor} <- decrease_note_count_if_public(user, object),
  342. :ok <- maybe_federate(activity) do
  343. {:ok, activity}
  344. end
  345. end
  346. def block(blocker, blocked, activity_id \\ nil, local \\ true) do
  347. ap_config = Application.get_env(:pleroma, :activitypub)
  348. unfollow_blocked = Keyword.get(ap_config, :unfollow_blocked)
  349. outgoing_blocks = Keyword.get(ap_config, :outgoing_blocks)
  350. with true <- unfollow_blocked do
  351. follow_activity = fetch_latest_follow(blocker, blocked)
  352. if follow_activity do
  353. unfollow(blocker, blocked, nil, local)
  354. end
  355. end
  356. with true <- outgoing_blocks,
  357. block_data <- make_block_data(blocker, blocked, activity_id),
  358. {:ok, activity} <- insert(block_data, local),
  359. :ok <- maybe_federate(activity) do
  360. {:ok, activity}
  361. else
  362. _e -> {:ok, nil}
  363. end
  364. end
  365. def unblock(blocker, blocked, activity_id \\ nil, local \\ true) do
  366. with %Activity{} = block_activity <- fetch_latest_block(blocker, blocked),
  367. unblock_data <- make_unblock_data(blocker, blocked, block_activity, activity_id),
  368. {:ok, activity} <- insert(unblock_data, local),
  369. :ok <- maybe_federate(activity) do
  370. {:ok, activity}
  371. end
  372. end
  373. def flag(
  374. %{
  375. actor: actor,
  376. context: context,
  377. account: account,
  378. statuses: statuses,
  379. content: content
  380. } = params
  381. ) do
  382. # only accept false as false value
  383. local = !(params[:local] == false)
  384. forward = !(params[:forward] == false)
  385. additional = params[:additional] || %{}
  386. params = %{
  387. actor: actor,
  388. context: context,
  389. account: account,
  390. statuses: statuses,
  391. content: content
  392. }
  393. additional =
  394. if forward do
  395. Map.merge(additional, %{"to" => [], "cc" => [account.ap_id]})
  396. else
  397. Map.merge(additional, %{"to" => [], "cc" => []})
  398. end
  399. with flag_data <- make_flag_data(params, additional),
  400. {:ok, activity} <- insert(flag_data, local),
  401. :ok <- maybe_federate(activity) do
  402. Enum.each(User.all_superusers(), fn superuser ->
  403. superuser
  404. |> Pleroma.Emails.AdminEmail.report(actor, account, statuses, content)
  405. |> Pleroma.Emails.Mailer.deliver_async()
  406. end)
  407. {:ok, activity}
  408. end
  409. end
  410. defp fetch_activities_for_context_query(context, opts) do
  411. public = ["https://www.w3.org/ns/activitystreams#Public"]
  412. recipients =
  413. if opts["user"], do: [opts["user"].ap_id | opts["user"].following] ++ public, else: public
  414. from(activity in Activity)
  415. |> restrict_blocked(opts)
  416. |> restrict_recipients(recipients, opts["user"])
  417. |> where(
  418. [activity],
  419. fragment(
  420. "?->>'type' = ? and ?->>'context' = ?",
  421. activity.data,
  422. "Create",
  423. activity.data,
  424. ^context
  425. )
  426. )
  427. |> order_by([activity], desc: activity.id)
  428. end
  429. @spec fetch_activities_for_context(String.t(), keyword() | map()) :: [Activity.t()]
  430. def fetch_activities_for_context(context, opts \\ %{}) do
  431. context
  432. |> fetch_activities_for_context_query(opts)
  433. |> Activity.with_preloaded_object()
  434. |> Repo.all()
  435. end
  436. @spec fetch_latest_activity_id_for_context(String.t(), keyword() | map()) ::
  437. Pleroma.FlakeId.t() | nil
  438. def fetch_latest_activity_id_for_context(context, opts \\ %{}) do
  439. context
  440. |> fetch_activities_for_context_query(opts)
  441. |> limit(1)
  442. |> select([a], a.id)
  443. |> Repo.one()
  444. end
  445. def fetch_public_activities(opts \\ %{}) do
  446. q = fetch_activities_query(["https://www.w3.org/ns/activitystreams#Public"], opts)
  447. q
  448. |> restrict_unlisted()
  449. |> Pagination.fetch_paginated(opts)
  450. |> Enum.reverse()
  451. end
  452. @valid_visibilities ~w[direct unlisted public private]
  453. defp restrict_visibility(query, %{visibility: visibility})
  454. when is_list(visibility) do
  455. if Enum.all?(visibility, &(&1 in @valid_visibilities)) do
  456. query =
  457. from(
  458. a in query,
  459. where:
  460. fragment(
  461. "activity_visibility(?, ?, ?) = ANY (?)",
  462. a.actor,
  463. a.recipients,
  464. a.data,
  465. ^visibility
  466. )
  467. )
  468. query
  469. else
  470. Logger.error("Could not restrict visibility to #{visibility}")
  471. end
  472. end
  473. defp restrict_visibility(query, %{visibility: visibility})
  474. when visibility in @valid_visibilities do
  475. query =
  476. from(
  477. a in query,
  478. where:
  479. fragment("activity_visibility(?, ?, ?) = ?", a.actor, a.recipients, a.data, ^visibility)
  480. )
  481. query
  482. end
  483. defp restrict_visibility(_query, %{visibility: visibility})
  484. when visibility not in @valid_visibilities do
  485. Logger.error("Could not restrict visibility to #{visibility}")
  486. end
  487. defp restrict_visibility(query, _visibility), do: query
  488. defp restrict_thread_visibility(query, %{"user" => %User{ap_id: ap_id}}) do
  489. query =
  490. from(
  491. a in query,
  492. where: fragment("thread_visibility(?, (?)->>'id') = true", ^ap_id, a.data)
  493. )
  494. query
  495. end
  496. defp restrict_thread_visibility(query, _), do: query
  497. def fetch_user_activities(user, reading_user, params \\ %{}) do
  498. params =
  499. params
  500. |> Map.put("type", ["Create", "Announce"])
  501. |> Map.put("actor_id", user.ap_id)
  502. |> Map.put("whole_db", true)
  503. |> Map.put("pinned_activity_ids", user.info.pinned_activities)
  504. recipients =
  505. if reading_user do
  506. ["https://www.w3.org/ns/activitystreams#Public"] ++
  507. [reading_user.ap_id | reading_user.following]
  508. else
  509. ["https://www.w3.org/ns/activitystreams#Public"]
  510. end
  511. fetch_activities(recipients, params)
  512. |> Enum.reverse()
  513. end
  514. defp restrict_since(query, %{"since_id" => ""}), do: query
  515. defp restrict_since(query, %{"since_id" => since_id}) do
  516. from(activity in query, where: activity.id > ^since_id)
  517. end
  518. defp restrict_since(query, _), do: query
  519. defp restrict_tag_reject(_query, %{"tag_reject" => _tag_reject, "skip_preload" => true}) do
  520. raise "Can't use the child object without preloading!"
  521. end
  522. defp restrict_tag_reject(query, %{"tag_reject" => tag_reject})
  523. when is_list(tag_reject) and tag_reject != [] do
  524. from(
  525. [_activity, object] in query,
  526. where: fragment("not (?)->'tag' \\?| (?)", object.data, ^tag_reject)
  527. )
  528. end
  529. defp restrict_tag_reject(query, _), do: query
  530. defp restrict_tag_all(_query, %{"tag_all" => _tag_all, "skip_preload" => true}) do
  531. raise "Can't use the child object without preloading!"
  532. end
  533. defp restrict_tag_all(query, %{"tag_all" => tag_all})
  534. when is_list(tag_all) and tag_all != [] do
  535. from(
  536. [_activity, object] in query,
  537. where: fragment("(?)->'tag' \\?& (?)", object.data, ^tag_all)
  538. )
  539. end
  540. defp restrict_tag_all(query, _), do: query
  541. defp restrict_tag(_query, %{"tag" => _tag, "skip_preload" => true}) do
  542. raise "Can't use the child object without preloading!"
  543. end
  544. defp restrict_tag(query, %{"tag" => tag}) when is_list(tag) do
  545. from(
  546. [_activity, object] in query,
  547. where: fragment("(?)->'tag' \\?| (?)", object.data, ^tag)
  548. )
  549. end
  550. defp restrict_tag(query, %{"tag" => tag}) when is_binary(tag) do
  551. from(
  552. [_activity, object] in query,
  553. where: fragment("(?)->'tag' \\? (?)", object.data, ^tag)
  554. )
  555. end
  556. defp restrict_tag(query, _), do: query
  557. defp restrict_to_cc(query, recipients_to, recipients_cc) do
  558. from(
  559. activity in query,
  560. where:
  561. fragment(
  562. "(?->'to' \\?| ?) or (?->'cc' \\?| ?)",
  563. activity.data,
  564. ^recipients_to,
  565. activity.data,
  566. ^recipients_cc
  567. )
  568. )
  569. end
  570. defp restrict_recipients(query, [], _user), do: query
  571. defp restrict_recipients(query, recipients, nil) do
  572. from(activity in query, where: fragment("? && ?", ^recipients, activity.recipients))
  573. end
  574. defp restrict_recipients(query, recipients, user) do
  575. from(
  576. activity in query,
  577. where: fragment("? && ?", ^recipients, activity.recipients),
  578. or_where: activity.actor == ^user.ap_id
  579. )
  580. end
  581. defp restrict_local(query, %{"local_only" => true}) do
  582. from(activity in query, where: activity.local == true)
  583. end
  584. defp restrict_local(query, _), do: query
  585. defp restrict_actor(query, %{"actor_id" => actor_id}) do
  586. from(activity in query, where: activity.actor == ^actor_id)
  587. end
  588. defp restrict_actor(query, _), do: query
  589. defp restrict_type(query, %{"type" => type}) when is_binary(type) do
  590. from(activity in query, where: fragment("?->>'type' = ?", activity.data, ^type))
  591. end
  592. defp restrict_type(query, %{"type" => type}) do
  593. from(activity in query, where: fragment("?->>'type' = ANY(?)", activity.data, ^type))
  594. end
  595. defp restrict_type(query, _), do: query
  596. defp restrict_state(query, %{"state" => state}) do
  597. from(activity in query, where: fragment("?->>'state' = ?", activity.data, ^state))
  598. end
  599. defp restrict_state(query, _), do: query
  600. defp restrict_favorited_by(query, %{"favorited_by" => ap_id}) do
  601. from(
  602. activity in query,
  603. where: fragment(~s(? <@ (? #> '{"object","likes"}'\)), ^ap_id, activity.data)
  604. )
  605. end
  606. defp restrict_favorited_by(query, _), do: query
  607. defp restrict_media(_query, %{"only_media" => _val, "skip_preload" => true}) do
  608. raise "Can't use the child object without preloading!"
  609. end
  610. defp restrict_media(query, %{"only_media" => val}) when val == "true" or val == "1" do
  611. from(
  612. [_activity, object] in query,
  613. where: fragment("not (?)->'attachment' = (?)", object.data, ^[])
  614. )
  615. end
  616. defp restrict_media(query, _), do: query
  617. defp restrict_replies(query, %{"exclude_replies" => val}) when val == "true" or val == "1" do
  618. from(
  619. activity in query,
  620. where: fragment("?->'object'->>'inReplyTo' is null", activity.data)
  621. )
  622. end
  623. defp restrict_replies(query, _), do: query
  624. defp restrict_reblogs(query, %{"exclude_reblogs" => val}) when val == "true" or val == "1" do
  625. from(activity in query, where: fragment("?->>'type' != 'Announce'", activity.data))
  626. end
  627. defp restrict_reblogs(query, _), do: query
  628. defp restrict_muted(query, %{"with_muted" => val}) when val in [true, "true", "1"], do: query
  629. defp restrict_muted(query, %{"muting_user" => %User{info: info}}) do
  630. mutes = info.mutes
  631. from(
  632. activity in query,
  633. where: fragment("not (? = ANY(?))", activity.actor, ^mutes),
  634. where: fragment("not (?->'to' \\?| ?)", activity.data, ^mutes)
  635. )
  636. end
  637. defp restrict_muted(query, _), do: query
  638. defp restrict_blocked(query, %{"blocking_user" => %User{info: info}}) do
  639. blocks = info.blocks || []
  640. domain_blocks = info.domain_blocks || []
  641. query =
  642. if has_named_binding?(query, :object), do: query, else: Activity.with_joined_object(query)
  643. from(
  644. [activity, object: o] in query,
  645. where: fragment("not (? = ANY(?))", activity.actor, ^blocks),
  646. where: fragment("not (? && ?)", activity.recipients, ^blocks),
  647. where:
  648. fragment(
  649. "not (?->>'type' = 'Announce' and ?->'to' \\?| ?)",
  650. activity.data,
  651. activity.data,
  652. ^blocks
  653. ),
  654. where: fragment("not (split_part(?, '/', 3) = ANY(?))", activity.actor, ^domain_blocks),
  655. where: fragment("not (split_part(?->>'actor', '/', 3) = ANY(?))", o.data, ^domain_blocks)
  656. )
  657. end
  658. defp restrict_blocked(query, _), do: query
  659. defp restrict_unlisted(query) do
  660. from(
  661. activity in query,
  662. where:
  663. fragment(
  664. "not (coalesce(?->'cc', '{}'::jsonb) \\?| ?)",
  665. activity.data,
  666. ^["https://www.w3.org/ns/activitystreams#Public"]
  667. )
  668. )
  669. end
  670. defp restrict_pinned(query, %{"pinned" => "true", "pinned_activity_ids" => ids}) do
  671. from(activity in query, where: activity.id in ^ids)
  672. end
  673. defp restrict_pinned(query, _), do: query
  674. defp restrict_muted_reblogs(query, %{"muting_user" => %User{info: info}}) do
  675. muted_reblogs = info.muted_reblogs || []
  676. from(
  677. activity in query,
  678. where:
  679. fragment(
  680. "not ( ?->>'type' = 'Announce' and ? = ANY(?))",
  681. activity.data,
  682. activity.actor,
  683. ^muted_reblogs
  684. )
  685. )
  686. end
  687. defp restrict_muted_reblogs(query, _), do: query
  688. defp maybe_preload_objects(query, %{"skip_preload" => true}), do: query
  689. defp maybe_preload_objects(query, _) do
  690. query
  691. |> Activity.with_preloaded_object()
  692. end
  693. defp maybe_preload_bookmarks(query, %{"skip_preload" => true}), do: query
  694. defp maybe_preload_bookmarks(query, opts) do
  695. query
  696. |> Activity.with_preloaded_bookmark(opts["user"])
  697. end
  698. defp maybe_set_thread_muted_field(query, %{"skip_preload" => true}), do: query
  699. defp maybe_set_thread_muted_field(query, opts) do
  700. query
  701. |> Activity.with_set_thread_muted_field(opts["user"])
  702. end
  703. defp maybe_order(query, %{order: :desc}) do
  704. query
  705. |> order_by(desc: :id)
  706. end
  707. defp maybe_order(query, %{order: :asc}) do
  708. query
  709. |> order_by(asc: :id)
  710. end
  711. defp maybe_order(query, _), do: query
  712. def fetch_activities_query(recipients, opts \\ %{}) do
  713. base_query = from(activity in Activity)
  714. base_query
  715. |> maybe_preload_objects(opts)
  716. |> maybe_preload_bookmarks(opts)
  717. |> maybe_set_thread_muted_field(opts)
  718. |> maybe_order(opts)
  719. |> restrict_recipients(recipients, opts["user"])
  720. |> restrict_tag(opts)
  721. |> restrict_tag_reject(opts)
  722. |> restrict_tag_all(opts)
  723. |> restrict_since(opts)
  724. |> restrict_local(opts)
  725. |> restrict_actor(opts)
  726. |> restrict_type(opts)
  727. |> restrict_state(opts)
  728. |> restrict_favorited_by(opts)
  729. |> restrict_blocked(opts)
  730. |> restrict_muted(opts)
  731. |> restrict_media(opts)
  732. |> restrict_visibility(opts)
  733. |> restrict_thread_visibility(opts)
  734. |> restrict_replies(opts)
  735. |> restrict_reblogs(opts)
  736. |> restrict_pinned(opts)
  737. |> restrict_muted_reblogs(opts)
  738. |> Activity.restrict_deactivated_users()
  739. end
  740. def fetch_activities(recipients, opts \\ %{}) do
  741. fetch_activities_query(recipients, opts)
  742. |> Pagination.fetch_paginated(opts)
  743. |> Enum.reverse()
  744. end
  745. def fetch_activities_bounded(recipients_to, recipients_cc, opts \\ %{}) do
  746. fetch_activities_query([], opts)
  747. |> restrict_to_cc(recipients_to, recipients_cc)
  748. |> Pagination.fetch_paginated(opts)
  749. |> Enum.reverse()
  750. end
  751. def upload(file, opts \\ []) do
  752. with {:ok, data} <- Upload.store(file, opts) do
  753. obj_data =
  754. if opts[:actor] do
  755. Map.put(data, "actor", opts[:actor])
  756. else
  757. data
  758. end
  759. Repo.insert(%Object{data: obj_data})
  760. end
  761. end
  762. defp object_to_user_data(data) do
  763. avatar =
  764. data["icon"]["url"] &&
  765. %{
  766. "type" => "Image",
  767. "url" => [%{"href" => data["icon"]["url"]}]
  768. }
  769. banner =
  770. data["image"]["url"] &&
  771. %{
  772. "type" => "Image",
  773. "url" => [%{"href" => data["image"]["url"]}]
  774. }
  775. locked = data["manuallyApprovesFollowers"] || false
  776. data = Transmogrifier.maybe_fix_user_object(data)
  777. user_data = %{
  778. ap_id: data["id"],
  779. info: %{
  780. "ap_enabled" => true,
  781. "source_data" => data,
  782. "banner" => banner,
  783. "locked" => locked
  784. },
  785. avatar: avatar,
  786. name: data["name"],
  787. follower_address: data["followers"],
  788. bio: data["summary"]
  789. }
  790. # nickname can be nil because of virtual actors
  791. user_data =
  792. if data["preferredUsername"] do
  793. Map.put(
  794. user_data,
  795. :nickname,
  796. "#{data["preferredUsername"]}@#{URI.parse(data["id"]).host}"
  797. )
  798. else
  799. Map.put(user_data, :nickname, nil)
  800. end
  801. {:ok, user_data}
  802. end
  803. def user_data_from_user_object(data) do
  804. with {:ok, data} <- MRF.filter(data),
  805. {:ok, data} <- object_to_user_data(data) do
  806. {:ok, data}
  807. else
  808. e -> {:error, e}
  809. end
  810. end
  811. def fetch_and_prepare_user_from_ap_id(ap_id) do
  812. with {:ok, data} <- Fetcher.fetch_and_contain_remote_object_from_id(ap_id),
  813. {:ok, data} <- user_data_from_user_object(data) do
  814. {:ok, data}
  815. else
  816. e -> Logger.error("Could not decode user at fetch #{ap_id}, #{inspect(e)}")
  817. end
  818. end
  819. def make_user_from_ap_id(ap_id) do
  820. if _user = User.get_cached_by_ap_id(ap_id) do
  821. Transmogrifier.upgrade_user_from_ap_id(ap_id)
  822. else
  823. with {:ok, data} <- fetch_and_prepare_user_from_ap_id(ap_id) do
  824. User.insert_or_update_user(data)
  825. else
  826. e -> {:error, e}
  827. end
  828. end
  829. end
  830. def make_user_from_nickname(nickname) do
  831. with {:ok, %{"ap_id" => ap_id}} when not is_nil(ap_id) <- WebFinger.finger(nickname) do
  832. make_user_from_ap_id(ap_id)
  833. else
  834. _e -> {:error, "No AP id in WebFinger"}
  835. end
  836. end
  837. # filter out broken threads
  838. def contain_broken_threads(%Activity{} = activity, %User{} = user) do
  839. entire_thread_visible_for_user?(activity, user)
  840. end
  841. # do post-processing on a specific activity
  842. def contain_activity(%Activity{} = activity, %User{} = user) do
  843. contain_broken_threads(activity, user)
  844. end
  845. def fetch_direct_messages_query do
  846. Activity
  847. |> restrict_type(%{"type" => "Create"})
  848. |> restrict_visibility(%{visibility: "direct"})
  849. |> order_by([activity], asc: activity.id)
  850. end
  851. end