Merge develop branch upstream
This commit is contained in:
commit
5d279a22b1
|
@ -24,6 +24,7 @@ stages:
|
||||||
- docker
|
- docker
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
|
- echo $MIX_ENV
|
||||||
- rm -rf _build/*/lib/pleroma
|
- rm -rf _build/*/lib/pleroma
|
||||||
- apt-get update && apt-get install -y cmake
|
- apt-get update && apt-get install -y cmake
|
||||||
- mix local.hex --force
|
- mix local.hex --force
|
||||||
|
@ -154,6 +155,20 @@ analysis:
|
||||||
script:
|
script:
|
||||||
- mix credo --strict --only=warnings,todo,fixme,consistency,readability
|
- mix credo --strict --only=warnings,todo,fixme,consistency,readability
|
||||||
|
|
||||||
|
cycles:
|
||||||
|
stage: test
|
||||||
|
image: elixir:1.11
|
||||||
|
only:
|
||||||
|
changes:
|
||||||
|
- "**/*.ex"
|
||||||
|
- "**/*.exs"
|
||||||
|
- "mix.lock"
|
||||||
|
cache: {}
|
||||||
|
script:
|
||||||
|
- mix deps.get
|
||||||
|
- mix compile
|
||||||
|
- mix xref graph --format cycles --label compile | awk '{print $0} END{exit ($0 != "No cycles found")}'
|
||||||
|
|
||||||
docs-deploy:
|
docs-deploy:
|
||||||
stage: deploy
|
stage: deploy
|
||||||
cache: *testing_cache_policy
|
cache: *testing_cache_policy
|
||||||
|
|
|
@ -13,21 +13,27 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- **Breaking:** Configuration: `:chat, enabled` moved to `:shout, enabled` and `:instance, chat_limit` moved to `:shout, limit`
|
- **Breaking:** Configuration: `:chat, enabled` moved to `:shout, enabled` and `:instance, chat_limit` moved to `:shout, limit`
|
||||||
|
- Support for Erlang/OTP 24
|
||||||
- The `application` metadata returned with statuses is no longer hardcoded. Apps that want to display these details will now have valid data for new posts after this change.
|
- The `application` metadata returned with statuses is no longer hardcoded. Apps that want to display these details will now have valid data for new posts after this change.
|
||||||
- HTTPSecurityPlug now sends a response header to opt out of Google's FLoC (Federated Learning of Cohorts) targeted advertising.
|
- HTTPSecurityPlug now sends a response header to opt out of Google's FLoC (Federated Learning of Cohorts) targeted advertising.
|
||||||
- Email address is now returned if requesting user is the owner of the user account so it can be exposed in client and FE user settings UIs.
|
- Email address is now returned if requesting user is the owner of the user account so it can be exposed in client and FE user settings UIs.
|
||||||
|
- Improved Twittercard and OpenGraph meta tag generation including thumbnails and image dimension metadata when available.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- MRF (`FollowBotPolicy`): New MRF Policy which makes a designated local Bot account attempt to follow all users in public Notes received by your instance. Users who require approving follower requests or have #nobot in their profile are excluded.
|
- MRF (`FollowBotPolicy`): New MRF Policy which makes a designated local Bot account attempt to follow all users in public Notes received by your instance. Users who require approving follower requests or have #nobot in their profile are excluded.
|
||||||
- Return OAuth token `id` (primary key) in POST `/oauth/token`.
|
- Return OAuth token `id` (primary key) in POST `/oauth/token`.
|
||||||
- `AnalyzeMetadata` upload filter for extracting attachment dimensions and generating blurhashes.
|
- `AnalyzeMetadata` upload filter for extracting image/video attachment dimensions and generating blurhashes for images. Blurhashes for videos are not generated at this time.
|
||||||
- Attachment dimensions and blurhashes are federated when available.
|
- Attachment dimensions and blurhashes are federated when available.
|
||||||
- Pinned posts federation
|
- Pinned posts federation
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Don't crash so hard when email settings are invalid.
|
- Don't crash so hard when email settings are invalid.
|
||||||
- Checking activated Upload Filters for required commands.
|
- Checking activated Upload Filters for required commands.
|
||||||
|
- Remote users can no longer reappear after being deleted.
|
||||||
|
- Deactivated users may now be deleted.
|
||||||
|
- Mix task `pleroma.database prune_objects`
|
||||||
|
- Linkify: Parsing crash with URLs ending in unbalanced closed paren, no path separator, and no query parameters
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
- **Breaking**: Remove deprecated `/api/qvitter/statuses/notifications/read` (replaced by `/api/v1/pleroma/notifications/read`)
|
- **Breaking**: Remove deprecated `/api/qvitter/statuses/notifications/read` (replaced by `/api/v1/pleroma/notifications/read`)
|
||||||
|
|
|
@ -35,6 +35,9 @@ Currently Pleroma is not packaged by any OS/Distros, but if you want to package
|
||||||
### Docker
|
### Docker
|
||||||
While we don’t provide docker files, other people have written very good ones. Take a look at <https://github.com/angristan/docker-pleroma> or <https://glitch.sh/sn0w/pleroma-docker>.
|
While we don’t provide docker files, other people have written very good ones. Take a look at <https://github.com/angristan/docker-pleroma> or <https://glitch.sh/sn0w/pleroma-docker>.
|
||||||
|
|
||||||
|
### Raspberry Pi
|
||||||
|
Community maintained Raspberry Pi image that you can flash and run Pleroma on your Raspberry Pi. Available here <https://github.com/guysoft/PleromaPi>.
|
||||||
|
|
||||||
### Compilation Troubleshooting
|
### Compilation Troubleshooting
|
||||||
If you ever encounter compilation issues during the updating of Pleroma, you can try these commands and see if they fix things:
|
If you ever encounter compilation issues during the updating of Pleroma, you can try these commands and see if they fix things:
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ For example, here is a sample policy module which rewrites all messages to "new
|
||||||
```elixir
|
```elixir
|
||||||
defmodule Pleroma.Web.ActivityPub.MRF.RewritePolicy do
|
defmodule Pleroma.Web.ActivityPub.MRF.RewritePolicy do
|
||||||
@moduledoc "MRF policy which rewrites all Notes to have 'new message content'."
|
@moduledoc "MRF policy which rewrites all Notes to have 'new message content'."
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
# Catch messages which contain Note objects with actual data to filter.
|
# Catch messages which contain Note objects with actual data to filter.
|
||||||
# Capture the object as `object`, the message content as `content` and the
|
# Capture the object as `object`, the message content as `content` and the
|
||||||
|
|
|
@ -300,7 +300,7 @@ See [Admin-API](admin_api.md)
|
||||||
* Note: Behaves exactly the same as `POST /api/v1/upload`.
|
* Note: Behaves exactly the same as `POST /api/v1/upload`.
|
||||||
Can only accept images - any attempt to upload non-image files will be met with `HTTP 415 Unsupported Media Type`.
|
Can only accept images - any attempt to upload non-image files will be met with `HTTP 415 Unsupported Media Type`.
|
||||||
|
|
||||||
## `/api/v1/pleroma/notification_settings`
|
## `/api/pleroma/notification_settings`
|
||||||
### Updates user notification settings
|
### Updates user notification settings
|
||||||
* Method `PUT`
|
* Method `PUT`
|
||||||
* Authentication: required
|
* Authentication: required
|
||||||
|
|
|
@ -5,25 +5,7 @@ This guide is a step-by-step installation guide for Alpine Linux. The instructio
|
||||||
|
|
||||||
It assumes that you have administrative rights, either as root or a user with [sudo permissions](https://www.linode.com/docs/tools-reference/custom-kernels-distros/install-alpine-linux-on-your-linode/#configuration). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su -l <username> -s $SHELL -c 'command'` instead.
|
It assumes that you have administrative rights, either as root or a user with [sudo permissions](https://www.linode.com/docs/tools-reference/custom-kernels-distros/install-alpine-linux-on-your-linode/#configuration). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su -l <username> -s $SHELL -c 'command'` instead.
|
||||||
|
|
||||||
### Required packages
|
{! backend/installation/generic_dependencies.include !}
|
||||||
|
|
||||||
* `postgresql`
|
|
||||||
* `elixir`
|
|
||||||
* `erlang`
|
|
||||||
* `erlang-parsetools`
|
|
||||||
* `erlang-xmerl`
|
|
||||||
* `git`
|
|
||||||
* `file-dev`
|
|
||||||
* Development Tools
|
|
||||||
* `cmake`
|
|
||||||
|
|
||||||
#### Optional packages used in this guide
|
|
||||||
|
|
||||||
* `nginx` (preferred, example configs for other reverse proxies can be found in the repo)
|
|
||||||
* `certbot` (or any other ACME client for Let’s Encrypt certificates)
|
|
||||||
* `ImageMagick`
|
|
||||||
* `ffmpeg`
|
|
||||||
* `exiftool`
|
|
||||||
|
|
||||||
### Prepare the system
|
### Prepare the system
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,9 @@
|
||||||
# Installing on Debian Based Distributions
|
# Installing on Debian Based Distributions
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
This guide will assume you are on Debian Stretch. This guide should also work with Ubuntu 16.04 and 18.04. It also assumes that you have administrative rights, either as root or a user with [sudo permissions](https://www.digitalocean.com/community/tutorials/how-to-add-delete-and-grant-sudo-privileges-to-users-on-a-debian-vps). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su <username> -s $SHELL -c 'command'` instead.
|
This guide will assume you are on Debian 11 (“bullseye”) or later. This guide should also work with Ubuntu 18.04 (“Bionic Beaver”) and later. It also assumes that you have administrative rights, either as root or a user with [sudo permissions](https://www.digitalocean.com/community/tutorials/how-to-add-delete-and-grant-sudo-privileges-to-users-on-a-debian-vps). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su <username> -s $SHELL -c 'command'` instead.
|
||||||
|
|
||||||
### Required packages
|
{! backend/installation/generic_dependencies.include !}
|
||||||
|
|
||||||
* `postgresql` (9.6+, Ubuntu 16.04 comes with 9.5, you can get a newer version from [here](https://www.postgresql.org/download/linux/ubuntu/))
|
|
||||||
* `postgresql-contrib` (9.6+, same situtation as above)
|
|
||||||
* `elixir` (1.8+, Follow the guide to install from the Erlang Solutions repo or use [asdf](https://github.com/asdf-vm/asdf) as the pleroma user)
|
|
||||||
* `erlang-dev`
|
|
||||||
* `erlang-nox`
|
|
||||||
* `libmagic-dev`
|
|
||||||
* `git`
|
|
||||||
* `build-essential`
|
|
||||||
* `cmake`
|
|
||||||
|
|
||||||
#### Optional packages used in this guide
|
|
||||||
|
|
||||||
* `nginx` (preferred, example configs for other reverse proxies can be found in the repo)
|
|
||||||
* `certbot` (or any other ACME client for Let’s Encrypt certificates)
|
|
||||||
* `ImageMagick`
|
|
||||||
* `ffmpeg`
|
|
||||||
* `exiftool`
|
|
||||||
|
|
||||||
### Prepare the system
|
### Prepare the system
|
||||||
|
|
||||||
|
@ -40,20 +22,14 @@ sudo apt install git build-essential postgresql postgresql-contrib cmake libmagi
|
||||||
|
|
||||||
### Install Elixir and Erlang
|
### Install Elixir and Erlang
|
||||||
|
|
||||||
* Download and add the Erlang repository:
|
* Install Elixir and Erlang (you might need to use backports or [asdf](https://github.com/asdf-vm/asdf) on old systems):
|
||||||
|
|
||||||
```shell
|
|
||||||
wget -P /tmp/ https://packages.erlang-solutions.com/erlang-solutions_2.0_all.deb
|
|
||||||
sudo dpkg -i /tmp/erlang-solutions_2.0_all.deb
|
|
||||||
```
|
|
||||||
|
|
||||||
* Install Elixir and Erlang:
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install elixir erlang-dev erlang-nox
|
sudo apt install elixir erlang-dev erlang-nox
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Optional packages: [`docs/installation/optional/media_graphics_packages.md`](../installation/optional/media_graphics_packages.md)
|
### Optional packages: [`docs/installation/optional/media_graphics_packages.md`](../installation/optional/media_graphics_packages.md)
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
|
|
||||||
This document was written for FreeBSD 12.1, but should be work on future releases.
|
This document was written for FreeBSD 12.1, but should be work on future releases.
|
||||||
|
|
||||||
## Required software
|
{! backend/installation/generic_dependencies.include !}
|
||||||
|
|
||||||
|
## Installing software used in this guide
|
||||||
|
|
||||||
This assumes the target system has `pkg(8)`.
|
This assumes the target system has `pkg(8)`.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
## Required dependencies
|
||||||
|
|
||||||
|
* PostgreSQL 9.6+
|
||||||
|
* Elixir 1.9+
|
||||||
|
* Erlang OTP 22.2+
|
||||||
|
* git
|
||||||
|
* file / libmagic
|
||||||
|
* gcc (clang might also work)
|
||||||
|
* GNU make
|
||||||
|
* CMake
|
||||||
|
|
||||||
|
## Optionnal dependencies
|
||||||
|
|
||||||
|
* ImageMagick
|
||||||
|
* FFmpeg
|
||||||
|
* exiftool
|
|
@ -3,9 +3,7 @@
|
||||||
|
|
||||||
This guide will assume that you have administrative rights, either as root or a user with [sudo permissions](https://wiki.gentoo.org/wiki/Sudo). Lines that begin with `#` indicate that they should be run as the superuser. Lines using `$` should be run as the indicated user, e.g. `pleroma$` should be run as the `pleroma` user.
|
This guide will assume that you have administrative rights, either as root or a user with [sudo permissions](https://wiki.gentoo.org/wiki/Sudo). Lines that begin with `#` indicate that they should be run as the superuser. Lines using `$` should be run as the indicated user, e.g. `pleroma$` should be run as the `pleroma` user.
|
||||||
|
|
||||||
### Configuring your hostname (optional)
|
{! backend/installation/generic_dependencies.include !}
|
||||||
|
|
||||||
If you would like your prompt to permanently include your host/domain, change `/etc/conf.d/hostname` to your hostname. You can reboot or use the `hostname` command to make immediate changes.
|
|
||||||
|
|
||||||
### Your make.conf, package.use, and USE flags
|
### Your make.conf, package.use, and USE flags
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Installing on NetBSD
|
# Installing on NetBSD
|
||||||
|
|
||||||
## Required software
|
{! backend/installation/generic_dependencies.include !}
|
||||||
|
|
||||||
|
## Installing software used in this guide
|
||||||
|
|
||||||
pkgin should have been installed by the NetBSD installer if you selected
|
pkgin should have been installed by the NetBSD installer if you selected
|
||||||
the right options. If it isn't installed, install it using pkg_add.
|
the right options. If it isn't installed, install it using pkg_add.
|
||||||
|
|
|
@ -4,19 +4,11 @@ This guide describes the installation and configuration of pleroma (and the requ
|
||||||
|
|
||||||
For any additional information regarding commands and configuration files mentioned here, check the man pages [online](https://man.openbsd.org/) or directly on your server with the man command.
|
For any additional information regarding commands and configuration files mentioned here, check the man pages [online](https://man.openbsd.org/) or directly on your server with the man command.
|
||||||
|
|
||||||
|
{! backend/installation/generic_dependencies.include !}
|
||||||
|
|
||||||
|
### Preparing the system
|
||||||
#### Required software
|
#### Required software
|
||||||
|
|
||||||
The following packages need to be installed:
|
|
||||||
|
|
||||||
* elixir
|
|
||||||
* gmake
|
|
||||||
* git
|
|
||||||
* postgresql-server
|
|
||||||
* postgresql-contrib
|
|
||||||
* cmake
|
|
||||||
* ffmpeg
|
|
||||||
* ImageMagick
|
|
||||||
|
|
||||||
To install them, run the following command (with doas or as root):
|
To install them, run the following command (with doas or as root):
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
@ -31,7 +31,7 @@ Other than things bundled in the OTP release Pleroma depends on:
|
||||||
|
|
||||||
=== "Alpine"
|
=== "Alpine"
|
||||||
```
|
```
|
||||||
echo "http://nl.alpinelinux.org/alpine/latest-stable/community" >> /etc/apk/repositories
|
awk 'NR==2' /etc/apk/repositories | sed 's/main/community/' | tee -a /etc/apk/repositories
|
||||||
apk update
|
apk update
|
||||||
apk add curl unzip ncurses postgresql postgresql-contrib nginx certbot file-dev
|
apk add curl unzip ncurses postgresql postgresql-contrib nginx certbot file-dev
|
||||||
```
|
```
|
||||||
|
@ -50,7 +50,6 @@ Per [`docs/installation/optional/media_graphics_packages.md`](optional/media_gra
|
||||||
|
|
||||||
=== "Alpine"
|
=== "Alpine"
|
||||||
```
|
```
|
||||||
echo "http://nl.alpinelinux.org/alpine/latest-stable/community" >> /etc/apk/repositories
|
|
||||||
apk update
|
apk update
|
||||||
apk add imagemagick ffmpeg exiftool
|
apk add imagemagick ffmpeg exiftool
|
||||||
```
|
```
|
||||||
|
|
|
@ -96,6 +96,15 @@ def run(["prune_objects" | args]) do
|
||||||
)
|
)
|
||||||
|> Repo.delete_all(timeout: :infinity)
|
|> Repo.delete_all(timeout: :infinity)
|
||||||
|
|
||||||
|
prune_hashtags_query = """
|
||||||
|
DELETE FROM hashtags AS ht
|
||||||
|
WHERE NOT EXISTS (
|
||||||
|
SELECT 1 FROM hashtags_objects hto
|
||||||
|
WHERE ht.id = hto.hashtag_id)
|
||||||
|
"""
|
||||||
|
|
||||||
|
Repo.query(prune_hashtags_query)
|
||||||
|
|
||||||
if Keyword.get(options, :vacuum) do
|
if Keyword.get(options, :vacuum) do
|
||||||
Maintenance.vacuum("full")
|
Maintenance.vacuum("full")
|
||||||
end
|
end
|
||||||
|
|
|
@ -313,13 +313,15 @@ def delete_all_by_object_ap_id(id) when is_binary(id) do
|
||||||
|
|
||||||
def delete_all_by_object_ap_id(_), do: nil
|
def delete_all_by_object_ap_id(_), do: nil
|
||||||
|
|
||||||
defp purge_web_resp_cache(%Activity{} = activity) do
|
defp purge_web_resp_cache(%Activity{data: %{"id" => id}} = activity) when is_binary(id) do
|
||||||
%{path: path} = URI.parse(activity.data["id"])
|
with %{path: path} <- URI.parse(id) do
|
||||||
@cachex.del(:web_resp_cache, path)
|
@cachex.del(:web_resp_cache, path)
|
||||||
|
end
|
||||||
|
|
||||||
activity
|
activity
|
||||||
end
|
end
|
||||||
|
|
||||||
defp purge_web_resp_cache(nil), do: nil
|
defp purge_web_resp_cache(activity), do: activity
|
||||||
|
|
||||||
def follow_accepted?(
|
def follow_accepted?(
|
||||||
%Activity{data: %{"type" => "Follow", "object" => followed_ap_id}} = activity
|
%Activity{data: %{"type" => "Follow", "object" => followed_ap_id}} = activity
|
||||||
|
|
|
@ -168,7 +168,8 @@ defp check_system_commands!(:ok) do
|
||||||
check_filter(Pleroma.Upload.Filter.Mogrify, "mogrify"),
|
check_filter(Pleroma.Upload.Filter.Mogrify, "mogrify"),
|
||||||
check_filter(Pleroma.Upload.Filter.Mogrifun, "mogrify"),
|
check_filter(Pleroma.Upload.Filter.Mogrifun, "mogrify"),
|
||||||
check_filter(Pleroma.Upload.Filter.AnalyzeMetadata, "mogrify"),
|
check_filter(Pleroma.Upload.Filter.AnalyzeMetadata, "mogrify"),
|
||||||
check_filter(Pleroma.Upload.Filter.AnalyzeMetadata, "convert")
|
check_filter(Pleroma.Upload.Filter.AnalyzeMetadata, "convert"),
|
||||||
|
check_filter(Pleroma.Upload.Filter.AnalyzeMetadata, "ffprobe")
|
||||||
]
|
]
|
||||||
|
|
||||||
preview_proxy_commands_status =
|
preview_proxy_commands_status =
|
||||||
|
|
|
@ -3,21 +3,21 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Config.Loader do
|
defmodule Pleroma.Config.Loader do
|
||||||
defp reject_keys,
|
# These modules are only being used as keys here (for equality check),
|
||||||
do: [
|
# so it's okay to use `Module.concat/1` to have the compiler ignore them.
|
||||||
Pleroma.Repo,
|
@reject_keys [
|
||||||
Pleroma.Web.Endpoint,
|
Module.concat(["Pleroma.Repo"]),
|
||||||
:env,
|
Module.concat(["Pleroma.Web.Endpoint"]),
|
||||||
:configurable_from_database,
|
:env,
|
||||||
:database,
|
:configurable_from_database,
|
||||||
:swarm
|
:database,
|
||||||
]
|
:swarm
|
||||||
|
]
|
||||||
|
|
||||||
defp reject_groups,
|
@reject_groups [
|
||||||
do: [
|
:postgrex,
|
||||||
:postgrex,
|
:tesla
|
||||||
:tesla
|
]
|
||||||
]
|
|
||||||
|
|
||||||
if Code.ensure_loaded?(Config.Reader) do
|
if Code.ensure_loaded?(Config.Reader) do
|
||||||
@reader Config.Reader
|
@reader Config.Reader
|
||||||
|
@ -54,7 +54,7 @@ defp filter(configs) do
|
||||||
@spec filter_group(atom(), keyword()) :: keyword()
|
@spec filter_group(atom(), keyword()) :: keyword()
|
||||||
def filter_group(group, configs) do
|
def filter_group(group, configs) do
|
||||||
Enum.reject(configs[group], fn {key, _v} ->
|
Enum.reject(configs[group], fn {key, _v} ->
|
||||||
key in reject_keys() or group in reject_groups() or
|
key in @reject_keys or group in @reject_groups or
|
||||||
(group == :phoenix and key == :serve_endpoints)
|
(group == :phoenix and key == :serve_endpoints)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,13 +5,18 @@
|
||||||
defmodule Pleroma.Instances do
|
defmodule Pleroma.Instances do
|
||||||
@moduledoc "Instances context."
|
@moduledoc "Instances context."
|
||||||
|
|
||||||
@adapter Pleroma.Instances.Instance
|
alias Pleroma.Instances.Instance
|
||||||
|
|
||||||
defdelegate filter_reachable(urls_or_hosts), to: @adapter
|
def filter_reachable(urls_or_hosts), do: Instance.filter_reachable(urls_or_hosts)
|
||||||
defdelegate reachable?(url_or_host), to: @adapter
|
|
||||||
defdelegate set_reachable(url_or_host), to: @adapter
|
def reachable?(url_or_host), do: Instance.reachable?(url_or_host)
|
||||||
defdelegate set_unreachable(url_or_host, unreachable_since \\ nil), to: @adapter
|
|
||||||
defdelegate get_consistently_unreachable(), to: @adapter
|
def set_reachable(url_or_host), do: Instance.set_reachable(url_or_host)
|
||||||
|
|
||||||
|
def set_unreachable(url_or_host, unreachable_since \\ nil),
|
||||||
|
do: Instance.set_unreachable(url_or_host, unreachable_since)
|
||||||
|
|
||||||
|
def get_consistently_unreachable, do: Instance.get_consistently_unreachable()
|
||||||
|
|
||||||
def set_consistently_unreachable(url_or_host),
|
def set_consistently_unreachable(url_or_host),
|
||||||
do: set_unreachable(url_or_host, reachability_datetime_threshold())
|
do: set_unreachable(url_or_host, reachability_datetime_threshold())
|
||||||
|
|
|
@ -8,8 +8,6 @@ defmodule Pleroma.Repo do
|
||||||
adapter: Ecto.Adapters.Postgres,
|
adapter: Ecto.Adapters.Postgres,
|
||||||
migration_timestamps: [type: :naive_datetime_usec]
|
migration_timestamps: [type: :naive_datetime_usec]
|
||||||
|
|
||||||
use Ecto.Explain
|
|
||||||
|
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
|
|
@ -411,7 +411,7 @@ defp increase_read_duration(_) do
|
||||||
{:ok, :no_duration_limit, :no_duration_limit}
|
{:ok, :no_duration_limit, :no_duration_limit}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp client, do: Pleroma.ReverseProxy.Client
|
defp client, do: Pleroma.ReverseProxy.Client.Wrapper
|
||||||
|
|
||||||
defp track_failed_url(url, error, opts) do
|
defp track_failed_url(url, error, opts) do
|
||||||
ttl =
|
ttl =
|
||||||
|
|
|
@ -17,22 +17,4 @@ defmodule Pleroma.ReverseProxy.Client do
|
||||||
@callback stream_body(map()) :: {:ok, binary(), map()} | :done | {:error, atom() | String.t()}
|
@callback stream_body(map()) :: {:ok, binary(), map()} | :done | {:error, atom() | String.t()}
|
||||||
|
|
||||||
@callback close(reference() | pid() | map()) :: :ok
|
@callback close(reference() | pid() | map()) :: :ok
|
||||||
|
|
||||||
def request(method, url, headers, body \\ "", opts \\ []) do
|
|
||||||
client().request(method, url, headers, body, opts)
|
|
||||||
end
|
|
||||||
|
|
||||||
def stream_body(ref), do: client().stream_body(ref)
|
|
||||||
|
|
||||||
def close(ref), do: client().close(ref)
|
|
||||||
|
|
||||||
defp client do
|
|
||||||
:tesla
|
|
||||||
|> Application.get_env(:adapter)
|
|
||||||
|> client()
|
|
||||||
end
|
|
||||||
|
|
||||||
defp client(Tesla.Adapter.Hackney), do: Pleroma.ReverseProxy.Client.Hackney
|
|
||||||
defp client(Tesla.Adapter.Gun), do: Pleroma.ReverseProxy.Client.Tesla
|
|
||||||
defp client(_), do: Pleroma.Config.get!(Pleroma.ReverseProxy.Client)
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.ReverseProxy.Client.Wrapper do
|
||||||
|
@moduledoc "Meta-client that calls the appropriate client from the config."
|
||||||
|
@behaviour Pleroma.ReverseProxy.Client
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def request(method, url, headers, body \\ "", opts \\ []) do
|
||||||
|
client().request(method, url, headers, body, opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def stream_body(ref), do: client().stream_body(ref)
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def close(ref), do: client().close(ref)
|
||||||
|
|
||||||
|
defp client do
|
||||||
|
:tesla
|
||||||
|
|> Application.get_env(:adapter)
|
||||||
|
|> client()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp client(Tesla.Adapter.Hackney), do: Pleroma.ReverseProxy.Client.Hackney
|
||||||
|
defp client(Tesla.Adapter.Gun), do: Pleroma.ReverseProxy.Client.Tesla
|
||||||
|
defp client(_), do: Pleroma.Config.get!(Pleroma.ReverseProxy.Client)
|
||||||
|
end
|
|
@ -9,7 +9,6 @@ defmodule Pleroma.Tests.AuthTestController do
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.Plugs.EnsurePublicOrAuthenticatedPlug
|
|
||||||
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
||||||
|
|
||||||
# Serves only with proper OAuth token (:api and :authenticated_api)
|
# Serves only with proper OAuth token (:api and :authenticated_api)
|
||||||
|
@ -47,10 +46,7 @@ defmodule Pleroma.Tests.AuthTestController do
|
||||||
# Via :authenticated_api, serves if token is present and has requested scopes
|
# Via :authenticated_api, serves if token is present and has requested scopes
|
||||||
#
|
#
|
||||||
# Suggested use: as :fallback_oauth_check but open with nil :user for :api on private instances
|
# Suggested use: as :fallback_oauth_check but open with nil :user for :api on private instances
|
||||||
plug(
|
plug(:skip_public_check when action == :fallback_oauth_skip_publicity_check)
|
||||||
:skip_plug,
|
|
||||||
EnsurePublicOrAuthenticatedPlug when action == :fallback_oauth_skip_publicity_check
|
|
||||||
)
|
|
||||||
|
|
||||||
plug(
|
plug(
|
||||||
OAuthScopesPlug,
|
OAuthScopesPlug,
|
||||||
|
@ -62,11 +58,7 @@ defmodule Pleroma.Tests.AuthTestController do
|
||||||
# Via :authenticated_api, serves if :user is set (regardless of token presence and its scopes)
|
# Via :authenticated_api, serves if :user is set (regardless of token presence and its scopes)
|
||||||
#
|
#
|
||||||
# Suggested use: making an :api endpoint always accessible (e.g. email confirmation endpoint)
|
# Suggested use: making an :api endpoint always accessible (e.g. email confirmation endpoint)
|
||||||
plug(
|
plug(:skip_auth when action == :skip_oauth_skip_publicity_check)
|
||||||
:skip_plug,
|
|
||||||
[OAuthScopesPlug, EnsurePublicOrAuthenticatedPlug]
|
|
||||||
when action == :skip_oauth_skip_publicity_check
|
|
||||||
)
|
|
||||||
|
|
||||||
# Via :authenticated_api, always fails with 403 (endpoint is insecure)
|
# Via :authenticated_api, always fails with 403 (endpoint is insecure)
|
||||||
# Via :api, drops :user if present and serves if public (private instance rejects on no user)
|
# Via :api, drops :user if present and serves if public (private instance rejects on no user)
|
||||||
|
|
|
@ -15,13 +15,13 @@ defmodule Pleroma.Upload.Filter do
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
@callback filter(Pleroma.Upload.t()) ::
|
@callback filter(upload :: struct()) ::
|
||||||
{:ok, :filtered}
|
{:ok, :filtered}
|
||||||
| {:ok, :noop}
|
| {:ok, :noop}
|
||||||
| {:ok, :filtered, Pleroma.Upload.t()}
|
| {:ok, :filtered, upload :: struct()}
|
||||||
| {:error, any()}
|
| {:error, any()}
|
||||||
|
|
||||||
@spec filter([module()], Pleroma.Upload.t()) :: {:ok, Pleroma.Upload.t()} | {:error, any()}
|
@spec filter([module()], upload :: struct()) :: {:ok, upload :: struct()} | {:error, any()}
|
||||||
|
|
||||||
def filter([], upload) do
|
def filter([], upload) do
|
||||||
{:ok, upload}
|
{:ok, upload}
|
||||||
|
|
|
@ -33,6 +33,23 @@ def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _} = upload)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def filter(%Pleroma.Upload{tempfile: file, content_type: "video" <> _} = upload) do
|
||||||
|
try do
|
||||||
|
result = media_dimensions(file)
|
||||||
|
|
||||||
|
upload =
|
||||||
|
upload
|
||||||
|
|> Map.put(:width, result.width)
|
||||||
|
|> Map.put(:height, result.height)
|
||||||
|
|
||||||
|
{:ok, :filtered, upload}
|
||||||
|
rescue
|
||||||
|
e in ErlangError ->
|
||||||
|
Logger.warn("#{__MODULE__}: #{inspect(e)}")
|
||||||
|
{:ok, :noop}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def filter(_), do: {:ok, :noop}
|
def filter(_), do: {:ok, :noop}
|
||||||
|
|
||||||
defp get_blurhash(file) do
|
defp get_blurhash(file) do
|
||||||
|
@ -42,4 +59,25 @@ defp get_blurhash(file) do
|
||||||
_ -> nil
|
_ -> nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp media_dimensions(file) do
|
||||||
|
with executable when is_binary(executable) <- System.find_executable("ffprobe"),
|
||||||
|
args = [
|
||||||
|
"-v",
|
||||||
|
"error",
|
||||||
|
"-show_entries",
|
||||||
|
"stream=width,height",
|
||||||
|
"-of",
|
||||||
|
"csv=p=0:s=x",
|
||||||
|
file
|
||||||
|
],
|
||||||
|
{result, 0} <- System.cmd(executable, args),
|
||||||
|
[width, height] <-
|
||||||
|
String.split(String.trim(result), "x") |> Enum.map(&String.to_integer(&1)) do
|
||||||
|
%{width: width, height: height}
|
||||||
|
else
|
||||||
|
nil -> {:error, {:ffprobe, :command_not_found}}
|
||||||
|
{:error, _} = error -> error
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1694,8 +1694,6 @@ def purge_user_changeset(user) do
|
||||||
email: nil,
|
email: nil,
|
||||||
name: nil,
|
name: nil,
|
||||||
password_hash: nil,
|
password_hash: nil,
|
||||||
keys: nil,
|
|
||||||
public_key: nil,
|
|
||||||
avatar: %{},
|
avatar: %{},
|
||||||
tags: [],
|
tags: [],
|
||||||
last_refreshed_at: nil,
|
last_refreshed_at: nil,
|
||||||
|
@ -1706,9 +1704,7 @@ def purge_user_changeset(user) do
|
||||||
follower_count: 0,
|
follower_count: 0,
|
||||||
following_count: 0,
|
following_count: 0,
|
||||||
is_locked: false,
|
is_locked: false,
|
||||||
is_confirmed: true,
|
|
||||||
password_reset_pending: false,
|
password_reset_pending: false,
|
||||||
is_approved: true,
|
|
||||||
registration_reason: nil,
|
registration_reason: nil,
|
||||||
confirmation_token: nil,
|
confirmation_token: nil,
|
||||||
domain_blocks: [],
|
domain_blocks: [],
|
||||||
|
@ -1723,45 +1719,53 @@ def purge_user_changeset(user) do
|
||||||
raw_fields: [],
|
raw_fields: [],
|
||||||
is_discoverable: false,
|
is_discoverable: false,
|
||||||
also_known_as: []
|
also_known_as: []
|
||||||
|
# id: preserved
|
||||||
|
# ap_id: preserved
|
||||||
|
# nickname: preserved
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Purge doesn't delete the user from the database.
|
||||||
|
# It just nulls all its fields and deactivates it.
|
||||||
|
# See `User.purge_user_changeset/1` above.
|
||||||
|
defp purge(%User{} = user) do
|
||||||
|
user
|
||||||
|
|> purge_user_changeset()
|
||||||
|
|> update_and_set_cache()
|
||||||
|
end
|
||||||
|
|
||||||
def delete(users) when is_list(users) do
|
def delete(users) when is_list(users) do
|
||||||
for user <- users, do: delete(user)
|
for user <- users, do: delete(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete(%User{} = user) do
|
def delete(%User{} = user) do
|
||||||
|
# Purge the user immediately
|
||||||
|
purge(user)
|
||||||
BackgroundWorker.enqueue("delete_user", %{"user_id" => user.id})
|
BackgroundWorker.enqueue("delete_user", %{"user_id" => user.id})
|
||||||
end
|
end
|
||||||
|
|
||||||
defp delete_and_invalidate_cache(%User{} = user) do
|
# *Actually* delete the user from the DB
|
||||||
|
defp delete_from_db(%User{} = user) do
|
||||||
invalidate_cache(user)
|
invalidate_cache(user)
|
||||||
Repo.delete(user)
|
Repo.delete(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp delete_or_deactivate(%User{local: false} = user), do: delete_and_invalidate_cache(user)
|
# If the user never finalized their account, it's safe to delete them.
|
||||||
|
defp maybe_delete_from_db(%User{local: true, is_confirmed: false} = user),
|
||||||
|
do: delete_from_db(user)
|
||||||
|
|
||||||
defp delete_or_deactivate(%User{local: true} = user) do
|
defp maybe_delete_from_db(%User{local: true, is_approved: false} = user),
|
||||||
status = account_status(user)
|
do: delete_from_db(user)
|
||||||
|
|
||||||
case status do
|
defp maybe_delete_from_db(user), do: {:ok, user}
|
||||||
:confirmation_pending ->
|
|
||||||
delete_and_invalidate_cache(user)
|
|
||||||
|
|
||||||
:approval_pending ->
|
|
||||||
delete_and_invalidate_cache(user)
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
user
|
|
||||||
|> purge_user_changeset()
|
|
||||||
|> update_and_set_cache()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def perform(:force_password_reset, user), do: force_password_reset(user)
|
def perform(:force_password_reset, user), do: force_password_reset(user)
|
||||||
|
|
||||||
@spec perform(atom(), User.t()) :: {:ok, User.t()}
|
@spec perform(atom(), User.t()) :: {:ok, User.t()}
|
||||||
def perform(:delete, %User{} = user) do
|
def perform(:delete, %User{} = user) do
|
||||||
|
# Purge the user again, in case perform/2 is called directly
|
||||||
|
purge(user)
|
||||||
|
|
||||||
# Remove all relationships
|
# Remove all relationships
|
||||||
user
|
user
|
||||||
|> get_followers()
|
|> get_followers()
|
||||||
|
@ -1779,10 +1783,9 @@ def perform(:delete, %User{} = user) do
|
||||||
|
|
||||||
delete_user_activities(user)
|
delete_user_activities(user)
|
||||||
delete_notifications_from_user_activities(user)
|
delete_notifications_from_user_activities(user)
|
||||||
|
|
||||||
delete_outgoing_pending_follow_requests(user)
|
delete_outgoing_pending_follow_requests(user)
|
||||||
|
|
||||||
delete_or_deactivate(user)
|
maybe_delete_from_db(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
def perform(:set_activation_async, user, status), do: set_activation(user, status)
|
def perform(:set_activation_async, user, status), do: set_activation(user, status)
|
||||||
|
|
|
@ -27,7 +27,7 @@ defmodule Pleroma.User.Query do
|
||||||
- e.g. Pleroma.User.Query.build(%{ap_id: ["http://ap_id1", "http://ap_id2"]})
|
- e.g. Pleroma.User.Query.build(%{ap_id: ["http://ap_id1", "http://ap_id2"]})
|
||||||
"""
|
"""
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
import Pleroma.Web.AdminAPI.Search, only: [not_empty_string: 1]
|
import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1]
|
||||||
|
|
||||||
alias Pleroma.FollowingRelationship
|
alias Pleroma.FollowingRelationship
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
|
|
@ -62,6 +62,14 @@ defp skip_plug(conn, plug_modules) do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp skip_auth(conn, _) do
|
||||||
|
skip_plug(conn, [OAuthScopesPlug, EnsurePublicOrAuthenticatedPlug])
|
||||||
|
end
|
||||||
|
|
||||||
|
defp skip_public_check(conn, _) do
|
||||||
|
skip_plug(conn, EnsurePublicOrAuthenticatedPlug)
|
||||||
|
end
|
||||||
|
|
||||||
# Executed just before actual controller action, invokes before-action hooks (callbacks)
|
# Executed just before actual controller action, invokes before-action hooks (callbacks)
|
||||||
defp action(conn, params) do
|
defp action(conn, params) do
|
||||||
with %{halted: false} = conn <-
|
with %{halted: false} = conn <-
|
||||||
|
|
|
@ -53,15 +53,18 @@ defp get_recipients(data) do
|
||||||
{recipients, to, cc}
|
{recipients, to, cc}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp check_actor_is_active(nil), do: true
|
defp check_actor_can_insert(%{"type" => "Delete"}), do: true
|
||||||
|
defp check_actor_can_insert(%{"type" => "Undo"}), do: true
|
||||||
|
|
||||||
defp check_actor_is_active(actor) when is_binary(actor) do
|
defp check_actor_can_insert(%{"actor" => actor}) when is_binary(actor) do
|
||||||
case User.get_cached_by_ap_id(actor) do
|
case User.get_cached_by_ap_id(actor) do
|
||||||
%User{is_active: true} -> true
|
%User{is_active: true} -> true
|
||||||
_ -> false
|
_ -> false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp check_actor_can_insert(_), do: true
|
||||||
|
|
||||||
defp check_remote_limit(%{"object" => %{"content" => content}}) when not is_nil(content) do
|
defp check_remote_limit(%{"object" => %{"content" => content}}) when not is_nil(content) do
|
||||||
limit = Config.get([:instance, :remote_limit])
|
limit = Config.get([:instance, :remote_limit])
|
||||||
String.length(content) <= limit
|
String.length(content) <= limit
|
||||||
|
@ -117,7 +120,7 @@ def persist(object, meta) do
|
||||||
def insert(map, local \\ true, fake \\ false, bypass_actor_check \\ false) when is_map(map) do
|
def insert(map, local \\ true, fake \\ false, bypass_actor_check \\ false) when is_map(map) do
|
||||||
with nil <- Activity.normalize(map),
|
with nil <- Activity.normalize(map),
|
||||||
map <- lazy_put_activity_defaults(map, fake),
|
map <- lazy_put_activity_defaults(map, fake),
|
||||||
{_, true} <- {:actor_check, bypass_actor_check || check_actor_is_active(map["actor"])},
|
{_, true} <- {:actor_check, bypass_actor_check || check_actor_can_insert(map)},
|
||||||
{_, true} <- {:remote_limit_pass, check_remote_limit(map)},
|
{_, true} <- {:remote_limit_pass, check_remote_limit(map)},
|
||||||
{:ok, map} <- MRF.filter(map),
|
{:ok, map} <- MRF.filter(map),
|
||||||
{recipients, _, _} = get_recipients(map),
|
{recipients, _, _} = get_recipients(map),
|
||||||
|
|
|
@ -51,17 +51,6 @@ defmodule Pleroma.Web.ActivityPub.MRF do
|
||||||
|
|
||||||
@required_description_keys [:key, :related_policy]
|
@required_description_keys [:key, :related_policy]
|
||||||
|
|
||||||
@callback filter(Map.t()) :: {:ok | :reject, Map.t()}
|
|
||||||
@callback describe() :: {:ok | :error, Map.t()}
|
|
||||||
@callback config_description() :: %{
|
|
||||||
optional(:children) => [map()],
|
|
||||||
key: atom(),
|
|
||||||
related_policy: String.t(),
|
|
||||||
label: String.t(),
|
|
||||||
description: String.t()
|
|
||||||
}
|
|
||||||
@optional_callbacks config_description: 0
|
|
||||||
|
|
||||||
def filter(policies, %{} = message) do
|
def filter(policies, %{} = message) do
|
||||||
policies
|
policies
|
||||||
|> Enum.reduce({:ok, message}, fn
|
|> Enum.reduce({:ok, message}, fn
|
||||||
|
@ -142,7 +131,7 @@ def describe(policies) do
|
||||||
def describe, do: get_policies() |> describe()
|
def describe, do: get_policies() |> describe()
|
||||||
|
|
||||||
def config_descriptions do
|
def config_descriptions do
|
||||||
Pleroma.Web.ActivityPub.MRF
|
Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|> Pleroma.Docs.Generator.list_behaviour_implementations()
|
|> Pleroma.Docs.Generator.list_behaviour_implementations()
|
||||||
|> config_descriptions()
|
|> config_descriptions()
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy do
|
defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy do
|
||||||
@moduledoc "Adds expiration to all local Create activities"
|
@moduledoc "Adds expiration to all local Create activities"
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(activity) do
|
def filter(activity) do
|
||||||
|
|
|
@ -7,7 +7,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy do
|
||||||
|
|
||||||
@moduledoc "Prevent followbots from following with a bit of heuristic"
|
@moduledoc "Prevent followbots from following with a bit of heuristic"
|
||||||
|
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
# XXX: this should become User.normalize_by_ap_id() or similar, really.
|
# XXX: this should become User.normalize_by_ap_id() or similar, really.
|
||||||
defp normalize_by_ap_id(%{"id" => id}), do: User.get_cached_by_ap_id(id)
|
defp normalize_by_ap_id(%{"id" => id}), do: User.get_cached_by_ap_id(id)
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy do
|
defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy do
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.MRF.DropPolicy do
|
defmodule Pleroma.Web.ActivityPub.MRF.DropPolicy do
|
||||||
require Logger
|
require Logger
|
||||||
@moduledoc "Drop and log everything received"
|
@moduledoc "Drop and log everything received"
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(object) do
|
def filter(object) do
|
||||||
|
|
|
@ -6,7 +6,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.EnsureRePrepended do
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
|
|
||||||
@moduledoc "Ensure a re: is prepended on replies to a post with a Subject"
|
@moduledoc "Ensure a re: is prepended on replies to a post with a Subject"
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
@reply_prefix Regex.compile!("^re:[[:space:]]*", [:caseless])
|
@reply_prefix Regex.compile!("^re:[[:space:]]*", [:caseless])
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.MRF.FollowBotPolicy do
|
defmodule Pleroma.Web.ActivityPub.MRF.FollowBotPolicy do
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
alias Pleroma.Config
|
alias Pleroma.Config
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.ActivityPub.MRF.ForceBotUnlistedPolicy do
|
defmodule Pleroma.Web.ActivityPub.MRF.ForceBotUnlistedPolicy do
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
@moduledoc "Remove bot posts from federated timeline"
|
@moduledoc "Remove bot posts from federated timeline"
|
||||||
|
|
||||||
require Pleroma.Constants
|
require Pleroma.Constants
|
||||||
|
|
|
@ -14,7 +14,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HashtagPolicy do
|
||||||
Note: This MRF Policy is always enabled, if you want to disable it you have to set empty lists.
|
Note: This MRF Policy is always enabled, if you want to disable it you have to set empty lists.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
defp check_reject(message, hashtags) do
|
defp check_reject(message, hashtags) do
|
||||||
if Enum.any?(Config.get([:mrf_hashtag, :reject]), fn match -> match in hashtags end) do
|
if Enum.any?(Config.get([:mrf_hashtag, :reject]), fn match -> match in hashtags end) do
|
||||||
|
|
|
@ -9,7 +9,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do
|
||||||
|
|
||||||
@moduledoc "Block messages with too much mentions (configurable)"
|
@moduledoc "Block messages with too much mentions (configurable)"
|
||||||
|
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
defp delist_message(message, threshold) when threshold > 0 do
|
defp delist_message(message, threshold) when threshold > 0 do
|
||||||
follower_collection = User.get_cached_by_ap_id(message["actor"]).follower_address
|
follower_collection = User.get_cached_by_ap_id(message["actor"]).follower_address
|
||||||
|
|
|
@ -7,7 +7,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
|
||||||
|
|
||||||
@moduledoc "Reject or Word-Replace messages with a keyword or regex"
|
@moduledoc "Reject or Word-Replace messages with a keyword or regex"
|
||||||
|
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
defp string_matches?(string, _) when not is_binary(string) do
|
defp string_matches?(string, _) when not is_binary(string) do
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do
|
defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do
|
||||||
@moduledoc "Preloads any attachments in the MediaProxy cache by prefetching them"
|
@moduledoc "Preloads any attachments in the MediaProxy cache by prefetching them"
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
alias Pleroma.HTTP
|
alias Pleroma.HTTP
|
||||||
alias Pleroma.Web.MediaProxy
|
alias Pleroma.Web.MediaProxy
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicy do
|
defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicy do
|
||||||
@moduledoc "Block messages which mention a user"
|
@moduledoc "Block messages which mention a user"
|
||||||
|
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(%{"type" => "Create"} = message) do
|
def filter(%{"type" => "Create"} = message) do
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy do
|
defmodule Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy do
|
||||||
@moduledoc "Filter local activities which have no content"
|
@moduledoc "Filter local activities which have no content"
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
alias Pleroma.Web.Endpoint
|
alias Pleroma.Web.Endpoint
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.ActivityPub.MRF.NoOpPolicy do
|
defmodule Pleroma.Web.ActivityPub.MRF.NoOpPolicy do
|
||||||
@moduledoc "Does nothing (lets the messages go through unmodified)"
|
@moduledoc "Does nothing (lets the messages go through unmodified)"
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(object) do
|
def filter(object) do
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.ActivityPub.MRF.NoPlaceholderTextPolicy do
|
defmodule Pleroma.Web.ActivityPub.MRF.NoPlaceholderTextPolicy do
|
||||||
@moduledoc "Ensure no content placeholder is present (such as the dot from mastodon)"
|
@moduledoc "Ensure no content placeholder is present (such as the dot from mastodon)"
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(
|
def filter(
|
||||||
|
|
|
@ -6,7 +6,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.NormalizeMarkup do
|
||||||
@moduledoc "Scrub configured hypertext markup"
|
@moduledoc "Scrub configured hypertext markup"
|
||||||
alias Pleroma.HTML
|
alias Pleroma.HTML
|
||||||
|
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(%{"type" => "Create", "object" => child_object} = object) do
|
def filter(%{"type" => "Create", "object" => child_object} = object) do
|
||||||
|
|
|
@ -9,7 +9,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do
|
||||||
require Pleroma.Constants
|
require Pleroma.Constants
|
||||||
|
|
||||||
@moduledoc "Filter activities depending on their age"
|
@moduledoc "Filter activities depending on their age"
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
defp check_date(%{"object" => %{"published" => published}} = message) do
|
defp check_date(%{"object" => %{"published" => published}} = message) do
|
||||||
with %DateTime{} = now <- DateTime.utc_now(),
|
with %DateTime{} = now <- DateTime.utc_now(),
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.ActivityPub.MRF.Policy do
|
||||||
|
@callback filter(Map.t()) :: {:ok | :reject, Map.t()}
|
||||||
|
@callback describe() :: {:ok | :error, Map.t()}
|
||||||
|
@callback config_description() :: %{
|
||||||
|
optional(:children) => [map()],
|
||||||
|
key: atom(),
|
||||||
|
related_policy: String.t(),
|
||||||
|
label: String.t(),
|
||||||
|
description: String.t()
|
||||||
|
}
|
||||||
|
@optional_callbacks config_description: 0
|
||||||
|
end
|
|
@ -8,7 +8,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do
|
||||||
alias Pleroma.Config
|
alias Pleroma.Config
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
require Pleroma.Constants
|
require Pleroma.Constants
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
||||||
@moduledoc "Filter activities depending on their origin instance"
|
@moduledoc "Filter activities depending on their origin instance"
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
alias Pleroma.Config
|
alias Pleroma.Config
|
||||||
alias Pleroma.FollowingRelationship
|
alias Pleroma.FollowingRelationship
|
||||||
|
|
|
@ -8,7 +8,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy do
|
||||||
alias Pleroma.Config
|
alias Pleroma.Config
|
||||||
|
|
||||||
@moduledoc "Detect new emojis by their shortcode and steals them"
|
@moduledoc "Detect new emojis by their shortcode and steals them"
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
defp accept_host?(host), do: host in Config.get([:mrf_steal_emoji, :hosts], [])
|
defp accept_host?(host), do: host in Config.get([:mrf_steal_emoji, :hosts], [])
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SubchainPolicy do
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
defp lookup_subchain(actor) do
|
defp lookup_subchain(actor) do
|
||||||
with matches <- Config.get([:mrf_subchain, :match_actor]),
|
with matches <- Config.get([:mrf_subchain, :match_actor]),
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
|
defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
Apply policies based on user tags
|
Apply policies based on user tags
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy do
|
||||||
alias Pleroma.Config
|
alias Pleroma.Config
|
||||||
|
|
||||||
@moduledoc "Accept-list of users from specified instances"
|
@moduledoc "Accept-list of users from specified instances"
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
defp filter_by_list(object, []), do: {:ok, object}
|
defp filter_by_list(object, []), do: {:ok, object}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicy do
|
defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicy do
|
||||||
@moduledoc "Filter messages which belong to certain activity vocabularies"
|
@moduledoc "Filter messages which belong to certain activity vocabularies"
|
||||||
|
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(%{"type" => "Undo", "object" => child_message} = message) do
|
def filter(%{"type" => "Undo", "object" => child_message} = message) do
|
||||||
|
|
|
@ -8,6 +8,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator do
|
||||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
alias Pleroma.Web.ActivityPub.Visibility
|
alias Pleroma.Web.ActivityPub.Visibility
|
||||||
|
|
||||||
|
@ -23,7 +24,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator do
|
||||||
field(:type, :string)
|
field(:type, :string)
|
||||||
field(:object, ObjectValidators.ObjectID)
|
field(:object, ObjectValidators.ObjectID)
|
||||||
field(:actor, ObjectValidators.ObjectID)
|
field(:actor, ObjectValidators.ObjectID)
|
||||||
field(:context, :string, autogenerate: {Utils, :generate_context_id, []})
|
field(:context, :string)
|
||||||
field(:to, ObjectValidators.Recipients, default: [])
|
field(:to, ObjectValidators.Recipients, default: [])
|
||||||
field(:cc, ObjectValidators.Recipients, default: [])
|
field(:cc, ObjectValidators.Recipients, default: [])
|
||||||
field(:published, ObjectValidators.DateTime)
|
field(:published, ObjectValidators.DateTime)
|
||||||
|
@ -36,6 +37,10 @@ def cast_and_validate(data) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_data(data) do
|
def cast_data(data) do
|
||||||
|
data =
|
||||||
|
data
|
||||||
|
|> fix()
|
||||||
|
|
||||||
%__MODULE__{}
|
%__MODULE__{}
|
||||||
|> changeset(data)
|
|> changeset(data)
|
||||||
end
|
end
|
||||||
|
@ -43,11 +48,21 @@ def cast_data(data) do
|
||||||
def changeset(struct, data) do
|
def changeset(struct, data) do
|
||||||
struct
|
struct
|
||||||
|> cast(data, __schema__(:fields))
|
|> cast(data, __schema__(:fields))
|
||||||
|> fix_after_cast()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def fix_after_cast(cng) do
|
defp fix(data) do
|
||||||
cng
|
data =
|
||||||
|
data
|
||||||
|
|> CommonFixes.fix_actor()
|
||||||
|
|> CommonFixes.fix_activity_addressing()
|
||||||
|
|
||||||
|
with %Object{} = object <- Object.normalize(data["object"]) do
|
||||||
|
data
|
||||||
|
|> CommonFixes.fix_activity_context(object)
|
||||||
|
|> CommonFixes.fix_object_action_recipients(object)
|
||||||
|
else
|
||||||
|
_ -> data
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp validate_data(data_cng) do
|
defp validate_data(data_cng) do
|
||||||
|
@ -60,7 +75,7 @@ defp validate_data(data_cng) do
|
||||||
|> validate_announcable()
|
|> validate_announcable()
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_announcable(cng) do
|
defp validate_announcable(cng) do
|
||||||
with actor when is_binary(actor) <- get_field(cng, :actor),
|
with actor when is_binary(actor) <- get_field(cng, :actor),
|
||||||
object when is_binary(object) <- get_field(cng, :object),
|
object when is_binary(object) <- get_field(cng, :object),
|
||||||
%User{} = actor <- User.get_cached_by_ap_id(actor),
|
%User{} = actor <- User.get_cached_by_ap_id(actor),
|
||||||
|
@ -91,7 +106,7 @@ def validate_announcable(cng) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_existing_announce(cng) do
|
defp validate_existing_announce(cng) do
|
||||||
actor = get_field(cng, :actor)
|
actor = get_field(cng, :actor)
|
||||||
object = get_field(cng, :object)
|
object = get_field(cng, :object)
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
|
defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
|
||||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
||||||
|
alias Pleroma.Object
|
||||||
alias Pleroma.Object.Containment
|
alias Pleroma.Object.Containment
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||||
|
@ -36,7 +37,7 @@ def fix_object_defaults(data) do
|
||||||
|> Transmogrifier.fix_implicit_addressing(follower_collection)
|
|> Transmogrifier.fix_implicit_addressing(follower_collection)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fix_activity_addressing(activity, _meta) do
|
def fix_activity_addressing(activity) do
|
||||||
%User{follower_address: follower_collection} = User.get_cached_by_ap_id(activity["actor"])
|
%User{follower_address: follower_collection} = User.get_cached_by_ap_id(activity["actor"])
|
||||||
|
|
||||||
activity
|
activity
|
||||||
|
@ -57,4 +58,21 @@ def fix_actor(data) do
|
||||||
|> Map.put("actor", actor)
|
|> Map.put("actor", actor)
|
||||||
|> Map.put("attributedTo", actor)
|
|> Map.put("attributedTo", actor)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def fix_activity_context(data, %Object{data: %{"context" => object_context}}) do
|
||||||
|
data
|
||||||
|
|> Map.put("context", object_context)
|
||||||
|
end
|
||||||
|
|
||||||
|
def fix_object_action_recipients(%{"actor" => actor} = data, %Object{data: %{"actor" => actor}}) do
|
||||||
|
to = ((data["to"] || []) -- [actor]) |> Enum.uniq()
|
||||||
|
|
||||||
|
Map.put(data, "to", to)
|
||||||
|
end
|
||||||
|
|
||||||
|
def fix_object_action_recipients(data, %Object{data: %{"actor" => actor}}) do
|
||||||
|
to = ((data["to"] || []) ++ [actor]) |> Enum.uniq()
|
||||||
|
|
||||||
|
Map.put(data, "to", to)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator do
|
||||||
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
||||||
|
alias Pleroma.User
|
||||||
|
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
||||||
|
@ -57,7 +58,7 @@ defp validate_data(cng) do
|
||||||
cng
|
cng
|
||||||
|> validate_required([:id, :type, :actor, :to, :cc, :object])
|
|> validate_required([:id, :type, :actor, :to, :cc, :object])
|
||||||
|> validate_inclusion(:type, ["Delete"])
|
|> validate_inclusion(:type, ["Delete"])
|
||||||
|> validate_actor_presence()
|
|> validate_delete_actor(:actor)
|
||||||
|> validate_modification_rights()
|
|> validate_modification_rights()
|
||||||
|> validate_object_or_user_presence(allowed_types: @deletable_types)
|
|> validate_object_or_user_presence(allowed_types: @deletable_types)
|
||||||
|> add_deleted_activity_id()
|
|> add_deleted_activity_id()
|
||||||
|
@ -72,4 +73,13 @@ def cast_and_validate(data) do
|
||||||
|> cast_data
|
|> cast_data
|
||||||
|> validate_data
|
|> validate_data
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp validate_delete_actor(cng, field_name) do
|
||||||
|
validate_change(cng, field_name, fn field_name, actor ->
|
||||||
|
case User.get_cached_by_ap_id(actor) do
|
||||||
|
%User{} -> []
|
||||||
|
_ -> [{field_name, "can't find user"}]
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
|
||||||
|
|
||||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
||||||
|
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
||||||
|
@ -31,6 +32,10 @@ def cast_and_validate(data) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_data(data) do
|
def cast_data(data) do
|
||||||
|
data =
|
||||||
|
data
|
||||||
|
|> fix()
|
||||||
|
|
||||||
%__MODULE__{}
|
%__MODULE__{}
|
||||||
|> changeset(data)
|
|> changeset(data)
|
||||||
end
|
end
|
||||||
|
@ -38,28 +43,24 @@ def cast_data(data) do
|
||||||
def changeset(struct, data) do
|
def changeset(struct, data) do
|
||||||
struct
|
struct
|
||||||
|> cast(data, __schema__(:fields))
|
|> cast(data, __schema__(:fields))
|
||||||
|> fix_after_cast()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def fix_after_cast(cng) do
|
defp fix(data) do
|
||||||
cng
|
data =
|
||||||
|> fix_context()
|
data
|
||||||
end
|
|> CommonFixes.fix_actor()
|
||||||
|
|> CommonFixes.fix_activity_addressing()
|
||||||
|
|
||||||
def fix_context(cng) do
|
with %Object{} = object <- Object.normalize(data["object"]) do
|
||||||
object = get_field(cng, :object)
|
data
|
||||||
|
|> CommonFixes.fix_activity_context(object)
|
||||||
with nil <- get_field(cng, :context),
|
|> CommonFixes.fix_object_action_recipients(object)
|
||||||
%Object{data: %{"context" => context}} <- Object.get_cached_by_ap_id(object) do
|
|
||||||
cng
|
|
||||||
|> put_change(:context, context)
|
|
||||||
else
|
else
|
||||||
_ ->
|
_ -> data
|
||||||
cng
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_emoji(cng) do
|
defp validate_emoji(cng) do
|
||||||
content = get_field(cng, :content)
|
content = get_field(cng, :content)
|
||||||
|
|
||||||
if Pleroma.Emoji.is_unicode_emoji?(content) do
|
if Pleroma.Emoji.is_unicode_emoji?(content) do
|
||||||
|
|
|
@ -7,6 +7,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator do
|
||||||
|
|
||||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
|
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
@ -31,6 +32,10 @@ def cast_and_validate(data) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_data(data) do
|
def cast_data(data) do
|
||||||
|
data =
|
||||||
|
data
|
||||||
|
|> fix()
|
||||||
|
|
||||||
%__MODULE__{}
|
%__MODULE__{}
|
||||||
|> changeset(data)
|
|> changeset(data)
|
||||||
end
|
end
|
||||||
|
@ -38,41 +43,20 @@ def cast_data(data) do
|
||||||
def changeset(struct, data) do
|
def changeset(struct, data) do
|
||||||
struct
|
struct
|
||||||
|> cast(data, __schema__(:fields))
|
|> cast(data, __schema__(:fields))
|
||||||
|> fix_after_cast()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def fix_after_cast(cng) do
|
defp fix(data) do
|
||||||
cng
|
data =
|
||||||
|> fix_recipients()
|
data
|
||||||
|> fix_context()
|
|> CommonFixes.fix_actor()
|
||||||
end
|
|> CommonFixes.fix_activity_addressing()
|
||||||
|
|
||||||
def fix_context(cng) do
|
with %Object{} = object <- Object.normalize(data["object"]) do
|
||||||
object = get_field(cng, :object)
|
data
|
||||||
|
|> CommonFixes.fix_activity_context(object)
|
||||||
with nil <- get_field(cng, :context),
|
|> CommonFixes.fix_object_action_recipients(object)
|
||||||
%Object{data: %{"context" => context}} <- Object.get_cached_by_ap_id(object) do
|
|
||||||
cng
|
|
||||||
|> put_change(:context, context)
|
|
||||||
else
|
else
|
||||||
_ ->
|
_ -> data
|
||||||
cng
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def fix_recipients(cng) do
|
|
||||||
to = get_field(cng, :to)
|
|
||||||
cc = get_field(cng, :cc)
|
|
||||||
object = get_field(cng, :object)
|
|
||||||
|
|
||||||
with {[], []} <- {to, cc},
|
|
||||||
%Object{data: %{"actor" => actor}} <- Object.get_cached_by_ap_id(object),
|
|
||||||
{:ok, actor} <- ObjectValidators.ObjectID.cast(actor) do
|
|
||||||
cng
|
|
||||||
|> put_change(:to, [actor])
|
|
||||||
else
|
|
||||||
_ ->
|
|
||||||
cng
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -85,7 +69,7 @@ defp validate_data(data_cng) do
|
||||||
|> validate_existing_like()
|
|> validate_existing_like()
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_existing_like(%{changes: %{actor: actor, object: object}} = cng) do
|
defp validate_existing_like(%{changes: %{actor: actor, object: object}} = cng) do
|
||||||
if Utils.get_existing_like(actor, %{data: %{"id" => object}}) do
|
if Utils.get_existing_like(actor, %{data: %{"id" => object}}) do
|
||||||
cng
|
cng
|
||||||
|> add_error(:actor, "already liked this object")
|
|> add_error(:actor, "already liked this object")
|
||||||
|
@ -95,5 +79,5 @@ def validate_existing_like(%{changes: %{actor: actor, object: object}} = cng) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_existing_like(cng), do: cng
|
defp validate_existing_like(cng), do: cng
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.UndoValidator do
|
||||||
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
||||||
|
alias Pleroma.User
|
||||||
|
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
||||||
|
@ -42,7 +43,7 @@ defp validate_data(data_cng) do
|
||||||
data_cng
|
data_cng
|
||||||
|> validate_inclusion(:type, ["Undo"])
|
|> validate_inclusion(:type, ["Undo"])
|
||||||
|> validate_required([:id, :type, :object, :actor, :to, :cc])
|
|> validate_required([:id, :type, :object, :actor, :to, :cc])
|
||||||
|> validate_actor_presence()
|
|> validate_undo_actor(:actor)
|
||||||
|> validate_object_presence()
|
|> validate_object_presence()
|
||||||
|> validate_undo_rights()
|
|> validate_undo_rights()
|
||||||
end
|
end
|
||||||
|
@ -59,4 +60,13 @@ def validate_undo_rights(cng) do
|
||||||
_ -> cng
|
_ -> cng
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp validate_undo_actor(cng, field_name) do
|
||||||
|
validate_change(cng, field_name, fn field_name, actor ->
|
||||||
|
case User.get_cached_by_ap_id(actor) do
|
||||||
|
%User{} -> []
|
||||||
|
_ -> [{field_name, "can't find user"}]
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -28,11 +28,12 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
|
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
|
||||||
@ap_streamer Pleroma.Config.get([:side_effects, :ap_streamer], ActivityPub)
|
|
||||||
@logger Pleroma.Config.get([:side_effects, :logger], Logger)
|
@logger Pleroma.Config.get([:side_effects, :logger], Logger)
|
||||||
|
|
||||||
@behaviour Pleroma.Web.ActivityPub.SideEffects.Handling
|
@behaviour Pleroma.Web.ActivityPub.SideEffects.Handling
|
||||||
|
|
||||||
|
defp ap_streamer, do: Pleroma.Config.get([:side_effects, :ap_streamer], ActivityPub)
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle(object, meta \\ [])
|
def handle(object, meta \\ [])
|
||||||
|
|
||||||
|
@ -302,8 +303,8 @@ def handle(%{data: %{"type" => "Delete", "object" => deleted_object}} = object,
|
||||||
|
|
||||||
MessageReference.delete_for_object(deleted_object)
|
MessageReference.delete_for_object(deleted_object)
|
||||||
|
|
||||||
@ap_streamer.stream_out(object)
|
ap_streamer().stream_out(object)
|
||||||
@ap_streamer.stream_out_participations(deleted_object, user)
|
ap_streamer().stream_out_participations(deleted_object, user)
|
||||||
:ok
|
:ok
|
||||||
else
|
else
|
||||||
{:actor, _} ->
|
{:actor, _} ->
|
||||||
|
|
|
@ -45,8 +45,6 @@ defmodule Pleroma.Web.AdminAPI.UserController do
|
||||||
when action in [:follow, :unfollow]
|
when action in [:follow, :unfollow]
|
||||||
)
|
)
|
||||||
|
|
||||||
plug(:put_view, Pleroma.Web.AdminAPI.AccountView)
|
|
||||||
|
|
||||||
action_fallback(AdminAPI.FallbackController)
|
action_fallback(AdminAPI.FallbackController)
|
||||||
|
|
||||||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.UserOperation
|
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.UserOperation
|
||||||
|
|
|
@ -10,12 +10,6 @@ defmodule Pleroma.Web.AdminAPI.Search do
|
||||||
|
|
||||||
@page_size 50
|
@page_size 50
|
||||||
|
|
||||||
defmacro not_empty_string(string) do
|
|
||||||
quote do
|
|
||||||
is_binary(unquote(string)) and unquote(string) != ""
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec user(map()) :: {:ok, [User.t()], pos_integer()}
|
@spec user(map()) :: {:ok, [User.t()], pos_integer()}
|
||||||
def user(params \\ %{}) do
|
def user(params \\ %{}) do
|
||||||
query =
|
query =
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.AdminAPI.UserView do
|
||||||
|
use Pleroma.Web, :view
|
||||||
|
alias Pleroma.Web.AdminAPI
|
||||||
|
|
||||||
|
def render(view, opts), do: AdminAPI.AccountView.render(view, opts)
|
||||||
|
end
|
|
@ -24,6 +24,7 @@ def create_operation do
|
||||||
requestBody: Helpers.request_body("Parameters", create_request()),
|
requestBody: Helpers.request_body("Parameters", create_request()),
|
||||||
responses: %{
|
responses: %{
|
||||||
200 => Operation.response("Media", "application/json", Attachment),
|
200 => Operation.response("Media", "application/json", Attachment),
|
||||||
|
400 => Operation.response("Media", "application/json", ApiError),
|
||||||
401 => Operation.response("Media", "application/json", ApiError),
|
401 => Operation.response("Media", "application/json", ApiError),
|
||||||
422 => Operation.response("Media", "application/json", ApiError)
|
422 => Operation.response("Media", "application/json", ApiError)
|
||||||
}
|
}
|
||||||
|
@ -121,6 +122,7 @@ def create2_operation do
|
||||||
requestBody: Helpers.request_body("Parameters", create_request()),
|
requestBody: Helpers.request_body("Parameters", create_request()),
|
||||||
responses: %{
|
responses: %{
|
||||||
202 => Operation.response("Media", "application/json", Attachment),
|
202 => Operation.response("Media", "application/json", Attachment),
|
||||||
|
400 => Operation.response("Media", "application/json", ApiError),
|
||||||
422 => Operation.response("Media", "application/json", ApiError),
|
422 => Operation.response("Media", "application/json", ApiError),
|
||||||
500 => Operation.response("Media", "application/json", ApiError)
|
500 => Operation.response("Media", "application/json", ApiError)
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.BooleanLike do
|
||||||
|
|
||||||
def cast(%Cast{value: value} = context) do
|
def cast(%Cast{value: value} = context) do
|
||||||
context
|
context
|
||||||
|> Map.put(:value, Pleroma.Web.ControllerHelper.truthy_param?(value))
|
|> Map.put(:value, Pleroma.Web.Utils.Params.truthy_param?(value))
|
||||||
|> Cast.ok()
|
|> Cast.ok()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,68 +3,11 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Web.Auth.Authenticator do
|
defmodule Pleroma.Web.Auth.Authenticator do
|
||||||
alias Pleroma.Registration
|
@callback get_user(Plug.Conn.t()) :: {:ok, user :: struct()} | {:error, any()}
|
||||||
alias Pleroma.User
|
@callback create_from_registration(Plug.Conn.t(), registration :: struct()) ::
|
||||||
|
|
||||||
def implementation do
|
|
||||||
Pleroma.Config.get(
|
|
||||||
Pleroma.Web.Auth.Authenticator,
|
|
||||||
Pleroma.Web.Auth.PleromaAuthenticator
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
@callback get_user(Plug.Conn.t()) :: {:ok, User.t()} | {:error, any()}
|
|
||||||
def get_user(plug), do: implementation().get_user(plug)
|
|
||||||
|
|
||||||
@callback create_from_registration(Plug.Conn.t(), Registration.t()) ::
|
|
||||||
{:ok, User.t()} | {:error, any()}
|
{:ok, User.t()} | {:error, any()}
|
||||||
def create_from_registration(plug, registration),
|
@callback get_registration(Plug.Conn.t()) :: {:ok, registration :: struct()} | {:error, any()}
|
||||||
do: implementation().create_from_registration(plug, registration)
|
|
||||||
|
|
||||||
@callback get_registration(Plug.Conn.t()) :: {:ok, Registration.t()} | {:error, any()}
|
|
||||||
def get_registration(plug), do: implementation().get_registration(plug)
|
|
||||||
|
|
||||||
@callback handle_error(Plug.Conn.t(), any()) :: any()
|
@callback handle_error(Plug.Conn.t(), any()) :: any()
|
||||||
def handle_error(plug, error),
|
|
||||||
do: implementation().handle_error(plug, error)
|
|
||||||
|
|
||||||
@callback auth_template() :: String.t() | nil
|
@callback auth_template() :: String.t() | nil
|
||||||
def auth_template do
|
|
||||||
# Note: `config :pleroma, :auth_template, "..."` support is deprecated
|
|
||||||
implementation().auth_template() ||
|
|
||||||
Pleroma.Config.get([:auth, :auth_template], Pleroma.Config.get(:auth_template)) ||
|
|
||||||
"show.html"
|
|
||||||
end
|
|
||||||
|
|
||||||
@callback oauth_consumer_template() :: String.t() | nil
|
@callback oauth_consumer_template() :: String.t() | nil
|
||||||
def oauth_consumer_template do
|
|
||||||
implementation().oauth_consumer_template() ||
|
|
||||||
Pleroma.Config.get([:auth, :oauth_consumer_template], "consumer.html")
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc "Gets user by nickname or email for auth."
|
|
||||||
@spec fetch_user(String.t()) :: User.t() | nil
|
|
||||||
def fetch_user(name) do
|
|
||||||
User.get_by_nickname_or_email(name)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Gets name and password from conn
|
|
||||||
#
|
|
||||||
@spec fetch_credentials(Plug.Conn.t() | map()) ::
|
|
||||||
{:ok, {name :: any, password :: any}} | {:error, :invalid_credentials}
|
|
||||||
def fetch_credentials(%Plug.Conn{params: params} = _),
|
|
||||||
do: fetch_credentials(params)
|
|
||||||
|
|
||||||
def fetch_credentials(params) do
|
|
||||||
case params do
|
|
||||||
%{"authorization" => %{"name" => name, "password" => password}} ->
|
|
||||||
{:ok, {name, password}}
|
|
||||||
|
|
||||||
%{"grant_type" => "password", "username" => name, "password" => password} ->
|
|
||||||
{:ok, {name, password}}
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
{:error, :invalid_credentials}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.Auth.Helpers do
|
||||||
|
alias Pleroma.User
|
||||||
|
|
||||||
|
@doc "Gets user by nickname or email for auth."
|
||||||
|
@spec fetch_user(String.t()) :: User.t() | nil
|
||||||
|
def fetch_user(name) do
|
||||||
|
User.get_by_nickname_or_email(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Gets name and password from conn
|
||||||
|
#
|
||||||
|
@spec fetch_credentials(Plug.Conn.t() | map()) ::
|
||||||
|
{:ok, {name :: any, password :: any}} | {:error, :invalid_credentials}
|
||||||
|
def fetch_credentials(%Plug.Conn{params: params} = _),
|
||||||
|
do: fetch_credentials(params)
|
||||||
|
|
||||||
|
def fetch_credentials(params) do
|
||||||
|
case params do
|
||||||
|
%{"authorization" => %{"name" => name, "password" => password}} ->
|
||||||
|
{:ok, {name, password}}
|
||||||
|
|
||||||
|
%{"grant_type" => "password", "username" => name, "password" => password} ->
|
||||||
|
{:ok, {name, password}}
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
{:error, :invalid_credentials}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -7,8 +7,7 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
import Pleroma.Web.Auth.Authenticator,
|
import Pleroma.Web.Auth.Helpers, only: [fetch_credentials: 1, fetch_user: 1]
|
||||||
only: [fetch_credentials: 1, fetch_user: 1]
|
|
||||||
|
|
||||||
@behaviour Pleroma.Web.Auth.Authenticator
|
@behaviour Pleroma.Web.Auth.Authenticator
|
||||||
@base Pleroma.Web.Auth.PleromaAuthenticator
|
@base Pleroma.Web.Auth.PleromaAuthenticator
|
||||||
|
|
|
@ -8,8 +8,7 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.Plugs.AuthenticationPlug
|
alias Pleroma.Web.Plugs.AuthenticationPlug
|
||||||
|
|
||||||
import Pleroma.Web.Auth.Authenticator,
|
import Pleroma.Web.Auth.Helpers, only: [fetch_credentials: 1, fetch_user: 1]
|
||||||
only: [fetch_credentials: 1, fetch_user: 1]
|
|
||||||
|
|
||||||
@behaviour Pleroma.Web.Auth.Authenticator
|
@behaviour Pleroma.Web.Auth.Authenticator
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.Auth.WrapperAuthenticator do
|
||||||
|
@behaviour Pleroma.Web.Auth.Authenticator
|
||||||
|
|
||||||
|
defp implementation do
|
||||||
|
Pleroma.Config.get(
|
||||||
|
Pleroma.Web.Auth.Authenticator,
|
||||||
|
Pleroma.Web.Auth.PleromaAuthenticator
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def get_user(plug), do: implementation().get_user(plug)
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def create_from_registration(plug, registration),
|
||||||
|
do: implementation().create_from_registration(plug, registration)
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def get_registration(plug), do: implementation().get_registration(plug)
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def handle_error(plug, error),
|
||||||
|
do: implementation().handle_error(plug, error)
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def auth_template do
|
||||||
|
# Note: `config :pleroma, :auth_template, "..."` support is deprecated
|
||||||
|
implementation().auth_template() ||
|
||||||
|
Pleroma.Config.get([:auth, :auth_template], Pleroma.Config.get(:auth_template)) ||
|
||||||
|
"show.html"
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def oauth_consumer_template do
|
||||||
|
implementation().oauth_consumer_template() ||
|
||||||
|
Pleroma.Config.get([:auth, :oauth_consumer_template], "consumer.html")
|
||||||
|
end
|
||||||
|
end
|
|
@ -223,7 +223,7 @@ defp object(draft) do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp preview?(draft) do
|
defp preview?(draft) do
|
||||||
preview? = Pleroma.Web.ControllerHelper.truthy_param?(draft.params[:preview])
|
preview? = Pleroma.Web.Utils.Params.truthy_param?(draft.params[:preview])
|
||||||
%__MODULE__{draft | preview?: preview?}
|
%__MODULE__{draft | preview?: preview?}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.CommonAPI.Utils do
|
defmodule Pleroma.Web.CommonAPI.Utils do
|
||||||
import Pleroma.Web.Gettext
|
import Pleroma.Web.Gettext
|
||||||
import Pleroma.Web.ControllerHelper, only: [truthy_param?: 1]
|
|
||||||
|
|
||||||
alias Calendar.Strftime
|
alias Calendar.Strftime
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
|
@ -19,6 +18,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
||||||
alias Pleroma.Web.CommonAPI.ActivityDraft
|
alias Pleroma.Web.CommonAPI.ActivityDraft
|
||||||
alias Pleroma.Web.MediaProxy
|
alias Pleroma.Web.MediaProxy
|
||||||
alias Pleroma.Web.Plugs.AuthenticationPlug
|
alias Pleroma.Web.Plugs.AuthenticationPlug
|
||||||
|
alias Pleroma.Web.Utils.Params
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
require Pleroma.Constants
|
require Pleroma.Constants
|
||||||
|
@ -160,7 +160,7 @@ def make_poll_data(%{poll: %{options: options, expires_in: expires_in}} = data)
|
||||||
|> DateTime.add(expires_in)
|
|> DateTime.add(expires_in)
|
||||||
|> DateTime.to_iso8601()
|
|> DateTime.to_iso8601()
|
||||||
|
|
||||||
key = if truthy_param?(data.poll[:multiple]), do: "anyOf", else: "oneOf"
|
key = if Params.truthy_param?(data.poll[:multiple]), do: "anyOf", else: "oneOf"
|
||||||
poll = %{"type" => "Question", key => option_notes, "closed" => end_time}
|
poll = %{"type" => "Question", key => option_notes, "closed" => end_time}
|
||||||
|
|
||||||
{:ok, {poll, emoji}}
|
{:ok, {poll, emoji}}
|
||||||
|
@ -203,7 +203,7 @@ def make_content_html(%ActivityDraft{} = draft) do
|
||||||
attachment_links =
|
attachment_links =
|
||||||
draft.params
|
draft.params
|
||||||
|> Map.get("attachment_links", Config.get([:instance, :attachment_links]))
|
|> Map.get("attachment_links", Config.get([:instance, :attachment_links]))
|
||||||
|> truthy_param?()
|
|> Params.truthy_param?()
|
||||||
|
|
||||||
content_type = get_content_type(draft.params[:content_type])
|
content_type = get_content_type(draft.params[:content_type])
|
||||||
|
|
||||||
|
|
|
@ -6,17 +6,7 @@ defmodule Pleroma.Web.ControllerHelper do
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
alias Pleroma.Pagination
|
alias Pleroma.Pagination
|
||||||
|
alias Pleroma.Web.Utils.Params
|
||||||
# As in Mastodon API, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
|
|
||||||
@falsy_param_values [false, 0, "0", "f", "F", "false", "False", "FALSE", "off", "OFF"]
|
|
||||||
|
|
||||||
def explicitly_falsy_param?(value), do: value in @falsy_param_values
|
|
||||||
|
|
||||||
# Note: `nil` and `""` are considered falsy values in Pleroma
|
|
||||||
def falsy_param?(value),
|
|
||||||
do: explicitly_falsy_param?(value) or value in [nil, ""]
|
|
||||||
|
|
||||||
def truthy_param?(value), do: not falsy_param?(value)
|
|
||||||
|
|
||||||
def json_response(conn, status, _) when status in [204, :no_content] do
|
def json_response(conn, status, _) when status in [204, :no_content] do
|
||||||
conn
|
conn
|
||||||
|
@ -123,6 +113,6 @@ def embed_relationships?(params) do
|
||||||
# To do once OpenAPI transition mess is over: just `truthy_param?(params[:with_relationships])`
|
# To do once OpenAPI transition mess is over: just `truthy_param?(params[:with_relationships])`
|
||||||
params
|
params
|
||||||
|> Map.get(:with_relationships, params["with_relationships"])
|
|> Map.get(:with_relationships, params["with_relationships"])
|
||||||
|> truthy_param?()
|
|> Params.truthy_param?()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,7 +8,6 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
||||||
import Pleroma.Web.ControllerHelper,
|
import Pleroma.Web.ControllerHelper,
|
||||||
only: [
|
only: [
|
||||||
add_link_headers: 2,
|
add_link_headers: 2,
|
||||||
truthy_param?: 1,
|
|
||||||
assign_account_by_id: 2,
|
assign_account_by_id: 2,
|
||||||
embed_relationships?: 1,
|
embed_relationships?: 1,
|
||||||
json_response: 3
|
json_response: 3
|
||||||
|
@ -25,16 +24,16 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
||||||
alias Pleroma.Web.MastodonAPI.MastodonAPIController
|
alias Pleroma.Web.MastodonAPI.MastodonAPIController
|
||||||
alias Pleroma.Web.MastodonAPI.StatusView
|
alias Pleroma.Web.MastodonAPI.StatusView
|
||||||
alias Pleroma.Web.OAuth.OAuthController
|
alias Pleroma.Web.OAuth.OAuthController
|
||||||
alias Pleroma.Web.Plugs.EnsurePublicOrAuthenticatedPlug
|
|
||||||
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
||||||
alias Pleroma.Web.Plugs.RateLimiter
|
alias Pleroma.Web.Plugs.RateLimiter
|
||||||
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
||||||
|
alias Pleroma.Web.Utils.Params
|
||||||
|
|
||||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||||
|
|
||||||
plug(:skip_plug, [OAuthScopesPlug, EnsurePublicOrAuthenticatedPlug] when action == :create)
|
plug(:skip_auth when action == :create)
|
||||||
|
|
||||||
plug(:skip_plug, EnsurePublicOrAuthenticatedPlug when action in [:show, :statuses])
|
plug(:skip_public_check when action in [:show, :statuses])
|
||||||
|
|
||||||
plug(
|
plug(
|
||||||
OAuthScopesPlug,
|
OAuthScopesPlug,
|
||||||
|
@ -188,7 +187,7 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p
|
||||||
:accepts_chat_messages
|
:accepts_chat_messages
|
||||||
]
|
]
|
||||||
|> Enum.reduce(%{}, fn key, acc ->
|
|> Enum.reduce(%{}, fn key, acc ->
|
||||||
Maps.put_if_present(acc, key, params[key], &{:ok, truthy_param?(&1)})
|
Maps.put_if_present(acc, key, params[key], &{:ok, Params.truthy_param?(&1)})
|
||||||
end)
|
end)
|
||||||
|> Maps.put_if_present(:name, params[:display_name])
|
|> Maps.put_if_present(:name, params[:display_name])
|
||||||
|> Maps.put_if_present(:bio, params[:note])
|
|> Maps.put_if_present(:bio, params[:note])
|
||||||
|
|
|
@ -14,16 +14,10 @@ defmodule Pleroma.Web.MastodonAPI.AppController do
|
||||||
alias Pleroma.Web.OAuth.App
|
alias Pleroma.Web.OAuth.App
|
||||||
alias Pleroma.Web.OAuth.Scopes
|
alias Pleroma.Web.OAuth.Scopes
|
||||||
alias Pleroma.Web.OAuth.Token
|
alias Pleroma.Web.OAuth.Token
|
||||||
alias Pleroma.Web.Plugs.EnsurePublicOrAuthenticatedPlug
|
|
||||||
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
|
||||||
|
|
||||||
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
|
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
|
||||||
|
|
||||||
plug(
|
plug(:skip_auth when action in [:create, :verify_credentials])
|
||||||
:skip_plug,
|
|
||||||
[OAuthScopesPlug, EnsurePublicOrAuthenticatedPlug]
|
|
||||||
when action in [:create, :verify_credentials]
|
|
||||||
)
|
|
||||||
|
|
||||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,7 @@ defmodule Pleroma.Web.MastodonAPI.CustomEmojiController do
|
||||||
|
|
||||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||||
|
|
||||||
plug(
|
plug(:skip_auth when action == :index)
|
||||||
:skip_plug,
|
|
||||||
[Pleroma.Web.Plugs.OAuthScopesPlug, Pleroma.Web.Plugs.EnsurePublicOrAuthenticatedPlug]
|
|
||||||
when action == :index
|
|
||||||
)
|
|
||||||
|
|
||||||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.CustomEmojiOperation
|
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.CustomEmojiOperation
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceController do
|
||||||
|
|
||||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||||
|
|
||||||
plug(
|
plug(:skip_auth when action in [:show, :peers])
|
||||||
:skip_plug,
|
|
||||||
[Pleroma.Web.Plugs.OAuthScopesPlug, Pleroma.Web.Plugs.EnsurePublicOrAuthenticatedPlug]
|
|
||||||
when action in [:show, :peers]
|
|
||||||
)
|
|
||||||
|
|
||||||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.InstanceOperation
|
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.InstanceOperation
|
||||||
|
|
||||||
|
|
|
@ -15,11 +15,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
plug(
|
plug(:skip_auth when action in [:empty_array, :empty_object])
|
||||||
:skip_plug,
|
|
||||||
[Pleroma.Web.Plugs.OAuthScopesPlug, Pleroma.Web.Plugs.EnsurePublicOrAuthenticatedPlug]
|
|
||||||
when action in [:empty_array, :empty_object]
|
|
||||||
)
|
|
||||||
|
|
||||||
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
|
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
|
||||||
|
|
||||||
|
|
|
@ -27,10 +27,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
|
||||||
|
|
||||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||||
|
|
||||||
plug(
|
plug(:skip_public_check when action in [:index, :show])
|
||||||
:skip_plug,
|
|
||||||
Pleroma.Web.Plugs.EnsurePublicOrAuthenticatedPlug when action in [:index, :show]
|
|
||||||
)
|
|
||||||
|
|
||||||
@unauthenticated_access %{fallback: :proceed_unauthenticated, scopes: []}
|
@unauthenticated_access %{fallback: :proceed_unauthenticated, scopes: []}
|
||||||
|
|
||||||
|
|
|
@ -12,12 +12,11 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|
||||||
alias Pleroma.Pagination
|
alias Pleroma.Pagination
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.Plugs.EnsurePublicOrAuthenticatedPlug
|
|
||||||
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
||||||
alias Pleroma.Web.Plugs.RateLimiter
|
alias Pleroma.Web.Plugs.RateLimiter
|
||||||
|
|
||||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||||
plug(:skip_plug, EnsurePublicOrAuthenticatedPlug when action in [:public, :hashtag])
|
plug(:skip_public_check when action in [:public, :hashtag])
|
||||||
|
|
||||||
# TODO: Replace with a macro when there is a Phoenix release with the following commit in it:
|
# TODO: Replace with a macro when there is a Phoenix release with the following commit in it:
|
||||||
# https://github.com/phoenixframework/phoenix/commit/2e8c63c01fec4dde5467dbbbf9705ff9e780735e
|
# https://github.com/phoenixframework/phoenix/commit/2e8c63c01fec4dde5467dbbbf9705ff9e780735e
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.Metadata.Providers.OpenGraph do
|
defmodule Pleroma.Web.Metadata.Providers.OpenGraph do
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.MediaProxy
|
||||||
alias Pleroma.Web.Metadata
|
alias Pleroma.Web.Metadata
|
||||||
alias Pleroma.Web.Metadata.Providers.Provider
|
alias Pleroma.Web.Metadata.Providers.Provider
|
||||||
alias Pleroma.Web.Metadata.Utils
|
alias Pleroma.Web.Metadata.Utils
|
||||||
|
@ -19,37 +20,24 @@ def build_tags(%{
|
||||||
}) do
|
}) do
|
||||||
attachments = build_attachments(object)
|
attachments = build_attachments(object)
|
||||||
scrubbed_content = Utils.scrub_html_and_truncate(object)
|
scrubbed_content = Utils.scrub_html_and_truncate(object)
|
||||||
# Zero width space
|
|
||||||
content =
|
|
||||||
if scrubbed_content != "" and scrubbed_content != "\u200B" do
|
|
||||||
": “" <> scrubbed_content <> "”"
|
|
||||||
else
|
|
||||||
""
|
|
||||||
end
|
|
||||||
|
|
||||||
# Most previews only show og:title which is inconvenient. Instagram
|
|
||||||
# hacks this by putting the description in the title and making the
|
|
||||||
# description longer prefixed by how many likes and shares the post
|
|
||||||
# has. Here we use the descriptive nickname in the title, and expand
|
|
||||||
# the full account & nickname in the description. We also use the cute^Wevil
|
|
||||||
# smart quotes around the status text like Instagram, too.
|
|
||||||
[
|
[
|
||||||
{:meta,
|
{:meta,
|
||||||
[
|
[
|
||||||
property: "og:title",
|
property: "og:title",
|
||||||
content: "#{user.name}" <> content
|
content: Utils.user_name_string(user)
|
||||||
], []},
|
], []},
|
||||||
{:meta, [property: "og:url", content: url], []},
|
{:meta, [property: "og:url", content: url], []},
|
||||||
{:meta,
|
{:meta,
|
||||||
[
|
[
|
||||||
property: "og:description",
|
property: "og:description",
|
||||||
content: "#{Utils.user_name_string(user)}" <> content
|
content: scrubbed_content
|
||||||
], []},
|
], []},
|
||||||
{:meta, [property: "og:type", content: "website"], []}
|
{:meta, [property: "og:type", content: "article"], []}
|
||||||
] ++
|
] ++
|
||||||
if attachments == [] or Metadata.activity_nsfw?(object) do
|
if attachments == [] or Metadata.activity_nsfw?(object) do
|
||||||
[
|
[
|
||||||
{:meta, [property: "og:image", content: Utils.attachment_url(User.avatar_url(user))],
|
{:meta, [property: "og:image", content: MediaProxy.preview_url(User.avatar_url(user))],
|
||||||
[]},
|
[]},
|
||||||
{:meta, [property: "og:image:width", content: 150], []},
|
{:meta, [property: "og:image:width", content: 150], []},
|
||||||
{:meta, [property: "og:image:height", content: 150], []}
|
{:meta, [property: "og:image:height", content: 150], []}
|
||||||
|
@ -70,8 +58,9 @@ def build_tags(%{user: user}) do
|
||||||
], []},
|
], []},
|
||||||
{:meta, [property: "og:url", content: user.uri || user.ap_id], []},
|
{:meta, [property: "og:url", content: user.uri || user.ap_id], []},
|
||||||
{:meta, [property: "og:description", content: truncated_bio], []},
|
{:meta, [property: "og:description", content: truncated_bio], []},
|
||||||
{:meta, [property: "og:type", content: "website"], []},
|
{:meta, [property: "og:type", content: "article"], []},
|
||||||
{:meta, [property: "og:image", content: Utils.attachment_url(User.avatar_url(user))], []},
|
{:meta, [property: "og:image", content: MediaProxy.preview_url(User.avatar_url(user))],
|
||||||
|
[]},
|
||||||
{:meta, [property: "og:image:width", content: 150], []},
|
{:meta, [property: "og:image:width", content: 150], []},
|
||||||
{:meta, [property: "og:image:height", content: 150], []}
|
{:meta, [property: "og:image:height", content: 150], []}
|
||||||
]
|
]
|
||||||
|
@ -82,29 +71,35 @@ defp build_attachments(%{data: %{"attachment" => attachments}}) do
|
||||||
Enum.reduce(attachments, [], fn attachment, acc ->
|
Enum.reduce(attachments, [], fn attachment, acc ->
|
||||||
rendered_tags =
|
rendered_tags =
|
||||||
Enum.reduce(attachment["url"], [], fn url, acc ->
|
Enum.reduce(attachment["url"], [], fn url, acc ->
|
||||||
# TODO: Add additional properties to objects when we have the data available.
|
# TODO: Whatsapp only wants JPEG or PNGs. It seems that if we add a second og:image
|
||||||
# Also, Whatsapp only wants JPEG or PNGs. It seems that if we add a second og:image
|
|
||||||
# object when a Video or GIF is attached it will display that in Whatsapp Rich Preview.
|
# object when a Video or GIF is attached it will display that in Whatsapp Rich Preview.
|
||||||
case Utils.fetch_media_type(@media_types, url["mediaType"]) do
|
case Utils.fetch_media_type(@media_types, url["mediaType"]) do
|
||||||
"audio" ->
|
"audio" ->
|
||||||
[
|
[
|
||||||
{:meta, [property: "og:audio", content: Utils.attachment_url(url["href"])], []}
|
{:meta, [property: "og:audio", content: MediaProxy.url(url["href"])], []}
|
||||||
| acc
|
| acc
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Not using preview_url for this. It saves bandwidth, but the image dimensions will
|
||||||
|
# be wrong. We generate it on the fly and have no way to capture or analyze the
|
||||||
|
# image to get the dimensions. This can be an issue for apps/FEs rendering images
|
||||||
|
# in timelines too, but you can get clever with the aspect ratio metadata as a
|
||||||
|
# workaround.
|
||||||
"image" ->
|
"image" ->
|
||||||
[
|
[
|
||||||
{:meta, [property: "og:image", content: Utils.attachment_url(url["href"])], []},
|
{:meta, [property: "og:image", content: MediaProxy.url(url["href"])], []},
|
||||||
{:meta, [property: "og:image:width", content: 150], []},
|
{:meta, [property: "og:image:alt", content: attachment["name"]], []}
|
||||||
{:meta, [property: "og:image:height", content: 150], []}
|
|
||||||
| acc
|
| acc
|
||||||
]
|
]
|
||||||
|
|> maybe_add_dimensions(url)
|
||||||
|
|
||||||
"video" ->
|
"video" ->
|
||||||
[
|
[
|
||||||
{:meta, [property: "og:video", content: Utils.attachment_url(url["href"])], []}
|
{:meta, [property: "og:video", content: MediaProxy.url(url["href"])], []}
|
||||||
| acc
|
| acc
|
||||||
]
|
]
|
||||||
|
|> maybe_add_dimensions(url)
|
||||||
|
|> maybe_add_video_thumbnail(url)
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
acc
|
acc
|
||||||
|
@ -116,4 +111,38 @@ defp build_attachments(%{data: %{"attachment" => attachments}}) do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp build_attachments(_), do: []
|
defp build_attachments(_), do: []
|
||||||
|
|
||||||
|
# We can use url["mediaType"] to dynamically fill the metadata
|
||||||
|
defp maybe_add_dimensions(metadata, url) do
|
||||||
|
type = url["mediaType"] |> String.split("/") |> List.first()
|
||||||
|
|
||||||
|
cond do
|
||||||
|
!is_nil(url["height"]) && !is_nil(url["width"]) ->
|
||||||
|
metadata ++
|
||||||
|
[
|
||||||
|
{:meta, [property: "og:#{type}:width", content: "#{url["width"]}"], []},
|
||||||
|
{:meta, [property: "og:#{type}:height", content: "#{url["height"]}"], []}
|
||||||
|
]
|
||||||
|
|
||||||
|
true ->
|
||||||
|
metadata
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Media Preview Proxy makes thumbnails of videos without resizing, so we can trust the
|
||||||
|
# width and height of the source video.
|
||||||
|
defp maybe_add_video_thumbnail(metadata, url) do
|
||||||
|
cond do
|
||||||
|
Pleroma.Config.get([:media_preview_proxy, :enabled], false) ->
|
||||||
|
metadata ++
|
||||||
|
[
|
||||||
|
{:meta, [property: "og:image:width", content: "#{url["width"]}"], []},
|
||||||
|
{:meta, [property: "og:image:height", content: "#{url["height"]}"], []},
|
||||||
|
{:meta, [property: "og:image", content: MediaProxy.preview_url(url["href"])], []}
|
||||||
|
]
|
||||||
|
|
||||||
|
true ->
|
||||||
|
metadata
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
|
defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.MediaProxy
|
||||||
alias Pleroma.Web.Metadata
|
alias Pleroma.Web.Metadata
|
||||||
alias Pleroma.Web.Metadata.Providers.Provider
|
alias Pleroma.Web.Metadata.Providers.Provider
|
||||||
alias Pleroma.Web.Metadata.Utils
|
alias Pleroma.Web.Metadata.Utils
|
||||||
|
@ -16,17 +17,10 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
|
||||||
def build_tags(%{activity_id: id, object: object, user: user}) do
|
def build_tags(%{activity_id: id, object: object, user: user}) do
|
||||||
attachments = build_attachments(id, object)
|
attachments = build_attachments(id, object)
|
||||||
scrubbed_content = Utils.scrub_html_and_truncate(object)
|
scrubbed_content = Utils.scrub_html_and_truncate(object)
|
||||||
# Zero width space
|
|
||||||
content =
|
|
||||||
if scrubbed_content != "" and scrubbed_content != "\u200B" do
|
|
||||||
"“" <> scrubbed_content <> "”"
|
|
||||||
else
|
|
||||||
""
|
|
||||||
end
|
|
||||||
|
|
||||||
[
|
[
|
||||||
title_tag(user),
|
title_tag(user),
|
||||||
{:meta, [property: "twitter:description", content: content], []}
|
{:meta, [property: "twitter:description", content: scrubbed_content], []}
|
||||||
] ++
|
] ++
|
||||||
if attachments == [] or Metadata.activity_nsfw?(object) do
|
if attachments == [] or Metadata.activity_nsfw?(object) do
|
||||||
[
|
[
|
||||||
|
@ -55,14 +49,14 @@ defp title_tag(user) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def image_tag(user) do
|
def image_tag(user) do
|
||||||
{:meta, [property: "twitter:image", content: Utils.attachment_url(User.avatar_url(user))], []}
|
{:meta, [property: "twitter:image", content: MediaProxy.preview_url(User.avatar_url(user))],
|
||||||
|
[]}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp build_attachments(id, %{data: %{"attachment" => attachments}}) do
|
defp build_attachments(id, %{data: %{"attachment" => attachments}}) do
|
||||||
Enum.reduce(attachments, [], fn attachment, acc ->
|
Enum.reduce(attachments, [], fn attachment, acc ->
|
||||||
rendered_tags =
|
rendered_tags =
|
||||||
Enum.reduce(attachment["url"], [], fn url, acc ->
|
Enum.reduce(attachment["url"], [], fn url, acc ->
|
||||||
# TODO: Add additional properties to objects when we have the data available.
|
|
||||||
case Utils.fetch_media_type(@media_types, url["mediaType"]) do
|
case Utils.fetch_media_type(@media_types, url["mediaType"]) do
|
||||||
"audio" ->
|
"audio" ->
|
||||||
[
|
[
|
||||||
|
@ -73,25 +67,37 @@ defp build_attachments(id, %{data: %{"attachment" => attachments}}) do
|
||||||
| acc
|
| acc
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Not using preview_url for this. It saves bandwidth, but the image dimensions will
|
||||||
|
# be wrong. We generate it on the fly and have no way to capture or analyze the
|
||||||
|
# image to get the dimensions. This can be an issue for apps/FEs rendering images
|
||||||
|
# in timelines too, but you can get clever with the aspect ratio metadata as a
|
||||||
|
# workaround.
|
||||||
"image" ->
|
"image" ->
|
||||||
[
|
[
|
||||||
{:meta, [property: "twitter:card", content: "summary_large_image"], []},
|
{:meta, [property: "twitter:card", content: "summary_large_image"], []},
|
||||||
{:meta,
|
{:meta,
|
||||||
[
|
[
|
||||||
property: "twitter:player",
|
property: "twitter:player",
|
||||||
content: Utils.attachment_url(url["href"])
|
content: MediaProxy.url(url["href"])
|
||||||
], []}
|
], []}
|
||||||
| acc
|
| acc
|
||||||
]
|
]
|
||||||
|
|> maybe_add_dimensions(url)
|
||||||
|
|
||||||
# TODO: Need the true width and height values here or Twitter renders an iFrame with
|
|
||||||
# a bad aspect ratio
|
|
||||||
"video" ->
|
"video" ->
|
||||||
|
# fallback to old placeholder values
|
||||||
|
height = url["height"] || 480
|
||||||
|
width = url["width"] || 480
|
||||||
|
|
||||||
[
|
[
|
||||||
{:meta, [property: "twitter:card", content: "player"], []},
|
{:meta, [property: "twitter:card", content: "player"], []},
|
||||||
{:meta, [property: "twitter:player", content: player_url(id)], []},
|
{:meta, [property: "twitter:player", content: player_url(id)], []},
|
||||||
{:meta, [property: "twitter:player:width", content: "480"], []},
|
{:meta, [property: "twitter:player:width", content: "#{width}"], []},
|
||||||
{:meta, [property: "twitter:player:height", content: "480"], []}
|
{:meta, [property: "twitter:player:height", content: "#{height}"], []},
|
||||||
|
{:meta, [property: "twitter:player:stream", content: MediaProxy.url(url["href"])],
|
||||||
|
[]},
|
||||||
|
{:meta,
|
||||||
|
[property: "twitter:player:stream:content_type", content: url["mediaType"]], []}
|
||||||
| acc
|
| acc
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -109,4 +115,20 @@ defp build_attachments(_id, _object), do: []
|
||||||
defp player_url(id) do
|
defp player_url(id) do
|
||||||
Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :notice_player, id)
|
Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :notice_player, id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Videos have problems without dimensions, but we used to not provide WxH for images.
|
||||||
|
# A default (read: incorrect) fallback for images is likely to cause rendering bugs.
|
||||||
|
defp maybe_add_dimensions(metadata, url) do
|
||||||
|
cond do
|
||||||
|
!is_nil(url["height"]) && !is_nil(url["width"]) ->
|
||||||
|
metadata ++
|
||||||
|
[
|
||||||
|
{:meta, [property: "twitter:player:width", content: "#{url["width"]}"], []},
|
||||||
|
{:meta, [property: "twitter:player:height", content: "#{url["height"]}"], []}
|
||||||
|
]
|
||||||
|
|
||||||
|
true ->
|
||||||
|
metadata
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,7 +7,6 @@ defmodule Pleroma.Web.Metadata.Utils do
|
||||||
alias Pleroma.Emoji
|
alias Pleroma.Emoji
|
||||||
alias Pleroma.Formatter
|
alias Pleroma.Formatter
|
||||||
alias Pleroma.HTML
|
alias Pleroma.HTML
|
||||||
alias Pleroma.Web.MediaProxy
|
|
||||||
|
|
||||||
def scrub_html_and_truncate(%{data: %{"content" => content}} = object) do
|
def scrub_html_and_truncate(%{data: %{"content" => content}} = object) do
|
||||||
content
|
content
|
||||||
|
@ -38,10 +37,6 @@ def scrub_html(content) when is_binary(content) do
|
||||||
|
|
||||||
def scrub_html(content), do: content
|
def scrub_html(content), do: content
|
||||||
|
|
||||||
def attachment_url(url) do
|
|
||||||
MediaProxy.preview_url(url)
|
|
||||||
end
|
|
||||||
|
|
||||||
def user_name_string(user) do
|
def user_name_string(user) do
|
||||||
"#{user.name} " <>
|
"#{user.name} " <>
|
||||||
if user.local do
|
if user.local do
|
||||||
|
|
|
@ -12,8 +12,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
||||||
alias Pleroma.Registration
|
alias Pleroma.Registration
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.Auth.Authenticator
|
alias Pleroma.Web.Auth.WrapperAuthenticator, as: Authenticator
|
||||||
alias Pleroma.Web.ControllerHelper
|
|
||||||
alias Pleroma.Web.OAuth.App
|
alias Pleroma.Web.OAuth.App
|
||||||
alias Pleroma.Web.OAuth.Authorization
|
alias Pleroma.Web.OAuth.Authorization
|
||||||
alias Pleroma.Web.OAuth.MFAController
|
alias Pleroma.Web.OAuth.MFAController
|
||||||
|
@ -24,6 +23,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
||||||
alias Pleroma.Web.OAuth.Token.Strategy.RefreshToken
|
alias Pleroma.Web.OAuth.Token.Strategy.RefreshToken
|
||||||
alias Pleroma.Web.OAuth.Token.Strategy.Revoke, as: RevokeToken
|
alias Pleroma.Web.OAuth.Token.Strategy.Revoke, as: RevokeToken
|
||||||
alias Pleroma.Web.Plugs.RateLimiter
|
alias Pleroma.Web.Plugs.RateLimiter
|
||||||
|
alias Pleroma.Web.Utils.Params
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
@ -32,10 +32,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
||||||
plug(:fetch_session)
|
plug(:fetch_session)
|
||||||
plug(:fetch_flash)
|
plug(:fetch_flash)
|
||||||
|
|
||||||
plug(:skip_plug, [
|
plug(:skip_auth)
|
||||||
Pleroma.Web.Plugs.OAuthScopesPlug,
|
|
||||||
Pleroma.Web.Plugs.EnsurePublicOrAuthenticatedPlug
|
|
||||||
])
|
|
||||||
|
|
||||||
plug(RateLimiter, [name: :authentication] when action == :create_authorization)
|
plug(RateLimiter, [name: :authentication] when action == :create_authorization)
|
||||||
|
|
||||||
|
@ -50,7 +47,7 @@ def authorize(%Plug.Conn{} = conn, %{"authorization" => _} = params) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def authorize(%Plug.Conn{assigns: %{token: %Token{}}} = conn, %{"force_login" => _} = params) do
|
def authorize(%Plug.Conn{assigns: %{token: %Token{}}} = conn, %{"force_login" => _} = params) do
|
||||||
if ControllerHelper.truthy_param?(params["force_login"]) do
|
if Params.truthy_param?(params["force_login"]) do
|
||||||
do_authorize(conn, params)
|
do_authorize(conn, params)
|
||||||
else
|
else
|
||||||
handle_existing_authorization(conn, params)
|
handle_existing_authorization(conn, params)
|
||||||
|
|
|
@ -11,7 +11,6 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.MastodonAPI.StatusView
|
alias Pleroma.Web.MastodonAPI.StatusView
|
||||||
alias Pleroma.Web.Plugs.EnsurePublicOrAuthenticatedPlug
|
|
||||||
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
||||||
alias Pleroma.Web.Plugs.RateLimiter
|
alias Pleroma.Web.Plugs.RateLimiter
|
||||||
|
|
||||||
|
@ -29,10 +28,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
|
||||||
|
|
||||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||||
|
|
||||||
plug(
|
plug(:skip_auth when action == :confirmation_resend)
|
||||||
:skip_plug,
|
|
||||||
[OAuthScopesPlug, EnsurePublicOrAuthenticatedPlug] when action == :confirmation_resend
|
|
||||||
)
|
|
||||||
|
|
||||||
plug(
|
plug(
|
||||||
OAuthScopesPlug,
|
OAuthScopesPlug,
|
||||||
|
|
|
@ -22,11 +22,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackController do
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@skip_plugs [
|
plug(:skip_auth when action in [:index, :archive, :show])
|
||||||
Pleroma.Web.Plugs.OAuthScopesPlug,
|
|
||||||
Pleroma.Web.Plugs.EnsurePublicOrAuthenticatedPlug
|
|
||||||
]
|
|
||||||
plug(:skip_plug, @skip_plugs when action in [:index, :archive, :show])
|
|
||||||
|
|
||||||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaEmojiPackOperation
|
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaEmojiPackOperation
|
||||||
|
|
||||||
|
|
|
@ -61,5 +61,5 @@
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<%= if Pleroma.Config.oauth_consumer_enabled?() do %>
|
<%= if Pleroma.Config.oauth_consumer_enabled?() do %>
|
||||||
<%= render @view_module, Pleroma.Web.Auth.Authenticator.oauth_consumer_template(), assigns %>
|
<%= render @view_module, Pleroma.Web.Auth.WrapperAuthenticator.oauth_consumer_template(), assigns %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
@ -7,17 +7,12 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
||||||
|
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.OAuth.Token
|
alias Pleroma.Web.OAuth.Token
|
||||||
alias Pleroma.Web.Plugs.EnsurePublicOrAuthenticatedPlug
|
|
||||||
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
||||||
alias Pleroma.Web.TwitterAPI.TokenView
|
alias Pleroma.Web.TwitterAPI.TokenView
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
plug(
|
plug(:skip_auth when action == :confirm_email)
|
||||||
:skip_plug,
|
|
||||||
[OAuthScopesPlug, EnsurePublicOrAuthenticatedPlug] when action == :confirm_email
|
|
||||||
)
|
|
||||||
|
|
||||||
plug(:skip_plug, OAuthScopesPlug when action in [:oauth_tokens, :revoke_token])
|
plug(:skip_plug, OAuthScopesPlug when action in [:oauth_tokens, :revoke_token])
|
||||||
|
|
||||||
action_fallback(:errors)
|
action_fallback(:errors)
|
||||||
|
|
|
@ -11,8 +11,8 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do
|
||||||
alias Pleroma.MFA
|
alias Pleroma.MFA
|
||||||
alias Pleroma.Object.Fetcher
|
alias Pleroma.Object.Fetcher
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.Auth.Authenticator
|
|
||||||
alias Pleroma.Web.Auth.TOTPAuthenticator
|
alias Pleroma.Web.Auth.TOTPAuthenticator
|
||||||
|
alias Pleroma.Web.Auth.WrapperAuthenticator
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
|
|
||||||
@status_types ["Article", "Event", "Note", "Video", "Page", "Question"]
|
@status_types ["Article", "Event", "Note", "Video", "Page", "Question"]
|
||||||
|
@ -88,7 +88,7 @@ def do_follow(%{assigns: %{user: %User{} = user}} = conn, %{"user" => %{"id" =>
|
||||||
#
|
#
|
||||||
def do_follow(conn, %{"authorization" => %{"name" => _, "password" => _, "id" => id}}) do
|
def do_follow(conn, %{"authorization" => %{"name" => _, "password" => _, "id" => id}}) do
|
||||||
with {_, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)},
|
with {_, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)},
|
||||||
{_, {:ok, user}, _} <- {:auth, Authenticator.get_user(conn), followee},
|
{_, {:ok, user}, _} <- {:auth, WrapperAuthenticator.get_user(conn), followee},
|
||||||
{_, _, _, false} <- {:mfa_required, followee, user, MFA.require?(user)},
|
{_, _, _, false} <- {:mfa_required, followee, user, MFA.require?(user)},
|
||||||
{:ok, _, _, _} <- CommonAPI.follow(user, followee) do
|
{:ok, _, _, _} <- CommonAPI.follow(user, followee) do
|
||||||
redirect(conn, to: "/users/#{followee.id}")
|
redirect(conn, to: "/users/#{followee.id}")
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.Utils.Guards do
|
||||||
|
@moduledoc """
|
||||||
|
Project-wide custom guards.
|
||||||
|
See: https://hexdocs.pm/elixir/master/patterns-and-guards.html#custom-patterns-and-guards-expressions
|
||||||
|
"""
|
||||||
|
|
||||||
|
@doc "Checks for non-empty string"
|
||||||
|
defguard not_empty_string(string) when is_binary(string) and string != ""
|
||||||
|
end
|
|
@ -0,0 +1,16 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.Utils.Params do
|
||||||
|
# As in Mastodon API, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
|
||||||
|
@falsy_param_values [false, 0, "0", "f", "F", "false", "False", "FALSE", "off", "OFF"]
|
||||||
|
|
||||||
|
defp explicitly_falsy_param?(value), do: value in @falsy_param_values
|
||||||
|
|
||||||
|
# Note: `nil` and `""` are considered falsy values in Pleroma
|
||||||
|
defp falsy_param?(value),
|
||||||
|
do: explicitly_falsy_param?(value) or value in [nil, ""]
|
||||||
|
|
||||||
|
def truthy_param?(value), do: not falsy_param?(value)
|
||||||
|
end
|
12
mix.exs
12
mix.exs
|
@ -121,8 +121,7 @@ defp deps do
|
||||||
{:phoenix_pubsub, "~> 2.0"},
|
{:phoenix_pubsub, "~> 2.0"},
|
||||||
{:phoenix_ecto, "~> 4.0"},
|
{:phoenix_ecto, "~> 4.0"},
|
||||||
{:ecto_enum, "~> 1.4"},
|
{:ecto_enum, "~> 1.4"},
|
||||||
{:ecto_explain, "~> 0.1.2"},
|
{:ecto_sql, "~> 3.6.2"},
|
||||||
{:ecto_sql, "~> 3.4.4"},
|
|
||||||
{:postgrex, ">= 0.15.5"},
|
{:postgrex, ">= 0.15.5"},
|
||||||
{:oban, "~> 2.3.4"},
|
{:oban, "~> 2.3.4"},
|
||||||
{:gettext, "~> 0.18"},
|
{:gettext, "~> 0.18"},
|
||||||
|
@ -158,7 +157,7 @@ defp deps do
|
||||||
{:floki, "~> 0.27"},
|
{:floki, "~> 0.27"},
|
||||||
{:timex, "~> 3.6"},
|
{:timex, "~> 3.6"},
|
||||||
{:ueberauth, "~> 0.4"},
|
{:ueberauth, "~> 0.4"},
|
||||||
{:linkify, "~> 0.5.0"},
|
{:linkify, "~> 0.5.1"},
|
||||||
{:http_signatures, "~> 0.1.0"},
|
{:http_signatures, "~> 0.1.0"},
|
||||||
{:telemetry, "~> 0.3"},
|
{:telemetry, "~> 0.3"},
|
||||||
{:poolboy, "~> 1.5"},
|
{:poolboy, "~> 1.5"},
|
||||||
|
@ -196,11 +195,12 @@ defp deps do
|
||||||
{:majic,
|
{:majic,
|
||||||
git: "https://git.pleroma.social/pleroma/elixir-libraries/majic.git",
|
git: "https://git.pleroma.social/pleroma/elixir-libraries/majic.git",
|
||||||
ref: "289cda1b6d0d70ccb2ba508a2b0bd24638db2880"},
|
ref: "289cda1b6d0d70ccb2ba508a2b0bd24638db2880"},
|
||||||
{:eblurhash,
|
{:eblurhash, "~> 1.1.0"},
|
||||||
git: "https://github.com/zotonic/eblurhash.git",
|
|
||||||
ref: "04a0b76eadf4de1be17726f39b6313b88708fd12"},
|
|
||||||
{:open_api_spex, "~> 3.10"},
|
{:open_api_spex, "~> 3.10"},
|
||||||
|
|
||||||
|
# indirect dependency version override
|
||||||
|
{:plug, "~> 1.10.4", override: true},
|
||||||
|
|
||||||
## dev & test
|
## dev & test
|
||||||
{:ex_doc, "~> 0.22", only: :dev, runtime: false},
|
{:ex_doc, "~> 0.22", only: :dev, runtime: false},
|
||||||
{:ex_machina, "~> 2.4", only: :test},
|
{:ex_machina, "~> 2.4", only: :test},
|
||||||
|
|
11
mix.lock
11
mix.lock
|
@ -29,11 +29,10 @@
|
||||||
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
|
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
|
||||||
"earmark": {:hex, :earmark, "1.4.15", "2c7f924bf495ec1f65bd144b355d0949a05a254d0ec561740308a54946a67888", [:mix], [{:earmark_parser, ">= 1.4.13", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "3b1209b85bc9f3586f370f7c363f6533788fb4e51db23aa79565875e7f9999ee"},
|
"earmark": {:hex, :earmark, "1.4.15", "2c7f924bf495ec1f65bd144b355d0949a05a254d0ec561740308a54946a67888", [:mix], [{:earmark_parser, ">= 1.4.13", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "3b1209b85bc9f3586f370f7c363f6533788fb4e51db23aa79565875e7f9999ee"},
|
||||||
"earmark_parser": {:hex, :earmark_parser, "1.4.13", "0c98163e7d04a15feb62000e1a891489feb29f3d10cb57d4f845c405852bbef8", [:mix], [], "hexpm", "d602c26af3a0af43d2f2645613f65841657ad6efc9f0e361c3b6c06b578214ba"},
|
"earmark_parser": {:hex, :earmark_parser, "1.4.13", "0c98163e7d04a15feb62000e1a891489feb29f3d10cb57d4f845c405852bbef8", [:mix], [], "hexpm", "d602c26af3a0af43d2f2645613f65841657ad6efc9f0e361c3b6c06b578214ba"},
|
||||||
"eblurhash": {:git, "https://github.com/zotonic/eblurhash.git", "04a0b76eadf4de1be17726f39b6313b88708fd12", [ref: "04a0b76eadf4de1be17726f39b6313b88708fd12"]},
|
"eblurhash": {:hex, :eblurhash, "1.1.0", "e10ccae762598507ebfacf0b645ed49520f2afa3e7e9943e73a91117dffce415", [:rebar3], [], "hexpm", "2e6b889d09fddd374e3c5ac57c486138768763264e99ac1074ae5fa7fc9ab51d"},
|
||||||
"ecto": {:hex, :ecto, "3.4.6", "08f7afad3257d6eb8613309af31037e16c36808dfda5a3cd0cb4e9738db030e4", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6f13a9e2a62e75c2dcfc7207bfc65645ab387af8360db4c89fee8b5a4bf3f70b"},
|
"ecto": {:hex, :ecto, "3.6.2", "efdf52acfc4ce29249bab5417415bd50abd62db7b0603b8bab0d7b996548c2bc", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "efad6dfb04e6f986b8a3047822b0f826d9affe8e4ebdd2aeedbfcb14fd48884e"},
|
||||||
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},
|
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},
|
||||||
"ecto_explain": {:hex, :ecto_explain, "0.1.2", "a9d504cbd4adc809911f796d5ef7ebb17a576a6d32286c3d464c015bd39d5541", [:mix], [], "hexpm", "1d0e7798ae30ecf4ce34e912e5354a0c1c832b7ebceba39298270b9a9f316330"},
|
"ecto_sql": {:hex, :ecto_sql, "3.6.2", "9526b5f691701a5181427634c30655ac33d11e17e4069eff3ae1176c764e0ba3", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.6.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.4.0 or ~> 0.5.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5ec9d7e6f742ea39b63aceaea9ac1d1773d574ea40df5a53ef8afbd9242fdb6b"},
|
||||||
"ecto_sql": {:hex, :ecto_sql, "3.4.5", "30161f81b167d561a9a2df4329c10ae05ff36eca7ccc84628f2c8b9fa1e43323", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0 or ~> 0.4.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.0", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "31990c6a3579b36a3c0841d34a94c275e727de8b84f58509da5f1b2032c98ac2"},
|
|
||||||
"eimp": {:hex, :eimp, "1.0.14", "fc297f0c7e2700457a95a60c7010a5f1dcb768a083b6d53f49cd94ab95a28f22", [:rebar3], [{:p1_utils, "1.0.18", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "501133f3112079b92d9e22da8b88bf4f0e13d4d67ae9c15c42c30bd25ceb83b6"},
|
"eimp": {:hex, :eimp, "1.0.14", "fc297f0c7e2700457a95a60c7010a5f1dcb768a083b6d53f49cd94ab95a28f22", [:rebar3], [{:p1_utils, "1.0.18", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "501133f3112079b92d9e22da8b88bf4f0e13d4d67ae9c15c42c30bd25ceb83b6"},
|
||||||
"elixir_make": {:hex, :elixir_make, "0.6.2", "7dffacd77dec4c37b39af867cedaabb0b59f6a871f89722c25b28fcd4bd70530", [:mix], [], "hexpm", "03e49eadda22526a7e5279d53321d1cced6552f344ba4e03e619063de75348d9"},
|
"elixir_make": {:hex, :elixir_make, "0.6.2", "7dffacd77dec4c37b39af867cedaabb0b59f6a871f89722c25b28fcd4bd70530", [:mix], [], "hexpm", "03e49eadda22526a7e5279d53321d1cced6552f344ba4e03e619063de75348d9"},
|
||||||
"esshd": {:hex, :esshd, "0.1.1", "d4dd4c46698093a40a56afecce8a46e246eb35463c457c246dacba2e056f31b5", [:mix], [], "hexpm", "d73e341e3009d390aa36387dc8862860bf9f874c94d9fd92ade2926376f49981"},
|
"esshd": {:hex, :esshd, "0.1.1", "d4dd4c46698093a40a56afecce8a46e246eb35463c457c246dacba2e056f31b5", [:mix], [], "hexpm", "d73e341e3009d390aa36387dc8862860bf9f874c94d9fd92ade2926376f49981"},
|
||||||
|
@ -68,7 +67,7 @@
|
||||||
"jose": {:hex, :jose, "1.11.1", "59da64010c69aad6cde2f5b9248b896b84472e99bd18f246085b7b9fe435dcdb", [:mix, :rebar3], [], "hexpm", "078f6c9fb3cd2f4cfafc972c814261a7d1e8d2b3685c0a76eb87e158efff1ac5"},
|
"jose": {:hex, :jose, "1.11.1", "59da64010c69aad6cde2f5b9248b896b84472e99bd18f246085b7b9fe435dcdb", [:mix, :rebar3], [], "hexpm", "078f6c9fb3cd2f4cfafc972c814261a7d1e8d2b3685c0a76eb87e158efff1ac5"},
|
||||||
"jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"},
|
"jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"},
|
||||||
"libring": {:hex, :libring, "1.4.0", "41246ba2f3fbc76b3971f6bce83119dfec1eee17e977a48d8a9cfaaf58c2a8d6", [:mix], [], "hexpm"},
|
"libring": {:hex, :libring, "1.4.0", "41246ba2f3fbc76b3971f6bce83119dfec1eee17e977a48d8a9cfaaf58c2a8d6", [:mix], [], "hexpm"},
|
||||||
"linkify": {:hex, :linkify, "0.5.0", "e0ea8de73ff44742d6a889721221f4c4eccaad5284957ee9832ffeb347602d54", [:mix], [], "hexpm", "4ccd958350aee7c51c89e21f05b15d30596ebbba707e051d21766be1809df2d7"},
|
"linkify": {:hex, :linkify, "0.5.1", "6dc415cbc948b2f6ecec7cb226aab7ba9d3a1815bb501ae33e042334d707ecee", [:mix], [], "hexpm", "a3128c7e22fada4aa7214009501d8131e1fa3faf2f0a68b33dba379dc84ff944"},
|
||||||
"majic": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/majic.git", "289cda1b6d0d70ccb2ba508a2b0bd24638db2880", [ref: "289cda1b6d0d70ccb2ba508a2b0bd24638db2880"]},
|
"majic": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/majic.git", "289cda1b6d0d70ccb2ba508a2b0bd24638db2880", [ref: "289cda1b6d0d70ccb2ba508a2b0bd24638db2880"]},
|
||||||
"makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"},
|
"makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"},
|
||||||
"makeup_elixir": {:hex, :makeup_elixir, "0.14.1", "4f0e96847c63c17841d42c08107405a005a2680eb9c7ccadfd757bd31dabccfb", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f2438b1a80eaec9ede832b5c41cd4f373b38fd7aa33e3b22d9db79e640cbde11"},
|
"makeup_elixir": {:hex, :makeup_elixir, "0.14.1", "4f0e96847c63c17841d42c08107405a005a2680eb9c7ccadfd757bd31dabccfb", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f2438b1a80eaec9ede832b5c41cd4f373b38fd7aa33e3b22d9db79e640cbde11"},
|
||||||
|
@ -95,7 +94,7 @@
|
||||||
"phoenix_html": {:hex, :phoenix_html, "2.14.3", "51f720d0d543e4e157ff06b65de38e13303d5778a7919bcc696599e5934271b8", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "efd697a7fff35a13eeeb6b43db884705cba353a1a41d127d118fda5f90c8e80f"},
|
"phoenix_html": {:hex, :phoenix_html, "2.14.3", "51f720d0d543e4e157ff06b65de38e13303d5778a7919bcc696599e5934271b8", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "efd697a7fff35a13eeeb6b43db884705cba353a1a41d127d118fda5f90c8e80f"},
|
||||||
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.0.0", "a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm", "c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"},
|
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.0.0", "a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm", "c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"},
|
||||||
"phoenix_swoosh": {:hex, :phoenix_swoosh, "0.3.3", "039435dd975f7e55953525b88f1d596f26c6141412584c16f4db109708a8ee68", [:mix], [{:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.0", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "4a540cea32e05356541737033d666ee7fea7700eb2101bf76783adbfe06601cd"},
|
"phoenix_swoosh": {:hex, :phoenix_swoosh, "0.3.3", "039435dd975f7e55953525b88f1d596f26c6141412584c16f4db109708a8ee68", [:mix], [{:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.0", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "4a540cea32e05356541737033d666ee7fea7700eb2101bf76783adbfe06601cd"},
|
||||||
"plug": {:hex, :plug, "1.11.1", "f2992bac66fdae679453c9e86134a4201f6f43a687d8ff1cd1b2862d53c80259", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "23524e4fefbb587c11f0833b3910bfb414bf2e2534d61928e920f54e3a1b881f"},
|
"plug": {:hex, :plug, "1.10.4", "41eba7d1a2d671faaf531fa867645bd5a3dce0957d8e2a3f398ccff7d2ef017f", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ad1e233fe73d2eec56616568d260777b67f53148a999dc2d048f4eb9778fe4a0"},
|
||||||
"plug_cowboy": {:hex, :plug_cowboy, "2.5.0", "51c998f788c4e68fc9f947a5eba8c215fbb1d63a520f7604134cab0270ea6513", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5b2c8925a5e2587446f33810a58c01e66b3c345652eeec809b76ba007acde71a"},
|
"plug_cowboy": {:hex, :plug_cowboy, "2.5.0", "51c998f788c4e68fc9f947a5eba8c215fbb1d63a520f7604134cab0270ea6513", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5b2c8925a5e2587446f33810a58c01e66b3c345652eeec809b76ba007acde71a"},
|
||||||
"plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"},
|
"plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"},
|
||||||
"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"},
|
"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"},
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.DeleteHashtagsObjectsCascade do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def up do
|
||||||
|
execute("ALTER TABLE hashtags_objects DROP CONSTRAINT hashtags_objects_object_id_fkey")
|
||||||
|
|
||||||
|
alter table(:hashtags_objects) do
|
||||||
|
modify(:object_id, references(:objects, on_delete: :delete_all))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def down do
|
||||||
|
execute("ALTER TABLE hashtags_objects DROP CONSTRAINT hashtags_objects_object_id_fkey")
|
||||||
|
|
||||||
|
alter table(:hashtags_objects) do
|
||||||
|
modify(:object_id, references(:objects, on_delete: :nothing))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,5 +1,5 @@
|
||||||
defmodule Fixtures.Modules.GoodMRF do
|
defmodule Fixtures.Modules.GoodMRF do
|
||||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(a), do: {:ok, a}
|
def filter(a), do: {:ok, a}
|
||||||
|
|
Binary file not shown.
|
@ -13,7 +13,7 @@ test "ecto.migrate info message" do
|
||||||
|
|
||||||
assert capture_log(fn ->
|
assert capture_log(fn ->
|
||||||
Mix.Tasks.Pleroma.Ecto.Migrate.run()
|
Mix.Tasks.Pleroma.Ecto.Migrate.run()
|
||||||
end) =~ "[info] Already up"
|
end) =~ "[info] Migrations already up"
|
||||||
|
|
||||||
Logger.configure(level: level)
|
Logger.configure(level: level)
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,7 +6,7 @@ defmodule Pleroma.Upload.Filter.AnalyzeMetadataTest do
|
||||||
use Pleroma.DataCase, async: true
|
use Pleroma.DataCase, async: true
|
||||||
alias Pleroma.Upload.Filter.AnalyzeMetadata
|
alias Pleroma.Upload.Filter.AnalyzeMetadata
|
||||||
|
|
||||||
test "adds the image dimensions" do
|
test "adds the dimensions and blurhash for images" do
|
||||||
upload = %Pleroma.Upload{
|
upload = %Pleroma.Upload{
|
||||||
name: "an… image.jpg",
|
name: "an… image.jpg",
|
||||||
content_type: "image/jpeg",
|
content_type: "image/jpeg",
|
||||||
|
@ -14,6 +14,20 @@ test "adds the image dimensions" do
|
||||||
tempfile: Path.absname("test/fixtures/image.jpg")
|
tempfile: Path.absname("test/fixtures/image.jpg")
|
||||||
}
|
}
|
||||||
|
|
||||||
assert {:ok, :filtered, %{width: 1024, height: 768}} = AnalyzeMetadata.filter(upload)
|
{:ok, :filtered, meta} = AnalyzeMetadata.filter(upload)
|
||||||
|
|
||||||
|
assert %{width: 1024, height: 768} = meta
|
||||||
|
assert meta.blurhash
|
||||||
|
end
|
||||||
|
|
||||||
|
test "adds the dimensions for videos" do
|
||||||
|
upload = %Pleroma.Upload{
|
||||||
|
name: "coolvideo.mp4",
|
||||||
|
content_type: "video/mp4",
|
||||||
|
path: Path.absname("test/fixtures/video.mp4"),
|
||||||
|
tempfile: Path.absname("test/fixtures/video.mp4")
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {:ok, :filtered, %{width: 480, height: 480}} = AnalyzeMetadata.filter(upload)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue