Merge branch 'develop' into fix/domain-block-subplan-cost
This commit is contained in:
commit
70d743bff9
20 changed files with 244 additions and 351 deletions
1
changelog.d/docs-otp-install-links.fix
Normal file
1
changelog.d/docs-otp-install-links.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Docs: Fixed OTP install links in documentation, broke up wall of install commands into smaller chunks, fixed sudo commands execution
|
||||||
0
changelog.d/grouped-notifs-embed.skip
Normal file
0
changelog.d/grouped-notifs-embed.skip
Normal file
|
|
@ -1 +0,0 @@
|
||||||
Detect image content types for extensionless MediaProxy responses.
|
|
||||||
1
changelog.d/oban-reindexer.add
Normal file
1
changelog.d/oban-reindexer.add
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Oban: Enabled the Reindexer plugin to reduce oban_jobs index DB bloat
|
||||||
0
changelog.d/syslog-fix-otp.skip
Normal file
0
changelog.d/syslog-fix-otp.skip
Normal file
1
changelog.d/syslog-pc.fix
Normal file
1
changelog.d/syslog-pc.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Fix intermittent failure to compile syslog package
|
||||||
|
|
@ -607,7 +607,11 @@ config :pleroma, Oban,
|
||||||
search_indexing: [limit: 10, paused: true],
|
search_indexing: [limit: 10, paused: true],
|
||||||
slow: 5
|
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: [
|
crontab: [
|
||||||
{"0 0 * * 0", Pleroma.Workers.Cron.DigestEmailsWorker},
|
{"0 0 * * 0", Pleroma.Workers.Cron.DigestEmailsWorker},
|
||||||
{"0 0 * * *", Pleroma.Workers.Cron.NewUsersDigestWorker},
|
{"0 0 * * *", Pleroma.Workers.Cron.NewUsersDigestWorker},
|
||||||
|
|
|
||||||
|
|
@ -76,35 +76,51 @@ $EDITOR /etc/pleroma/config.exs
|
||||||
```
|
```
|
||||||
## Installing the release
|
## Installing the release
|
||||||
Before proceeding, get the flavour from [Detecting flavour](otp_en.md#detecting-flavour) section in OTP installation guide.
|
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
|
```sh
|
||||||
# Delete all files in pleroma user's directory
|
|
||||||
rm -r ~pleroma/*
|
rm -r ~pleroma/*
|
||||||
|
```
|
||||||
|
|
||||||
# Set the flavour environment variable to the string you got in Detecting flavour section.
|
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
|
For example if the flavour is `amd64-musl` the command will be:
|
||||||
|
|
||||||
|
```sh
|
||||||
export FLAVOUR="amd64-musl"
|
export FLAVOUR="amd64-musl"
|
||||||
|
```
|
||||||
|
|
||||||
# Clone the release build into a temporary directory and unpack it
|
Clone the release build into a temporary directory and unpack it.
|
||||||
# Replace `stable` with `unstable` if you want to run the unstable branch
|
Replace `stable` with `develop`, if you want to run the develop 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/
|
|
||||||
"
|
|
||||||
|
|
||||||
# Move the release to the home directory and delete temporary files
|
```sh
|
||||||
sudo -Hu pleroma "
|
sudo -Hu pleroma curl "https://git.pleroma.social/api/packages/pleroma/generic/pleroma-otp-stable-$FLAVOUR/latest/pleroma.zip" -o /tmp/pleroma.zip
|
||||||
mv /tmp/release/* ~pleroma/
|
sudo -Hu pleroma unzip /tmp/pleroma.zip -d /tmp/
|
||||||
rmdir /tmp/release
|
```
|
||||||
rm /tmp/pleroma.zip
|
|
||||||
"
|
|
||||||
|
|
||||||
# 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"
|
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
|
sleep 20 && curl http://localhost:4000/api/v1/instance
|
||||||
|
```
|
||||||
|
|
||||||
# Stop the instance
|
Stop the instance:
|
||||||
|
|
||||||
|
```sh
|
||||||
sudo -Hu pleroma "./bin/pleroma stop"
|
sudo -Hu pleroma "./bin/pleroma stop"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -130,60 +130,90 @@ Restart PostgreSQL to apply configuration changes:
|
||||||
```
|
```
|
||||||
|
|
||||||
### Installing Pleroma
|
### Installing Pleroma
|
||||||
|
Create a Pleroma user:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# Create a Pleroma user
|
|
||||||
adduser --system --shell /bin/false --home /opt/pleroma pleroma
|
adduser --system --shell /bin/false --home /opt/pleroma pleroma
|
||||||
|
```
|
||||||
|
|
||||||
# Set the flavour environment variable to the string you got in Detecting flavour section.
|
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:
|
||||||
# For example if the flavour is `amd64-musl` the command will be
|
|
||||||
|
```sh
|
||||||
export FLAVOUR="amd64-musl"
|
export FLAVOUR="amd64-musl"
|
||||||
|
```
|
||||||
|
|
||||||
# Clone the release build into a temporary directory and unpack it
|
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/
|
|
||||||
"
|
|
||||||
|
|
||||||
# Move the release to the home directory and delete temporary files
|
```sh
|
||||||
sudo -Hu pleroma "
|
sudo -Hu pleroma curl "https://git.pleroma.social/api/packages/pleroma/generic/pleroma-otp-stable-$FLAVOUR/latest/pleroma.zip" -o /tmp/pleroma.zip
|
||||||
mv /tmp/release/* /opt/pleroma
|
sudo -Hu pleroma unzip /tmp/pleroma.zip -d /tmp/
|
||||||
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
|
|
||||||
|
|
||||||
|
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
|
mkdir -p /var/lib/pleroma/uploads
|
||||||
chown -R pleroma /var/lib/pleroma
|
chown -R pleroma /var/lib/pleroma
|
||||||
|
```
|
||||||
|
|
||||||
# Create custom public files directory (custom emojis, frontend bundle overrides, robots.txt, etc.)
|
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
|
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
|
mkdir -p /var/lib/pleroma/static
|
||||||
chown -R pleroma /var/lib/pleroma
|
chown -R pleroma /var/lib/pleroma
|
||||||
|
```
|
||||||
|
|
||||||
# Create a config directory
|
Create a config directory:
|
||||||
|
|
||||||
|
```sh
|
||||||
mkdir -p /etc/pleroma
|
mkdir -p /etc/pleroma
|
||||||
chown -R pleroma /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"
|
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"
|
sudo -u postgres -s $SHELL -lc "psql -f /tmp/setup_db.psql"
|
||||||
|
|
||||||
# Create the database schema
|
|
||||||
sudo -Hu pleroma "./bin/pleroma_ctl migrate"
|
sudo -Hu pleroma "./bin/pleroma_ctl migrate"
|
||||||
|
```
|
||||||
|
|
||||||
# If you have installed RUM indexes uncommend and run
|
(Optional) If you have installed RUM indexes:
|
||||||
# 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_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"
|
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
|
sleep 20 && curl http://localhost:4000/api/v1/instance
|
||||||
|
```
|
||||||
|
|
||||||
# Stop the instance
|
Stop the instance:
|
||||||
|
|
||||||
|
```sh
|
||||||
sudo -Hu pleroma "./bin/pleroma stop"
|
sudo -Hu pleroma "./bin/pleroma stop"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ defmodule Pleroma.ReverseProxy do
|
||||||
@max_read_duration :timer.seconds(30)
|
@max_read_duration :timer.seconds(30)
|
||||||
@max_body_length :infinity
|
@max_body_length :infinity
|
||||||
@failed_request_ttl :timer.seconds(60)
|
@failed_request_ttl :timer.seconds(60)
|
||||||
@sniff_bytes 8 * 1024
|
|
||||||
@methods ~w(GET HEAD)
|
@methods ~w(GET HEAD)
|
||||||
|
|
||||||
@allowed_mime_types Pleroma.Config.get([Pleroma.Upload, :allowed_mime_types], [])
|
@allowed_mime_types Pleroma.Config.get([Pleroma.Upload, :allowed_mime_types], [])
|
||||||
|
|
@ -70,12 +69,7 @@ defmodule Pleroma.ReverseProxy do
|
||||||
* `inline_content_types`:
|
* `inline_content_types`:
|
||||||
* `true` will not alter `content-disposition` (up to the upstream),
|
* `true` will not alter `content-disposition` (up to the upstream),
|
||||||
* `false` will add `content-disposition: attachment` to any request,
|
* `false` will add `content-disposition: attachment` to any request,
|
||||||
* a list of whitelisted content types for which `content-disposition: inline`
|
* a list of whitelisted content types
|
||||||
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`.
|
|
||||||
|
|
||||||
* `req_headers`, `resp_headers` additional headers.
|
* `req_headers`, `resp_headers` additional headers.
|
||||||
|
|
||||||
|
|
@ -112,7 +106,6 @@ defmodule Pleroma.ReverseProxy do
|
||||||
| {:req_headers, [{String.t(), String.t()}]}
|
| {:req_headers, [{String.t(), String.t()}]}
|
||||||
| {:resp_headers, [{String.t(), String.t()}]}
|
| {:resp_headers, [{String.t(), String.t()}]}
|
||||||
| {:inline_content_types, boolean() | list(String.t())}
|
| {:inline_content_types, boolean() | list(String.t())}
|
||||||
| {:sniff_content_type, boolean()}
|
|
||||||
| {:redirect_on_failure, boolean()}
|
| {:redirect_on_failure, boolean()}
|
||||||
|
|
||||||
@spec call(Plug.Conn.t(), String.t(), list(option())) :: Plug.Conn.t()
|
@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
|
defp response(conn, client, url, status, headers, opts) do
|
||||||
Logger.debug("#{__MODULE__} #{status} #{url} #{inspect(headers)}")
|
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 =
|
result =
|
||||||
conn
|
conn
|
||||||
|> put_resp_headers(build_resp_headers(headers, opts))
|
|> put_resp_headers(build_resp_headers(headers, opts))
|
||||||
|> send_chunked(status)
|
|> send_chunked(status)
|
||||||
|> chunk_reply(client, opts, prefetched)
|
|> chunk_reply(client, opts)
|
||||||
|
|
||||||
case result do
|
case result do
|
||||||
{:ok, conn} ->
|
{:ok, conn} ->
|
||||||
|
|
@ -272,29 +246,18 @@ defmodule Pleroma.ReverseProxy do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp chunk_reply(conn, client, opts, :none) do
|
defp chunk_reply(conn, client, opts) do
|
||||||
chunk_reply(conn, client, opts, 0, 0)
|
chunk_reply(conn, client, opts, 0, 0)
|
||||||
end
|
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
|
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),
|
sent_so_far = sent_so_far + byte_size(data),
|
||||||
:ok <-
|
:ok <-
|
||||||
body_size_constraint(
|
body_size_constraint(
|
||||||
|
|
@ -310,24 +273,6 @@ defmodule Pleroma.ReverseProxy do
|
||||||
end
|
end
|
||||||
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
|
defp write_chunk(conn, data) do
|
||||||
case chunk(conn, data) do
|
case chunk(conn, data) do
|
||||||
{:error, error} -> {:error, {:downstream, error}}
|
{:error, error} -> {:error, {:downstream, error}}
|
||||||
|
|
@ -335,54 +280,6 @@ defmodule Pleroma.ReverseProxy do
|
||||||
end
|
end
|
||||||
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
|
defp head_response(conn, url, code, headers, opts) do
|
||||||
Logger.debug("#{__MODULE__} #{code} #{url} #{inspect(headers)}")
|
Logger.debug("#{__MODULE__} #{code} #{url} #{inspect(headers)}")
|
||||||
|
|
||||||
|
|
@ -430,33 +327,16 @@ defmodule Pleroma.ReverseProxy do
|
||||||
|> build_req_range_or_encoding_header(opts)
|
|> build_req_range_or_encoding_header(opts)
|
||||||
|> build_req_user_agent_header(opts)
|
|> build_req_user_agent_header(opts)
|
||||||
|> merge_headers(Keyword.get(opts, :req_headers, []))
|
|> 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
|
end
|
||||||
|
|
||||||
# Disable content-encoding if any @range_headers are requested (see #1823).
|
# Disable content-encoding if any @range_headers are requested (see #1823).
|
||||||
defp build_req_range_or_encoding_header(headers, _opts) do
|
defp build_req_range_or_encoding_header(headers, _opts) do
|
||||||
range? = Enum.any?(headers, fn {header, _} -> Enum.member?(@range_headers, header) end)
|
range? = Enum.any?(headers, fn {header, _} -> Enum.member?(@range_headers, header) end)
|
||||||
|
|
||||||
cond do
|
if range? && List.keymember?(headers, "accept-encoding", 0) do
|
||||||
range? && List.keymember?(headers, "accept-encoding", 0) ->
|
List.keydelete(headers, "accept-encoding", 0)
|
||||||
List.keydelete(headers, "accept-encoding", 0)
|
else
|
||||||
|
headers
|
||||||
true ->
|
|
||||||
headers
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -479,6 +359,12 @@ defmodule Pleroma.ReverseProxy do
|
||||||
|> ensure_no_transform()
|
|> ensure_no_transform()
|
||||||
end
|
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
|
defp ensure_no_transform(headers) do
|
||||||
{_, cache_control} =
|
{_, cache_control} =
|
||||||
List.keyfind(headers, "cache-control", 0, {"cache-control", @default_cache_control_header})
|
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)
|
replace_header(headers, "content-disposition", disposition)
|
||||||
else
|
else
|
||||||
if opt == true do
|
headers
|
||||||
headers
|
|
||||||
else
|
|
||||||
name = inline_filename(content_type)
|
|
||||||
|
|
||||||
disposition =
|
|
||||||
if name do
|
|
||||||
"inline; filename=\"#{name}\""
|
|
||||||
else
|
|
||||||
"inline"
|
|
||||||
end
|
|
||||||
|
|
||||||
replace_header(headers, "content-disposition", disposition)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -589,13 +462,6 @@ defmodule Pleroma.ReverseProxy do
|
||||||
[{key, value} | Enum.reject(headers, fn {header, _} -> header == key end)]
|
[{key, value} | Enum.reject(headers, fn {header, _} -> header == key end)]
|
||||||
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
|
defp header_length_constraint(headers, limit) do
|
||||||
lengths =
|
lengths =
|
||||||
for {"content-length", value} <- headers,
|
for {"content-length", value} <- headers,
|
||||||
|
|
@ -640,9 +506,7 @@ defmodule Pleroma.ReverseProxy do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp check_read_duration(_, _), do: {:ok, :no_duration_limit}
|
defp check_read_duration(_, _), do: {:ok, :no_duration_limit, :no_duration_limit}
|
||||||
|
|
||||||
defp increase_read_duration(:no_duration_limit), do: {:ok, :no_duration_limit}
|
|
||||||
|
|
||||||
defp increase_read_duration({previous_duration, started})
|
defp increase_read_duration({previous_duration, started})
|
||||||
when is_integer(previous_duration) and is_integer(started) do
|
when is_integer(previous_duration) and is_integer(started) do
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.Account
|
alias Pleroma.Web.ApiSpec.Schemas.Account
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.ApiError
|
alias Pleroma.Web.ApiSpec.Schemas.ApiError
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
|
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
|
||||||
|
alias Pleroma.Web.ApiSpec.Schemas.ChatMessage
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.Status
|
alias Pleroma.Web.ApiSpec.Schemas.Status
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.VisibilityScope
|
alias Pleroma.Web.ApiSpec.Schemas.VisibilityScope
|
||||||
|
|
||||||
|
|
@ -304,7 +305,25 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do
|
||||||
page_max_id: %Schema{type: :string, nullable: true},
|
page_max_id: %Schema{type: :string, nullable: true},
|
||||||
latest_page_notification_at: %Schema{type: :string, format: :"date-time", nullable: true},
|
latest_page_notification_at: %Schema{type: :string, format: :"date-time", nullable: true},
|
||||||
sample_account_ids: %Schema{type: :array, items: %Schema{type: :string}},
|
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: [
|
required: [
|
||||||
:group_key,
|
:group_key,
|
||||||
|
|
|
||||||
|
|
@ -101,13 +101,13 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
|
||||||
|> Enum.filter(& &1)
|
|> Enum.filter(& &1)
|
||||||
|> Enum.uniq_by(& &1[:id])
|
|> Enum.uniq_by(& &1[:id])
|
||||||
|
|
||||||
actors =
|
accounts =
|
||||||
notification_groups
|
notification_groups
|
||||||
|> List.flatten()
|
|> 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,
|
statuses: statuses,
|
||||||
notification_groups:
|
notification_groups:
|
||||||
Enum.map(
|
Enum.map(
|
||||||
|
|
@ -191,7 +191,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
|
||||||
|
|
||||||
defp render_group(
|
defp render_group(
|
||||||
[%Notification{} = notification | _] = notifications,
|
[%Notification{} = notification | _] = notifications,
|
||||||
_reading_user,
|
reading_user,
|
||||||
grouped_types,
|
grouped_types,
|
||||||
notification_group_counts,
|
notification_group_counts,
|
||||||
notification_group_bounds,
|
notification_group_bounds,
|
||||||
|
|
@ -237,13 +237,49 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
|
||||||
response
|
response
|
||||||
end
|
end
|
||||||
|
|
||||||
if status_activity do
|
response =
|
||||||
Map.put(response, :status_id, to_string(status_activity.id))
|
if status_activity do
|
||||||
else
|
Map.put(response, :status_id, to_string(status_activity.id))
|
||||||
response
|
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
|
||||||
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
|
defp status_activity_for_group([%Notification{} = notification | _], grouped_types) do
|
||||||
status_activity_for(notification, grouped_types)
|
status_activity_for(notification, grouped_types)
|
||||||
end
|
end
|
||||||
|
|
@ -287,6 +323,19 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
|
||||||
|> Enum.uniq_by(& &1.id)
|
|> Enum.uniq_by(& &1.id)
|
||||||
end
|
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
|
defp put_emoji(response, activity) do
|
||||||
response
|
response
|
||||||
|> Map.put(:emoji, activity.data["content"])
|
|> Map.put(:emoji, activity.data["content"])
|
||||||
|
|
|
||||||
|
|
@ -631,7 +631,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
||||||
String.contains?(media_type, "image") -> "image"
|
String.contains?(media_type, "image") -> "image"
|
||||||
String.contains?(media_type, "video") -> "video"
|
String.contains?(media_type, "video") -> "video"
|
||||||
String.contains?(media_type, "audio") -> "audio"
|
String.contains?(media_type, "audio") -> "audio"
|
||||||
attachment["type"] == "Image" -> "image"
|
|
||||||
true -> "unknown"
|
true -> "unknown"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -208,7 +208,6 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyController do
|
||||||
|
|
||||||
defp media_proxy_opts do
|
defp media_proxy_opts do
|
||||||
Config.get([:media_proxy, :proxy_opts], [])
|
Config.get([:media_proxy, :proxy_opts], [])
|
||||||
|> Keyword.put_new(:sniff_content_type, true)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp sandbox(conn, _params) do
|
defp sandbox(conn, _params) do
|
||||||
|
|
|
||||||
8
mix.exs
8
mix.exs
|
|
@ -172,6 +172,14 @@ defmodule Pleroma.Mixfile do
|
||||||
{:gen_smtp, "~> 0.15"},
|
{:gen_smtp, "~> 0.15"},
|
||||||
{:mua, "~> 0.2.4"},
|
{:mua, "~> 0.2.4"},
|
||||||
{:mail, "~> 0.3.1"},
|
{: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"},
|
{:ex_syslogger, "~> 1.5"},
|
||||||
{:floki, "~> 0.38"},
|
{:floki, "~> 0.38"},
|
||||||
{:timex, "~> 3.7"},
|
{:timex, "~> 3.7"},
|
||||||
|
|
|
||||||
2
mix.lock
2
mix.lock
|
|
@ -139,7 +139,7 @@
|
||||||
"statistex": {:hex, :statistex, "1.1.0", "7fec1eb2f580a0d2c1a05ed27396a084ab064a40cfc84246dbfb0c72a5c761e5", [:mix], [], "hexpm", "f5950ea26ad43246ba2cce54324ac394a4e7408fdcf98b8e230f503a0cba9cf5"},
|
"statistex": {:hex, :statistex, "1.1.0", "7fec1eb2f580a0d2c1a05ed27396a084ab064a40cfc84246dbfb0c72a5c761e5", [:mix], [], "hexpm", "f5950ea26ad43246ba2cce54324ac394a4e7408fdcf98b8e230f503a0cba9cf5"},
|
||||||
"sweet_xml": {:hex, :sweet_xml, "0.7.5", "803a563113981aaac202a1dbd39771562d0ad31004ddbfc9b5090bdcd5605277", [:mix], [], "hexpm", "193b28a9b12891cae351d81a0cead165ffe67df1b73fe5866d10629f4faefb12"},
|
"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"},
|
"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"},
|
"table_rex": {:hex, :table_rex, "4.1.0", "fbaa8b1ce154c9772012bf445bfb86b587430fb96f3b12022d3f35ee4a68c918", [:mix], [], "hexpm", "95932701df195d43bc2d1c6531178fc8338aa8f38c80f098504d529c43bc2601"},
|
||||||
"telemetry": {:hex, :telemetry, "1.0.0", "0f453a102cdf13d506b7c0ab158324c337c41f1cc7548f0bc0e130bbf0ae9452", [:rebar3], [], "hexpm", "73bc09fa59b4a0284efb4624335583c528e07ec9ae76aca96ea0673850aec57a"},
|
"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"},
|
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.2", "2caabe9344ec17eafe5403304771c3539f3b6e2f7fb6a6f602558c825d0d0bfb", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9b43db0dc33863930b9ef9d27137e78974756f5f198cae18409970ed6fa5b561"},
|
||||||
|
|
|
||||||
|
|
@ -579,56 +579,6 @@ defmodule Pleroma.ReverseProxyTest do
|
||||||
assert Conn.get_resp_header(conn, "content-type") == ["application/octet-stream"]
|
assert Conn.get_resp_header(conn, "content-type") == ["application/octet-stream"]
|
||||||
end
|
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
|
test "preserves a generic content type for a non-image body", %{conn: conn} do
|
||||||
body = "not an image"
|
body = "not an image"
|
||||||
|
|
||||||
|
|
@ -823,24 +773,6 @@ defmodule Pleroma.ReverseProxyTest do
|
||||||
conn = ReverseProxy.call(conn, "/disposition")
|
conn = ReverseProxy.call(conn, "/disposition")
|
||||||
|
|
||||||
assert {"content-type", "image/gif"} in conn.resp_headers
|
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
|
end
|
||||||
|
|
||||||
test "with content-disposition header", %{conn: conn} do
|
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
|
assert {"content-disposition", "attachment; filename=\"filename.jpg\""} in conn.resp_headers
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
describe "content-type sanitisation" do
|
describe "content-type sanitisation" do
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,15 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
|
||||||
}
|
}
|
||||||
|
|
||||||
test_notifications_rendering([notification], recipient, [expected])
|
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
|
end
|
||||||
|
|
||||||
test "Mention notification" do
|
test "Mention notification" do
|
||||||
|
|
@ -182,6 +191,16 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
|
||||||
}
|
}
|
||||||
|
|
||||||
test_notifications_rendering([notification], follower, [expected])
|
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
|
end
|
||||||
|
|
||||||
test "EmojiReact notification" do
|
test "EmojiReact notification" do
|
||||||
|
|
@ -210,6 +229,13 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
|
||||||
}
|
}
|
||||||
|
|
||||||
test_notifications_rendering([notification], user, [expected])
|
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
|
end
|
||||||
|
|
||||||
test "EmojiReact custom emoji notification" do
|
test "EmojiReact custom emoji notification" do
|
||||||
|
|
@ -295,6 +321,15 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
|
||||||
}
|
}
|
||||||
|
|
||||||
test_notifications_rendering([notification], moderator_user, [expected])
|
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
|
end
|
||||||
|
|
||||||
test "Edit notification" do
|
test "Edit notification" do
|
||||||
|
|
|
||||||
|
|
@ -668,23 +668,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
|
||||||
assert expected == StatusView.render("attachment.json", %{attachment: object})
|
assert expected == StatusView.render("attachment.json", %{attachment: object})
|
||||||
assert_schema(expected, "Attachment", api_spec)
|
assert_schema(expected, "Attachment", api_spec)
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
test "put the url advertised in the Activity in to the url attribute" do
|
test "put the url advertised in the Activity in to the url attribute" do
|
||||||
|
|
|
||||||
|
|
@ -71,10 +71,7 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
|
||||||
|
|
||||||
test "it performs ReverseProxy.call with valid signature", %{conn: conn, url: url} do
|
test "it performs ReverseProxy.call with valid signature", %{conn: conn, url: url} do
|
||||||
with_mock Pleroma.ReverseProxy,
|
with_mock Pleroma.ReverseProxy,
|
||||||
call: fn _conn, _url, opts ->
|
call: fn _conn, _url, _opts -> %Conn{status: :success} end do
|
||||||
assert opts[:sniff_content_type]
|
|
||||||
%Conn{status: :success}
|
|
||||||
end do
|
|
||||||
assert %Conn{status: :success} = get(conn, url)
|
assert %Conn{status: :success} = get(conn, url)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue