Merge remote-tracking branch 'origin/develop' into unlisted-fix
This commit is contained in:
commit
8488362248
61 changed files with 659 additions and 467 deletions
|
|
@ -79,12 +79,12 @@ build-1.14.5-otp-25:
|
||||||
script:
|
script:
|
||||||
- mix compile --force
|
- mix compile --force
|
||||||
|
|
||||||
build-1.17.1-otp-26:
|
build-1.18.3-otp-27:
|
||||||
extends:
|
extends:
|
||||||
- .build_changes_policy
|
- .build_changes_policy
|
||||||
- .using-ci-base
|
- .using-ci-base
|
||||||
stage: build
|
stage: build
|
||||||
image: git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.17.1-otp-26
|
image: git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.18.3-otp-27
|
||||||
script:
|
script:
|
||||||
- mix compile --force
|
- mix compile --force
|
||||||
|
|
||||||
|
|
@ -142,12 +142,12 @@ unit-testing-1.14.5-otp-25:
|
||||||
coverage_format: cobertura
|
coverage_format: cobertura
|
||||||
path: coverage.xml
|
path: coverage.xml
|
||||||
|
|
||||||
unit-testing-1.17.1-otp-26:
|
unit-testing-1.18.3-otp-27:
|
||||||
extends:
|
extends:
|
||||||
- .build_changes_policy
|
- .build_changes_policy
|
||||||
- .using-ci-base
|
- .using-ci-base
|
||||||
stage: test
|
stage: test
|
||||||
image: git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.17.1-otp-26
|
image: git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.18.3-otp-27
|
||||||
cache: *testing_cache_policy
|
cache: *testing_cache_policy
|
||||||
services: *testing_services
|
services: *testing_services
|
||||||
script: *testing_script
|
script: *testing_script
|
||||||
|
|
|
||||||
1
changelog.d/admin-api-docs-fix.skip
Normal file
1
changelog.d/admin-api-docs-fix.skip
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Fix 'Create a user' description in admin api docs
|
||||||
0
changelog.d/admin-api-log-fix.skip
Normal file
0
changelog.d/admin-api-log-fix.skip
Normal file
1
changelog.d/assign-app-user-oom.fix
Normal file
1
changelog.d/assign-app-user-oom.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Fix AssignAppUser migration OOM
|
||||||
0
changelog.d/doc-typo.skip
Normal file
0
changelog.d/doc-typo.skip
Normal file
1
changelog.d/elixir-1-18.fix
Normal file
1
changelog.d/elixir-1-18.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Elixir 1.18: Fixed warnings and new deprecations
|
||||||
1
changelog.d/expiring-blocks.add
Normal file
1
changelog.d/expiring-blocks.add
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Add `duration` to the block endpoint, which makes block expire
|
||||||
0
changelog.d/fixtests.skip
Normal file
0
changelog.d/fixtests.skip
Normal file
0
changelog.d/openbsd-docs-update.skip
Normal file
0
changelog.d/openbsd-docs-update.skip
Normal file
1
changelog.d/openbsd-update-httpd-relayd.change
Normal file
1
changelog.d/openbsd-update-httpd-relayd.change
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Updated relayd/httpd config files to be on par with nginx
|
||||||
1
changelog.d/openbsd-update-rc.fix
Normal file
1
changelog.d/openbsd-update-rc.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
replaced depracated flags and functions, renamed service to fit other service files
|
||||||
0
changelog.d/private-functions.skip
Normal file
0
changelog.d/private-functions.skip
Normal file
0
changelog.d/remove-forgotten-OTPVersion-usage.skip
Normal file
0
changelog.d/remove-forgotten-OTPVersion-usage.skip
Normal file
1
changelog.d/webfinger.change
Normal file
1
changelog.d/webfinger.change
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Don't require an Accept header for WebFinger queries and default to JSON.
|
||||||
8
ci/elixir-1.18.3-otp-27/Dockerfile
Normal file
8
ci/elixir-1.18.3-otp-27/Dockerfile
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
FROM elixir:1.18.3-otp-27
|
||||||
|
|
||||||
|
# Single RUN statement, otherwise intermediate images are created
|
||||||
|
# https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run
|
||||||
|
RUN apt-get update &&\
|
||||||
|
apt-get install -y libmagic-dev cmake libimage-exiftool-perl ffmpeg &&\
|
||||||
|
mix local.hex --force &&\
|
||||||
|
mix local.rebar --force
|
||||||
1
ci/elixir-1.18.3-otp-27/build_and_push.sh
Executable file
1
ci/elixir-1.18.3-otp-27/build_and_push.sh
Executable file
|
|
@ -0,0 +1 @@
|
||||||
|
docker buildx build --platform linux/amd64,linux/arm64 -t git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.18.3-otp-27 --push .
|
||||||
|
|
@ -70,6 +70,8 @@ The `/api/v1/pleroma/admin/*` path is backwards compatible with `/api/pleroma/ad
|
||||||
- `nicknames`
|
- `nicknames`
|
||||||
- Response: Array of user nicknames
|
- Response: Array of user nicknames
|
||||||
|
|
||||||
|
## `POST /api/v1/pleroma/admin/users`
|
||||||
|
|
||||||
### Create a user
|
### Create a user
|
||||||
|
|
||||||
- Method: `POST`
|
- Method: `POST`
|
||||||
|
|
@ -81,7 +83,7 @@ The `/api/v1/pleroma/admin/*` path is backwards compatible with `/api/pleroma/ad
|
||||||
`password`
|
`password`
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
- Response: User’s nickname
|
- Response: Array of user objects
|
||||||
|
|
||||||
## `POST /api/v1/pleroma/admin/users/follow`
|
## `POST /api/v1/pleroma/admin/users/follow`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
## Required dependencies
|
## Required dependencies
|
||||||
|
|
||||||
* PostgreSQL >=11.0
|
* PostgreSQL >=11.0
|
||||||
* Elixir >=1.14.0 <1.17
|
* Elixir >=1.14.0 <1.19
|
||||||
* Erlang OTP >=23.0.0 (supported: <27)
|
* Erlang OTP >=23.0.0 (supported: <28)
|
||||||
* git
|
* git
|
||||||
* file / libmagic
|
* file / libmagic
|
||||||
* gcc or clang
|
* gcc or clang
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,29 @@
|
||||||
# Installing on OpenBSD
|
# Installing on OpenBSD
|
||||||
|
|
||||||
This guide describes the installation and configuration of pleroma (and the required software to run it) on a single OpenBSD 6.6 server.
|
{! backend/installation/otp_vs_from_source_source.include !}
|
||||||
|
|
||||||
|
This guide describes the installation and configuration of Pleroma (and the required software to run it) on a single OpenBSD 7.7 server.
|
||||||
|
|
||||||
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 !}
|
{! backend/installation/generic_dependencies.include !}
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
### Preparing the system
|
### Preparing the system
|
||||||
#### Required software
|
#### Required software
|
||||||
|
|
||||||
To install them, run the following command (with doas or as root):
|
To install required packages, run the following command:
|
||||||
|
|
||||||
```
|
```
|
||||||
pkg_add elixir gmake git postgresql-server postgresql-contrib cmake ffmpeg ImageMagick libvips
|
# pkg_add elixir gmake git postgresql-server postgresql-contrib cmake libmagic libvips
|
||||||
```
|
```
|
||||||
|
|
||||||
Pleroma requires a reverse proxy, OpenBSD has relayd in base (and is used in this guide) and packages/ports are available for nginx (www/nginx) and apache (www/apache-httpd). Independently of the reverse proxy, [acme-client(1)](https://man.openbsd.org/acme-client) can be used to get a certificate from Let's Encrypt.
|
Pleroma requires a reverse proxy, OpenBSD has relayd in base (and is used in this guide) and packages/ports are available for nginx (www/nginx) and apache (www/apache-httpd).
|
||||||
|
Independently of the reverse proxy, [acme-client(1)](https://man.openbsd.org/acme-client) can be used to get a certificate from Let's Encrypt.
|
||||||
|
|
||||||
#### Optional software
|
#### Optional software
|
||||||
|
|
||||||
Per [`docs/installation/optional/media_graphics_packages.md`](../installation/optional/media_graphics_packages.md):
|
|
||||||
* ImageMagick
|
* ImageMagick
|
||||||
* ffmpeg
|
* ffmpeg
|
||||||
* exiftool
|
* exiftool
|
||||||
|
|
@ -27,234 +31,351 @@ Per [`docs/installation/optional/media_graphics_packages.md`](../installation/op
|
||||||
To install the above:
|
To install the above:
|
||||||
|
|
||||||
```
|
```
|
||||||
pkg_add ImageMagick ffmpeg p5-Image-ExifTool
|
# pkg_add ImageMagick ffmpeg p5-Image-ExifTool
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Creating the pleroma user
|
For more information read [`docs/installation/optional/media_graphics_packages.md`](../installation/optional/media_graphics_packages.md):
|
||||||
Pleroma will be run by a dedicated user, \_pleroma. Before creating it, insert the following lines in login.conf:
|
|
||||||
|
### PostgreSQL
|
||||||
|
|
||||||
|
Switch to the \_postgresql user and initialize PostgreSQL:
|
||||||
|
|
||||||
|
```
|
||||||
|
# su _postgresql
|
||||||
|
$ initdb -D /var/postgresql/data -U postgres --encoding=utf-8 --lc-collate=C
|
||||||
|
```
|
||||||
|
|
||||||
|
Running PostgreSQL in a different directory than `/var/postgresql/data` requires changing the `daemon_flags` variable in the `/etc/rc.d/postgresql` script.
|
||||||
|
|
||||||
|
For security reasons it is recommended to change the authentication method for `local` and `host` connections with the localhost address to `scram-sha-256`.<br>
|
||||||
|
Do not forget to set a password for the `postgres` user before doing so, otherwise you won't be able to log back in unless you change the authentication method back to `trust`.<br>
|
||||||
|
Changing the password hashing algorithm is not needed.<br>
|
||||||
|
For more information [read](https://www.postgresql.org/docs/16/auth-pg-hba-conf.html) the PostgreSQL documentation.
|
||||||
|
|
||||||
|
Enable and start the postgresql service:
|
||||||
|
|
||||||
|
```
|
||||||
|
# rcctl enable postgresql
|
||||||
|
# rcctl start postgresql
|
||||||
|
```
|
||||||
|
|
||||||
|
To check that PostgreSQL started properly and didn't fail right after starting, run `# rcctl check postgresql` which should return `postgresql(ok)`.
|
||||||
|
|
||||||
|
### Configuring Pleroma
|
||||||
|
|
||||||
|
Pleroma will be run by a dedicated \_pleroma user. Before creating it, insert the following lines in `/etc/login.conf`:
|
||||||
|
|
||||||
```
|
```
|
||||||
pleroma:\
|
pleroma:\
|
||||||
:datasize-max=1536M:\
|
:datasize=1536M:\
|
||||||
:datasize-cur=1536M:\
|
:openfiles-max=4096:\
|
||||||
:openfiles-max=4096
|
:openfiles-cur=1024:\
|
||||||
|
:setenv=LC_ALL=en_US.UTF-8,VIX_COMPILATION_MODE=PLATFORM_PROVIDED_LIBVIPS,MIX_ENV=prod:\
|
||||||
|
:tc=daemon:
|
||||||
```
|
```
|
||||||
This creates a "pleroma" login class and sets higher values than default for datasize and openfiles (see [login.conf(5)](https://man.openbsd.org/login.conf)), this is required to avoid having pleroma crash some time after starting.
|
|
||||||
|
|
||||||
Create the \_pleroma user, assign it the pleroma login class and create its home directory (/home/\_pleroma/): `useradd -m -L pleroma _pleroma`
|
This creates a "pleroma" login class and sets higher values than default for datasize and openfiles (see [login.conf(5)](https://man.openbsd.org/login.conf)), this is required to avoid having Pleroma crash some time after starting.
|
||||||
|
|
||||||
#### Clone pleroma's directory
|
Create the \_pleroma user, assign it the pleroma login class and create its home directory (/home/\_pleroma/):
|
||||||
Enter a shell as the \_pleroma user. As root, run `su _pleroma -;cd`. Then clone the repository with `git clone -b stable https://git.pleroma.social/pleroma/pleroma.git`. Pleroma is now installed in /home/\_pleroma/pleroma/, it will be configured and started at the end of this guide.
|
|
||||||
|
|
||||||
#### PostgreSQL
|
|
||||||
Start a shell as the \_postgresql user (as root run `su _postgresql -` then run the `initdb` command to initialize postgresql:
|
|
||||||
You will need to specify pgdata directory to the default (/var/postgresql/data) with the `-D <path>` and set the user to postgres with the `-U <username>` flag. This can be done as follows:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
initdb -D /var/postgresql/data -U postgres
|
# useradd -m -L pleroma _pleroma
|
||||||
```
|
```
|
||||||
If you are not using the default directory, you will have to update the `datadir` variable in the /etc/rc.d/postgresql script.
|
|
||||||
|
|
||||||
When this is done, enable postgresql so that it starts on boot and start it. As root, run:
|
Switch to the _pleroma user:
|
||||||
|
|
||||||
```
|
```
|
||||||
rcctl enable postgresql
|
# su -l _pleroma
|
||||||
rcctl start postgresql
|
```
|
||||||
|
|
||||||
|
Clone the Pleroma repository:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ git clone -b stable https://git.pleroma.social/pleroma/pleroma.git
|
||||||
|
$ cd pleroma
|
||||||
|
```
|
||||||
|
|
||||||
|
Pleroma is now installed in /home/\_pleroma/pleroma/. To configure it run:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ mix deps.get
|
||||||
|
$ MIX_ENV=prod mix pleroma.instance gen # You will be asked a few questions here.
|
||||||
|
$ cp config/generated_config.exs config/prod.secret.exs
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: Answer yes when asked to install Hex and rebar3. This step might take some time as Pleroma gets compiled first.
|
||||||
|
|
||||||
|
Create the Pleroma database:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ psql -U postgres -f config/setup_db.psql
|
||||||
|
```
|
||||||
|
|
||||||
|
Apply database migrations:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ MIX_ENV=prod mix ecto.migrate
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: You will need to run this step again when updating your instance to a newer version with `git pull` or `git checkout tags/NEW_VERSION`.
|
||||||
|
|
||||||
|
As \_pleroma in /home/\_pleroma/pleroma, you can now run `MIX_ENV=prod mix phx.server` to start your instance.
|
||||||
|
In another SSH session or a tmux window, check that it is working properly by running `ftp -MVo - http://127.0.0.1:4000/api/v1/instance`, you should get json output.
|
||||||
|
Double-check that the *uri* value near the bottom is your instance's domain name and the instance *title* are correct.
|
||||||
|
|
||||||
|
### Configuring acme-client
|
||||||
|
|
||||||
|
acme-client is used to get SSL/TLS certificates from Let's Encrypt.
|
||||||
|
Insert the following configuration in `/etc/acme-client.conf` and replace `example.tld` with your domain:
|
||||||
|
|
||||||
|
```
|
||||||
|
#
|
||||||
|
# $OpenBSD: acme-client.conf,v 1.5 2023/05/10 07:34:57 tb Exp $
|
||||||
|
#
|
||||||
|
|
||||||
|
authority letsencrypt {
|
||||||
|
api url "https://acme-v02.api.letsencrypt.org/directory"
|
||||||
|
account key "/etc/acme/letsencrypt-privkey.pem"
|
||||||
|
}
|
||||||
|
|
||||||
|
domain example.tld {
|
||||||
|
# Adds alternative names to the certificate. Useful when serving media on another domain. Comma or space separated list.
|
||||||
|
# alternative names { }
|
||||||
|
|
||||||
|
domain key "/etc/ssl/private/example.tld.key"
|
||||||
|
domain certificate "/etc/ssl/example.tld_cert-only.crt"
|
||||||
|
domain full chain certificate "/etc/ssl/example.tld.crt"
|
||||||
|
sign with letsencrypt
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Check the configuration:
|
||||||
|
|
||||||
|
```
|
||||||
|
# acme-client -n
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuring the Web server
|
||||||
|
|
||||||
|
Pleroma supports two Web servers:
|
||||||
|
|
||||||
|
* nginx (recommended for most users)
|
||||||
|
* OpenBSD's httpd and relayd (ONLY for advanced users, media proxy cache is NOT supported and will NOT work properly)
|
||||||
|
|
||||||
|
#### nginx
|
||||||
|
|
||||||
|
Since nginx is not installed by default, install it by running:
|
||||||
|
|
||||||
|
```
|
||||||
|
# pkg_add nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
Add the following to `/etc/nginx/nginx.conf`, within the `server {}` block listening on port 80 and change `server_name`, as follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
http {
|
||||||
|
...
|
||||||
|
|
||||||
|
server {
|
||||||
|
...
|
||||||
|
server_name localhost; # Replace with your domain
|
||||||
|
|
||||||
|
location /.well-known/acme-challenge {
|
||||||
|
rewrite ^/\.well-known/acme-challenge/(.*) /$1 break;
|
||||||
|
root /var/www/acme;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Start the nginx service and acquire certificates:
|
||||||
|
|
||||||
|
```
|
||||||
|
# rcctl start nginx
|
||||||
|
# acme-client example.tld
|
||||||
|
```
|
||||||
|
|
||||||
|
Add certificate auto-renewal by adding acme-client to `/etc/weekly.local`, replace `example.tld` with your domain:
|
||||||
|
|
||||||
|
```
|
||||||
|
# echo "acme-client example.tld && rcctl reload nginx" >> /etc/weekly.local
|
||||||
|
```
|
||||||
|
|
||||||
|
OpenBSD's default nginx configuration does not contain an include directive, which is typically used for multiple sites.
|
||||||
|
Therefore, you will need to first create the required directory as follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
# mkdir /etc/nginx/sites-available
|
||||||
|
# mkdir /etc/nginx/sites-enabled
|
||||||
|
```
|
||||||
|
|
||||||
|
Next add the `include` directive to `/etc/nginx/nginx.conf`, within the `http {}` block, as follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
http {
|
||||||
|
...
|
||||||
|
|
||||||
|
server {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
include /etc/nginx/sites-enabled/*;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
As root, copy `/home/_pleroma/pleroma/installation/pleroma.nginx` to `/etc/nginx/sites-available/pleroma.nginx`.
|
||||||
|
|
||||||
|
Edit default `/etc/nginx/sites-available/pleroma.nginx` settings and replace `example.tld` with your domain:
|
||||||
|
|
||||||
|
* Uncomment the location block for `~ /\.well-known/acme-challenge` in the server block listening on port 80
|
||||||
|
- add `rewrite ^/\.well-known/acme-challenge/(.*) /$1 break;` above the `root` location
|
||||||
|
- change the `root` location to `/var/www/acme;`
|
||||||
|
* Change `ssl_trusted_certificate` to `/etc/ssl/example.tld_cert-only.crt`
|
||||||
|
* Change `ssl_certificate` to `/etc/ssl/example.tld.crt`
|
||||||
|
* Change `ssl_certificate_key` to `/etc/ssl/private/example.tld.key`
|
||||||
|
|
||||||
|
Remove the following `location {}` block from `/etc/nginx/nginx.conf`, that was previously added for acquiring certificates and change `server_name` back to `localhost`:
|
||||||
|
|
||||||
|
```
|
||||||
|
http {
|
||||||
|
...
|
||||||
|
|
||||||
|
server {
|
||||||
|
...
|
||||||
|
server_name example.tld; # Change back to localhost
|
||||||
|
|
||||||
|
# Delete this block
|
||||||
|
location /.well-known/acme-challenge {
|
||||||
|
rewrite ^/\.well-known/acme-challenge/(.*) /$1 break;
|
||||||
|
root /var/www/acme;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Symlink the Pleroma configuration to the enabled sites:
|
||||||
|
|
||||||
|
```
|
||||||
|
# ln -s /etc/nginx/sites-available/pleroma.nginx /etc/nginx/sites-enabled
|
||||||
|
```
|
||||||
|
|
||||||
|
Check nginx configuration syntax by running:
|
||||||
|
|
||||||
|
```
|
||||||
|
# nginx -t
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: If the above command complains about a `conflicting server name`, check again that the `location {}` block for acquiring certificates has been removed from `/etc/nginx/nginx.conf` and that the `server_name` has been reverted back to `localhost`.
|
||||||
|
After doing so run `# nginx -t` again.
|
||||||
|
|
||||||
|
If the configuration is correct, you can now enable and reload the nginx service:
|
||||||
|
|
||||||
|
```
|
||||||
|
# rcctl enable nginx
|
||||||
|
# rcctl reload nginx
|
||||||
```
|
```
|
||||||
To check that it started properly and didn't fail right after starting, you can run `ps aux | grep postgres`, there should be multiple lines of output.
|
|
||||||
|
|
||||||
#### httpd
|
#### httpd
|
||||||
httpd will have three functions:
|
|
||||||
|
***Skip this section when using nginx***
|
||||||
|
|
||||||
|
httpd will have two functions:
|
||||||
|
|
||||||
* redirect requests trying to reach the instance over http to the https URL
|
* redirect requests trying to reach the instance over http to the https URL
|
||||||
* serve a robots.txt file
|
|
||||||
* get Let's Encrypt certificates, with acme-client
|
* get Let's Encrypt certificates, with acme-client
|
||||||
|
|
||||||
Insert the following config in httpd.conf:
|
As root, copy `/home/_pleroma/pleroma/installation/openbsd/httpd.conf` to `/etc/httpd.conf`, or modify the existing one.
|
||||||
|
|
||||||
|
Edit `/etc/httpd.conf` settings and change:
|
||||||
|
|
||||||
|
* `<ipaddr>` with your instance's IPv4 address
|
||||||
|
* All occurrences of `example.tld` with your instance's domain name
|
||||||
|
* When using IPv6 also change:
|
||||||
|
- Uncomment the `ext_inet6="<ip6addr>"` line near the beginning of the file and change `<ip6addr` to your instance's IPv6 address
|
||||||
|
- Uncomment the line starting with `listen on $ext_inet6` in the `server` block
|
||||||
|
|
||||||
|
Check the configuration by running:
|
||||||
```
|
```
|
||||||
# $OpenBSD: httpd.conf,v 1.17 2017/04/16 08:50:49 ajacoutot Exp $
|
# httpd -n
|
||||||
|
|
||||||
ext_inet="<IPv4 address>"
|
|
||||||
ext_inet6="<IPv6 address>"
|
|
||||||
|
|
||||||
server "default" {
|
|
||||||
listen on $ext_inet port 80 # Comment to disable listening on IPv4
|
|
||||||
listen on $ext_inet6 port 80 # Comment to disable listening on IPv6
|
|
||||||
listen on 127.0.0.1 port 80 # Do NOT comment this line
|
|
||||||
|
|
||||||
log syslog
|
|
||||||
directory no index
|
|
||||||
|
|
||||||
location "/.well-known/acme-challenge/*" {
|
|
||||||
root "/acme"
|
|
||||||
request strip 2
|
|
||||||
}
|
|
||||||
|
|
||||||
location "/robots.txt" { root "/htdocs/local/" }
|
|
||||||
location "/*" { block return 302 "https://$HTTP_HOST$REQUEST_URI" }
|
|
||||||
}
|
|
||||||
|
|
||||||
types {
|
|
||||||
}
|
|
||||||
```
|
|
||||||
Do not forget to change *<IPv4/6 address\>* to your server's address(es). If httpd should only listen on one protocol family, comment one of the two first *listen* options.
|
|
||||||
|
|
||||||
Create the /var/www/htdocs/local/ folder and write the content of your robots.txt in /var/www/htdocs/local/robots.txt.
|
|
||||||
Check the configuration with `httpd -n`, if it is OK enable and start httpd (as root):
|
|
||||||
```
|
|
||||||
rcctl enable httpd
|
|
||||||
rcctl start httpd
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### acme-client
|
If the configuration is correct, enable and start the `httpd` service:
|
||||||
acme-client is used to get SSL/TLS certificates from Let's Encrypt.
|
|
||||||
Insert the following configuration in /etc/acme-client.conf:
|
|
||||||
```
|
|
||||||
#
|
|
||||||
# $OpenBSD: acme-client.conf,v 1.4 2017/03/22 11:14:14 benno Exp $
|
|
||||||
#
|
|
||||||
|
|
||||||
authority letsencrypt-<domain name> {
|
```
|
||||||
#agreement url "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf"
|
# rcctl enable httpd
|
||||||
api url "https://acme-v02.api.letsencrypt.org/directory"
|
# rcctl start httpd
|
||||||
account key "/etc/acme/letsencrypt-privkey-<domain name>.pem"
|
```
|
||||||
}
|
|
||||||
|
|
||||||
domain <domain name> {
|
Acquire certificate:
|
||||||
domain key "/etc/ssl/private/<domain name>.key"
|
|
||||||
domain certificate "/etc/ssl/<domain name>.crt"
|
|
||||||
domain full chain certificate "/etc/ssl/<domain name>.fullchain.pem"
|
|
||||||
sign with letsencrypt-<domain name>
|
|
||||||
challengedir "/var/www/acme/"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
Replace *<domain name\>* by the domain name you'll use for your instance. As root, run `acme-client -n` to check the config, then `acme-client -ADv <domain name>` to create account and domain keys, and request a certificate for the first time.
|
|
||||||
Make acme-client run everyday by adding it in /etc/daily.local. As root, run the following command: `echo "acme-client <domain name>" >> /etc/daily.local`.
|
|
||||||
|
|
||||||
Relayd will look for certificates and keys based on the address it listens on (see next part), the easiest way to make them available to relayd is to create a link, as root run:
|
|
||||||
```
|
```
|
||||||
ln -s /etc/ssl/<domain name>.fullchain.pem /etc/ssl/<IP address>.crt
|
# acme-client example.tld
|
||||||
ln -s /etc/ssl/private/<domain name>.key /etc/ssl/private/<IP address>.key
|
|
||||||
```
|
```
|
||||||
This will have to be done for each IPv4 and IPv6 address relayd listens on.
|
|
||||||
|
|
||||||
#### relayd
|
#### relayd
|
||||||
|
|
||||||
|
***Skip this section when using nginx***
|
||||||
|
|
||||||
relayd will be used as the reverse proxy sitting in front of pleroma.
|
relayd will be used as the reverse proxy sitting in front of pleroma.
|
||||||
Insert the following configuration in /etc/relayd.conf:
|
|
||||||
|
As root, copy `/home/_pleroma/pleroma/installation/openbsd/relayd.conf` to `/etc/relayd.conf`, or modify the existing one.
|
||||||
|
|
||||||
|
Edit `/etc/relayd.conf` settings and change:
|
||||||
|
|
||||||
|
* `<ipaddr>` with your instance's IPv4 address
|
||||||
|
* All occurrences of `example.tld` with your instance's domain name
|
||||||
|
* When using IPv6 also change:
|
||||||
|
- Uncomment the `ext_inet6="<ip6addr>"` line near the beginning of the file and change `<ip6addr>` to your instance's IPv6 address
|
||||||
|
- Uncomment the line starting with `listen on $ext_inet6` in the `relay wwwtls` block
|
||||||
|
|
||||||
|
Check the configuration by running:
|
||||||
```
|
```
|
||||||
# $OpenBSD: relayd.conf,v 1.4 2018/03/23 09:55:06 claudio Exp $
|
# relayd -n
|
||||||
|
|
||||||
ext_inet="<IPv4 address>"
|
|
||||||
ext_inet6="<IPv6 address>"
|
|
||||||
|
|
||||||
table <pleroma_server> { 127.0.0.1 }
|
|
||||||
table <httpd_server> { 127.0.0.1 }
|
|
||||||
|
|
||||||
http protocol plerup { # Protocol for upstream pleroma server
|
|
||||||
#tcp { nodelay, sack, socket buffer 65536, backlog 128 } # Uncomment and adjust as you see fit
|
|
||||||
tls ciphers "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305"
|
|
||||||
tls ecdhe secp384r1
|
|
||||||
|
|
||||||
# Forward some paths to the local server (as pleroma won't respond to them as you might want)
|
|
||||||
pass request quick path "/robots.txt" forward to <httpd_server>
|
|
||||||
|
|
||||||
# Append a bunch of headers
|
|
||||||
match request header append "X-Forwarded-For" value "$REMOTE_ADDR" # This two header and the next one are not strictly required by pleroma but adding them won't hurt
|
|
||||||
match request header append "X-Forwarded-By" value "$SERVER_ADDR:$SERVER_PORT"
|
|
||||||
|
|
||||||
match response header append "X-XSS-Protection" value "1; mode=block"
|
|
||||||
match response header append "X-Permitted-Cross-Domain-Policies" value "none"
|
|
||||||
match response header append "X-Frame-Options" value "DENY"
|
|
||||||
match response header append "X-Content-Type-Options" value "nosniff"
|
|
||||||
match response header append "Referrer-Policy" value "same-origin"
|
|
||||||
match response header append "X-Download-Options" value "noopen"
|
|
||||||
match response header append "Content-Security-Policy" value "default-src 'none'; base-uri 'self'; form-action 'self'; img-src 'self' data: https:; media-src 'self' https:; style-src 'self' 'unsafe-inline'; font-src 'self'; script-src 'self'; connect-src 'self' wss://CHANGEME.tld; upgrade-insecure-requests;" # Modify "CHANGEME.tld" and set your instance's domain here
|
|
||||||
match request header append "Connection" value "upgrade"
|
|
||||||
#match response header append "Strict-Transport-Security" value "max-age=31536000; includeSubDomains" # Uncomment this only after you get HTTPS working.
|
|
||||||
|
|
||||||
# If you do not want remote frontends to be able to access your Pleroma backend server, comment these lines
|
|
||||||
match response header append "Access-Control-Allow-Origin" value "*"
|
|
||||||
match response header append "Access-Control-Allow-Methods" value "POST, PUT, DELETE, GET, PATCH, OPTIONS"
|
|
||||||
match response header append "Access-Control-Allow-Headers" value "Authorization, Content-Type, Idempotency-Key"
|
|
||||||
match response header append "Access-Control-Expose-Headers" value "Link, X-RateLimit-Reset, X-RateLimit-Limit, X-RateLimit-Remaining, X-Request-Id"
|
|
||||||
# Stop commenting lines here
|
|
||||||
}
|
|
||||||
|
|
||||||
relay wwwtls {
|
|
||||||
listen on $ext_inet port https tls # Comment to disable listening on IPv4
|
|
||||||
listen on $ext_inet6 port https tls # Comment to disable listening on IPv6
|
|
||||||
|
|
||||||
protocol plerup
|
|
||||||
|
|
||||||
forward to <pleroma_server> port 4000 check http "/" code 200
|
|
||||||
forward to <httpd_server> port 80 check http "/robots.txt" code 200
|
|
||||||
}
|
|
||||||
```
|
|
||||||
Again, change *<IPv4/6 address\>* to your server's address(es) and comment one of the two *listen* options if needed. Also change *wss://CHANGEME.tld* to *wss://<your instance's domain name\>*.
|
|
||||||
Check the configuration with `relayd -n`, if it is OK enable and start relayd (as root):
|
|
||||||
```
|
|
||||||
rcctl enable relayd
|
|
||||||
rcctl start relayd
|
|
||||||
```
|
```
|
||||||
|
|
||||||
##### (Strongly recommended) serve media on another domain
|
If the configuration is correct, enable and start the `relayd` service:
|
||||||
|
|
||||||
|
```
|
||||||
|
# rcctl enable relayd
|
||||||
|
# rcctl start relayd
|
||||||
|
```
|
||||||
|
|
||||||
|
Add certificate auto-renewal by adding acme-client to `/etc/weekly.local`, replace `example.tld` with your domain:
|
||||||
|
|
||||||
|
```
|
||||||
|
# echo "acme-client example.tld && rcctl reload relayd" >> /etc/weekly.local
|
||||||
|
```
|
||||||
|
|
||||||
|
#### (Strongly recommended) serve media on another domain
|
||||||
|
|
||||||
Refer to the [Hardening your instance](../configuration/hardening.md) document on how to serve media on another domain. We STRONGLY RECOMMEND you to do this to minimize attack vectors.
|
Refer to the [Hardening your instance](../configuration/hardening.md) document on how to serve media on another domain. We STRONGLY RECOMMEND you to do this to minimize attack vectors.
|
||||||
|
|
||||||
#### pf
|
### Starting pleroma at boot
|
||||||
Enabling and configuring pf is highly recommended.
|
|
||||||
In /etc/pf.conf, insert the following configuration:
|
Copy the startup script and make sure it's executable:
|
||||||
|
|
||||||
```
|
```
|
||||||
# Macros
|
# cp /home/_pleroma/pleroma/installation/openbsd/rc.d/pleroma /etc/rc.d/pleroma
|
||||||
if="<network interface>"
|
# chmod 555 /etc/rc.d/pleroma
|
||||||
authorized_ssh_clients="any"
|
|
||||||
|
|
||||||
# Skip traffic on loopback interface
|
|
||||||
set skip on lo
|
|
||||||
|
|
||||||
# Default behavior
|
|
||||||
set block-policy drop
|
|
||||||
block in log all
|
|
||||||
pass out quick
|
|
||||||
|
|
||||||
# Security features
|
|
||||||
match in all scrub (no-df random-id)
|
|
||||||
block in log from urpf-failed
|
|
||||||
|
|
||||||
# Rules
|
|
||||||
pass in quick on $if inet proto icmp to ($if) icmp-type { echoreq unreach paramprob trace } # ICMP
|
|
||||||
pass in quick on $if inet6 proto icmp6 to ($if) icmp6-type { echoreq unreach paramprob timex toobig } # ICMPv6
|
|
||||||
pass in quick on $if proto tcp to ($if) port { http https } # relayd/httpd
|
|
||||||
pass in quick on $if proto tcp from $authorized_ssh_clients to ($if) port ssh
|
|
||||||
```
|
|
||||||
Replace *<network interface\>* by your server's network interface name (which you can get with ifconfig). Consider replacing the content of the authorized\_ssh\_clients macro by, for example, your home IP address, to avoid SSH connection attempts from bots.
|
|
||||||
|
|
||||||
Check pf's configuration by running `pfctl -nf /etc/pf.conf`, load it with `pfctl -f /etc/pf.conf` and enable pf at boot with `rcctl enable pf`.
|
|
||||||
|
|
||||||
#### Configure and start pleroma
|
|
||||||
Enter a shell as \_pleroma (as root `su _pleroma -`) and enter pleroma's installation directory (`cd ~/pleroma/`).
|
|
||||||
|
|
||||||
Then follow the main installation guide:
|
|
||||||
|
|
||||||
* run `mix deps.get`
|
|
||||||
* run `MIX_ENV=prod mix pleroma.instance gen` and enter your instance's information when asked
|
|
||||||
* copy config/generated\_config.exs to config/prod.secret.exs. The default values should be sufficient but you should edit it and check that everything seems OK.
|
|
||||||
* exit your current shell back to a root one and run `psql -U postgres -f /home/_pleroma/pleroma/config/setup_db.psql` to setup the database.
|
|
||||||
* return to a \_pleroma shell into pleroma's installation directory (`su _pleroma -;cd ~/pleroma`) and run `MIX_ENV=prod mix ecto.migrate`
|
|
||||||
|
|
||||||
As \_pleroma in /home/\_pleroma/pleroma, you can now run `LC_ALL=en_US.UTF-8 MIX_ENV=prod mix phx.server` to start your instance.
|
|
||||||
In another SSH session/tmux window, check that it is working properly by running `ftp -MVo - http://127.0.0.1:4000/api/v1/instance`, you should get json output. Double-check that *uri*'s value is your instance's domain name.
|
|
||||||
|
|
||||||
##### Starting pleroma at boot
|
|
||||||
An rc script to automatically start pleroma at boot hasn't been written yet, it can be run in a tmux session (tmux is in base).
|
|
||||||
|
|
||||||
|
|
||||||
#### Create administrative user
|
|
||||||
|
|
||||||
If your instance is up and running, you can create your first user with administrative rights with the following command as the \_pleroma user.
|
|
||||||
```
|
|
||||||
LC_ALL=en_US.UTF-8 MIX_ENV=prod mix pleroma.user new <username> <your@emailaddress> --admin
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Further reading
|
Enable and start the pleroma service:
|
||||||
|
|
||||||
|
```
|
||||||
|
# rcctl enable pleroma
|
||||||
|
# rcctl start pleroma
|
||||||
|
```
|
||||||
|
|
||||||
|
### Create administrative user
|
||||||
|
|
||||||
|
If your instance is up and running, you can create your first user with administrative rights with the following commands as the \_pleroma user:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cd pleroma
|
||||||
|
$ MIX_ENV=prod mix pleroma.user new <username> <your@emailaddress> --admin
|
||||||
|
```
|
||||||
|
|
||||||
|
### Further reading
|
||||||
|
|
||||||
{! backend/installation/further_reading.include !}
|
{! backend/installation/further_reading.include !}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Note: This article is potentially outdated because at this time we may not have
|
||||||
|
|
||||||
Tarvitset:
|
Tarvitset:
|
||||||
* Oman domainin
|
* Oman domainin
|
||||||
* OpenBSD 6.3 -serverin
|
* OpenBSD 7.5 -serverin
|
||||||
* Auttavan ymmärryksen unix-järjestelmistä
|
* Auttavan ymmärryksen unix-järjestelmistä
|
||||||
|
|
||||||
Komennot, joiden edessä on '#', tulee ajaa käyttäjänä `root`. Tämä on
|
Komennot, joiden edessä on '#', tulee ajaa käyttäjänä `root`. Tämä on
|
||||||
|
|
@ -18,7 +18,7 @@ Matrix-kanava #pleroma:libera.chat ovat hyviä paikkoja löytää apua
|
||||||
|
|
||||||
Asenna tarvittava ohjelmisto:
|
Asenna tarvittava ohjelmisto:
|
||||||
|
|
||||||
`# pkg_add git elixir gmake postgresql-server-10.3 postgresql-contrib-10.3 cmake ffmpeg ImageMagick libvips`
|
`# pkg_add git elixir gmake postgresql-server postgresql-contrib cmake libmagic libvips`
|
||||||
|
|
||||||
#### Optional software
|
#### Optional software
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,20 +2,21 @@
|
||||||
# Default httpd.conf file for Pleroma on OpenBSD
|
# Default httpd.conf file for Pleroma on OpenBSD
|
||||||
# Simple installation instructions
|
# Simple installation instructions
|
||||||
# 1. Place file in /etc
|
# 1. Place file in /etc
|
||||||
# 2. Replace <IPv4 address> with your public IP address
|
# 2. Replace <ipaddr> with your public IP address
|
||||||
# 3. If using IPv6, uncomment IPv6 lines and replace <IPv6 address> with your public IPv6 address
|
# 3. If using IPv6, uncomment IPv6 lines and replace <ip6addr> with your public IPv6 address
|
||||||
# 4. Check file using 'doas httpd -n'
|
# 4. Replace all occurences of example.tld with your instance's domain name.
|
||||||
# 5. Enable and start httpd:
|
# 5. Check file using 'doas httpd -n'
|
||||||
|
# 6. Enable and start httpd:
|
||||||
# # doas rcctl enable httpd
|
# # doas rcctl enable httpd
|
||||||
# # doas rcctl start httpd
|
# # doas rcctl start httpd
|
||||||
#
|
#
|
||||||
|
|
||||||
ext_inet="<IPv4 address>"
|
ext_inet="<ipaddr>"
|
||||||
#ext_inet6="<IPv6 address>"
|
#ext_inet6="<ip6addr>"
|
||||||
|
|
||||||
server "default" {
|
server "example.tld" {
|
||||||
listen on $ext_inet port 80 # Comment to disable listening on IPv4
|
listen on $ext_inet port 80 # Comment to disable listening on IPv4
|
||||||
# listen on $ext_inet6 port 80 # Comment to disable listening on IPv6
|
#listen on $ext_inet6 port 80 # Comment to disable listening on IPv6
|
||||||
listen on 127.0.0.1 port 80 # Do NOT comment this line
|
listen on 127.0.0.1 port 80 # Do NOT comment this line
|
||||||
|
|
||||||
log syslog
|
log syslog
|
||||||
|
|
@ -26,10 +27,18 @@ server "default" {
|
||||||
request strip 2
|
request strip 2
|
||||||
}
|
}
|
||||||
|
|
||||||
location "/robots.txt" { root "/htdocs/local/" }
|
location "/*" { block return 301 "https://$HTTP_HOST$REQUEST_URI" }
|
||||||
location "/*" { block return 302 "https://$HTTP_HOST$REQUEST_URI" }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Example of serving a basic static website besides Pleroma using the example configuration in relayd
|
||||||
|
#server "site.example.tld" {
|
||||||
|
# listen on 127.0.0.1 port 8080
|
||||||
|
#
|
||||||
|
# location "/*" {
|
||||||
|
# root "/website"
|
||||||
|
# }
|
||||||
|
#}
|
||||||
|
|
||||||
types {
|
types {
|
||||||
include "/usr/share/misc/mime.types"
|
include "/usr/share/misc/mime.types"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,16 @@
|
||||||
#
|
#
|
||||||
# Simple installation instructions:
|
# Simple installation instructions:
|
||||||
# 1. Install Pleroma per wiki instructions
|
# 1. Install Pleroma per wiki instructions
|
||||||
# 2. Place this pleromad file in /etc/rc.d
|
# 2. Place this pleroma file in /etc/rc.d
|
||||||
# 3. Enable and start Pleroma
|
# 3. Enable and start Pleroma
|
||||||
# # doas rcctl enable pleromad
|
# # doas rcctl enable pleroma
|
||||||
# # doas rcctl start pleromad
|
# # doas rcctl start pleroma
|
||||||
#
|
#
|
||||||
|
|
||||||
daemon="/usr/local/bin/elixir"
|
daemon="/usr/local/bin/elixir"
|
||||||
daemon_flags="--detached -S /usr/local/bin/mix phx.server"
|
daemon_flags="--erl \"-detached\" -S /usr/local/bin/mix phx.server"
|
||||||
daemon_user="_pleroma"
|
daemon_user="_pleroma"
|
||||||
|
daemon_execdir="/home/_pleroma/pleroma"
|
||||||
|
|
||||||
. /etc/rc.d/rc.subr
|
. /etc/rc.d/rc.subr
|
||||||
|
|
||||||
|
|
@ -23,10 +24,6 @@ rc_check() {
|
||||||
pgrep -q -U _pleroma -f "phx.server"
|
pgrep -q -U _pleroma -f "phx.server"
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_start() {
|
|
||||||
${rcexec} "cd pleroma; ${daemon} ${daemon_flags}"
|
|
||||||
}
|
|
||||||
|
|
||||||
rc_stop() {
|
rc_stop() {
|
||||||
pkill -q -U _pleroma -f "phx.server"
|
pkill -q -U _pleroma -f "phx.server"
|
||||||
}
|
}
|
||||||
|
|
@ -3,9 +3,10 @@
|
||||||
# Simple installation instructions:
|
# Simple installation instructions:
|
||||||
# 1. Place in /etc
|
# 1. Place in /etc
|
||||||
# 2. Replace <ipaddr> with your public IPv4 address
|
# 2. Replace <ipaddr> with your public IPv4 address
|
||||||
# 3. If using IPv6i, uncomment IPv6 lines and replace <ip6addr> with your public IPv6 address
|
# 3. If using IPv6, uncomment IPv6 lines and replace <ip6addr> with your public IPv6 address
|
||||||
# 4. Check file using 'doas relayd -n'
|
# 4. Replace all occurrences of example.tld with your instance's domain
|
||||||
# 5. Reload/start relayd
|
# 5. Check file using 'doas relayd -n'
|
||||||
|
# 6. Reload/start relayd
|
||||||
# # doas rcctl enable relayd
|
# # doas rcctl enable relayd
|
||||||
# # doas rcctl start relayd
|
# # doas rcctl start relayd
|
||||||
#
|
#
|
||||||
|
|
@ -14,31 +15,54 @@ ext_inet="<ipaddr>"
|
||||||
#ext_inet6="<ip6addr>"
|
#ext_inet6="<ip6addr>"
|
||||||
|
|
||||||
table <pleroma_server> { 127.0.0.1 }
|
table <pleroma_server> { 127.0.0.1 }
|
||||||
table <httpd_server> { 127.0.0.1 }
|
|
||||||
|
|
||||||
http protocol plerup { # Protocol for upstream pleroma server
|
# Uncomment when you want to serve other services than Pleroma.
|
||||||
|
# In this example tables are used only as way to differentiate between Pleroma and other services.
|
||||||
|
# Feel free to rename "httpd_server" everywhere to fit your setup.
|
||||||
|
#table <httpd_server> { 127.0.0.1 }
|
||||||
|
|
||||||
|
http protocol pleroma { # Protocol for upstream Pleroma server
|
||||||
#tcp { nodelay, sack, socket buffer 65536, backlog 128 } # Uncomment and adjust as you see fit
|
#tcp { nodelay, sack, socket buffer 65536, backlog 128 } # Uncomment and adjust as you see fit
|
||||||
tls ciphers "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA0-POLY1305"
|
tls ciphers "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"
|
||||||
tls ecdhe secp384r1
|
tls ecdhe "X25519,P-256,P-384,secp521r1" # relayd default+secp521r1
|
||||||
|
|
||||||
# Forward some paths to the local server (as pleroma won't respond to them as you might want)
|
return error
|
||||||
pass request quick path "/robots.txt" forward to <httpd_server>
|
|
||||||
|
|
||||||
# Append a bunch of headers
|
# When serving multiple services with different certificates, specify multiple "tls keypair" keywords
|
||||||
match request header append "X-Forwarded-For" value "$REMOTE_ADDR" # This two header and the next one are not strictl required by pleroma but adding them won't hurt
|
# and add forwards to those services before the block keyword near the bottom of the protocol and relay configurations.
|
||||||
match request header append "X-Forwarded-By" value "$SERVER_ADDR:$SERVER_PORT"
|
# The string in quotes must match the fullchain certificate file created by acme-client without the extension.
|
||||||
|
# For example:
|
||||||
|
# tls keypair "pleroma.example.tld"
|
||||||
|
# tls keypair "example.tld"
|
||||||
|
tls keypair "example.tld"
|
||||||
|
|
||||||
|
match request header append "X-Forwarded-For" value "$REMOTE_ADDR"
|
||||||
match request header append "Connection" value "upgrade"
|
match request header append "Connection" value "upgrade"
|
||||||
|
|
||||||
|
# When hosting Pleroma on a subdomain, replace example.tld accordingly (not the base domain).
|
||||||
|
# From the above example, "example.tld" should be replaced with "pleroma.example.tld" instead.
|
||||||
|
pass request quick header "Host" value "example.tld" forward to <pleroma_server>
|
||||||
|
|
||||||
|
# Uncomment when serving media uploads on a different (sub)domain.
|
||||||
|
# Keep media proxy disabled, as it will NOT work under relayd/httpd. If you want to also setup media proxy, use nginx instead.
|
||||||
|
#pass request quick header "Host" value "media.example.tld" forward to <pleroma_server>
|
||||||
|
|
||||||
|
# When serving multiple services, add the forwards here.
|
||||||
|
# Example:
|
||||||
|
#pass request quick header "Host" value "example.tld" forward to <httpd_server>
|
||||||
|
|
||||||
|
block
|
||||||
}
|
}
|
||||||
|
|
||||||
relay wwwtls {
|
relay wwwtls {
|
||||||
listen on $ext_inet port https tls # Comment to disable listening on IPv4
|
listen on $ext_inet port https tls # Comment to disable listening on IPv4
|
||||||
# listen on $ext_inet6 port https tls # Comment to disable listening on IPv6
|
#listen on $ext_inet6 port https tls # Comment to disable listening on IPv6
|
||||||
|
|
||||||
protocol plerup
|
protocol pleroma
|
||||||
|
|
||||||
forward to <pleroma_server> port 4000 check http "/" code 200
|
forward to <pleroma_server> port 4000 check tcp timeout 500 # Adjust timeout accordingly when relayd returns 502 while Pleroma is running without problems.
|
||||||
forward to <httpd_server> port 80 check http "/robots.txt" code 200
|
|
||||||
|
# When serving multiple services, add the forwards here.
|
||||||
|
# Example:
|
||||||
|
#forward to <httpd_server> port 8080
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@ defmodule Mix.Tasks.Pleroma.TestRunner do
|
||||||
use Mix.Task
|
use Mix.Task
|
||||||
|
|
||||||
def run(args \\ []) do
|
def run(args \\ []) do
|
||||||
case System.cmd("mix", ["test"] ++ args, into: IO.stream(:stdio, :line)) do
|
case System.cmd("mix", ["test", "--warnings-as-errors"] ++ args,
|
||||||
|
into: IO.stream(:stdio, :line)
|
||||||
|
) do
|
||||||
{_, 0} ->
|
{_, 0} ->
|
||||||
:ok
|
:ok
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,9 +43,6 @@ defmodule Pleroma.Application do
|
||||||
# every time the application is restarted, so we disable module
|
# every time the application is restarted, so we disable module
|
||||||
# conflicts at runtime
|
# conflicts at runtime
|
||||||
Code.compiler_options(ignore_module_conflict: true)
|
Code.compiler_options(ignore_module_conflict: true)
|
||||||
# Disable warnings_as_errors at runtime, it breaks Phoenix live reload
|
|
||||||
# due to protocol consolidation warnings
|
|
||||||
Code.compiler_options(warnings_as_errors: false)
|
|
||||||
Pleroma.Telemetry.Logger.attach()
|
Pleroma.Telemetry.Logger.attach()
|
||||||
Config.Holder.save_default()
|
Config.Holder.save_default()
|
||||||
Pleroma.HTML.compile_scrubbers()
|
Pleroma.HTML.compile_scrubbers()
|
||||||
|
|
@ -71,26 +68,11 @@ defmodule Pleroma.Application do
|
||||||
Finch.start_link(name: MyFinch)
|
Finch.start_link(name: MyFinch)
|
||||||
end
|
end
|
||||||
|
|
||||||
if adapter == Tesla.Adapter.Gun do
|
# Disable warnings_as_errors at runtime, it breaks Phoenix live reload
|
||||||
if version = Pleroma.OTPVersion.version() do
|
# due to protocol consolidation warnings
|
||||||
[major, minor] =
|
# :warnings_as_errors is deprecated via Code.compiler_options/2 since 1.18
|
||||||
version
|
if Version.compare(System.version(), "1.18.0") == :lt do
|
||||||
|> String.split(".")
|
Code.compiler_options(warnings_as_errors: false)
|
||||||
|> Enum.map(&String.to_integer/1)
|
|
||||||
|> Enum.take(2)
|
|
||||||
|
|
||||||
if (major == 22 and minor < 2) or major < 22 do
|
|
||||||
raise "
|
|
||||||
!!!OTP VERSION WARNING!!!
|
|
||||||
You are using gun adapter with OTP version #{version}, which doesn't support correct handling of unordered certificates chains. Please update your Erlang/OTP to at least 22.2.
|
|
||||||
"
|
|
||||||
end
|
|
||||||
else
|
|
||||||
raise "
|
|
||||||
!!!OTP VERSION WARNING!!!
|
|
||||||
To support correct handling of unordered certificates chains - OTP version must be > 22.2.
|
|
||||||
"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Define workers and child supervisors to be supervised
|
# Define workers and child supervisors to be supervised
|
||||||
|
|
|
||||||
|
|
@ -302,7 +302,7 @@ defmodule Pleroma.ConfigDB do
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_elixir_types(%{"tuple" => entity}) do
|
def to_elixir_types(%{"tuple" => entity}) do
|
||||||
Enum.reduce(entity, {}, &Tuple.append(&2, to_elixir_types(&1)))
|
Enum.reduce(entity, {}, &Tuple.insert_at(&2, tuple_size(&2), to_elixir_types(&1)))
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_elixir_types(entity) when is_map(entity) do
|
def to_elixir_types(entity) when is_map(entity) do
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ defmodule Pleroma.Language.LanguageDetector do
|
||||||
def configured? do
|
def configured? do
|
||||||
provider = get_provider()
|
provider = get_provider()
|
||||||
|
|
||||||
!!provider and provider.configured?
|
!!provider and provider.configured?()
|
||||||
end
|
end
|
||||||
|
|
||||||
def missing_dependencies do
|
def missing_dependencies do
|
||||||
|
|
@ -41,7 +41,7 @@ defmodule Pleroma.Language.LanguageDetector do
|
||||||
text = prepare_text(text)
|
text = prepare_text(text)
|
||||||
word_count = text |> String.split(~r/\s+/) |> Enum.count()
|
word_count = text |> String.split(~r/\s+/) |> Enum.count()
|
||||||
|
|
||||||
if word_count < @words_threshold or !provider or !provider.configured? do
|
if word_count < @words_threshold or !provider or !provider.configured?() do
|
||||||
nil
|
nil
|
||||||
else
|
else
|
||||||
with language <- provider.detect(text),
|
with language <- provider.detect(text),
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ defmodule Pleroma.Language.Translation do
|
||||||
def configured? do
|
def configured? do
|
||||||
provider = get_provider()
|
provider = get_provider()
|
||||||
|
|
||||||
!!provider and provider.configured?
|
!!provider and provider.configured?()
|
||||||
end
|
end
|
||||||
|
|
||||||
def missing_dependencies do
|
def missing_dependencies do
|
||||||
|
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
defmodule Pleroma.OTPVersion do
|
|
||||||
@spec version() :: String.t() | nil
|
|
||||||
def version do
|
|
||||||
# OTP Version https://erlang.org/doc/system_principles/versions.html#otp-version
|
|
||||||
[
|
|
||||||
Path.join(:code.root_dir(), "OTP_VERSION"),
|
|
||||||
Path.join([:code.root_dir(), "releases", :erlang.system_info(:otp_release), "OTP_VERSION"])
|
|
||||||
]
|
|
||||||
|> get_version_from_files()
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec get_version_from_files([Path.t()]) :: String.t() | nil
|
|
||||||
def get_version_from_files([]), do: nil
|
|
||||||
|
|
||||||
def get_version_from_files([path | paths]) do
|
|
||||||
if File.exists?(path) do
|
|
||||||
path
|
|
||||||
|> File.read!()
|
|
||||||
|> String.replace(~r/\r|\n|\s/, "")
|
|
||||||
else
|
|
||||||
get_version_from_files(paths)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -308,7 +308,7 @@ defmodule Pleroma.User do
|
||||||
|
|
||||||
def binary_id(%User{} = user), do: binary_id(user.id)
|
def binary_id(%User{} = user), do: binary_id(user.id)
|
||||||
|
|
||||||
@doc "Returns status account"
|
@doc "Returns account status"
|
||||||
@spec account_status(User.t()) :: account_status()
|
@spec account_status(User.t()) :: account_status()
|
||||||
def account_status(%User{is_active: false}), do: :deactivated
|
def account_status(%User{is_active: false}), do: :deactivated
|
||||||
def account_status(%User{password_reset_pending: true}), do: :password_reset_pending
|
def account_status(%User{password_reset_pending: true}), do: :password_reset_pending
|
||||||
|
|
@ -895,7 +895,7 @@ defmodule Pleroma.User do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_email_not_in_blacklisted_domain(changeset, field) do
|
defp validate_email_not_in_blacklisted_domain(changeset, field) do
|
||||||
validate_change(changeset, field, fn _, value ->
|
validate_change(changeset, field, fn _, value ->
|
||||||
valid? =
|
valid? =
|
||||||
Config.get([User, :email_blacklist])
|
Config.get([User, :email_blacklist])
|
||||||
|
|
@ -912,9 +912,9 @@ defmodule Pleroma.User do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
def maybe_validate_required_email(changeset, true), do: changeset
|
defp maybe_validate_required_email(changeset, true), do: changeset
|
||||||
|
|
||||||
def maybe_validate_required_email(changeset, _) do
|
defp maybe_validate_required_email(changeset, _) do
|
||||||
if Config.get([:instance, :account_activation_required]) do
|
if Config.get([:instance, :account_activation_required]) do
|
||||||
validate_required(changeset, [:email])
|
validate_required(changeset, [:email])
|
||||||
else
|
else
|
||||||
|
|
@ -1109,15 +1109,15 @@ defmodule Pleroma.User do
|
||||||
|
|
||||||
defp maybe_send_registration_email(_), do: {:ok, :noop}
|
defp maybe_send_registration_email(_), do: {:ok, :noop}
|
||||||
|
|
||||||
def needs_update?(%User{local: true}), do: false
|
defp needs_update?(%User{local: true}), do: false
|
||||||
|
|
||||||
def needs_update?(%User{local: false, last_refreshed_at: nil}), do: true
|
defp needs_update?(%User{local: false, last_refreshed_at: nil}), do: true
|
||||||
|
|
||||||
def needs_update?(%User{local: false} = user) do
|
defp needs_update?(%User{local: false} = user) do
|
||||||
NaiveDateTime.diff(NaiveDateTime.utc_now(), user.last_refreshed_at) >= 86_400
|
NaiveDateTime.diff(NaiveDateTime.utc_now(), user.last_refreshed_at) >= 86_400
|
||||||
end
|
end
|
||||||
|
|
||||||
def needs_update?(_), do: true
|
defp needs_update?(_), do: true
|
||||||
|
|
||||||
@spec maybe_direct_follow(User.t(), User.t()) ::
|
@spec maybe_direct_follow(User.t(), User.t()) ::
|
||||||
{:ok, User.t(), User.t()} | {:error, String.t()}
|
{:ok, User.t(), User.t()} | {:error, String.t()}
|
||||||
|
|
@ -1708,7 +1708,9 @@ defmodule Pleroma.User do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def block(%User{} = blocker, %User{} = blocked) do
|
def block(blocker, blocked, params \\ %{})
|
||||||
|
|
||||||
|
def block(%User{} = blocker, %User{} = blocked, params) do
|
||||||
# sever any follow relationships to prevent leaks per activitypub (Pleroma issue #213)
|
# sever any follow relationships to prevent leaks per activitypub (Pleroma issue #213)
|
||||||
blocker =
|
blocker =
|
||||||
if following?(blocker, blocked) do
|
if following?(blocker, blocked) do
|
||||||
|
|
@ -1738,12 +1740,33 @@ defmodule Pleroma.User do
|
||||||
|
|
||||||
{:ok, blocker} = update_follower_count(blocker)
|
{:ok, blocker} = update_follower_count(blocker)
|
||||||
{:ok, blocker, _} = Participation.mark_all_as_read(blocker, blocked)
|
{:ok, blocker, _} = Participation.mark_all_as_read(blocker, blocked)
|
||||||
add_to_block(blocker, blocked)
|
|
||||||
|
duration = Map.get(params, :duration, 0)
|
||||||
|
|
||||||
|
expires_at =
|
||||||
|
if duration > 0 do
|
||||||
|
DateTime.utc_now()
|
||||||
|
|> DateTime.add(duration)
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
user_block = add_to_block(blocker, blocked, expires_at)
|
||||||
|
|
||||||
|
if duration > 0 do
|
||||||
|
Pleroma.Workers.MuteExpireWorker.new(
|
||||||
|
%{"op" => "unblock_user", "blocker_id" => blocker.id, "blocked_id" => blocked.id},
|
||||||
|
scheduled_at: expires_at
|
||||||
|
)
|
||||||
|
|> Oban.insert()
|
||||||
|
end
|
||||||
|
|
||||||
|
user_block
|
||||||
end
|
end
|
||||||
|
|
||||||
# helper to handle the block given only an actor's AP id
|
# helper to handle the block given only an actor's AP id
|
||||||
def block(%User{} = blocker, %{ap_id: ap_id}) do
|
def block(%User{} = blocker, %{ap_id: ap_id}, params) do
|
||||||
block(blocker, get_cached_by_ap_id(ap_id))
|
block(blocker, get_cached_by_ap_id(ap_id), params)
|
||||||
end
|
end
|
||||||
|
|
||||||
def unblock(%User{} = blocker, %User{} = blocked) do
|
def unblock(%User{} = blocker, %User{} = blocked) do
|
||||||
|
|
@ -1984,7 +2007,7 @@ defmodule Pleroma.User do
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec purge_user_changeset(User.t()) :: Ecto.Changeset.t()
|
@spec purge_user_changeset(User.t()) :: Ecto.Changeset.t()
|
||||||
def purge_user_changeset(user) do
|
defp purge_user_changeset(user) do
|
||||||
# "Right to be forgotten"
|
# "Right to be forgotten"
|
||||||
# https://gdpr.eu/right-to-be-forgotten/
|
# https://gdpr.eu/right-to-be-forgotten/
|
||||||
change(user, %{
|
change(user, %{
|
||||||
|
|
@ -2156,7 +2179,7 @@ defmodule Pleroma.User do
|
||||||
Repo.all(query)
|
Repo.all(query)
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete_notifications_from_user_activities(%User{ap_id: ap_id}) do
|
defp delete_notifications_from_user_activities(%User{ap_id: ap_id}) do
|
||||||
Notification
|
Notification
|
||||||
|> join(:inner, [n], activity in assoc(n, :activity))
|
|> join(:inner, [n], activity in assoc(n, :activity))
|
||||||
|> where([n, a], fragment("? = ?", a.actor, ^ap_id))
|
|> where([n, a], fragment("? = ?", a.actor, ^ap_id))
|
||||||
|
|
@ -2615,7 +2638,7 @@ defmodule Pleroma.User do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Internal function; public one is `deactivate/2`
|
# Internal function; public one is `set_activation/2`
|
||||||
defp set_activation_status(user, status) do
|
defp set_activation_status(user, status) do
|
||||||
user
|
user
|
||||||
|> cast(%{is_active: status}, [:is_active])
|
|> cast(%{is_active: status}, [:is_active])
|
||||||
|
|
@ -2634,7 +2657,7 @@ defmodule Pleroma.User do
|
||||||
|> update_and_set_cache()
|
|> update_and_set_cache()
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_fields(changeset, remote? \\ false) do
|
defp validate_fields(changeset, remote?) do
|
||||||
limit_name = if remote?, do: :max_remote_account_fields, else: :max_account_fields
|
limit_name = if remote?, do: :max_remote_account_fields, else: :max_account_fields
|
||||||
limit = Config.get([:instance, limit_name], 0)
|
limit = Config.get([:instance, limit_name], 0)
|
||||||
|
|
||||||
|
|
@ -2779,10 +2802,10 @@ defmodule Pleroma.User do
|
||||||
set_domain_blocks(user, List.delete(user.domain_blocks, domain_blocked))
|
set_domain_blocks(user, List.delete(user.domain_blocks, domain_blocked))
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec add_to_block(User.t(), User.t()) ::
|
@spec add_to_block(User.t(), User.t(), integer() | nil) ::
|
||||||
{:ok, UserRelationship.t()} | {:error, Ecto.Changeset.t()}
|
{:ok, UserRelationship.t()} | {:error, Ecto.Changeset.t()}
|
||||||
defp add_to_block(%User{} = user, %User{} = blocked) do
|
defp add_to_block(%User{} = user, %User{} = blocked, expires_at) do
|
||||||
with {:ok, relationship} <- UserRelationship.create_block(user, blocked) do
|
with {:ok, relationship} <- UserRelationship.create_block(user, blocked, expires_at) do
|
||||||
@cachex.del(:user_cache, "blocked_users_ap_ids:#{user.ap_id}")
|
@cachex.del(:user_cache, "blocked_users_ap_ids:#{user.ap_id}")
|
||||||
{:ok, relationship}
|
{:ok, relationship}
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -327,8 +327,8 @@ defmodule Pleroma.Web.ActivityPub.Builder do
|
||||||
}, []}
|
}, []}
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec block(User.t(), User.t()) :: {:ok, map(), keyword()}
|
@spec block(User.t(), User.t(), map()) :: {:ok, map(), keyword()}
|
||||||
def block(blocker, blocked) do
|
def block(blocker, blocked, params \\ %{}) do
|
||||||
{:ok,
|
{:ok,
|
||||||
%{
|
%{
|
||||||
"id" => Utils.generate_activity_id(),
|
"id" => Utils.generate_activity_id(),
|
||||||
|
|
@ -336,7 +336,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
|
||||||
"actor" => blocker.ap_id,
|
"actor" => blocker.ap_id,
|
||||||
"object" => blocked.ap_id,
|
"object" => blocked.ap_id,
|
||||||
"to" => [blocked.ap_id]
|
"to" => [blocked.ap_id]
|
||||||
}, []}
|
}, Keyword.new(params)}
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec announce(User.t(), Object.t(), keyword()) :: {:ok, map(), keyword()}
|
@spec announce(User.t(), Object.t(), keyword()) :: {:ok, map(), keyword()}
|
||||||
|
|
|
||||||
|
|
@ -200,14 +200,13 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate(%{"type" => type} = object, meta)
|
def validate(%{"type" => type} = object, meta)
|
||||||
when type in ~w[Accept Reject Follow Update Like EmojiReact Announce
|
when type in ~w[Accept Reject Follow Like EmojiReact Announce
|
||||||
ChatMessage Answer] do
|
ChatMessage Answer] do
|
||||||
validator =
|
validator =
|
||||||
case type do
|
case type do
|
||||||
"Accept" -> AcceptRejectValidator
|
"Accept" -> AcceptRejectValidator
|
||||||
"Reject" -> AcceptRejectValidator
|
"Reject" -> AcceptRejectValidator
|
||||||
"Follow" -> FollowValidator
|
"Follow" -> FollowValidator
|
||||||
"Update" -> UpdateValidator
|
|
||||||
"Like" -> LikeValidator
|
"Like" -> LikeValidator
|
||||||
"EmojiReact" -> EmojiReactValidator
|
"EmojiReact" -> EmojiReactValidator
|
||||||
"Announce" -> AnnounceValidator
|
"Announce" -> AnnounceValidator
|
||||||
|
|
@ -215,16 +214,19 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
||||||
"Answer" -> AnswerValidator
|
"Answer" -> AnswerValidator
|
||||||
end
|
end
|
||||||
|
|
||||||
cast_func =
|
|
||||||
if type == "Update" do
|
|
||||||
fn o -> validator.cast_and_validate(o, meta) end
|
|
||||||
else
|
|
||||||
fn o -> validator.cast_and_validate(o) end
|
|
||||||
end
|
|
||||||
|
|
||||||
with {:ok, object} <-
|
with {:ok, object} <-
|
||||||
object
|
object
|
||||||
|> cast_func.()
|
|> validator.cast_and_validate()
|
||||||
|
|> Ecto.Changeset.apply_action(:insert) do
|
||||||
|
object = stringify_keys(object)
|
||||||
|
{:ok, object, meta}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate(%{"type" => type} = object, meta) when type == "Update" do
|
||||||
|
with {:ok, object} <-
|
||||||
|
object
|
||||||
|
|> UpdateValidator.cast_and_validate(meta)
|
||||||
|> Ecto.Changeset.apply_action(:insert) do
|
|> Ecto.Changeset.apply_action(:insert) do
|
||||||
object = stringify_keys(object)
|
object = stringify_keys(object)
|
||||||
{:ok, object, meta}
|
{:ok, object, meta}
|
||||||
|
|
|
||||||
|
|
@ -50,13 +50,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.TagValidator do
|
||||||
end
|
end
|
||||||
|
|
||||||
def changeset(struct, %{"type" => "Hashtag", "name" => name} = data) do
|
def changeset(struct, %{"type" => "Hashtag", "name" => name} = data) do
|
||||||
name =
|
name = String.downcase(name)
|
||||||
cond do
|
|
||||||
"#" <> name -> name
|
|
||||||
name -> name
|
|
||||||
end
|
|
||||||
|> String.downcase()
|
|
||||||
|
|
||||||
data = Map.put(data, "name", name)
|
data = Map.put(data, "name", name)
|
||||||
|
|
||||||
struct
|
struct
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
||||||
) do
|
) do
|
||||||
with %User{} = blocker <- User.get_cached_by_ap_id(blocking_user),
|
with %User{} = blocker <- User.get_cached_by_ap_id(blocking_user),
|
||||||
%User{} = blocked <- User.get_cached_by_ap_id(blocked_user) do
|
%User{} = blocked <- User.get_cached_by_ap_id(blocked_user) do
|
||||||
User.block(blocker, blocked)
|
User.block(blocker, blocked, Enum.into(meta, %{}))
|
||||||
end
|
end
|
||||||
|
|
||||||
{:ok, object, meta}
|
{:ok, object, meta}
|
||||||
|
|
|
||||||
|
|
@ -335,13 +335,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
||||||
|
|
||||||
if params["password"] do
|
if params["password"] do
|
||||||
User.force_password_reset_async(user)
|
User.force_password_reset_async(user)
|
||||||
end
|
|
||||||
|
|
||||||
ModerationLog.insert_log(%{
|
ModerationLog.insert_log(%{
|
||||||
actor: admin,
|
actor: admin,
|
||||||
subject: [user],
|
subject: [user],
|
||||||
action: "force_password_reset"
|
action: "force_password_reset"
|
||||||
})
|
})
|
||||||
|
end
|
||||||
|
|
||||||
json(conn, %{status: "success"})
|
json(conn, %{status: "success"})
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -284,18 +284,6 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
|
||||||
:query,
|
:query,
|
||||||
%Schema{allOf: [BooleanLike], default: true},
|
%Schema{allOf: [BooleanLike], default: true},
|
||||||
"Mute notifications in addition to statuses? Defaults to `true`."
|
"Mute notifications in addition to statuses? Defaults to `true`."
|
||||||
),
|
|
||||||
Operation.parameter(
|
|
||||||
:duration,
|
|
||||||
:query,
|
|
||||||
%Schema{type: :integer},
|
|
||||||
"Expire the mute in `duration` seconds. Default 0 for infinity"
|
|
||||||
),
|
|
||||||
Operation.parameter(
|
|
||||||
:expires_in,
|
|
||||||
:query,
|
|
||||||
%Schema{type: :integer, default: 0},
|
|
||||||
"Deprecated, use `duration` instead"
|
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
responses: %{
|
responses: %{
|
||||||
|
|
@ -323,16 +311,37 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
|
||||||
tags: ["Account actions"],
|
tags: ["Account actions"],
|
||||||
summary: "Block",
|
summary: "Block",
|
||||||
operationId: "AccountController.block",
|
operationId: "AccountController.block",
|
||||||
|
requestBody: request_body("Parameters", block_request()),
|
||||||
security: [%{"oAuth" => ["follow", "write:blocks"]}],
|
security: [%{"oAuth" => ["follow", "write:blocks"]}],
|
||||||
description:
|
description:
|
||||||
"Block the given account. Clients should filter statuses from this account if received (e.g. due to a boost in the Home timeline)",
|
"Block the given account. Clients should filter statuses from this account if received (e.g. due to a boost in the Home timeline)",
|
||||||
parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
|
parameters: [
|
||||||
|
%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}
|
||||||
|
],
|
||||||
responses: %{
|
responses: %{
|
||||||
200 => Operation.response("Relationship", "application/json", AccountRelationship)
|
200 => Operation.response("Relationship", "application/json", AccountRelationship)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp block_request do
|
||||||
|
%Schema{
|
||||||
|
title: "AccountBlockRequest",
|
||||||
|
description: "POST body for blocking an account",
|
||||||
|
type: :object,
|
||||||
|
properties: %{
|
||||||
|
duration: %Schema{
|
||||||
|
type: :integer,
|
||||||
|
nullable: true,
|
||||||
|
description: "Expire the mute in `duration` seconds. Default 0 for infinity"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
example: %{
|
||||||
|
"duration" => 86_400
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
def unblock_operation do
|
def unblock_operation do
|
||||||
%Operation{
|
%Operation{
|
||||||
tags: ["Account actions"],
|
tags: ["Account actions"],
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
|
||||||
id: FlakeID,
|
id: FlakeID,
|
||||||
locked: %Schema{type: :boolean},
|
locked: %Schema{type: :boolean},
|
||||||
mute_expires_at: %Schema{type: :string, format: "date-time", nullable: true},
|
mute_expires_at: %Schema{type: :string, format: "date-time", nullable: true},
|
||||||
|
block_expires_at: %Schema{type: :string, format: "date-time", nullable: true},
|
||||||
note: %Schema{type: :string, format: :html},
|
note: %Schema{type: :string, format: :html},
|
||||||
statuses_count: %Schema{type: :integer},
|
statuses_count: %Schema{type: :integer},
|
||||||
url: %Schema{type: :string, format: :uri},
|
url: %Schema{type: :string, format: :uri},
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,9 @@ defmodule Pleroma.Web.CommonAPI do
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
@spec block(User.t(), User.t()) :: {:ok, Activity.t()} | Pipeline.errors()
|
@spec block(User.t(), User.t()) :: {:ok, Activity.t()} | Pipeline.errors()
|
||||||
def block(blocked, blocker) do
|
def block(blocked, blocker, params \\ %{}) do
|
||||||
with {:ok, block_data, _} <- Builder.block(blocker, blocked),
|
with {:ok, block_data, meta} <- Builder.block(blocker, blocked, params),
|
||||||
{:ok, block, _} <- Pipeline.common_pipeline(block_data, local: true) do
|
{:ok, block, _} <- Pipeline.common_pipeline(block_data, meta ++ [local: true]) do
|
||||||
{:ok, block}
|
{:ok, block}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -501,8 +501,14 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc "POST /api/v1/accounts/:id/block"
|
@doc "POST /api/v1/accounts/:id/block"
|
||||||
def block(%{assigns: %{user: blocker, account: blocked}} = conn, _params) do
|
def block(
|
||||||
with {:ok, _activity} <- CommonAPI.block(blocked, blocker) do
|
%{
|
||||||
|
assigns: %{user: blocker, account: blocked},
|
||||||
|
private: %{open_api_spex: %{body_params: params}}
|
||||||
|
} = conn,
|
||||||
|
_params
|
||||||
|
) do
|
||||||
|
with {:ok, _activity} <- CommonAPI.block(blocked, blocker, params) do
|
||||||
render(conn, "relationship.json", user: blocker, target: blocked)
|
render(conn, "relationship.json", user: blocker, target: blocked)
|
||||||
else
|
else
|
||||||
{:error, message} -> json_response(conn, :forbidden, %{error: message})
|
{:error, message} -> json_response(conn, :forbidden, %{error: message})
|
||||||
|
|
@ -607,7 +613,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
||||||
users: users,
|
users: users,
|
||||||
for: user,
|
for: user,
|
||||||
as: :user,
|
as: :user,
|
||||||
embed_relationships: embed_relationships?(params)
|
embed_relationships: embed_relationships?(params),
|
||||||
|
blocks: true
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -340,6 +340,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
||||||
|> maybe_put_unread_notification_count(user, opts[:for])
|
|> maybe_put_unread_notification_count(user, opts[:for])
|
||||||
|> maybe_put_email_address(user, opts[:for])
|
|> maybe_put_email_address(user, opts[:for])
|
||||||
|> maybe_put_mute_expires_at(user, opts[:for], opts)
|
|> maybe_put_mute_expires_at(user, opts[:for], opts)
|
||||||
|
|> maybe_put_block_expires_at(user, opts[:for], opts)
|
||||||
|> maybe_show_birthday(user, opts[:for])
|
|> maybe_show_birthday(user, opts[:for])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -476,6 +477,16 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
||||||
|
|
||||||
defp maybe_put_mute_expires_at(data, _, _, _), do: data
|
defp maybe_put_mute_expires_at(data, _, _, _), do: data
|
||||||
|
|
||||||
|
defp maybe_put_block_expires_at(data, %User{} = user, target, %{blocks: true}) do
|
||||||
|
Map.put(
|
||||||
|
data,
|
||||||
|
:block_expires_at,
|
||||||
|
UserRelationship.get_block_expire_date(target, user)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp maybe_put_block_expires_at(data, _, _, _), do: data
|
||||||
|
|
||||||
defp maybe_show_birthday(data, %User{id: user_id} = user, %User{id: user_id}) do
|
defp maybe_show_birthday(data, %User{id: user_id} = user, %User{id: user_id}) do
|
||||||
data
|
data
|
||||||
|> Kernel.put_in([:pleroma, :birthday], user.birthday)
|
|> Kernel.put_in([:pleroma, :birthday], user.birthday)
|
||||||
|
|
|
||||||
|
|
@ -157,7 +157,8 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
|
||||||
"pleroma:bookmark_folders",
|
"pleroma:bookmark_folders",
|
||||||
if Pleroma.Language.LanguageDetector.configured?() do
|
if Pleroma.Language.LanguageDetector.configured?() do
|
||||||
"pleroma:language_detection"
|
"pleroma:language_detection"
|
||||||
end
|
end,
|
||||||
|
"pleroma:block_expiration"
|
||||||
]
|
]
|
||||||
|> Enum.filter(& &1)
|
|> Enum.filter(& &1)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,7 @@ defmodule Pleroma.Web.Router do
|
||||||
end
|
end
|
||||||
|
|
||||||
pipeline :well_known do
|
pipeline :well_known do
|
||||||
plug(:accepts, ["activity+json", "json", "jrd", "jrd+json", "xml", "xrd+xml"])
|
plug(:accepts, ["activity+json", "json", "jrd", "jrd+json", "xml", "xrd+xml", "html"])
|
||||||
end
|
end
|
||||||
|
|
||||||
pipeline :config do
|
pipeline :config do
|
||||||
|
|
|
||||||
|
|
@ -231,8 +231,8 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= for %{data: mention, object: object, from: from} <- @mentions do %>
|
<%= for %{data: mention, object: object, from: from} <- @mentions do %>
|
||||||
<%# mention START %>
|
<% # mention START %>
|
||||||
<%# user card START %>
|
<% # user card START %>
|
||||||
<div style="background-color:transparent;">
|
<div style="background-color:transparent;">
|
||||||
<div class="block-grid mixed-two-up no-stack"
|
<div class="block-grid mixed-two-up no-stack"
|
||||||
style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
|
style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
|
||||||
|
|
@ -291,7 +291,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<%# user card END %>
|
<% # user card END %>
|
||||||
|
|
||||||
<div style="background-color:transparent;">
|
<div style="background-color:transparent;">
|
||||||
<div class="block-grid"
|
<div class="block-grid"
|
||||||
|
|
@ -333,12 +333,12 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<%# mention END %>
|
<% # mention END %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<%= if @followers != [] do %>
|
<%= if @followers != [] do %>
|
||||||
|
|
||||||
<%# new followers header START %>
|
<% # new followers header START %>
|
||||||
<div style="background-color:transparent;">
|
<div style="background-color:transparent;">
|
||||||
<div class="block-grid"
|
<div class="block-grid"
|
||||||
style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
|
style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
|
||||||
|
|
@ -397,10 +397,10 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<%# new followers header END %>
|
<% # new followers header END %>
|
||||||
|
|
||||||
<%= for %{data: follow, from: from} <- @followers do %>
|
<%= for %{data: follow, from: from} <- @followers do %>
|
||||||
<%# user card START %>
|
<% # user card START %>
|
||||||
<div style="background-color:transparent;">
|
<div style="background-color:transparent;">
|
||||||
<div class="block-grid mixed-two-up no-stack"
|
<div class="block-grid mixed-two-up no-stack"
|
||||||
style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
|
style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
|
||||||
|
|
@ -459,13 +459,13 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<%# user card END %>
|
<% # user card END %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<%# divider start %>
|
<% # divider start %>
|
||||||
<div style="background-color:transparent;">
|
<div style="background-color:transparent;">
|
||||||
<div class="block-grid"
|
<div class="block-grid"
|
||||||
style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
|
style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
|
||||||
|
|
@ -514,7 +514,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%# divider end %>
|
<% # divider end %>
|
||||||
|
|
||||||
|
|
||||||
<div style="background-color:transparent;">
|
<div style="background-color:transparent;">
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<%= for {user, total_statuses, latest_status} <- @users_and_statuses do %>
|
<%= for {user, total_statuses, latest_status} <- @users_and_statuses do %>
|
||||||
<%# user card START %>
|
<% # user card START %>
|
||||||
<div style="background-color:transparent;">
|
<div style="background-color:transparent;">
|
||||||
<div class="block-grid mixed-two-up no-stack"
|
<div class="block-grid mixed-two-up no-stack"
|
||||||
style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
|
style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
|
||||||
|
|
@ -60,7 +60,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<%# user card END %>
|
<% # user card END %>
|
||||||
|
|
||||||
<%= if latest_status do %>
|
<%= if latest_status do %>
|
||||||
<div style="background-color:transparent;">
|
<div style="background-color:transparent;">
|
||||||
|
|
@ -104,7 +104,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%# divider start %>
|
<% # divider start %>
|
||||||
<div style="background-color:transparent;">
|
<div style="background-color:transparent;">
|
||||||
<div class="block-grid"
|
<div class="block-grid"
|
||||||
style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
|
style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
|
||||||
|
|
@ -153,6 +153,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%# divider end %>
|
<% # divider end %>
|
||||||
<%# user card END %>
|
<% # user card END %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@
|
||||||
<td style="word-break: break-word; vertical-align: top;" valign="top">
|
<td style="word-break: break-word; vertical-align: top;" valign="top">
|
||||||
<!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td align="center" style="background-color:<%= @styling.background_color %>"><![endif]-->
|
<!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td align="center" style="background-color:<%= @styling.background_color %>"><![endif]-->
|
||||||
|
|
||||||
<%# header %>
|
<% # header %>
|
||||||
<div style="background-color:transparent;">
|
<div style="background-color:transparent;">
|
||||||
<div class="block-grid"
|
<div class="block-grid"
|
||||||
style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
|
style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
|
||||||
|
|
@ -145,7 +145,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<%# title %>
|
<% # title %>
|
||||||
<%= if @title do %>
|
<%= if @title do %>
|
||||||
<div style="background-color:transparent;">
|
<div style="background-color:transparent;">
|
||||||
<div class="block-grid"
|
<div class="block-grid"
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
<%= label @form, :scope, Gettext.dpgettext("static_pages", "oauth scopes message", "The following permissions will be granted") %>
|
<%= label @form, :scope, Gettext.dpgettext("static_pages", "oauth scopes message", "The following permissions will be granted") %>
|
||||||
<div class="scopes">
|
<div class="scopes">
|
||||||
<%= for scope <- @available_scopes do %>
|
<%= for scope <- @available_scopes do %>
|
||||||
<%# Note: using hidden input with `unchecked_value` in order to distinguish user's empty selection from `scope` param being omitted %>
|
<% # Note: using hidden input with `unchecked_value` in order to distinguish user's empty selection from `scope` param being omitted %>
|
||||||
<%= if scope in @scopes do %>
|
<%= if scope in @scopes do %>
|
||||||
<div class="scope">
|
<div class="scope">
|
||||||
<%= checkbox @form, :"scope_#{scope}", value: scope in @scopes && scope, checked_value: scope, unchecked_value: "", name: "authorization[scope][]" %>
|
<%= checkbox @form, :"scope_#{scope}", value: scope in @scopes && scope, checked_value: scope, unchecked_value: "", name: "authorization[scope][]" %>
|
||||||
|
|
|
||||||
|
|
@ -41,5 +41,10 @@ defmodule Pleroma.Web.WebFinger.WebFingerController do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Default to JSON when no format is specified or format is not recognized
|
||||||
|
def webfinger(%{assigns: %{format: _format}} = conn, %{"resource" => _resource} = params) do
|
||||||
|
webfinger(put_in(conn.assigns.format, "json"), params)
|
||||||
|
end
|
||||||
|
|
||||||
def webfinger(conn, _params), do: send_resp(conn, 400, "Bad Request")
|
def webfinger(conn, _params), do: send_resp(conn, 400, "Bad Request")
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,13 @@
|
||||||
defmodule Pleroma.Workers.MuteExpireWorker do
|
defmodule Pleroma.Workers.MuteExpireWorker do
|
||||||
use Oban.Worker, queue: :background
|
use Oban.Worker, queue: :background
|
||||||
|
|
||||||
|
alias Pleroma.User
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def perform(%Job{args: %{"op" => "unmute_user", "muter_id" => muter_id, "mutee_id" => mutee_id}}) do
|
def perform(%Job{
|
||||||
Pleroma.User.unmute(muter_id, mutee_id)
|
args: %{"op" => "unmute_user", "muter_id" => muter_id, "mutee_id" => mutee_id}
|
||||||
|
}) do
|
||||||
|
User.unmute(muter_id, mutee_id)
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -18,6 +22,17 @@ defmodule Pleroma.Workers.MuteExpireWorker do
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def perform(%Job{
|
||||||
|
args: %{"op" => "unblock_user", "blocker_id" => blocker_id, "blocked_id" => blocked_id}
|
||||||
|
}) do
|
||||||
|
Pleroma.Web.CommonAPI.unblock(
|
||||||
|
User.get_cached_by_id(blocked_id),
|
||||||
|
User.get_cached_by_id(blocker_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def timeout(_job), do: :timer.seconds(5)
|
def timeout(_job), do: :timer.seconds(5)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
15
mix.exs
15
mix.exs
|
|
@ -37,22 +37,13 @@ defmodule Pleroma.Mixfile do
|
||||||
pleroma: [
|
pleroma: [
|
||||||
include_executables_for: [:unix],
|
include_executables_for: [:unix],
|
||||||
applications: [ex_syslogger: :load, syslog: :load, eldap: :transient],
|
applications: [ex_syslogger: :load, syslog: :load, eldap: :transient],
|
||||||
steps: [:assemble, &put_otp_version/1, ©_files/1, ©_nginx_config/1],
|
steps: [:assemble, ©_files/1, ©_nginx_config/1],
|
||||||
config_providers: [{Pleroma.Config.ReleaseRuntimeProvider, []}]
|
config_providers: [{Pleroma.Config.ReleaseRuntimeProvider, []}]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
def put_otp_version(%{path: target_path} = release) do
|
|
||||||
File.write!(
|
|
||||||
Path.join([target_path, "OTP_VERSION"]),
|
|
||||||
Pleroma.OTPVersion.version()
|
|
||||||
)
|
|
||||||
|
|
||||||
release
|
|
||||||
end
|
|
||||||
|
|
||||||
def copy_files(%{path: target_path} = release) do
|
def copy_files(%{path: target_path} = release) do
|
||||||
File.cp_r!("./rel/files", target_path)
|
File.cp_r!("./rel/files", target_path)
|
||||||
release
|
release
|
||||||
|
|
@ -213,7 +204,7 @@ defmodule Pleroma.Mixfile do
|
||||||
{:poison, "~> 3.0", only: :test},
|
{:poison, "~> 3.0", only: :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},
|
||||||
{:credo, "~> 1.6", only: [:dev, :test], runtime: false},
|
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
|
||||||
{:mock, "~> 0.3.5", only: :test},
|
{:mock, "~> 0.3.5", only: :test},
|
||||||
{:covertool, "~> 2.0", only: :test},
|
{:covertool, "~> 2.0", only: :test},
|
||||||
{:hackney, "~> 1.18.0", override: true},
|
{:hackney, "~> 1.18.0", override: true},
|
||||||
|
|
@ -236,7 +227,7 @@ defmodule Pleroma.Mixfile do
|
||||||
"ecto.rollback": ["pleroma.ecto.rollback"],
|
"ecto.rollback": ["pleroma.ecto.rollback"],
|
||||||
"ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
|
"ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
|
||||||
"ecto.reset": ["ecto.drop", "ecto.setup"],
|
"ecto.reset": ["ecto.drop", "ecto.setup"],
|
||||||
test: ["ecto.create --quiet", "ecto.migrate", "test"],
|
test: ["ecto.create --quiet", "ecto.migrate", "test --warnings-as-errors"],
|
||||||
docs: ["pleroma.docs", "docs"],
|
docs: ["pleroma.docs", "docs"],
|
||||||
analyze: ["credo --strict --only=warnings,todo,fixme,consistency,readability"],
|
analyze: ["credo --strict --only=warnings,todo,fixme,consistency,readability"],
|
||||||
copyright: &add_copyright/1,
|
copyright: &add_copyright/1,
|
||||||
|
|
|
||||||
2
mix.lock
2
mix.lock
|
|
@ -23,7 +23,7 @@
|
||||||
"cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"},
|
"cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"},
|
||||||
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
|
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
|
||||||
"cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"},
|
"cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"},
|
||||||
"credo": {:hex, :credo, "1.7.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"},
|
"credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"},
|
||||||
"crontab": {:hex, :crontab, "1.1.8", "2ce0e74777dfcadb28a1debbea707e58b879e6aa0ffbf9c9bb540887bce43617", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
|
"crontab": {:hex, :crontab, "1.1.8", "2ce0e74777dfcadb28a1debbea707e58b879e6aa0ffbf9c9bb540887bce43617", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
|
||||||
"custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"},
|
"custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"},
|
||||||
"db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"},
|
"db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"},
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,24 @@
|
||||||
defmodule Pleroma.Repo.Migrations.AssignAppUser do
|
defmodule Pleroma.Repo.Migrations.AssignAppUser do
|
||||||
use Ecto.Migration
|
use Ecto.Migration
|
||||||
|
|
||||||
|
import Ecto.Query
|
||||||
|
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.Web.OAuth.App
|
alias Pleroma.Web.OAuth.App
|
||||||
alias Pleroma.Web.OAuth.Token
|
alias Pleroma.Web.OAuth.Token
|
||||||
|
|
||||||
def up do
|
def up do
|
||||||
Repo.all(Token)
|
Token
|
||||||
|> Enum.group_by(fn x -> Map.get(x, :app_id) end)
|
|> where([t], not is_nil(t.user_id))
|
||||||
|> Enum.each(fn {_app_id, tokens} ->
|
|> group_by([t], t.app_id)
|
||||||
token =
|
|> select([t], %{app_id: t.app_id, id: min(t.id)})
|
||||||
Enum.filter(tokens, fn x -> not is_nil(x.user_id) end)
|
|> order_by(asc: :app_id)
|
||||||
|> List.first()
|
|> Repo.stream()
|
||||||
|
|> Stream.each(fn %{id: id} ->
|
||||||
|
token = Token.Query.get_by_id(id) |> Repo.one()
|
||||||
App.maybe_update_owner(token)
|
App.maybe_update_owner(token)
|
||||||
end)
|
end)
|
||||||
|
|> Stream.run()
|
||||||
end
|
end
|
||||||
|
|
||||||
def down, do: :ok
|
def down, do: :ok
|
||||||
|
|
|
||||||
1
test/fixtures/warnings/otp_version/21.1
vendored
1
test/fixtures/warnings/otp_version/21.1
vendored
|
|
@ -1 +0,0 @@
|
||||||
21.1
|
|
||||||
1
test/fixtures/warnings/otp_version/22.1
vendored
1
test/fixtures/warnings/otp_version/22.1
vendored
|
|
@ -1 +0,0 @@
|
||||||
22.1
|
|
||||||
1
test/fixtures/warnings/otp_version/22.4
vendored
1
test/fixtures/warnings/otp_version/22.4
vendored
|
|
@ -1 +0,0 @@
|
||||||
22.4
|
|
||||||
1
test/fixtures/warnings/otp_version/23.0
vendored
1
test/fixtures/warnings/otp_version/23.0
vendored
|
|
@ -1 +0,0 @@
|
||||||
23.0
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
defmodule Pleroma.OTPVersionTest do
|
|
||||||
use ExUnit.Case, async: true
|
|
||||||
|
|
||||||
alias Pleroma.OTPVersion
|
|
||||||
|
|
||||||
describe "check/1" do
|
|
||||||
test "22.4" do
|
|
||||||
assert OTPVersion.get_version_from_files(["test/fixtures/warnings/otp_version/22.4"]) ==
|
|
||||||
"22.4"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "22.1" do
|
|
||||||
assert OTPVersion.get_version_from_files(["test/fixtures/warnings/otp_version/22.1"]) ==
|
|
||||||
"22.1"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "21.1" do
|
|
||||||
assert OTPVersion.get_version_from_files(["test/fixtures/warnings/otp_version/21.1"]) ==
|
|
||||||
"21.1"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "23.0" do
|
|
||||||
assert OTPVersion.get_version_from_files(["test/fixtures/warnings/otp_version/23.0"]) ==
|
|
||||||
"23.0"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "with nonexistent file" do
|
|
||||||
assert OTPVersion.get_version_from_files([
|
|
||||||
"test/fixtures/warnings/otp_version/non-exising",
|
|
||||||
"test/fixtures/warnings/otp_version/22.4"
|
|
||||||
]) == "22.4"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "empty paths" do
|
|
||||||
assert OTPVersion.get_version_from_files([]) == nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -2669,8 +2669,12 @@ defmodule Pleroma.UserTest do
|
||||||
|
|
||||||
assert {:ok, user} = User.update_last_active_at(user)
|
assert {:ok, user} = User.update_last_active_at(user)
|
||||||
|
|
||||||
assert user.last_active_at >= test_started_at
|
assert NaiveDateTime.compare(user.last_active_at, test_started_at) in [:gt, :eq]
|
||||||
assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
|
|
||||||
|
assert NaiveDateTime.compare(
|
||||||
|
user.last_active_at,
|
||||||
|
NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
|
||||||
|
) in [:lt, :eq]
|
||||||
|
|
||||||
last_active_at =
|
last_active_at =
|
||||||
NaiveDateTime.utc_now()
|
NaiveDateTime.utc_now()
|
||||||
|
|
@ -2682,10 +2686,15 @@ defmodule Pleroma.UserTest do
|
||||||
|> cast(%{last_active_at: last_active_at}, [:last_active_at])
|
|> cast(%{last_active_at: last_active_at}, [:last_active_at])
|
||||||
|> User.update_and_set_cache()
|
|> User.update_and_set_cache()
|
||||||
|
|
||||||
assert user.last_active_at == last_active_at
|
assert NaiveDateTime.compare(user.last_active_at, last_active_at) == :eq
|
||||||
|
|
||||||
assert {:ok, user} = User.update_last_active_at(user)
|
assert {:ok, user} = User.update_last_active_at(user)
|
||||||
assert user.last_active_at >= test_started_at
|
assert NaiveDateTime.compare(user.last_active_at, test_started_at) in [:gt, :eq]
|
||||||
assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
|
|
||||||
|
assert NaiveDateTime.compare(
|
||||||
|
user.last_active_at,
|
||||||
|
NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
|
||||||
|
) in [:lt, :eq]
|
||||||
end
|
end
|
||||||
|
|
||||||
test "active_user_count/1" do
|
test "active_user_count/1" do
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,17 @@ defmodule Pleroma.Web.CommonAPITest do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "add expiring block", %{blocker: blocker, blocked: blocked} do
|
||||||
|
{:ok, _} = CommonAPI.block(blocked, blocker, %{expires_in: 60})
|
||||||
|
assert User.blocks?(blocker, blocked)
|
||||||
|
|
||||||
|
worker = Pleroma.Workers.MuteExpireWorker
|
||||||
|
args = %{"op" => "unblock_user", "blocker_id" => blocker.id, "blocked_id" => blocked.id}
|
||||||
|
|
||||||
|
assert :ok = perform_job(worker, args)
|
||||||
|
refute User.blocks?(blocker, blocked)
|
||||||
|
end
|
||||||
|
|
||||||
test "it blocks and does not federate if outgoing blocks are disabled", %{
|
test "it blocks and does not federate if outgoing blocks are disabled", %{
|
||||||
blocker: blocker,
|
blocker: blocker,
|
||||||
blocked: blocked
|
blocked: blocked
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,12 @@ defmodule Pleroma.Web.Plugs.UserTrackingPlugTest do
|
||||||
|> assign(:user, user)
|
|> assign(:user, user)
|
||||||
|> UserTrackingPlug.call(%{})
|
|> UserTrackingPlug.call(%{})
|
||||||
|
|
||||||
assert user.last_active_at >= test_started_at
|
assert NaiveDateTime.compare(user.last_active_at, test_started_at) in [:gt, :eq]
|
||||||
assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
|
|
||||||
|
assert NaiveDateTime.compare(
|
||||||
|
user.last_active_at,
|
||||||
|
NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
|
||||||
|
) in [:lt, :eq]
|
||||||
end
|
end
|
||||||
|
|
||||||
test "doesn't update last_active_at if it was updated recently", %{conn: conn} do
|
test "doesn't update last_active_at if it was updated recently", %{conn: conn} do
|
||||||
|
|
@ -38,7 +42,7 @@ defmodule Pleroma.Web.Plugs.UserTrackingPlugTest do
|
||||||
|> assign(:user, user)
|
|> assign(:user, user)
|
||||||
|> UserTrackingPlug.call(%{})
|
|> UserTrackingPlug.call(%{})
|
||||||
|
|
||||||
assert user.last_active_at == last_active_at
|
assert NaiveDateTime.compare(user.last_active_at, last_active_at) == :eq
|
||||||
end
|
end
|
||||||
|
|
||||||
test "skips updating last_active_at if user ID is nil", %{conn: conn} do
|
test "skips updating last_active_at if user ID is nil", %{conn: conn} do
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do
|
defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do
|
||||||
use Pleroma.Web.ConnCase
|
use Pleroma.Web.ConnCase
|
||||||
|
|
||||||
import ExUnit.CaptureLog
|
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
import Tesla.Mock
|
import Tesla.Mock
|
||||||
|
|
||||||
|
|
@ -55,6 +54,26 @@ defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "Webfinger defaults to JSON when no Accept header is provided" do
|
||||||
|
user =
|
||||||
|
insert(:user,
|
||||||
|
ap_id: "https://hyrule.world/users/zelda",
|
||||||
|
also_known_as: ["https://mushroom.kingdom/users/toad"]
|
||||||
|
)
|
||||||
|
|
||||||
|
response =
|
||||||
|
build_conn()
|
||||||
|
|> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost")
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
|
assert response["subject"] == "acct:#{user.nickname}@localhost"
|
||||||
|
|
||||||
|
assert response["aliases"] == [
|
||||||
|
"https://hyrule.world/users/zelda",
|
||||||
|
"https://mushroom.kingdom/users/toad"
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
test "reach user on tld, while pleroma is running on subdomain" do
|
test "reach user on tld, while pleroma is running on subdomain" do
|
||||||
clear_config([Pleroma.Web.Endpoint, :url, :host], "sub.example.com")
|
clear_config([Pleroma.Web.Endpoint, :url, :host], "sub.example.com")
|
||||||
|
|
||||||
|
|
@ -109,16 +128,25 @@ defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do
|
||||||
assert result == "Couldn't find user"
|
assert result == "Couldn't find user"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "Sends a 404 when invalid format" do
|
test "Returns JSON when format is not supported" do
|
||||||
user = insert(:user)
|
user =
|
||||||
|
insert(:user,
|
||||||
|
ap_id: "https://hyrule.world/users/zelda",
|
||||||
|
also_known_as: ["https://mushroom.kingdom/users/toad"]
|
||||||
|
)
|
||||||
|
|
||||||
assert capture_log(fn ->
|
response =
|
||||||
assert_raise Phoenix.NotAcceptableError, fn ->
|
build_conn()
|
||||||
build_conn()
|
|> put_req_header("accept", "text/html")
|
||||||
|> put_req_header("accept", "text/html")
|
|> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost")
|
||||||
|> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost")
|
|> json_response(200)
|
||||||
end
|
|
||||||
end) =~ "no supported media type in accept header"
|
assert response["subject"] == "acct:#{user.nickname}@localhost"
|
||||||
|
|
||||||
|
assert response["aliases"] == [
|
||||||
|
"https://hyrule.world/users/zelda",
|
||||||
|
"https://mushroom.kingdom/users/toad"
|
||||||
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
test "Sends a 400 when resource param is missing" do
|
test "Sends a 400 when resource param is missing" do
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@
|
||||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
Code.put_compiler_option(:warnings_as_errors, true)
|
|
||||||
|
|
||||||
ExUnit.configure(capture_log: true, max_cases: System.schedulers_online())
|
ExUnit.configure(capture_log: true, max_cases: System.schedulers_online())
|
||||||
|
|
||||||
ExUnit.start(exclude: [:federated])
|
ExUnit.start(exclude: [:federated])
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue