1 diff --git a/CHANGELOG.md b/CHANGELOG.md
2 index 6a7ec1032876ec7c4aa4043bf095599749f68160..f6fc6aaee23c312a43f67b5210688b28e1060554 100644
5 @@ -14,6 +14,26 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
12 +- `/proxy` endpoint now sets a Content-Security-Policy (sandbox)
13 +- WebSocket endpoint now respects unauthenticated restrictions for streams of public posts
14 +- OEmbed HTML tags are now filtered
17 +- docs: Be more explicit about the level of compatibility of OTP releases
18 +- Set default background worker timeout to 15 minutes
21 +- Atom/RSS formatting (HTML truncation, published, missing summary)
22 +- Remove `static_fe` pipeline for `/users/:nickname/feed`
23 +- Stop oban from retrying if validating errors occur when processing incoming data
24 +- Make sure object refetching as used by already received polls follows MRF rules
27 +- BREAKING: Support for passwords generated with `crypt(3)` (Gnu Social migration artifact)
32 diff --git a/changelog.d/3126.fix b/changelog.d/3126.fix
34 index 0000000000000000000000000000000000000000..91d396c89d4fbc9ee4c572006a56f376d309d241
36 +++ b/changelog.d/3126.fix
38 +MediaProxy responses now return a sandbox CSP header
39 diff --git a/changelog.d/3883.fix b/changelog.d/3883.fix
41 index 0000000000000000000000000000000000000000..6824f201345db5fd24305782dc6b842692216f4e
43 +++ b/changelog.d/3883.fix
45 +Fix abnormal behaviour when refetching a poll
46 diff --git a/changelog.d/3891.fix b/changelog.d/3891.fix
48 index 0000000000000000000000000000000000000000..f1fb62d826a3a3f5e442a9f2a585550975175570
50 +++ b/changelog.d/3891.fix
52 +OEmbed HTML tags are now filtered
53 diff --git a/changelog.d/fix-object-test.fix b/changelog.d/fix-object-test.fix
55 index 0000000000000000000000000000000000000000..5eea719f0bd89557ab2052d925036bf4802442bb
57 +++ b/changelog.d/fix-object-test.fix
59 +Correctly handle the situation when a poll has both "anyOf" and "oneOf" but one of them being empty
60 diff --git a/docs/installation/otp_en.md b/docs/installation/otp_en.md
61 index 8c02201e67699c54b694ddef13d4e54520751c98..f2812346b1348cdf5c383e1812d841a4ffaaf10c 100644
62 --- a/docs/installation/otp_en.md
63 +++ b/docs/installation/otp_en.md
66 {! backend/installation/otp_vs_from_source.include !}
68 -This guide covers a installation using an OTP release. To install Pleroma from source, please check out the corresponding guide for your distro.
69 +This guide covers a installation using OTP releases as built by the Pleroma project, it is meant as a fallback to distribution packages/recipes which are the preferred installation method.
70 +To install Pleroma from source, please check out the corresponding guide for your distro.
73 -* A machine running Linux with GNU (e.g. Debian, Ubuntu) or musl (e.g. Alpine) libc and `x86_64`, `aarch64` or `armv7l` CPU, you have root access to. If you are not sure if it's compatible see [Detecting flavour section](#detecting-flavour) below
74 +* A machine you have root access to running Debian GNU/Linux or compatible (eg. Ubuntu), or Alpine on `x86_64`, `aarch64` or `armv7l` CPU. If you are not sure what you are running see [Detecting flavour section](#detecting-flavour) below
75 * A (sub)domain pointed to the machine
77 -You will be running commands as root. If you aren't root already, please elevate your privileges by executing `sudo su`/`su`.
78 +You will be running commands as root. If you aren't root already, please elevate your privileges by executing `sudo -i`/`su`.
80 -While in theory OTP releases are possbile to install on any compatible machine, for the sake of simplicity this guide focuses only on Debian/Ubuntu and Alpine.
81 +Similarly to other binaries, OTP releases tend to be only compatible with the distro they are built on, as such this guide focuses only on Debian/Ubuntu and Alpine.
85 @@ -19,7 +20,7 @@ Paste the following into the shell:
86 arch="$(uname -m)";if [ "$arch" = "x86_64" ];then arch="amd64";elif [ "$arch" = "armv7l" ];then arch="arm";elif [ "$arch" = "aarch64" ];then arch="arm64";else echo "Unsupported arch: $arch">&2;fi;if getconf GNU_LIBC_VERSION>/dev/null;then libc_postfix="";elif [ "$(ldd 2>&1|head -c 9)" = "musl libc" ];then libc_postfix="-musl";elif [ "$(find /lib/libc.musl*|wc -l)" ];then libc_postfix="-musl";else echo "Unsupported libc">&2;fi;echo "$arch$libc_postfix"
89 -If your platform is supported the output will contain the flavour string, you will need it later. If not, this just means that we don't build releases for your platform, you can still try installing from source.
90 +This should give your flavour string. If not this just means that we don't build releases for your platform, you can still try installing from source.
92 ### Installing the required packages
94 diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex
95 index a9a9eeeed17adaacc51a5cd6927e5f0daa65e79d..cc3772563b8380af0da1a64ceba238ea144a05ac 100644
96 --- a/lib/pleroma/object/fetcher.ex
97 +++ b/lib/pleroma/object/fetcher.ex
98 @@ -8,77 +8,30 @@ defmodule Pleroma.Object.Fetcher do
101 alias Pleroma.Object.Containment
103 alias Pleroma.Signature
104 alias Pleroma.Web.ActivityPub.InternalFetchActor
105 + alias Pleroma.Web.ActivityPub.MRF
106 alias Pleroma.Web.ActivityPub.ObjectValidator
107 + alias Pleroma.Web.ActivityPub.Pipeline
108 alias Pleroma.Web.ActivityPub.Transmogrifier
109 alias Pleroma.Web.Federator
112 require Pleroma.Constants
114 - defp touch_changeset(changeset) do
116 - NaiveDateTime.utc_now()
117 - |> NaiveDateTime.truncate(:second)
119 - Ecto.Changeset.put_change(changeset, :updated_at, updated_at)
122 - defp maybe_reinject_internal_fields(%{data: %{} = old_data}, new_data) do
124 - %{"formerRepresentations" => %{"orderedItems" => list}} when is_list(list) -> true
128 - internal_fields = Map.take(old_data, Pleroma.Constants.object_internal_fields())
130 - remote_history_exists? = has_history?.(new_data)
132 - # If the remote history exists, we treat that as the only source of truth.
134 - if has_history?.(old_data) and not remote_history_exists? do
135 - Map.put(new_data, "formerRepresentations", old_data["formerRepresentations"])
140 - # If the remote does not have history information, we need to manage it ourselves
142 - if not remote_history_exists? do
144 - Pleroma.Constants.status_updatable_fields()
145 - |> Enum.any?(fn field -> Map.get(old_data, field) != Map.get(new_data, field) end)
147 - %{updated_object: updated_object} =
149 - |> Object.Updater.maybe_update_history(old_data,
151 - use_history_in_new_object?: false
159 - Map.merge(new_data, internal_fields)
162 - defp maybe_reinject_internal_fields(_, new_data), do: new_data
164 @spec reinject_object(struct(), map()) :: {:ok, Object.t()} | {:error, any()}
165 - defp reinject_object(%Object{data: %{"type" => "Question"}} = object, new_data) do
166 + defp reinject_object(%Object{data: %{}} = object, new_data) do
167 Logger.debug("Reinjecting object #{new_data["id"]}")
169 - with data <- maybe_reinject_internal_fields(object, new_data),
170 - {:ok, data, _} <- ObjectValidator.validate(data, %{}),
171 - changeset <- Object.change(object, %{data: data}),
172 - changeset <- touch_changeset(changeset),
173 - {:ok, object} <- Repo.insert_or_update(changeset),
174 - {:ok, object} <- Object.set_cache(object) do
176 + with {:ok, new_data, _} <- ObjectValidator.validate(new_data, %{}),
177 + {:ok, new_data} <- MRF.filter(new_data),
178 + {:ok, new_object, _} <-
179 + Object.Updater.do_update_and_invalidate_cache(
182 + _touch_changeset? = true
187 Logger.error("Error while processing object: #{inspect(e)}")
188 @@ -86,20 +39,11 @@ defp reinject_object(%Object{data: %{"type" => "Question"}} = object, new_data)
192 - defp reinject_object(%Object{} = object, new_data) do
193 - Logger.debug("Reinjecting object #{new_data["id"]}")
195 - with new_data <- Transmogrifier.fix_object(new_data),
196 - data <- maybe_reinject_internal_fields(object, new_data),
197 - changeset <- Object.change(object, %{data: data}),
198 - changeset <- touch_changeset(changeset),
199 - {:ok, object} <- Repo.insert_or_update(changeset),
200 - {:ok, object} <- Object.set_cache(object) do
201 + defp reinject_object(_, new_data) do
202 + with {:ok, object, _} <- Pipeline.common_pipeline(new_data, local: false) do
206 - Logger.error("Error while processing object: #{inspect(e)}")
212 diff --git a/lib/pleroma/object/updater.ex b/lib/pleroma/object/updater.ex
213 index ab38d3ed2b65c843b9268e6b01cb214dbc26b3bb..b1e4870bac4c7900966a57d7dd6774606c0f6109 100644
214 --- a/lib/pleroma/object/updater.ex
215 +++ b/lib/pleroma/object/updater.ex
217 defmodule Pleroma.Object.Updater do
218 require Pleroma.Constants
220 + alias Pleroma.Object
223 def update_content_fields(orig_object_data, updated_object) do
224 Pleroma.Constants.status_updatable_fields()
226 @@ -97,12 +100,14 @@ def maybe_update_history(
229 defp maybe_update_poll(to_be_updated, updated_object) do
230 - choice_key = fn data ->
231 - if Map.has_key?(data, "anyOf"), do: "anyOf", else: "oneOf"
233 + %{"anyOf" => [_ | _]} -> "anyOf"
234 + %{"oneOf" => [_ | _]} -> "oneOf"
238 with true <- to_be_updated["type"] == "Question",
239 - key <- choice_key.(updated_object),
240 + key when not is_nil(key) <- choice_key.(updated_object),
241 true <- key == choice_key.(to_be_updated),
242 orig_choices <- to_be_updated[key] |> Enum.map(&Map.drop(&1, ["replies"])),
243 new_choices <- updated_object[key] |> Enum.map(&Map.drop(&1, ["replies"])),
244 @@ -237,4 +242,49 @@ def do_with_history(object, fun) do
245 {:history_items, e} -> e
249 + defp maybe_touch_changeset(changeset, true) do
251 + NaiveDateTime.utc_now()
252 + |> NaiveDateTime.truncate(:second)
254 + Ecto.Changeset.put_change(changeset, :updated_at, updated_at)
257 + defp maybe_touch_changeset(changeset, _), do: changeset
259 + def do_update_and_invalidate_cache(orig_object, updated_object, touch_changeset? \\ false) do
260 + orig_object_ap_id = updated_object["id"]
261 + orig_object_data = orig_object.data
264 + updated_data: updated_object_data,
266 + used_history_in_new_object?: used_history_in_new_object?
267 + } = make_new_object_data_from_update_object(orig_object_data, updated_object)
271 + |> Repo.preload(:hashtags)
272 + |> Object.change(%{data: updated_object_data})
273 + |> maybe_touch_changeset(touch_changeset?)
275 + with {:ok, new_object} <- Repo.update(changeset),
276 + {:ok, _} <- Object.invalid_object_cache(new_object),
277 + {:ok, _} <- Object.set_cache(new_object),
278 + # The metadata/utils.ex uses the object id for the cache.
279 + {:ok, _} <- Pleroma.Activity.HTML.invalidate_cache_for(new_object.id) do
280 + if used_history_in_new_object? do
281 + with create_activity when not is_nil(create_activity) <-
282 + Pleroma.Activity.get_create_by_object_ap_id(orig_object_ap_id),
283 + {:ok, _} <- Pleroma.Activity.HTML.invalidate_cache_for(create_activity.id) do
290 + {:ok, new_object, updated}
294 diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex
295 index a2152b945235892d7f87c3fb4b185a740bd4112e..fc5dec3628c7f5e0e19c2c91cdb4baa22f103a39 100644
296 --- a/lib/pleroma/web/activity_pub/side_effects.ex
297 +++ b/lib/pleroma/web/activity_pub/side_effects.ex
298 @@ -428,37 +428,13 @@ defp handle_update_object(
301 if orig_object_data["type"] in Pleroma.Constants.updatable_object_types() do
303 - updated_data: updated_object_data,
305 - used_history_in_new_object?: used_history_in_new_object?
306 - } = Object.Updater.make_new_object_data_from_update_object(orig_object_data, updated_object)
310 - |> Repo.preload(:hashtags)
311 - |> Object.change(%{data: updated_object_data})
313 - with {:ok, new_object} <- Repo.update(changeset),
314 - {:ok, _} <- Object.invalid_object_cache(new_object),
315 - {:ok, _} <- Object.set_cache(new_object),
316 - # The metadata/utils.ex uses the object id for the cache.
317 - {:ok, _} <- Pleroma.Activity.HTML.invalidate_cache_for(new_object.id) do
318 - if used_history_in_new_object? do
319 - with create_activity when not is_nil(create_activity) <-
320 - Pleroma.Activity.get_create_by_object_ap_id(orig_object_ap_id),
321 - {:ok, _} <- Pleroma.Activity.HTML.invalidate_cache_for(create_activity.id) do
327 + {:ok, _, updated} =
328 + Object.Updater.do_update_and_invalidate_cache(orig_object, updated_object)
332 - |> Activity.normalize()
333 - |> ActivityPub.notify_and_stream()
337 + |> Activity.normalize()
338 + |> ActivityPub.notify_and_stream()
342 diff --git a/lib/pleroma/web/feed/feed_view.ex b/lib/pleroma/web/feed/feed_view.ex
343 index 449659f4bbe7b37a3c5f9d11b55fe7036d0d425f..034722eb2e7a7c99fcb1384132d81b6ed7dcd3f1 100644
344 --- a/lib/pleroma/web/feed/feed_view.ex
345 +++ b/lib/pleroma/web/feed/feed_view.ex
346 @@ -6,7 +6,6 @@ defmodule Pleroma.Web.Feed.FeedView do
348 use Pleroma.Web, :view
350 - alias Pleroma.Formatter
353 alias Pleroma.Web.Gettext
354 @@ -72,7 +71,9 @@ def logo(user) do
356 def last_activity(activities), do: List.last(activities)
358 - def activity_title(%{"content" => content, "summary" => summary} = data, opts \\ %{}) do
359 + def activity_title(%{"content" => content} = data, opts \\ %{}) do
360 + summary = Map.get(data, "summary", "")
364 summary != "" -> summary
365 @@ -81,9 +82,8 @@ def activity_title(%{"content" => content, "summary" => summary} = data, opts \\
369 - |> Pleroma.Web.Metadata.Utils.scrub_html()
370 - |> Pleroma.Emoji.Formatter.demojify()
371 - |> Formatter.truncate(opts[:max_length], opts[:omission])
372 + |> Pleroma.Web.Metadata.Utils.scrub_html_and_truncate(opts[:max_length], opts[:omission])
373 + |> HtmlEntities.encode()
376 def activity_description(data) do
377 diff --git a/lib/pleroma/web/media_proxy/media_proxy_controller.ex b/lib/pleroma/web/media_proxy/media_proxy_controller.ex
378 index d2ad62c13910fbb4a53630ff395089ce204ee8dc..bda5b36edcea2341d29052567b0b4638d3d41660 100644
379 --- a/lib/pleroma/web/media_proxy/media_proxy_controller.ex
380 +++ b/lib/pleroma/web/media_proxy/media_proxy_controller.ex
381 @@ -12,6 +12,8 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyController do
382 alias Pleroma.Web.MediaProxy
387 def remote(conn, %{"sig" => sig64, "url" => url64}) do
388 with {_, true} <- {:enabled, MediaProxy.enabled?()},
389 {:ok, url} <- MediaProxy.decode_url(sig64, url64),
390 @@ -202,4 +204,9 @@ defp media_preview_proxy_config do
391 defp media_proxy_opts do
392 Config.get([:media_proxy, :proxy_opts], [])
395 + defp sandbox(conn, _params) do
397 + |> merge_resp_headers([{"content-security-policy", "sandbox;"}])
400 diff --git a/lib/pleroma/web/metadata/utils.ex b/lib/pleroma/web/metadata/utils.ex
401 index 15414a988d72ca36c2ea8e92f6b7528ce4d8df94..80a8be9a2d5e2db48f37d1ff809c1e565517a087 100644
402 --- a/lib/pleroma/web/metadata/utils.ex
403 +++ b/lib/pleroma/web/metadata/utils.ex
404 @@ -30,12 +30,13 @@ def scrub_html_and_truncate(%{data: %{"content" => content}} = object) do
405 |> scrub_html_and_truncate_object_field(object)
408 - def scrub_html_and_truncate(content, max_length \\ 200) when is_binary(content) do
409 + def scrub_html_and_truncate(content, max_length \\ 200, omission \\ "...")
410 + when is_binary(content) do
413 |> Emoji.Formatter.demojify()
414 |> HtmlEntities.decode()
415 - |> Formatter.truncate(max_length)
416 + |> Formatter.truncate(max_length, omission)
419 def scrub_html(content) when is_binary(content) do
420 diff --git a/lib/pleroma/web/plugs/authentication_plug.ex b/lib/pleroma/web/plugs/authentication_plug.ex
421 index a7fd697b5d106a5101ea484d79ca05b3cbd3fc97..f912a1542f8a761cb4cee485528beddd2f0cc60c 100644
422 --- a/lib/pleroma/web/plugs/authentication_plug.ex
423 +++ b/lib/pleroma/web/plugs/authentication_plug.ex
424 @@ -38,10 +38,6 @@ def call(
426 def call(conn, _), do: conn
428 - def checkpw(password, "$6" <> _ = password_hash) do
429 - :crypt.crypt(password, password_hash) == password_hash
432 def checkpw(password, "$2" <> _ = password_hash) do
433 # Handle bcrypt passwords for Mastodon migration
434 Bcrypt.verify_pass(password, password_hash)
435 @@ -60,10 +56,6 @@ def maybe_update_password(%User{password_hash: "$2" <> _} = user, password) do
436 do_update_password(user, password)
439 - def maybe_update_password(%User{password_hash: "$6" <> _} = user, password) do
440 - do_update_password(user, password)
443 def maybe_update_password(user, _), do: {:ok, user}
445 defp do_update_password(user, password) do
446 diff --git a/lib/pleroma/web/rich_media/parsers/o_embed.ex b/lib/pleroma/web/rich_media/parsers/o_embed.ex
447 index 75318d9c7207bc0cf2890a5193bb0eeed6600418..0f303176ce849ad36587859edf7d1af73773edbe 100644
448 --- a/lib/pleroma/web/rich_media/parsers/o_embed.ex
449 +++ b/lib/pleroma/web/rich_media/parsers/o_embed.ex
450 @@ -6,8 +6,8 @@ defmodule Pleroma.Web.RichMedia.Parsers.OEmbed do
451 def parse(html, _data) do
452 with elements = [_ | _] <- get_discovery_data(html),
453 oembed_url when is_binary(oembed_url) <- get_oembed_url(elements),
454 - {:ok, oembed_data} <- get_oembed_data(oembed_url) do
456 + {:ok, oembed_data = %{"html" => html}} <- get_oembed_data(oembed_url) do
457 + %{oembed_data | "html" => Pleroma.HTML.filter_tags(html)}
461 diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
462 index ba1d64ab23dbf9f21342c239d800708724e9498d..c1a690e28a59009292587d76176a80cd73715fb4 100644
463 --- a/lib/pleroma/web/router.ex
464 +++ b/lib/pleroma/web/router.ex
465 @@ -835,8 +835,7 @@ defmodule Pleroma.Web.Router do
468 scope "/", Pleroma.Web do
469 - # Note: html format is supported only if static FE is enabled
470 - pipe_through([:accepts_html_xml, :static_fe])
471 + pipe_through([:accepts_html_xml])
473 get("/users/:nickname/feed", Feed.UserController, :feed, as: :user_feed)
475 diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex
476 index 3c0da5c276d7aa0936511a9726d001405eee0243..b9a04cc7674408bd063cd0cb5c4d3ef8d055afb8 100644
477 --- a/lib/pleroma/web/streamer.ex
478 +++ b/lib/pleroma/web/streamer.ex
479 @@ -25,6 +25,7 @@ defmodule Pleroma.Web.Streamer do
480 def registry, do: @registry
482 @public_streams ["public", "public:local", "public:media", "public:local:media"]
483 + @local_streams ["public:local", "public:local:media"]
484 @user_streams ["user", "user:notification", "direct", "user:pleroma_chat"]
486 @doc "Expands and authorizes a stream, and registers the process for streaming."
487 @@ -41,14 +42,37 @@ def get_topic_and_add_socket(stream, user, oauth_token, params \\ %{}) do
491 + defp can_access_stream(user, oauth_token, kind) do
492 + with {_, true} <- {:restrict?, Config.restrict_unauthenticated_access?(:timelines, kind)},
493 + {_, %User{id: user_id}, %Token{user_id: user_id}} <- {:user, user, oauth_token},
496 + OAuthScopesPlug.filter_descendants(["read:statuses"], oauth_token.scopes) != []} do
507 @doc "Expand and authorizes a stream"
508 @spec get_topic(stream :: String.t(), User.t() | nil, Token.t() | nil, Map.t()) ::
509 {:ok, topic :: String.t()} | {:error, :bad_topic}
510 def get_topic(stream, user, oauth_token, params \\ %{})
512 - # Allow all public steams.
513 - def get_topic(stream, _user, _oauth_token, _params) when stream in @public_streams do
515 + # Allow all public steams if the instance allows unauthenticated access.
516 + # Otherwise, only allow users with valid oauth tokens.
517 + def get_topic(stream, user, oauth_token, _params) when stream in @public_streams do
518 + kind = if stream in @local_streams, do: :local, else: :federated
520 + if can_access_stream(user, oauth_token, kind) do
523 + {:error, :unauthorized}
527 # Allow all hashtags streams.
528 @@ -57,12 +81,20 @@ def get_topic("hashtag", _user, _oauth_token, %{"tag" => tag} = _params) do
531 # Allow remote instance streams.
532 - def get_topic("public:remote", _user, _oauth_token, %{"instance" => instance} = _params) do
533 - {:ok, "public:remote:" <> instance}
534 + def get_topic("public:remote", user, oauth_token, %{"instance" => instance} = _params) do
535 + if can_access_stream(user, oauth_token, :federated) do
536 + {:ok, "public:remote:" <> instance}
538 + {:error, :unauthorized}
542 - def get_topic("public:remote:media", _user, _oauth_token, %{"instance" => instance} = _params) do
543 - {:ok, "public:remote:media:" <> instance}
544 + def get_topic("public:remote:media", user, oauth_token, %{"instance" => instance} = _params) do
545 + if can_access_stream(user, oauth_token, :federated) do
546 + {:ok, "public:remote:media:" <> instance}
548 + {:error, :unauthorized}
552 # Expand user streams.
553 diff --git a/lib/pleroma/web/templates/feed/feed/_activity.atom.eex b/lib/pleroma/web/templates/feed/feed/_activity.atom.eex
554 index 260338772ac9823de69c4c85fe2eb7765bcd9b9d..b774f7984428c554757867b3d1934b7d24bc1547 100644
555 --- a/lib/pleroma/web/templates/feed/feed/_activity.atom.eex
556 +++ b/lib/pleroma/web/templates/feed/feed/_activity.atom.eex
558 <id><%= @data["id"] %></id>
559 <title><%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %></title>
560 <content type="html"><%= activity_description(@data) %></content>
561 - <published><%= to_rfc3339(@activity.data["published"]) %></published>
562 - <updated><%= to_rfc3339(@activity.data["published"]) %></updated>
563 + <published><%= to_rfc3339(@data["published"]) %></published>
564 + <updated><%= to_rfc3339(@data["published"]) %></updated>
565 <ostatus:conversation ref="<%= activity_context(@activity) %>">
566 <%= activity_context(@activity) %>
567 </ostatus:conversation>
568 diff --git a/lib/pleroma/web/templates/feed/feed/_activity.rss.eex b/lib/pleroma/web/templates/feed/feed/_activity.rss.eex
569 index 5c8f35fe47f44a93d889580334463d884143e32b..7de98f73682965562b1d013cfe17e804c397ba83 100644
570 --- a/lib/pleroma/web/templates/feed/feed/_activity.rss.eex
571 +++ b/lib/pleroma/web/templates/feed/feed/_activity.rss.eex
573 <guid><%= @data["id"] %></guid>
574 <title><%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %></title>
575 <description><%= activity_description(@data) %></description>
576 - <pubDate><%= to_rfc2822(@activity.data["published"]) %></pubDate>
577 + <pubDate><%= to_rfc2822(@data["published"]) %></pubDate>
578 <ostatus:conversation ref="<%= activity_context(@activity) %>">
579 <%= activity_context(@activity) %>
580 </ostatus:conversation>
581 diff --git a/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex b/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex
582 index 25980c1e4292b1eb3e197325229e1f2118747cb6..03c222975ec756c28fbdc35578402ddd0976fbab 100644
583 --- a/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex
584 +++ b/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex
586 <id><%= @data["id"] %></id>
587 <title><%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %></title>
588 <content type="html"><%= activity_description(@data) %></content>
589 - <published><%= to_rfc3339(@activity.data["published"]) %></published>
590 - <updated><%= to_rfc3339(@activity.data["published"]) %></updated>
591 + <published><%= to_rfc3339(@data["published"]) %></published>
592 + <updated><%= to_rfc3339(@data["published"]) %></updated>
593 <ostatus:conversation ref="<%= activity_context(@activity) %>">
594 <%= activity_context(@activity) %>
595 </ostatus:conversation>
596 diff --git a/lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex b/lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex
597 index d582c83e8c7f497e299899b611a6e522046779f8..1b8c34b87101e664ecdf6c6f6735a53f794ea3db 100644
598 --- a/lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex
599 +++ b/lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex
602 <guid isPermalink="true"><%= activity_context(@activity) %></guid>
603 <link><%= activity_context(@activity) %></link>
604 - <pubDate><%= to_rfc2822(@activity.data["published"]) %></pubDate>
605 + <pubDate><%= to_rfc2822(@data["published"]) %></pubDate>
607 <description><%= activity_description(@data) %></description>
608 <%= for attachment <- @data["attachment"] || [] do %>
609 diff --git a/lib/pleroma/workers/background_worker.ex b/lib/pleroma/workers/background_worker.ex
610 index 3805293bc351f91e80e042bac8c730e6f3a9cbb2..79441761267b8a4aa54a86bb94228440fb73cb15 100644
611 --- a/lib/pleroma/workers/background_worker.ex
612 +++ b/lib/pleroma/workers/background_worker.ex
613 @@ -45,5 +45,5 @@ def perform(%Job{args: %{"op" => "delete_instance", "host" => host}}) do
617 - def timeout(_job), do: :timer.seconds(5)
618 + def timeout(_job), do: :timer.seconds(900)
620 diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex
621 index 4f513b907481ee86c14ef5fa6552aa32a0eedc31..cf1bb62b44e2d0f26cc66b883d65d3f4bb4c6768 100644
622 --- a/lib/pleroma/workers/receiver_worker.ex
623 +++ b/lib/pleroma/workers/receiver_worker.ex
624 @@ -13,6 +13,9 @@ def perform(%Job{args: %{"op" => "incoming_ap_doc", "params" => params}}) do
627 {:error, :origin_containment_failed} -> {:cancel, :origin_containment_failed}
628 + {:error, :already_present} -> {:cancel, :already_present}
629 + {:error, {:validate_object, reason}} -> {:cancel, reason}
630 + {:error, {:error, {:validate, reason}}} -> {:cancel, reason}
631 {:error, {:reject, reason}} -> {:cancel, reason}
634 diff --git a/mix.exs b/mix.exs
635 index ab0be4deb0f6ff76df4a084d9672729c536d07a0..79fd9c9efebee61253cb417aed03fc95b52bf7be 100644
638 @@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do
642 - version: version("2.5.1"),
643 + version: version("2.5.2"),
645 elixirc_paths: elixirc_paths(Mix.env()),
646 compilers: [:phoenix, :gettext] ++ Mix.compilers(),
647 @@ -150,7 +150,6 @@ defp deps do
648 {:sweet_xml, "~> 0.7.2"},
649 {:earmark, "~> 1.4.22"},
650 {:bbcode_pleroma, "~> 0.2.0"},
651 - {:crypt, "~> 1.0"},
652 {:cors_plug, "~> 2.0"},
653 {:web_push_encryption, "~> 0.3.1"},
655 diff --git a/mix.lock b/mix.lock
656 index 3027863262e5fc733b9a11b39d25d918e49515ce..8419dc73972280de7f3f5b5b2b6135ae0f08ace5 100644
660 "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
661 "credo": {:hex, :credo, "1.6.7", "323f5734350fd23a456f2688b9430e7d517afb313fbd38671b8a4449798a7854", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "41e110bfb007f7eda7f897c10bf019ceab9a0b269ce79f015d54b0dcf4fc7dd3"},
662 "crontab": {:hex, :crontab, "1.1.8", "2ce0e74777dfcadb28a1debbea707e58b879e6aa0ffbf9c9bb540887bce43617", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
663 - "crypt": {:hex, :crypt, "1.0.1", "a3567e1c651a2ec42c6650d9f3ab789e0f12a508c060653a9bbb5fafe60f043c", [:rebar3], [], "hexpm", "968dffe321c7a5d9f9b4577c4a4ff56a1c26d1a8a2270eb22c7636a0b43d3982"},
664 "custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"},
665 "db_connection": {:hex, :db_connection, "2.4.2", "f92e79aff2375299a16bcb069a14ee8615c3414863a6fef93156aee8e86c2ff3", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4fe53ca91b99f55ea249693a0229356a08f4d1a7931d8ffa79289b145fe83668"},
666 "decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
667 diff --git a/test/pleroma/object/fetcher_test.exs b/test/pleroma/object/fetcher_test.exs
668 index c8ad66ddb45eda7658a1d552ab8948cbef004417..53c9277d6778014dbcd8a9f0de26e595375766a9 100644
669 --- a/test/pleroma/object/fetcher_test.exs
670 +++ b/test/pleroma/object/fetcher_test.exs
671 @@ -9,8 +9,12 @@ defmodule Pleroma.Object.FetcherTest do
672 alias Pleroma.Instances
674 alias Pleroma.Object.Fetcher
675 + alias Pleroma.Web.ActivityPub.ObjectValidator
677 + require Pleroma.Constants
680 + import Pleroma.Factory
684 @@ -284,6 +288,8 @@ test "it can refetch pruned objects" do
686 describe "refetching" do
688 + insert(:user, ap_id: "https://mastodon.social/users/emelie")
691 "id" => "https://mastodon.social/1",
692 "actor" => "https://mastodon.social/users/emelie",
693 @@ -293,10 +299,14 @@ test "it can refetch pruned objects" do
699 + "to" => [Pleroma.Constants.as_public()],
701 + "published" => "2023-05-08 23:43:20Z",
702 + "updated" => "2023-05-09 23:43:20Z"
705 + {:ok, local_object1, _} = ObjectValidator.validate(object1, [])
708 "id" => "https://mastodon.social/2",
709 "actor" => "https://mastodon.social/users/emelie",
710 @@ -306,8 +316,10 @@ test "it can refetch pruned objects" do
715 + "to" => [Pleroma.Constants.as_public()],
717 + "published" => "2023-05-08 23:43:20Z",
718 + "updated" => "2023-05-09 23:43:25Z",
719 "formerRepresentations" => %{
720 "type" => "OrderedCollection",
722 @@ -319,14 +331,18 @@ test "it can refetch pruned objects" do
728 + "to" => [Pleroma.Constants.as_public()],
730 + "published" => "2023-05-08 23:43:20Z",
731 + "updated" => "2023-05-09 23:43:21Z"
738 + {:ok, local_object2, _} = ObjectValidator.validate(object2, [])
743 @@ -335,7 +351,7 @@ test "it can refetch pruned objects" do
746 headers: [{"content-type", "application/activity+json"}],
747 - body: Jason.encode!(object1)
748 + body: Jason.encode!(object1 |> Map.put("updated", "2023-05-09 23:44:20Z"))
752 @@ -345,7 +361,7 @@ test "it can refetch pruned objects" do
755 headers: [{"content-type", "application/activity+json"}],
756 - body: Jason.encode!(object2)
757 + body: Jason.encode!(object2 |> Map.put("updated", "2023-05-09 23:44:20Z"))
761 @@ -370,7 +386,7 @@ test "it can refetch pruned objects" do
762 apply(HttpRequestMock, :request, [env])
765 - %{object1: object1, object2: object2}
766 + %{object1: local_object1, object2: local_object2}
769 test "it keeps formerRepresentations if remote does not have this attr", %{object1: object1} do
770 @@ -388,8 +404,9 @@ test "it keeps formerRepresentations if remote does not have this attr", %{objec
776 + "to" => [Pleroma.Constants.as_public()],
778 + "published" => "2023-05-08 23:43:20Z"
782 @@ -467,6 +484,53 @@ test "it adds to formerRepresentations if the remote does not have one and the o
787 + test "it keeps the history intact if only updated time has changed",
788 + %{object1: object1} do
792 + "updated" => "2023-05-08 23:43:47Z",
793 + "formerRepresentations" => %{
794 + "type" => "OrderedCollection",
795 + "orderedItems" => [
796 + %{"type" => "Note", "content" => "mew mew 1"}
802 + {:ok, o} = Object.create(full_object1)
804 + assert {:ok, refetched} = Fetcher.refetch_object(o)
807 + "content" => "test 1",
808 + "formerRepresentations" => %{
809 + "orderedItems" => [
810 + %{"content" => "mew mew 1"}
817 + test "it goes through ObjectValidator and MRF", %{object2: object2} do
818 + with_mock Pleroma.Web.ActivityPub.MRF, [:passthrough],
820 + %{"type" => "Note"} = object ->
821 + {:ok, Map.put(object, "content", "MRFd content")}
826 + {:ok, o} = Object.create(object2)
828 + assert {:ok, refetched} = Fetcher.refetch_object(o)
830 + assert %{"content" => "MRFd content"} = refetched.data
835 describe "fetch with history" do
836 diff --git a/test/pleroma/web/federator_test.exs b/test/pleroma/web/federator_test.exs
837 index 41d1c5d5e842f627668eba496f19b1f50fe9eaa2..1ffe6aae15d129eca24bbdbb1324862ddde0421a 100644
838 --- a/test/pleroma/web/federator_test.exs
839 +++ b/test/pleroma/web/federator_test.exs
840 @@ -133,7 +133,7 @@ test "successfully processes incoming AP docs with correct origin" do
841 assert {:ok, _activity} = ObanHelpers.perform(job)
843 assert {:ok, job} = Federator.incoming_ap_doc(params)
844 - assert {:error, :already_present} = ObanHelpers.perform(job)
845 + assert {:cancel, :already_present} = ObanHelpers.perform(job)
848 test "rejects incoming AP docs with incorrect origin" do
849 diff --git a/test/pleroma/web/feed/user_controller_test.exs b/test/pleroma/web/feed/user_controller_test.exs
850 index de32d3d4bf0398692fd16e4bc15c94cc8ac0a81b..d3c4108de09bc3a1d8a41bb427999026848b6b6e 100644
851 --- a/test/pleroma/web/feed/user_controller_test.exs
852 +++ b/test/pleroma/web/feed/user_controller_test.exs
853 @@ -57,9 +57,23 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
856 note_activity2 = insert(:note_activity, note: note2)
862 + "content" => "This note tests whether HTML entities are truncated properly",
863 + "summary" => "Won't, didn't fail",
864 + "inReplyTo" => note_activity2.id
868 + _note_activity3 = insert(:note_activity, note: note3)
869 object = Object.normalize(note_activity, fetch: false)
871 - [user: user, object: object, max_id: note_activity2.id]
872 + encoded_title = FeedView.activity_title(note3.data)
874 + [user: user, object: object, max_id: note_activity2.id, encoded_title: encoded_title]
877 test "gets an atom feed", %{conn: conn, user: user, object: object, max_id: max_id} do
878 @@ -74,7 +88,7 @@ test "gets an atom feed", %{conn: conn, user: user, object: object, max_id: max_
880 |> SweetXml.xpath(~x"//entry/title/text()"l)
882 - assert activity_titles == ['2hu', '2hu & as']
883 + assert activity_titles == ['Won\'t, didn\'...', '2hu', '2hu & as']
884 assert resp =~ FeedView.escape(object.data["content"])
885 assert resp =~ FeedView.escape(object.data["summary"])
886 assert resp =~ FeedView.escape(object.data["context"])
887 @@ -105,7 +119,7 @@ test "gets a rss feed", %{conn: conn, user: user, object: object, max_id: max_id
889 |> SweetXml.xpath(~x"//item/title/text()"l)
891 - assert activity_titles == ['2hu', '2hu & as']
892 + assert activity_titles == ['Won\'t, didn\'...', '2hu', '2hu & as']
893 assert resp =~ FeedView.escape(object.data["content"])
894 assert resp =~ FeedView.escape(object.data["summary"])
895 assert resp =~ FeedView.escape(object.data["context"])
896 @@ -176,6 +190,30 @@ test "does not require authentication on non-federating instances", %{conn: conn
897 |> get("/users/#{user.nickname}/feed.rss")
901 + test "does not mangle HTML entities midway", %{
905 + encoded_title: encoded_title
909 + |> put_req_header("accept", "application/atom+xml")
910 + |> get(user_feed_path(conn, :feed, user.nickname))
915 + |> SweetXml.parse()
916 + |> SweetXml.xpath(~x"//entry/title/text()"l)
918 + assert activity_titles == ['Won\'t, didn\'...', '2hu', '2hu & as']
919 + assert resp =~ FeedView.escape(object.data["content"])
920 + assert resp =~ FeedView.escape(object.data["summary"])
921 + assert resp =~ FeedView.escape(object.data["context"])
922 + assert resp =~ encoded_title
926 # Note: see ActivityPubControllerTest for JSON format tests
927 diff --git a/test/pleroma/web/media_proxy/media_proxy_controller_test.exs b/test/pleroma/web/media_proxy/media_proxy_controller_test.exs
928 index 5246bf0c4b1990e9c8948f1e0bab4b94c64271f7..9ce092fd8fa01c3cb548deffe21cb726ed6c0d77 100644
929 --- a/test/pleroma/web/media_proxy/media_proxy_controller_test.exs
930 +++ b/test/pleroma/web/media_proxy/media_proxy_controller_test.exs
931 @@ -6,7 +6,9 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
932 use Pleroma.Web.ConnCase
937 + alias Pleroma.ReverseProxy.ClientMock
938 alias Pleroma.Web.MediaProxy
941 @@ -74,6 +76,20 @@ test "it returns 404 when url is in banned_urls cache", %{conn: conn, url: url}
942 assert %Conn{status: 404, resp_body: "Not Found"} = get(conn, url)
946 + test "it applies sandbox CSP to MediaProxy requests", %{conn: conn} do
947 + media_url = "https://lain.com/image.png"
948 + media_proxy_url = MediaProxy.encode_url(media_url)
951 + |> expect(:request, fn :get, ^media_url, _, _, _ ->
952 + {:ok, 200, [{"content-type", "image/png"}]}
955 + %Conn{resp_headers: headers} = get(conn, media_proxy_url)
957 + assert {"content-security-policy", "sandbox;"} in headers
961 describe "Media Preview Proxy" do
962 diff --git a/test/pleroma/web/metadata/utils_test.exs b/test/pleroma/web/metadata/utils_test.exs
963 index 85ef6033a7c77b47d7e315ab28272d5efd9f0f5e..3daf852fba8d75c3783ac66b3f2212344b4a40ae 100644
964 --- a/test/pleroma/web/metadata/utils_test.exs
965 +++ b/test/pleroma/web/metadata/utils_test.exs
966 @@ -72,7 +72,7 @@ test "it does not return old content after editing" do
970 - describe "scrub_html_and_truncate/2" do
971 + describe "scrub_html_and_truncate/3" do
972 test "it returns text without encode HTML" do
973 assert Utils.scrub_html_and_truncate("Pleroma's really cool!") == "Pleroma's really cool!"
975 diff --git a/test/pleroma/web/plugs/authentication_plug_test.exs b/test/pleroma/web/plugs/authentication_plug_test.exs
976 index 41fdb93bc96338125067d525b48c4b9e98ba069e..b8acd01c59232fc1d97f98f4850867da946c1fa4 100644
977 --- a/test/pleroma/web/plugs/authentication_plug_test.exs
978 +++ b/test/pleroma/web/plugs/authentication_plug_test.exs
979 @@ -70,28 +70,6 @@ test "with a bcrypt hash, it updates to a pkbdf2 hash", %{conn: conn} do
980 assert "$pbkdf2" <> _ = user.password_hash
984 - test "with a crypt hash, it updates to a pkbdf2 hash", %{conn: conn} do
988 - "$6$9psBWV8gxkGOZWBz$PmfCycChoxeJ3GgGzwvhlgacb9mUoZ.KUXNCssekER4SJ7bOK53uXrHNb2e4i8yPFgSKyzaW9CcmrDXWIEMtD1"
993 - |> assign(:auth_user, user)
994 - |> assign(:auth_credentials, %{password: "password"})
995 - |> AuthenticationPlug.call(%{})
997 - assert conn.assigns.user.id == conn.assigns.auth_user.id
998 - assert conn.assigns.token == nil
999 - assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug)
1001 - user = User.get_by_id(user.id)
1002 - assert "$pbkdf2" <> _ = user.password_hash
1005 describe "checkpw/2" do
1006 test "check pbkdf2 hash" do
1008 @@ -101,14 +79,6 @@ test "check pbkdf2 hash" do
1009 refute AuthenticationPlug.checkpw("test-password1", hash)
1013 - test "check sha512-crypt hash" do
1015 - "$6$9psBWV8gxkGOZWBz$PmfCycChoxeJ3GgGzwvhlgacb9mUoZ.KUXNCssekER4SJ7bOK53uXrHNb2e4i8yPFgSKyzaW9CcmrDXWIEMtD1"
1017 - assert AuthenticationPlug.checkpw("password", hash)
1020 test "check bcrypt hash" do
1021 hash = "$2a$10$uyhC/R/zoE1ndwwCtMusK.TLVzkQ/Ugsbqp3uXI.CTTz0gBw.24jS"
1023 diff --git a/test/pleroma/web/rich_media/parser_test.exs b/test/pleroma/web/rich_media/parser_test.exs
1024 index ffdc4e5d78cf1b00ffbef87b19cde55e2fde5469..9064138a64352f8374eeced43659eabd847b0ab2 100644
1025 --- a/test/pleroma/web/rich_media/parser_test.exs
1026 +++ b/test/pleroma/web/rich_media/parser_test.exs
1027 @@ -129,7 +129,7 @@ test "parses twitter card" do
1031 - test "parses OEmbed" do
1032 + test "parses OEmbed and filters HTML tags" do
1033 assert Parser.parse("http://example.com/oembed") ==
1036 @@ -139,7 +139,7 @@ test "parses OEmbed" do
1037 "flickr_type" => "photo",
1040 - "<a data-flickr-embed=\"true\" href=\"https://www.flickr.com/photos/bees/2362225867/\" title=\"Bacon Lollys by \u202E\u202D\u202Cbees\u202C, on Flickr\"><img src=\"https://farm4.staticflickr.com/3040/2362225867_4a87ab8baf_b.jpg\" width=\"1024\" height=\"768\" alt=\"Bacon Lollys\"></a><script async src=\"https://embedr.flickr.com/assets/client-code.js\" charset=\"utf-8\"></script>",
1041 + "<a href=\"https://www.flickr.com/photos/bees/2362225867/\" title=\"Bacon Lollys by \u202E\u202D\u202Cbees\u202C, on Flickr\"><img src=\"https://farm4.staticflickr.com/3040/2362225867_4a87ab8baf_b.jpg\" width=\"1024\" height=\"768\" alt=\"Bacon Lollys\"/></a>",
1042 "license" => "All Rights Reserved",
1044 "provider_name" => "Flickr",
1045 diff --git a/test/pleroma/web/streamer_test.exs b/test/pleroma/web/streamer_test.exs
1046 index 8b0c84164dfa20067f9fd96a35225a1dbe93e142..7ab0e379b403b04954c965057a53be8a0f465121 100644
1047 --- a/test/pleroma/web/streamer_test.exs
1048 +++ b/test/pleroma/web/streamer_test.exs
1049 @@ -29,6 +29,26 @@ test "allows public" do
1050 assert {:ok, "public:local:media"} = Streamer.get_topic("public:local:media", nil, nil)
1053 + test "rejects local public streams if restricted_unauthenticated is on" do
1054 + clear_config([:restrict_unauthenticated, :timelines, :local], true)
1056 + assert {:error, :unauthorized} = Streamer.get_topic("public:local", nil, nil)
1057 + assert {:error, :unauthorized} = Streamer.get_topic("public:local:media", nil, nil)
1060 + test "rejects remote public streams if restricted_unauthenticated is on" do
1061 + clear_config([:restrict_unauthenticated, :timelines, :federated], true)
1063 + assert {:error, :unauthorized} = Streamer.get_topic("public", nil, nil)
1064 + assert {:error, :unauthorized} = Streamer.get_topic("public:media", nil, nil)
1066 + assert {:error, :unauthorized} =
1067 + Streamer.get_topic("public:remote", nil, nil, %{"instance" => "lain.com"})
1069 + assert {:error, :unauthorized} =
1070 + Streamer.get_topic("public:remote:media", nil, nil, %{"instance" => "lain.com"})
1073 test "allows instance streams" do
1074 assert {:ok, "public:remote:lain.com"} =
1075 Streamer.get_topic("public:remote", nil, nil, %{"instance" => "lain.com"})
1076 @@ -69,6 +89,63 @@ test "allows public streams (regardless of OAuth token scopes)", %{
1080 + test "allows local public streams if restricted_unauthenticated is on", %{
1082 + token: oauth_token
1084 + clear_config([:restrict_unauthenticated, :timelines, :local], true)
1086 + %{token: read_notifications_token} = oauth_access(["read:notifications"], user: user)
1087 + %{token: badly_scoped_token} = oauth_access(["irrelevant:scope"], user: user)
1089 + assert {:ok, "public:local"} = Streamer.get_topic("public:local", user, oauth_token)
1091 + assert {:ok, "public:local:media"} =
1092 + Streamer.get_topic("public:local:media", user, oauth_token)
1094 + for token <- [read_notifications_token, badly_scoped_token] do
1095 + assert {:error, :unauthorized} = Streamer.get_topic("public:local", user, token)
1097 + assert {:error, :unauthorized} = Streamer.get_topic("public:local:media", user, token)
1101 + test "allows remote public streams if restricted_unauthenticated is on", %{
1103 + token: oauth_token
1105 + clear_config([:restrict_unauthenticated, :timelines, :federated], true)
1107 + %{token: read_notifications_token} = oauth_access(["read:notifications"], user: user)
1108 + %{token: badly_scoped_token} = oauth_access(["irrelevant:scope"], user: user)
1110 + assert {:ok, "public"} = Streamer.get_topic("public", user, oauth_token)
1111 + assert {:ok, "public:media"} = Streamer.get_topic("public:media", user, oauth_token)
1113 + assert {:ok, "public:remote:lain.com"} =
1114 + Streamer.get_topic("public:remote", user, oauth_token, %{"instance" => "lain.com"})
1116 + assert {:ok, "public:remote:media:lain.com"} =
1117 + Streamer.get_topic("public:remote:media", user, oauth_token, %{
1118 + "instance" => "lain.com"
1121 + for token <- [read_notifications_token, badly_scoped_token] do
1122 + assert {:error, :unauthorized} = Streamer.get_topic("public", user, token)
1123 + assert {:error, :unauthorized} = Streamer.get_topic("public:media", user, token)
1125 + assert {:error, :unauthorized} =
1126 + Streamer.get_topic("public:remote", user, token, %{
1127 + "instance" => "lain.com"
1130 + assert {:error, :unauthorized} =
1131 + Streamer.get_topic("public:remote:media", user, token, %{
1132 + "instance" => "lain.com"
1137 test "allows user streams (with proper OAuth token scopes)", %{
1139 token: read_oauth_token
1140 diff --git a/test/pleroma/workers/receiver_worker_test.exs b/test/pleroma/workers/receiver_worker_test.exs
1141 index 283beee4d552293f22a01a2bf184e0ad065a43f3..acea0ae0003812e18e5d5b42df72744c58b6f26a 100644
1142 --- a/test/pleroma/workers/receiver_worker_test.exs
1143 +++ b/test/pleroma/workers/receiver_worker_test.exs
1144 @@ -11,7 +11,7 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do
1146 alias Pleroma.Workers.ReceiverWorker
1148 - test "it ignores MRF reject" do
1149 + test "it does not retry MRF reject" do
1150 params = insert(:note).data
1152 with_mock Pleroma.Web.ActivityPub.Transmogrifier,
1153 @@ -22,4 +22,31 @@ test "it ignores MRF reject" do
1158 + test "it does not retry ObjectValidator reject" do
1160 + insert(:note_activity).data
1161 + |> Map.put("id", Pleroma.Web.ActivityPub.Utils.generate_activity_id())
1162 + |> Map.put("object", %{
1164 + "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id()
1167 + with_mock Pleroma.Web.ActivityPub.ObjectValidator, [:passthrough],
1168 + validate: fn _, _ -> {:error, %Ecto.Changeset{}} end do
1169 + assert {:cancel, {:error, %Ecto.Changeset{}}} =
1170 + ReceiverWorker.perform(%Oban.Job{
1171 + args: %{"op" => "incoming_ap_doc", "params" => params}
1176 + test "it does not retry duplicates" do
1177 + params = insert(:note_activity).data
1179 + assert {:cancel, :already_present} =
1180 + ReceiverWorker.perform(%Oban.Job{
1181 + args: %{"op" => "incoming_ap_doc", "params" => params}