commit: 05cb931e4d5e312477cc6c4cf80ab10180b84fd1
parent e798be90accbc93e9c7102a51ffd2575c9e617ec
Author: marcin mikołajczak <git@mkljczk.pl>
Date: Thu, 22 Feb 2024 12:03:06 +0100
Merge remote-tracking branch 'origin/develop' into post-languages
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
Diffstat:
74 files changed, 635 insertions(+), 577 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -57,5 +57,6 @@ pleroma.iml
.tool-versions
# Editor temp files
-/*~
-/*#
+*~
+*#
+*.swp
diff --git a/CHANGELOG.md b/CHANGELOG.md
@@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
+## 2.6.2
+
+### Security
+- MRF StealEmojiPolicy: Sanitize shortcodes (thanks to Hazel K for the report
+
## 2.6.1
### Changed
- - Document maximum supported version of Erlang & Elixir
diff --git a/changelog.d/atom-leak.skip b/changelog.d/atom-leak.skip
diff --git a/changelog.d/bandit.change b/changelog.d/bandit.change
@@ -0,0 +1 @@
+Support Bandit as an alternative to Cowboy for the HTTP server.
diff --git a/changelog.d/bugfix-ccworks.fix b/changelog.d/bugfix-ccworks.fix
@@ -0,0 +1 @@
+Fix federation with Convergence AP Bridge
+\ No newline at end of file
diff --git a/changelog.d/config-stat-symlink.fix b/changelog.d/config-stat-symlink.fix
@@ -0,0 +1 @@
+- Config: Check the permissions of the linked file instead of the symlink
diff --git a/changelog.d/content-length.fix b/changelog.d/content-length.fix
@@ -0,0 +1 @@
+MediaProxy was setting the content-length header which is not permitted by RFC9112§6.2 when we are chunking the reply as it conflicts with the existence of the transfer-encoding header.
diff --git a/changelog.d/dialyzer4.skip b/changelog.d/dialyzer4.skip
diff --git a/changelog.d/gun-logs.skip b/changelog.d/gun-logs.skip
diff --git a/changelog.d/gun_pool.fix b/changelog.d/gun_pool.fix
@@ -0,0 +1 @@
+Fix logic error in Gun connection pooling which prevented retries even when the worker was launched with retry = true
diff --git a/changelog.d/memleak.fix b/changelog.d/memleak.fix
@@ -0,0 +1 @@
+Fix a memory leak caused by Websocket connections that would not enter a state where a full garbage collection run could be triggered.
diff --git a/changelog.d/mergeback-2.6.2.skip b/changelog.d/mergeback-2.6.2.skip
diff --git a/changelog.d/notifications-index.fix b/changelog.d/notifications-index.fix
@@ -0,0 +1 @@
+Fix notifications query which was not using the index properly
diff --git a/changelog.d/oauth-nickname.skip b/changelog.d/oauth-nickname.skip
@@ -0,0 +1 @@
+Use User.full_nickname/1 in oauth html template
+\ No newline at end of file
diff --git a/changelog.d/rich_media.fix b/changelog.d/rich_media.fix
@@ -0,0 +1 @@
+Rich Media Preview cache eviction when the activity is updated.
diff --git a/changelog.d/rich_media_tests.skip b/changelog.d/rich_media_tests.skip
diff --git a/changelog.d/tesla.deps b/changelog.d/tesla.deps
@@ -0,0 +1 @@
+Update Tesla HTTP client middleware to 1.8.0
diff --git a/changelog.d/websocket-refactor.change b/changelog.d/websocket-refactor.change
@@ -0,0 +1 @@
+Refactor the Mastodon /api/v1/streaming websocket handler to use Phoenix.Socket.Transport
diff --git a/config/config.exs b/config/config.exs
@@ -114,14 +114,7 @@ config :pleroma, :uri_schemes,
config :pleroma, Pleroma.Web.Endpoint,
url: [host: "localhost"],
http: [
- ip: {127, 0, 0, 1},
- dispatch: [
- {:_,
- [
- {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
- {:_, Plug.Cowboy.Handler, {Pleroma.Web.Endpoint, []}}
- ]}
- ]
+ ip: {127, 0, 0, 1}
],
protocol: "https",
secret_key_base: "aK4Abxf29xU9TTDKre9coZPUgevcVCFQJe/5xP/7Lt4BEif6idBIbjupVbOrbKxl",
diff --git a/config/dev.exs b/config/dev.exs
@@ -8,8 +8,7 @@ import Config
# with brunch.io to recompile .js and .css sources.
config :pleroma, Pleroma.Web.Endpoint,
http: [
- port: 4000,
- protocol_options: [max_request_line_length: 8192, max_header_value_length: 8192]
+ port: 4000
],
protocol: "http",
debug_errors: true,
diff --git a/lib/mix/tasks/pleroma/emoji.ex b/lib/mix/tasks/pleroma/emoji.ex
@@ -111,7 +111,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do
{:ok, _} =
:zip.unzip(binary_archive,
- cwd: pack_path,
+ cwd: String.to_charlist(pack_path),
file_list: files_to_unzip
)
diff --git a/lib/phoenix/transports/web_socket/raw.ex b/lib/phoenix/transports/web_socket/raw.ex
@@ -1,93 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Phoenix.Transports.WebSocket.Raw do
- import Plug.Conn,
- only: [
- fetch_query_params: 1,
- send_resp: 3
- ]
-
- alias Phoenix.Socket.Transport
-
- def default_config do
- [
- timeout: 60_000,
- transport_log: false,
- cowboy: Phoenix.Endpoint.CowboyWebSocket
- ]
- end
-
- def init(%Plug.Conn{method: "GET"} = conn, {endpoint, handler, transport}) do
- {_, opts} = handler.__transport__(transport)
-
- conn =
- conn
- |> fetch_query_params
- |> Transport.transport_log(opts[:transport_log])
- |> Transport.check_origin(handler, endpoint, opts)
-
- case conn do
- %{halted: false} = conn ->
- case handler.connect(%{
- endpoint: endpoint,
- transport: transport,
- options: [serializer: nil],
- params: conn.params
- }) do
- {:ok, socket} ->
- {:ok, conn, {__MODULE__, {socket, opts}}}
-
- :error ->
- send_resp(conn, :forbidden, "")
- {:error, conn}
- end
-
- _ ->
- {:error, conn}
- end
- end
-
- def init(conn, _) do
- send_resp(conn, :bad_request, "")
- {:error, conn}
- end
-
- def ws_init({socket, config}) do
- Process.flag(:trap_exit, true)
- {:ok, %{socket: socket}, config[:timeout]}
- end
-
- def ws_handle(op, data, state) do
- state.socket.handler
- |> apply(:handle, [op, data, state])
- |> case do
- {op, data} ->
- {:reply, {op, data}, state}
-
- {op, data, state} ->
- {:reply, {op, data}, state}
-
- %{} = state ->
- {:ok, state}
-
- _ ->
- {:ok, state}
- end
- end
-
- def ws_info({_, _} = tuple, state) do
- {:reply, tuple, state}
- end
-
- def ws_info(_tuple, state), do: {:ok, state}
-
- def ws_close(state) do
- ws_handle(:closed, :normal, state)
- end
-
- def ws_terminate(reason, state) do
- ws_handle(:closed, reason, state)
- end
-end
diff --git a/lib/pleroma/activity/html.ex b/lib/pleroma/activity/html.ex
@@ -28,7 +28,7 @@ defmodule Pleroma.Activity.HTML do
end
end
- defp add_cache_key_for(activity_id, additional_key) do
+ def add_cache_key_for(activity_id, additional_key) do
current = get_cache_keys_for(activity_id)
unless additional_key in current do
diff --git a/lib/pleroma/caching.ex b/lib/pleroma/caching.ex
@@ -8,10 +8,13 @@ defmodule Pleroma.Caching do
@callback put(Cachex.cache(), any(), any(), Keyword.t()) :: {Cachex.status(), boolean()}
@callback put(Cachex.cache(), any(), any()) :: {Cachex.status(), boolean()}
@callback fetch!(Cachex.cache(), any(), function() | nil) :: any()
+ @callback fetch(Cachex.cache(), any(), function() | nil) ::
+ {atom(), any()} | {atom(), any(), any()}
# @callback del(Cachex.cache(), any(), Keyword.t()) :: {Cachex.status(), boolean()}
@callback del(Cachex.cache(), any()) :: {Cachex.status(), boolean()}
@callback stream!(Cachex.cache(), any()) :: Enumerable.t()
@callback expire_at(Cachex.cache(), binary(), number()) :: {Cachex.status(), boolean()}
+ @callback expire(Cachex.cache(), binary(), number()) :: {Cachex.status(), boolean()}
@callback exists?(Cachex.cache(), any()) :: {Cachex.status(), boolean()}
@callback execute!(Cachex.cache(), function()) :: any()
@callback get_and_update(Cachex.cache(), any(), function()) ::
diff --git a/lib/pleroma/config/deprecation_warnings.ex b/lib/pleroma/config/deprecation_warnings.ex
@@ -256,7 +256,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
move_namespace_and_warn(@mrf_config_map, warning_preface)
end
- @spec move_namespace_and_warn([config_map()], String.t()) :: :ok | nil
+ @spec move_namespace_and_warn([config_map()], String.t()) :: :ok | :error
def move_namespace_and_warn(config_map, warning_preface) do
warning =
Enum.reduce(config_map, "", fn
@@ -279,7 +279,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
end
end
- @spec check_media_proxy_whitelist_config() :: :ok | nil
+ @spec check_media_proxy_whitelist_config() :: :ok | :error
def check_media_proxy_whitelist_config do
whitelist = Config.get([:media_proxy, :whitelist])
@@ -340,7 +340,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
end
end
- @spec check_activity_expiration_config() :: :ok | nil
+ @spec check_activity_expiration_config() :: :ok | :error
def check_activity_expiration_config do
warning_preface = """
!!!DEPRECATION WARNING!!!
@@ -356,7 +356,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
)
end
- @spec check_remote_ip_plug_name() :: :ok | nil
+ @spec check_remote_ip_plug_name() :: :ok | :error
def check_remote_ip_plug_name do
warning_preface = """
!!!DEPRECATION WARNING!!!
@@ -372,7 +372,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
)
end
- @spec check_uploaders_s3_public_endpoint() :: :ok | nil
+ @spec check_uploaders_s3_public_endpoint() :: :ok | :error
def check_uploaders_s3_public_endpoint do
s3_config = Pleroma.Config.get([Pleroma.Uploaders.S3])
@@ -393,7 +393,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
end
end
- @spec check_old_chat_shoutbox() :: :ok | nil
+ @spec check_old_chat_shoutbox() :: :ok | :error
def check_old_chat_shoutbox do
instance_config = Pleroma.Config.get([:instance])
chat_config = Pleroma.Config.get([:chat]) || []
diff --git a/lib/pleroma/config/release_runtime_provider.ex b/lib/pleroma/config/release_runtime_provider.ex
@@ -21,7 +21,7 @@ defmodule Pleroma.Config.ReleaseRuntimeProvider do
with_runtime_config =
if File.exists?(config_path) do
# <https://git.pleroma.social/pleroma/pleroma/-/issues/3135>
- %File.Stat{mode: mode} = File.lstat!(config_path)
+ %File.Stat{mode: mode} = File.stat!(config_path)
if Bitwise.band(mode, 0o007) > 0 do
raise "Configuration at #{config_path} has world-permissions, execute the following: chmod o= #{config_path}"
diff --git a/lib/pleroma/emoji/pack.ex b/lib/pleroma/emoji/pack.ex
@@ -100,7 +100,7 @@ defmodule Pleroma.Emoji.Pack do
{:ok, _emoji_files} =
:zip.unzip(
to_charlist(file.path),
- [{:file_list, Enum.map(emojies, & &1[:path])}, {:cwd, tmp_dir}]
+ [{:file_list, Enum.map(emojies, & &1[:path])}, {:cwd, String.to_charlist(tmp_dir)}]
)
{_, updated_pack} =
diff --git a/lib/pleroma/filter.ex b/lib/pleroma/filter.ex
@@ -216,9 +216,6 @@ defmodule Pleroma.Filter do
:re ->
~r/\b#{phrases}\b/i
-
- _ ->
- nil
end
end
diff --git a/lib/pleroma/gun/connection_pool/worker_supervisor.ex b/lib/pleroma/gun/connection_pool/worker_supervisor.ex
@@ -21,7 +21,9 @@ defmodule Pleroma.Gun.ConnectionPool.WorkerSupervisor do
def start_worker(opts, retry \\ false) do
case DynamicSupervisor.start_child(__MODULE__, {Pleroma.Gun.ConnectionPool.Worker, opts}) do
{:error, :max_children} ->
- if Enum.any?([retry, free_pool()], &match?(&1, :error)) do
+ funs = [fn -> !retry end, fn -> match?(:error, free_pool()) end]
+
+ if Enum.any?(funs, fn fun -> fun.() end) do
:telemetry.execute([:pleroma, :connection_pool, :provision_failure], %{opts: opts})
{:error, :pool_full}
else
diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex
@@ -6,8 +6,6 @@ defmodule Pleroma.HTML do
# Scrubbers are compiled on boot so they can be configured in OTP releases
# @on_load :compile_scrubbers
- @cachex Pleroma.Config.get([:cachex, :provider], Cachex)
-
def compile_scrubbers do
dir = Path.join(:code.priv_dir(:pleroma), "scrubbers")
@@ -67,27 +65,20 @@ defmodule Pleroma.HTML do
end
end
- def extract_first_external_url_from_object(%{data: %{"content" => content}} = object)
+ @spec extract_first_external_url_from_object(Pleroma.Object.t()) ::
+ {:ok, String.t()} | {:error, :no_content}
+ def extract_first_external_url_from_object(%{data: %{"content" => content}})
when is_binary(content) do
- unless object.data["fake"] do
- key = "URL|#{object.id}"
+ url =
+ content
+ |> Floki.parse_fragment!()
+ |> Floki.find("a:not(.mention,.hashtag,.attachment,[rel~=\"tag\"])")
+ |> Enum.take(1)
+ |> Floki.attribute("href")
+ |> Enum.at(0)
- @cachex.fetch!(:scrubber_cache, key, fn _key ->
- {:commit, {:ok, extract_first_external_url(content)}}
- end)
- else
- {:ok, extract_first_external_url(content)}
- end
+ {:ok, url}
end
def extract_first_external_url_from_object(_), do: {:error, :no_content}
-
- def extract_first_external_url(content) do
- content
- |> Floki.parse_fragment!()
- |> Floki.find("a:not(.mention,.hashtag,.attachment,[rel~=\"tag\"])")
- |> Enum.take(1)
- |> Floki.attribute("href")
- |> Enum.at(0)
- end
end
diff --git a/lib/pleroma/http/request_builder.ex b/lib/pleroma/http/request_builder.ex
@@ -54,12 +54,12 @@ defmodule Pleroma.HTTP.RequestBuilder do
@doc """
Add optional parameters to the request
"""
- @spec add_param(Request.t(), atom(), atom(), any()) :: Request.t()
+ @spec add_param(Request.t(), atom(), atom() | String.t(), any()) :: Request.t()
def add_param(request, :query, :query, values), do: %{request | query: values}
def add_param(request, :body, :body, value), do: %{request | body: value}
- def add_param(request, :body, key, value) do
+ def add_param(request, :body, key, value) when is_binary(key) do
request
|> Map.put(:body, Multipart.new())
|> Map.update!(
diff --git a/lib/pleroma/maps.ex b/lib/pleroma/maps.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Maps do
@@ -18,4 +18,17 @@ defmodule Pleroma.Maps do
rescue
_ -> data
end
+
+ def filter_empty_values(data) do
+ # TODO: Change to Map.filter in Elixir 1.13+
+ data
+ |> Enum.filter(fn
+ {_k, nil} -> false
+ {_k, ""} -> false
+ {_k, []} -> false
+ {_k, %{} = v} -> Map.keys(v) != []
+ {_k, _v} -> true
+ end)
+ |> Map.new()
+ end
end
diff --git a/lib/pleroma/mfa.ex b/lib/pleroma/mfa.ex
@@ -77,7 +77,7 @@ defmodule Pleroma.MFA do
{:ok, codes}
else
{:error, msg} ->
- %{error: msg}
+ {:error, msg}
end
end
diff --git a/lib/pleroma/mfa/totp.ex b/lib/pleroma/mfa/totp.ex
@@ -14,6 +14,7 @@ defmodule Pleroma.MFA.TOTP do
@doc """
https://github.com/google/google-authenticator/wiki/Key-Uri-Format
"""
+ @spec provisioning_uri(String.t(), String.t(), list()) :: String.t()
def provisioning_uri(secret, label, opts \\ []) do
query =
%{
@@ -27,7 +28,7 @@ defmodule Pleroma.MFA.TOTP do
|> URI.encode_query()
%URI{scheme: "otpauth", host: "totp", path: "/" <> label, query: query}
- |> URI.to_string()
+ |> to_string()
end
defp default_period, do: Config.get(@config_ns ++ [:period])
diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex
@@ -88,7 +88,7 @@ defmodule Pleroma.Notification do
where: q.seen == true,
select: type(q.id, :string),
limit: 1,
- order_by: [desc: :id]
+ order_by: fragment("? desc nulls last", q.id)
)
end
diff --git a/lib/pleroma/pagination.ex b/lib/pleroma/pagination.ex
@@ -61,15 +61,16 @@ defmodule Pleroma.Pagination do
|> Repo.all()
end
- @spec paginate(Ecto.Query.t(), map(), type(), atom() | nil) :: [Ecto.Schema.t()]
- def paginate(query, options, method \\ :keyset, table_binding \\ nil)
-
- def paginate(list, options, _method, _table_binding) when is_list(list) do
+ @spec paginate_list(list(), keyword()) :: list()
+ def paginate_list(list, options) do
offset = options[:offset] || 0
limit = options[:limit] || 0
Enum.slice(list, offset, limit)
end
+ @spec paginate(Ecto.Query.t(), map(), type(), atom() | nil) :: [Ecto.Schema.t()]
+ def paginate(query, options, method \\ :keyset, table_binding \\ nil)
+
def paginate(query, options, :keyset, table_binding) do
query
|> restrict(:min_id, options, table_binding)
diff --git a/lib/pleroma/password/pbkdf2.ex b/lib/pleroma/password/pbkdf2.ex
@@ -28,7 +28,7 @@ defmodule Pleroma.Password.Pbkdf2 do
iterations = String.to_integer(iterations)
- digest = String.to_atom(digest)
+ digest = String.to_existing_atom(digest)
binary_hash =
KeyGenerator.generate(password, salt, digest: digest, iterations: iterations, length: 64)
diff --git a/lib/pleroma/reverse_proxy.ex b/lib/pleroma/reverse_proxy.ex
@@ -8,7 +8,7 @@ defmodule Pleroma.ReverseProxy do
~w(if-unmodified-since if-none-match) ++ @range_headers
@resp_cache_headers ~w(etag date last-modified)
@keep_resp_headers @resp_cache_headers ++
- ~w(content-length content-type content-disposition content-encoding) ++
+ ~w(content-type content-disposition content-encoding) ++
~w(content-range accept-ranges vary)
@default_cache_control_header "public, max-age=1209600"
@valid_resp_codes [200, 206, 304]
diff --git a/lib/pleroma/telemetry/logger.ex b/lib/pleroma/telemetry/logger.ex
@@ -59,7 +59,7 @@ defmodule Pleroma.Telemetry.Logger do
_,
_
) do
- Logger.error(fn ->
+ Logger.debug(fn ->
"Connection pool had to refuse opening a connection to #{key} due to connection limit exhaustion"
end)
end
@@ -81,7 +81,7 @@ defmodule Pleroma.Telemetry.Logger do
%{key: key, protocol: :http},
_
) do
- Logger.info(fn ->
+ Logger.debug(fn ->
"Pool worker for #{key}: #{length(clients)} clients are using an HTTP1 connection at the same time, head-of-line blocking might occur."
end)
end
diff --git a/lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex b/lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex
@@ -36,6 +36,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy do
extension = if extension == "", do: ".png", else: extension
+ shortcode = Path.basename(shortcode)
file_path = Path.join(emoji_dir_path, shortcode <> extension)
case File.write(file_path, response.body) do
@@ -78,6 +79,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy do
new_emojis =
foreign_emojis
|> Enum.reject(fn {shortcode, _url} -> shortcode in installed_emoji end)
+ |> Enum.reject(fn {shortcode, _url} -> String.contains?(shortcode, ["/", "\\"]) end)
|> Enum.filter(fn {shortcode, _url} ->
reject_emoji? =
[:mrf_steal_emoji, :rejected_shortcodes]
diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex
@@ -4,6 +4,7 @@
defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
alias Pleroma.EctoType.ActivityPub.ObjectValidators
+ alias Pleroma.Maps
alias Pleroma.Object
alias Pleroma.Object.Containment
alias Pleroma.User
@@ -29,6 +30,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
end
def fix_object_defaults(data) do
+ data = Maps.filter_empty_values(data)
+
context =
Utils.maybe_create_context(
data["context"] || data["conversation"] || data["inReplyTo"] || data["id"]
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -337,6 +337,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def fix_tag(object), do: object
+ # prefer content over contentMap
def fix_content_map(%{"content" => content} = object) when not_empty_string(content), do: object
# content map usually only has one language so this will do for now.
diff --git a/lib/pleroma/web/controller_helper.ex b/lib/pleroma/web/controller_helper.ex
@@ -20,7 +20,7 @@ defmodule Pleroma.Web.ControllerHelper do
|> json(json)
end
- @spec fetch_integer_param(map(), String.t(), integer() | nil) :: integer() | nil
+ @spec fetch_integer_param(map(), String.t() | atom(), integer() | nil) :: integer() | nil
def fetch_integer_param(params, name, default \\ nil) do
params
|> Map.get(name, default)
diff --git a/lib/pleroma/web/embed_controller.ex b/lib/pleroma/web/embed_controller.ex
@@ -11,8 +11,6 @@ defmodule Pleroma.Web.EmbedController do
alias Pleroma.Web.ActivityPub.Visibility
- plug(:put_layout, :embed)
-
def show(conn, %{"id" => id}) do
with %Activity{local: true} = activity <-
Activity.get_by_id_with_object(id),
diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex
@@ -9,6 +9,16 @@ defmodule Pleroma.Web.Endpoint do
alias Pleroma.Config
+ socket("/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler,
+ longpoll: false,
+ websocket: [
+ path: "/",
+ compress: false,
+ error_handler: {Pleroma.Web.MastodonAPI.WebsocketHandler, :handle_error, []},
+ fullsweep_after: 20
+ ]
+ )
+
socket("/socket", Pleroma.Web.UserSocket,
websocket: [
path: "/websocket",
@@ -18,7 +28,8 @@ defmodule Pleroma.Web.Endpoint do
],
timeout: 60_000,
transport_log: false,
- compress: false
+ compress: false,
+ fullsweep_after: 20
],
longpoll: false
)
@@ -32,7 +43,8 @@ defmodule Pleroma.Web.Endpoint do
plug(Pleroma.Web.Plugs.HTTPSecurityPlug)
plug(Pleroma.Web.Plugs.UploadedMedia)
- @static_cache_control "public, no-cache"
+ @static_cache_control "public, max-age=1209600"
+ @static_cache_disabled "public, no-cache"
# InstanceStatic needs to be before Plug.Static to be able to override shipped-static files
# If you're adding new paths to `only:` you'll need to configure them in InstanceStatic as well
@@ -43,22 +55,32 @@ defmodule Pleroma.Web.Endpoint do
from: :pleroma,
only: ["emoji", "images"],
gzip: true,
- cache_control_for_etags: "public, max-age=1209600",
+ cache_control_for_etags: @static_cache_control,
headers: %{
- "cache-control" => "public, max-age=1209600"
+ "cache-control" => @static_cache_control
}
)
plug(Pleroma.Web.Plugs.InstanceStatic,
at: "/",
gzip: true,
- cache_control_for_etags: @static_cache_control,
+ cache_control_for_etags: @static_cache_disabled,
headers: %{
- "cache-control" => @static_cache_control
+ "cache-control" => @static_cache_disabled
+ }
+ )
+
+ plug(Pleroma.Web.Plugs.FrontendStatic,
+ at: "/",
+ frontend_type: :primary,
+ only: ["index.html"],
+ gzip: true,
+ cache_control_for_etags: @static_cache_disabled,
+ headers: %{
+ "cache-control" => @static_cache_disabled
}
)
- # Careful! No `only` restriction here, as we don't know what frontends contain.
plug(Pleroma.Web.Plugs.FrontendStatic,
at: "/",
frontend_type: :primary,
@@ -75,9 +97,9 @@ defmodule Pleroma.Web.Endpoint do
at: "/pleroma/admin",
frontend_type: :admin,
gzip: true,
- cache_control_for_etags: @static_cache_control,
+ cache_control_for_etags: @static_cache_disabled,
headers: %{
- "cache-control" => @static_cache_control
+ "cache-control" => @static_cache_disabled
}
)
@@ -92,9 +114,9 @@ defmodule Pleroma.Web.Endpoint do
only: Pleroma.Constants.static_only_files(),
# credo:disable-for-previous-line Credo.Check.Readability.MaxLineLength
gzip: true,
- cache_control_for_etags: @static_cache_control,
+ cache_control_for_etags: @static_cache_disabled,
headers: %{
- "cache-control" => @static_cache_control
+ "cache-control" => @static_cache_disabled
}
)
diff --git a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex
@@ -156,7 +156,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
tags
end
- Pleroma.Pagination.paginate(tags, options)
+ Pleroma.Pagination.paginate_list(tags, options)
end
defp add_joined_tag(tags) do
diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex
@@ -11,28 +11,21 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
alias Pleroma.Web.Streamer
alias Pleroma.Web.StreamerView
- @behaviour :cowboy_websocket
+ @behaviour Phoenix.Socket.Transport
# Client ping period.
@tick :timer.seconds(30)
- # Cowboy timeout period.
- @timeout :timer.seconds(60)
- # Hibernate every X messages
- @hibernate_every 100
-
- def init(%{qs: qs} = req, state) do
- with params <- Enum.into(:cow_qs.parse_qs(qs), %{}),
- sec_websocket <- :cowboy_req.header("sec-websocket-protocol", req, nil),
- access_token <- Map.get(params, "access_token"),
- {:ok, user, oauth_token} <- authenticate_request(access_token, sec_websocket),
- {:ok, topic} <- Streamer.get_topic(params["stream"], user, oauth_token, params) do
- req =
- if sec_websocket do
- :cowboy_req.set_resp_header("sec-websocket-protocol", sec_websocket, req)
- else
- req
- end
+ @impl Phoenix.Socket.Transport
+ def child_spec(_opts), do: :ignore
+
+ # This only prepares the connection and is not in the process yet
+ @impl Phoenix.Socket.Transport
+ def connect(%{params: params} = transport_info) do
+ with access_token <- Map.get(params, "access_token"),
+ {:ok, user, oauth_token} <- authenticate_request(access_token),
+ {:ok, topic} <-
+ Streamer.get_topic(params["stream"], user, oauth_token, params) do
topics =
if topic do
[topic]
@@ -40,41 +33,40 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
[]
end
- {:cowboy_websocket, req,
- %{user: user, topics: topics, oauth_token: oauth_token, count: 0, timer: nil},
- %{idle_timeout: @timeout}}
+ state = %{
+ user: user,
+ topics: topics,
+ oauth_token: oauth_token,
+ count: 0,
+ timer: nil
+ }
+
+ {:ok, state}
else
{:error, :bad_topic} ->
- Logger.debug("#{__MODULE__} bad topic #{inspect(req)}")
- req = :cowboy_req.reply(404, req)
- {:ok, req, state}
+ Logger.debug("#{__MODULE__} bad topic #{inspect(transport_info)}")
+
+ {:error, :bad_topic}
{:error, :unauthorized} ->
- Logger.debug("#{__MODULE__} authentication error: #{inspect(req)}")
- req = :cowboy_req.reply(401, req)
- {:ok, req, state}
+ Logger.debug("#{__MODULE__} authentication error: #{inspect(transport_info)}")
+ {:error, :unauthorized}
end
end
- def websocket_init(state) do
- Logger.debug(
- "#{__MODULE__} accepted websocket connection for user #{(state.user || %{id: "anonymous"}).id}, topics #{state.topics}"
- )
-
+ # All subscriptions/links and messages cannot be created
+ # until the processed is launched with init/1
+ @impl Phoenix.Socket.Transport
+ def init(state) do
Enum.each(state.topics, fn topic -> Streamer.add_socket(topic, state.oauth_token) end)
- {:ok, %{state | timer: timer()}}
- end
- # Client's Pong frame.
- def websocket_handle(:pong, state) do
- if state.timer, do: Process.cancel_timer(state.timer)
- {:ok, %{state | timer: timer()}}
- end
+ Process.send_after(self(), :ping, @tick)
- # We only receive pings for now
- def websocket_handle(:ping, state), do: {:ok, state}
+ {:ok, state}
+ end
- def websocket_handle({:text, text}, state) do
+ @impl Phoenix.Socket.Transport
+ def handle_in({text, [opcode: :text]}, state) do
with {:ok, %{} = event} <- Jason.decode(text) do
handle_client_event(event, state)
else
@@ -84,50 +76,47 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
end
end
- def websocket_handle(frame, state) do
+ def handle_in(frame, state) do
Logger.error("#{__MODULE__} received frame: #{inspect(frame)}")
{:ok, state}
end
- def websocket_info({:render_with_user, view, template, item, topic}, state) do
+ @impl Phoenix.Socket.Transport
+ def handle_info({:render_with_user, view, template, item, topic}, state) do
user = %User{} = User.get_cached_by_ap_id(state.user.ap_id)
unless Streamer.filtered_by_user?(user, item) do
- websocket_info({:text, view.render(template, item, user, topic)}, %{state | user: user})
+ message = view.render(template, item, user, topic)
+ {:push, {:text, message}, %{state | user: user}}
else
{:ok, state}
end
end
- def websocket_info({:text, message}, state) do
- # If the websocket processed X messages, force an hibernate/GC.
- # We don't hibernate at every message to balance CPU usage/latency with RAM usage.
- if state.count > @hibernate_every do
- {:reply, {:text, message}, %{state | count: 0}, :hibernate}
- else
- {:reply, {:text, message}, %{state | count: state.count + 1}}
- end
+ def handle_info({:text, text}, state) do
+ {:push, {:text, text}, state}
end
- # Ping tick. We don't re-queue a timer there, it is instead queued when :pong is received.
- # As we hibernate there, reset the count to 0.
- # If the client misses :pong, Cowboy will automatically timeout the connection after
- # `@idle_timeout`.
- def websocket_info(:tick, state) do
- {:reply, :ping, %{state | timer: nil, count: 0}, :hibernate}
+ def handle_info(:ping, state) do
+ Process.send_after(self(), :ping, @tick)
+
+ {:push, {:ping, ""}, state}
end
- def websocket_info(:close, state) do
- {:stop, state}
+ def handle_info(:close, state) do
+ {:stop, {:closed, 'connection closed by server'}, state}
end
- # State can be `[]` only in case we terminate before switching to websocket,
- # we already log errors for these cases in `init/1`, so just do nothing here
- def terminate(_reason, _req, []), do: :ok
+ def handle_info(msg, state) do
+ Logger.debug("#{__MODULE__} received info: #{inspect(msg)}")
- def terminate(reason, _req, state) do
+ {:ok, state}
+ end
+
+ @impl Phoenix.Socket.Transport
+ def terminate(reason, state) do
Logger.debug(
- "#{__MODULE__} terminating websocket connection for user #{(state.user || %{id: "anonymous"}).id}, topics #{state.topics || "?"}: #{inspect(reason)}"
+ "#{__MODULE__} terminating websocket connection for user #{(state.user || %{id: "anonymous"}).id}, topics #{state.topics || "?"}: #{inspect(reason)})"
)
Enum.each(state.topics, fn topic -> Streamer.remove_socket(topic) end)
@@ -135,16 +124,13 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
end
# Public streams without authentication.
- defp authenticate_request(nil, nil) do
+ defp authenticate_request(nil) do
{:ok, nil, nil}
end
# Authenticated streams.
- defp authenticate_request(access_token, sec_websocket) do
- token = access_token || sec_websocket
-
- with true <- is_bitstring(token),
- oauth_token = %Token{user_id: user_id} <- Repo.get_by(Token, token: token),
+ defp authenticate_request(access_token) do
+ with oauth_token = %Token{user_id: user_id} <- Repo.get_by(Token, token: access_token),
user = %User{} <- User.get_cached_by_id(user_id) do
{:ok, user, oauth_token}
else
@@ -152,36 +138,32 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
end
end
- defp timer do
- Process.send_after(self(), :tick, @tick)
- end
-
defp handle_client_event(%{"type" => "subscribe", "stream" => _topic} = params, state) do
with {_, {:ok, topic}} <-
{:topic, Streamer.get_topic(params["stream"], state.user, state.oauth_token, params)},
{_, false} <- {:subscribed, topic in state.topics} do
Streamer.add_socket(topic, state.oauth_token)
- {[
- {:text,
- StreamerView.render("pleroma_respond.json", %{type: "subscribe", result: "success"})}
- ], %{state | topics: [topic | state.topics]}}
+ message =
+ StreamerView.render("pleroma_respond.json", %{type: "subscribe", result: "success"})
+
+ {:reply, :ok, {:text, message}, %{state | topics: [topic | state.topics]}}
else
{:subscribed, true} ->
- {[
- {:text,
- StreamerView.render("pleroma_respond.json", %{type: "subscribe", result: "ignored"})}
- ], state}
+ message =
+ StreamerView.render("pleroma_respond.json", %{type: "subscribe", result: "ignored"})
+
+ {:reply, :error, {:text, message}, state}
{:topic, {:error, error}} ->
- {[
- {:text,
- StreamerView.render("pleroma_respond.json", %{
- type: "subscribe",
- result: "error",
- error: error
- })}
- ], state}
+ message =
+ StreamerView.render("pleroma_respond.json", %{
+ type: "subscribe",
+ result: "error",
+ error: error
+ })
+
+ {:reply, :error, {:text, message}, state}
end
end
@@ -191,26 +173,26 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
{_, true} <- {:subscribed, topic in state.topics} do
Streamer.remove_socket(topic)
- {[
- {:text,
- StreamerView.render("pleroma_respond.json", %{type: "unsubscribe", result: "success"})}
- ], %{state | topics: List.delete(state.topics, topic)}}
+ message =
+ StreamerView.render("pleroma_respond.json", %{type: "unsubscribe", result: "success"})
+
+ {:reply, :ok, {:text, message}, %{state | topics: List.delete(state.topics, topic)}}
else
{:subscribed, false} ->
- {[
- {:text,
- StreamerView.render("pleroma_respond.json", %{type: "unsubscribe", result: "ignored"})}
- ], state}
+ message =
+ StreamerView.render("pleroma_respond.json", %{type: "unsubscribe", result: "ignored"})
+
+ {:reply, :error, {:text, message}, state}
{:topic, {:error, error}} ->
- {[
- {:text,
- StreamerView.render("pleroma_respond.json", %{
- type: "unsubscribe",
- result: "error",
- error: error
- })}
- ], state}
+ message =
+ StreamerView.render("pleroma_respond.json", %{
+ type: "unsubscribe",
+ result: "error",
+ error: error
+ })
+
+ {:reply, :error, {:text, message}, state}
end
end
@@ -219,39 +201,47 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
state
) do
with {:auth, nil, nil} <- {:auth, state.user, state.oauth_token},
- {:ok, user, oauth_token} <- authenticate_request(access_token, nil) do
- {[
- {:text,
- StreamerView.render("pleroma_respond.json", %{
- type: "pleroma:authenticate",
- result: "success"
- })}
- ], %{state | user: user, oauth_token: oauth_token}}
+ {:ok, user, oauth_token} <- authenticate_request(access_token) do
+ message =
+ StreamerView.render("pleroma_respond.json", %{
+ type: "pleroma:authenticate",
+ result: "success"
+ })
+
+ {:reply, :ok, {:text, message}, %{state | user: user, oauth_token: oauth_token}}
else
{:auth, _, _} ->
- {[
- {:text,
- StreamerView.render("pleroma_respond.json", %{
- type: "pleroma:authenticate",
- result: "error",
- error: :already_authenticated
- })}
- ], state}
+ message =
+ StreamerView.render("pleroma_respond.json", %{
+ type: "pleroma:authenticate",
+ result: "error",
+ error: :already_authenticated
+ })
+
+ {:reply, :error, {:text, message}, state}
_ ->
- {[
- {:text,
- StreamerView.render("pleroma_respond.json", %{
- type: "pleroma:authenticate",
- result: "error",
- error: :unauthorized
- })}
- ], state}
+ message =
+ StreamerView.render("pleroma_respond.json", %{
+ type: "pleroma:authenticate",
+ result: "error",
+ error: :unauthorized
+ })
+
+ {:reply, :error, {:text, message}, state}
end
end
defp handle_client_event(params, state) do
Logger.error("#{__MODULE__} received unknown event: #{inspect(params)}")
- {[], state}
+ {:ok, state}
+ end
+
+ def handle_error(conn, :unauthorized) do
+ Plug.Conn.send_resp(conn, 401, "Unauthorized")
+ end
+
+ def handle_error(conn, _reason) do
+ Plug.Conn.send_resp(conn, 404, "Not Found")
end
end
diff --git a/lib/pleroma/web/o_auth/o_auth_controller.ex b/lib/pleroma/web/o_auth/o_auth_controller.ex
@@ -610,13 +610,8 @@ defmodule Pleroma.Web.OAuth.OAuthController do
end
end
- @spec validate_scopes(App.t(), map() | list()) ::
+ @spec validate_scopes(App.t(), list()) ::
{:ok, list()} | {:error, :missing_scopes | :unsupported_scopes}
- defp validate_scopes(%App{} = app, params) when is_map(params) do
- requested_scopes = Scopes.fetch_scopes(params, app.scopes)
- validate_scopes(app, requested_scopes)
- end
-
defp validate_scopes(%App{} = app, requested_scopes) when is_list(requested_scopes) do
Scopes.validate(requested_scopes, app.scopes)
end
diff --git a/lib/pleroma/web/o_status/o_status_controller.ex b/lib/pleroma/web/o_status/o_status_controller.ex
@@ -112,7 +112,6 @@ defmodule Pleroma.Web.OStatus.OStatusController do
%{data: %{"attachment" => [%{"url" => [url | _]} | _]}} <- object,
true <- String.starts_with?(url["mediaType"], ["audio", "video"]) do
conn
- |> put_layout(:metadata_player)
|> put_resp_header("x-frame-options", "ALLOW")
|> put_resp_header(
"content-security-policy",
diff --git a/lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex b/lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex
@@ -28,7 +28,7 @@ defmodule Pleroma.Web.PleromaAPI.MascotController do
_
) do
with {:content_type, "image" <> _} <- {:content_type, file.content_type},
- {:ok, object} <- ActivityPub.upload(file, actor: User.ap_id(user)) do
+ {_, {:ok, object}} <- {:upload, ActivityPub.upload(file, actor: User.ap_id(user))} do
attachment = render_attachment(object)
{:ok, _user} = User.mascot_update(user, attachment)
diff --git a/lib/pleroma/web/plugs/rate_limiter/supervisor.ex b/lib/pleroma/web/plugs/rate_limiter/supervisor.ex
@@ -14,7 +14,7 @@ defmodule Pleroma.Web.Plugs.RateLimiter.Supervisor do
Pleroma.Web.Plugs.RateLimiter.LimiterSupervisor
]
- opts = [strategy: :one_for_one, name: Pleroma.Web.Streamer.Supervisor]
+ opts = [strategy: :one_for_one]
Supervisor.init(children, opts)
end
end
diff --git a/lib/pleroma/web/rich_media/helpers.ex b/lib/pleroma/web/rich_media/helpers.ex
@@ -8,6 +8,8 @@ defmodule Pleroma.Web.RichMedia.Helpers do
alias Pleroma.Object
alias Pleroma.Web.RichMedia.Parser
+ @cachex Pleroma.Config.get([:cachex, :provider], Cachex)
+
@config_impl Application.compile_env(:pleroma, [__MODULE__, :config_impl], Pleroma.Config)
@options [
@@ -16,51 +18,10 @@ defmodule Pleroma.Web.RichMedia.Helpers do
recv_timeout: 2_000
]
- @spec validate_page_url(URI.t() | binary()) :: :ok | :error
- defp validate_page_url(page_url) when is_binary(page_url) do
- validate_tld = @config_impl.get([Pleroma.Formatter, :validate_tld])
-
- page_url
- |> Linkify.Parser.url?(validate_tld: validate_tld)
- |> parse_uri(page_url)
- end
-
- defp validate_page_url(%URI{host: host, scheme: "https", authority: authority})
- when is_binary(authority) do
- cond do
- host in @config_impl.get([:rich_media, :ignore_hosts], []) ->
- :error
-
- get_tld(host) in @config_impl.get([:rich_media, :ignore_tld], []) ->
- :error
-
- true ->
- :ok
- end
- end
-
- defp validate_page_url(_), do: :error
-
- defp parse_uri(true, url) do
- url
- |> URI.parse()
- |> validate_page_url
- end
-
- defp parse_uri(_, _), do: :error
-
- defp get_tld(host) do
- host
- |> String.split(".")
- |> Enum.reverse()
- |> hd
- end
-
def fetch_data_for_object(object) do
with true <- @config_impl.get([:rich_media, :enabled]),
{:ok, page_url} <-
HTML.extract_first_external_url_from_object(object),
- :ok <- validate_page_url(page_url),
{:ok, rich_media} <- Parser.parse(page_url) do
%{page_url: page_url, rich_media: rich_media}
else
@@ -71,7 +32,24 @@ defmodule Pleroma.Web.RichMedia.Helpers do
def fetch_data_for_activity(%Activity{data: %{"type" => "Create"}} = activity) do
with true <- @config_impl.get([:rich_media, :enabled]),
%Object{} = object <- Object.normalize(activity, fetch: false) do
- fetch_data_for_object(object)
+ if object.data["fake"] do
+ fetch_data_for_object(object)
+ else
+ key = "URL|#{activity.id}"
+
+ @cachex.fetch!(:scrubber_cache, key, fn _ ->
+ result = fetch_data_for_object(object)
+
+ cond do
+ match?(%{page_url: _, rich_media: _}, result) ->
+ Activity.HTML.add_cache_key_for(activity.id, key)
+ {:commit, result}
+
+ true ->
+ {:ignore, %{}}
+ end
+ end)
+ end
else
_ -> %{}
end
diff --git a/lib/pleroma/web/rich_media/parser.ex b/lib/pleroma/web/rich_media/parser.ex
@@ -6,6 +6,7 @@ defmodule Pleroma.Web.RichMedia.Parser do
require Logger
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
+ @config_impl Application.compile_env(:pleroma, [__MODULE__, :config_impl], Pleroma.Config)
defp parsers do
Pleroma.Config.get([:rich_media, :parsers])
@@ -13,70 +14,66 @@ defmodule Pleroma.Web.RichMedia.Parser do
def parse(nil), do: {:error, "No URL provided"}
- if Pleroma.Config.get(:env) == :test do
- @spec parse(String.t()) :: {:ok, map()} | {:error, any()}
- def parse(url), do: parse_url(url)
- else
- @spec parse(String.t()) :: {:ok, map()} | {:error, any()}
- def parse(url) do
- with {:ok, data} <- get_cached_or_parse(url),
- {:ok, _} <- set_ttl_based_on_image(data, url) do
- {:ok, data}
- end
+ @spec parse(String.t()) :: {:ok, map()} | {:error, any()}
+ def parse(url) do
+ with :ok <- validate_page_url(url),
+ {:ok, data} <- get_cached_or_parse(url),
+ {:ok, _} <- set_ttl_based_on_image(data, url) do
+ {:ok, data}
end
+ end
- defp get_cached_or_parse(url) do
- case @cachex.fetch(:rich_media_cache, url, fn ->
- case parse_url(url) do
- {:ok, _} = res ->
- {:commit, res}
-
- {:error, reason} = e ->
- # Unfortunately we have to log errors here, instead of doing that
- # along with ttl setting at the bottom. Otherwise we can get log spam
- # if more than one process was waiting for the rich media card
- # while it was generated. Ideally we would set ttl here as well,
- # so we don't override it number_of_waiters_on_generation
- # times, but one, obviously, can't set ttl for not-yet-created entry
- # and Cachex doesn't support returning ttl from the fetch callback.
- log_error(url, reason)
- {:commit, e}
- end
- end) do
- {action, res} when action in [:commit, :ok] ->
- case res do
- {:ok, _data} = res ->
- res
-
- {:error, reason} = e ->
- if action == :commit, do: set_error_ttl(url, reason)
- e
- end
-
- {:error, e} ->
- {:error, {:cachex_error, e}}
- end
+ defp get_cached_or_parse(url) do
+ case @cachex.fetch(:rich_media_cache, url, fn ->
+ case parse_url(url) do
+ {:ok, _} = res ->
+ {:commit, res}
+
+ {:error, reason} = e ->
+ # Unfortunately we have to log errors here, instead of doing that
+ # along with ttl setting at the bottom. Otherwise we can get log spam
+ # if more than one process was waiting for the rich media card
+ # while it was generated. Ideally we would set ttl here as well,
+ # so we don't override it number_of_waiters_on_generation
+ # times, but one, obviously, can't set ttl for not-yet-created entry
+ # and Cachex doesn't support returning ttl from the fetch callback.
+ log_error(url, reason)
+ {:commit, e}
+ end
+ end) do
+ {action, res} when action in [:commit, :ok] ->
+ case res do
+ {:ok, _data} = res ->
+ res
+
+ {:error, reason} = e ->
+ if action == :commit, do: set_error_ttl(url, reason)
+ e
+ end
+
+ {:error, e} ->
+ {:error, {:cachex_error, e}}
end
+ end
- defp set_error_ttl(_url, :body_too_large), do: :ok
- defp set_error_ttl(_url, {:content_type, _}), do: :ok
+ defp set_error_ttl(_url, :body_too_large), do: :ok
+ defp set_error_ttl(_url, {:content_type, _}), do: :ok
- # The TTL is not set for the errors above, since they are unlikely to change
- # with time
+ # The TTL is not set for the errors above, since they are unlikely to change
+ # with time
- defp set_error_ttl(url, _reason) do
- ttl = Pleroma.Config.get([:rich_media, :failure_backoff], 60_000)
- @cachex.expire(:rich_media_cache, url, ttl)
- :ok
- end
+ defp set_error_ttl(url, _reason) do
+ ttl = Pleroma.Config.get([:rich_media, :failure_backoff], 60_000)
+ @cachex.expire(:rich_media_cache, url, ttl)
+ :ok
+ end
- defp log_error(url, {:invalid_metadata, data}) do
- Logger.debug(fn -> "Incomplete or invalid metadata for #{url}: #{inspect(data)}" end)
- end
+ defp log_error(url, {:invalid_metadata, data}) do
+ Logger.debug(fn -> "Incomplete or invalid metadata for #{url}: #{inspect(data)}" end)
+ end
- defp log_error(url, reason) do
- Logger.warning(fn -> "Rich media error for #{url}: #{inspect(reason)}" end)
- end
+ defp log_error(url, reason) do
+ Logger.warning(fn -> "Rich media error for #{url}: #{inspect(reason)}" end)
end
@doc """
@@ -166,4 +163,46 @@ defmodule Pleroma.Web.RichMedia.Parser do
end)
|> Map.new()
end
+
+ @spec validate_page_url(URI.t() | binary()) :: :ok | :error
+ defp validate_page_url(page_url) when is_binary(page_url) do
+ validate_tld = @config_impl.get([Pleroma.Formatter, :validate_tld])
+
+ page_url
+ |> Linkify.Parser.url?(validate_tld: validate_tld)
+ |> parse_uri(page_url)
+ end
+
+ defp validate_page_url(%URI{host: host, scheme: "https"}) do
+ cond do
+ Linkify.Parser.ip?(host) ->
+ :error
+
+ host in @config_impl.get([:rich_media, :ignore_hosts], []) ->
+ :error
+
+ get_tld(host) in @config_impl.get([:rich_media, :ignore_tld], []) ->
+ :error
+
+ true ->
+ :ok
+ end
+ end
+
+ defp validate_page_url(_), do: :error
+
+ defp parse_uri(true, url) do
+ url
+ |> URI.parse()
+ |> validate_page_url
+ end
+
+ defp parse_uri(_, _), do: :error
+
+ defp get_tld(host) do
+ host
+ |> String.split(".")
+ |> Enum.reverse()
+ |> hd
+ end
end
diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex
@@ -13,7 +13,6 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do
alias Pleroma.Web.Metadata
alias Pleroma.Web.Router.Helpers
- plug(:put_layout, :static_fe)
plug(:assign_id)
@page_keys ["max_id", "min_id", "limit", "since_id", "order"]
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
@@ -13,7 +13,7 @@
<div class="account-header__avatar" style="background-image: url('<%= Pleroma.User.avatar_url(@user) %>')"></div>
<div class="account-header__meta">
<div class="account-header__display-name"><%= @user.name %></div>
- <div class="account-header__nickname">@<%= @user.nickname %>@<%= Pleroma.User.get_host(@user) %></div>
+ <div class="account-header__nickname">@<%= Pleroma.User.full_nickname(@user.nickname) %></div>
</div>
</div>
<% end %>
diff --git a/lib/pleroma/workers/background_worker.ex b/lib/pleroma/workers/background_worker.ex
@@ -28,7 +28,7 @@ defmodule Pleroma.Workers.BackgroundWorker do
def perform(%Job{args: %{"op" => op, "user_id" => user_id, "identifiers" => identifiers}})
when op in ["blocks_import", "follow_import", "mutes_import"] do
user = User.get_cached_by_id(user_id)
- {:ok, User.Import.perform(String.to_atom(op), user, identifiers)}
+ {:ok, User.Import.perform(String.to_existing_atom(op), user, identifiers)}
end
def perform(%Job{
diff --git a/mix.exs b/mix.exs
@@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do
def project do
[
app: :pleroma,
- version: version("2.6.51"),
+ version: version("2.6.52"),
elixir: "~> 1.11",
elixirc_paths: elixirc_paths(Mix.env()),
compilers: Mix.compilers(),
@@ -137,7 +137,7 @@ defmodule Pleroma.Mixfile do
{:calendar, "~> 1.0"},
{:cachex, "~> 3.2"},
{:poison, "~> 3.0", override: true},
- {:tesla, "~> 1.4.0", override: true},
+ {:tesla, "~> 1.8.0"},
{:castore, "~> 0.1"},
{:cowlib, "~> 2.9", override: true},
{:gun, "~> 2.0.0-rc.1", override: true},
@@ -188,6 +188,7 @@ defmodule Pleroma.Mixfile do
{:exile,
git: "https://git.pleroma.social/pleroma/elixir-libraries/exile.git",
ref: "0d6337cf68e7fbc8a093cae000955aa93b067f91"},
+ {:bandit, "~> 1.2"},
## dev & test
{:ex_doc, "~> 0.22", only: :dev, runtime: false},
diff --git a/mix.lock b/mix.lock
@@ -1,5 +1,6 @@
%{
"accept": {:hex, :accept, "0.3.5", "b33b127abca7cc948bbe6caa4c263369abf1347cfa9d8e699c6d214660f10cd1", [:rebar3], [], "hexpm", "11b18c220bcc2eab63b5470c038ef10eb6783bcb1fcdb11aa4137defa5ac1bb8"},
+ "bandit": {:hex, :bandit, "1.2.1", "aa485b4ac175065b8e0fb5864ddd5dd7b50d52336b36f61c82f484c3718b3d15", [:mix], [{:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "27393e590a407f1b7d51c5fee4737f139fe224a30449ce25061eac70f763896b"},
"base62": {:hex, :base62, "1.2.2", "85c6627eb609317b70f555294045895ffaaeb1758666ab9ef9ca38865b11e629", [:mix], [{:custom_base, "~> 0.2.1", [hex: :custom_base, repo: "hexpm", optional: false]}], "hexpm", "d41336bda8eaa5be197f1e4592400513ee60518e5b9f4dcf38f4b4dae6f377bb"},
"bbcode_pleroma": {:hex, :bbcode_pleroma, "0.2.0", "d36f5bca6e2f62261c45be30fa9b92725c0655ad45c99025cb1c3e28e25803ef", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "19851074419a5fedb4ef49e1f01b30df504bb5dbb6d6adfc135238063bebd1c3"},
"bcrypt_elixir": {:hex, :bcrypt_elixir, "2.3.1", "5114d780459a04f2b4aeef52307de23de961b69e13a5cd98a911e39fda13f420", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "42182d5f46764def15bf9af83739e3bf4ad22661b1c34fc3e88558efced07279"},
@@ -51,7 +52,7 @@
"fast_html": {:hex, :fast_html, "2.2.0", "6c5ef1be087a4ed613b0379c13f815c4d11742b36b67bb52cee7859847c84520", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "064c4f23b4a6168f9187dac8984b056f2c531bb0787f559fd6a8b34b38aefbae"},
"fast_sanitize": {:hex, :fast_sanitize, "0.2.3", "67b93dfb34e302bef49fec3aaab74951e0f0602fd9fa99085987af05bd91c7a5", [:mix], [{:fast_html, "~> 2.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "e8ad286d10d0386e15d67d0ee125245ebcfbc7d7290b08712ba9013c8c5e56e2"},
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
- "finch": {:hex, :finch, "0.17.0", "17d06e1d44d891d20dbd437335eebe844e2426a0cd7e3a3e220b461127c73f70", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "8d014a661bb6a437263d4b5abf0bcbd3cf0deb26b1e8596f2a271d22e48934c7"},
+ "finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"},
"flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "31fc8090fde1acd267c07c36ea7365b8604055f897d3a53dd967658c691bd827"},
"floki": {:hex, :floki, "0.35.2", "87f8c75ed8654b9635b311774308b2760b47e9a579dabf2e4d5f1e1d42c39e0b", [:mix], [], "hexpm", "6b05289a8e9eac475f644f09c2e4ba7e19201fd002b89c28c1293e7bd16773d9"},
"gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm", "29bd14a88030980849c7ed2447b8db6d6c9278a28b11a44cafe41b791205440f"},
@@ -132,7 +133,8 @@
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.2", "2caabe9344ec17eafe5403304771c3539f3b6e2f7fb6a6f602558c825d0d0bfb", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9b43db0dc33863930b9ef9d27137e78974756f5f198cae18409970ed6fa5b561"},
"telemetry_metrics_prometheus_core": {:hex, :telemetry_metrics_prometheus_core, "1.2.0", "b583c3f18508f5c5561b674d16cf5d9afd2ea3c04505b7d92baaeac93c1b8260", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "9cba950e1c4733468efbe3f821841f34ac05d28e7af7798622f88ecdbbe63ea3"},
"telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"},
- "tesla": {:hex, :tesla, "1.4.4", "bb89aa0c9745190930366f6a2ac612cdf2d0e4d7fff449861baa7875afd797b2", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.3", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "d5503a49f9dec1b287567ea8712d085947e247cb11b06bc54adb05bfde466457"},
+ "tesla": {:hex, :tesla, "1.8.0", "d511a4f5c5e42538d97eef7c40ec4f3e44effdc5068206f42ed859e09e51d1fd", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, ">= 1.0.0", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.2", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "10501f360cd926a309501287470372af1a6e1cbed0f43949203a4c13300bc79f"},
+ "thousand_island": {:hex, :thousand_island, "1.3.2", "bc27f9afba6e1a676dd36507d42e429935a142cf5ee69b8e3f90bff1383943cd", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "0e085b93012cd1057b378fce40cbfbf381ff6d957a382bfdd5eca1a98eec2535"},
"timex": {:hex, :timex, "3.7.7", "3ed093cae596a410759104d878ad7b38e78b7c2151c6190340835515d4a46b8a", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "0ec4b09f25fe311321f9fc04144a7e3affe48eb29481d7a5583849b6c4dfa0a7"},
"toml": {:hex, :toml, "0.7.0", "fbcd773caa937d0c7a02c301a1feea25612720ac3fa1ccb8bfd9d30d822911de", [:mix], [], "hexpm", "0690246a2478c1defd100b0c9b89b4ea280a22be9a7b313a8a058a2408a2fa70"},
"trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bd4fde4c15f3e993a999e019d64347489b91b7a9096af68b2bdadd192afa693f"},
diff --git a/priv/gettext/ja/LC_MESSAGES/errors.po b/priv/gettext/ja/LC_MESSAGES/errors.po
@@ -3,16 +3,16 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-18 09:07+0000\n"
-"PO-Revision-Date: 2021-09-19 09:45+0000\n"
-"Last-Translator: Ryo Ueno <r.ueno.nfive@gmail.com>\n"
+"PO-Revision-Date: 2024-02-16 11:49+0000\n"
+"Last-Translator: SyoBoN <syobon@syobon.net>\n"
"Language-Team: Japanese <https://translate.pleroma.social/projects/pleroma/"
-"pleroma/ja/>\n"
+"pleroma-backend-domain-errors/ja/>\n"
"Language: ja\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.6.2\n"
+"X-Generator: Weblate 4.13.1\n"
## This file is a PO Template file.
##
@@ -25,11 +25,11 @@ msgstr ""
## effect: edit them in PO (`.po`) files instead.
## From Ecto.Changeset.cast/4
msgid "can't be blank"
-msgstr ""
+msgstr "空にすることはできません"
## From Ecto.Changeset.unique_constraint/3
msgid "has already been taken"
-msgstr ""
+msgstr "すでに使用されています"
## From Ecto.Changeset.put_change/3
msgid "is invalid"
@@ -37,7 +37,7 @@ msgstr ""
## From Ecto.Changeset.validate_format/3
msgid "has invalid format"
-msgstr ""
+msgstr "書式が正しくありません"
## From Ecto.Changeset.validate_subset/3
msgid "has an invalid entry"
@@ -45,7 +45,7 @@ msgstr ""
## From Ecto.Changeset.validate_exclusion/3
msgid "is reserved"
-msgstr ""
+msgstr "予約されています"
## From Ecto.Changeset.validate_confirmation/3
msgid "does not match confirmation"
@@ -61,23 +61,23 @@ msgstr ""
## From Ecto.Changeset.validate_length/3
msgid "should be %{count} character(s)"
msgid_plural "should be %{count} character(s)"
-msgstr[0] ""
+msgstr[0] "%{count}文字である必要があります"
msgid "should have %{count} item(s)"
msgid_plural "should have %{count} item(s)"
-msgstr[0] ""
+msgstr[0] "%{count}個の要素を含む必要があります"
msgid "should be at least %{count} character(s)"
msgid_plural "should be at least %{count} character(s)"
-msgstr[0] ""
+msgstr[0] "%{count}文字以上である必要があります"
msgid "should have at least %{count} item(s)"
msgid_plural "should have at least %{count} item(s)"
-msgstr[0] ""
+msgstr[0] "%{count}個以上の要素を含む必要があります"
msgid "should be at most %{count} character(s)"
msgid_plural "should be at most %{count} character(s)"
-msgstr[0] ""
+msgstr[0] "%{count}文字以下である必要があります"
msgid "should have at most %{count} item(s)"
msgid_plural "should have at most %{count} item(s)"
@@ -102,7 +102,7 @@ msgstr "%{number}でなければなりません"
#: lib/pleroma/web/common_api/common_api.ex:505
#, elixir-format
msgid "Account not found"
-msgstr "アカウントがありません"
+msgstr "アカウントが見つかりません"
#: lib/pleroma/web/common_api/common_api.ex:339
#, elixir-format
@@ -226,7 +226,7 @@ msgstr ""
#: lib/pleroma/web/common_api/utils.ex:414
#, elixir-format
msgid "Invalid password."
-msgstr ""
+msgstr "パスワードが間違っています。"
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:220
#, elixir-format
@@ -236,7 +236,7 @@ msgstr ""
#: lib/pleroma/web/twitter_api/twitter_api.ex:109
#, elixir-format
msgid "Kocaptcha service unavailable"
-msgstr ""
+msgstr "Kocaptchaが利用できません"
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:112
#, elixir-format
@@ -259,12 +259,12 @@ msgstr ""
#: lib/pleroma/web/feed/user_controller.ex:71 lib/pleroma/web/ostatus/ostatus_controller.ex:143
#, elixir-format
msgid "Not found"
-msgstr ""
+msgstr "見つかりません"
#: lib/pleroma/web/common_api/common_api.ex:331
#, elixir-format
msgid "Poll's author can't vote"
-msgstr ""
+msgstr "作成者は投票できません"
#: lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:20
#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:37 lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:49
@@ -284,17 +284,17 @@ msgstr ""
#: lib/pleroma/web/common_api/activity_draft.ex:107
#, elixir-format
msgid "The message visibility must be direct"
-msgstr ""
+msgstr "公開範囲は「ダイレクト」でなければいけません"
#: lib/pleroma/web/common_api/utils.ex:573
#, elixir-format
msgid "The status is over the character limit"
-msgstr ""
+msgstr "文字数制限を超過しています"
#: lib/pleroma/plugs/ensure_public_or_authenticated_plug.ex:31
#, elixir-format
msgid "This resource requires authentication."
-msgstr ""
+msgstr "認証が必要です。"
#: lib/pleroma/plugs/rate_limiter/rate_limiter.ex:206
#, elixir-format
@@ -304,7 +304,7 @@ msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:356
#, elixir-format
msgid "Too many choices"
-msgstr ""
+msgstr "選択肢が多すぎます"
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:443
#, elixir-format
@@ -320,7 +320,7 @@ msgstr ""
#: lib/pleroma/web/oauth/oauth_controller.ex:308
#, elixir-format
msgid "Your account is currently disabled"
-msgstr ""
+msgstr "あなたのアカウントは無効化されています"
#: lib/pleroma/web/oauth/oauth_controller.ex:183
#: lib/pleroma/web/oauth/oauth_controller.ex:331
@@ -331,23 +331,23 @@ msgstr ""
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:390
#, elixir-format
msgid "can't read inbox of %{nickname} as %{as_nickname}"
-msgstr ""
+msgstr "%{nickname}のinboxを%{as_nickname}として閲覧することはできません"
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:473
#, elixir-format
msgid "can't update outbox of %{nickname} as %{as_nickname}"
-msgstr ""
+msgstr "%{nickname}のoutboxを%{as_nickname}として更新することはできません"
#: lib/pleroma/web/common_api/common_api.ex:471
#, elixir-format
msgid "conversation is already muted"
-msgstr ""
+msgstr "この会話はミュート済みです"
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:314
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:492
#, elixir-format
msgid "error"
-msgstr ""
+msgstr "エラー"
#: lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:32
#, elixir-format
@@ -357,7 +357,7 @@ msgstr ""
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:62
#, elixir-format
msgid "not found"
-msgstr ""
+msgstr "見つかりません"
#: lib/pleroma/web/oauth/oauth_controller.ex:394
#, elixir-format
@@ -382,28 +382,28 @@ msgstr ""
#: lib/pleroma/web/oauth/oauth_controller.ex:410
#, elixir-format
msgid "Failed to authenticate: %{message}."
-msgstr ""
+msgstr "認証に失敗しました: %{message}。"
#: lib/pleroma/web/oauth/oauth_controller.ex:441
#, elixir-format
msgid "Failed to set up user account."
-msgstr ""
+msgstr "ユーザーアカウントの設定に失敗しました。"
#: lib/pleroma/plugs/oauth_scopes_plug.ex:38
#, elixir-format
msgid "Insufficient permissions: %{permissions}."
-msgstr ""
+msgstr "%{permissions}の権限が必要です。"
#: lib/pleroma/plugs/uploaded_media.ex:104
#, elixir-format
msgid "Internal Error"
-msgstr ""
+msgstr "内部エラー"
#: lib/pleroma/web/oauth/fallback_controller.ex:22
#: lib/pleroma/web/oauth/fallback_controller.ex:29
#, elixir-format
msgid "Invalid Username/Password"
-msgstr ""
+msgstr "ユーザー名/パスワードが間違っています"
#: lib/pleroma/web/twitter_api/twitter_api.ex:118
#, elixir-format
@@ -423,7 +423,7 @@ msgstr ""
#: lib/pleroma/web/oauth/fallback_controller.ex:14
#, elixir-format
msgid "Unknown error, please check the details and try again."
-msgstr ""
+msgstr "不明なエラーです。詳細を確認し、再度試行してください。"
#: lib/pleroma/web/oauth/oauth_controller.ex:119
#: lib/pleroma/web/oauth/oauth_controller.ex:158
@@ -449,17 +449,17 @@ msgstr ""
#: lib/pleroma/web/twitter_api/twitter_api.ex:103
#, elixir-format
msgid "CAPTCHA Error"
-msgstr ""
+msgstr "CAPTCHAエラー"
#: lib/pleroma/web/common_api/common_api.ex:290
#, elixir-format
msgid "Could not add reaction emoji"
-msgstr ""
+msgstr "リアクションを追加できません"
#: lib/pleroma/web/common_api/common_api.ex:301
#, elixir-format
msgid "Could not remove reaction emoji"
-msgstr ""
+msgstr "リアクションを解除できません"
#: lib/pleroma/web/twitter_api/twitter_api.ex:129
#, elixir-format
@@ -469,7 +469,7 @@ msgstr ""
#: lib/pleroma/web/mastodon_api/controllers/list_controller.ex:92
#, elixir-format
msgid "List not found"
-msgstr ""
+msgstr "リストが見つかりません"
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:123
#, elixir-format
@@ -480,7 +480,7 @@ msgstr ""
#: lib/pleroma/web/oauth/oauth_controller.ex:321
#, elixir-format
msgid "Password reset is required"
-msgstr ""
+msgstr "パスワードのリセットが必要です"
#: lib/pleroma/tests/auth_test_controller.ex:9
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:6 lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:6
@@ -522,7 +522,7 @@ msgstr ""
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:28
#, elixir-format
msgid "Two-factor authentication enabled, you must use a access token."
-msgstr ""
+msgstr "二段階認証が有効になっています。アクセストークンが必要です。"
#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:210
#, elixir-format
@@ -552,7 +552,7 @@ msgstr ""
#: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:61
#, elixir-format
msgid "Web push subscription is disabled on this Pleroma instance"
-msgstr ""
+msgstr "このPleromaインスタンスではプッシュ通知が利用できません"
#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:451
#, elixir-format
@@ -562,19 +562,19 @@ msgstr ""
#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:126
#, elixir-format
msgid "authorization required for timeline view"
-msgstr ""
+msgstr "タイムラインを閲覧するには認証が必要です"
#: lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:24
#, elixir-format
msgid "Access denied"
-msgstr ""
+msgstr "アクセスが拒否されました"
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:282
#, elixir-format
msgid "This API requires an authenticated user"
-msgstr ""
+msgstr "このAPIを利用するには認証が必要です"
#: lib/pleroma/plugs/user_is_admin_plug.ex:21
#, elixir-format
msgid "User is not an admin."
-msgstr ""
+msgstr "ユーザーは管理者ではありません。"
diff --git a/test/fixtures/ccworld-ap-bridge_note.json b/test/fixtures/ccworld-ap-bridge_note.json
@@ -0,0 +1 @@
+{"@context":"https://www.w3.org/ns/activitystreams","type":"Note","id":"https://cc.mkdir.uk/ap/note/e5d1d0a1-1ab3-4498-9949-588e3fdea286","attributedTo":"https://cc.mkdir.uk/ap/acct/hiira","inReplyTo":"","quoteUrl":"","content":"おはコンー","published":"2024-01-19T22:08:05Z","to":["https://www.w3.org/ns/activitystreams#Public"],"tag":null,"attachment":[],"object":null}
diff --git a/test/fixtures/rich_media/google.html b/test/fixtures/rich_media/google.html
@@ -0,0 +1,12 @@
+<meta property="og:url" content="https://google.com">
+<meta property="og:type" content="website">
+<meta property="og:title" content="Google">
+<meta property="og:description" content="Search the world's information, including webpages, images, videos and more. Google has many special features to help you find exactly what you're looking for.">
+<meta property="og:image" content="">
+
+<meta name="twitter:card" content="summary_large_image">
+<meta property="twitter:domain" content="google.com">
+<meta property="twitter:url" content="https://google.com">
+<meta name="twitter:title" content="Google">
+<meta name="twitter:description" content="Search the world's information, including webpages, images, videos and more. Google has many special features to help you find exactly what you're looking for.">
+<meta name="twitter:image" content="">
diff --git a/test/fixtures/rich_media/oembed.html b/test/fixtures/rich_media/oembed.html
@@ -1,3 +1,3 @@
<link rel="alternate" type="application/json+oembed"
- href="http://example.com/oembed.json"
+ href="https://example.com/oembed.json"
title="Bacon Lollys oEmbed Profile" />
diff --git a/test/fixtures/rich_media/yahoo.html b/test/fixtures/rich_media/yahoo.html
@@ -0,0 +1,12 @@
+<meta property="og:url" content="https://yahoo.com">
+<meta property="og:type" content="website">
+<meta property="og:title" content="Yahoo | Mail, Weather, Search, Politics, News, Finance, Sports & Videos">
+<meta property="og:description" content="Latest news coverage, email, free stock quotes, live scores and video are just the beginning. Discover more every day at Yahoo!">
+<meta property="og:image" content="https://s.yimg.com/cv/apiv2/social/images/yahoo_default_logo.png">
+
+<meta name="twitter:card" content="summary_large_image">
+<meta property="twitter:domain" content="yahoo.com">
+<meta property="twitter:url" content="https://yahoo.com">
+<meta name="twitter:title" content="Yahoo | Mail, Weather, Search, Politics, News, Finance, Sports & Videos">
+<meta name="twitter:description" content="Latest news coverage, email, free stock quotes, live scores and video are just the beginning. Discover more every day at Yahoo!">
+<meta name="twitter:image" content="https://s.yimg.com/cv/apiv2/social/images/yahoo_default_logo.png">
diff --git a/test/pleroma/integration/mastodon_websocket_test.exs b/test/pleroma/integration/mastodon_websocket_test.exs
@@ -268,17 +268,6 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do
end)
end
- test "accepts valid token on Sec-WebSocket-Protocol header", %{token: token} do
- assert {:ok, _} = start_socket("?stream=user", [{"Sec-WebSocket-Protocol", token.token}])
-
- capture_log(fn ->
- assert {:error, %WebSockex.RequestError{code: 401}} =
- start_socket("?stream=user", [{"Sec-WebSocket-Protocol", "I am a friend"}])
-
- Process.sleep(30)
- end)
- end
-
test "accepts valid token on client-sent event", %{token: token} do
assert {:ok, pid} = start_socket()
diff --git a/test/pleroma/maps_test.exs b/test/pleroma/maps_test.exs
@@ -0,0 +1,22 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2024 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.MapsTest do
+ use Pleroma.DataCase, async: true
+
+ alias Pleroma.Maps
+
+ describe "filter_empty_values/1" do
+ assert %{"bar" => "b", "ray" => ["foo"], "objs" => %{"a" => "b"}} ==
+ Maps.filter_empty_values(%{
+ "foo" => nil,
+ "fooz" => "",
+ "bar" => "b",
+ "rei" => [],
+ "ray" => ["foo"],
+ "obj" => %{},
+ "objs" => %{"a" => "b"}
+ })
+ end
+end
diff --git a/test/pleroma/web/activity_pub/mrf/steal_emoji_policy_test.exs b/test/pleroma/web/activity_pub/mrf/steal_emoji_policy_test.exs
@@ -87,6 +87,32 @@ defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicyTest do
assert File.exists?(fullpath)
end
+ test "rejects invalid shortcodes", %{path: path} do
+ message = %{
+ "type" => "Create",
+ "object" => %{
+ "emoji" => [{"fired/fox", "https://example.org/emoji/firedfox"}],
+ "actor" => "https://example.org/users/admin"
+ }
+ }
+
+ fullpath = Path.join(path, "fired/fox.png")
+
+ Tesla.Mock.mock(fn %{method: :get, url: "https://example.org/emoji/firedfox"} ->
+ %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.jpg")}
+ end)
+
+ clear_config(:mrf_steal_emoji, hosts: ["example.org"], size_limit: 284_468)
+
+ refute "firedfox" in installed()
+ refute File.exists?(path)
+
+ assert {:ok, _message} = StealEmojiPolicy.filter(message)
+
+ refute "fired/fox" in installed()
+ refute File.exists?(fullpath)
+ end
+
test "reject regex shortcode", %{message: message} do
refute "firedfox" in installed()
diff --git a/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs b/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs
@@ -93,6 +93,17 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidatorTest
%{valid?: true} = ArticleNotePageValidator.cast_and_validate(note)
end
+ test "a Note from Convergence AP Bridge validates" do
+ insert(:user, ap_id: "https://cc.mkdir.uk/ap/acct/hiira")
+
+ note =
+ "test/fixtures/ccworld-ap-bridge_note.json"
+ |> File.read!()
+ |> Jason.decode!()
+
+ %{valid?: true} = ArticleNotePageValidator.cast_and_validate(note)
+ end
+
test "a note with an attachment should work", _ do
insert(:user, %{ap_id: "https://owncast.localhost.localdomain/federation/user/streamer"})
diff --git a/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs
@@ -336,13 +336,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
path -> Pleroma.Test.StaticConfig.get(path)
end)
- Tesla.Mock.mock(fn
- %{
- method: :get,
- url: "https://example.com/twitter-card"
- } ->
- %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/twitter_card.html")}
-
+ Tesla.Mock.mock_global(fn
env ->
apply(HttpRequestMock, :request, [env])
end)
diff --git a/test/pleroma/web/pleroma_api/views/chat_message_reference_view_test.exs b/test/pleroma/web/pleroma_api/views/chat_message_reference_view_test.exs
@@ -49,6 +49,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatMessageReferenceViewTest do
:chat_message_id_idempotency_key_cache, ^id -> {:ok, "123"}
cache, key -> NullCache.get(cache, key)
end)
+ |> stub(:fetch, fn :rich_media_cache, _, _ -> {:ok, {:ok, %{}}} end)
chat_message = MessageReferenceView.render("show.json", chat_message_reference: cm_ref)
diff --git a/test/pleroma/web/rich_media/helpers_test.exs b/test/pleroma/web/rich_media/helpers_test.exs
@@ -3,7 +3,7 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.RichMedia.HelpersTest do
- use Pleroma.DataCase, async: true
+ use Pleroma.DataCase, async: false
alias Pleroma.StaticStubbedConfigMock, as: ConfigMock
alias Pleroma.Web.CommonAPI
@@ -14,7 +14,7 @@ defmodule Pleroma.Web.RichMedia.HelpersTest do
import Tesla.Mock
setup do
- mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+ mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
ConfigMock
|> stub(:get, fn
@@ -83,8 +83,34 @@ defmodule Pleroma.Web.RichMedia.HelpersTest do
Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
end
- # This does not seem to work. The urls are being fetched.
- @tag skip: true
+ test "recrawls URLs on updates" do
+ original_url = "https://google.com/"
+ updated_url = "https://yahoo.com/"
+
+ Pleroma.StaticStubbedConfigMock
+ |> stub(:get, fn
+ [:rich_media, :enabled] -> true
+ path -> Pleroma.Test.StaticConfig.get(path)
+ end)
+
+ user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{status: "I like this site #{original_url}"})
+
+ assert match?(
+ %{page_url: ^original_url, rich_media: _},
+ Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
+ )
+
+ {:ok, _} = CommonAPI.update(user, activity, %{status: "I like this site #{updated_url}"})
+
+ activity = Pleroma.Activity.get_by_id(activity.id)
+
+ assert match?(
+ %{page_url: ^updated_url, rich_media: _},
+ Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
+ )
+ end
+
test "refuses to crawl URLs of private network from posts" do
user = insert(:user)
@@ -102,10 +128,10 @@ defmodule Pleroma.Web.RichMedia.HelpersTest do
path -> Pleroma.Test.StaticConfig.get(path)
end)
- assert %{} = Helpers.fetch_data_for_activity(activity)
- assert %{} = Helpers.fetch_data_for_activity(activity2)
- assert %{} = Helpers.fetch_data_for_activity(activity3)
- assert %{} = Helpers.fetch_data_for_activity(activity4)
- assert %{} = Helpers.fetch_data_for_activity(activity5)
+ assert %{} == Helpers.fetch_data_for_activity(activity)
+ assert %{} == Helpers.fetch_data_for_activity(activity2)
+ assert %{} == Helpers.fetch_data_for_activity(activity3)
+ assert %{} == Helpers.fetch_data_for_activity(activity4)
+ assert %{} == Helpers.fetch_data_for_activity(activity5)
end
end
diff --git a/test/pleroma/web/rich_media/parser_test.exs b/test/pleroma/web/rich_media/parser_test.exs
@@ -3,95 +3,26 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.RichMedia.ParserTest do
- use ExUnit.Case, async: true
+ use Pleroma.DataCase, async: false
alias Pleroma.Web.RichMedia.Parser
- setup do
- Tesla.Mock.mock(fn
- %{
- method: :get,
- url: "http://example.com/ogp"
- } ->
- %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/ogp.html")}
-
- %{
- method: :get,
- url: "http://example.com/non-ogp"
- } ->
- %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/non_ogp_embed.html")}
-
- %{
- method: :get,
- url: "http://example.com/ogp-missing-title"
- } ->
- %Tesla.Env{
- status: 200,
- body: File.read!("test/fixtures/rich_media/ogp-missing-title.html")
- }
-
- %{
- method: :get,
- url: "http://example.com/twitter-card"
- } ->
- %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/twitter_card.html")}
-
- %{
- method: :get,
- url: "http://example.com/oembed"
- } ->
- %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/oembed.html")}
-
- %{
- method: :get,
- url: "http://example.com/oembed.json"
- } ->
- %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/oembed.json")}
-
- %{method: :get, url: "http://example.com/empty"} ->
- %Tesla.Env{status: 200, body: "hello"}
+ import Tesla.Mock
- %{method: :get, url: "http://example.com/malformed"} ->
- %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/malformed-data.html")}
-
- %{method: :get, url: "http://example.com/error"} ->
- {:error, :overload}
-
- %{
- method: :head,
- url: "http://example.com/huge-page"
- } ->
- %Tesla.Env{
- status: 200,
- headers: [{"content-length", "2000001"}, {"content-type", "text/html"}]
- }
-
- %{
- method: :head,
- url: "http://example.com/pdf-file"
- } ->
- %Tesla.Env{
- status: 200,
- headers: [{"content-length", "1000000"}, {"content-type", "application/pdf"}]
- }
-
- %{method: :head} ->
- %Tesla.Env{status: 404, body: "", headers: []}
- end)
-
- :ok
+ setup do
+ mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
end
test "returns error when no metadata present" do
- assert {:error, _} = Parser.parse("http://example.com/empty")
+ assert {:error, _} = Parser.parse("https://example.com/empty")
end
test "doesn't just add a title" do
- assert {:error, {:invalid_metadata, _}} = Parser.parse("http://example.com/non-ogp")
+ assert {:error, {:invalid_metadata, _}} = Parser.parse("https://example.com/non-ogp")
end
test "parses ogp" do
- assert Parser.parse("http://example.com/ogp") ==
+ assert Parser.parse("https://example.com/ogp") ==
{:ok,
%{
"image" => "http://ia.media-imdb.com/images/rock.jpg",
@@ -99,12 +30,12 @@ defmodule Pleroma.Web.RichMedia.ParserTest do
"description" =>
"Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer.",
"type" => "video.movie",
- "url" => "http://example.com/ogp"
+ "url" => "https://example.com/ogp"
}}
end
test "falls back to <title> when ogp:title is missing" do
- assert Parser.parse("http://example.com/ogp-missing-title") ==
+ assert Parser.parse("https://example.com/ogp-missing-title") ==
{:ok,
%{
"image" => "http://ia.media-imdb.com/images/rock.jpg",
@@ -112,12 +43,12 @@ defmodule Pleroma.Web.RichMedia.ParserTest do
"description" =>
"Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer.",
"type" => "video.movie",
- "url" => "http://example.com/ogp-missing-title"
+ "url" => "https://example.com/ogp-missing-title"
}}
end
test "parses twitter card" do
- assert Parser.parse("http://example.com/twitter-card") ==
+ assert Parser.parse("https://example.com/twitter-card") ==
{:ok,
%{
"card" => "summary",
@@ -125,12 +56,12 @@ defmodule Pleroma.Web.RichMedia.ParserTest do
"image" => "https://farm6.staticflickr.com/5510/14338202952_93595258ff_z.jpg",
"title" => "Small Island Developing States Photo Submission",
"description" => "View the album on Flickr.",
- "url" => "http://example.com/twitter-card"
+ "url" => "https://example.com/twitter-card"
}}
end
test "parses OEmbed and filters HTML tags" do
- assert Parser.parse("http://example.com/oembed") ==
+ assert Parser.parse("https://example.com/oembed") ==
{:ok,
%{
"author_name" => "\u202E\u202D\u202Cbees\u202C",
@@ -150,7 +81,7 @@ defmodule Pleroma.Web.RichMedia.ParserTest do
"thumbnail_width" => 150,
"title" => "Bacon Lollys",
"type" => "photo",
- "url" => "http://example.com/oembed",
+ "url" => "https://example.com/oembed",
"version" => "1.0",
"web_page" => "https://www.flickr.com/photos/bees/2362225867/",
"web_page_short_url" => "https://flic.kr/p/4AK2sc",
@@ -159,18 +90,18 @@ defmodule Pleroma.Web.RichMedia.ParserTest do
end
test "rejects invalid OGP data" do
- assert {:error, _} = Parser.parse("http://example.com/malformed")
+ assert {:error, _} = Parser.parse("https://example.com/malformed")
end
test "returns error if getting page was not successful" do
- assert {:error, :overload} = Parser.parse("http://example.com/error")
+ assert {:error, :overload} = Parser.parse("https://example.com/error")
end
test "does a HEAD request to check if the body is too large" do
- assert {:error, :body_too_large} = Parser.parse("http://example.com/huge-page")
+ assert {:error, :body_too_large} = Parser.parse("https://example.com/huge-page")
end
test "does a HEAD request to check if the body is html" do
- assert {:error, {:content_type, _}} = Parser.parse("http://example.com/pdf-file")
+ assert {:error, {:content_type, _}} = Parser.parse("https://example.com/pdf-file")
end
end
diff --git a/test/support/cachex_proxy.ex b/test/support/cachex_proxy.ex
@@ -27,9 +27,15 @@ defmodule Pleroma.CachexProxy do
defdelegate fetch!(cache, key, func), to: Cachex
@impl true
+ defdelegate fetch(cache, key, func), to: Cachex
+
+ @impl true
defdelegate expire_at(cache, str, num), to: Cachex
@impl true
+ defdelegate expire(cache, str, num), to: Cachex
+
+ @impl true
defdelegate exists?(cache, key), to: Cachex
@impl true
diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex
@@ -1059,7 +1059,7 @@ defmodule HttpRequestMock do
}}
end
- def get("http://example.com/malformed", _, _, _) do
+ def get("https://example.com/malformed", _, _, _) do
{:ok,
%Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/malformed-data.html")}}
end
@@ -1464,6 +1464,45 @@ defmodule HttpRequestMock do
}}
end
+ def get("https://google.com/", _, _, _) do
+ {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/google.html")}}
+ end
+
+ def get("https://yahoo.com/", _, _, _) do
+ {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/yahoo.html")}}
+ end
+
+ def get("https://example.com/error", _, _, _), do: {:error, :overload}
+
+ def get("https://example.com/ogp-missing-title", _, _, _) do
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/rich_media/ogp-missing-title.html")
+ }}
+ end
+
+ def get("https://example.com/oembed", _, _, _) do
+ {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/oembed.html")}}
+ end
+
+ def get("https://example.com/oembed.json", _, _, _) do
+ {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/oembed.json")}}
+ end
+
+ def get("https://example.com/twitter-card", _, _, _) do
+ {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/twitter_card.html")}}
+ end
+
+ def get("https://example.com/non-ogp", _, _, _) do
+ {:ok,
+ %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/non_ogp_embed.html")}}
+ end
+
+ def get("https://example.com/empty", _, _, _) do
+ {:ok, %Tesla.Env{status: 200, body: "hello"}}
+ end
+
def get(url, query, body, headers) do
{:error,
"Mock response not implemented for GET #{inspect(url)}, #{query}, #{inspect(body)}, #{inspect(headers)}"}
@@ -1537,14 +1576,41 @@ defmodule HttpRequestMock do
# Most of the rich media mocks are missing HEAD requests, so we just return 404.
@rich_media_mocks [
+ "https://example.com/empty",
+ "https://example.com/error",
+ "https://example.com/malformed",
+ "https://example.com/non-ogp",
+ "https://example.com/oembed",
+ "https://example.com/oembed.json",
"https://example.com/ogp",
"https://example.com/ogp-missing-data",
- "https://example.com/twitter-card"
+ "https://example.com/ogp-missing-title",
+ "https://example.com/twitter-card",
+ "https://google.com/",
+ "https://pleroma.local/notice/9kCP7V",
+ "https://yahoo.com/"
]
+
def head(url, _query, _body, _headers) when url in @rich_media_mocks do
{:ok, %Tesla.Env{status: 404, body: ""}}
end
+ def head("https://example.com/pdf-file", _, _, _) do
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ headers: [{"content-length", "1000000"}, {"content-type", "application/pdf"}]
+ }}
+ end
+
+ def head("https://example.com/huge-page", _, _, _) do
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ headers: [{"content-length", "2000001"}, {"content-type", "text/html"}]
+ }}
+ end
+
def head(url, query, body, headers) do
{:error,
"Mock response not implemented for HEAD #{inspect(url)}, #{query}, #{inspect(body)}, #{inspect(headers)}"}
diff --git a/test/support/null_cache.ex b/test/support/null_cache.ex
@@ -29,6 +29,9 @@ defmodule Pleroma.NullCache do
end
@impl true
+ def fetch(_, key, func), do: func.(key)
+
+ @impl true
def get_and_update(_, _, func) do
func.(nil)
end
@@ -37,6 +40,9 @@ defmodule Pleroma.NullCache do
def expire_at(_, _, _), do: {:ok, true}
@impl true
+ def expire(_, _, _), do: {:ok, true}
+
+ @impl true
def exists?(_, _), do: {:ok, false}
@impl true