Merge branch 'develop' into fix/domain-block-subplan-cost

This commit is contained in:
lain 2026-09-02 10:19:27 +00:00
commit 70d743bff9
20 changed files with 244 additions and 351 deletions

View file

@ -0,0 +1 @@
Docs: Fixed OTP install links in documentation, broke up wall of install commands into smaller chunks, fixed sudo commands execution

View file

View file

@ -1 +0,0 @@
Detect image content types for extensionless MediaProxy responses.

View file

@ -0,0 +1 @@
Oban: Enabled the Reindexer plugin to reduce oban_jobs index DB bloat

View file

View file

@ -0,0 +1 @@
Fix intermittent failure to compile syslog package

View file

@ -607,7 +607,11 @@ config :pleroma, Oban,
search_indexing: [limit: 10, paused: true],
slow: 5
],
plugins: [Oban.Plugins.Lazarus, {Oban.Plugins.Pruner, max_age: 900}],
plugins: [
Oban.Plugins.Lazarus,
{Oban.Plugins.Pruner, max_age: 900},
{Oban.Plugins.Reindexer, schedule: "@weekly"}
],
crontab: [
{"0 0 * * 0", Pleroma.Workers.Cron.DigestEmailsWorker},
{"0 0 * * *", Pleroma.Workers.Cron.NewUsersDigestWorker},

View file

@ -76,35 +76,51 @@ $EDITOR /etc/pleroma/config.exs
```
## Installing the release
Before proceeding, get the flavour from [Detecting flavour](otp_en.md#detecting-flavour) section in OTP installation guide.
Delete all files in pleroma user's directory:
```sh
# Delete all files in pleroma user's directory
rm -r ~pleroma/*
```
# Set the flavour environment variable to the string you got in Detecting flavour section.
# For example if the flavour is `amd64-musl` the command will be
Set the flavour environment variable to the string you got in Detecting flavour section.
For example if the flavour is `amd64-musl` the command will be:
```sh
export FLAVOUR="amd64-musl"
```
# Clone the release build into a temporary directory and unpack it
# Replace `stable` with `unstable` if you want to run the unstable branch
sudo -Hu pleroma "
curl 'https://git.pleroma.social/api/v4/projects/2/jobs/artifacts/stable/download?job=$FLAVOUR' -o /tmp/pleroma.zip
unzip /tmp/pleroma.zip -d /tmp/
"
Clone the release build into a temporary directory and unpack it.
Replace `stable` with `develop`, if you want to run the develop branch.
# Move the release to the home directory and delete temporary files
sudo -Hu pleroma "
mv /tmp/release/* ~pleroma/
rmdir /tmp/release
rm /tmp/pleroma.zip
"
```sh
sudo -Hu pleroma curl "https://git.pleroma.social/api/packages/pleroma/generic/pleroma-otp-stable-$FLAVOUR/latest/pleroma.zip" -o /tmp/pleroma.zip
sudo -Hu pleroma unzip /tmp/pleroma.zip -d /tmp/
```
# Start the instance to verify that everything is working as expected
Move the release to the home directory and delete temporary files:
```sh
sudo -Hu pleroma mv /tmp/release/* ~pleroma/
sudo -Hu pleroma rmdir /tmp/release
sudo -Hu pleroma rm /tmp/pleroma.zip
```
Start the instance to verify that everything is working as expected:
```sh
sudo -Hu pleroma "./bin/pleroma daemon"
```
# Wait for about 20 seconds and query the instance endpoint, if it shows your uri, name and email correctly, you are configured correctly
Wait for about 20 seconds and query the instance endpoint, if it shows your uri, name and email correctly, you are configured correctly:
```sh
sleep 20 && curl http://localhost:4000/api/v1/instance
```
# Stop the instance
Stop the instance:
```sh
sudo -Hu pleroma "./bin/pleroma stop"
```

View file

@ -130,60 +130,90 @@ Restart PostgreSQL to apply configuration changes:
```
### Installing Pleroma
Create a Pleroma user:
```sh
# Create a Pleroma user
adduser --system --shell /bin/false --home /opt/pleroma pleroma
```
# Set the flavour environment variable to the string you got in Detecting flavour section.
# For example if the flavour is `amd64-musl` the command will be
Set the flavour environment variable to the string you got in Detecting flavour section. For example if the flavour is `amd64-musl` the command will be:
```sh
export FLAVOUR="amd64-musl"
```
# Clone the release build into a temporary directory and unpack it
sudo -Hu pleroma "
curl 'https://git.pleroma.social/api/v4/projects/2/jobs/artifacts/stable/download?job=$FLAVOUR' -o /tmp/pleroma.zip
unzip /tmp/pleroma.zip -d /tmp/
"
Clone the release build into a temporary directory and unpack it:
# Move the release to the home directory and delete temporary files
sudo -Hu pleroma "
mv /tmp/release/* /opt/pleroma
rmdir /tmp/release
rm /tmp/pleroma.zip
"
# Create uploads directory and set proper permissions (skip if planning to use a remote uploader)
# Note: It does not have to be `/var/lib/pleroma/uploads`, the config generator will ask about the upload directory later
```sh
sudo -Hu pleroma curl "https://git.pleroma.social/api/packages/pleroma/generic/pleroma-otp-stable-$FLAVOUR/latest/pleroma.zip" -o /tmp/pleroma.zip
sudo -Hu pleroma unzip /tmp/pleroma.zip -d /tmp/
```
Move the release to the home directory and delete temporary files:
```sh
sudo -Hu pleroma mv /tmp/release/* /opt/pleroma
sudo -Hu pleroma rmdir /tmp/release
sudo -Hu pleroma rm /tmp/pleroma.zip
```
Create uploads directory and set proper permissions (skip if planning to use a remote uploader).
Note: It does not have to be `/var/lib/pleroma/uploads`, the config generator will ask about the upload directory later.
```sh
mkdir -p /var/lib/pleroma/uploads
chown -R pleroma /var/lib/pleroma
```
# Create custom public files directory (custom emojis, frontend bundle overrides, robots.txt, etc.)
# Note: It does not have to be `/var/lib/pleroma/static`, the config generator will ask about the custom public files directory later
Create custom public files directory (custom emojis, frontend bundle overrides, robots.txt, etc.)
Note: It does not have to be `/var/lib/pleroma/static`, the config generator will ask about the custom public files directory later.
```sh
mkdir -p /var/lib/pleroma/static
chown -R pleroma /var/lib/pleroma
```
# Create a config directory
Create a config directory:
```sh
mkdir -p /etc/pleroma
chown -R pleroma /etc/pleroma
```
# Run the config generator
Run the config generator:
```sh
sudo -Hu pleroma "./bin/pleroma_ctl instance gen --output /etc/pleroma/config.exs --output-psql /tmp/setup_db.psql"
```
# Create the postgres database
Create the postgres database and schema:
```sh
sudo -u postgres -s $SHELL -lc "psql -f /tmp/setup_db.psql"
# Create the database schema
sudo -Hu pleroma "./bin/pleroma_ctl migrate"
```
# If you have installed RUM indexes uncommend and run
# sudo -Hu pleroma "./bin/pleroma_ctl migrate --migrations-path priv/repo/optional_migrations/rum_indexing/"
(Optional) If you have installed RUM indexes:
# Start the instance to verify that everything is working as expected
```sh
sudo -Hu pleroma "./bin/pleroma_ctl migrate --migrations-path priv/repo/optional_migrations/rum_indexing/"
```
Start the instance to verify that everything is working as expected:
```sh
sudo -Hu pleroma "./bin/pleroma daemon"
```
# Wait for about 20 seconds and query the instance endpoint, if it shows your uri, name and email correctly, you are configured correctly
Wait for about 20 seconds and query the instance endpoint, if it shows your uri, name and email correctly, you are configured correctly:
```sh
sleep 20 && curl http://localhost:4000/api/v1/instance
```
# Stop the instance
Stop the instance:
```sh
sudo -Hu pleroma "./bin/pleroma stop"
```

View file

@ -17,7 +17,6 @@ defmodule Pleroma.ReverseProxy do
@max_read_duration :timer.seconds(30)
@max_body_length :infinity
@failed_request_ttl :timer.seconds(60)
@sniff_bytes 8 * 1024
@methods ~w(GET HEAD)
@allowed_mime_types Pleroma.Config.get([Pleroma.Upload, :allowed_mime_types], [])
@ -70,12 +69,7 @@ defmodule Pleroma.ReverseProxy do
* `inline_content_types`:
* `true` will not alter `content-disposition` (up to the upstream),
* `false` will add `content-disposition: attachment` to any request,
* a list of whitelisted content types for which `content-disposition: inline`
is always set (overriding any upstream header) so the media can be embedded
in pages; the filename is derived from the content type
* `sniff_content_type` (default `false`): detects an image MIME type from the first
response chunk when the upstream type is missing or `application/octet-stream`.
* a list of whitelisted content types
* `req_headers`, `resp_headers` additional headers.
@ -112,7 +106,6 @@ defmodule Pleroma.ReverseProxy do
| {:req_headers, [{String.t(), String.t()}]}
| {:resp_headers, [{String.t(), String.t()}]}
| {:inline_content_types, boolean() | list(String.t())}
| {:sniff_content_type, boolean()}
| {:redirect_on_failure, boolean()}
@spec call(Plug.Conn.t(), String.t(), list(option())) :: Plug.Conn.t()
@ -228,30 +221,11 @@ defmodule Pleroma.ReverseProxy do
defp response(conn, client, url, status, headers, opts) do
Logger.debug("#{__MODULE__} #{status} #{url} #{inspect(headers)}")
case maybe_prefetch_for_content_type(headers, client, opts) do
{_headers, client, {:error, {:upstream, error}}} ->
Logger.warning(
"#{__MODULE__} request to #{url} failed before streaming: #{inspect(error)}"
)
client().close(client)
track_failed_url(url, error, opts)
conn
|> error_or_redirect(url, 500, "Request failed", opts)
|> halt()
{headers, client, prefetched} ->
stream_response(conn, client, url, status, headers, opts, prefetched)
end
end
defp stream_response(conn, client, url, status, headers, opts, prefetched) do
result =
conn
|> put_resp_headers(build_resp_headers(headers, opts))
|> send_chunked(status)
|> chunk_reply(client, opts, prefetched)
|> chunk_reply(client, opts)
case result do
{:ok, conn} ->
@ -272,29 +246,18 @@ defmodule Pleroma.ReverseProxy do
end
end
defp chunk_reply(conn, client, opts, :none) do
defp chunk_reply(conn, client, opts) do
chunk_reply(conn, client, opts, 0, 0)
end
defp chunk_reply(conn, _client, _opts, :done), do: {:ok, conn}
defp chunk_reply(conn, _client, _opts, {:error, error}), do: {:error, error, conn}
defp chunk_reply(conn, client, opts, {:ok, data, duration}) do
with :ok <-
body_size_constraint(
byte_size(data),
Keyword.get(opts, :max_body_length, @max_body_length)
),
{:ok, conn} <- write_chunk(conn, data) do
chunk_reply(conn, client, opts, byte_size(data), duration)
else
{:error, {:downstream, error}} -> {:error, {:downstream, error}, conn}
{:error, error} -> {:error, {:upstream, error}, conn}
end
end
defp chunk_reply(conn, client, opts, sent_so_far, duration) do
with {:ok, data, client, duration} <- read_chunk(client, duration, opts),
with {:ok, duration} <-
check_read_duration(
duration,
Keyword.get(opts, :max_read_duration, @max_read_duration)
),
{:ok, data, client} <- client().stream_body(client),
{:ok, duration} <- increase_read_duration(duration),
sent_so_far = sent_so_far + byte_size(data),
:ok <-
body_size_constraint(
@ -310,24 +273,6 @@ defmodule Pleroma.ReverseProxy do
end
end
defp read_chunk(client, duration, opts) do
result =
with {:ok, timer} <-
check_read_duration(
duration,
Keyword.get(opts, :max_read_duration, @max_read_duration)
),
{:ok, data, client} <- client().stream_body(client),
{:ok, duration} <- increase_read_duration(timer) do
{:ok, data, client, duration}
end
case result do
{:error, error} -> {:error, {:upstream, error}}
result -> result
end
end
defp write_chunk(conn, data) do
case chunk(conn, data) do
{:error, error} -> {:error, {:downstream, error}}
@ -335,54 +280,6 @@ defmodule Pleroma.ReverseProxy do
end
end
defp maybe_prefetch_for_content_type(headers, client, opts) do
if Keyword.get(opts, :sniff_content_type, false) and generic_content_type?(headers) do
case read_chunk(client, 0, opts) do
{:ok, data, client, duration} ->
{maybe_put_image_content_type(headers, data), client, {:ok, data, duration}}
:done ->
{headers, client, :done}
{:error, error} ->
{headers, client, {:error, error}}
end
else
{headers, client, :none}
end
end
defp generic_content_type?(headers) do
headers
|> get_content_type()
|> String.trim()
|> String.downcase()
|> then(&(&1 in ["", "application/octet-stream"]))
end
defp maybe_put_image_content_type(headers, data) do
with false <- data == "",
{:ok, %{mime_type: "image/" <> _ = content_type}} <-
Majic.perform({:bytes, binary_part(data, 0, min(byte_size(data), @sniff_bytes))},
pool: Pleroma.MajicPool
) do
[
{"content-type", content_type}
| Enum.reject(headers, fn {key, _} -> key == "content-type" end)
]
else
_ -> headers
end
rescue
error ->
Logger.debug("#{__MODULE__}: content-type sniffing failed: #{Exception.message(error)}")
headers
catch
kind, reason ->
Logger.debug("#{__MODULE__}: content-type sniffing failed: #{kind}: #{inspect(reason)}")
headers
end
defp head_response(conn, url, code, headers, opts) do
Logger.debug("#{__MODULE__} #{code} #{url} #{inspect(headers)}")
@ -430,33 +327,16 @@ defmodule Pleroma.ReverseProxy do
|> build_req_range_or_encoding_header(opts)
|> build_req_user_agent_header(opts)
|> merge_headers(Keyword.get(opts, :req_headers, []))
|> maybe_force_identity_encoding(opts)
end
defp merge_headers(headers, extra_headers) do
Enum.reduce(extra_headers, headers, fn {key, value}, headers ->
List.keystore(headers, String.downcase(key), 0, {String.downcase(key), value})
end)
end
defp maybe_force_identity_encoding(headers, opts) do
if Keyword.get(opts, :sniff_content_type, false) do
List.keystore(headers, "accept-encoding", 0, {"accept-encoding", "identity"})
else
headers
end
end
# Disable content-encoding if any @range_headers are requested (see #1823).
defp build_req_range_or_encoding_header(headers, _opts) do
range? = Enum.any?(headers, fn {header, _} -> Enum.member?(@range_headers, header) end)
cond do
range? && List.keymember?(headers, "accept-encoding", 0) ->
List.keydelete(headers, "accept-encoding", 0)
true ->
headers
if range? && List.keymember?(headers, "accept-encoding", 0) do
List.keydelete(headers, "accept-encoding", 0)
else
headers
end
end
@ -479,6 +359,12 @@ defmodule Pleroma.ReverseProxy do
|> ensure_no_transform()
end
defp merge_headers(headers, extra_headers) do
Enum.reduce(extra_headers, headers, fn {key, value}, headers ->
List.keystore(headers, String.downcase(key), 0, {String.downcase(key), value})
end)
end
defp ensure_no_transform(headers) do
{_, cache_control} =
List.keyfind(headers, "cache-control", 0, {"cache-control", @default_cache_control_header})
@ -568,20 +454,7 @@ defmodule Pleroma.ReverseProxy do
replace_header(headers, "content-disposition", disposition)
else
if opt == true do
headers
else
name = inline_filename(content_type)
disposition =
if name do
"inline; filename=\"#{name}\""
else
"inline"
end
replace_header(headers, "content-disposition", disposition)
end
headers
end
end
@ -589,13 +462,6 @@ defmodule Pleroma.ReverseProxy do
[{key, value} | Enum.reject(headers, fn {header, _} -> header == key end)]
end
defp inline_filename(content_type) do
case MIME.extensions(content_type) do
[ext | _] when ext != "" -> "inline.#{ext}"
_ -> nil
end
end
defp header_length_constraint(headers, limit) do
lengths =
for {"content-length", value} <- headers,
@ -640,9 +506,7 @@ defmodule Pleroma.ReverseProxy do
end
end
defp check_read_duration(_, _), do: {:ok, :no_duration_limit}
defp increase_read_duration(:no_duration_limit), do: {:ok, :no_duration_limit}
defp check_read_duration(_, _), do: {:ok, :no_duration_limit, :no_duration_limit}
defp increase_read_duration({previous_duration, started})
when is_integer(previous_duration) and is_integer(started) do

View file

@ -8,6 +8,7 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do
alias Pleroma.Web.ApiSpec.Schemas.Account
alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
alias Pleroma.Web.ApiSpec.Schemas.ChatMessage
alias Pleroma.Web.ApiSpec.Schemas.Status
alias Pleroma.Web.ApiSpec.Schemas.VisibilityScope
@ -304,7 +305,25 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do
page_max_id: %Schema{type: :string, nullable: true},
latest_page_notification_at: %Schema{type: :string, format: :"date-time", nullable: true},
sample_account_ids: %Schema{type: :array, items: %Schema{type: :string}},
status_id: %Schema{type: :string, nullable: true}
status_id: %Schema{type: :string, nullable: true},
target_id: %Schema{
type: :string,
description: "ID of the target account for a move notification"
},
emoji: %Schema{
type: :string,
description: "Emoji used for an emoji reaction notification"
},
emoji_url: %Schema{
type: :string,
nullable: true,
description: "URL of the custom emoji used for an emoji reaction notification"
},
chat_message: ChatMessage,
report: %Schema{
type: :object,
description: "Report embedded in a report notification"
}
},
required: [
:group_key,

View file

@ -101,13 +101,13 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
|> Enum.filter(& &1)
|> Enum.uniq_by(& &1[:id])
actors =
accounts =
notification_groups
|> List.flatten()
|> notification_actors()
|> notification_accounts()
%{
accounts: AccountView.render("index.json", %{users: actors, for: reading_user}),
accounts: AccountView.render("index.json", %{users: accounts, for: reading_user}),
statuses: statuses,
notification_groups:
Enum.map(
@ -191,7 +191,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
defp render_group(
[%Notification{} = notification | _] = notifications,
_reading_user,
reading_user,
grouped_types,
notification_group_counts,
notification_group_bounds,
@ -237,13 +237,49 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
response
end
if status_activity do
Map.put(response, :status_id, to_string(status_activity.id))
else
response
response =
if status_activity do
Map.put(response, :status_id, to_string(status_activity.id))
else
response
end
put_group_details(response, notification, reading_user)
end
defp put_group_details(response, %Notification{type: "move", activity: activity}, _reading_user) do
case User.get_cached_by_ap_id(activity.data["target"]) do
%User{id: id} -> Map.put(response, :target_id, to_string(id))
_ -> response
end
end
defp put_group_details(
response,
%Notification{type: "pleroma:emoji_reaction", activity: activity},
_reading_user
) do
put_emoji(response, activity)
end
defp put_group_details(
response,
%Notification{type: "pleroma:chat_mention", activity: activity},
reading_user
) do
put_chat_message(response, activity, reading_user, %{})
end
defp put_group_details(
response,
%Notification{type: "pleroma:report", activity: activity},
_reading_user
) do
put_report(response, activity)
end
defp put_group_details(response, _notification, _reading_user), do: response
defp status_activity_for_group([%Notification{} = notification | _], grouped_types) do
status_activity_for(notification, grouped_types)
end
@ -287,6 +323,19 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
|> Enum.uniq_by(& &1.id)
end
defp notification_accounts(notifications) do
move_targets =
notifications
|> Enum.filter(&(&1.type == "move"))
|> Enum.map(&User.get_cached_by_ap_id(&1.activity.data["target"]))
|> Enum.filter(& &1)
notifications
|> notification_actors()
|> Kernel.++(move_targets)
|> Enum.uniq_by(& &1.id)
end
defp put_emoji(response, activity) do
response
|> Map.put(:emoji, activity.data["content"])

View file

@ -631,7 +631,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
String.contains?(media_type, "image") -> "image"
String.contains?(media_type, "video") -> "video"
String.contains?(media_type, "audio") -> "audio"
attachment["type"] == "Image" -> "image"
true -> "unknown"
end

View file

@ -208,7 +208,6 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyController do
defp media_proxy_opts do
Config.get([:media_proxy, :proxy_opts], [])
|> Keyword.put_new(:sniff_content_type, true)
end
defp sandbox(conn, _params) do

View file

@ -172,6 +172,14 @@ defmodule Pleroma.Mixfile do
{:gen_smtp, "~> 0.15"},
{:mua, "~> 0.2.4"},
{:mail, "~> 0.3.1"},
# Fixes intermittent failure to compile due to an old pc version,
# upstream hasn't made a release with the fix yet.
# https://github.com/Vagabond/erlang-syslog/pull/44
{:syslog,
git: "https://github.com/Vagabond/erlang-syslog",
ref: "614a1fde7a8654bee2815b599bbdaae1bb0323b5",
override: true,
runtime: false},
{:ex_syslogger, "~> 1.5"},
{:floki, "~> 0.38"},
{:timex, "~> 3.7"},

View file

@ -139,7 +139,7 @@
"statistex": {:hex, :statistex, "1.1.0", "7fec1eb2f580a0d2c1a05ed27396a084ab064a40cfc84246dbfb0c72a5c761e5", [:mix], [], "hexpm", "f5950ea26ad43246ba2cce54324ac394a4e7408fdcf98b8e230f503a0cba9cf5"},
"sweet_xml": {:hex, :sweet_xml, "0.7.5", "803a563113981aaac202a1dbd39771562d0ad31004ddbfc9b5090bdcd5605277", [:mix], [], "hexpm", "193b28a9b12891cae351d81a0cead165ffe67df1b73fe5866d10629f4faefb12"},
"swoosh": {:hex, :swoosh, "1.16.12", "cbb24ad512f2f7f24c7a469661c188a00a8c2cd64e0ab54acd1520f132092dfd", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.2.3", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "0e262df1ae510d59eeaaa3db42189a2aa1b3746f73771eb2616fc3f7ee63cc20"},
"syslog": {:hex, :syslog, "1.1.0", "6419a232bea84f07b56dc575225007ffe34d9fdc91abe6f1b2f254fd71d8efc2", [:rebar3], [], "hexpm", "4c6a41373c7e20587be33ef841d3de6f3beba08519809329ecc4d27b15b659e1"},
"syslog": {:git, "https://github.com/Vagabond/erlang-syslog", "614a1fde7a8654bee2815b599bbdaae1bb0323b5", [ref: "614a1fde7a8654bee2815b599bbdaae1bb0323b5"]},
"table_rex": {:hex, :table_rex, "4.1.0", "fbaa8b1ce154c9772012bf445bfb86b587430fb96f3b12022d3f35ee4a68c918", [:mix], [], "hexpm", "95932701df195d43bc2d1c6531178fc8338aa8f38c80f098504d529c43bc2601"},
"telemetry": {:hex, :telemetry, "1.0.0", "0f453a102cdf13d506b7c0ab158324c337c41f1cc7548f0bc0e130bbf0ae9452", [:rebar3], [], "hexpm", "73bc09fa59b4a0284efb4624335583c528e07ec9ae76aca96ea0673850aec57a"},
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.2", "2caabe9344ec17eafe5403304771c3539f3b6e2f7fb6a6f602558c825d0d0bfb", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9b43db0dc33863930b9ef9d27137e78974756f5f198cae18409970ed6fa5b561"},

View file

@ -579,56 +579,6 @@ defmodule Pleroma.ReverseProxyTest do
assert Conn.get_resp_header(conn, "content-type") == ["application/octet-stream"]
end
test "sniffs and preserves an image body with a generic content type", %{conn: conn} do
body = File.read!("test/fixtures/image.jpg")
ClientMock
|> expect(:request, fn :get, "/extensionless", headers, _, _ ->
assert {"accept-encoding", "identity"} in headers
{:ok, 200, [{"content-type", "application/octet-stream"}], %{body: body}}
end)
|> expect(:stream_body, fn %{body: ^body} = client ->
{:ok, body, Map.delete(client, :body)}
end)
|> expect(:stream_body, fn %{} -> :done end)
conn =
ReverseProxy.call(conn, "/extensionless",
sniff_content_type: true,
max_read_duration: :infinity,
req_headers: [{"accept-encoding", "gzip"}]
)
assert conn.resp_body == body
assert Conn.get_resp_header(conn, "content-type") == ["image/jpeg"]
assert Conn.get_resp_header(conn, "content-disposition") == [
"inline; filename=\"inline.jpg\""
]
end
test "redirects a content sniffing failure before committing the response", %{conn: conn} do
url = "https://example.com/extensionless"
ClientMock
|> expect(:request, fn :get, ^url, _, _, _ ->
{:ok, 200, [{"content-type", "application/octet-stream"}], %{url: url}}
end)
|> expect(:stream_body, fn _ -> {:error, :closed} end)
|> expect(:close, fn _ -> :ok end)
conn =
ReverseProxy.call(conn, url,
sniff_content_type: true,
redirect_on_failure: true
)
assert conn.status == 302
assert Conn.get_resp_header(conn, "location") == [url]
assert conn.state == :sent
assert Cachex.get(:failed_proxy_url_cache, url) == {:ok, true}
end
test "preserves a generic content type for a non-image body", %{conn: conn} do
body = "not an image"
@ -823,24 +773,6 @@ defmodule Pleroma.ReverseProxyTest do
conn = ReverseProxy.call(conn, "/disposition")
assert {"content-type", "image/gif"} in conn.resp_headers
assert {"content-disposition", "inline; filename=\"inline.gif\""} in conn.resp_headers
end
test "forces inline for inline content types overriding upstream attachment", %{
conn: conn
} do
disposition_headers_mock([
{"content-type", "image/png"},
{"content-disposition", "attachment; filename=\"filename.png\""},
{"content-disposition", "attachment; filename=\"duplicate.png\""},
{"content-length", "0"}
])
conn = ReverseProxy.call(conn, "/disposition")
[disposition] = Conn.get_resp_header(conn, "content-disposition")
assert String.starts_with?(disposition, "inline")
refute String.starts_with?(disposition, "attachment")
end
test "with content-disposition header", %{conn: conn} do
@ -853,50 +785,6 @@ defmodule Pleroma.ReverseProxyTest do
assert {"content-disposition", "attachment; filename=\"filename.jpg\""} in conn.resp_headers
end
test "with inline_content_types: true leaves upstream headers untouched", %{
conn: conn
} do
# opt == true: the proxy must not synthesise or rewrite content-disposition.
disposition_headers_mock([
{"content-type", "image/png"},
{"content-disposition", "attachment; filename=\"upstream.png\""},
{"content-length", "0"}
])
conn = ReverseProxy.call(conn, "/disposition", inline_content_types: true)
assert {"content-disposition", "attachment; filename=\"upstream.png\""} in conn.resp_headers
end
test "forces bare inline for a whitelisted type with no MIME extension", %{
conn: conn
} do
# image/x-foo-bar has no entry in MIME's database, so inline_filename/1
# returns nil and the disposition should be the bare token "inline".
disposition_headers_mock([
{"content-type", "image/x-foo-bar"},
{"content-length", "0"}
])
conn = ReverseProxy.call(conn, "/disposition", inline_content_types: ["image/x-foo-bar"])
[disposition] = Conn.get_resp_header(conn, "content-disposition")
assert disposition == "inline"
end
test "serves modern browser image types inline", %{conn: conn} do
disposition_headers_mock([
{"content-type", "image/webp"},
{"content-length", "0"}
])
conn = ReverseProxy.call(conn, "/disposition")
assert Conn.get_resp_header(conn, "content-disposition") == [
"inline; filename=\"inline.webp\""
]
end
end
describe "content-type sanitisation" do

View file

@ -65,6 +65,15 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
}
test_notifications_rendering([notification], recipient, [expected])
grouped =
NotificationView.render("grouped_index.json", %{
notifications: [notification],
for: recipient
})
assert [group] = grouped.notification_groups
assert group.chat_message == expected.chat_message
end
test "Mention notification" do
@ -182,6 +191,16 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
}
test_notifications_rendering([notification], follower, [expected])
grouped =
NotificationView.render("grouped_index.json", %{
notifications: [notification],
for: follower
})
assert [group] = grouped.notification_groups
assert group.target_id == new_user.id
assert Enum.any?(grouped.accounts, &(&1.id == new_user.id))
end
test "EmojiReact notification" do
@ -210,6 +229,13 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
}
test_notifications_rendering([notification], user, [expected])
grouped =
NotificationView.render("grouped_index.json", %{notifications: [notification], for: user})
assert [group] = grouped.notification_groups
assert group.emoji == expected.emoji
assert group.emoji_url == expected.emoji_url
end
test "EmojiReact custom emoji notification" do
@ -295,6 +321,15 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
}
test_notifications_rendering([notification], moderator_user, [expected])
grouped =
NotificationView.render("grouped_index.json", %{
notifications: [notification],
for: moderator_user
})
assert [group] = grouped.notification_groups
assert group.report == expected.report
end
test "Edit notification" do

View file

@ -668,23 +668,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
assert expected == StatusView.render("attachment.json", %{attachment: object})
assert_schema(expected, "Attachment", api_spec)
end
test "uses the ActivityStreams image type when the MIME type is generic" do
object = %{
"type" => "Image",
"url" => [
%{
"mediaType" => "application/octet-stream",
"href" => "https://example.com/extensionless"
}
]
}
attachment = StatusView.render("attachment.json", %{attachment: object})
assert attachment.type == "image"
assert attachment.pleroma.mime_type == "application/octet-stream"
end
end
test "put the url advertised in the Activity in to the url attribute" do

View file

@ -71,10 +71,7 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
test "it performs ReverseProxy.call with valid signature", %{conn: conn, url: url} do
with_mock Pleroma.ReverseProxy,
call: fn _conn, _url, opts ->
assert opts[:sniff_content_type]
%Conn{status: :success}
end do
call: fn _conn, _url, _opts -> %Conn{status: :success} end do
assert %Conn{status: :success} = get(conn, url)
end
end