Compare commits
42 commits
8d82808d7a
...
521fc70e48
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
521fc70e48 | ||
|
|
f4a8c426df | ||
|
|
6439a5b334 | ||
|
|
0b813b9c4a | ||
|
|
029994aa75 | ||
|
|
820a4cd97c | ||
|
|
ad5bb02bd6 | ||
|
|
cb389e788d | ||
|
|
ba280b2d0f | ||
|
|
861a9f9365 | ||
|
|
519ef4be5e | ||
|
|
f6c410b06c | ||
|
|
f16dad2879 | ||
|
|
421187dbfa | ||
|
|
ac6ec02725 | ||
|
|
af4bed50e6 | ||
|
|
033083d1d1 | ||
|
|
343e42126a | ||
|
|
b2be7d48bc | ||
|
|
02185ec711 | ||
|
|
7283d4f9be | ||
|
|
6a81e4fe00 | ||
|
|
520bac27dc | ||
|
|
5068e31583 | ||
|
|
c07506ab6e | ||
|
|
3d7d119782 | ||
|
|
b013ec9123 | ||
|
|
7ce7d4d319 | ||
|
|
33b8ccf21f | ||
|
|
b552c25039 | ||
|
|
72fea0c901 | ||
|
|
1085f6d7cd | ||
|
|
89ac0b8f0a | ||
|
|
65456aed12 | ||
|
|
5600634574 | ||
|
|
e40bedc601 | ||
|
|
8936066427 | ||
|
|
71a4b8d0f2 | ||
|
|
f2ad6100f2 | ||
|
|
500340fc82 | ||
|
|
b85507c764 | ||
|
|
01d94a0135 |
86 changed files with 1646 additions and 160 deletions
1
changelog.d/emoji-reaction-url-escape.fix
Normal file
1
changelog.d/emoji-reaction-url-escape.fix
Normal file
|
|
@ -0,0 +1 @@
|
|||
Encode custom emoji URLs in EmojiReact activity tags.
|
||||
1
changelog.d/hackney-mediaproxy.change
Normal file
1
changelog.d/hackney-mediaproxy.change
Normal file
|
|
@ -0,0 +1 @@
|
|||
Use a custom redirect handler to ensure MediaProxy redirects are followed with Hackney
|
||||
1
changelog.d/hackney.change
Normal file
1
changelog.d/hackney.change
Normal file
|
|
@ -0,0 +1 @@
|
|||
Update Hackney, the default HTTP client, to the latest release which supports Happy Eyeballs for improved IPv6 federation
|
||||
1
changelog.d/instance-domain-blocks.add
Normal file
1
changelog.d/instance-domain-blocks.add
Normal file
|
|
@ -0,0 +1 @@
|
|||
Add v1/instance/domain_blocks endpoint
|
||||
1
changelog.d/oauth-registration-redirect_uris.fix
Normal file
1
changelog.d/oauth-registration-redirect_uris.fix
Normal file
|
|
@ -0,0 +1 @@
|
|||
Fix OAuth app registration to accept `redirect_uris` as an array of strings (RFC 7591), while keeping backwards compatibility with string input.
|
||||
1
changelog.d/oban-web.add
Normal file
1
changelog.d/oban-web.add
Normal file
|
|
@ -0,0 +1 @@
|
|||
Added Oban Web dashboard located at /pleroma/oban
|
||||
1
changelog.d/paginate-follow-requests.change
Normal file
1
changelog.d/paginate-follow-requests.change
Normal file
|
|
@ -0,0 +1 @@
|
|||
Paginate follow requests
|
||||
1
changelog.d/phoenix-livedashboard-move.change
Normal file
1
changelog.d/phoenix-livedashboard-move.change
Normal file
|
|
@ -0,0 +1 @@
|
|||
Moved Phoenix LiveDashboard to /pleroma/live_dashboard
|
||||
1
changelog.d/reduce-flaky-tests.skip
Normal file
1
changelog.d/reduce-flaky-tests.skip
Normal file
|
|
@ -0,0 +1 @@
|
|||
Reduce the number of flaky tests by making them sync if they affect the global state, and silence noisy test output.
|
||||
1
changelog.d/release-to-docker.add
Normal file
1
changelog.d/release-to-docker.add
Normal file
|
|
@ -0,0 +1 @@
|
|||
Add instructions on how to run a release in docker, to make it easier to run on older distros.
|
||||
1
changelog.d/vix-0.36.0.fix
Normal file
1
changelog.d/vix-0.36.0.fix
Normal file
|
|
@ -0,0 +1 @@
|
|||
Fix compilation with vips-8.18.0 with bumping to vix 0.36.0
|
||||
|
|
@ -102,7 +102,6 @@ config :pleroma, :http, send_user_agent: false
|
|||
|
||||
rum_enabled = System.get_env("RUM_ENABLED") == "true"
|
||||
config :pleroma, :database, rum_enabled: rum_enabled
|
||||
IO.puts("RUM enabled: #{rum_enabled}")
|
||||
|
||||
config :joken, default_signer: "yU8uHKq+yyAkZ11Hx//jcdacWc8yQ1bxAAGrplzB0Zwwjkp35v0RK9SO8WTPr6QZ"
|
||||
|
||||
|
|
@ -192,7 +191,7 @@ config :pleroma, Pleroma.Application,
|
|||
streamer_registry: false,
|
||||
test_http_pools: true
|
||||
|
||||
config :pleroma, Pleroma.Web.Streaming, sync_streaming: true
|
||||
config :pleroma, Pleroma.Web.Streamer, sync_streaming: true
|
||||
|
||||
config :pleroma, Pleroma.Uploaders.Uploader, timeout: 1_000
|
||||
|
||||
|
|
@ -207,8 +206,9 @@ config :pleroma, Pleroma.User.Backup, tempdir: "test/tmp"
|
|||
|
||||
if File.exists?("./config/test.secret.exs") do
|
||||
import_config "test.secret.exs"
|
||||
else
|
||||
IO.puts(
|
||||
"You may want to create test.secret.exs to declare custom database connection parameters."
|
||||
)
|
||||
end
|
||||
|
||||
# Avoid noisy shutdown logs from os_mon during tests.
|
||||
config :os_mon,
|
||||
start_cpu_sup: false,
|
||||
start_memsup: false
|
||||
|
|
|
|||
47
docs/administration/dashboards.md
Normal file
47
docs/administration/dashboards.md
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# Dashboards
|
||||
|
||||
Pleroma comes with two types of backend dashboards viewable to instance administrators:
|
||||
|
||||
* [Phoenix LiveDashboard](https://hexdocs.pm/phoenix_live_dashboard/Phoenix.LiveDashboard.html) - A general system oriented dashboard for viewing statistics about Pleroma resource consumption, Pleroma's database and Pleroma's job processor (Oban).
|
||||
* [Oban Web](https://hexdocs.pm/oban_web/overview.html) - A dashboard specific to Oban for viewing Oban statistics, managing jobs and job queues.
|
||||
|
||||
!!! note
|
||||
Both dashboards require working Websockets.
|
||||
If your browser or web server don't support Websockets, both dashboards either won't update or will not display all information.
|
||||
|
||||
## Phoenix LiveDashboard
|
||||
|
||||
Instance administrators can access this dashboard at `/pleroma/live_dashboard`, giving a simple overview of software versions including Erlang and Elixir versions, instance uptime and resource consumption.
|
||||
|
||||
This dashboard gives insights into the current state of the BEAM VM running Pleroma code and database statistics including basic diagnostics.
|
||||
It can be useful for troubleshooting of some issues namely regarding database performance.
|
||||
|
||||
### Relevant dashboard tabs
|
||||
|
||||
* Home - A general overview of system information including software versions, uptime and memory BEAM memory consumption.
|
||||
* OS Data - Information about the OS and system such as CPU load, memory usage and disk usage.
|
||||
* Ecto Stats - Information about the Pleroma database.
|
||||
- Diagnose - Basic database diagnostics, including a `bloat` warning when an index or a table have excessive bloat, which can lead to bad database performance.
|
||||
- Bloat - A table showing size of "bloat" (unused wasted space) in database tables and indexes. Very high bloat size in the `activities` and `objects` tables can lead to bad performance especially on slower disks such as on most VPS providers.
|
||||
- Db settings - A small list of PostgreSQL settings mostly relevant to database performance.
|
||||
- Total table size - Shows sizes of all database tables including indexes sorted by size, useful for quickly checking overall database size.
|
||||
- Long running queries - A list of of slow database queries and their duration. Multiple entries with duration in multiple seconds indicate a slowly performing database.
|
||||
* Oban - Shows a list of all Oban jobs.
|
||||
|
||||
!!! note
|
||||
The DB bloat warning for `index 'oban_jobs::oban_jobs_args_index'` in Ecto Stats can be safely ignored.
|
||||
|
||||
## Oban Web
|
||||
|
||||
An advanced dashboard and management console viewable to instance administrators specifically for Oban, Pleroma's job processor.
|
||||
It allows managing jobs, including force retrying failed jobs and job deletion.
|
||||
It can be accessed at `/pleroma/oban`.
|
||||
|
||||
!!! danger
|
||||
This dashboard is very powerful! If you are unsure what a certain feature does, don't use it.
|
||||
Changing individual queue state/settings in the "Queues" view is heavily discouraged.
|
||||
|
||||
* Shows a real time chart of either a number of executed jobs, or job execution/wait time per a given time frame and the state/queue/worker.
|
||||
* Shows a list of jobs in each state, their argument, number of attempts and execution/scheduled time.
|
||||
* Selecting one or multiple jobs in the list allows performing actions like canceling/deleting and retrying.
|
||||
* Clicking on a job shows a detailed view including the full argument, when it was inserted, information about its attempts, and performing actions on it.
|
||||
|
|
@ -13,6 +13,9 @@ You will be running commands as root. If you aren't root already, please elevate
|
|||
|
||||
Similarly to other binaries, OTP releases tend to be only compatible with the distro they are built on, as such this guide focuses only on Debian/Ubuntu and Alpine.
|
||||
|
||||
!!! note
|
||||
If you get `GLIBC_... not found` errors on Debian/Ubuntu, you can run the OTP release from `/opt/pleroma` inside a newer distro container without upgrading the host. See [`release_to_docker_en.md`](release_to_docker_en.md).
|
||||
|
||||
### Detecting flavour
|
||||
|
||||
Paste the following into the shell:
|
||||
|
|
|
|||
61
docs/installation/release_to_docker_en.md
Normal file
61
docs/installation/release_to_docker_en.md
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
# Running OTP releases via Docker (glibc shim)
|
||||
|
||||
Pleroma OTP releases are built on specific distros. If your host OS is older than
|
||||
the build environment, you may hit runtime linker errors such as:
|
||||
|
||||
```
|
||||
/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.38' not found
|
||||
```
|
||||
|
||||
If you don't want to upgrade your host OS, you can run the existing OTP release
|
||||
from `/opt/pleroma` inside an Ubuntu 24.04 container while keeping your existing
|
||||
host config and data directories.
|
||||
|
||||
This approach uses a small "shim" container image to provide a newer `glibc`.
|
||||
It is **not** the official Pleroma Docker image.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Docker Engine + the Docker Compose plugin on the host
|
||||
- Root access (or equivalent access to the Docker socket)
|
||||
- Existing OTP release in `/opt/pleroma`
|
||||
- Existing config in `/etc/pleroma` and data in `/var/lib/pleroma`
|
||||
|
||||
## Setup
|
||||
|
||||
1. Copy the provided templates:
|
||||
|
||||
```sh
|
||||
mkdir -p /etc/pleroma/container
|
||||
cp -a /opt/pleroma/installation/release-to-docker/* /etc/pleroma/container/
|
||||
```
|
||||
|
||||
2. Build the shim image:
|
||||
|
||||
```sh
|
||||
cd /etc/pleroma/container
|
||||
docker compose build
|
||||
```
|
||||
|
||||
3. Replace your systemd unit:
|
||||
|
||||
```sh
|
||||
cp /etc/pleroma/container/pleroma.service /etc/systemd/system/pleroma.service
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now pleroma
|
||||
journalctl -u pleroma -f
|
||||
```
|
||||
|
||||
## Running migrations / `pleroma_ctl`
|
||||
|
||||
Migrations are run automatically by default when the container starts. You can
|
||||
disable this by setting `PLEROMA_RUN_MIGRATIONS=0` in
|
||||
`/etc/pleroma/container/docker-compose.yml`.
|
||||
|
||||
To run admin commands inside the container:
|
||||
|
||||
```sh
|
||||
cd /etc/pleroma/container
|
||||
docker compose exec pleroma /opt/pleroma/bin/pleroma_ctl status
|
||||
docker compose run --rm --no-deps pleroma /opt/pleroma/bin/pleroma_ctl migrate
|
||||
```
|
||||
26
installation/release-to-docker/Dockerfile
Normal file
26
installation/release-to-docker/Dockerfile
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
FROM ubuntu:24.04
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive \
|
||||
LANG=C.UTF-8 \
|
||||
LC_ALL=C.UTF-8
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
gosu \
|
||||
libstdc++6 \
|
||||
libncurses6 libncursesw6 \
|
||||
openssl libssl3 \
|
||||
libmagic1t64 file \
|
||||
postgresql-client \
|
||||
ffmpeg imagemagick libimage-exiftool-perl \
|
||||
libvips42t64 \
|
||||
unzip \
|
||||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /opt/pleroma
|
||||
|
||||
COPY pleroma-host-release-entrypoint.sh /usr/local/bin/pleroma-host-release-entrypoint.sh
|
||||
RUN chmod +x /usr/local/bin/pleroma-host-release-entrypoint.sh
|
||||
ENTRYPOINT ["/usr/local/bin/pleroma-host-release-entrypoint.sh"]
|
||||
CMD ["/opt/pleroma/bin/pleroma", "start"]
|
||||
66
installation/release-to-docker/README.md
Normal file
66
installation/release-to-docker/README.md
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
# Run OTP releases on older glibc using Docker
|
||||
|
||||
Pleroma OTP releases are built on specific distros and may require a newer `glibc`
|
||||
than your host has. A typical failure looks like:
|
||||
|
||||
```
|
||||
... /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.38' not found ...
|
||||
```
|
||||
|
||||
If you don't want to upgrade your host OS, you can run the existing OTP release
|
||||
from `/opt/pleroma` inside an Ubuntu 24.04 container while keeping your existing
|
||||
host paths (`/etc/pleroma`, `/var/lib/pleroma`, etc.).
|
||||
|
||||
This folder provides a "shim" container + systemd unit. It is **not** the Pleroma
|
||||
Docker image.
|
||||
|
||||
## What this does
|
||||
|
||||
- Builds a small Ubuntu 24.04 image with runtime libs (including newer `glibc`).
|
||||
- Mounts your existing host release at `/opt/pleroma` into the container.
|
||||
- Runs as the same UID/GID that owns `/opt/pleroma` on the host (via `gosu`).
|
||||
- Optionally runs migrations automatically on container start.
|
||||
- Uses `network_mode: host` so your existing config that talks to `localhost`
|
||||
keeps working.
|
||||
|
||||
## Setup (Debian/Ubuntu host)
|
||||
|
||||
1. Install Docker Engine + the Docker Compose plugin.
|
||||
2. Copy these files to a stable location (example: `/etc/pleroma/container`):
|
||||
|
||||
```
|
||||
mkdir -p /etc/pleroma/container
|
||||
cp -a /opt/pleroma/installation/release-to-docker/* /etc/pleroma/container/
|
||||
```
|
||||
|
||||
3. Build the shim image:
|
||||
|
||||
```
|
||||
cd /etc/pleroma/container
|
||||
docker compose build
|
||||
```
|
||||
|
||||
4. Replace your systemd unit:
|
||||
|
||||
```
|
||||
cp /etc/pleroma/container/pleroma.service /etc/systemd/system/pleroma.service
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now pleroma
|
||||
journalctl -u pleroma -f
|
||||
```
|
||||
|
||||
## Running `pleroma_ctl`
|
||||
|
||||
Since the host binary may not run on older `glibc`, run admin commands inside the
|
||||
container:
|
||||
|
||||
```
|
||||
cd /etc/pleroma/container
|
||||
docker compose exec pleroma /opt/pleroma/bin/pleroma_ctl status
|
||||
docker compose run --rm --no-deps pleroma /opt/pleroma/bin/pleroma_ctl migrate
|
||||
```
|
||||
|
||||
## Configuration notes
|
||||
|
||||
- Migrations run automatically by default.
|
||||
- Set `PLEROMA_RUN_MIGRATIONS=0` in `docker-compose.yml` to disable.
|
||||
22
installation/release-to-docker/docker-compose.yml
Normal file
22
installation/release-to-docker/docker-compose.yml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
services:
|
||||
pleroma:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
image: pleroma-host-release-wrapper:ubuntu24
|
||||
init: true
|
||||
network_mode: host
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
HOME: /opt/pleroma
|
||||
LANG: C.UTF-8
|
||||
LC_ALL: C.UTF-8
|
||||
ELIXIR_ERL_OPTIONS: "+fnu"
|
||||
# Set to 0 to skip running migrations on container start.
|
||||
PLEROMA_RUN_MIGRATIONS: "1"
|
||||
volumes:
|
||||
# Existing OTP release installation (host)
|
||||
- /opt/pleroma:/opt/pleroma:rw
|
||||
# Existing config + uploads + static (host)
|
||||
- /etc/pleroma:/etc/pleroma:rw
|
||||
- /var/lib/pleroma:/var/lib/pleroma:rw
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
uid="${PLEROMA_UID:-}"
|
||||
gid="${PLEROMA_GID:-}"
|
||||
|
||||
if [[ -z "${uid}" || -z "${gid}" ]]; then
|
||||
uid="$(stat -c '%u' /opt/pleroma)"
|
||||
gid="$(stat -c '%g' /opt/pleroma)"
|
||||
fi
|
||||
|
||||
export HOME="${HOME:-/opt/pleroma}"
|
||||
|
||||
if [[ "${PLEROMA_RUN_MIGRATIONS:-1}" != "0" && "${1:-}" == "/opt/pleroma/bin/pleroma" && "${2:-}" == "start" ]]; then
|
||||
echo "Running migrations..."
|
||||
gosu "${uid}:${gid}" /opt/pleroma/bin/pleroma_ctl migrate
|
||||
fi
|
||||
|
||||
exec gosu "${uid}:${gid}" "$@"
|
||||
16
installation/release-to-docker/pleroma.service
Normal file
16
installation/release-to-docker/pleroma.service
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[Unit]
|
||||
Description=Pleroma social network (OTP release via Docker glibc shim)
|
||||
After=network.target docker.service postgresql.service nginx.service
|
||||
Requires=docker.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=/etc/pleroma/container
|
||||
ExecStart=/usr/bin/docker compose up --build --remove-orphans
|
||||
ExecStop=/usr/bin/docker compose down
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
TimeoutStartSec=0
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
@ -330,7 +330,13 @@ defmodule Mix.Tasks.Pleroma.Config do
|
|||
|> Enum.each(&write_and_delete(&1, file, opts[:delete]))
|
||||
|
||||
:ok = File.close(file)
|
||||
System.cmd("mix", ["format", path])
|
||||
|
||||
# Ensure `mix format` runs in the same env as the current task and doesn't
|
||||
# emit config-time stderr noise (e.g. dev secret warnings) into `mix test`.
|
||||
System.cmd("mix", ["format", path],
|
||||
env: [{"MIX_ENV", to_string(Mix.env())}],
|
||||
stderr_to_stdout: true
|
||||
)
|
||||
end
|
||||
|
||||
defp config_header, do: "import Config\r\n\r\n"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ defmodule Pleroma.Emoji do
|
|||
|
||||
alias Pleroma.Emoji.Combinations
|
||||
alias Pleroma.Emoji.Loader
|
||||
alias Pleroma.Utils.URIEncoding
|
||||
alias Pleroma.Web.Endpoint
|
||||
|
||||
require Logger
|
||||
|
||||
|
|
@ -189,6 +191,34 @@ defmodule Pleroma.Emoji do
|
|||
|
||||
def emoji_url(_), do: nil
|
||||
|
||||
@spec local_url(String.t() | nil) :: String.t() | nil
|
||||
def local_url(nil), do: nil
|
||||
|
||||
def local_url("http" <> _ = url) do
|
||||
URIEncoding.encode_url(url)
|
||||
end
|
||||
|
||||
def local_url("/" <> _ = path) do
|
||||
path = URIEncoding.encode_url(path, bypass_parse: true, bypass_decode: true)
|
||||
Endpoint.url() <> path
|
||||
end
|
||||
|
||||
def local_url(path) when is_binary(path) do
|
||||
local_url("/" <> path)
|
||||
end
|
||||
|
||||
def build_emoji_tag({name, url}) do
|
||||
url = URIEncoding.encode_url(url)
|
||||
|
||||
%{
|
||||
"icon" => %{"url" => "#{url}", "type" => "Image"},
|
||||
"name" => ":" <> name <> ":",
|
||||
"type" => "Emoji",
|
||||
"updated" => "1970-01-01T00:00:00Z",
|
||||
"id" => url
|
||||
}
|
||||
end
|
||||
|
||||
def emoji_name_with_instance(name, url) do
|
||||
url = url |> URI.parse() |> Map.get(:host)
|
||||
"#{name}@#{url}"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
defmodule Pleroma.Emoji.Formatter do
|
||||
alias Pleroma.Emoji
|
||||
alias Pleroma.HTML
|
||||
alias Pleroma.Web.Endpoint
|
||||
alias Pleroma.Web.MediaProxy
|
||||
|
||||
def emojify(text) do
|
||||
|
|
@ -44,7 +43,7 @@ defmodule Pleroma.Emoji.Formatter do
|
|||
Emoji.get_all()
|
||||
|> Enum.filter(fn {emoji, %Emoji{}} -> String.contains?(text, ":#{emoji}:") end)
|
||||
|> Enum.reduce(%{}, fn {name, %Emoji{file: file}}, acc ->
|
||||
Map.put(acc, name, to_string(URI.merge(Endpoint.url(), file)))
|
||||
Map.put(acc, name, Emoji.local_url(file))
|
||||
end)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -147,24 +147,22 @@ defmodule Pleroma.FollowingRelationship do
|
|||
|> Repo.aggregate(:count, :id)
|
||||
end
|
||||
|
||||
def get_follow_requests(%User{id: id}) do
|
||||
def get_follow_requests_query(%User{id: id}) do
|
||||
__MODULE__
|
||||
|> join(:inner, [r], f in assoc(r, :follower))
|
||||
|> join(:inner, [r], f in assoc(r, :follower), as: :follower)
|
||||
|> where([r], r.state == ^:follow_pending)
|
||||
|> where([r], r.following_id == ^id)
|
||||
|> where([r, f], f.is_active == true)
|
||||
|> select([r, f], f)
|
||||
|> Repo.all()
|
||||
|> where([r, follower: f], f.is_active == true)
|
||||
|> select([r, follower: f], f)
|
||||
end
|
||||
|
||||
def get_outgoing_follow_requests(%User{id: id}) do
|
||||
def get_outgoing_follow_requests_query(%User{id: id}) do
|
||||
__MODULE__
|
||||
|> join(:inner, [r], f in assoc(r, :following))
|
||||
|> join(:inner, [r], f in assoc(r, :following), as: :following)
|
||||
|> where([r], r.state == ^:follow_pending)
|
||||
|> where([r], r.follower_id == ^id)
|
||||
|> where([r, f], f.is_active == true)
|
||||
|> select([r, f], f)
|
||||
|> Repo.all()
|
||||
|> where([r, following: f], f.is_active == true)
|
||||
|> select([r, following: f], f)
|
||||
end
|
||||
|
||||
def following?(%User{id: follower_id}, %User{id: followed_id}) do
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@ defmodule Pleroma.HTTP.AdapterHelper.Hackney do
|
|||
@behaviour Pleroma.HTTP.AdapterHelper
|
||||
|
||||
@defaults [
|
||||
follow_redirect: true,
|
||||
force_redirect: true
|
||||
follow_redirect: false,
|
||||
force_redirect: false,
|
||||
with_body: true
|
||||
]
|
||||
|
||||
@spec options(keyword(), URI.t()) :: keyword()
|
||||
|
|
|
|||
|
|
@ -5,6 +5,23 @@
|
|||
defmodule Pleroma.ReverseProxy.Client.Hackney do
|
||||
@behaviour Pleroma.ReverseProxy.Client
|
||||
|
||||
# In-app redirect handler to avoid Hackney redirect bugs:
|
||||
# - https://github.com/benoitc/hackney/issues/527 (relative/protocol-less redirects can crash Hackney)
|
||||
# - https://github.com/benoitc/hackney/issues/273 (redirects not followed when using HTTP proxy)
|
||||
#
|
||||
# Based on a redirect handler from Pleb, slightly modified to work with Hackney:
|
||||
# https://declin.eu/objects/d4f38e62-5429-4614-86d1-e8fc16e6bf33
|
||||
@redirect_statuses [301, 302, 303, 307, 308]
|
||||
defp absolute_redirect_url(original_url, resp_headers) do
|
||||
location =
|
||||
Enum.find(resp_headers, fn {header, _location} ->
|
||||
String.downcase(header) == "location"
|
||||
end)
|
||||
|
||||
URI.merge(original_url, elem(location, 1))
|
||||
|> URI.to_string()
|
||||
end
|
||||
|
||||
@impl true
|
||||
def request(method, url, headers, body, opts \\ []) do
|
||||
opts =
|
||||
|
|
@ -12,7 +29,35 @@ defmodule Pleroma.ReverseProxy.Client.Hackney do
|
|||
path
|
||||
end)
|
||||
|
||||
:hackney.request(method, url, headers, body, opts)
|
||||
if opts[:follow_redirect] != false do
|
||||
{_state, req_opts} = Access.get_and_update(opts, :follow_redirect, fn a -> {a, false} end)
|
||||
res = :hackney.request(method, url, headers, body, req_opts)
|
||||
|
||||
case res do
|
||||
{:ok, code, resp_headers, _client} when code in @redirect_statuses ->
|
||||
:hackney.request(
|
||||
method,
|
||||
absolute_redirect_url(url, resp_headers),
|
||||
headers,
|
||||
body,
|
||||
req_opts
|
||||
)
|
||||
|
||||
{:ok, code, resp_headers} when code in @redirect_statuses ->
|
||||
:hackney.request(
|
||||
method,
|
||||
absolute_redirect_url(url, resp_headers),
|
||||
headers,
|
||||
body,
|
||||
req_opts
|
||||
)
|
||||
|
||||
_ ->
|
||||
res
|
||||
end
|
||||
else
|
||||
:hackney.request(method, url, headers, body, opts)
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
|
|
|
|||
|
|
@ -29,22 +29,26 @@ defmodule Pleroma.Upload.Filter.Exiftool.ReadDescription do
|
|||
do: current_description
|
||||
|
||||
defp read_when_empty(_, file, tag) do
|
||||
try do
|
||||
{tag_content, 0} =
|
||||
System.cmd("exiftool", ["-b", "-s3", tag, file],
|
||||
stderr_to_stdout: false,
|
||||
parallelism: true
|
||||
)
|
||||
if File.exists?(file) do
|
||||
try do
|
||||
{tag_content, 0} =
|
||||
System.cmd("exiftool", ["-m", "-b", "-s3", tag, file],
|
||||
stderr_to_stdout: false,
|
||||
parallelism: true
|
||||
)
|
||||
|
||||
tag_content = String.trim(tag_content)
|
||||
tag_content = String.trim(tag_content)
|
||||
|
||||
if tag_content != "" and
|
||||
String.length(tag_content) <=
|
||||
Pleroma.Config.get([:instance, :description_limit]),
|
||||
do: tag_content,
|
||||
else: nil
|
||||
rescue
|
||||
_ in ErlangError -> nil
|
||||
if tag_content != "" and
|
||||
String.length(tag_content) <=
|
||||
Pleroma.Config.get([:instance, :description_limit]),
|
||||
do: tag_content,
|
||||
else: nil
|
||||
rescue
|
||||
_ in ErlangError -> nil
|
||||
end
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -16,11 +16,12 @@ defmodule Pleroma.Upload.Filter.Exiftool.StripLocation do
|
|||
|
||||
def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _}) do
|
||||
try do
|
||||
case System.cmd("exiftool", ["-overwrite_original", "-gps:all=", "-png:all=", file],
|
||||
case System.cmd("exiftool", ["-m", "-overwrite_original", "-gps:all=", "-png:all=", file],
|
||||
stderr_to_stdout: true,
|
||||
parallelism: true
|
||||
) do
|
||||
{_response, 0} -> {:ok, :filtered}
|
||||
{error, 1} -> {:error, error}
|
||||
{error, _} -> {:error, error}
|
||||
end
|
||||
rescue
|
||||
e in ErlangError ->
|
||||
|
|
|
|||
|
|
@ -287,8 +287,14 @@ defmodule Pleroma.User do
|
|||
defdelegate following(user), to: FollowingRelationship
|
||||
defdelegate following?(follower, followed), to: FollowingRelationship
|
||||
defdelegate following_ap_ids(user), to: FollowingRelationship
|
||||
defdelegate get_follow_requests(user), to: FollowingRelationship
|
||||
defdelegate get_outgoing_follow_requests(user), to: FollowingRelationship
|
||||
defdelegate get_follow_requests_query(user), to: FollowingRelationship
|
||||
defdelegate get_outgoing_follow_requests_query(user), to: FollowingRelationship
|
||||
|
||||
def get_follow_requests(user) do
|
||||
get_follow_requests_query(user)
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
defdelegate search(query, opts \\ []), to: User.Search
|
||||
|
||||
@doc """
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ defmodule Pleroma.Web.ActivityPub.Builder do
|
|||
alias Pleroma.Web.ActivityPub.Utils
|
||||
alias Pleroma.Web.ActivityPub.Visibility
|
||||
alias Pleroma.Web.CommonAPI.ActivityDraft
|
||||
alias Pleroma.Web.Endpoint
|
||||
|
||||
require Pleroma.Constants
|
||||
|
||||
|
|
@ -64,15 +63,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
|
|||
|
||||
defp add_emoji_content(data, emoji, url) do
|
||||
tag = [
|
||||
%{
|
||||
"id" => url,
|
||||
"type" => "Emoji",
|
||||
"name" => Emoji.maybe_quote(emoji),
|
||||
"icon" => %{
|
||||
"type" => "Image",
|
||||
"url" => url
|
||||
}
|
||||
}
|
||||
Emoji.build_emoji_tag({Emoji.maybe_strip_name(emoji), url})
|
||||
]
|
||||
|
||||
data
|
||||
|
|
@ -113,7 +104,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
|
|||
|
||||
defp local_custom_emoji_react(data, emoji) do
|
||||
with %{file: path} = emojo <- Emoji.get(emoji) do
|
||||
url = "#{Endpoint.url()}#{path}"
|
||||
url = Emoji.local_url(path)
|
||||
add_emoji_content(data, emojo.code, url)
|
||||
else
|
||||
_ -> {:error, "Emoji does not exist"}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,14 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do
|
|||
end
|
||||
|
||||
defp fetch(url) do
|
||||
http_client_opts = Pleroma.Config.get([:media_proxy, :proxy_opts, :http], pool: :media)
|
||||
# This module uses Tesla (Pleroma.HTTP) to fetch the MediaProxy URL.
|
||||
# Redirect following is handled by Tesla middleware, so we must not enable
|
||||
# adapter-level redirect logic (Hackney can crash on relative redirects when proxied).
|
||||
http_client_opts =
|
||||
[:media_proxy, :proxy_opts, :http]
|
||||
|> Pleroma.Config.get(pool: :media)
|
||||
|> Keyword.drop([:follow_redirect, :force_redirect])
|
||||
|
||||
HTTP.get(url, [], http_client_opts)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
@behaviour Pleroma.Web.ActivityPub.Transmogrifier.API
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
||||
alias Pleroma.Emoji
|
||||
alias Pleroma.Maps
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Object.Containment
|
||||
|
|
@ -1005,32 +1006,20 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
def take_emoji_tags(%User{emoji: emoji}) do
|
||||
emoji
|
||||
|> Map.to_list()
|
||||
|> Enum.map(&build_emoji_tag/1)
|
||||
|> Enum.map(&Emoji.build_emoji_tag/1)
|
||||
end
|
||||
|
||||
# TODO: we should probably send mtime instead of unix epoch time for updated
|
||||
def add_emoji_tags(%{"emoji" => emoji} = object) do
|
||||
tags = object["tag"] || []
|
||||
|
||||
out = Enum.map(emoji, &build_emoji_tag/1)
|
||||
out = Enum.map(emoji, &Emoji.build_emoji_tag/1)
|
||||
|
||||
Map.put(object, "tag", tags ++ out)
|
||||
end
|
||||
|
||||
def add_emoji_tags(object), do: object
|
||||
|
||||
def build_emoji_tag({name, url}) do
|
||||
url = URI.encode(url)
|
||||
|
||||
%{
|
||||
"icon" => %{"url" => "#{url}", "type" => "Image"},
|
||||
"name" => ":" <> name <> ":",
|
||||
"type" => "Emoji",
|
||||
"updated" => "1970-01-01T00:00:00Z",
|
||||
"id" => url
|
||||
}
|
||||
end
|
||||
|
||||
def set_conversation(object) do
|
||||
Map.put(object, "conversation", object["context"])
|
||||
end
|
||||
|
|
|
|||
|
|
@ -123,7 +123,10 @@ defmodule Pleroma.Web.ApiSpec.Admin.OAuthAppOperation do
|
|||
name: %Schema{type: :string, description: "Application Name"},
|
||||
scopes: %Schema{type: :array, items: %Schema{type: :string}, description: "oAuth scopes"},
|
||||
redirect_uris: %Schema{
|
||||
type: :string,
|
||||
oneOf: [
|
||||
%Schema{type: :string},
|
||||
%Schema{type: :array, items: %Schema{type: :string}}
|
||||
],
|
||||
description:
|
||||
"Where the user should be redirected after authorization. To display the authorization code to the user instead of redirecting to a web page, use `urn:ietf:wg:oauth:2.0:oob` in this parameter."
|
||||
},
|
||||
|
|
@ -141,7 +144,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.OAuthAppOperation do
|
|||
},
|
||||
example: %{
|
||||
"name" => "My App",
|
||||
"redirect_uris" => "https://myapp.com/auth/callback",
|
||||
"redirect_uris" => ["https://myapp.com/auth/callback"],
|
||||
"website" => "https://myapp.com/",
|
||||
"scopes" => ["read", "write"],
|
||||
"trusted" => true
|
||||
|
|
@ -157,7 +160,10 @@ defmodule Pleroma.Web.ApiSpec.Admin.OAuthAppOperation do
|
|||
name: %Schema{type: :string, description: "Application Name"},
|
||||
scopes: %Schema{type: :array, items: %Schema{type: :string}, description: "oAuth scopes"},
|
||||
redirect_uris: %Schema{
|
||||
type: :string,
|
||||
oneOf: [
|
||||
%Schema{type: :string},
|
||||
%Schema{type: :array, items: %Schema{type: :string}}
|
||||
],
|
||||
description:
|
||||
"Where the user should be redirected after authorization. To display the authorization code to the user instead of redirecting to a web page, use `urn:ietf:wg:oauth:2.0:oob` in this parameter."
|
||||
},
|
||||
|
|
@ -175,7 +181,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.OAuthAppOperation do
|
|||
},
|
||||
example: %{
|
||||
"name" => "My App",
|
||||
"redirect_uris" => "https://myapp.com/auth/callback",
|
||||
"redirect_uris" => ["https://myapp.com/auth/callback"],
|
||||
"website" => "https://myapp.com/",
|
||||
"scopes" => ["read", "write"],
|
||||
"trusted" => true
|
||||
|
|
|
|||
|
|
@ -97,7 +97,10 @@ defmodule Pleroma.Web.ApiSpec.AppOperation do
|
|||
properties: %{
|
||||
client_name: %Schema{type: :string, description: "A name for your application."},
|
||||
redirect_uris: %Schema{
|
||||
type: :string,
|
||||
oneOf: [
|
||||
%Schema{type: :string},
|
||||
%Schema{type: :array, items: %Schema{type: :string}}
|
||||
],
|
||||
description:
|
||||
"Where the user should be redirected after authorization. To display the authorization code to the user instead of redirecting to a web page, use `urn:ietf:wg:oauth:2.0:oob` in this parameter."
|
||||
},
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ defmodule Pleroma.Web.ApiSpec.FollowRequestOperation do
|
|||
summary: "Retrieve follow requests",
|
||||
security: [%{"oAuth" => ["read:follows", "follow"]}],
|
||||
operationId: "FollowRequestController.index",
|
||||
parameters: pagination_params(),
|
||||
responses: %{
|
||||
200 =>
|
||||
Operation.response("Array of Account", "application/json", %Schema{
|
||||
|
|
@ -62,4 +63,22 @@ defmodule Pleroma.Web.ApiSpec.FollowRequestOperation do
|
|||
required: true
|
||||
)
|
||||
end
|
||||
|
||||
defp pagination_params do
|
||||
[
|
||||
Operation.parameter(:max_id, :query, :string, "Return items older than this ID"),
|
||||
Operation.parameter(
|
||||
:since_id,
|
||||
:query,
|
||||
:string,
|
||||
"Return the oldest items newer than this ID"
|
||||
),
|
||||
Operation.parameter(
|
||||
:limit,
|
||||
:query,
|
||||
%Schema{type: :integer, default: 20},
|
||||
"Maximum number of items to return. Will be ignored if it's more than 40"
|
||||
)
|
||||
]
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -57,6 +57,22 @@ defmodule Pleroma.Web.ApiSpec.InstanceOperation do
|
|||
}
|
||||
end
|
||||
|
||||
def domain_blocks_operation do
|
||||
%Operation{
|
||||
tags: ["Instance misc"],
|
||||
summary: "Retrieve instance domain blocks",
|
||||
operationId: "InstanceController.domain_blocks",
|
||||
responses: %{
|
||||
200 =>
|
||||
Operation.response(
|
||||
"Array of domain blocks",
|
||||
"application/json",
|
||||
array_of_domain_blocks()
|
||||
)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def translation_languages_operation do
|
||||
%Operation{
|
||||
tags: ["Instance misc"],
|
||||
|
|
@ -420,4 +436,19 @@ defmodule Pleroma.Web.ApiSpec.InstanceOperation do
|
|||
}
|
||||
}
|
||||
end
|
||||
|
||||
defp array_of_domain_blocks do
|
||||
%Schema{
|
||||
type: :array,
|
||||
items: %Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
domain: %Schema{type: :string},
|
||||
digest: %Schema{type: :string},
|
||||
severity: %Schema{type: :string},
|
||||
comment: %Schema{type: :string}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaFollowRequestOperation do
|
|||
summary: "Retrieve outgoing follow requests",
|
||||
security: [%{"oAuth" => ["read:follows", "follow"]}],
|
||||
operationId: "PleromaFollowRequestController.outgoing",
|
||||
parameters: pagination_params(),
|
||||
responses: %{
|
||||
200 =>
|
||||
Operation.response("Array of Account", "application/json", %Schema{
|
||||
|
|
@ -28,4 +29,22 @@ defmodule Pleroma.Web.ApiSpec.PleromaFollowRequestOperation do
|
|||
}
|
||||
}
|
||||
end
|
||||
|
||||
defp pagination_params do
|
||||
[
|
||||
Operation.parameter(:max_id, :query, :string, "Return items older than this ID"),
|
||||
Operation.parameter(
|
||||
:since_id,
|
||||
:query,
|
||||
:string,
|
||||
"Return the oldest items newer than this ID"
|
||||
),
|
||||
Operation.parameter(
|
||||
:limit,
|
||||
:query,
|
||||
%Schema{type: :integer, default: 20},
|
||||
"Maximum number of items to return. Will be ignored if it's more than 40"
|
||||
)
|
||||
]
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -29,6 +29,11 @@ defmodule Pleroma.Web.Fallback.RedirectController do
|
|||
)
|
||||
end
|
||||
|
||||
def live_dashboard(conn, _params) do
|
||||
conn
|
||||
|> redirect(to: "/pleroma/live_dashboard")
|
||||
end
|
||||
|
||||
def redirector(conn, _params, code \\ 200) do
|
||||
{:ok, index_content} = File.read(index_file_path(conn))
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,10 @@
|
|||
defmodule Pleroma.Web.MastodonAPI.FollowRequestController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
import Pleroma.Web.ControllerHelper,
|
||||
only: [add_link_headers: 2]
|
||||
|
||||
alias Pleroma.Pagination
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.CommonAPI
|
||||
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
||||
|
|
@ -24,10 +28,15 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestController do
|
|||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.FollowRequestOperation
|
||||
|
||||
@doc "GET /api/v1/follow_requests"
|
||||
def index(%{assigns: %{user: followed}} = conn, _params) do
|
||||
follow_requests = User.get_follow_requests(followed)
|
||||
def index(%{assigns: %{user: followed}} = conn, params) do
|
||||
follow_requests =
|
||||
followed
|
||||
|> User.get_follow_requests_query()
|
||||
|> Pagination.fetch_paginated(params, :keyset, :follower)
|
||||
|
||||
render(conn, "index.json", for: followed, users: follow_requests, as: :user)
|
||||
conn
|
||||
|> add_link_headers(follow_requests)
|
||||
|> render("index.json", for: followed, users: follow_requests, as: :user)
|
||||
end
|
||||
|
||||
@doc "POST /api/v1/follow_requests/:id/authorize"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceController do
|
|||
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||
|
||||
plug(:skip_auth when action in [:show, :show2, :peers])
|
||||
plug(:skip_auth)
|
||||
|
||||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.InstanceOperation
|
||||
|
||||
|
|
@ -31,6 +31,11 @@ defmodule Pleroma.Web.MastodonAPI.InstanceController do
|
|||
render(conn, "rules.json")
|
||||
end
|
||||
|
||||
@doc "GET /api/v1/instance/domain_blocks"
|
||||
def domain_blocks(conn, _params) do
|
||||
render(conn, "domain_blocks.json")
|
||||
end
|
||||
|
||||
@doc "GET /api/v1/instance/translation_languages"
|
||||
def translation_languages(conn, _params) do
|
||||
render(conn, "translation_languages.json")
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
alias Pleroma.User
|
||||
alias Pleroma.UserNote
|
||||
alias Pleroma.UserRelationship
|
||||
alias Pleroma.Utils.URIEncoding
|
||||
alias Pleroma.Web.CommonAPI.Utils
|
||||
alias Pleroma.Web.MastodonAPI.AccountView
|
||||
alias Pleroma.Web.MediaProxy
|
||||
|
|
@ -123,6 +124,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
target,
|
||||
&User.blocks_user?(&1, &2)
|
||||
),
|
||||
block_expires_at: maybe_put_block_expires_at(user_relationships, target, reading_user),
|
||||
blocked_by:
|
||||
UserRelationship.exists?(
|
||||
user_relationships,
|
||||
|
|
@ -139,6 +141,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
target,
|
||||
&User.mutes?(&1, &2)
|
||||
),
|
||||
mute_expires_at: maybe_put_mute_expires_at(user_relationships, target, reading_user),
|
||||
muting_notifications:
|
||||
UserRelationship.exists?(
|
||||
user_relationships,
|
||||
|
|
@ -238,7 +241,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
|
||||
emojis =
|
||||
Enum.map(user.emoji, fn {shortcode, raw_url} ->
|
||||
url = MediaProxy.url(raw_url)
|
||||
url =
|
||||
raw_url
|
||||
|> encode_emoji_url()
|
||||
|> MediaProxy.url()
|
||||
|
||||
%{
|
||||
shortcode: shortcode,
|
||||
|
|
@ -339,8 +345,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
|> maybe_put_unread_conversation_count(user, opts[:for])
|
||||
|> maybe_put_unread_notification_count(user, opts[:for])
|
||||
|> maybe_put_email_address(user, opts[:for])
|
||||
|> maybe_put_mute_expires_at(user, opts[:for], opts)
|
||||
|> maybe_put_block_expires_at(user, opts[:for], opts)
|
||||
|> maybe_put_mute_expires_at(user, opts[:for], relationship)
|
||||
|> maybe_put_block_expires_at(user, opts[:for], relationship)
|
||||
|> maybe_show_birthday(user, opts[:for])
|
||||
end
|
||||
|
||||
|
|
@ -356,8 +362,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
%User{id: user_id}
|
||||
) do
|
||||
count =
|
||||
User.get_follow_requests(user)
|
||||
|> length()
|
||||
user
|
||||
|> User.get_follow_requests_query()
|
||||
|> Pleroma.Repo.aggregate(:count)
|
||||
|
||||
data
|
||||
|> Kernel.put_in([:follow_requests_count], count)
|
||||
|
|
@ -467,22 +474,58 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
|
||||
defp maybe_put_email_address(data, _, _), do: data
|
||||
|
||||
defp maybe_put_mute_expires_at(data, %User{} = user, target, %{mutes: true}) do
|
||||
Map.put(
|
||||
data,
|
||||
:mute_expires_at,
|
||||
UserRelationship.get_mute_expire_date(target, user)
|
||||
)
|
||||
defp maybe_put_mute_expires_at(user_relationships, %User{} = target, %User{} = user) do
|
||||
cond do
|
||||
UserRelationship.exists?(user_relationships, :mute, user, target, &User.mutes_user?(&1, &2)) ->
|
||||
UserRelationship.get_mute_expire_date(user, target)
|
||||
|
||||
true ->
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_put_mute_expires_at(data, %User{} = target, %User{} = user, relationship) do
|
||||
cond do
|
||||
Map.has_key?(relationship, :mute_expires_at) ->
|
||||
Map.put(data, :mute_expires_at, relationship.mute_expires_at)
|
||||
|
||||
User.mutes_user?(user, target) ->
|
||||
Map.put(data, :mute_expires_at, UserRelationship.get_mute_expire_date(user, target))
|
||||
|
||||
true ->
|
||||
Map.put(data, :mute_expires_at, nil)
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_put_mute_expires_at(data, _, _, _), do: data
|
||||
|
||||
defp maybe_put_block_expires_at(data, %User{} = user, target, %{blocks: true}) do
|
||||
Map.put(
|
||||
data,
|
||||
:block_expires_at,
|
||||
UserRelationship.get_block_expire_date(target, user)
|
||||
)
|
||||
defp maybe_put_block_expires_at(user_relationships, %User{} = target, %User{} = user) do
|
||||
cond do
|
||||
UserRelationship.exists?(
|
||||
user_relationships,
|
||||
:block,
|
||||
user,
|
||||
target,
|
||||
&User.blocks_user?(&1, &2)
|
||||
) ->
|
||||
UserRelationship.get_block_expire_date(user, target)
|
||||
|
||||
true ->
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_put_block_expires_at(data, %User{} = target, %User{} = user, relationship) do
|
||||
cond do
|
||||
Map.has_key?(relationship, :block_expires_at) ->
|
||||
Map.put(data, :block_expires_at, relationship.block_expires_at)
|
||||
|
||||
User.blocks_user?(user, target) ->
|
||||
Map.put(data, :block_expires_at, UserRelationship.get_block_expire_date(user, target))
|
||||
|
||||
true ->
|
||||
Map.put(data, :block_expires_at, nil)
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_put_block_expires_at(data, _, _, _), do: data
|
||||
|
|
@ -511,4 +554,13 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
# See https://git.pleroma.social/pleroma/pleroma-meta/-/issues/14
|
||||
user.actor_type == "Service" || user.actor_type == "Group"
|
||||
end
|
||||
|
||||
defp encode_emoji_url(nil), do: nil
|
||||
defp encode_emoji_url("http" <> _ = url), do: URIEncoding.encode_url(url)
|
||||
|
||||
defp encode_emoji_url("/" <> _ = path),
|
||||
do: URIEncoding.encode_url(path, bypass_parse: true, bypass_decode: true)
|
||||
|
||||
defp encode_emoji_url(path) when is_binary(path),
|
||||
do: URIEncoding.encode_url(path, bypass_parse: true, bypass_decode: true)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,14 +6,13 @@ defmodule Pleroma.Web.MastodonAPI.CustomEmojiView do
|
|||
use Pleroma.Web, :view
|
||||
|
||||
alias Pleroma.Emoji
|
||||
alias Pleroma.Web.Endpoint
|
||||
|
||||
def render("index.json", %{custom_emojis: custom_emojis}) do
|
||||
render_many(custom_emojis, __MODULE__, "show.json")
|
||||
end
|
||||
|
||||
def render("show.json", %{custom_emoji: {shortcode, %Emoji{file: relative_url, tags: tags}}}) do
|
||||
url = Endpoint.url() |> URI.merge(relative_url) |> to_string()
|
||||
url = Emoji.local_url(relative_url)
|
||||
|
||||
%{
|
||||
"shortcode" => shortcode,
|
||||
|
|
|
|||
|
|
@ -5,11 +5,18 @@
|
|||
defmodule Pleroma.Web.MastodonAPI.InstanceView do
|
||||
use Pleroma.Web, :view
|
||||
|
||||
import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1]
|
||||
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.Web.ActivityPub.MRF
|
||||
|
||||
@mastodon_api_level "2.7.2"
|
||||
|
||||
@block_severities %{
|
||||
federated_timeline_removal: "silence",
|
||||
reject: "suspend"
|
||||
}
|
||||
|
||||
def render("show.json", _) do
|
||||
instance = Config.get(:instance)
|
||||
|
||||
|
|
@ -90,6 +97,53 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
|
|||
}
|
||||
end
|
||||
|
||||
def render("domain_blocks.json", _) do
|
||||
if Config.get([:mrf, :transparency]) do
|
||||
exclusions = Config.get([:mrf, :transparency_exclusions]) |> MRF.instance_list_from_tuples()
|
||||
|
||||
domain_blocks =
|
||||
Config.get(:mrf_simple)
|
||||
|> Enum.map(fn {rule, instances} ->
|
||||
instances
|
||||
|> Enum.map(fn
|
||||
{host, reason} when not_empty_string(host) and not_empty_string(reason) ->
|
||||
{host, reason}
|
||||
|
||||
{host, _reason} when not_empty_string(host) ->
|
||||
{host, ""}
|
||||
|
||||
host when not_empty_string(host) ->
|
||||
{host, ""}
|
||||
|
||||
_ ->
|
||||
nil
|
||||
end)
|
||||
|> Enum.reject(&is_nil/1)
|
||||
|> Enum.reject(fn {host, _} ->
|
||||
host in exclusions or not Map.has_key?(@block_severities, rule)
|
||||
end)
|
||||
|> Enum.map(fn {host, reason} ->
|
||||
domain_block = %{
|
||||
domain: host,
|
||||
digest: :crypto.hash(:sha256, host) |> Base.encode16(case: :lower),
|
||||
severity: Map.get(@block_severities, rule)
|
||||
}
|
||||
|
||||
if not_empty_string(reason) do
|
||||
Map.put(domain_block, :comment, reason)
|
||||
else
|
||||
domain_block
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|> List.flatten()
|
||||
|
||||
domain_blocks
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def render("translation_languages.json", _) do
|
||||
with true <- Pleroma.Language.Translation.configured?(),
|
||||
{:ok, languages} <- Pleroma.Language.Translation.languages_matrix() do
|
||||
|
|
|
|||
|
|
@ -31,9 +31,32 @@ defmodule Pleroma.Web.OAuth.App do
|
|||
|
||||
@spec changeset(t(), map()) :: Ecto.Changeset.t()
|
||||
def changeset(struct, params) do
|
||||
params = normalize_redirect_uris_param(params)
|
||||
|
||||
cast(struct, params, [:client_name, :redirect_uris, :scopes, :website, :trusted, :user_id])
|
||||
end
|
||||
|
||||
defp normalize_redirect_uris_param(%{} = params) do
|
||||
case params do
|
||||
%{redirect_uris: redirect_uris} when is_list(redirect_uris) ->
|
||||
Map.put(params, :redirect_uris, normalize_redirect_uris(redirect_uris))
|
||||
|
||||
%{"redirect_uris" => redirect_uris} when is_list(redirect_uris) ->
|
||||
Map.put(params, "redirect_uris", normalize_redirect_uris(redirect_uris))
|
||||
|
||||
_ ->
|
||||
params
|
||||
end
|
||||
end
|
||||
|
||||
defp normalize_redirect_uris(redirect_uris) when is_list(redirect_uris) do
|
||||
redirect_uris
|
||||
|> Enum.filter(&is_binary/1)
|
||||
|> Enum.map(&String.trim/1)
|
||||
|> Enum.reject(&(&1 == ""))
|
||||
|> Enum.join("\n")
|
||||
end
|
||||
|
||||
@spec register_changeset(t(), map()) :: Ecto.Changeset.t()
|
||||
def register_changeset(struct, params \\ %{}) do
|
||||
changeset =
|
||||
|
|
|
|||
|
|
@ -5,6 +5,10 @@
|
|||
defmodule Pleroma.Web.PleromaAPI.FollowRequestController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
import Pleroma.Web.ControllerHelper,
|
||||
only: [add_link_headers: 2]
|
||||
|
||||
alias Pleroma.Pagination
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
||||
|
||||
|
|
@ -17,11 +21,15 @@ defmodule Pleroma.Web.PleromaAPI.FollowRequestController do
|
|||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaFollowRequestOperation
|
||||
|
||||
@doc "GET /api/v1/pleroma/outgoing_follow_requests"
|
||||
def outgoing(%{assigns: %{user: follower}} = conn, _params) do
|
||||
follow_requests = User.get_outgoing_follow_requests(follower)
|
||||
def outgoing(%{assigns: %{user: follower}} = conn, params) do
|
||||
follow_requests =
|
||||
follower
|
||||
|> User.get_outgoing_follow_requests_query()
|
||||
|> Pagination.fetch_paginated(params, :keyset, :following)
|
||||
|
||||
conn
|
||||
|> put_view(Pleroma.Web.MastodonAPI.FollowRequestView)
|
||||
|> add_link_headers(follow_requests)
|
||||
|> render("index.json", for: follower, users: follow_requests, as: :user)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ defmodule Pleroma.Web.PleromaAPI.BookmarkFolderView do
|
|||
|
||||
alias Pleroma.BookmarkFolder
|
||||
alias Pleroma.Emoji
|
||||
alias Pleroma.Web.Endpoint
|
||||
|
||||
def render("show.json", %{folder: %BookmarkFolder{} = folder}) do
|
||||
%{
|
||||
|
|
@ -33,7 +32,7 @@ defmodule Pleroma.Web.PleromaAPI.BookmarkFolderView do
|
|||
emoji = Emoji.get(emoji)
|
||||
|
||||
if emoji != nil do
|
||||
Endpoint.url() |> URI.merge(emoji.file) |> to_string()
|
||||
Emoji.local_url(emoji.file)
|
||||
else
|
||||
nil
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
defmodule Pleroma.Web.Router do
|
||||
use Pleroma.Web, :router
|
||||
import Phoenix.LiveDashboard.Router
|
||||
import Oban.Web.Router
|
||||
|
||||
pipeline :accepts_html do
|
||||
plug(:accepts, ["html"])
|
||||
|
|
@ -813,6 +814,7 @@ defmodule Pleroma.Web.Router do
|
|||
get("/instance", InstanceController, :show)
|
||||
get("/instance/peers", InstanceController, :peers)
|
||||
get("/instance/rules", InstanceController, :rules)
|
||||
get("/instance/domain_blocks", InstanceController, :domain_blocks)
|
||||
get("/instance/translation_languages", InstanceController, :translation_languages)
|
||||
|
||||
get("/statuses", StatusController, :index)
|
||||
|
|
@ -1043,7 +1045,8 @@ defmodule Pleroma.Web.Router do
|
|||
|
||||
scope "/" do
|
||||
pipe_through([:pleroma_html, :authenticate, :require_admin])
|
||||
live_dashboard("/phoenix/live_dashboard", additional_pages: [oban: Oban.LiveDashboard])
|
||||
live_dashboard("/pleroma/live_dashboard", additional_pages: [oban: Oban.LiveDashboard])
|
||||
oban_dashboard("/pleroma/oban")
|
||||
end
|
||||
|
||||
# Test-only routes needed to test action dispatching and plug chain execution
|
||||
|
|
@ -1084,14 +1087,20 @@ defmodule Pleroma.Web.Router do
|
|||
get("/:maybe_nickname_or_id", RedirectController, :redirector_with_meta)
|
||||
match(:*, "/api/pleroma/*path", LegacyPleromaApiRerouterPlug, [])
|
||||
get("/api/*path", RedirectController, :api_not_implemented)
|
||||
get("/phoenix/live_dashboard", RedirectController, :live_dashboard)
|
||||
get("/*path", RedirectController, :redirector_with_preload)
|
||||
|
||||
options("/*path", RedirectController, :empty)
|
||||
end
|
||||
|
||||
# /pleroma/{phoenix,oban}/* need to get filtered out from api routes for frontend configuration
|
||||
# to not drop admin overrides for /pleroma/admin.
|
||||
@non_api_routes ["/pleroma/live_dashboard", "/pleroma/oban"]
|
||||
|
||||
def get_api_routes do
|
||||
Phoenix.Router.routes(__MODULE__)
|
||||
|> Enum.reject(fn r -> r.plug == Pleroma.Web.Fallback.RedirectController end)
|
||||
|> Enum.reject(fn r -> String.starts_with?(r.path, @non_api_routes) end)
|
||||
|> Enum.map(fn r ->
|
||||
r.path
|
||||
|> String.split("/", trim: true)
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ defmodule Pleroma.Web.Streamer do
|
|||
end)
|
||||
end
|
||||
|
||||
defp do_stream("user", item) do
|
||||
defp do_stream("user", %Activity{} = item) do
|
||||
Logger.debug("Trying to push to users")
|
||||
|
||||
recipient_topics =
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
|||
alias Pleroma.Emoji
|
||||
alias Pleroma.Healthcheck
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Utils.URIEncoding
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.Web.Auth.WrapperAuthenticator, as: Authenticator
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
|
@ -180,12 +181,22 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
|||
def emoji(conn, _params) do
|
||||
emoji =
|
||||
Enum.reduce(Emoji.get_all(), %{}, fn {code, %Emoji{file: file, tags: tags}}, acc ->
|
||||
file = encode_emoji_url(file)
|
||||
Map.put(acc, code, %{image_url: file, tags: tags})
|
||||
end)
|
||||
|
||||
json(conn, emoji)
|
||||
end
|
||||
|
||||
defp encode_emoji_url(nil), do: nil
|
||||
defp encode_emoji_url("http" <> _ = url), do: URIEncoding.encode_url(url)
|
||||
|
||||
defp encode_emoji_url("/" <> _ = path),
|
||||
do: URIEncoding.encode_url(path, bypass_parse: true, bypass_decode: true)
|
||||
|
||||
defp encode_emoji_url(path) when is_binary(path),
|
||||
do: URIEncoding.encode_url(path, bypass_parse: true, bypass_decode: true)
|
||||
|
||||
def update_notification_settings(%{assigns: %{user: user}} = conn, params) do
|
||||
with {:ok, _} <- User.update_notification_settings(user, params) do
|
||||
json(conn, %{status: "success"})
|
||||
|
|
|
|||
9
mix.exs
9
mix.exs
|
|
@ -130,7 +130,7 @@ defmodule Pleroma.Mixfile do
|
|||
{:ecto_enum, "~> 1.4"},
|
||||
{:postgrex, ">= 0.20.0"},
|
||||
{:phoenix_html, "~> 3.3"},
|
||||
{:phoenix_live_view, "~> 0.19.0"},
|
||||
{:phoenix_live_view, "~> 1.1.0"},
|
||||
{:phoenix_live_dashboard, "~> 0.8.0"},
|
||||
{:telemetry_metrics, "~> 0.6"},
|
||||
{:telemetry_poller, "~> 1.0"},
|
||||
|
|
@ -140,6 +140,7 @@ defmodule Pleroma.Mixfile do
|
|||
{:oban_plugins_lazarus,
|
||||
git: "https://git.pleroma.social/pleroma/elixir-libraries/oban_plugins_lazarus.git",
|
||||
ref: "e49fc355baaf0e435208bf5f534d31e26e897711"},
|
||||
{:oban_web, "~> 2.11"},
|
||||
{:gettext, "~> 0.20"},
|
||||
{:bcrypt_elixir, "~> 2.2"},
|
||||
{:trailing_format_plug, "~> 0.0.7"},
|
||||
|
|
@ -192,7 +193,7 @@ defmodule Pleroma.Mixfile do
|
|||
{:majic, "~> 1.0"},
|
||||
{:open_api_spex, "~> 3.16"},
|
||||
{:ecto_psql_extras, "~> 0.8"},
|
||||
{:vix, "~> 0.26.0"},
|
||||
{:vix, "~> 0.36"},
|
||||
{:elixir_make, "~> 0.7.7", override: true},
|
||||
{:blurhash, "~> 0.1.0", hex: :rinpatch_blurhash},
|
||||
{:exile, "~> 0.10.0"},
|
||||
|
|
@ -210,7 +211,7 @@ defmodule Pleroma.Mixfile do
|
|||
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
|
||||
{:mock, "~> 0.3.5", only: :test},
|
||||
{:covertool, "~> 2.0", only: :test},
|
||||
{:hackney, "~> 1.18.0", override: true},
|
||||
{:hackney, "~> 1.25.0", override: true},
|
||||
{:mox, "~> 1.0", only: :test},
|
||||
{:websockex, "~> 0.4.3", only: :test},
|
||||
{:benchee, "~> 1.0", only: :benchmark},
|
||||
|
|
@ -230,7 +231,7 @@ defmodule Pleroma.Mixfile do
|
|||
"ecto.rollback": ["pleroma.ecto.rollback"],
|
||||
"ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
|
||||
"ecto.reset": ["ecto.drop", "ecto.setup"],
|
||||
test: ["ecto.create --quiet", "ecto.migrate", "test --warnings-as-errors"],
|
||||
test: ["ecto.create --quiet", "pleroma.ecto.migrate --quiet", "test --warnings-as-errors"],
|
||||
docs: ["pleroma.docs", "docs"],
|
||||
analyze: ["credo --strict --only=warnings,todo,fixme,consistency,readability"],
|
||||
copyright: &add_copyright/1,
|
||||
|
|
|
|||
12
mix.lock
12
mix.lock
|
|
@ -13,7 +13,7 @@
|
|||
"captcha": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git", "e7b7cc34cc16b383461b966484c297e4ec9aeef6", [ref: "e7b7cc34cc16b383461b966484c297e4ec9aeef6"]},
|
||||
"castore": {:hex, :castore, "1.0.15", "8aa930c890fe18b6fe0a0cff27b27d0d4d231867897bd23ea772dee561f032a3", [:mix], [], "hexpm", "96ce4c69d7d5d7a0761420ef743e2f4096253931a3ba69e5ff8ef1844fe446d3"},
|
||||
"cc_precompiler": {:hex, :cc_precompiler, "0.1.11", "8c844d0b9fb98a3edea067f94f616b3f6b29b959b6b3bf25fee94ffe34364768", [:mix], [{:elixir_make, "~> 0.7", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "3427232caf0835f94680e5bcf082408a70b48ad68a5f5c0b02a3bea9f3a075b9"},
|
||||
"certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
|
||||
"certifi": {:hex, :certifi, "2.15.0", "0e6e882fcdaaa0a5a9f2b3db55b1394dba07e8d6d9bcad08318fb604c6839712", [:rebar3], [], "hexpm", "b147ed22ce71d72eafdad94f055165c1c182f61a2ff49df28bcc71d1d5b94a60"},
|
||||
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
|
||||
"comeonin": {:hex, :comeonin, "5.5.1", "5113e5f3800799787de08a6e0db307133850e635d34e9fab23c70b6501669510", [:mix], [], "hexpm", "65aac8f19938145377cee73973f192c5645873dcf550a8a6b18187d17c13ccdb"},
|
||||
"concurrent_limiter": {:hex, :concurrent_limiter, "0.1.1", "43ae1dc23edda1ab03dd66febc739c4ff710d047bb4d735754909f9a474ae01c", [:mix], [{:telemetry, "~> 0.3", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "53968ff238c0fbb4d7ed76ddb1af0be6f3b2f77909f6796e249e737c505a16eb"},
|
||||
|
|
@ -59,7 +59,7 @@
|
|||
"gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm", "29bd14a88030980849c7ed2447b8db6d6c9278a28b11a44cafe41b791205440f"},
|
||||
"gettext": {:hex, :gettext, "0.24.0", "6f4d90ac5f3111673cbefc4ebee96fe5f37a114861ab8c7b7d5b30a1108ce6d8", [:mix], [{:expo, "~> 0.5.1", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "bdf75cdfcbe9e4622dd18e034b227d77dd17f0f133853a1c73b97b3d6c770e8b"},
|
||||
"gun": {:hex, :gun, "2.2.0", "b8f6b7d417e277d4c2b0dc3c07dfdf892447b087f1cc1caff9c0f556b884e33d", [:make, :rebar3], [{:cowlib, ">= 2.15.0 and < 3.0.0", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "76022700c64287feb4df93a1795cff6741b83fb37415c40c34c38d2a4645261a"},
|
||||
"hackney": {:hex, :hackney, "1.18.2", "d7ff544ddae5e1cb49e9cf7fa4e356d7f41b283989a1c304bfc47a8cc1cf966f", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "af94d5c9f97857db257090a4a10e5426ecb6f4918aa5cc666798566ae14b65fd"},
|
||||
"hackney": {:hex, :hackney, "1.25.0", "390e9b83f31e5b325b9f43b76e1a785cbdb69b5b6cd4e079aa67835ded046867", [:rebar3], [{:certifi, "~> 2.15.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.4", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "7209bfd75fd1f42467211ff8f59ea74d6f2a9e81cbcee95a56711ee79fd6b1d4"},
|
||||
"hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"},
|
||||
"html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"},
|
||||
"http_signatures": {:hex, :http_signatures, "0.1.2", "ed1cc7043abcf5bb4f30d68fb7bad9d618ec1a45c4ff6c023664e78b67d9c406", [:mix], [], "hexpm", "f08aa9ac121829dae109d608d83c84b940ef2f183ae50f2dd1e9a8bc619d8be7"},
|
||||
|
|
@ -95,7 +95,9 @@
|
|||
"nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "cb6730f943cfc6aad674c92161be23a8411f15d1", [ref: "cb6730f943cfc6aad674c92161be23a8411f15d1"]},
|
||||
"oban": {:hex, :oban, "2.19.4", "045adb10db1161dceb75c254782f97cdc6596e7044af456a59decb6d06da73c1", [:mix], [{:ecto_sql, "~> 3.10", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:igniter, "~> 0.5", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5fcc6219e6464525b808d97add17896e724131f498444a292071bf8991c99f97"},
|
||||
"oban_live_dashboard": {:hex, :oban_live_dashboard, "0.1.1", "8aa4ceaf381c818f7d5c8185cc59942b8ac82ef0cf559881aacf8d3f8ac7bdd3", [:mix], [{:oban, "~> 2.15", [hex: :oban, repo: "hexpm", optional: false]}, {:phoenix_live_dashboard, "~> 0.7", [hex: :phoenix_live_dashboard, repo: "hexpm", optional: false]}], "hexpm", "16dc4ce9c9a95aa2e655e35ed4e675652994a8def61731a18af85e230e1caa63"},
|
||||
"oban_met": {:hex, :oban_met, "1.0.5", "bb633ab06448dab2ef9194f6688d33b3d07fc3f2ad793a1a08f4dfbb2cc9fe50", [:mix], [{:oban, "~> 2.19", [hex: :oban, repo: "hexpm", optional: false]}], "hexpm", "64664d50805bbfd3903aeada1f3c39634652a87844797ee400b0bcc95a28f5ea"},
|
||||
"oban_plugins_lazarus": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/oban_plugins_lazarus.git", "e49fc355baaf0e435208bf5f534d31e26e897711", [ref: "e49fc355baaf0e435208bf5f534d31e26e897711"]},
|
||||
"oban_web": {:hex, :oban_web, "2.11.6", "53933cb4253c4d9f1098ee311c06f07935259f0e564dcf2d66bae4cc98e317fe", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: false]}, {:oban, "~> 2.19", [hex: :oban, repo: "hexpm", optional: false]}, {:oban_met, "~> 1.0", [hex: :oban_met, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.7", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}], "hexpm", "576d94b705688c313694c2c114ca21aa0f8f2ad1b9ca45c052c5ba316d3e8d10"},
|
||||
"octo_fetch": {:hex, :octo_fetch, "0.4.0", "074b5ecbc08be10b05b27e9db08bc20a3060142769436242702931c418695b19", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "cf8be6f40cd519d7000bb4e84adcf661c32e59369ca2827c4e20042eda7a7fc6"},
|
||||
"open_api_spex": {:hex, :open_api_spex, "3.22.0", "fbf90dc82681dc042a4ee79853c8e989efbba73d9e87439085daf849bbf8bc20", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0 or ~> 6.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "dd751ddbdd709bb4a5313e9a24530da6e66594773c7242a0c2592cbd9f589063"},
|
||||
"parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
|
||||
|
|
@ -105,12 +107,12 @@
|
|||
"phoenix_html": {:hex, :phoenix_html, "3.3.4", "42a09fc443bbc1da37e372a5c8e6755d046f22b9b11343bf885067357da21cb3", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0249d3abec3714aff3415e7ee3d9786cb325be3151e6c4b3021502c585bf53fb"},
|
||||
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.7", "405880012cb4b706f26dd1c6349125bfc903fb9e44d1ea668adaf4e04d4884b7", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "3a8625cab39ec261d48a13b7468dc619c0ede099601b084e343968309bd4d7d7"},
|
||||
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.3.3", "3a53772a6118d5679bf50fc1670505a290e32a1d195df9e069d8c53ab040c054", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "766796676e5f558dbae5d1bdb066849673e956005e3730dfd5affd7a6da4abac"},
|
||||
"phoenix_live_view": {:hex, :phoenix_live_view, "0.19.5", "6e730595e8e9b8c5da230a814e557768828fd8dfeeb90377d2d8dbb52d4ec00a", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b2eaa0dd3cfb9bd7fb949b88217df9f25aed915e986a28ad5c8a0d054e7ca9d3"},
|
||||
"phoenix_live_view": {:hex, :phoenix_live_view, "1.1.19", "c95e9acbc374fb796ee3e24bfecc8213123c74d9f9e45667ca40bb0a4d242953", [:mix], [{:igniter, ">= 0.6.16 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:lazy_html, "~> 0.1.0", [hex: :lazy_html, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0 or ~> 1.8.0-rc", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d5ad357d6b21562a5b431f0ad09dfe76db9ce5648c6949f1aac334c8c4455d32"},
|
||||
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"},
|
||||
"phoenix_swoosh": {:hex, :phoenix_swoosh, "1.2.1", "b74ccaa8046fbc388a62134360ee7d9742d5a8ae74063f34eb050279de7a99e1", [:mix], [{:finch, "~> 0.8", [hex: :finch, repo: "hexpm", optional: true]}, {:hackney, "~> 1.10", [hex: :hackney, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.5", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "4000eeba3f9d7d1a6bf56d2bd56733d5cadf41a7f0d8ffe5bb67e7d667e204a2"},
|
||||
"phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},
|
||||
"phoenix_view": {:hex, :phoenix_view, "2.0.4", "b45c9d9cf15b3a1af5fb555c674b525391b6a1fe975f040fb4d913397b31abf4", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "4e992022ce14f31fe57335db27a28154afcc94e9983266835bb3040243eb620b"},
|
||||
"plug": {:hex, :plug, "1.18.1", "5067f26f7745b7e31bc3368bc1a2b818b9779faa959b49c934c17730efc911cf", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "57a57db70df2b422b564437d2d33cf8d33cd16339c1edb190cd11b1a3a546cc2"},
|
||||
"plug": {:hex, :plug, "1.19.1", "09bac17ae7a001a68ae393658aa23c7e38782be5c5c00c80be82901262c394c0", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "560a0017a8f6d5d30146916862aaf9300b7280063651dd7e532b8be168511e62"},
|
||||
"plug_cowboy": {:hex, :plug_cowboy, "2.7.4", "729c752d17cf364e2b8da5bdb34fb5804f56251e88bb602aff48ae0bd8673d11", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "9b85632bd7012615bae0a5d70084deb1b25d2bcbb32cab82d1e9a1e023168aa3"},
|
||||
"plug_crypto": {:hex, :plug_crypto, "2.1.1", "19bda8184399cb24afa10be734f84a16ea0a2bc65054e23a62bb10f06bc89491", [:mix], [], "hexpm", "6470bce6ffe41c8bd497612ffde1a7e4af67f36a15eea5f921af71cf3e11247c"},
|
||||
"plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "79fd4fcf34d110605c26560cbae8f23c603ec4158c08298bd4360fdea90bb5cf"},
|
||||
|
|
@ -150,7 +152,7 @@
|
|||
"ueberauth": {:hex, :ueberauth, "0.10.8", "ba78fbcbb27d811a6cd06ad851793aaf7d27c3b30c9e95349c2c362b344cd8f0", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "f2d3172e52821375bccb8460e5fa5cb91cfd60b19b636b6e57e9759b6f8c10c1"},
|
||||
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.1", "a48703a25c170eedadca83b11e88985af08d35f37c6f664d6dcfb106a97782fc", [:rebar3], [], "hexpm", "b3a917854ce3ae233619744ad1e0102e05673136776fb2fa76234f3e03b23642"},
|
||||
"unsafe": {:hex, :unsafe, "1.0.2", "23c6be12f6c1605364801f4b47007c0c159497d0446ad378b5cf05f1855c0581", [:mix], [], "hexpm", "b485231683c3ab01a9cd44cb4a79f152c6f3bb87358439c6f68791b85c2df675"},
|
||||
"vix": {:hex, :vix, "0.26.0", "027f10b6969b759318be84bd0bd8c88af877445e4e41cf96a0460392cea5399c", [:make, :mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:cc_precompiler, "~> 0.1.4 or ~> 0.2", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.7.3 or ~> 0.8", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:kino, "~> 0.7", [hex: :kino, repo: "hexpm", optional: true]}], "hexpm", "71b0a79ae7f199cacfc8e679b0e4ba25ee47dc02e182c5b9097efb29fbe14efd"},
|
||||
"vix": {:hex, :vix, "0.36.0", "3132dc065beda06dab1895a53d8c852d8e6a5bbca375c609435e968b1290e113", [:make, :mix], [{:cc_precompiler, "~> 0.1.4 or ~> 0.2", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.7.3 or ~> 0.8", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:kino, "~> 0.7", [hex: :kino, repo: "hexpm", optional: true]}], "hexpm", "92f912b4e90c453f92942742105bcdb367ad53406759da251bd2e587e33f4134"},
|
||||
"web_push_encryption": {:hex, :web_push_encryption, "0.3.1", "76d0e7375142dfee67391e7690e89f92578889cbcf2879377900b5620ee4708d", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jose, "~> 1.11.1", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "4f82b2e57622fb9337559058e8797cb0df7e7c9790793bdc4e40bc895f70e2a2"},
|
||||
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
|
||||
"websock_adapter": {:hex, :websock_adapter, "0.5.8", "3b97dc94e407e2d1fc666b2fb9acf6be81a1798a2602294aac000260a7c4a47d", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "315b9a1865552212b5f35140ad194e67ce31af45bcee443d4ecb96b5fd3f3782"},
|
||||
|
|
|
|||
18
test/fixtures/server.pem
vendored
Normal file
18
test/fixtures/server.pem
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIICpDCCAYwCCQC0vCQAnSoGdzANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls
|
||||
b2NhbGhvc3QwHhcNMjYwMTE2MTY1ODE5WhcNMzYwMTE0MTY1ODE5WjAUMRIwEAYD
|
||||
VQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCq
|
||||
dZ4O2upZqwIo1eK5KrW1IIsjkfsFK8hE7Llh+4axcesiUKot0ib1CUhRSYiL1DLO
|
||||
CIYQOw8IKQDVSC4JWAX9SsnX4W8dwexMQuSQG7/IKX2auC1bNNySFvoqM6Gq3GL9
|
||||
MqBFonZGXDPZu8fmxsI/2p9+2GK13F+HXgoLlXSCoO3XELJaBmjv29tgxxWRxCiH
|
||||
m4u0briSxgUEx+CctpKPvGDmLaoIOIhjtuoG6OjkeWUOp6jDcteazO23VxPyF5cS
|
||||
NbRJgm8AckrTQ6wbWSnhyqF8rPEsIc0ZAlUdDEs5fL3sjugc566FvE+GOkZIEyDD
|
||||
tgWbc4Ne+Kp/nnt6oVxpAgMBAAEwDQYJKoZIhvcNAQELBQADggEBADv+J1DTok8V
|
||||
MKVKo0hsRnHTeJQ2+EIgOspuYlEzez3PysOZH6diAQxO2lzuo9LKxP3hnmw17XO/
|
||||
P2oCzYyb9/P58VY/gr4UDIfuhgcE0cVfdsRhVId/I2FW6VP2f5q1TGbDUxSsVIlG
|
||||
6hufn1aLBu90LtEbDkHqbnD05yYPwdqzWg4TrOXbX+jBhQrXJJdB3W7KTgozjRQw
|
||||
F7+/2IyXoxXuxcwQBQlYhUbvGlsFqFpP/6cz2al5i5pNUkiNaSYwlRmuwa7zoTft
|
||||
tHf57dhfXIpXET2BaJM6DSjDOOG/QleRXkvkTI5J21q+Bo+XnOzo19p4cZKJpTFC
|
||||
SNgrftyNh3k=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Mix.PleromaTest do
|
||||
use ExUnit.Case, async: true
|
||||
use ExUnit.Case, async: false
|
||||
import Mix.Pleroma
|
||||
|
||||
setup_all do
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Mix.Tasks.Pleroma.AppTest do
|
||||
use Pleroma.DataCase, async: true
|
||||
use Pleroma.DataCase, async: false
|
||||
|
||||
setup_all do
|
||||
Mix.shell(Mix.Shell.Process)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Mix.Tasks.Pleroma.DatabaseTest do
|
||||
use Pleroma.DataCase, async: true
|
||||
use Pleroma.DataCase, async: false
|
||||
use Oban.Testing, repo: Pleroma.Repo
|
||||
|
||||
alias Pleroma.Activity
|
||||
|
|
|
|||
|
|
@ -16,6 +16,14 @@ defmodule Pleroma.HTTP.AdapterHelper.HackneyTest do
|
|||
describe "options/2" do
|
||||
setup do: clear_config([:http, :adapter], a: 1, b: 2)
|
||||
|
||||
test "uses redirect-safe defaults", %{uri: uri} do
|
||||
opts = Hackney.options([], uri)
|
||||
|
||||
assert opts[:follow_redirect] == false
|
||||
assert opts[:force_redirect] == false
|
||||
assert opts[:with_body] == true
|
||||
end
|
||||
|
||||
test "add proxy and opts from config", %{uri: uri} do
|
||||
opts = Hackney.options([proxy: "localhost:8123"], uri)
|
||||
|
||||
|
|
|
|||
355
test/pleroma/http/hackney_follow_redirect_regression_test.exs
Normal file
355
test/pleroma/http/hackney_follow_redirect_regression_test.exs
Normal file
|
|
@ -0,0 +1,355 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.HTTP.HackneyFollowRedirectRegressionTest do
|
||||
use ExUnit.Case, async: false
|
||||
|
||||
setup do
|
||||
{:ok, _} = Application.ensure_all_started(:hackney)
|
||||
|
||||
{:ok, tls_server} = start_tls_redirect_server()
|
||||
{:ok, proxy} = start_connect_proxy()
|
||||
|
||||
on_exit(fn ->
|
||||
stop_connect_proxy(proxy)
|
||||
stop_tls_redirect_server(tls_server)
|
||||
end)
|
||||
|
||||
{:ok, tls_server: tls_server, proxy: proxy}
|
||||
end
|
||||
|
||||
test "hackney follow_redirect crashes behind CONNECT proxy on relative redirects", %{
|
||||
tls_server: tls_server,
|
||||
proxy: proxy
|
||||
} do
|
||||
url = "#{tls_server.base_url}/redirect"
|
||||
|
||||
opts = [
|
||||
pool: :media,
|
||||
proxy: proxy.proxy_url,
|
||||
insecure: true,
|
||||
connect_timeout: 1_000,
|
||||
recv_timeout: 1_000,
|
||||
follow_redirect: true,
|
||||
force_redirect: true
|
||||
]
|
||||
|
||||
{pid, ref} = spawn_monitor(fn -> :hackney.request(:get, url, [], <<>>, opts) end)
|
||||
|
||||
assert_receive {:DOWN, ^ref, :process, ^pid, reason}, 5_000
|
||||
|
||||
assert match?({%FunctionClauseError{}, _}, reason) or match?(%FunctionClauseError{}, reason) or
|
||||
match?({:function_clause, _}, reason)
|
||||
end
|
||||
|
||||
test "redirects work via proxy when hackney follow_redirect is disabled", %{
|
||||
tls_server: tls_server,
|
||||
proxy: proxy
|
||||
} do
|
||||
url = "#{tls_server.base_url}/redirect"
|
||||
|
||||
adapter_opts = [
|
||||
pool: :media,
|
||||
proxy: proxy.proxy_url,
|
||||
insecure: true,
|
||||
connect_timeout: 1_000,
|
||||
recv_timeout: 1_000,
|
||||
follow_redirect: false,
|
||||
force_redirect: false,
|
||||
with_body: true
|
||||
]
|
||||
|
||||
client = Tesla.client([Tesla.Middleware.FollowRedirects], Tesla.Adapter.Hackney)
|
||||
|
||||
assert {:ok, %Tesla.Env{status: 200, body: "ok"}} =
|
||||
Tesla.request(client, method: :get, url: url, opts: [adapter: adapter_opts])
|
||||
end
|
||||
|
||||
test "reverse proxy hackney client follows redirects via proxy without crashing", %{
|
||||
tls_server: tls_server,
|
||||
proxy: proxy
|
||||
} do
|
||||
url = "#{tls_server.base_url}/redirect"
|
||||
|
||||
opts = [
|
||||
pool: :media,
|
||||
proxy: proxy.proxy_url,
|
||||
insecure: true,
|
||||
connect_timeout: 1_000,
|
||||
recv_timeout: 1_000,
|
||||
follow_redirect: true
|
||||
]
|
||||
|
||||
assert {:ok, 200, _headers, ref} =
|
||||
Pleroma.ReverseProxy.Client.Hackney.request(:get, url, [], "", opts)
|
||||
|
||||
assert collect_body(ref) == "ok"
|
||||
Pleroma.ReverseProxy.Client.Hackney.close(ref)
|
||||
end
|
||||
|
||||
defp collect_body(ref, acc \\ "") do
|
||||
case Pleroma.ReverseProxy.Client.Hackney.stream_body(ref) do
|
||||
:done -> acc
|
||||
{:ok, data, _ref} -> collect_body(ref, acc <> data)
|
||||
{:error, error} -> flunk("stream_body failed: #{inspect(error)}")
|
||||
end
|
||||
end
|
||||
|
||||
defp start_tls_redirect_server do
|
||||
certfile = Path.expand("../../fixtures/server.pem", __DIR__)
|
||||
keyfile = Path.expand("../../fixtures/private_key.pem", __DIR__)
|
||||
|
||||
{:ok, listener} =
|
||||
:ssl.listen(0, [
|
||||
:binary,
|
||||
certfile: certfile,
|
||||
keyfile: keyfile,
|
||||
reuseaddr: true,
|
||||
active: false,
|
||||
packet: :raw,
|
||||
ip: {127, 0, 0, 1}
|
||||
])
|
||||
|
||||
{:ok, {{127, 0, 0, 1}, port}} = :ssl.sockname(listener)
|
||||
|
||||
{:ok, acceptor} =
|
||||
Task.start_link(fn ->
|
||||
accept_tls_loop(listener)
|
||||
end)
|
||||
|
||||
{:ok, %{listener: listener, acceptor: acceptor, base_url: "https://127.0.0.1:#{port}"}}
|
||||
end
|
||||
|
||||
defp stop_tls_redirect_server(%{listener: listener, acceptor: acceptor}) do
|
||||
:ok = :ssl.close(listener)
|
||||
|
||||
if Process.alive?(acceptor) do
|
||||
Process.exit(acceptor, :normal)
|
||||
end
|
||||
end
|
||||
|
||||
defp accept_tls_loop(listener) do
|
||||
case :ssl.transport_accept(listener) do
|
||||
{:ok, socket} ->
|
||||
_ = Task.start(fn -> serve_tls(socket) end)
|
||||
accept_tls_loop(listener)
|
||||
|
||||
{:error, :closed} ->
|
||||
:ok
|
||||
|
||||
{:error, _reason} ->
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
defp serve_tls(tcp_socket) do
|
||||
with {:ok, ssl_socket} <- :ssl.handshake(tcp_socket, 2_000),
|
||||
{:ok, data} <- recv_ssl_headers(ssl_socket),
|
||||
{:ok, path} <- parse_path(data) do
|
||||
case path do
|
||||
"/redirect" ->
|
||||
send_ssl_response(ssl_socket, 302, "Found", [{"Location", "/final"}], "")
|
||||
|
||||
"/final" ->
|
||||
send_ssl_response(ssl_socket, 200, "OK", [], "ok")
|
||||
|
||||
_ ->
|
||||
send_ssl_response(ssl_socket, 404, "Not Found", [], "not found")
|
||||
end
|
||||
|
||||
:ssl.close(ssl_socket)
|
||||
else
|
||||
_ ->
|
||||
_ = :gen_tcp.close(tcp_socket)
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
defp recv_ssl_headers(socket, acc \\ <<>>) do
|
||||
case :ssl.recv(socket, 0, 1_000) do
|
||||
{:ok, data} ->
|
||||
acc = acc <> data
|
||||
|
||||
if :binary.match(acc, "\r\n\r\n") != :nomatch do
|
||||
{:ok, acc}
|
||||
else
|
||||
if byte_size(acc) > 8_192 do
|
||||
{:error, :too_large}
|
||||
else
|
||||
recv_ssl_headers(socket, acc)
|
||||
end
|
||||
end
|
||||
|
||||
{:error, _} = error ->
|
||||
error
|
||||
end
|
||||
end
|
||||
|
||||
defp send_ssl_response(socket, status, reason, headers, body) do
|
||||
base_headers =
|
||||
[
|
||||
{"Content-Length", Integer.to_string(byte_size(body))},
|
||||
{"Connection", "close"}
|
||||
] ++ headers
|
||||
|
||||
iodata =
|
||||
[
|
||||
"HTTP/1.1 ",
|
||||
Integer.to_string(status),
|
||||
" ",
|
||||
reason,
|
||||
"\r\n",
|
||||
Enum.map(base_headers, fn {k, v} -> [k, ": ", v, "\r\n"] end),
|
||||
"\r\n",
|
||||
body
|
||||
]
|
||||
|
||||
:ssl.send(socket, iodata)
|
||||
end
|
||||
|
||||
defp start_connect_proxy do
|
||||
{:ok, listener} =
|
||||
:gen_tcp.listen(0, [
|
||||
:binary,
|
||||
active: false,
|
||||
packet: :raw,
|
||||
reuseaddr: true,
|
||||
ip: {127, 0, 0, 1}
|
||||
])
|
||||
|
||||
{:ok, {{127, 0, 0, 1}, port}} = :inet.sockname(listener)
|
||||
|
||||
{:ok, acceptor} =
|
||||
Task.start_link(fn ->
|
||||
accept_proxy_loop(listener)
|
||||
end)
|
||||
|
||||
{:ok, %{listener: listener, acceptor: acceptor, proxy_url: "127.0.0.1:#{port}"}}
|
||||
end
|
||||
|
||||
defp stop_connect_proxy(%{listener: listener, acceptor: acceptor}) do
|
||||
:ok = :gen_tcp.close(listener)
|
||||
|
||||
if Process.alive?(acceptor) do
|
||||
Process.exit(acceptor, :normal)
|
||||
end
|
||||
end
|
||||
|
||||
defp accept_proxy_loop(listener) do
|
||||
case :gen_tcp.accept(listener) do
|
||||
{:ok, socket} ->
|
||||
_ = Task.start(fn -> serve_proxy(socket) end)
|
||||
accept_proxy_loop(listener)
|
||||
|
||||
{:error, :closed} ->
|
||||
:ok
|
||||
|
||||
{:error, _reason} ->
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
defp serve_proxy(client_socket) do
|
||||
with {:ok, {headers, rest}} <- recv_tcp_headers(client_socket),
|
||||
{:ok, {host, port}} <- parse_connect(headers),
|
||||
{:ok, upstream_socket} <- connect_upstream(host, port) do
|
||||
:gen_tcp.send(client_socket, "HTTP/1.1 200 Connection established\r\n\r\n")
|
||||
|
||||
if rest != <<>> do
|
||||
:gen_tcp.send(upstream_socket, rest)
|
||||
end
|
||||
|
||||
tunnel(client_socket, upstream_socket)
|
||||
else
|
||||
_ ->
|
||||
:gen_tcp.close(client_socket)
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
defp tunnel(client_socket, upstream_socket) do
|
||||
parent = self()
|
||||
_ = spawn_link(fn -> forward(client_socket, upstream_socket, parent) end)
|
||||
_ = spawn_link(fn -> forward(upstream_socket, client_socket, parent) end)
|
||||
|
||||
receive do
|
||||
:tunnel_closed -> :ok
|
||||
after
|
||||
10_000 -> :ok
|
||||
end
|
||||
|
||||
:gen_tcp.close(client_socket)
|
||||
:gen_tcp.close(upstream_socket)
|
||||
end
|
||||
|
||||
defp forward(from_socket, to_socket, parent) do
|
||||
case :gen_tcp.recv(from_socket, 0, 10_000) do
|
||||
{:ok, data} ->
|
||||
_ = :gen_tcp.send(to_socket, data)
|
||||
forward(from_socket, to_socket, parent)
|
||||
|
||||
{:error, _reason} ->
|
||||
send(parent, :tunnel_closed)
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
defp recv_tcp_headers(socket, acc \\ <<>>) do
|
||||
case :gen_tcp.recv(socket, 0, 1_000) do
|
||||
{:ok, data} ->
|
||||
acc = acc <> data
|
||||
|
||||
case :binary.match(acc, "\r\n\r\n") do
|
||||
:nomatch ->
|
||||
if byte_size(acc) > 8_192 do
|
||||
{:error, :too_large}
|
||||
else
|
||||
recv_tcp_headers(socket, acc)
|
||||
end
|
||||
|
||||
{idx, _len} ->
|
||||
split_at = idx + 4
|
||||
<<headers::binary-size(split_at), rest::binary>> = acc
|
||||
{:ok, {headers, rest}}
|
||||
end
|
||||
|
||||
{:error, _} = error ->
|
||||
error
|
||||
end
|
||||
end
|
||||
|
||||
defp parse_connect(data) do
|
||||
with [request_line | _] <- String.split(data, "\r\n", trim: true),
|
||||
["CONNECT", hostport | _] <- String.split(request_line, " ", parts: 3),
|
||||
[host, port_str] <- String.split(hostport, ":", parts: 2),
|
||||
{port, ""} <- Integer.parse(port_str) do
|
||||
{:ok, {host, port}}
|
||||
else
|
||||
_ -> {:error, :invalid_connect}
|
||||
end
|
||||
end
|
||||
|
||||
defp connect_upstream(host, port) do
|
||||
address =
|
||||
case :inet.parse_address(String.to_charlist(host)) do
|
||||
{:ok, ip} -> ip
|
||||
{:error, _} -> String.to_charlist(host)
|
||||
end
|
||||
|
||||
:gen_tcp.connect(address, port, [:binary, active: false, packet: :raw], 1_000)
|
||||
end
|
||||
|
||||
defp parse_path(data) do
|
||||
case String.split(data, "\r\n", parts: 2) do
|
||||
[request_line | _] ->
|
||||
case String.split(request_line, " ") do
|
||||
[_method, path, _protocol] -> {:ok, path}
|
||||
_ -> {:error, :invalid_request}
|
||||
end
|
||||
|
||||
_ ->
|
||||
{:error, :invalid_request}
|
||||
end
|
||||
end
|
||||
end
|
||||
151
test/pleroma/http/hackney_redirect_regression_test.exs
Normal file
151
test/pleroma/http/hackney_redirect_regression_test.exs
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.HTTP.HackneyRedirectRegressionTest do
|
||||
use ExUnit.Case, async: false
|
||||
|
||||
alias Pleroma.HTTP.AdapterHelper.Hackney, as: HackneyAdapterHelper
|
||||
|
||||
setup do
|
||||
{:ok, _} = Application.ensure_all_started(:hackney)
|
||||
|
||||
{:ok, server} = start_server()
|
||||
on_exit(fn -> stop_server(server) end)
|
||||
|
||||
{:ok, server: server}
|
||||
end
|
||||
|
||||
test "pooled redirects work with follow_redirect disabled", %{server: server} do
|
||||
url = "#{server.base_url}/redirect"
|
||||
uri = URI.parse(url)
|
||||
|
||||
adapter_opts =
|
||||
HackneyAdapterHelper.options(
|
||||
[pool: :media, follow_redirect: false, no_proxy_env: true],
|
||||
uri
|
||||
)
|
||||
|
||||
client = Tesla.client([Tesla.Middleware.FollowRedirects], Tesla.Adapter.Hackney)
|
||||
|
||||
assert {:ok, %Tesla.Env{status: 200, body: "ok"}} =
|
||||
Tesla.request(client, method: :get, url: url, opts: [adapter: adapter_opts])
|
||||
end
|
||||
|
||||
defp start_server do
|
||||
{:ok, listener} =
|
||||
:gen_tcp.listen(0, [
|
||||
:binary,
|
||||
active: false,
|
||||
packet: :raw,
|
||||
reuseaddr: true,
|
||||
ip: {127, 0, 0, 1}
|
||||
])
|
||||
|
||||
{:ok, {{127, 0, 0, 1}, port}} = :inet.sockname(listener)
|
||||
|
||||
{:ok, acceptor} =
|
||||
Task.start_link(fn ->
|
||||
accept_loop(listener)
|
||||
end)
|
||||
|
||||
{:ok, %{listener: listener, acceptor: acceptor, base_url: "http://127.0.0.1:#{port}"}}
|
||||
end
|
||||
|
||||
defp stop_server(%{listener: listener, acceptor: acceptor}) do
|
||||
:ok = :gen_tcp.close(listener)
|
||||
|
||||
if Process.alive?(acceptor) do
|
||||
Process.exit(acceptor, :normal)
|
||||
end
|
||||
end
|
||||
|
||||
defp accept_loop(listener) do
|
||||
case :gen_tcp.accept(listener) do
|
||||
{:ok, socket} ->
|
||||
serve(socket)
|
||||
accept_loop(listener)
|
||||
|
||||
{:error, :closed} ->
|
||||
:ok
|
||||
|
||||
{:error, _reason} ->
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
defp serve(socket) do
|
||||
with {:ok, data} <- recv_headers(socket),
|
||||
{:ok, path} <- parse_path(data) do
|
||||
case path do
|
||||
"/redirect" ->
|
||||
send_response(socket, 302, "Found", [{"Location", "/final"}], "")
|
||||
|
||||
"/final" ->
|
||||
send_response(socket, 200, "OK", [], "ok")
|
||||
|
||||
_ ->
|
||||
send_response(socket, 404, "Not Found", [], "not found")
|
||||
end
|
||||
else
|
||||
_ -> :ok
|
||||
end
|
||||
|
||||
:gen_tcp.close(socket)
|
||||
end
|
||||
|
||||
defp recv_headers(socket, acc \\ <<>>) do
|
||||
case :gen_tcp.recv(socket, 0, 1_000) do
|
||||
{:ok, data} ->
|
||||
acc = acc <> data
|
||||
|
||||
if :binary.match(acc, "\r\n\r\n") != :nomatch do
|
||||
{:ok, acc}
|
||||
else
|
||||
if byte_size(acc) > 8_192 do
|
||||
{:error, :too_large}
|
||||
else
|
||||
recv_headers(socket, acc)
|
||||
end
|
||||
end
|
||||
|
||||
{:error, _} = error ->
|
||||
error
|
||||
end
|
||||
end
|
||||
|
||||
defp parse_path(data) do
|
||||
case String.split(data, "\r\n", parts: 2) do
|
||||
[request_line | _] ->
|
||||
case String.split(request_line, " ") do
|
||||
[_method, path, _protocol] -> {:ok, path}
|
||||
_ -> {:error, :invalid_request}
|
||||
end
|
||||
|
||||
_ ->
|
||||
{:error, :invalid_request}
|
||||
end
|
||||
end
|
||||
|
||||
defp send_response(socket, status, reason, headers, body) do
|
||||
base_headers =
|
||||
[
|
||||
{"Content-Length", Integer.to_string(byte_size(body))},
|
||||
{"Connection", "close"}
|
||||
] ++ headers
|
||||
|
||||
iodata =
|
||||
[
|
||||
"HTTP/1.1 ",
|
||||
Integer.to_string(status),
|
||||
" ",
|
||||
reason,
|
||||
"\r\n",
|
||||
Enum.map(base_headers, fn {k, v} -> [k, ": ", v, "\r\n"] end),
|
||||
"\r\n",
|
||||
body
|
||||
]
|
||||
|
||||
:gen_tcp.send(socket, iodata)
|
||||
end
|
||||
end
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.HTTPTest do
|
||||
use ExUnit.Case, async: true
|
||||
use ExUnit.Case, async: false
|
||||
use Pleroma.Tests.Helpers
|
||||
|
||||
import Tesla.Mock
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Repo.Migrations.AutolinkerToLinkifyTest do
|
||||
use Pleroma.DataCase, async: true
|
||||
use Pleroma.DataCase, async: false
|
||||
import Pleroma.Factory
|
||||
import Pleroma.Tests.Helpers
|
||||
alias Pleroma.ConfigDB
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ defmodule Pleroma.Upload.Filter.Exiftool.StripLocationTest do
|
|||
|
||||
assert Filter.Exiftool.StripLocation.filter(upload) == {:ok, :filtered}
|
||||
|
||||
{exif_original, 0} = System.cmd("exiftool", ["test/fixtures/DSCN0010.#{type}"])
|
||||
{exif_filtered, 0} = System.cmd("exiftool", ["test/fixtures/DSCN0010_tmp.#{type}"])
|
||||
{exif_original, 0} = System.cmd("exiftool", ["-m", "test/fixtures/DSCN0010.#{type}"])
|
||||
{exif_filtered, 0} = System.cmd("exiftool", ["-m", "test/fixtures/DSCN0010_tmp.#{type}"])
|
||||
|
||||
assert String.match?(exif_original, ~r/GPS/)
|
||||
refute String.match?(exif_filtered, ~r/GPS/)
|
||||
|
|
|
|||
|
|
@ -54,14 +54,17 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicyTest do
|
|||
setup do: clear_config([:media_proxy, :enabled], true)
|
||||
|
||||
test "it prefetches media proxy URIs" do
|
||||
Tesla.Mock.mock(fn %{method: :get, url: "http://example.com/image.jpg"} ->
|
||||
{:ok, %Tesla.Env{status: 200, body: ""}}
|
||||
end)
|
||||
|
||||
with_mock HTTP, get: fn _, _, _ -> {:ok, []} end do
|
||||
with_mock HTTP,
|
||||
get: fn _, _, opts ->
|
||||
send(self(), {:prefetch_opts, opts})
|
||||
{:ok, []}
|
||||
end do
|
||||
MediaProxyWarmingPolicy.filter(@message)
|
||||
|
||||
assert called(HTTP.get(:_, :_, :_))
|
||||
assert_receive {:prefetch_opts, opts}
|
||||
refute Keyword.has_key?(opts, :follow_redirect)
|
||||
refute Keyword.has_key?(opts, :force_redirect)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -81,10 +84,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicyTest do
|
|||
end
|
||||
|
||||
test "history-aware" do
|
||||
Tesla.Mock.mock(fn %{method: :get, url: "http://example.com/image.jpg"} ->
|
||||
{:ok, %Tesla.Env{status: 200, body: ""}}
|
||||
end)
|
||||
|
||||
with_mock HTTP, get: fn _, _, _ -> {:ok, []} end do
|
||||
MRF.filter_one(MediaProxyWarmingPolicy, @message_with_history)
|
||||
|
||||
|
|
@ -93,10 +92,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicyTest do
|
|||
end
|
||||
|
||||
test "works with Updates" do
|
||||
Tesla.Mock.mock(fn %{method: :get, url: "http://example.com/image.jpg"} ->
|
||||
{:ok, %Tesla.Env{status: 200, body: ""}}
|
||||
end)
|
||||
|
||||
with_mock HTTP, get: fn _, _, _ -> {:ok, []} end do
|
||||
MRF.filter_one(MediaProxyWarmingPolicy, @message_with_history |> Map.put("type", "Update"))
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicyTest do
|
||||
use Pleroma.DataCase, async: true
|
||||
use Pleroma.DataCase, async: false
|
||||
|
||||
alias Pleroma.Web.ActivityPub.MRF.RemoteReportPolicy
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,46 @@
|
|||
defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiTagBuildingTest do
|
||||
use Pleroma.DataCase, async: true
|
||||
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
|
||||
test "it encodes the id to be a valid url" do
|
||||
name = "hanapog"
|
||||
url = "https://misskey.local.live/emojis/hana pog.png"
|
||||
|
||||
tag = Transmogrifier.build_emoji_tag({name, url})
|
||||
tag = Pleroma.Emoji.build_emoji_tag({name, url})
|
||||
|
||||
assert tag["id"] == "https://misskey.local.live/emojis/hana%20pog.png"
|
||||
end
|
||||
|
||||
test "it does not double-encode already encoded urls" do
|
||||
name = "hanapog"
|
||||
url = "https://misskey.local.live/emojis/hana%20pog.png"
|
||||
|
||||
tag = Pleroma.Emoji.build_emoji_tag({name, url})
|
||||
|
||||
assert tag["id"] == url
|
||||
end
|
||||
|
||||
test "it encodes disallowed path characters" do
|
||||
name = "hanapog"
|
||||
url = "https://example.com/emojis/hana[pog].png"
|
||||
|
||||
tag = Pleroma.Emoji.build_emoji_tag({name, url})
|
||||
|
||||
assert tag["id"] == "https://example.com/emojis/hana%5Bpog%5D.png"
|
||||
end
|
||||
|
||||
test "local_url does not decode percent in filenames" do
|
||||
url = Pleroma.Emoji.local_url("/emoji/hana%20pog.png")
|
||||
|
||||
assert url == Pleroma.Web.Endpoint.url() <> "/emoji/hana%2520pog.png"
|
||||
|
||||
tag = Pleroma.Emoji.build_emoji_tag({"hanapog", url})
|
||||
|
||||
assert tag["id"] == url
|
||||
end
|
||||
|
||||
test "local_url encodes question marks in filenames" do
|
||||
url = Pleroma.Emoji.local_url("/emoji/file?name.png")
|
||||
|
||||
assert url == Pleroma.Web.Endpoint.url() <> "/emoji/file%3Fname.png"
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -759,6 +759,22 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
|
|||
)
|
||||
end
|
||||
|
||||
test "EmojiReact custom emoji urls are URI encoded" do
|
||||
user = insert(:user, local: true)
|
||||
note_activity = insert(:note_activity)
|
||||
|
||||
{:ok, react_activity} = CommonAPI.react_with_emoji(note_activity.id, user, ":dinosaur:")
|
||||
{:ok, data} = Transmogrifier.prepare_outgoing(react_activity.data)
|
||||
|
||||
assert length(data["tag"]) == 1
|
||||
|
||||
tag = List.first(data["tag"])
|
||||
url = tag["icon"]["url"]
|
||||
|
||||
assert url == "http://localhost:4001/emoji/dino%20walking.gif"
|
||||
assert tag["id"] == "http://localhost:4001/emoji/dino%20walking.gif"
|
||||
end
|
||||
|
||||
test "it prepares a quote post" do
|
||||
user = insert(:user)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.UtilsTest do
|
||||
use Pleroma.DataCase, async: true
|
||||
use Pleroma.DataCase, async: false
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Repo
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.UserViewTest do
|
||||
use Pleroma.DataCase, async: true
|
||||
use Pleroma.DataCase, async: false
|
||||
import Pleroma.Factory
|
||||
|
||||
alias Pleroma.User
|
||||
|
|
|
|||
|
|
@ -57,6 +57,28 @@ defmodule Pleroma.Web.AdminAPI.OAuthAppControllerTest do
|
|||
} = response
|
||||
end
|
||||
|
||||
test "success with redirect_uris array", %{conn: conn} do
|
||||
base_url = Endpoint.url()
|
||||
app_name = "Trusted app"
|
||||
|
||||
response =
|
||||
conn
|
||||
|> put_req_header("content-type", "application/json")
|
||||
|> post("/api/pleroma/admin/oauth_app", %{
|
||||
name: app_name,
|
||||
redirect_uris: [base_url]
|
||||
})
|
||||
|> json_response_and_validate_schema(200)
|
||||
|
||||
assert %{
|
||||
"client_id" => _,
|
||||
"client_secret" => _,
|
||||
"name" => ^app_name,
|
||||
"redirect_uri" => ^base_url,
|
||||
"trusted" => false
|
||||
} = response
|
||||
end
|
||||
|
||||
test "with trusted", %{conn: conn} do
|
||||
base_url = Endpoint.url()
|
||||
app_name = "Trusted app"
|
||||
|
|
|
|||
|
|
@ -77,6 +77,10 @@ defmodule Pleroma.Web.FallbackTest do
|
|||
assert redirected_to(get(conn, "/pleroma/admin")) =~ "/pleroma/admin/"
|
||||
end
|
||||
|
||||
test "GET /phoenix/live_dashboard -> /pleroma/live_dashboard", %{conn: conn} do
|
||||
assert redirected_to(get(conn, "/phoenix/live_dashboard")) =~ "/pleroma/live_dashboard"
|
||||
end
|
||||
|
||||
test "OPTIONS /*path", %{conn: conn} do
|
||||
assert conn
|
||||
|> options("/foo")
|
||||
|
|
|
|||
|
|
@ -1901,7 +1901,13 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
|
|||
|
||||
{:ok, _user_relationships} = User.mute(user, other_user1)
|
||||
{:ok, _user_relationships} = User.mute(user, other_user2)
|
||||
{:ok, _user_relationships} = User.mute(user, other_user3)
|
||||
{:ok, _user_relationships} = User.mute(user, other_user3, %{duration: 24 * 60 * 60})
|
||||
|
||||
date =
|
||||
DateTime.utc_now()
|
||||
|> DateTime.add(24 * 60 * 60)
|
||||
|> DateTime.truncate(:second)
|
||||
|> DateTime.to_iso8601()
|
||||
|
||||
result =
|
||||
conn
|
||||
|
|
@ -1937,6 +1943,17 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
|
|||
|> json_response_and_validate_schema(200)
|
||||
|
||||
assert [%{"id" => ^id3}] = result
|
||||
|
||||
result =
|
||||
conn
|
||||
|> get("/api/v1/mutes")
|
||||
|> json_response_and_validate_schema(200)
|
||||
|
||||
assert [
|
||||
%{"id" => ^id3, "mute_expires_at" => ^date},
|
||||
%{"id" => ^id2, "mute_expires_at" => nil},
|
||||
%{"id" => ^id1, "mute_expires_at" => nil}
|
||||
] = result
|
||||
end
|
||||
|
||||
test "list of mutes with with_relationships parameter" do
|
||||
|
|
@ -1951,20 +1968,44 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
|
|||
|
||||
{:ok, _} = User.mute(user, other_user1)
|
||||
{:ok, _} = User.mute(user, other_user2)
|
||||
{:ok, _} = User.mute(user, other_user3)
|
||||
{:ok, _} = User.mute(user, other_user3, %{duration: 24 * 60 * 60})
|
||||
|
||||
date =
|
||||
DateTime.utc_now()
|
||||
|> DateTime.add(24 * 60 * 60)
|
||||
|> DateTime.truncate(:second)
|
||||
|> DateTime.to_iso8601()
|
||||
|
||||
assert [
|
||||
%{
|
||||
"id" => ^id3,
|
||||
"pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
|
||||
"pleroma" => %{
|
||||
"relationship" => %{
|
||||
"muting" => true,
|
||||
"mute_expires_at" => ^date,
|
||||
"followed_by" => true
|
||||
}
|
||||
}
|
||||
},
|
||||
%{
|
||||
"id" => ^id2,
|
||||
"pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
|
||||
"pleroma" => %{
|
||||
"relationship" => %{
|
||||
"muting" => true,
|
||||
"mute_expires_at" => nil,
|
||||
"followed_by" => true
|
||||
}
|
||||
}
|
||||
},
|
||||
%{
|
||||
"id" => ^id1,
|
||||
"pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
|
||||
"pleroma" => %{
|
||||
"relationship" => %{
|
||||
"muting" => true,
|
||||
"mute_expires_at" => nil,
|
||||
"followed_by" => true
|
||||
}
|
||||
}
|
||||
}
|
||||
] =
|
||||
conn
|
||||
|
|
@ -1980,7 +2021,13 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
|
|||
|
||||
{:ok, _user_relationship} = User.block(user, other_user1)
|
||||
{:ok, _user_relationship} = User.block(user, other_user3)
|
||||
{:ok, _user_relationship} = User.block(user, other_user2)
|
||||
{:ok, _user_relationship} = User.block(user, other_user2, %{duration: 24 * 60 * 60})
|
||||
|
||||
date =
|
||||
DateTime.utc_now()
|
||||
|> DateTime.add(24 * 60 * 60)
|
||||
|> DateTime.truncate(:second)
|
||||
|> DateTime.to_iso8601()
|
||||
|
||||
result =
|
||||
conn
|
||||
|
|
@ -2045,6 +2092,18 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
|
|||
|> json_response_and_validate_schema(200)
|
||||
|
||||
assert [%{"id" => ^id1}] = result
|
||||
|
||||
result =
|
||||
conn
|
||||
|> assign(:user, user)
|
||||
|> get("api/v1/blocks")
|
||||
|> json_response_and_validate_schema(200)
|
||||
|
||||
assert [
|
||||
%{"id" => ^id3, "block_expires_at" => nil},
|
||||
%{"id" => ^id2, "block_expires_at" => ^date},
|
||||
%{"id" => ^id1, "block_expires_at" => nil}
|
||||
] = result
|
||||
end
|
||||
|
||||
test "list of blocks with with_relationships parameter" do
|
||||
|
|
@ -2059,20 +2118,44 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
|
|||
|
||||
{:ok, _} = User.block(user, other_user1)
|
||||
{:ok, _} = User.block(user, other_user2)
|
||||
{:ok, _} = User.block(user, other_user3)
|
||||
{:ok, _} = User.block(user, other_user3, %{duration: 24 * 60 * 60})
|
||||
|
||||
date =
|
||||
DateTime.utc_now()
|
||||
|> DateTime.add(24 * 60 * 60)
|
||||
|> DateTime.truncate(:second)
|
||||
|> DateTime.to_iso8601()
|
||||
|
||||
assert [
|
||||
%{
|
||||
"id" => ^id3,
|
||||
"pleroma" => %{"relationship" => %{"blocking" => true, "followed_by" => false}}
|
||||
"pleroma" => %{
|
||||
"relationship" => %{
|
||||
"blocking" => true,
|
||||
"block_expires_at" => ^date,
|
||||
"followed_by" => false
|
||||
}
|
||||
}
|
||||
},
|
||||
%{
|
||||
"id" => ^id2,
|
||||
"pleroma" => %{"relationship" => %{"blocking" => true, "followed_by" => false}}
|
||||
"pleroma" => %{
|
||||
"relationship" => %{
|
||||
"blocking" => true,
|
||||
"block_expires_at" => nil,
|
||||
"followed_by" => false
|
||||
}
|
||||
}
|
||||
},
|
||||
%{
|
||||
"id" => ^id1,
|
||||
"pleroma" => %{"relationship" => %{"blocking" => true, "followed_by" => false}}
|
||||
"pleroma" => %{
|
||||
"relationship" => %{
|
||||
"blocking" => true,
|
||||
"block_expires_at" => nil,
|
||||
"followed_by" => false
|
||||
}
|
||||
}
|
||||
}
|
||||
] =
|
||||
conn
|
||||
|
|
|
|||
|
|
@ -61,6 +61,33 @@ defmodule Pleroma.Web.MastodonAPI.AppControllerTest do
|
|||
assert app.user_id == nil
|
||||
end
|
||||
|
||||
test "creates an oauth app with redirect_uris array", %{conn: conn} do
|
||||
app_attrs = build(:oauth_app)
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> put_req_header("content-type", "application/json")
|
||||
|> post("/api/v1/apps", %{
|
||||
client_name: app_attrs.client_name,
|
||||
redirect_uris: [app_attrs.redirect_uris]
|
||||
})
|
||||
|
||||
[app] = Repo.all(App)
|
||||
|
||||
expected = %{
|
||||
"name" => app.client_name,
|
||||
"website" => app.website,
|
||||
"client_id" => app.client_id,
|
||||
"client_secret" => app.client_secret,
|
||||
"id" => app.id |> to_string(),
|
||||
"redirect_uri" => app.redirect_uris,
|
||||
"vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
|
||||
}
|
||||
|
||||
assert expected == json_response_and_validate_schema(conn, 200)
|
||||
assert app.user_id == nil
|
||||
end
|
||||
|
||||
test "creates an oauth app with a user", %{conn: conn} do
|
||||
user = insert(:user)
|
||||
app_attrs = build(:oauth_app)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,11 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do
|
|||
|
||||
import Pleroma.Factory
|
||||
|
||||
defp extract_next_link_header(header) do
|
||||
[_, next_link] = Regex.run(~r{<(?<next_link>.*)>; rel="next"}, header)
|
||||
next_link
|
||||
end
|
||||
|
||||
describe "locked accounts" do
|
||||
setup do
|
||||
user = insert(:user, is_locked: true)
|
||||
|
|
@ -31,6 +36,23 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do
|
|||
assert to_string(other_user.id) == relationship["id"]
|
||||
end
|
||||
|
||||
test "/api/v1/follow_requests paginates", %{user: user, conn: conn} do
|
||||
for _ <- 1..21 do
|
||||
other_user = insert(:user)
|
||||
{:ok, _, _, _activity} = CommonAPI.follow(other_user, user)
|
||||
{:ok, _, _} = User.follow(other_user, user, :follow_pending)
|
||||
end
|
||||
|
||||
conn = get(conn, "/api/v1/follow_requests")
|
||||
assert length(json_response_and_validate_schema(conn, 200)) == 20
|
||||
assert [link_header] = get_resp_header(conn, "link")
|
||||
assert link_header =~ "rel=\"next\""
|
||||
next_link = extract_next_link_header(link_header)
|
||||
assert next_link =~ "/api/v1/follow_requests"
|
||||
conn = get(conn, next_link)
|
||||
assert length(json_response_and_validate_schema(conn, 200)) == 1
|
||||
end
|
||||
|
||||
test "/api/v1/follow_requests/:id/authorize works", %{user: user, conn: conn} do
|
||||
other_user = insert(:user)
|
||||
|
||||
|
|
|
|||
|
|
@ -153,6 +153,49 @@ defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do
|
|||
] = result["rules"]
|
||||
end
|
||||
|
||||
describe "instance domain blocks" do
|
||||
setup do
|
||||
clear_config([:mrf_simple, :reject], [{"fediverse.pl", "uses pl-fe"}])
|
||||
end
|
||||
|
||||
test "get instance domain blocks", %{conn: conn} do
|
||||
conn = get(conn, "/api/v1/instance/domain_blocks")
|
||||
|
||||
assert [
|
||||
%{
|
||||
"comment" => "uses pl-fe",
|
||||
"digest" => "55e3f44aefe7eb022d3b1daaf7396cabf7f181bf6093c8ea841e30c9fc7d8226",
|
||||
"domain" => "fediverse.pl",
|
||||
"severity" => "suspend"
|
||||
}
|
||||
] == json_response_and_validate_schema(conn, 200)
|
||||
end
|
||||
|
||||
test "omits comment field if comment is empty", %{conn: conn} do
|
||||
clear_config([:mrf_simple, :reject], ["fediverse.pl"])
|
||||
|
||||
conn = get(conn, "/api/v1/instance/domain_blocks")
|
||||
|
||||
assert [
|
||||
%{
|
||||
"digest" => "55e3f44aefe7eb022d3b1daaf7396cabf7f181bf6093c8ea841e30c9fc7d8226",
|
||||
"domain" => "fediverse.pl",
|
||||
"severity" => "suspend"
|
||||
} = domain_block
|
||||
] = json_response_and_validate_schema(conn, 200)
|
||||
|
||||
refute Map.has_key?(domain_block, "comment")
|
||||
end
|
||||
|
||||
test "returns empty array if mrf transparency is disabled", %{conn: conn} do
|
||||
clear_config([:mrf, :transparency], false)
|
||||
|
||||
conn = get(conn, "/api/v1/instance/domain_blocks")
|
||||
|
||||
assert [] == json_response_and_validate_schema(conn, 200)
|
||||
end
|
||||
end
|
||||
|
||||
test "translation languages matrix", %{conn: conn} do
|
||||
clear_config([Pleroma.Language.Translation, :provider], TranslationMock)
|
||||
|
||||
|
|
|
|||
|
|
@ -105,6 +105,25 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
|
|||
assert expected == AccountView.render("show.json", %{user: user, skip_visibility_check: true})
|
||||
end
|
||||
|
||||
test "encodes emoji urls in the emojis field" do
|
||||
user =
|
||||
insert(:user,
|
||||
name: ":brackets: :percent:",
|
||||
emoji: %{
|
||||
"brackets" => "/emoji/hana[pog].png",
|
||||
"percent" => "/emoji/hana%20pog.png"
|
||||
}
|
||||
)
|
||||
|
||||
%{emojis: emojis} =
|
||||
AccountView.render("show.json", %{user: user, skip_visibility_check: true})
|
||||
|
||||
emoji_urls = Map.new(emojis, &{&1.shortcode, &1.url})
|
||||
|
||||
assert emoji_urls["brackets"] == "/emoji/hana%5Bpog%5D.png"
|
||||
assert emoji_urls["percent"] == "/emoji/hana%2520pog.png"
|
||||
end
|
||||
|
||||
describe "roles and privileges" do
|
||||
setup do
|
||||
clear_config([:instance, :moderator_privileges], [:cofe, :only_moderator])
|
||||
|
|
@ -420,8 +439,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
|
|||
following: false,
|
||||
followed_by: false,
|
||||
blocking: false,
|
||||
block_expires_at: nil,
|
||||
blocked_by: false,
|
||||
muting: false,
|
||||
mute_expires_at: nil,
|
||||
muting_notifications: false,
|
||||
subscribing: false,
|
||||
notifying: false,
|
||||
|
|
@ -517,6 +538,53 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
|
|||
test_relationship_rendering(user, other_user, expected)
|
||||
end
|
||||
|
||||
test "represent a relationship for the blocking and blocked user with expiry" do
|
||||
user = insert(:user)
|
||||
other_user = insert(:user)
|
||||
date = DateTime.utc_now() |> DateTime.add(24 * 60 * 60) |> DateTime.truncate(:second)
|
||||
|
||||
{:ok, user, other_user} = User.follow(user, other_user)
|
||||
{:ok, _subscription} = User.subscribe(user, other_user)
|
||||
{:ok, _user_relationship} = User.block(user, other_user, %{duration: 24 * 60 * 60})
|
||||
{:ok, _user_relationship} = User.block(other_user, user)
|
||||
|
||||
expected =
|
||||
Map.merge(
|
||||
@blank_response,
|
||||
%{
|
||||
following: false,
|
||||
blocking: true,
|
||||
block_expires_at: date,
|
||||
blocked_by: true,
|
||||
id: to_string(other_user.id)
|
||||
}
|
||||
)
|
||||
|
||||
test_relationship_rendering(user, other_user, expected)
|
||||
end
|
||||
|
||||
test "represent a relationship for the muting user with expiry" do
|
||||
user = insert(:user)
|
||||
other_user = insert(:user)
|
||||
date = DateTime.utc_now() |> DateTime.add(24 * 60 * 60) |> DateTime.truncate(:second)
|
||||
|
||||
{:ok, _user_relationship} =
|
||||
User.mute(user, other_user, %{notifications: true, duration: 24 * 60 * 60})
|
||||
|
||||
expected =
|
||||
Map.merge(
|
||||
@blank_response,
|
||||
%{
|
||||
muting: true,
|
||||
mute_expires_at: date,
|
||||
muting_notifications: true,
|
||||
id: to_string(other_user.id)
|
||||
}
|
||||
)
|
||||
|
||||
test_relationship_rendering(user, other_user, expected)
|
||||
end
|
||||
|
||||
test "represent a relationship for the user blocking a domain" do
|
||||
user = insert(:user)
|
||||
other_user = insert(:user, ap_id: "https://bad.site/users/other_user")
|
||||
|
|
@ -837,12 +905,39 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
|
|||
User.mute(user, other_user, %{notifications: true, duration: 24 * 60 * 60})
|
||||
|
||||
%{
|
||||
pleroma: %{
|
||||
relationship: %{
|
||||
mute_expires_at: mute_expires_at
|
||||
}
|
||||
},
|
||||
mute_expires_at: mute_expires_at
|
||||
} = AccountView.render("show.json", %{user: other_user, for: user, mutes: true})
|
||||
} = AccountView.render("show.json", %{user: other_user, for: user, embed_relationships: true})
|
||||
|
||||
assert DateTime.diff(
|
||||
mute_expires_at,
|
||||
DateTime.utc_now() |> DateTime.add(24 * 60 * 60)
|
||||
) in -3..3
|
||||
end
|
||||
|
||||
test "renders block expiration date" do
|
||||
user = insert(:user)
|
||||
other_user = insert(:user)
|
||||
|
||||
{:ok, _user_relationships} =
|
||||
User.block(user, other_user, %{duration: 24 * 60 * 60})
|
||||
|
||||
%{
|
||||
pleroma: %{
|
||||
relationship: %{
|
||||
block_expires_at: block_expires_at
|
||||
}
|
||||
},
|
||||
block_expires_at: block_expires_at
|
||||
} = AccountView.render("show.json", %{user: other_user, for: user, embed_relationships: true})
|
||||
|
||||
assert DateTime.diff(
|
||||
block_expires_at,
|
||||
DateTime.utc_now() |> DateTime.add(24 * 60 * 60)
|
||||
) in -3..3
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
|
|||
data: %{
|
||||
"reactions" => [
|
||||
["👍", [user.ap_id], nil],
|
||||
["dinosaur", [user.ap_id], "http://localhost:4001/emoji/dino walking.gif"]
|
||||
["dinosaur", [user.ap_id], "http://localhost:4001/emoji/dino%20walking.gif"]
|
||||
]
|
||||
}
|
||||
)
|
||||
|
|
@ -243,7 +243,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
|
|||
account: AccountView.render("show.json", %{user: other_user, for: user}),
|
||||
status: StatusView.render("show.json", %{activity: activity, for: user}),
|
||||
created_at: Utils.to_masto_date(notification.inserted_at),
|
||||
emoji_url: "http://localhost:4001/emoji/dino walking.gif"
|
||||
emoji_url: "http://localhost:4001/emoji/dino%20walking.gif"
|
||||
}
|
||||
|
||||
test_notifications_rendering([notification], user, [expected])
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
|
|||
count: 2,
|
||||
me: false,
|
||||
name: "dinosaur",
|
||||
url: "http://localhost:4001/emoji/dino walking.gif",
|
||||
url: "http://localhost:4001/emoji/dino%20walking.gif",
|
||||
account_ids: [other_user.id, user.id]
|
||||
},
|
||||
%{name: "🍵", count: 1, me: false, url: nil, account_ids: [third_user.id]}
|
||||
|
|
@ -70,7 +70,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
|
|||
count: 2,
|
||||
me: true,
|
||||
name: "dinosaur",
|
||||
url: "http://localhost:4001/emoji/dino walking.gif",
|
||||
url: "http://localhost:4001/emoji/dino%20walking.gif",
|
||||
account_ids: [other_user.id, user.id]
|
||||
},
|
||||
%{name: "🍵", count: 1, me: false, url: nil, account_ids: [third_user.id]}
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do
|
|||
"name" => "dinosaur",
|
||||
"count" => 1,
|
||||
"me" => true,
|
||||
"url" => "http://localhost:4001/emoji/dino walking.gif",
|
||||
"url" => "http://localhost:4001/emoji/dino%20walking.gif",
|
||||
"account_ids" => [other_user.id]
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
defmodule Pleroma.Web.PleromaAPI.ChatMessageReferenceViewTest do
|
||||
alias Pleroma.NullCache
|
||||
use Pleroma.DataCase, async: true
|
||||
use Pleroma.DataCase, async: false
|
||||
|
||||
alias Pleroma.Chat
|
||||
alias Pleroma.Chat.MessageReference
|
||||
|
|
@ -18,6 +18,11 @@ defmodule Pleroma.Web.PleromaAPI.ChatMessageReferenceViewTest do
|
|||
import Mox
|
||||
import Pleroma.Factory
|
||||
|
||||
setup do
|
||||
Mox.stub_with(Pleroma.CachexMock, Pleroma.NullCache)
|
||||
:ok
|
||||
end
|
||||
|
||||
setup do: clear_config([:rich_media, :enabled], true)
|
||||
|
||||
test "it displays a chat message" do
|
||||
|
|
|
|||
|
|
@ -106,7 +106,6 @@ defmodule Pleroma.Web.Plugs.FrontendStaticPlugTest do
|
|||
"manifest.json",
|
||||
"auth",
|
||||
"proxy",
|
||||
"phoenix",
|
||||
"test",
|
||||
"user_exists",
|
||||
"check_password"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
defmodule Pleroma.Web.RichMedia.CardTest do
|
||||
use Oban.Testing, repo: Pleroma.Repo
|
||||
use Pleroma.DataCase, async: true
|
||||
use Pleroma.DataCase, async: false
|
||||
|
||||
alias Pleroma.Tests.ObanHelpers
|
||||
alias Pleroma.UnstubbedConfigMock, as: ConfigMock
|
||||
|
|
@ -19,6 +19,8 @@ defmodule Pleroma.Web.RichMedia.CardTest do
|
|||
setup do
|
||||
mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||
|
||||
Mox.stub_with(Pleroma.CachexMock, Pleroma.NullCache)
|
||||
|
||||
ConfigMock
|
||||
|> stub_with(Pleroma.Test.StaticConfig)
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,12 @@ defmodule Pleroma.Web.StreamerTest do
|
|||
|
||||
@moduletag needs_streamer: true, capture_log: true
|
||||
|
||||
setup do: clear_config([:instance, :skip_thread_containment])
|
||||
setup do
|
||||
clear_config([:instance, :skip_thread_containment])
|
||||
Mox.stub_with(Pleroma.CachexMock, Pleroma.NullCache)
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
describe "get_topic/_ (unauthenticated)" do
|
||||
test "allows no stream" do
|
||||
|
|
|
|||
|
|
@ -3,12 +3,13 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.WebFingerTest do
|
||||
use Pleroma.DataCase, async: true
|
||||
use Pleroma.DataCase, async: false
|
||||
alias Pleroma.Web.WebFinger
|
||||
import Pleroma.Factory
|
||||
import Tesla.Mock
|
||||
|
||||
setup do
|
||||
Mox.stub_with(Pleroma.CachexMock, Pleroma.NullCache)
|
||||
mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||
:ok
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Workers.PublisherWorkerTest do
|
||||
use Pleroma.DataCase, async: true
|
||||
use Pleroma.DataCase, async: false
|
||||
use Oban.Testing, repo: Pleroma.Repo
|
||||
|
||||
import Pleroma.Factory
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Workers.ReachabilityWorkerTest do
|
||||
use Pleroma.DataCase, async: true
|
||||
use Pleroma.DataCase, async: false
|
||||
use Oban.Testing, repo: Pleroma.Repo
|
||||
|
||||
import Mock
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Workers.ReceiverWorkerTest do
|
||||
use Pleroma.DataCase, async: true
|
||||
use Pleroma.DataCase, async: false
|
||||
use Oban.Testing, repo: Pleroma.Repo
|
||||
|
||||
import Mock
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Workers.RemoteFetcherWorkerTest do
|
||||
use Pleroma.DataCase, async: true
|
||||
use Pleroma.DataCase, async: false
|
||||
use Oban.Testing, repo: Pleroma.Repo
|
||||
|
||||
alias Pleroma.Workers.RemoteFetcherWorker
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue