Merge branch 'develop' into 'endorsements-api'

# Conflicts:
#   test/pleroma/web/pleroma_api/controllers/account_controller_test.exs
This commit is contained in:
nicole mikołajczyk 2025-10-08 05:04:55 +02:00
commit 5ce3c12c28
641 changed files with 5697 additions and 1718 deletions

View file

@ -1,4 +1,4 @@
image: git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.14.5-otp-25 image: git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.15.8-otp-26
variables: &global_variables variables: &global_variables
# Only used for the release # Only used for the release
@ -14,9 +14,10 @@ variables: &global_variables
workflow: workflow:
rules: rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" - if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "develop"
- if: $CI_COMMIT_BRANCH == "stable"
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
when: never when: never
- if: $CI_COMMIT_BRANCH
cache: &global_cache_policy cache: &global_cache_policy
key: $CI_JOB_IMAGE-$CI_COMMIT_SHORT_SHA key: $CI_JOB_IMAGE-$CI_COMMIT_SHORT_SHA
@ -71,7 +72,7 @@ check-changelog:
tags: tags:
- amd64 - amd64
build-1.14.5-otp-25: build-1.15.8-otp-26:
extends: extends:
- .build_changes_policy - .build_changes_policy
- .using-ci-base - .using-ci-base
@ -79,12 +80,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
@ -119,7 +120,7 @@ benchmark:
- mix ecto.migrate - mix ecto.migrate
- mix pleroma.load_testing - mix pleroma.load_testing
unit-testing-1.14.5-otp-25: unit-testing-1.15.8-otp-26:
extends: extends:
- .build_changes_policy - .build_changes_policy
- .using-ci-base - .using-ci-base
@ -131,10 +132,25 @@ unit-testing-1.14.5-otp-25:
- name: postgres:13-alpine - name: postgres:13-alpine
alias: postgres alias: postgres
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
before_script: &testing_before_script
- echo $MIX_ENV
- rm -rf _build/*/lib/pleroma
# Create a non-root user for running tests
- useradd -m -s /bin/bash testuser
# Install dependencies as root first
- mix deps.get
# Set proper ownership for everything
- chown -R testuser:testuser .
- chown -R testuser:testuser /root/.mix || true
- chown -R testuser:testuser /root/.hex || true
# Create user-specific directories
- su testuser -c "HOME=/home/testuser mix local.hex --force"
- su testuser -c "HOME=/home/testuser mix local.rebar --force"
script: &testing_script script: &testing_script
- mix ecto.create # Run tests as non-root user
- mix ecto.migrate - su testuser -c "HOME=/home/testuser mix ecto.create"
- mix pleroma.test_runner --cover --preload-modules - su testuser -c "HOME=/home/testuser mix ecto.migrate"
- su testuser -c "HOME=/home/testuser mix pleroma.test_runner --cover --preload-modules"
coverage: '/^Line total: ([^ ]*%)$/' coverage: '/^Line total: ([^ ]*%)$/'
artifacts: artifacts:
reports: reports:
@ -142,14 +158,15 @@ 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
before_script: *testing_before_script
script: *testing_script script: *testing_script
formatting-1.15: formatting-1.15:
@ -208,7 +225,7 @@ docs-deploy:
before_script: before_script:
- apk add curl - apk add curl
script: script:
- curl --fail-with-body -X POST -F"token=$CI_JOB_TOKEN" -F'ref=master' -F"variables[BRANCH]=$CI_COMMIT_REF_NAME" https://git.pleroma.social/api/v4/projects/673/trigger/pipeline - curl --fail-with-body -X POST -F"token=$DOCS_PIPELINE_TRIGGER" -F'ref=master' -F"variables[BRANCH]=$CI_COMMIT_REF_NAME" https://git.pleroma.social/api/v4/projects/673/trigger/pipeline
review_app: review_app:
image: alpine:3.9 image: alpine:3.9
stage: deploy stage: deploy
@ -249,7 +266,7 @@ spec-deploy:
before_script: before_script:
- apk add curl - apk add curl
script: script:
- curl --fail-with-body -X POST -F"token=$CI_JOB_TOKEN" -F'ref=master' -F"variables[BRANCH]=$CI_COMMIT_REF_NAME" -F"variables[JOB_REF]=$CI_JOB_ID" https://git.pleroma.social/api/v4/projects/1130/trigger/pipeline - curl --fail-with-body -X POST -F"token=$API_DOCS_PIPELINE_TRIGGER" -F'ref=master' -F"variables[BRANCH]=$CI_COMMIT_REF_NAME" -F"variables[JOB_REF]=$CI_JOB_ID" https://git.pleroma.social/api/v4/projects/1130/trigger/pipeline
stop_review_app: stop_review_app:
@ -273,7 +290,7 @@ stop_review_app:
amd64: amd64:
stage: release stage: release
image: image:
name: hexpm/elixir-amd64:1.17.3-erlang-26.2.5.6-ubuntu-focal-20241011 name: hexpm/elixir-amd64:1.17.3-erlang-27.3.4.2-ubuntu-noble-20250716
only: &release-only only: &release-only
- stable@pleroma/pleroma - stable@pleroma/pleroma
- develop@pleroma/pleroma - develop@pleroma/pleroma
@ -300,7 +317,7 @@ amd64:
VIX_COMPILATION_MODE: PLATFORM_PROVIDED_LIBVIPS VIX_COMPILATION_MODE: PLATFORM_PROVIDED_LIBVIPS
DEBIAN_FRONTEND: noninteractive DEBIAN_FRONTEND: noninteractive
before_script: &before-release before_script: &before-release
- apt-get update && apt-get install -y cmake libmagic-dev libvips-dev erlang-dev git - apt-get update && apt-get install -y cmake libmagic-dev libvips-dev erlang-dev git build-essential
- echo "import Config" > config/prod.secret.exs - echo "import Config" > config/prod.secret.exs
- mix local.hex --force - mix local.hex --force
- mix local.rebar --force - mix local.rebar --force
@ -316,7 +333,7 @@ amd64-musl:
artifacts: *release-artifacts artifacts: *release-artifacts
only: *release-only only: *release-only
image: image:
name: hexpm/elixir-amd64:1.17.3-erlang-26.2.5.6-alpine-3.17.9 name: hexpm/elixir-amd64:1.17.3-erlang-27.3.4.2-alpine-3.22.1
tags: tags:
- amd64 - amd64
cache: *release-cache cache: *release-cache
@ -360,7 +377,7 @@ arm64:
tags: tags:
- arm - arm
image: image:
name: hexpm/elixir-arm64:1.17.3-erlang-26.2.5.6-ubuntu-focal-20241011 name: hexpm/elixir-arm64:1.17.3-erlang-27.3.4.2-ubuntu-noble-20250716
cache: *release-cache cache: *release-cache
variables: *release-variables variables: *release-variables
before_script: *before-release before_script: *before-release
@ -373,7 +390,7 @@ arm64-musl:
tags: tags:
- arm - arm
image: image:
name: hexpm/elixir-arm64:1.17.3-erlang-26.2.5.6-alpine-3.17.9 name: hexpm/elixir-arm64:1.17.3-erlang-27.3.4.2-alpine-3.22.1
cache: *release-cache cache: *release-cache
variables: *release-variables variables: *release-variables
before_script: *before-release-musl before_script: *before-release-musl

View file

@ -1,10 +1,10 @@
# https://hub.docker.com/r/hexpm/elixir/tags # https://hub.docker.com/r/hexpm/elixir/tags
ARG ELIXIR_IMG=hexpm/elixir ARG ELIXIR_IMG=hexpm/elixir
ARG ELIXIR_VER=1.14.5 ARG ELIXIR_VER=1.17.3
ARG ERLANG_VER=25.3.2.14 ARG ERLANG_VER=26.2.5.6
ARG ALPINE_VER=3.17.9 ARG ALPINE_VER=3.17.9
FROM ${ELIXIR_IMG}:${ELIXIR_VER}-erlang-${ERLANG_VER}-alpine-${ALPINE_VER} as build FROM ${ELIXIR_IMG}:${ELIXIR_VER}-erlang-${ERLANG_VER}-alpine-${ALPINE_VER} AS build
COPY . . COPY . .
@ -15,6 +15,7 @@ RUN apk add git gcc g++ musl-dev make cmake file-dev vips-dev &&\
echo "import Config" > config/prod.secret.exs &&\ echo "import Config" > config/prod.secret.exs &&\
mix local.hex --force &&\ mix local.hex --force &&\
mix local.rebar --force &&\ mix local.rebar --force &&\
mix deps.clean --all &&\
mix deps.get --only prod &&\ mix deps.get --only prod &&\
mkdir release &&\ mkdir release &&\
mix release --path release mix release --path release

View file

@ -0,0 +1 @@
Fix 'Create a user' description in admin api docs

View file

View file

@ -0,0 +1 @@
Admin API: Fixed self-revocation vulnerability where admins could accidentally revoke their own admin status via the single-user permission endpoint

View file

@ -0,0 +1 @@
Fix AssignAppUser migration OOM

View file

@ -0,0 +1 @@
- Fix building "captcha" library with OpenBSD make

View file

@ -0,0 +1 @@
Docs: Restore DB schema before data to avoid long restore times

View file

@ -0,0 +1 @@
Return 404 with a better error message instead of 400 when receiving an activity for a deactivated user

View file

@ -0,0 +1 @@
Use JSON for DeepL API requests

View file

@ -0,0 +1 @@
Deleting an instance queues individual jobs for each user that needs to be deleted from the server.

View file

View file

@ -0,0 +1 @@
Support Dislike activity, as sent by Mitra and Friendica, by changing it into a thumbs-down EmojiReact

View file

View file

@ -0,0 +1 @@
Update Dockerfile to use Elixir 1.17.3, Erlang 26.2.5.6, and Alpine 3.17.9 to match CI release builds

1
changelog.d/docs.skip Normal file
View file

@ -0,0 +1 @@
Update *Differences in Mastodon API responses from vanilla Mastodon*

View file

@ -0,0 +1 @@
Elixir 1.18: Fixed warnings and new deprecations

View file

@ -0,0 +1 @@
Added a way to upload new packs from a URL or ZIP file via Admin API

View file

@ -0,0 +1 @@
Fix endorsement state display in relationship view

View file

@ -0,0 +1 @@
Add `duration` to the block endpoint, which makes block expire

View file

@ -0,0 +1 @@
Expose markup configuration in InstanceView

View file

@ -0,0 +1 @@
Fix reports being rejected when the activity had an empty CC or TO field (instead of not having them at all)

View file

View file

1
changelog.d/gun.change Normal file
View file

@ -0,0 +1 @@
Update Cowboy, Gun, and Plug family of dependencies

View file

@ -0,0 +1 @@
Hashtag searches return real results based on words in your query

View file

@ -0,0 +1 @@
Fix ModerationLog FunctionClauseError for unknown actions

View file

@ -0,0 +1 @@
Added MRF.QuietReply which prevents replies to public posts from being published to the timelines

View file

View file

@ -0,0 +1 @@
Add `update` to @notification_types

View file

@ -0,0 +1 @@
Oban.Plugins.Lazarus to help recover stuck jobs from an unclean shutdown of Pleroma

View file

@ -0,0 +1 @@
Oban Notifier was changed to Oban.Notifiers.PG for performance and scalability benefits

View file

View file

@ -0,0 +1 @@
Updated relayd/httpd config files to be on par with nginx

View file

@ -0,0 +1 @@
replaced depracated flags and functions, renamed service to fit other service files

View file

@ -0,0 +1,2 @@
Update Pleroma-FE to 2.9.2

View file

@ -0,0 +1 @@
Updated Postgrex library to 0.20.0

View file

@ -0,0 +1 @@
Fix federation issue where Public visibility information in cc field was lost when sent to remote servers, causing posts to appear with inconsistent visibility across instances

View file

View file

@ -0,0 +1 @@
Improved the logic of how we determine if a server is unreachable.

View file

@ -0,0 +1 @@
Relax alsoKnownAs requirements to just URI, not necessarily HTTP(S)

View file

View file

@ -0,0 +1 @@
Allow anonymizing reports sent to remote servers

View file

@ -0,0 +1 @@
Add only_reblogs parameter to account statuses API for filtering to show only reblogs/reposts

View file

@ -0,0 +1 @@
Change scrobble external link param name to use snake case

View file

@ -0,0 +1 @@
Change SMTP example to use the Mua adapter that works with OTP>25

1
changelog.d/tesla.change Normal file
View file

@ -0,0 +1 @@
Updated Tesla to 1.15.3

View file

@ -0,0 +1 @@
Backport [Elixir PR 14242](https://github.com/elixir-lang/elixir/pull/14242) fixing racy mkdir and lack of error handling of parent directory creation

View file

@ -0,0 +1 @@
Allow Terms of Service panel behaviour to be configurable

1
changelog.d/typo.skip Normal file
View file

@ -0,0 +1 @@
Fix typo in test name

View file

@ -0,0 +1 @@
Update voters count in remote polls when refreshing

View file

@ -0,0 +1 @@
Fix HTTP client making invalid requests due to no percent encoding processing or validation.

View file

@ -0,0 +1 @@
Enforce an exact domain match for WebFinger resolution

View file

@ -0,0 +1 @@
Don't require an Accept header for WebFinger queries and default to JSON.

View 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

View 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 .

View file

@ -194,7 +194,6 @@ config :pleroma, :instance,
account_approval_required: false, account_approval_required: false,
federating: true, federating: true,
federation_incoming_replies_max_depth: 100, federation_incoming_replies_max_depth: 100,
federation_reachability_timeout_days: 7,
allow_relay: true, allow_relay: true,
public: true, public: true,
quarantined_instances: [], quarantined_instances: [],
@ -307,6 +306,7 @@ config :pleroma, :frontend_configurations,
collapseMessageWithSubject: false, collapseMessageWithSubject: false,
disableChat: false, disableChat: false,
greentext: false, greentext: false,
embeddedToS: true,
hideFilteredStatuses: false, hideFilteredStatuses: false,
hideMutedPosts: false, hideMutedPosts: false,
hidePostStats: false, hidePostStats: false,
@ -364,7 +364,9 @@ config :pleroma, :activitypub,
note_replies_output_limit: 5, note_replies_output_limit: 5,
sign_object_fetches: true, sign_object_fetches: true,
authorized_fetch_mode: false, authorized_fetch_mode: false,
client_api_enabled: false client_api_enabled: false,
anonymize_reporter: false,
anonymize_reporter_local_nickname: ""
config :pleroma, :streamer, config :pleroma, :streamer,
workers: 3, workers: 3,
@ -589,6 +591,7 @@ config :pleroma, Pleroma.User,
# value or it cannot enforce uniqueness. # value or it cannot enforce uniqueness.
config :pleroma, Oban, config :pleroma, Oban,
repo: Pleroma.Repo, repo: Pleroma.Repo,
notifier: Oban.Notifiers.PG,
log: false, log: false,
queues: [ queues: [
activity_expiration: 10, activity_expiration: 10,
@ -599,7 +602,7 @@ config :pleroma, Oban,
search_indexing: [limit: 10, paused: true], search_indexing: [limit: 10, paused: true],
slow: 5 slow: 5
], ],
plugins: [{Oban.Plugins.Pruner, max_age: 900}], plugins: [Oban.Plugins.Lazarus, {Oban.Plugins.Pruner, max_age: 900}],
crontab: [ crontab: [
{"0 0 * * 0", Pleroma.Workers.Cron.DigestEmailsWorker}, {"0 0 * * 0", Pleroma.Workers.Cron.DigestEmailsWorker},
{"0 0 * * *", Pleroma.Workers.Cron.NewUsersDigestWorker}, {"0 0 * * *", Pleroma.Workers.Cron.NewUsersDigestWorker},

View file

@ -1261,6 +1261,7 @@ config :pleroma, :config_description, [
background: "/static/aurora_borealis.jpg", background: "/static/aurora_borealis.jpg",
collapseMessageWithSubject: false, collapseMessageWithSubject: false,
greentext: false, greentext: false,
embeddedToS: true,
hideFilteredStatuses: false, hideFilteredStatuses: false,
hideMutedPosts: false, hideMutedPosts: false,
hidePostStats: false, hidePostStats: false,
@ -1312,6 +1313,12 @@ config :pleroma, :config_description, [
type: :boolean, type: :boolean,
description: "Enables green text on lines prefixed with the > character" description: "Enables green text on lines prefixed with the > character"
}, },
%{
key: :embeddedToS,
label: "Embedded ToS panel",
type: :boolean,
description: "Hide Terms of Service panel decorations on About and Registration pages"
},
%{ %{
key: :hideFilteredStatuses, key: :hideFilteredStatuses,
label: "Hide Filtered Statuses", label: "Hide Filtered Statuses",
@ -1790,6 +1797,23 @@ config :pleroma, :config_description, [
key: :client_api_enabled, key: :client_api_enabled,
type: :boolean, type: :boolean,
description: "Allow client to server ActivityPub interactions" description: "Allow client to server ActivityPub interactions"
},
%{
key: :anonymize_reporter,
type: :boolean,
label: "Anonymize local reports",
description:
"If true, replace local reporters with the designated local user for the copy to be sent to remote servers"
},
%{
key: :anonymize_reporter_local_nickname,
type: :string,
label: "Anonymized reporter",
description:
"The nickname of the designated local user that replaces the actual reporter in the copy to be sent to remote servers",
suggestions: [
"lain"
]
} }
] ]
}, },

View file

@ -170,6 +170,10 @@ config :pleroma, Pleroma.Upload.Filter.Mogrify, config_impl: Pleroma.StaticStubb
config :pleroma, Pleroma.Upload.Filter.Mogrify, mogrify_impl: Pleroma.MogrifyMock config :pleroma, Pleroma.Upload.Filter.Mogrify, mogrify_impl: Pleroma.MogrifyMock
config :pleroma, Pleroma.Signature, http_signatures_impl: Pleroma.StubbedHTTPSignaturesMock config :pleroma, Pleroma.Signature, http_signatures_impl: Pleroma.StubbedHTTPSignaturesMock
config :pleroma, Pleroma.Web.ActivityPub.Publisher, signature_impl: Pleroma.SignatureMock
config :pleroma, Pleroma.Web.ActivityPub.Publisher,
transmogrifier_impl: Pleroma.Web.ActivityPub.TransmogrifierMock
peer_module = peer_module =
if String.to_integer(System.otp_release()) >= 25 do if String.to_integer(System.otp_release()) >= 25 do

View file

@ -2,28 +2,60 @@
## Backup ## Backup
1. Stop the Pleroma service. 1. Stop the Pleroma service:
2. Go to the working directory of Pleroma (default is `/opt/pleroma`) ```
3. Run `sudo -Hu postgres pg_dump -d <pleroma_db> --format=custom -f </path/to/backup_location/pleroma.pgdump>` (make sure the postgres user has write access to the destination file) # sudo systemctl stop pleroma
```
2. Go to the working directory of Pleroma (default is `/opt/pleroma`).
3. Run (make sure the postgres user has write access to the destination file):
```
# sudo -Hu postgres pg_dump -d <pleroma_db> -v --format=custom --compress=9 -f </path/to/backup_location/pleroma.pgdump>
```
4. Copy `pleroma.pgdump`, `config/prod.secret.exs`, `config/setup_db.psql` (if still available) and the `uploads` folder to your backup destination. If you have other modifications, copy those changes too. 4. Copy `pleroma.pgdump`, `config/prod.secret.exs`, `config/setup_db.psql` (if still available) and the `uploads` folder to your backup destination. If you have other modifications, copy those changes too.
5. Restart the Pleroma service. 5. Restart the Pleroma service:
```
# sudo systemctl start pleroma
```
## Restore/Move ## Restore/Move
1. Optionally reinstall Pleroma (either on the same server or on another server if you want to move servers). 1. Optionally reinstall Pleroma (either on the same server or on another server if you want to move servers).
2. Stop the Pleroma service. 2. Stop the Pleroma service:
3. Go to the working directory of Pleroma (default is `/opt/pleroma`) ```
# sudo systemctl stop pleroma
```
3. Go to the working directory of Pleroma (default is `/opt/pleroma`).
4. Copy the above mentioned files back to their original position. 4. Copy the above mentioned files back to their original position.
5. Drop the existing database and user if restoring in-place. `sudo -Hu postgres psql -c 'DROP DATABASE <pleroma_db>;';` `sudo -Hu postgres psql -c 'DROP USER <pleroma_db>;'` 5. Drop the existing database and user if restoring in-place:
6. Restore the database schema and pleroma postgres role the with the original `setup_db.psql` if you have it: `sudo -Hu postgres psql -f config/setup_db.psql`. ```
# sudo -Hu postgres dropdb <pleroma_db>
# sudo -Hu postgres dropuser <pleroma_user>
```
6. Restore the database schema and pleroma database user the with the original `setup_db.psql` if you have it:
```
# sudo -Hu postgres psql -f config/setup_db.psql
```
Alternatively, run the `mix pleroma.instance gen` task again. You can ignore most of the questions, but make the database user, name, and password the same as found in your backup of `config/prod.secret.exs`. Then run the restoration of the pleroma role and schema with of the generated `config/setup_db.psql` as instructed above. You may delete the `config/generated_config.exs` file as it is not needed. Alternatively, run the `mix pleroma.instance gen` task again. You can ignore most of the questions, but make the database user, name, and password the same as found in your backup of `config/prod.secret.exs`. Then run the restoration of the pleroma user and schema with the generated `config/setup_db.psql` as instructed above. You may delete the `config/generated_config.exs` file as it is not needed.
7. Now restore the Pleroma instance's data into the empty database schema: `sudo -Hu postgres pg_restore -d <pleroma_db> -v -1 </path/to/backup_location/pleroma.pgdump>` 7. Now restore the Pleroma instance's schema into the empty database schema:
8. If you installed a newer Pleroma version, you should run `mix ecto.migrate`[^1]. This task performs database migrations, if there were any. ```
9. Restart the Pleroma service. # sudo -Hu postgres pg_restore -d <pleroma_db> -v -s -1 </path/to/backup_location/pleroma.pgdump>
10. Run `sudo -Hu postgres vacuumdb --all --analyze-in-stages`. This will quickly generate the statistics so that postgres can properly plan queries. ```
11. If setting up on a new server configure Nginx by using the `installation/pleroma.nginx` config sample or reference the Pleroma installation guide for your OS which contains the Nginx configuration instructions. 8. Now restore the Pleroma instance's data into the database:
```
# sudo -Hu postgres pg_restore -d <pleroma_db> -v -a -1 --disable-triggers </path/to/backup_location/pleroma.pgdump>
```
9. If you installed a newer Pleroma version, you should run `mix ecto.migrate`[^1]. This task performs database migrations, if there were any.
10. Generate the statistics so that PostgreSQL can properly plan queries:
```
# sudo -Hu postgres vacuumdb -v --all --analyze-in-stages
```
11. Restart the Pleroma service:
```
# sudo systemctl start pleroma
```
12. If setting up on a new server, configure Nginx by using your original configuration or by using the `installation/pleroma.nginx` config sample or reference the Pleroma installation guide for your OS which contains the Nginx configuration instructions.
[^1]: Prefix with `MIX_ENV=prod` to run it using the production config file. [^1]: Prefix with `MIX_ENV=prod` to run it using the production config file.
@ -32,10 +64,26 @@
1. Optionally you can remove the users of your instance. This will trigger delete requests for their accounts and posts. Note that this is 'best effort' and doesn't mean that all traces of your instance will be gone from the fediverse. 1. Optionally you can remove the users of your instance. This will trigger delete requests for their accounts and posts. Note that this is 'best effort' and doesn't mean that all traces of your instance will be gone from the fediverse.
* You can do this from the admin-FE where you can select all local users and delete the accounts using the *Moderate multiple users* dropdown. * You can do this from the admin-FE where you can select all local users and delete the accounts using the *Moderate multiple users* dropdown.
* You can also list local users and delete them individually using the CLI tasks for [Managing users](./CLI_tasks/user.md). * You can also list local users and delete them individually using the CLI tasks for [Managing users](./CLI_tasks/user.md).
2. Stop the Pleroma service `systemctl stop pleroma` 2. Stop the Pleroma service:
3. Disable pleroma from systemd `systemctl disable pleroma` ```
# systemctl stop pleroma
```
3. Disable pleroma from systemd:
```
# systemctl disable pleroma
```
4. Remove the files and folders you created during installation (see installation guide). This includes the pleroma, nginx and systemd files and folders. 4. Remove the files and folders you created during installation (see installation guide). This includes the pleroma, nginx and systemd files and folders.
5. Reload nginx now that the configuration is removed `systemctl reload nginx` 5. Reload nginx now that the configuration is removed:
6. Remove the database and database user `sudo -Hu postgres psql -c 'DROP DATABASE <pleroma_db>;';` `sudo -Hu postgres psql -c 'DROP USER <pleroma_db>;'` ```
7. Remove the system user `userdel pleroma` # systemctl reload nginx
8. Remove the dependencies that you don't need anymore (see installation guide). Make sure you don't remove packages that are still needed for other software that you have running! ```
6. Remove the database and database user:
```
# sudo -Hu postgres dropdb <pleroma_db>
# sudo -Hu postgres dropuser <pleroma_user>
```
7. Remove the system user:
```
# userdel -r pleroma
```
8. Remove the dependencies that you don't need anymore (see installation guide). **Make sure you don't remove packages that are still needed for other software that you have running!**

View file

@ -28,6 +28,7 @@ Feel free to contact us to be added to this list!
### AndStatus ### AndStatus
- Homepage: <http://andstatus.org/> - Homepage: <http://andstatus.org/>
- Source Code: <https://github.com/andstatus/andstatus/> - Source Code: <https://github.com/andstatus/andstatus/>
- Contact: [@AndStatus@mastodon.social](https://mastodon.social/@AndStatus)
- Platforms: Android - Platforms: Android
- Features: MastoAPI, ActivityPub (Client-to-Server) - Features: MastoAPI, ActivityPub (Client-to-Server)
@ -40,8 +41,8 @@ Feel free to contact us to be added to this list!
### Fedilab ### Fedilab
- Homepage: <https://fedilab.app/> - Homepage: <https://fedilab.app/>
- Source Code: <https://framagit.org/tom79/fedilab/> - Source Code: <https://codeberg.org/tom79/Fedilab>
- Contact: [@fedilab@framapiaf.org](https://framapiaf.org/users/fedilab) - Contact: [@apps@toot.fedilab.app](https://toot.fedilab.app/@apps)
- Platforms: Android - Platforms: Android
- Features: MastoAPI, Streaming Ready, Moderation, Text Formatting - Features: MastoAPI, Streaming Ready, Moderation, Text Formatting
@ -51,8 +52,8 @@ Feel free to contact us to be added to this list!
- Features: MastoAPI, No Streaming - Features: MastoAPI, No Streaming
### Husky ### Husky
- Source code: <https://git.mentality.rip/FWGS/Husky> - Source code: <https://github.com/captainepoch/husky>
- Contact: [@Husky@enigmatic.observer](https://enigmatic.observer/users/Husky) - Contact: [@husky@stereophonic.space](https://stereophonic.space/users/husky)
- Platforms: Android - Platforms: Android
- Features: MastoAPI, No Streaming, Emoji Reactions, Text Formatting, FE Stickers - Features: MastoAPI, No Streaming, Emoji Reactions, Text Formatting, FE Stickers
@ -65,7 +66,7 @@ Feel free to contact us to be added to this list!
### Tusky ### Tusky
- Homepage: <https://tuskyapp.github.io/> - Homepage: <https://tuskyapp.github.io/>
- Source Code: <https://github.com/tuskyapp/Tusky> - Source Code: <https://github.com/tuskyapp/Tusky>
- Contact: [@ConnyDuck@mastodon.social](https://mastodon.social/users/ConnyDuck) - Contact: [@Tusky@mastodon.social](https://mastodon.social/@Tusky)
- Platforms: Android - Platforms: Android
- Features: MastoAPI, No Streaming - Features: MastoAPI, No Streaming
@ -76,10 +77,10 @@ Feel free to contact us to be added to this list!
- Platform: Android - Platform: Android
- Features: MastoAPI, No Streaming - Features: MastoAPI, No Streaming
### Indigenous ### IndiePass
- Homepage: <https://indigenous.realize.be/> - Homepage: <https://indiepass.app/>
- Source Code: <https://github.com/swentel/indigenous-android/> - Source Code: <https://github.com/IndiePass/indiepass-android>
- Contact: [@swentel@realize.be](https://realize.be) - Contact: [@marksuth@mastodon.social](https://mastodon.social/@marksuth)
- Platforms: Android - Platforms: Android
- Features: MastoAPI, No Streaming - Features: MastoAPI, No Streaming

View file

@ -733,13 +733,11 @@ An example for SMTP adapter:
```elixir ```elixir
config :pleroma, Pleroma.Emails.Mailer, config :pleroma, Pleroma.Emails.Mailer,
enabled: true, enabled: true,
adapter: Swoosh.Adapters.SMTP, adapter: Swoosh.Adapters.Mua,
relay: "smtp.gmail.com", relay: "smtp.gmail.com",
username: "YOUR_USERNAME@gmail.com", auth: [username: "YOUR_USERNAME@gmail.com", password: "YOUR_SMTP_PASSWORD"],
password: "YOUR_SMTP_PASSWORD",
port: 465, port: 465,
ssl: true, protocol: :ssl
auth: :always
``` ```
An example for Mua adapter: An example for Mua adapter:

View file

@ -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: Users nickname - Response: Array of user objects
## `POST /api/v1/pleroma/admin/users/follow` ## `POST /api/v1/pleroma/admin/users/follow`

View file

@ -40,10 +40,13 @@ Has these additional fields under the `pleroma` object:
- `parent_visible`: If the parent of this post is visible to the user or not. - `parent_visible`: If the parent of this post is visible to the user or not.
- `pinned_at`: a datetime (iso8601) when status was pinned, `null` otherwise. - `pinned_at`: a datetime (iso8601) when status was pinned, `null` otherwise.
- `quotes_count`: the count of status quotes. - `quotes_count`: the count of status quotes.
- `non_anonymous`: true if the source post specifies the poll results are not anonymous. Currently only implemented by Smithereen.
- `bookmark_folder`: the ID of the folder bookmark is stored within (if any). - `bookmark_folder`: the ID of the folder bookmark is stored within (if any).
- `list_id`: the ID of the list the post is addressed to (if any, only returned to author). - `list_id`: the ID of the list the post is addressed to (if any, only returned to author).
Has these additional fields under the `poll.pleroma` object:
- `non_anonymous`: true if the source post specifies the poll results are not anonymous. Currently only implemented by Smithereen.
The `GET /api/v1/statuses/:id/source` endpoint additionally has the following attributes: The `GET /api/v1/statuses/:id/source` endpoint additionally has the following attributes:
- `content_type`: The content type of the status source. - `content_type`: The content type of the status source.
@ -88,6 +91,7 @@ The `id` parameter can also be the `nickname` of the user. This only works in th
- `only_media`: include only statuses with media attached - `only_media`: include only statuses with media attached
- `with_muted`: include statuses/reactions from muted accounts - `with_muted`: include statuses/reactions from muted accounts
- `exclude_reblogs`: exclude reblogs - `exclude_reblogs`: exclude reblogs
- `only_reblogs`: include only reblogs
- `exclude_replies`: exclude replies - `exclude_replies`: exclude replies
- `exclude_visibilities`: exclude visibilities - `exclude_visibilities`: exclude visibilities
@ -97,6 +101,9 @@ Endpoints which accept `with_relationships` parameter:
- `/api/v1/accounts/:id/followers` - `/api/v1/accounts/:id/followers`
- `/api/v1/accounts/:id/following` - `/api/v1/accounts/:id/following`
- `/api/v1/mutes` - `/api/v1/mutes`
- `/api/v1/blocks`
- `/api/v1/search`
- `/api/v2/search`
Has these additional fields under the `pleroma` object: Has these additional fields under the `pleroma` object:

View file

@ -671,6 +671,7 @@ Audio scrobbling in Pleroma is **deprecated**.
"artist": "Some Artist", "artist": "Some Artist",
"album": "Some Album", "album": "Some Album",
"length": 180000, "length": 180000,
"external_link": "https://www.last.fm/music/Some+Artist/_/Some+Title",
"created_at": "2019-09-28T12:40:45.000Z" "created_at": "2019-09-28T12:40:45.000Z"
} }
] ]

View file

@ -14,7 +14,7 @@ Note: This article is potentially outdated because at this time we may not have
- PostgreSQL 11.0以上 (Ubuntu16.04では9.5しか提供されていないので,[](https://www.postgresql.org/download/linux/ubuntu/)こちらから新しいバージョンを入手してください) - PostgreSQL 11.0以上 (Ubuntu16.04では9.5しか提供されていないので,[](https://www.postgresql.org/download/linux/ubuntu/)こちらから新しいバージョンを入手してください)
- `postgresql-contrib` 11.0以上 (同上) - `postgresql-contrib` 11.0以上 (同上)
- Elixir 1.14 以上 ([Debianのリポジトリからインストールしないこと ここからインストールすること!](https://elixir-lang.org/install.html#unix-and-unix-like)。または [asdf](https://github.com/asdf-vm/asdf) をpleromaユーザーでインストールしてください) - Elixir 1.15 以上 ([Debianのリポジトリからインストールしないこと ここからインストールすること!](https://elixir-lang.org/install.html#unix-and-unix-like)。または [asdf](https://github.com/asdf-vm/asdf) をpleromaユーザーでインストールしてください)
- `erlang-dev` - `erlang-dev`
- `erlang-nox` - `erlang-nox`
- `git` - `git`

View file

@ -1,8 +1,8 @@
## Required dependencies ## Required dependencies
* PostgreSQL >=11.0 * PostgreSQL >=11.0
* Elixir >=1.14.0 <1.17 * Elixir >=1.15.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

View file

@ -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 !}

View file

@ -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

View file

@ -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"
} }

View file

@ -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"
} }

View file

@ -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
} }

View file

@ -26,7 +26,11 @@ defmodule Mix.Pleroma do
Application.put_env(:phoenix, :serve_endpoints, false, persistent: true) Application.put_env(:phoenix, :serve_endpoints, false, persistent: true)
unless System.get_env("DEBUG") do unless System.get_env("DEBUG") do
Logger.remove_backend(:console) try do
Logger.remove_backend(:console)
catch
:exit, _ -> :ok
end
end end
adapter = Application.get_env(:tesla, :adapter) adapter = Application.get_env(:tesla, :adapter)

View file

@ -271,7 +271,7 @@ defmodule Mix.Tasks.Pleroma.Instance do
[config_dir, psql_dir, static_dir, uploads_dir] [config_dir, psql_dir, static_dir, uploads_dir]
|> Enum.reject(&File.exists?/1) |> Enum.reject(&File.exists?/1)
|> Enum.each(fn dir -> |> Enum.each(fn dir ->
File.mkdir_p!(dir) Pleroma.Backports.mkdir_p!(dir)
File.chmod!(dir, 0o700) File.chmod!(dir, 0o700)
end) end)

View file

@ -22,7 +22,7 @@ defmodule Mix.Tasks.Pleroma.RobotsTxt do
static_dir = Pleroma.Config.get([:instance, :static_dir], "instance/static/") static_dir = Pleroma.Config.get([:instance, :static_dir], "instance/static/")
if !File.exists?(static_dir) do if !File.exists?(static_dir) do
File.mkdir_p!(static_dir) Pleroma.Backports.mkdir_p!(static_dir)
end end
robots_txt_path = Path.join(static_dir, "robots.txt") robots_txt_path = Path.join(static_dir, "robots.txt")

View file

@ -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

View file

@ -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

72
lib/pleroma/backports.ex Normal file
View file

@ -0,0 +1,72 @@
# Copyright 2012 Plataformatec
# Copyright 2021 The Elixir Team
# SPDX-License-Identifier: Apache-2.0
defmodule Pleroma.Backports do
import File, only: [dir?: 1]
# <https://github.com/elixir-lang/elixir/pull/14242>
# To be removed when we require Elixir 1.19
@doc """
Tries to create the directory `path`.
Missing parent directories are created. Returns `:ok` if successful, or
`{:error, reason}` if an error occurs.
Typical error reasons are:
* `:eacces` - missing search or write permissions for the parent
directories of `path`
* `:enospc` - there is no space left on the device
* `:enotdir` - a component of `path` is not a directory
"""
@spec mkdir_p(Path.t()) :: :ok | {:error, File.posix() | :badarg}
def mkdir_p(path) do
do_mkdir_p(IO.chardata_to_string(path))
end
defp do_mkdir_p("/") do
:ok
end
defp do_mkdir_p(path) do
parent = Path.dirname(path)
if parent == path do
:ok
else
case do_mkdir_p(parent) do
:ok ->
case :file.make_dir(path) do
{:error, :eexist} ->
if dir?(path), do: :ok, else: {:error, :enotdir}
other ->
other
end
e ->
e
end
end
end
@doc """
Same as `mkdir_p/1`, but raises a `File.Error` exception in case of failure.
Otherwise `:ok`.
"""
@spec mkdir_p!(Path.t()) :: :ok
def mkdir_p!(path) do
case mkdir_p(path) do
:ok ->
:ok
{:error, reason} ->
raise File.Error,
reason: reason,
action: "make directory (with -p)",
path: IO.chardata_to_string(path)
end
end
end

View file

@ -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

View file

@ -100,6 +100,7 @@ defmodule Pleroma.Constants do
"Add", "Add",
"Remove", "Remove",
"Like", "Like",
"Dislike",
"Announce", "Announce",
"Undo", "Undo",
"Flag", "Flag",
@ -115,6 +116,7 @@ defmodule Pleroma.Constants do
"Flag", "Flag",
"Follow", "Follow",
"Like", "Like",
"Dislike",
"EmojiReact", "EmojiReact",
"Announce" "Announce"
] ]

View file

@ -225,6 +225,97 @@ defmodule Pleroma.Emoji.Pack do
end end
end end
def download_zip(name, opts \\ %{}) do
with :ok <- validate_not_empty([name]),
:ok <- validate_new_pack(name),
{:ok, archive_data} <- fetch_archive_data(opts),
pack_path <- path_join_name_safe(emoji_path(), name),
:ok <- create_pack_dir(pack_path),
:ok <- safe_unzip(archive_data, pack_path) do
ensure_pack_json(pack_path, archive_data, opts)
else
{:error, :empty_values} -> {:error, "Pack name cannot be empty"}
{:error, reason} when is_binary(reason) -> {:error, reason}
_ -> {:error, "Could not process pack"}
end
end
defp create_pack_dir(pack_path) do
case File.mkdir_p(pack_path) do
:ok -> :ok
{:error, _} -> {:error, "Could not create the pack directory"}
end
end
defp safe_unzip(archive_data, pack_path) do
case SafeZip.unzip_data(archive_data, pack_path) do
{:ok, _} -> :ok
{:error, reason} when is_binary(reason) -> {:error, reason}
_ -> {:error, "Could not unzip pack"}
end
end
defp validate_new_pack(name) do
pack_path = path_join_name_safe(emoji_path(), name)
if File.exists?(pack_path) do
{:error, "Pack already exists, refusing to import #{name}"}
else
:ok
end
end
defp fetch_archive_data(%{url: url}) do
case Pleroma.HTTP.get(url) do
{:ok, %{status: 200, body: data}} -> {:ok, data}
_ -> {:error, "Could not download pack"}
end
end
defp fetch_archive_data(%{file: %Plug.Upload{path: path}}) do
case File.read(path) do
{:ok, data} -> {:ok, data}
_ -> {:error, "Could not read the uploaded pack file"}
end
end
defp fetch_archive_data(_) do
{:error, "Neither file nor URL was present in the request"}
end
defp ensure_pack_json(pack_path, archive_data, opts) do
pack_json_path = Path.join(pack_path, "pack.json")
if not File.exists?(pack_json_path) do
create_pack_json(pack_path, pack_json_path, archive_data, opts)
end
:ok
end
defp create_pack_json(pack_path, pack_json_path, archive_data, opts) do
emoji_map =
Pleroma.Emoji.Loader.make_shortcode_to_file_map(
pack_path,
Map.get(opts, :exts, [".png", ".gif", ".jpg"])
)
archive_sha = :crypto.hash(:sha256, archive_data) |> Base.encode16()
pack_json = %{
pack: %{
license: Map.get(opts, :license, ""),
homepage: Map.get(opts, :homepage, ""),
description: Map.get(opts, :description, ""),
src: Map.get(opts, :url),
src_sha256: archive_sha
},
files: emoji_map
}
File.write!(pack_json_path, Jason.encode!(pack_json, pretty: true))
end
@spec download(String.t(), String.t(), String.t()) :: {:ok, t()} | {:error, atom()} @spec download(String.t(), String.t(), String.t()) :: {:ok, t()} | {:error, atom()}
def download(name, url, as) do def download(name, url, as) do
uri = url |> String.trim() |> URI.parse() uri = url |> String.trim() |> URI.parse()
@ -488,7 +579,7 @@ defmodule Pleroma.Emoji.Pack do
with true <- String.contains?(file_path, "/"), with true <- String.contains?(file_path, "/"),
path <- Path.dirname(file_path), path <- Path.dirname(file_path),
false <- File.exists?(path) do false <- File.exists?(path) do
File.mkdir_p!(path) Pleroma.Backports.mkdir_p!(path)
end end
end end
@ -536,7 +627,7 @@ defmodule Pleroma.Emoji.Pack do
emoji_path = emoji_path() emoji_path = emoji_path()
# Create the directory first if it does not exist. This is probably the first request made # Create the directory first if it does not exist. This is probably the first request made
# with the API so it should be sufficient # with the API so it should be sufficient
with {:create_dir, :ok} <- {:create_dir, File.mkdir_p(emoji_path)}, with {:create_dir, :ok} <- {:create_dir, Pleroma.Backports.mkdir_p(emoji_path)},
{:ls, {:ok, results}} <- {:ls, File.ls(emoji_path)} do {:ls, {:ok, results}} <- {:ls, File.ls(emoji_path)} do
{:ok, Enum.sort(results)} {:ok, Enum.sort(results)}
else else
@ -561,7 +652,7 @@ defmodule Pleroma.Emoji.Pack do
end end
defp unzip(archive, pack_info, remote_pack, local_pack) do defp unzip(archive, pack_info, remote_pack, local_pack) do
with :ok <- File.mkdir_p!(local_pack.path) do with :ok <- Pleroma.Backports.mkdir_p!(local_pack.path) do
files = Enum.map(remote_pack["files"], fn {_, path} -> path end) files = Enum.map(remote_pack["files"], fn {_, path} -> path end)
# Fallback cannot contain a pack.json file # Fallback cannot contain a pack.json file
files = if pack_info[:fallback], do: files, else: ["pack.json" | files] files = if pack_info[:fallback], do: files, else: ["pack.json" | files]

View file

@ -66,7 +66,7 @@ defmodule Pleroma.Frontend do
def unzip(zip, dest) do def unzip(zip, dest) do
File.rm_rf!(dest) File.rm_rf!(dest)
File.mkdir_p!(dest) Pleroma.Backports.mkdir_p!(dest)
case Pleroma.SafeZip.unzip_data(zip, dest) do case Pleroma.SafeZip.unzip_data(zip, dest) do
{:ok, _} -> :ok {:ok, _} -> :ok
@ -90,7 +90,7 @@ defmodule Pleroma.Frontend do
defp install_frontend(frontend_info, source, dest) do defp install_frontend(frontend_info, source, dest) do
from = frontend_info["build_dir"] || "dist" from = frontend_info["build_dir"] || "dist"
File.rm_rf!(dest) File.rm_rf!(dest)
File.mkdir_p!(dest) Pleroma.Backports.mkdir_p!(dest)
File.cp_r!(Path.join([source, from]), dest) File.cp_r!(Path.join([source, from]), dest)
:ok :ok
end end

View file

@ -22,14 +22,18 @@ defmodule Pleroma.Gopher.Server do
def init([ip, port]) do def init([ip, port]) do
Logger.info("Starting gopher server on #{port}") Logger.info("Starting gopher server on #{port}")
:ranch.start_listener( {:ok, _pid} =
:gopher, :ranch.start_listener(
100, :gopher,
:ranch_tcp, :ranch_tcp,
[ip: ip, port: port], %{
__MODULE__.ProtocolHandler, num_acceptors: 100,
[] max_connections: 100,
) socket_opts: [ip: ip, port: port]
},
__MODULE__.ProtocolHandler,
[]
)
{:ok, %{ip: ip, port: port}} {:ok, %{ip: ip, port: port}}
end end
@ -43,13 +47,13 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.ActivityPub.Visibility
def start_link(ref, socket, transport, opts) do def start_link(ref, transport, opts) do
pid = spawn_link(__MODULE__, :init, [ref, socket, transport, opts]) pid = spawn_link(__MODULE__, :init, [ref, transport, opts])
{:ok, pid} {:ok, pid}
end end
def init(ref, socket, transport, [] = _Opts) do def init(ref, transport, opts \\ []) do
:ok = :ranch.accept_ack(ref) {:ok, socket} = :ranch.handshake(ref, opts)
loop(socket, transport) loop(socket, transport)
end end

View file

@ -130,4 +130,66 @@ defmodule Pleroma.Hashtag do
end end
def get_recipients_for_activity(_activity), do: [] def get_recipients_for_activity(_activity), do: []
def search(query, options \\ []) do
limit = Keyword.get(options, :limit, 20)
offset = Keyword.get(options, :offset, 0)
search_terms =
query
|> String.downcase()
|> String.trim()
|> String.split(~r/\s+/)
|> Enum.filter(&(&1 != ""))
|> Enum.map(&String.trim_leading(&1, "#"))
|> Enum.filter(&(&1 != ""))
if Enum.empty?(search_terms) do
[]
else
# Use PostgreSQL's ANY operator with array for efficient multi-term search
# This is much more efficient than multiple OR clauses
search_patterns = Enum.map(search_terms, &"%#{&1}%")
# Create ranking query that prioritizes exact matches and closer matches
# Use a subquery to properly handle computed columns in ORDER BY
base_query =
from(ht in Hashtag,
where: fragment("LOWER(?) LIKE ANY(?)", ht.name, ^search_patterns),
select: %{
name: ht.name,
# Ranking: exact matches get highest priority (0)
# then prefix matches (1), then contains (2)
match_rank:
fragment(
"""
CASE
WHEN LOWER(?) = ANY(?) THEN 0
WHEN LOWER(?) LIKE ANY(?) THEN 1
ELSE 2
END
""",
ht.name,
^search_terms,
ht.name,
^Enum.map(search_terms, &"#{&1}%")
),
# Secondary sort by name length (shorter names first)
name_length: fragment("LENGTH(?)", ht.name)
}
)
from(result in subquery(base_query),
order_by: [
asc: result.match_rank,
asc: result.name_length,
asc: result.name
],
limit: ^limit,
offset: ^offset
)
|> Repo.all()
|> Enum.map(& &1.name)
end
end
end end

View file

@ -105,20 +105,57 @@ defmodule Pleroma.HTTP do
end end
defp adapter_middlewares(Tesla.Adapter.Gun, extra_middleware) do defp adapter_middlewares(Tesla.Adapter.Gun, extra_middleware) do
[Tesla.Middleware.FollowRedirects, Pleroma.Tesla.Middleware.ConnectionPool] ++ default_middleware() ++
[Pleroma.Tesla.Middleware.ConnectionPool] ++
extra_middleware extra_middleware
end end
defp adapter_middlewares({Tesla.Adapter.Finch, _}, extra_middleware) do
[Tesla.Middleware.FollowRedirects] ++ extra_middleware
end
defp adapter_middlewares(_, extra_middleware) do defp adapter_middlewares(_, extra_middleware) do
if Pleroma.Config.get(:env) == :test do # A lot of tests are written expecting unencoded URLs
# Emulate redirects in test env, which are handled by adapters in other environments # and the burden of fixing that is high. Also it makes
[Tesla.Middleware.FollowRedirects] # them hard to read. Tests will opt-in when we want to validate
else # the encoding is being done correctly.
extra_middleware cond do
Pleroma.Config.get(:env) == :test and Pleroma.Config.get(:test_url_encoding) ->
default_middleware()
Pleroma.Config.get(:env) == :test ->
# Emulate redirects in test env, which are handled by adapters in other environments
[Tesla.Middleware.FollowRedirects]
# Hackney and Finch
true ->
default_middleware() ++ extra_middleware
end end
end end
defp default_middleware,
do: [Tesla.Middleware.FollowRedirects, Pleroma.Tesla.Middleware.EncodeUrl]
def encode_url(url) when is_binary(url) do
URI.parse(url)
|> then(fn parsed ->
path = encode_path(parsed.path)
query = encode_query(parsed.query)
%{parsed | path: path, query: query}
end)
|> URI.to_string()
end
defp encode_path(nil), do: nil
defp encode_path(path) when is_binary(path) do
path
|> URI.decode()
|> URI.encode()
end
defp encode_query(nil), do: nil
defp encode_query(query) when is_binary(query) do
query
|> URI.decode_query()
|> URI.encode_query()
end
end end

View file

@ -15,25 +15,7 @@ defmodule Pleroma.Instances do
defdelegate set_unreachable(url_or_host, unreachable_since \\ nil), to: Instance defdelegate set_unreachable(url_or_host, unreachable_since \\ nil), to: Instance
defdelegate get_consistently_unreachable, to: Instance defdelegate get_unreachable, to: Instance
def set_consistently_unreachable(url_or_host),
do: set_unreachable(url_or_host, reachability_datetime_threshold())
def reachability_datetime_threshold do
federation_reachability_timeout_days =
Pleroma.Config.get([:instance, :federation_reachability_timeout_days], 0)
if federation_reachability_timeout_days > 0 do
NaiveDateTime.add(
NaiveDateTime.utc_now(),
-federation_reachability_timeout_days * 24 * 3600,
:second
)
else
~N[0000-01-01 00:00:00]
end
end
def host(url_or_host) when is_binary(url_or_host) do def host(url_or_host) when is_binary(url_or_host) do
if url_or_host =~ ~r/^http/i do if url_or_host =~ ~r/^http/i do
@ -42,4 +24,21 @@ defmodule Pleroma.Instances do
url_or_host url_or_host
end end
end end
@doc "Schedules reachability checks for all unreachable instances"
def check_all_unreachable do
get_unreachable()
|> Enum.each(fn {domain, _} ->
Pleroma.Workers.ReachabilityWorker.new(%{"domain" => domain})
|> Oban.insert()
end)
end
@doc "Deletes all users and activities for unreachable instances"
def delete_all_unreachable do
get_unreachable()
|> Enum.each(fn {domain, _} ->
Instance.delete(domain)
end)
end
end end

View file

@ -9,7 +9,6 @@ defmodule Pleroma.Instances.Instance do
alias Pleroma.Instances.Instance alias Pleroma.Instances.Instance
alias Pleroma.Maps alias Pleroma.Maps
alias Pleroma.Repo alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Workers.DeleteWorker alias Pleroma.Workers.DeleteWorker
use Ecto.Schema use Ecto.Schema
@ -51,7 +50,7 @@ defmodule Pleroma.Instances.Instance do
|> cast(params, [:software_name, :software_version, :software_repository]) |> cast(params, [:software_name, :software_version, :software_repository])
end end
def filter_reachable([]), do: %{} def filter_reachable([]), do: []
def filter_reachable(urls_or_hosts) when is_list(urls_or_hosts) do def filter_reachable(urls_or_hosts) when is_list(urls_or_hosts) do
hosts = hosts =
@ -68,19 +67,15 @@ defmodule Pleroma.Instances.Instance do
) )
|> Map.new(& &1) |> Map.new(& &1)
reachability_datetime_threshold = Instances.reachability_datetime_threshold()
for entry <- Enum.filter(urls_or_hosts, &is_binary/1) do for entry <- Enum.filter(urls_or_hosts, &is_binary/1) do
host = host(entry) host = host(entry)
unreachable_since = unreachable_since_by_host[host] unreachable_since = unreachable_since_by_host[host]
if !unreachable_since || if is_nil(unreachable_since) do
NaiveDateTime.compare(unreachable_since, reachability_datetime_threshold) == :gt do entry
{entry, unreachable_since}
end end
end end
|> Enum.filter(& &1) |> Enum.filter(& &1)
|> Map.new(& &1)
end end
def reachable?(url_or_host) when is_binary(url_or_host) do def reachable?(url_or_host) when is_binary(url_or_host) do
@ -88,7 +83,7 @@ defmodule Pleroma.Instances.Instance do
from(i in Instance, from(i in Instance,
where: where:
i.host == ^host(url_or_host) and i.host == ^host(url_or_host) and
i.unreachable_since <= ^Instances.reachability_datetime_threshold(), not is_nil(i.unreachable_since),
select: true select: true
) )
) )
@ -97,9 +92,16 @@ defmodule Pleroma.Instances.Instance do
def reachable?(url_or_host) when is_binary(url_or_host), do: true def reachable?(url_or_host) when is_binary(url_or_host), do: true
def set_reachable(url_or_host) when is_binary(url_or_host) do def set_reachable(url_or_host) when is_binary(url_or_host) do
%Instance{host: host(url_or_host)} host = host(url_or_host)
|> changeset(%{unreachable_since: nil})
|> Repo.insert(on_conflict: {:replace, [:unreachable_since]}, conflict_target: :host) result =
%Instance{host: host}
|> changeset(%{unreachable_since: nil})
|> Repo.insert(on_conflict: {:replace, [:unreachable_since]}, conflict_target: :host)
Pleroma.Workers.ReachabilityWorker.delete_jobs_for_host(host)
result
end end
def set_reachable(_), do: {:error, nil} def set_reachable(_), do: {:error, nil}
@ -132,11 +134,9 @@ defmodule Pleroma.Instances.Instance do
def set_unreachable(_, _), do: {:error, nil} def set_unreachable(_, _), do: {:error, nil}
def get_consistently_unreachable do def get_unreachable do
reachability_datetime_threshold = Instances.reachability_datetime_threshold()
from(i in Instance, from(i in Instance,
where: ^reachability_datetime_threshold > i.unreachable_since, where: not is_nil(i.unreachable_since),
order_by: i.unreachable_since, order_by: i.unreachable_since,
select: {i.host, i.unreachable_since} select: {i.host, i.unreachable_since}
) )
@ -296,20 +296,14 @@ defmodule Pleroma.Instances.Instance do
Deletes all users from an instance in a background task, thus also deleting Deletes all users from an instance in a background task, thus also deleting
all of those users' activities and notifications. all of those users' activities and notifications.
""" """
def delete_users_and_activities(host) when is_binary(host) do def delete(host) when is_binary(host) do
DeleteWorker.new(%{"op" => "delete_instance", "host" => host}) DeleteWorker.new(%{"op" => "delete_instance", "host" => host})
|> Oban.insert() |> Oban.insert()
end end
def perform(:delete_instance, host) when is_binary(host) do @doc "Schedules reachability check for instance"
User.Query.build(%{nickname: "@#{host}"}) def check_unreachable(domain) when is_binary(domain) do
|> Repo.chunk_stream(100, :batches) Pleroma.Workers.ReachabilityWorker.new(%{"domain" => domain})
|> Stream.each(fn users -> |> Oban.insert()
users
|> Enum.each(fn user ->
User.perform(:delete, user)
end)
end)
|> Stream.run()
end end
end end

View file

@ -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),

View file

@ -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

View file

@ -24,17 +24,15 @@ defmodule Pleroma.Language.Translation.Deepl do
|> URI.to_string() |> URI.to_string()
case Pleroma.HTTP.post( case Pleroma.HTTP.post(
endpoint <> endpoint,
"?" <> Jason.encode!(%{
URI.encode_query(%{ text: [content],
text: content, source_lang: source_language |> String.upcase(),
source_lang: source_language |> String.upcase(), target_lang: target_language,
target_lang: target_language, tag_handling: "html"
tag_handling: "html" }),
}),
"",
[ [
{"Content-Type", "application/x-www-form-urlencoded"}, {"Content-Type", "application/json"},
{"Authorization", "DeepL-Auth-Key #{api_key()}"} {"Authorization", "DeepL-Auth-Key #{api_key()}"}
] ]
) do ) do

View file

@ -25,7 +25,7 @@ defmodule Pleroma.Language.Translation.Provider do
@callback supported_languages(type :: :string | :target) :: @callback supported_languages(type :: :string | :target) ::
{:ok, [String.t()]} | {:error, atom()} {:ok, [String.t()]} | {:error, atom()}
@callback languages_matrix() :: {:ok, Map.t()} | {:error, atom()} @callback languages_matrix() :: {:ok, map()} | {:error, atom()}
@callback name() :: String.t() @callback name() :: String.t()

View file

@ -575,6 +575,12 @@ defmodule Pleroma.ModerationLog do
"@#{actor_nickname} requested account backup for @#{user_nickname}" "@#{actor_nickname} requested account backup for @#{user_nickname}"
end end
def get_log_entry_message(%ModerationLog{data: data}) do
actor_name = get_in(data, ["actor", "nickname"]) || "unknown"
action = data["action"] || "unknown"
"@#{actor_name} performed action #{action}"
end
defp nicknames_to_string(nicknames) do defp nicknames_to_string(nicknames) do
nicknames nicknames
|> Enum.map(&"@#{&1}") |> Enum.map(&"@#{&1}")

View file

@ -74,6 +74,7 @@ defmodule Pleroma.Notification do
reblog reblog
poll poll
status status
update
} }
def changeset(%Notification{} = notification, attrs) do def changeset(%Notification{} = notification, attrs) do

View file

@ -4,7 +4,6 @@
defmodule Pleroma.Object.Fetcher do defmodule Pleroma.Object.Fetcher do
alias Pleroma.HTTP alias Pleroma.HTTP
alias Pleroma.Instances
alias Pleroma.Maps alias Pleroma.Maps
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.Object.Containment alias Pleroma.Object.Containment
@ -19,8 +18,6 @@ defmodule Pleroma.Object.Fetcher do
require Logger require Logger
require Pleroma.Constants require Pleroma.Constants
@mix_env Mix.env()
@spec reinject_object(struct(), map()) :: {:ok, Object.t()} | {:error, any()} @spec reinject_object(struct(), map()) :: {:ok, Object.t()} | {:error, any()}
defp reinject_object(%Object{data: %{}} = object, new_data) do defp reinject_object(%Object{data: %{}} = object, new_data) do
Logger.debug("Reinjecting object #{new_data["id"]}") Logger.debug("Reinjecting object #{new_data["id"]}")
@ -152,10 +149,6 @@ defmodule Pleroma.Object.Fetcher do
{:ok, body} <- get_object(id), {:ok, body} <- get_object(id),
{:ok, data} <- safe_json_decode(body), {:ok, data} <- safe_json_decode(body),
:ok <- Containment.contain_origin_from_id(id, data) do :ok <- Containment.contain_origin_from_id(id, data) do
if not Instances.reachable?(id) do
Instances.set_reachable(id)
end
{:ok, data} {:ok, data}
else else
{:scheme, _} -> {:scheme, _} ->
@ -178,13 +171,8 @@ defmodule Pleroma.Object.Fetcher do
def fetch_and_contain_remote_object_from_id(_id), def fetch_and_contain_remote_object_from_id(_id),
do: {:error, "id must be a string"} do: {:error, "id must be a string"}
defp check_crossdomain_redirect(final_host, original_url) defp check_crossdomain_redirect(final_host, _original_url) when is_nil(final_host) do
{:cross_domain_redirect, false}
# Handle the common case in tests where responses don't include URLs
if @mix_env == :test do
defp check_crossdomain_redirect(nil, _) do
{:cross_domain_redirect, false}
end
end end
defp check_crossdomain_redirect(final_host, original_url) do defp check_crossdomain_redirect(final_host, original_url) do

View file

@ -5,6 +5,7 @@
defmodule Pleroma.Object.Updater do defmodule Pleroma.Object.Updater do
require Pleroma.Constants require Pleroma.Constants
alias Pleroma.Maps
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.Repo alias Pleroma.Repo
@ -115,6 +116,7 @@ defmodule Pleroma.Object.Updater do
# Choices are the same, but counts are different # Choices are the same, but counts are different
to_be_updated to_be_updated
|> Map.put(key, updated_object[key]) |> Map.put(key, updated_object[key])
|> Maps.put_if_present("votersCount", updated_object["votersCount"])
else else
# Choices (or vote type) have changed, do not allow this # Choices (or vote type) have changed, do not allow this
_ -> to_be_updated _ -> to_be_updated

View file

@ -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

View file

@ -158,6 +158,8 @@ defmodule Pleroma.ReverseProxy do
Logger.debug("#{__MODULE__} #{method} #{url} #{inspect(headers)}") Logger.debug("#{__MODULE__} #{method} #{url} #{inspect(headers)}")
method = method |> String.downcase() |> String.to_existing_atom() method = method |> String.downcase() |> String.to_existing_atom()
url = maybe_encode_url(url)
case client().request(method, url, headers, "", opts) do case client().request(method, url, headers, "", opts) do
{:ok, code, headers, client} when code in @valid_resp_codes -> {:ok, code, headers, client} when code in @valid_resp_codes ->
{:ok, code, downcase_headers(headers), client} {:ok, code, downcase_headers(headers), client}
@ -449,4 +451,18 @@ defmodule Pleroma.ReverseProxy do
_ -> delete_resp_header(conn, "content-length") _ -> delete_resp_header(conn, "content-length")
end end
end end
# Only when Tesla adapter is Hackney or Finch does the URL
# need encoding before Reverse Proxying as both end up
# using the raw Hackney client and cannot leverage our
# EncodeUrl Tesla middleware
# Also do it for test environment
defp maybe_encode_url(url) do
case Application.get_env(:tesla, :adapter) do
Tesla.Adapter.Hackney -> Pleroma.HTTP.encode_url(url)
{Tesla.Adapter.Finch, _} -> Pleroma.HTTP.encode_url(url)
Tesla.Mock -> Pleroma.HTTP.encode_url(url)
_ -> url
end
end
end end

View file

@ -56,10 +56,6 @@ defmodule Pleroma.SafeZip do
{_, true} <- {:safe_path, safe_path?(path)} do {_, true} <- {:safe_path, safe_path?(path)} do
{:cont, {:ok, maybe_add_file(type, path, fl)}} {:cont, {:ok, maybe_add_file(type, path, fl)}}
else else
{:get_type, e} ->
{:halt,
{:error, "Couldn't determine file type of ZIP entry at #{path} (#{inspect(e)})"}}
{:type, _} -> {:type, _} ->
{:halt, {:error, "Potentially unsafe file type in ZIP at: #{path}"}} {:halt, {:error, "Potentially unsafe file type in ZIP at: #{path}"}}

View file

@ -157,26 +157,55 @@ defmodule Pleroma.Search.QdrantSearch do
end end
defmodule Pleroma.Search.QdrantSearch.OpenAIClient do defmodule Pleroma.Search.QdrantSearch.OpenAIClient do
use Tesla
alias Pleroma.Config.Getting, as: Config alias Pleroma.Config.Getting, as: Config
plug(Tesla.Middleware.BaseUrl, Config.get([Pleroma.Search.QdrantSearch, :openai_url])) def post(path, body) do
plug(Tesla.Middleware.JSON) Tesla.post(client(), path, body)
end
plug(Tesla.Middleware.Headers, [ defp client do
{"Authorization", Tesla.client(middleware())
"Bearer #{Pleroma.Config.get([Pleroma.Search.QdrantSearch, :openai_api_key])}"} end
])
defp middleware do
[
{Tesla.Middleware.BaseUrl, Config.get([Pleroma.Search.QdrantSearch, :openai_url])},
Tesla.Middleware.JSON,
{Tesla.Middleware.Headers,
[
{"Authorization", "Bearer #{Config.get([Pleroma.Search.QdrantSearch, :openai_api_key])}"}
]}
]
end
end end
defmodule Pleroma.Search.QdrantSearch.QdrantClient do defmodule Pleroma.Search.QdrantSearch.QdrantClient do
use Tesla
alias Pleroma.Config.Getting, as: Config alias Pleroma.Config.Getting, as: Config
plug(Tesla.Middleware.BaseUrl, Config.get([Pleroma.Search.QdrantSearch, :qdrant_url])) def delete(path) do
plug(Tesla.Middleware.JSON) Tesla.delete(client(), path)
end
plug(Tesla.Middleware.Headers, [ def post(path, body) do
{"api-key", Pleroma.Config.get([Pleroma.Search.QdrantSearch, :qdrant_api_key])} Tesla.post(client(), path, body)
]) end
def put(path, body) do
Tesla.put(client(), path, body)
end
defp client do
Tesla.client(middleware())
end
defp middleware do
[
{Tesla.Middleware.BaseUrl, Config.get([Pleroma.Search.QdrantSearch, :qdrant_url])},
Tesla.Middleware.JSON,
{Tesla.Middleware.Headers,
[
{"api-key", Pleroma.Config.get([Pleroma.Search.QdrantSearch, :qdrant_api_key])}
]}
]
end
end end

Some files were not shown because too many files have changed in this diff Show more