forked from AkkomaGang/akkoma
Compare commits
110 commits
keys-extra
...
develop
Author | SHA1 | Date | |
---|---|---|---|
ad92e504d7 | |||
1ffbaa2924 | |||
2e049037de | |||
a2256b3f9e | |||
054396a99e | |||
a846e60d71 | |||
1be18a9f4c | |||
55fc410f80 | |||
ae40ccb8ca | |||
7ed52838f4 | |||
fe23660a2d | |||
177d420ae7 | |||
b0f2ed6eaa | |||
39cef8b8d2 | |||
3ba743d635 | |||
bd02c3d7de | |||
8de373fa24 | |||
d32c4e89bc | |||
7c095a6b70 | |||
e0428a8f14 | |||
e5619c0895 | |||
833d7661d6 | |||
|
d8c7ed70d0 | ||
e8bf4422ff | |||
bcfbfbcff5 | |||
f2e45d4d4b | |||
7615a11a1e | |||
e3c8c4f24f | |||
67cdc38296 | |||
89d209f486 | |||
087ada3b2e | |||
91bedcfa68 | |||
f19d5d1380 | |||
ff5d197341 | |||
7632765b43 | |||
294de939cb | |||
7583eceb38 | |||
834edfcf96 | |||
79b282dea6 | |||
d1d82782db | |||
|
2b1a252cc7 | ||
f048e0cf1b | |||
416aebb76a | |||
932810c35e | |||
4c7ef1e027 | |||
0f9c9aac38 | |||
c0a99df06a | |||
0cb4c35ee4 | |||
c9b3fcc1d3 | |||
11c5838947 | |||
6ed5be61ff | |||
180dc8b472 | |||
d330c57cda | |||
bd64d07082 | |||
9d2c558f64 | |||
ac25b051ae | |||
c5a44a59db | |||
58d5d9d7bf | |||
b6e8fde4dd | |||
bee10eab5e | |||
13215f5f06 | |||
430b376ded | |||
ccf1007883 | |||
6da783b84d | |||
8f322456a0 | |||
9c876cea21 | |||
9728e2f8f7 | |||
b0f7da9ce0 | |||
fc99c694e6 | |||
fbb13fde76 | |||
cbd236aeb5 | |||
71d3bbd7be | |||
98a3dab10a | |||
88a8086ad3 | |||
40da4e88ea | |||
a2e397a79d | |||
e4332d06b5 | |||
|
661b7fedb6 | ||
|
8b5aca9619 | ||
f101886709 | |||
09fa7227f6 | |||
d5b0720596 | |||
940792f8ba | |||
3c72b48a05 | |||
6475cf127e | |||
a8a231c5b2 | |||
2901fda29c | |||
bd14440386 | |||
|
b312edac4c | ||
3bb31117e6 | |||
2c5c531c35 | |||
a3101a435b | |||
d488cf476e | |||
ca182a0ae7 | |||
495a1a71e8 | |||
cf19d4901f | |||
07539f7825 | |||
0ab2f2ab45 | |||
95ed4931f8 | |||
7cd3954152 | |||
80a4e30be7 | |||
3ff0f46b9f | |||
4ff5293093 | |||
3b197503d2 | |||
c0b2bba55e | |||
4b765b1886 | |||
cba2c5725f | |||
97037c0b53 | |||
|
3947012691 | ||
|
d61b7d4b49 |
81 changed files with 871 additions and 369 deletions
|
@ -6,9 +6,12 @@ depends_on:
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
- &scw-secrets
|
- &scw-secrets
|
||||||
- SCW_ACCESS_KEY
|
SCW_ACCESS_KEY:
|
||||||
- SCW_SECRET_KEY
|
from_secret: SCW_ACCESS_KEY
|
||||||
- SCW_DEFAULT_ORGANIZATION_ID
|
SCW_SECRET_KEY:
|
||||||
|
from_secret: SCW_SECRET_KEY
|
||||||
|
SCW_DEFAULT_ORGANIZATION_ID:
|
||||||
|
from_secret: SCW_DEFAULT_ORGANIZATION_ID
|
||||||
- &setup-hex "mix local.hex --force && mix local.rebar --force"
|
- &setup-hex "mix local.hex --force && mix local.rebar --force"
|
||||||
- &on-release
|
- &on-release
|
||||||
when:
|
when:
|
||||||
|
@ -56,7 +59,7 @@ steps:
|
||||||
release-debian-bookworm:
|
release-debian-bookworm:
|
||||||
image: akkoma/releaser
|
image: akkoma/releaser
|
||||||
<<: *on-release
|
<<: *on-release
|
||||||
secrets: *scw-secrets
|
environment: *scw-secrets
|
||||||
commands:
|
commands:
|
||||||
- export SOURCE=akkoma-amd64.zip
|
- export SOURCE=akkoma-amd64.zip
|
||||||
# AMD64
|
# AMD64
|
||||||
|
@ -85,7 +88,7 @@ steps:
|
||||||
release-debian-bullseye:
|
release-debian-bullseye:
|
||||||
image: akkoma/releaser
|
image: akkoma/releaser
|
||||||
<<: *on-release
|
<<: *on-release
|
||||||
secrets: *scw-secrets
|
environment: *scw-secrets
|
||||||
commands:
|
commands:
|
||||||
- export SOURCE=akkoma-amd64-debian-bullseye.zip
|
- export SOURCE=akkoma-amd64-debian-bullseye.zip
|
||||||
# AMD64
|
# AMD64
|
||||||
|
@ -111,7 +114,7 @@ steps:
|
||||||
release-musl:
|
release-musl:
|
||||||
image: akkoma/releaser
|
image: akkoma/releaser
|
||||||
<<: *on-stable
|
<<: *on-stable
|
||||||
secrets: *scw-secrets
|
environment: *scw-secrets
|
||||||
commands:
|
commands:
|
||||||
- export SOURCE=akkoma-amd64-musl.zip
|
- export SOURCE=akkoma-amd64-musl.zip
|
||||||
- export DEST=scaleway:akkoma-updates/$${CI_COMMIT_TAG:-"$CI_COMMIT_BRANCH"}/akkoma-amd64-musl.zip
|
- export DEST=scaleway:akkoma-updates/$${CI_COMMIT_TAG:-"$CI_COMMIT_BRANCH"}/akkoma-amd64-musl.zip
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
labels:
|
labels:
|
||||||
platform: linux/aarch64
|
platform: linux/arm64
|
||||||
|
|
||||||
depends_on:
|
depends_on:
|
||||||
- test
|
- test
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
- &scw-secrets
|
- &scw-secrets
|
||||||
- SCW_ACCESS_KEY
|
SCW_ACCESS_KEY:
|
||||||
- SCW_SECRET_KEY
|
from_secret: SCW_ACCESS_KEY
|
||||||
- SCW_DEFAULT_ORGANIZATION_ID
|
SCW_SECRET_KEY:
|
||||||
|
from_secret: SCW_SECRET_KEY
|
||||||
|
SCW_DEFAULT_ORGANIZATION_ID:
|
||||||
|
from_secret: SCW_DEFAULT_ORGANIZATION_ID
|
||||||
- &setup-hex "mix local.hex --force && mix local.rebar --force"
|
- &setup-hex "mix local.hex --force && mix local.rebar --force"
|
||||||
- &on-release
|
- &on-release
|
||||||
when:
|
when:
|
||||||
|
@ -56,7 +59,7 @@ steps:
|
||||||
release-debian-bookworm:
|
release-debian-bookworm:
|
||||||
image: akkoma/releaser:arm64
|
image: akkoma/releaser:arm64
|
||||||
<<: *on-release
|
<<: *on-release
|
||||||
secrets: *scw-secrets
|
environment: *scw-secrets
|
||||||
commands:
|
commands:
|
||||||
- export SOURCE=akkoma-arm64.zip
|
- export SOURCE=akkoma-arm64.zip
|
||||||
- export DEST=scaleway:akkoma-updates/$${CI_COMMIT_TAG:-"$CI_COMMIT_BRANCH"}/akkoma-arm64-ubuntu-jammy.zip
|
- export DEST=scaleway:akkoma-updates/$${CI_COMMIT_TAG:-"$CI_COMMIT_BRANCH"}/akkoma-arm64-ubuntu-jammy.zip
|
||||||
|
@ -83,7 +86,7 @@ steps:
|
||||||
release-musl:
|
release-musl:
|
||||||
image: akkoma/releaser:arm64
|
image: akkoma/releaser:arm64
|
||||||
<<: *on-stable
|
<<: *on-stable
|
||||||
secrets: *scw-secrets
|
environment: *scw-secrets
|
||||||
commands:
|
commands:
|
||||||
- export SOURCE=akkoma-arm64-musl.zip
|
- export SOURCE=akkoma-arm64-musl.zip
|
||||||
- export DEST=scaleway:akkoma-updates/$${CI_COMMIT_TAG:-"$CI_COMMIT_BRANCH"}/akkoma-arm64-musl.zip
|
- export DEST=scaleway:akkoma-updates/$${CI_COMMIT_TAG:-"$CI_COMMIT_BRANCH"}/akkoma-arm64-musl.zip
|
||||||
|
|
|
@ -6,10 +6,6 @@ depends_on:
|
||||||
- build-amd64
|
- build-amd64
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
- &scw-secrets
|
|
||||||
- SCW_ACCESS_KEY
|
|
||||||
- SCW_SECRET_KEY
|
|
||||||
- SCW_DEFAULT_ORGANIZATION_ID
|
|
||||||
- &setup-hex "mix local.hex --force && mix local.rebar --force"
|
- &setup-hex "mix local.hex --force && mix local.rebar --force"
|
||||||
- &on-release
|
- &on-release
|
||||||
when:
|
when:
|
||||||
|
@ -49,12 +45,14 @@ variables:
|
||||||
steps:
|
steps:
|
||||||
docs:
|
docs:
|
||||||
<<: *on-point-release
|
<<: *on-point-release
|
||||||
secrets:
|
|
||||||
- SCW_ACCESS_KEY
|
|
||||||
- SCW_SECRET_KEY
|
|
||||||
- SCW_DEFAULT_ORGANIZATION_ID
|
|
||||||
environment:
|
environment:
|
||||||
CI: "true"
|
CI: "true"
|
||||||
|
SCW_ACCESS_KEY:
|
||||||
|
from_secret: SCW_ACCESS_KEY
|
||||||
|
SCW_SECRET_KEY:
|
||||||
|
from_secret: SCW_SECRET_KEY
|
||||||
|
SCW_DEFAULT_ORGANIZATION_ID:
|
||||||
|
from_secret: SCW_DEFAULT_ORGANIZATION_ID
|
||||||
image: python:3.10-slim
|
image: python:3.10-slim
|
||||||
commands:
|
commands:
|
||||||
- apt-get update && apt-get install -y rclone wget git zip
|
- apt-get update && apt-get install -y rclone wget git zip
|
||||||
|
|
|
@ -2,10 +2,6 @@ labels:
|
||||||
platform: linux/amd64
|
platform: linux/amd64
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
- &scw-secrets
|
|
||||||
- SCW_ACCESS_KEY
|
|
||||||
- SCW_SECRET_KEY
|
|
||||||
- SCW_DEFAULT_ORGANIZATION_ID
|
|
||||||
- &setup-hex "mix local.hex --force && mix local.rebar --force"
|
- &setup-hex "mix local.hex --force && mix local.rebar --force"
|
||||||
- &on-release
|
- &on-release
|
||||||
when:
|
when:
|
||||||
|
|
|
@ -17,10 +17,6 @@ matrix:
|
||||||
OTP_VERSION: 26
|
OTP_VERSION: 26
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
- &scw-secrets
|
|
||||||
- SCW_ACCESS_KEY
|
|
||||||
- SCW_SECRET_KEY
|
|
||||||
- SCW_DEFAULT_ORGANIZATION_ID
|
|
||||||
- &setup-hex "mix local.hex --force && mix local.rebar --force"
|
- &setup-hex "mix local.hex --force && mix local.rebar --force"
|
||||||
- &on-release
|
- &on-release
|
||||||
when:
|
when:
|
||||||
|
@ -87,5 +83,5 @@ steps:
|
||||||
- mix ecto.create
|
- mix ecto.create
|
||||||
- mix ecto.migrate
|
- mix ecto.migrate
|
||||||
- mkdir -p test/tmp
|
- mkdir -p test/tmp
|
||||||
- mix test --preload-modules --exclude erratic --exclude federated --exclude mocked
|
- mix test --preload-modules --exclude erratic --exclude federated --exclude mocked || mix test --failed
|
||||||
- mix test --preload-modules --only mocked
|
- mix test --preload-modules --only mocked || mix test --failed
|
||||||
|
|
35
CHANGELOG.md
35
CHANGELOG.md
|
@ -4,10 +4,38 @@ All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
## UNRELEASED
|
## Unreleased
|
||||||
|
|
||||||
|
## 2025.01.01
|
||||||
|
|
||||||
|
Hotfix: Federation could break if a null value found its way into `should_federate?\1`
|
||||||
|
|
||||||
|
## 2025.01
|
||||||
|
|
||||||
|
## Added
|
||||||
|
- New config option `:instance, :cleanup_attachments_delay`
|
||||||
|
- It is now possible to display custom source URLs in akkoma-fe;
|
||||||
|
the settings are part of the frontend configuration
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
- Media proxy no longer attempts to proxy embedded images
|
||||||
|
- Fix significant uneccessary overhead of attachment cleanup;
|
||||||
|
it no longer attempts to cleanup attachments of deleted remote posts
|
||||||
|
- Fix “Delete & Redraft” often losing attachments if attachment cleanup was enabled
|
||||||
|
- ObjectAge policy no longer lets unlisted posts slip through
|
||||||
|
- ObjectAge policy no longer leaks belated DMs and follower-only posts
|
||||||
|
- the NodeINfo endpoint now uses the correct content type
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
- Anonymous objects now federate completely without an id
|
||||||
|
adopting a proposed AP spec errata and restoring federation
|
||||||
|
with e.g. IceShrimp.NET and fedify-based implementations
|
||||||
|
|
||||||
|
## 3.13.3
|
||||||
|
|
||||||
## BREAKING
|
## BREAKING
|
||||||
- Minimum PostgreSQL version is raised to 12
|
- Minimum PostgreSQL version is raised to 12
|
||||||
|
- Swagger UI moved from `/akkoma/swaggerui/` to `/pleroma/swaggerui/`
|
||||||
|
|
||||||
## Added
|
## Added
|
||||||
- Implement [FEP-67ff](https://codeberg.org/fediverse/fep/src/branch/main/fep/67ff/fep-67ff.md) (federation documentation)
|
- Implement [FEP-67ff](https://codeberg.org/fediverse/fep/src/branch/main/fep/67ff/fep-67ff.md) (federation documentation)
|
||||||
|
@ -17,6 +45,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
- Meilisearch: order of results returned from our REST API now actually matches how Meilisearch ranks results
|
- Meilisearch: order of results returned from our REST API now actually matches how Meilisearch ranks results
|
||||||
|
- Emoji are now federated as anonymous objects, fixing issues with
|
||||||
|
some strict servers e.g. rejecting e.g. remote emoji reactions
|
||||||
|
- AP objects with additional JSON-LD profiles beyond ActivityStreams can now be fetched
|
||||||
|
- Single-selection polls no longer expose the voter_count; MastoAPI demands it be null
|
||||||
|
and this confused some clients leading to vote distributions >100%
|
||||||
|
|
||||||
## Changed
|
## Changed
|
||||||
- Refactored Rich Media to cache the content in the database. Fetching operations that could block status rendering have been eliminated.
|
- Refactored Rich Media to cache the content in the database. Fetching operations that could block status rendering have been eliminated.
|
||||||
|
|
|
@ -255,6 +255,7 @@
|
||||||
external_user_synchronization: true,
|
external_user_synchronization: true,
|
||||||
extended_nickname_format: true,
|
extended_nickname_format: true,
|
||||||
cleanup_attachments: false,
|
cleanup_attachments: false,
|
||||||
|
cleanup_attachments_delay: 1800,
|
||||||
multi_factor_authentication: [
|
multi_factor_authentication: [
|
||||||
totp: [
|
totp: [
|
||||||
# digits 6 or 8
|
# digits 6 or 8
|
||||||
|
@ -302,6 +303,7 @@
|
||||||
allow_headings: false,
|
allow_headings: false,
|
||||||
allow_tables: false,
|
allow_tables: false,
|
||||||
allow_fonts: false,
|
allow_fonts: false,
|
||||||
|
allow_math: true,
|
||||||
scrub_policy: [
|
scrub_policy: [
|
||||||
Pleroma.HTML.Scrubber.Default,
|
Pleroma.HTML.Scrubber.Default,
|
||||||
Pleroma.HTML.Transform.MediaProxy
|
Pleroma.HTML.Transform.MediaProxy
|
||||||
|
|
|
@ -1184,7 +1184,7 @@
|
||||||
logoMask: true,
|
logoMask: true,
|
||||||
minimalScopesMode: false,
|
minimalScopesMode: false,
|
||||||
noAttachmentLinks: false,
|
noAttachmentLinks: false,
|
||||||
nsfwCensorImage: "/static/img/nsfw.74818f9.png",
|
nsfwCensorImage: "",
|
||||||
postContentType: "text/plain",
|
postContentType: "text/plain",
|
||||||
redirectRootLogin: "/main/friends",
|
redirectRootLogin: "/main/friends",
|
||||||
redirectRootNoLogin: "/main/all",
|
redirectRootNoLogin: "/main/all",
|
||||||
|
@ -1194,7 +1194,9 @@
|
||||||
showInstanceSpecificPanel: false,
|
showInstanceSpecificPanel: false,
|
||||||
subjectLineBehavior: "email",
|
subjectLineBehavior: "email",
|
||||||
theme: "pleroma-dark",
|
theme: "pleroma-dark",
|
||||||
webPushNotifications: false
|
webPushNotifications: false,
|
||||||
|
backendCommitUrl: "",
|
||||||
|
frontendCommitUrl: ""
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
children: [
|
children: [
|
||||||
|
@ -1285,7 +1287,7 @@
|
||||||
type: {:string, :image},
|
type: {:string, :image},
|
||||||
description:
|
description:
|
||||||
"URL of the image to use for hiding NSFW media attachments in the timeline",
|
"URL of the image to use for hiding NSFW media attachments in the timeline",
|
||||||
suggestions: ["/static/img/nsfw.74818f9.png"]
|
suggestions: [""]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :postContentType,
|
key: :postContentType,
|
||||||
|
@ -1398,6 +1400,18 @@
|
||||||
label: "Stop Gifs",
|
label: "Stop Gifs",
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Whether to pause animated images until they're hovered on"
|
description: "Whether to pause animated images until they're hovered on"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: :backendCommitUrl,
|
||||||
|
label: "Backend Commit URL",
|
||||||
|
type: :string,
|
||||||
|
description: "URL prefix for backend commit hashes"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: :frontendCommitUrl,
|
||||||
|
label: "Frontend Commit URL",
|
||||||
|
type: :string,
|
||||||
|
description: "URL prefix for frontend commit hashes"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -51,7 +51,8 @@
|
||||||
hostname: System.get_env("DB_HOST") || "localhost",
|
hostname: System.get_env("DB_HOST") || "localhost",
|
||||||
pool: Ecto.Adapters.SQL.Sandbox,
|
pool: Ecto.Adapters.SQL.Sandbox,
|
||||||
pool_size: 50,
|
pool_size: 50,
|
||||||
queue_target: 5000
|
queue_target: 5000,
|
||||||
|
log: false
|
||||||
|
|
||||||
config :pleroma, :dangerzone, override_repo_pool_size: true
|
config :pleroma, :dangerzone, override_repo_pool_size: true
|
||||||
|
|
||||||
|
|
|
@ -11,4 +11,4 @@ echo "-- Running migrations..."
|
||||||
mix ecto.migrate
|
mix ecto.migrate
|
||||||
|
|
||||||
echo "-- Starting!"
|
echo "-- Starting!"
|
||||||
mix phx.server
|
elixir --erl "+sbwt none +sbwtdcpu none +sbwtdio none" -S mix phx.server
|
||||||
|
|
|
@ -4,12 +4,12 @@
|
||||||
|
|
||||||
1. Stop the Akkoma service.
|
1. Stop the Akkoma service.
|
||||||
2. Go to the working directory of Akkoma (default is `/opt/akkoma`)
|
2. Go to the working directory of Akkoma (default is `/opt/akkoma`)
|
||||||
3. Run[¹] `sudo -Hu postgres pg_dump -d akkoma --format=custom -f </path/to/backup_location/akkoma.pgdump>` (make sure the postgres user has write access to the destination file)
|
3. Run `sudo -Hu postgres pg_dump -d akkoma --format=custom -f </path/to/backup_location/akkoma.pgdump>`[¹] (make sure the postgres user has write access to the destination file)
|
||||||
4. Copy `akkoma.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 `akkoma.pgdump`, `config/config.exs`[²], `uploads` folder, and [static directory](../configuration/static_dir.md) to your backup destination. If you have other modifications, copy those changes too.
|
||||||
5. Restart the Akkoma service.
|
5. Restart the Akkoma service.
|
||||||
|
|
||||||
[¹]: We assume the database name is "akkoma". If not, you can find the correct name in your config files.
|
[¹]: We assume the database name is "akkoma". If not, you can find the correct name in your configuration files.
|
||||||
[²]: If you've installed using OTP, you need `config/config.exs` instead of `config/prod.secret.exs`.
|
[²]: If you have a from source installation, you need `config/prod.secret.exs` instead of `config/config.exs`. The `config/config.exs` file also exists, but in case of from source installations, it only contains the default values and it is tracked by Git, so you don't need to back it up.
|
||||||
|
|
||||||
## Restore/Move
|
## Restore/Move
|
||||||
|
|
||||||
|
@ -17,19 +17,16 @@
|
||||||
2. Stop the Akkoma service.
|
2. Stop the Akkoma service.
|
||||||
3. Go to the working directory of Akkoma (default is `/opt/akkoma`)
|
3. Go to the working directory of Akkoma (default is `/opt/akkoma`)
|
||||||
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 akkoma;';` `sudo -Hu postgres psql -c 'DROP USER akkoma;'`
|
5. Drop the existing database and user[¹]. `sudo -Hu postgres psql -c 'DROP DATABASE akkoma;';` `sudo -Hu postgres psql -c 'DROP USER akkoma;'`
|
||||||
6. Restore the database schema and akkoma role using either of the following options
|
6. Restore the database schema and akkoma role[¹] (replace the password with the one you find in the configuration file), `sudo -Hu postgres psql -c "CREATE USER akkoma WITH ENCRYPTED PASSWORD '<database-password-wich-you-can-find-in-your-configuration-file>';"` `sudo -Hu postgres psql -c "CREATE DATABASE akkoma OWNER akkoma;"`.
|
||||||
* You can use the original `setup_db.psql` if you have it[²]: `sudo -Hu postgres psql -f config/setup_db.psql`.
|
|
||||||
* Or recreate the database and user yourself (replace the password with the one you find in the config file) `sudo -Hu postgres psql -c "CREATE USER akkoma WITH ENCRYPTED PASSWORD '<database-password-wich-you-can-find-in-your-config-file>'; CREATE DATABASE akkoma OWNER akkoma;"`.
|
|
||||||
7. Now restore the Akkoma instance's data into the empty database schema[¹]: `sudo -Hu postgres pg_restore -d akkoma -v -1 </path/to/backup_location/akkoma.pgdump>`
|
7. Now restore the Akkoma instance's data into the empty database schema[¹]: `sudo -Hu postgres pg_restore -d akkoma -v -1 </path/to/backup_location/akkoma.pgdump>`
|
||||||
8. If you installed a newer Akkoma version, you should run `MIX_ENV=prod mix ecto.migrate`[³]. This task performs database migrations, if there were any.
|
8. If you installed a newer Akkoma version, you should run the database migrations `./bin/pleroma_ctl migrate`[²].
|
||||||
9. Restart the Akkoma service.
|
9. Restart the Akkoma service.
|
||||||
10. Run `sudo -Hu postgres vacuumdb --all --analyze-in-stages`. This will quickly generate the statistics so that postgres can properly plan queries.
|
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/akkoma.nginx` config sample or reference the Akkoma installation guide for your OS which contains the Nginx configuration instructions.
|
11. If setting up on a new server, configure Nginx by using the `installation/nginx/akkoma.nginx` configuration sample or reference the Akkoma installation guide which contains the Nginx configuration instructions.
|
||||||
|
|
||||||
[¹]: We assume the database name and user are both "akkoma". If not, you can find the correct name in your config files.
|
[¹]: We assume the database name and user are both "akkoma". If not, you can find the correct name in your configuration files.
|
||||||
[²]: You can recreate the `config/setup_db.psql` by running 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 backed up config file. This will also create a new `config/generated_config.exs` file which you may delete as it is not needed.
|
[²]: If you have a from source installation, the command is `MIX_ENV=prod mix ecto.migrate`. Note that we prefix with `MIX_ENV=prod` to use the `config/prod.secret.exs` configuration file.
|
||||||
[³]: Prefix with `MIX_ENV=prod` to run it using the production config file.
|
|
||||||
|
|
||||||
## Remove
|
## Remove
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@ To add configuration to your config file, you can copy it from the base config.
|
||||||
* `registration_reason_length`: Maximum registration reason length (default: `500`).
|
* `registration_reason_length`: Maximum registration reason length (default: `500`).
|
||||||
* `external_user_synchronization`: Enabling following/followers counters synchronization for external users.
|
* `external_user_synchronization`: Enabling following/followers counters synchronization for external users.
|
||||||
* `cleanup_attachments`: Remove attachments along with statuses. Does not affect duplicate files and attachments without status. Enabling this will increase load to database when deleting statuses on larger instances.
|
* `cleanup_attachments`: Remove attachments along with statuses. Does not affect duplicate files and attachments without status. Enabling this will increase load to database when deleting statuses on larger instances.
|
||||||
|
* `cleanup_attachments_delay`: How many seconds to wait after post deletion before attempting to deletion; useful for “delete & redraft” functionality (default: `1800`)
|
||||||
* `show_reactions`: Let favourites and emoji reactions be viewed through the API (default: `true`).
|
* `show_reactions`: Let favourites and emoji reactions be viewed through the API (default: `true`).
|
||||||
* `password_reset_token_validity`: The time after which reset tokens aren't accepted anymore, in seconds (default: one day).
|
* `password_reset_token_validity`: The time after which reset tokens aren't accepted anymore, in seconds (default: one day).
|
||||||
* `local_bubble`: Array of domains representing instances closely related to yours. Used to populate the `bubble` timeline. e.g `["example.com"]`, (default: `[]`)
|
* `local_bubble`: Array of domains representing instances closely related to yours. Used to populate the `bubble` timeline. e.g `["example.com"]`, (default: `[]`)
|
||||||
|
@ -338,7 +339,7 @@ config :pleroma, :frontends,
|
||||||
|
|
||||||
* `:primary` - The frontend that will be served at `/`
|
* `:primary` - The frontend that will be served at `/`
|
||||||
* `:admin` - The frontend that will be served at `/pleroma/admin`
|
* `:admin` - The frontend that will be served at `/pleroma/admin`
|
||||||
* `:swagger` - Config for developers to act as an API reference to be served at `/akkoma/swaggerui/` (trailing slash _needed_). Disabled by default.
|
* `:swagger` - Config for developers to act as an API reference to be served at `/pleroma/swaggerui/` (trailing slash _needed_). Disabled by default.
|
||||||
* `:mastodon` - The mastodon-fe configuration. This shouldn't need to be changed. This is served at `/web` when installed.
|
* `:mastodon` - The mastodon-fe configuration. This shouldn't need to be changed. This is served at `/web` when installed.
|
||||||
|
|
||||||
### :static\_fe
|
### :static\_fe
|
||||||
|
|
|
@ -60,4 +60,4 @@ config :pleroma, :frontends,
|
||||||
|
|
||||||
Then run the [pleroma.frontend cli task](../../administration/CLI_tasks/frontend) with the name of `swagger-ui` to install the distribution files.
|
Then run the [pleroma.frontend cli task](../../administration/CLI_tasks/frontend) with the name of `swagger-ui` to install the distribution files.
|
||||||
|
|
||||||
You will now be able to view documentation at `/akkoma/swaggerui`
|
You will now be able to view documentation at `/pleroma/swaggerui`
|
||||||
|
|
|
@ -6,7 +6,7 @@ as soon as the post is received by your instance.
|
||||||
|
|
||||||
## Nginx
|
## Nginx
|
||||||
|
|
||||||
The following are excerpts from the [suggested nginx config](../../../installation/nginx/akkoma.nginx) that demonstrates the necessary config for the media proxy to work.
|
The following are excerpts from the [suggested nginx config](https://akkoma.dev/AkkomaGang/akkoma/src/branch/develop/installation/nginx/akkoma.nginx) that demonstrates the necessary config for the media proxy to work.
|
||||||
|
|
||||||
A `proxy_cache_path` must be defined, for example:
|
A `proxy_cache_path` must be defined, for example:
|
||||||
|
|
||||||
|
|
|
@ -35,32 +35,24 @@ sudo useradd -r -s /bin/false -m -d /var/lib/akkoma -U akkoma
|
||||||
|
|
||||||
### Install Elixir and Erlang
|
### Install Elixir and Erlang
|
||||||
|
|
||||||
|
#### Using `apt`
|
||||||
If your distribution packages a recent enough version of Elixir, you can install it directly from the distro repositories and skip to the next section of the guide:
|
If your distribution packages a recent enough version of Elixir, you can install it directly from the distro repositories and skip to the next section of the guide:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
sudo apt install elixir erlang-dev erlang-nox
|
sudo apt install elixir erlang-dev erlang-nox
|
||||||
```
|
```
|
||||||
|
|
||||||
Otherwise use [asdf](https://github.com/asdf-vm/asdf) to install the latest versions of Elixir and Erlang.
|
#### Using `asdf`
|
||||||
|
If your distribution does not have a recent version of Elxir in their repositories, you can use [asdf](https://asdf-vm.com/) to install a newer version of Elixir and Erlang.
|
||||||
|
|
||||||
First, install some dependencies needed to build Elixir and Erlang:
|
First, install some dependencies needed to build Elixir and Erlang:
|
||||||
```shell
|
```shell
|
||||||
sudo apt install curl unzip build-essential autoconf m4 libncurses5-dev libssh-dev unixodbc-dev xsltproc libxml2-utils libncurses-dev
|
sudo apt install curl unzip build-essential autoconf m4 libncurses5-dev libssh-dev unixodbc-dev xsltproc libxml2-utils libncurses-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
Then login to the `akkoma` user and install asdf:
|
Then login to the `akkoma` user.
|
||||||
```shell
|
|
||||||
git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.11.3
|
|
||||||
```
|
|
||||||
|
|
||||||
Add the following lines to `~/.bashrc`:
|
Install asdf by following steps 1 to 3 on [their website](https://asdf-vm.com/guide/getting-started.html), then restart the shell to load asdf:
|
||||||
```shell
|
|
||||||
. "$HOME/.asdf/asdf.sh"
|
|
||||||
# asdf completions
|
|
||||||
. "$HOME/.asdf/completions/asdf.bash"
|
|
||||||
```
|
|
||||||
|
|
||||||
Restart the shell:
|
|
||||||
```shell
|
```shell
|
||||||
exec $SHELL
|
exec $SHELL
|
||||||
```
|
```
|
||||||
|
@ -69,15 +61,15 @@ Next install Erlang:
|
||||||
```shell
|
```shell
|
||||||
asdf plugin add erlang https://github.com/asdf-vm/asdf-erlang.git
|
asdf plugin add erlang https://github.com/asdf-vm/asdf-erlang.git
|
||||||
export KERL_CONFIGURE_OPTIONS="--disable-debug --without-javac"
|
export KERL_CONFIGURE_OPTIONS="--disable-debug --without-javac"
|
||||||
asdf install erlang 25.3.2.5
|
asdf install erlang 26.2.5.4
|
||||||
asdf global erlang 25.3.2.5
|
asdf global erlang 26.2.5.4
|
||||||
```
|
```
|
||||||
|
|
||||||
Now install Elixir:
|
Now install Elixir:
|
||||||
```shell
|
```shell
|
||||||
asdf plugin-add elixir https://github.com/asdf-vm/asdf-elixir.git
|
asdf plugin-add elixir https://github.com/asdf-vm/asdf-elixir.git
|
||||||
asdf install elixir 1.15.4-otp-25
|
asdf install elixir 1.17.3-otp-26
|
||||||
asdf global elixir 1.15.4-otp-25
|
asdf global elixir 1.17.3-otp-26
|
||||||
```
|
```
|
||||||
|
|
||||||
Confirm that Elixir is installed correctly by checking the version:
|
Confirm that Elixir is installed correctly by checking the version:
|
||||||
|
|
|
@ -6,7 +6,9 @@ probably install frontends.
|
||||||
These are no longer bundled with the distribution and need an extra
|
These are no longer bundled with the distribution and need an extra
|
||||||
command to install.
|
command to install.
|
||||||
|
|
||||||
For most installations, the following will suffice:
|
You **must** run frontend management tasks as the akkoma user,
|
||||||
|
the same way you downloaded the build or cloned the git repo before.
|
||||||
|
But otherwise, for most installations, the following will suffice:
|
||||||
|
|
||||||
=== "OTP"
|
=== "OTP"
|
||||||
```sh
|
```sh
|
||||||
|
@ -28,4 +30,3 @@ For most installations, the following will suffice:
|
||||||
```
|
```
|
||||||
|
|
||||||
For more customised installations, refer to [Frontend Management](../../configuration/frontend_management)
|
For more customised installations, refer to [Frontend Management](../../configuration/frontend_management)
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
## Required dependencies
|
## Required dependencies
|
||||||
|
|
||||||
* PostgreSQL 12+
|
* PostgreSQL 12+
|
||||||
* Elixir 1.14+ (currently tested up to 1.16)
|
* Elixir 1.14+ (currently tested up to 1.17)
|
||||||
* Erlang OTP 25+ (currently tested up to OTP26)
|
* Erlang OTP 25+ (currently tested up to OTP27)
|
||||||
* git
|
* git
|
||||||
* file / libmagic
|
* file / libmagic
|
||||||
* gcc (clang might also work)
|
* gcc (clang might also work)
|
||||||
|
|
|
@ -19,6 +19,9 @@ Environment="MIX_ENV=prod"
|
||||||
; Don't listen epmd on 0.0.0.0
|
; Don't listen epmd on 0.0.0.0
|
||||||
Environment="ERL_EPMD_ADDRESS=127.0.0.1"
|
Environment="ERL_EPMD_ADDRESS=127.0.0.1"
|
||||||
|
|
||||||
|
; Don't busy wait
|
||||||
|
Environment="ERL_AFLAGS=+sbwt none +sbwtdcpu none +sbwtdio none"
|
||||||
|
|
||||||
; Make sure that all paths fit your installation.
|
; Make sure that all paths fit your installation.
|
||||||
; Path to the home directory of the user running the Akkoma service.
|
; Path to the home directory of the user running the Akkoma service.
|
||||||
Environment="HOME=/var/lib/akkoma"
|
Environment="HOME=/var/lib/akkoma"
|
||||||
|
|
|
@ -1,23 +1,43 @@
|
||||||
#!/sbin/openrc-run
|
#!/sbin/openrc-run
|
||||||
supervisor=supervise-daemon
|
supervisor=supervise-daemon
|
||||||
command_user=akkoma:akkoma
|
|
||||||
command_background=1
|
|
||||||
# Ask process to terminate within 30 seconds, otherwise kill it
|
|
||||||
retry="SIGTERM/30/SIGKILL/5"
|
|
||||||
pidfile="/var/run/akkoma.pid"
|
|
||||||
directory=/opt/akkoma
|
|
||||||
healthcheck_delay=60
|
|
||||||
healthcheck_timer=30
|
|
||||||
no_new_privs="yes"
|
no_new_privs="yes"
|
||||||
|
pidfile="/var/run/akkoma.pid"
|
||||||
|
|
||||||
: ${akkoma_port:-4000}
|
# Ask process first to terminate itself within 60s, otherwise kill it
|
||||||
|
retry="SIGTERM/60/SIGKILL/5"
|
||||||
|
|
||||||
# Needs OpenRC >= 0.42
|
# if you really want to use start-stop-daemon instead,
|
||||||
#respawn_max=0
|
# also put the following in the config:
|
||||||
#respawn_delay=5
|
# command_background=1
|
||||||
|
|
||||||
|
# Adjust defaults as needed in /etc/conf.d/akkoma;
|
||||||
|
# no need to directly edit the service file
|
||||||
|
command_user="${command_user:-akkoma:akkoma}"
|
||||||
|
directory="${directory:-/var/lib/akkoma/akkoma}"
|
||||||
|
akkoma_port="${akkoma_port:-4000}"
|
||||||
|
# whether to allow connecting a remote exlixir shell to the running Akkoma instance
|
||||||
|
akkoma_console=${akkoma_console:-NO}
|
||||||
|
|
||||||
|
output_log="${output_log:-/var/log/akkoma}"
|
||||||
|
error_log="${error_log:-/var/log/akkoma}"
|
||||||
|
|
||||||
|
# 0 means unlimited restarts
|
||||||
|
respawn_max="${respawn_max:-0}"
|
||||||
|
respawn_delay="${respawn_delay:-5}"
|
||||||
|
# define respawn period to only count crashes within a
|
||||||
|
# sliding time window towards respawn_max, e.g.:
|
||||||
|
# respawn_period=2850
|
||||||
|
|
||||||
|
healthcheck_delay="${healthcheck_delay:-60}"
|
||||||
|
healthcheck_timer="${healthcheck_timer:-30}"
|
||||||
|
|
||||||
|
MIX_ENV=prod
|
||||||
|
ERL_EPMD_ADDRESS="${ERL_EPMD_ADDRESS:-127.0.0.1}"
|
||||||
|
ERL_AFLAGS="${ERL_AFLAGS:-+sbwt none +sbwtdcpu none +sbwtdio none}"
|
||||||
|
supervise_daemon_args="${supervise_daemon_args} --env MIX_ENV=${MIX_ENV}"
|
||||||
|
supervise_daemon_args="${supervise_daemon_args} --env ERL_EPMD_ADDRESS=${ERL_EPMD_ADDRESS}"
|
||||||
|
supervise_daemon_args="${supervise_daemon_args} --env ERL_AFLAGS='${ERL_AFLAGS}'"
|
||||||
|
|
||||||
# put akkoma_console=YES in /etc/conf.d/akkoma if you want to be able to
|
|
||||||
# connect to akkoma via an elixir console
|
|
||||||
if yesno "${akkoma_console}"; then
|
if yesno "${akkoma_console}"; then
|
||||||
command=elixir
|
command=elixir
|
||||||
command_args="--name akkoma@127.0.0.1 --erl '-kernel inet_dist_listen_min 9001 inet_dist_listen_max 9001 inet_dist_use_interface {127,0,0,1}' -S mix phx.server"
|
command_args="--name akkoma@127.0.0.1 --erl '-kernel inet_dist_listen_min 9001 inet_dist_listen_max 9001 inet_dist_use_interface {127,0,0,1}' -S mix phx.server"
|
||||||
|
@ -31,13 +51,24 @@ else
|
||||||
command_args="phx.server"
|
command_args="phx.server"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export MIX_ENV=prod
|
|
||||||
export ERL_EPMD_ADDRESS=127.0.0.1
|
|
||||||
|
|
||||||
depend() {
|
depend() {
|
||||||
need nginx postgresql
|
need nginx postgresql
|
||||||
}
|
}
|
||||||
|
|
||||||
|
start_pre() {
|
||||||
|
# Ensure logfile ownership and perms are alright
|
||||||
|
checkpath --file --owner "$command_user" "$output_log" "$error_log" \
|
||||||
|
|| eerror "Logfile(s) not owned by $command_user, or not a file!"
|
||||||
|
checkpath --writable "$output_log" "$error_log" \
|
||||||
|
|| eerror "Logfile(s) not writable!"
|
||||||
|
|
||||||
|
# If a recompile is needed perform it with lowest prio
|
||||||
|
# (delaying the actual start) to avoid hogging too much
|
||||||
|
# CPU from other services
|
||||||
|
cd "$directory"
|
||||||
|
doas -u "${command_user%%:*}" env MIX_ENV="$MIX_ENV" nice -n 19 "$command" compile
|
||||||
|
}
|
||||||
|
|
||||||
healthcheck() {
|
healthcheck() {
|
||||||
# put akkoma_health=YES in /etc/conf.d/akkoma if you want healthchecking
|
# put akkoma_health=YES in /etc/conf.d/akkoma if you want healthchecking
|
||||||
# and make sure you have curl installed
|
# and make sure you have curl installed
|
||||||
|
|
|
@ -11,11 +11,13 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
daemon="/usr/local/bin/elixir"
|
daemon="/usr/local/bin/elixir"
|
||||||
daemon_flags="--detached -S /usr/local/bin/mix phx.server"
|
daemon_flags="-S /usr/local/bin/mix phx.server"
|
||||||
daemon_user="_akkoma"
|
daemon_user="_akkoma"
|
||||||
|
daemon_execdir="/home/_akkoma/akkoma"
|
||||||
|
|
||||||
. /etc/rc.d/rc.subr
|
. /etc/rc.d/rc.subr
|
||||||
|
|
||||||
|
rc_bg="YES"
|
||||||
rc_reload=NO
|
rc_reload=NO
|
||||||
pexp="phx.server"
|
pexp="phx.server"
|
||||||
|
|
||||||
|
@ -24,7 +26,7 @@ rc_check() {
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_start() {
|
rc_start() {
|
||||||
${rcexec} "cd akkoma; ${daemon} ${daemon_flags}"
|
rc_exec "${daemon} ${daemon_flags}"
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_stop() {
|
rc_stop() {
|
||||||
|
|
|
@ -343,10 +343,16 @@ def run(["prune_objects" | args]) do
|
||||||
|
|
||||||
%{:num_rows => del_hashtags} =
|
%{:num_rows => del_hashtags} =
|
||||||
"""
|
"""
|
||||||
DELETE FROM hashtags AS ht
|
DELETE FROM hashtags
|
||||||
WHERE NOT EXISTS (
|
USING hashtags AS ht
|
||||||
SELECT 1 FROM hashtags_objects hto
|
LEFT JOIN hashtags_objects hto
|
||||||
WHERE ht.id = hto.hashtag_id)
|
ON ht.id = hto.hashtag_id
|
||||||
|
LEFT JOIN user_follows_hashtag ufht
|
||||||
|
ON ht.id = ufht.hashtag_id
|
||||||
|
WHERE
|
||||||
|
hashtags.id = ht.id
|
||||||
|
AND hto.hashtag_id is NULL
|
||||||
|
AND ufht.hashtag_id is NULL
|
||||||
"""
|
"""
|
||||||
|> Repo.query!()
|
|> Repo.query!()
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,7 @@ def run(["get-packs" | args]) do
|
||||||
|
|
||||||
{:ok, _} =
|
{:ok, _} =
|
||||||
:zip.unzip(binary_archive,
|
:zip.unzip(binary_archive,
|
||||||
cwd: pack_path,
|
cwd: to_charlist(pack_path),
|
||||||
file_list: files_to_unzip
|
file_list: files_to_unzip
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -84,8 +84,14 @@ defp default_config(Swoosh.Adapters.SMTP, conf, _) do
|
||||||
cacerts: os_cacerts,
|
cacerts: os_cacerts,
|
||||||
versions: [:"tlsv1.2", :"tlsv1.3"],
|
versions: [:"tlsv1.2", :"tlsv1.3"],
|
||||||
verify: :verify_peer,
|
verify: :verify_peer,
|
||||||
# some versions have supposedly issues verifying wildcard certs without this
|
|
||||||
server_name_indication: relay,
|
server_name_indication: relay,
|
||||||
|
# This allows wildcard ceritifcates to be verified properly.
|
||||||
|
# The :https parameter simply means to use the HTTPS wildcard format
|
||||||
|
# (as opposed to say LDAP). SMTP servers tend to use the same type of
|
||||||
|
# certs as HTTPS ones so this should work for most.
|
||||||
|
customize_hostname_check: [
|
||||||
|
match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
|
||||||
|
],
|
||||||
# the default of 10 is too restrictive
|
# the default of 10 is too restrictive
|
||||||
depth: 32
|
depth: 32
|
||||||
]
|
]
|
||||||
|
|
|
@ -125,7 +125,7 @@ def add_file(%Pack{} = pack, _, _, %Plug.Upload{content_type: "application/zip"}
|
||||||
{:ok, _emoji_files} =
|
{:ok, _emoji_files} =
|
||||||
:zip.unzip(
|
:zip.unzip(
|
||||||
to_charlist(file.path),
|
to_charlist(file.path),
|
||||||
[{:file_list, Enum.map(emojies, & &1[:path])}, {:cwd, tmp_dir}]
|
[{:file_list, Enum.map(emojies, & &1[:path])}, {:cwd, to_charlist(tmp_dir)}]
|
||||||
)
|
)
|
||||||
|
|
||||||
{_, updated_pack} =
|
{_, updated_pack} =
|
||||||
|
|
|
@ -79,6 +79,10 @@ def unzip(zip, dest) do
|
||||||
|
|
||||||
new_file_path = Path.join(dest, path)
|
new_file_path = Path.join(dest, path)
|
||||||
|
|
||||||
|
new_file_path
|
||||||
|
|> Path.dirname()
|
||||||
|
|> File.rm()
|
||||||
|
|
||||||
new_file_path
|
new_file_path
|
||||||
|> Path.dirname()
|
|> Path.dirname()
|
||||||
|> File.mkdir_p!()
|
|> File.mkdir_p!()
|
||||||
|
|
|
@ -9,7 +9,6 @@ defmodule Pleroma.Object do
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.Config
|
|
||||||
alias Pleroma.Hashtag
|
alias Pleroma.Hashtag
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.Object.Fetcher
|
alias Pleroma.Object.Fetcher
|
||||||
|
@ -241,23 +240,11 @@ def delete(%Object{data: %{"id" => id}} = object) do
|
||||||
with {:ok, _obj} = swap_object_with_tombstone(object),
|
with {:ok, _obj} = swap_object_with_tombstone(object),
|
||||||
deleted_activity = Activity.delete_all_by_object_ap_id(id),
|
deleted_activity = Activity.delete_all_by_object_ap_id(id),
|
||||||
{:ok, _} <- invalid_object_cache(object) do
|
{:ok, _} <- invalid_object_cache(object) do
|
||||||
cleanup_attachments(
|
AttachmentsCleanupWorker.enqueue_if_needed(object.data)
|
||||||
Config.get([:instance, :cleanup_attachments]),
|
|
||||||
%{object: object}
|
|
||||||
)
|
|
||||||
|
|
||||||
{:ok, object, deleted_activity}
|
{:ok, object, deleted_activity}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec cleanup_attachments(boolean(), %{required(:object) => map()}) ::
|
|
||||||
{:ok, Oban.Job.t() | nil}
|
|
||||||
def cleanup_attachments(true, %{object: _} = params) do
|
|
||||||
AttachmentsCleanupWorker.enqueue("cleanup_attachments", params)
|
|
||||||
end
|
|
||||||
|
|
||||||
def cleanup_attachments(_, _), do: {:ok, nil}
|
|
||||||
|
|
||||||
def prune(%Object{data: %{"id" => _id}} = object) do
|
def prune(%Object{data: %{"id" => _id}} = object) do
|
||||||
with {:ok, object} <- Repo.delete(object),
|
with {:ok, object} <- Repo.delete(object),
|
||||||
{:ok, _} <- invalid_object_cache(object) do
|
{:ok, _} <- invalid_object_cache(object) do
|
||||||
|
|
|
@ -12,8 +12,6 @@ defmodule Pleroma.Object.Containment do
|
||||||
spoofing, therefore removal of object containment functions is NOT recommended.
|
spoofing, therefore removal of object containment functions is NOT recommended.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
|
||||||
|
|
||||||
def get_actor(%{"actor" => actor}) when is_binary(actor) do
|
def get_actor(%{"actor" => actor}) when is_binary(actor) do
|
||||||
actor
|
actor
|
||||||
end
|
end
|
||||||
|
@ -50,16 +48,39 @@ def get_object(_) do
|
||||||
defp compare_uris(%URI{host: host} = _id_uri, %URI{host: host} = _other_uri), do: :ok
|
defp compare_uris(%URI{host: host} = _id_uri, %URI{host: host} = _other_uri), do: :ok
|
||||||
defp compare_uris(_id_uri, _other_uri), do: :error
|
defp compare_uris(_id_uri, _other_uri), do: :error
|
||||||
|
|
||||||
defp compare_uris_exact(uri, uri), do: :ok
|
defp uri_strip_slash(%URI{path: path} = uri) when is_binary(path),
|
||||||
|
do: %{uri | path: String.replace_suffix(path, "/", "")}
|
||||||
|
|
||||||
defp compare_uris_exact(%URI{} = id, %URI{} = other),
|
defp uri_strip_slash(uri), do: uri
|
||||||
do: compare_uris_exact(URI.to_string(id), URI.to_string(other))
|
|
||||||
|
|
||||||
defp compare_uris_exact(id_uri, other_uri)
|
# domain names are case-insensitive per spec (other parts of URIs aren’t necessarily)
|
||||||
when is_binary(id_uri) and is_binary(other_uri) do
|
defp uri_normalise_host(%URI{host: host} = uri) when is_binary(host),
|
||||||
norm_id = String.replace_suffix(id_uri, "/", "")
|
do: %{uri | host: String.downcase(host, :ascii)}
|
||||||
norm_other = String.replace_suffix(other_uri, "/", "")
|
|
||||||
if norm_id == norm_other, do: :ok, else: :error
|
defp uri_normalise_host(uri), do: uri
|
||||||
|
|
||||||
|
defp compare_uri_identities(uri, uri), do: :ok
|
||||||
|
|
||||||
|
defp compare_uri_identities(id_uri, other_uri) when is_binary(id_uri) and is_binary(other_uri),
|
||||||
|
do: compare_uri_identities(URI.parse(id_uri), URI.parse(other_uri))
|
||||||
|
|
||||||
|
defp compare_uri_identities(%URI{} = id, %URI{} = other) do
|
||||||
|
normid =
|
||||||
|
%{id | fragment: nil}
|
||||||
|
|> uri_strip_slash()
|
||||||
|
|> uri_normalise_host()
|
||||||
|
|
||||||
|
normother =
|
||||||
|
%{other | fragment: nil}
|
||||||
|
|> uri_strip_slash()
|
||||||
|
|> uri_normalise_host()
|
||||||
|
|
||||||
|
# Conversion back to binary avoids issues from non-normalised deprecated authority field
|
||||||
|
if URI.to_string(normid) == URI.to_string(normother) do
|
||||||
|
:ok
|
||||||
|
else
|
||||||
|
:error
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
|
@ -93,21 +114,13 @@ def contain_origin(id, %{"attributedTo" => actor} = params),
|
||||||
def contain_origin(_id, _data), do: :ok
|
def contain_origin(_id, _data), do: :ok
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Check whether the fetch URL (after redirects) exactly (sans tralining slash) matches either
|
Check whether the fetch URL (after redirects) is the
|
||||||
the canonical ActivityPub id or the objects url field (for display URLs from *key and Mastodon)
|
same location the canonical ActivityPub id points to.
|
||||||
|
|
||||||
Since this is meant to be used for fetches, anonymous or transient objects are not accepted here.
|
Since this is meant to be used for fetches, anonymous or transient objects are not accepted here.
|
||||||
"""
|
"""
|
||||||
def contain_id_to_fetch(url, %{"id" => id} = data) when is_binary(id) do
|
def contain_id_to_fetch(url, %{"id" => id}) when is_binary(id) do
|
||||||
with {:id, :error} <- {:id, compare_uris_exact(id, url)},
|
compare_uri_identities(url, id)
|
||||||
# "url" can be a "Link" object and this is checked before full normalisation
|
|
||||||
display_url <- Transmogrifier.fix_url(data)["url"],
|
|
||||||
true <- display_url != nil do
|
|
||||||
compare_uris_exact(display_url, url)
|
|
||||||
else
|
|
||||||
{:id, :ok} -> :ok
|
|
||||||
_ -> :error
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def contain_id_to_fetch(_url, _data), do: :error
|
def contain_id_to_fetch(_url, _data), do: :error
|
||||||
|
|
|
@ -116,7 +116,7 @@ defp reinject_object(%Object{} = object, new_data) do
|
||||||
@doc "Assumes object already is in our database and refetches from remote to update (e.g. for polls)"
|
@doc "Assumes object already is in our database and refetches from remote to update (e.g. for polls)"
|
||||||
def refetch_object(%Object{data: %{"id" => id}} = object) do
|
def refetch_object(%Object{data: %{"id" => id}} = object) do
|
||||||
with {:local, false} <- {:local, Object.local?(object)},
|
with {:local, false} <- {:local, Object.local?(object)},
|
||||||
{:ok, new_data} <- fetch_and_contain_remote_object_from_id(id),
|
{:ok, new_data} <- fetch_and_contain_remote_object_from_id(id, true),
|
||||||
{:id, true} <- {:id, new_data["id"] == id},
|
{:id, true} <- {:id, new_data["id"] == id},
|
||||||
{:ok, object} <- reinject_object(object, new_data) do
|
{:ok, object} <- reinject_object(object, new_data) do
|
||||||
{:ok, object}
|
{:ok, object}
|
||||||
|
@ -253,14 +253,17 @@ defp maybe_date_fetch(headers, date) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc "Fetches arbitrary remote object and performs basic safety and authenticity checks"
|
@doc """
|
||||||
def fetch_and_contain_remote_object_from_id(id)
|
Fetches arbitrary remote object and performs basic safety and authenticity checks.
|
||||||
|
When the fetch URL is known to already be a canonical AP id, checks are stricter.
|
||||||
|
"""
|
||||||
|
def fetch_and_contain_remote_object_from_id(id, is_ap_id \\ false)
|
||||||
|
|
||||||
def fetch_and_contain_remote_object_from_id(%{"id" => id}),
|
def fetch_and_contain_remote_object_from_id(%{"id" => id}, is_ap_id),
|
||||||
do: fetch_and_contain_remote_object_from_id(id)
|
do: fetch_and_contain_remote_object_from_id(id, is_ap_id)
|
||||||
|
|
||||||
def fetch_and_contain_remote_object_from_id(id) when is_binary(id) do
|
def fetch_and_contain_remote_object_from_id(id, is_ap_id) when is_binary(id) do
|
||||||
Logger.debug("Fetching object #{id} via AP")
|
Logger.debug("Fetching object #{id} via AP [ap_id=#{is_ap_id}]")
|
||||||
|
|
||||||
with {:valid_uri_scheme, true} <- {:valid_uri_scheme, String.starts_with?(id, "http")},
|
with {:valid_uri_scheme, true} <- {:valid_uri_scheme, String.starts_with?(id, "http")},
|
||||||
%URI{} = uri <- URI.parse(id),
|
%URI{} = uri <- URI.parse(id),
|
||||||
|
@ -270,18 +273,31 @@ def fetch_and_contain_remote_object_from_id(id) when is_binary(id) do
|
||||||
{:mrf_accept_check, Pleroma.Web.ActivityPub.MRF.SimplePolicy.check_accept(uri)},
|
{:mrf_accept_check, Pleroma.Web.ActivityPub.MRF.SimplePolicy.check_accept(uri)},
|
||||||
{:local_fetch, :ok} <- {:local_fetch, Containment.contain_local_fetch(id)},
|
{:local_fetch, :ok} <- {:local_fetch, Containment.contain_local_fetch(id)},
|
||||||
{:ok, final_id, body} <- get_object(id),
|
{:ok, final_id, body} <- get_object(id),
|
||||||
|
# a canonical ID shouldn't be a redirect
|
||||||
|
true <- !is_ap_id || final_id == id,
|
||||||
{:ok, data} <- safe_json_decode(body),
|
{:ok, data} <- safe_json_decode(body),
|
||||||
{_, :ok} <- {:strict_id, Containment.contain_id_to_fetch(final_id, data)},
|
{_, :ok} <- {:containment, Containment.contain_origin(final_id, data)},
|
||||||
{_, :ok} <- {:containment, Containment.contain_origin(final_id, data)} do
|
{_, _, :ok} <- {:strict_id, data["id"], Containment.contain_id_to_fetch(final_id, data)} do
|
||||||
unless Instances.reachable?(final_id) do
|
unless Instances.reachable?(final_id) do
|
||||||
Instances.set_reachable(final_id)
|
Instances.set_reachable(final_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
{:ok, data}
|
{:ok, data}
|
||||||
else
|
else
|
||||||
{:strict_id, _} = e ->
|
# E.g. Mastodon and *key serve the AP object directly under their display URLs without
|
||||||
log_fetch_error(id, e)
|
# redirecting to their canonical location first, thus ids will expectedly differ.
|
||||||
{:error, :id_mismatch}
|
# Similarly keys, either use a fragment ID and are a subobjects or a distinct ID
|
||||||
|
# but for compatibility are still a subobject presenting their owning actors ID at the toplevel.
|
||||||
|
# Refetching _once_ from the listed id, should yield a strict match afterwards.
|
||||||
|
{:strict_id, ap_id, _} = e ->
|
||||||
|
case is_ap_id do
|
||||||
|
false ->
|
||||||
|
fetch_and_contain_remote_object_from_id(ap_id, true)
|
||||||
|
|
||||||
|
true ->
|
||||||
|
log_fetch_error(id, e)
|
||||||
|
{:error, :id_mismatch}
|
||||||
|
end
|
||||||
|
|
||||||
{:mrf_reject_check, _} = e ->
|
{:mrf_reject_check, _} = e ->
|
||||||
log_fetch_error(id, e)
|
log_fetch_error(id, e)
|
||||||
|
@ -301,7 +317,7 @@ def fetch_and_contain_remote_object_from_id(id) when is_binary(id) do
|
||||||
|
|
||||||
{:containment, reason} ->
|
{:containment, reason} ->
|
||||||
log_fetch_error(id, reason)
|
log_fetch_error(id, reason)
|
||||||
{:error, reason}
|
{:error, {:containment, reason}}
|
||||||
|
|
||||||
{:error, e} ->
|
{:error, e} ->
|
||||||
{:error, e}
|
{:error, e}
|
||||||
|
@ -311,25 +327,13 @@ def fetch_and_contain_remote_object_from_id(id) when is_binary(id) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_and_contain_remote_object_from_id(_id),
|
def fetch_and_contain_remote_object_from_id(_id, _is_ap_id),
|
||||||
do: {:error, :invalid_id}
|
do: {:error, :invalid_id}
|
||||||
|
|
||||||
defp check_crossdomain_redirect(final_host, original_url)
|
|
||||||
|
|
||||||
# HOPEFULLY TEMPORARY
|
# HOPEFULLY TEMPORARY
|
||||||
# Basically none of our Tesla mocks in tests set the (supposed to
|
# Basically none of our Tesla mocks in tests set the (supposed to
|
||||||
# exist for Tesla proper) url parameter for their responses
|
# exist for Tesla proper) url parameter for their responses
|
||||||
# causing almost every fetch in test to fail otherwise
|
# causing almost every fetch in test to fail otherwise
|
||||||
if @mix_env == :test do
|
|
||||||
defp check_crossdomain_redirect(nil, _) do
|
|
||||||
{:cross_domain_redirect, false}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp check_crossdomain_redirect(final_host, original_url) do
|
|
||||||
{:cross_domain_redirect, final_host != URI.parse(original_url).host}
|
|
||||||
end
|
|
||||||
|
|
||||||
if @mix_env == :test do
|
if @mix_env == :test do
|
||||||
defp get_final_id(nil, initial_url), do: initial_url
|
defp get_final_id(nil, initial_url), do: initial_url
|
||||||
defp get_final_id("", initial_url), do: initial_url
|
defp get_final_id("", initial_url), do: initial_url
|
||||||
|
@ -339,6 +343,7 @@ defp get_final_id(final_url, _intial_url) do
|
||||||
final_url
|
final_url
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc "Do NOT use; only public for use in tests"
|
||||||
def get_object(id) do
|
def get_object(id) do
|
||||||
date = Pleroma.Signature.signed_date()
|
date = Pleroma.Signature.signed_date()
|
||||||
|
|
||||||
|
@ -354,10 +359,6 @@ def get_object(id) do
|
||||||
with {:ok, %{body: body, status: code, headers: headers, url: final_url}}
|
with {:ok, %{body: body, status: code, headers: headers, url: final_url}}
|
||||||
when code in 200..299 <-
|
when code in 200..299 <-
|
||||||
HTTP.Backoff.get(id, headers),
|
HTTP.Backoff.get(id, headers),
|
||||||
remote_host <-
|
|
||||||
URI.parse(final_url).host,
|
|
||||||
{:cross_domain_redirect, false} <-
|
|
||||||
check_crossdomain_redirect(remote_host, id),
|
|
||||||
{:has_content_type, {_, content_type}} <-
|
{:has_content_type, {_, content_type}} <-
|
||||||
{:has_content_type, List.keyfind(headers, "content-type", 0)},
|
{:has_content_type, List.keyfind(headers, "content-type", 0)},
|
||||||
{:parse_content_type, {:ok, "application", subtype, type_params}} <-
|
{:parse_content_type, {:ok, "application", subtype, type_params}} <-
|
||||||
|
@ -368,8 +369,12 @@ def get_object(id) do
|
||||||
{"activity+json", _} ->
|
{"activity+json", _} ->
|
||||||
{:ok, final_id, body}
|
{:ok, final_id, body}
|
||||||
|
|
||||||
{"ld+json", %{"profile" => "https://www.w3.org/ns/activitystreams"}} ->
|
{"ld+json", %{"profile" => profiles}} ->
|
||||||
{:ok, final_id, body}
|
if "https://www.w3.org/ns/activitystreams" in String.split(profiles) do
|
||||||
|
{:ok, final_id, body}
|
||||||
|
else
|
||||||
|
{:error, {:content_type, content_type}}
|
||||||
|
end
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
{:error, {:content_type, content_type}}
|
{:error, {:content_type, content_type}}
|
||||||
|
|
|
@ -95,21 +95,29 @@ defp query_with(q, :rum, search_query) do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def maybe_restrict_local(q, user) do
|
def should_restrict_local(user) do
|
||||||
limit = Pleroma.Config.get([:instance, :limit_to_local_content], :unauthenticated)
|
limit = Pleroma.Config.get([:instance, :limit_to_local_content], :unauthenticated)
|
||||||
|
|
||||||
case {limit, user} do
|
case {limit, user} do
|
||||||
{:all, _} -> restrict_local(q)
|
{:all, _} -> true
|
||||||
{:unauthenticated, %User{}} -> q
|
{:unauthenticated, %User{}} -> false
|
||||||
{:unauthenticated, _} -> restrict_local(q)
|
{:unauthenticated, _} -> true
|
||||||
{false, _} -> q
|
{false, _} -> false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def maybe_restrict_local(q, user) do
|
||||||
|
case should_restrict_local(user) do
|
||||||
|
true -> restrict_local(q)
|
||||||
|
false -> q
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp restrict_local(q), do: where(q, local: true)
|
defp restrict_local(q), do: where(q, local: true)
|
||||||
|
|
||||||
def maybe_fetch(activities, user, search_query) do
|
def maybe_fetch(activities, user, search_query) do
|
||||||
with true <- Regex.match?(~r/https?:/, search_query),
|
with false <- should_restrict_local(user),
|
||||||
|
true <- Regex.match?(~r/https?:/, search_query),
|
||||||
{:ok, object} <- Fetcher.fetch_object_from_id(search_query),
|
{:ok, object} <- Fetcher.fetch_object_from_id(search_query),
|
||||||
%Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
|
%Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
|
||||||
true <- Visibility.visible_for_user?(activity, user) do
|
true <- Visibility.visible_for_user?(activity, user) do
|
||||||
|
|
|
@ -6,12 +6,10 @@ defmodule Pleroma.Signature do
|
||||||
@behaviour HTTPSignatures.Adapter
|
@behaviour HTTPSignatures.Adapter
|
||||||
|
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
|
||||||
alias Pleroma.User.SigningKey
|
alias Pleroma.User.SigningKey
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
def key_id_to_actor_id(key_id) do
|
def key_id_to_actor_id(key_id) do
|
||||||
# Given the key ID, first attempt to look it up in the signing keys table.
|
|
||||||
case SigningKey.key_id_to_ap_id(key_id) do
|
case SigningKey.key_id_to_ap_id(key_id) do
|
||||||
nil ->
|
nil ->
|
||||||
# hm, we SHOULD have gotten this in the pipeline before we hit here!
|
# hm, we SHOULD have gotten this in the pipeline before we hit here!
|
||||||
|
@ -49,7 +47,7 @@ def refetch_public_key(conn) do
|
||||||
|
|
||||||
def sign(%User{} = user, headers) do
|
def sign(%User{} = user, headers) do
|
||||||
with {:ok, private_key} <- SigningKey.private_key(user) do
|
with {:ok, private_key} <- SigningKey.private_key(user) do
|
||||||
HTTPSignatures.sign(private_key, user.ap_id <> "#main-key", headers)
|
HTTPSignatures.sign(private_key, SigningKey.local_key_id(user.ap_id), headers)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ defmodule Pleroma.Upload.Filter.Exiftool.StripMetadata do
|
||||||
|
|
||||||
# Formats not compatible with exiftool at this time
|
# Formats not compatible with exiftool at this time
|
||||||
def filter(%Pleroma.Upload{content_type: "image/webp"}), do: {:ok, :noop}
|
def filter(%Pleroma.Upload{content_type: "image/webp"}), do: {:ok, :noop}
|
||||||
|
def filter(%Pleroma.Upload{content_type: "image/bmp"}), do: {:ok, :noop}
|
||||||
def filter(%Pleroma.Upload{content_type: "image/svg+xml"}), do: {:ok, :noop}
|
def filter(%Pleroma.Upload{content_type: "image/svg+xml"}), do: {:ok, :noop}
|
||||||
|
|
||||||
def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _}) do
|
def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _}) do
|
||||||
|
|
|
@ -101,7 +101,6 @@ defmodule Pleroma.User do
|
||||||
field(:password, :string, virtual: true)
|
field(:password, :string, virtual: true)
|
||||||
field(:password_confirmation, :string, virtual: true)
|
field(:password_confirmation, :string, virtual: true)
|
||||||
field(:keys, :string)
|
field(:keys, :string)
|
||||||
field(:public_key, :string)
|
|
||||||
field(:ap_id, :string)
|
field(:ap_id, :string)
|
||||||
field(:avatar, :map, default: %{})
|
field(:avatar, :map, default: %{})
|
||||||
field(:local, :boolean, default: true)
|
field(:local, :boolean, default: true)
|
||||||
|
@ -444,6 +443,7 @@ defp fix_follower_address(params), do: params
|
||||||
def remote_user_changeset(struct \\ %User{local: false}, params) do
|
def remote_user_changeset(struct \\ %User{local: false}, params) do
|
||||||
bio_limit = Config.get([:instance, :user_bio_length], 5000)
|
bio_limit = Config.get([:instance, :user_bio_length], 5000)
|
||||||
name_limit = Config.get([:instance, :user_name_length], 100)
|
name_limit = Config.get([:instance, :user_name_length], 100)
|
||||||
|
fields_limit = Config.get([:instance, :max_remote_account_fields], 0)
|
||||||
|
|
||||||
name =
|
name =
|
||||||
case params[:name] do
|
case params[:name] do
|
||||||
|
@ -457,6 +457,7 @@ def remote_user_changeset(struct \\ %User{local: false}, params) do
|
||||||
|> Map.put_new(:last_refreshed_at, NaiveDateTime.utc_now())
|
|> Map.put_new(:last_refreshed_at, NaiveDateTime.utc_now())
|
||||||
|> truncate_if_exists(:name, name_limit)
|
|> truncate_if_exists(:name, name_limit)
|
||||||
|> truncate_if_exists(:bio, bio_limit)
|
|> truncate_if_exists(:bio, bio_limit)
|
||||||
|
|> Map.update(:fields, [], &Enum.take(&1, fields_limit))
|
||||||
|> truncate_fields_param()
|
|> truncate_fields_param()
|
||||||
|> fix_follower_address()
|
|> fix_follower_address()
|
||||||
|
|
||||||
|
@ -471,7 +472,6 @@ def remote_user_changeset(struct \\ %User{local: false}, params) do
|
||||||
:inbox,
|
:inbox,
|
||||||
:shared_inbox,
|
:shared_inbox,
|
||||||
:nickname,
|
:nickname,
|
||||||
:public_key,
|
|
||||||
:avatar,
|
:avatar,
|
||||||
:ap_enabled,
|
:ap_enabled,
|
||||||
:banner,
|
:banner,
|
||||||
|
@ -532,7 +532,6 @@ def update_changeset(struct, params \\ %{}) do
|
||||||
:name,
|
:name,
|
||||||
:emoji,
|
:emoji,
|
||||||
:avatar,
|
:avatar,
|
||||||
:public_key,
|
|
||||||
:inbox,
|
:inbox,
|
||||||
:shared_inbox,
|
:shared_inbox,
|
||||||
:is_locked,
|
:is_locked,
|
||||||
|
@ -1634,8 +1633,12 @@ def blocks_user?(%User{} = user, %User{} = target) do
|
||||||
|
|
||||||
def blocks_user?(_, _), do: false
|
def blocks_user?(_, _), do: false
|
||||||
|
|
||||||
def blocks_domain?(%User{} = user, %User{} = target) do
|
def blocks_domain?(%User{} = user, %User{ap_id: ap_id}) do
|
||||||
%{host: host} = URI.parse(target.ap_id)
|
blocks_domain?(user, ap_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def blocks_domain?(%User{} = user, url) when is_binary(url) do
|
||||||
|
%{host: host} = URI.parse(url)
|
||||||
Enum.member?(user.domain_blocks, host)
|
Enum.member?(user.domain_blocks, host)
|
||||||
# TODO: functionality should probably be changed such that subdomains block as well,
|
# TODO: functionality should probably be changed such that subdomains block as well,
|
||||||
# but as it stands, this just hecks up the relationships endpoint
|
# but as it stands, this just hecks up the relationships endpoint
|
||||||
|
|
|
@ -2,9 +2,9 @@ defmodule Pleroma.User.SigningKey do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
require Pleroma.Constants
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.HTTP
|
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
@ -91,7 +91,15 @@ def generate_local_keys(ap_id) do
|
||||||
|> change()
|
|> change()
|
||||||
|> put_change(:public_key, local_pem)
|
|> put_change(:public_key, local_pem)
|
||||||
|> put_change(:private_key, private_pem)
|
|> put_change(:private_key, private_pem)
|
||||||
|> put_change(:key_id, ap_id <> "#main-key")
|
|> put_change(:key_id, local_key_id(ap_id))
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec local_key_id(String.t()) :: String.t()
|
||||||
|
@doc """
|
||||||
|
Given an AP ID, return the key ID for the local user.
|
||||||
|
"""
|
||||||
|
def local_key_id(ap_id) do
|
||||||
|
ap_id <> "#main-key"
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec private_pem_to_public_pem(binary) :: {:ok, binary()} | {:error, String.t()}
|
@spec private_pem_to_public_pem(binary) :: {:ok, binary()} | {:error, String.t()}
|
||||||
|
@ -136,7 +144,7 @@ def public_key_pem(%User{} = user) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def public_key_pem(e) do
|
def public_key_pem(_e) do
|
||||||
{:error, "key not found"}
|
{:error, "key not found"}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -186,32 +194,24 @@ def get_or_fetch_by_key_id(key_id) do
|
||||||
"""
|
"""
|
||||||
def fetch_remote_key(key_id) do
|
def fetch_remote_key(key_id) do
|
||||||
Logger.debug("Fetching remote key: #{key_id}")
|
Logger.debug("Fetching remote key: #{key_id}")
|
||||||
# we should probably sign this, just in case
|
|
||||||
resp = Pleroma.Object.Fetcher.get_object(key_id)
|
|
||||||
|
|
||||||
case resp do
|
with {:ok, _body} = resp <-
|
||||||
{:ok, _original_url, body} ->
|
Pleroma.Object.Fetcher.fetch_and_contain_remote_object_from_id(key_id),
|
||||||
case handle_signature_response(resp) do
|
{:ok, ap_id, public_key_pem} <- handle_signature_response(resp) do
|
||||||
{:ok, ap_id, public_key_pem} ->
|
Logger.debug("Fetched remote key: #{ap_id}")
|
||||||
Logger.debug("Fetched remote key: #{ap_id}")
|
# fetch the user
|
||||||
# fetch the user
|
{:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
|
||||||
{:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
|
# store the key
|
||||||
# store the key
|
key = %__MODULE__{
|
||||||
key = %__MODULE__{
|
user_id: user.id,
|
||||||
user_id: user.id,
|
public_key: public_key_pem,
|
||||||
public_key: public_key_pem,
|
key_id: key_id
|
||||||
key_id: key_id
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Repo.insert(key, on_conflict: :replace_all, conflict_target: :key_id)
|
Repo.insert(key, on_conflict: :replace_all, conflict_target: :key_id)
|
||||||
|
else
|
||||||
e ->
|
e ->
|
||||||
Logger.debug("Failed to fetch remote key: #{inspect(e)}")
|
Logger.debug("Failed to fetch remote key: #{inspect(e)}")
|
||||||
{:error, "Could not fetch key"}
|
|
||||||
end
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
Logger.debug("Failed to fetch remote key: #{inspect(resp)}")
|
|
||||||
{:error, "Could not fetch key"}
|
{:error, "Could not fetch key"}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -227,16 +227,26 @@ defp extract_key_details(%{"id" => ap_id, "publicKey" => public_key}) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp handle_signature_response({:ok, _original_url, body}) do
|
defp handle_signature_response({:ok, body}) do
|
||||||
case Jason.decode(body) do
|
case body do
|
||||||
{:ok, %{"id" => _user_id, "publicKey" => _public_key} = body} ->
|
%{
|
||||||
|
"type" => "CryptographicKey",
|
||||||
|
"publicKeyPem" => public_key_pem,
|
||||||
|
"owner" => ap_id
|
||||||
|
} ->
|
||||||
|
{:ok, ap_id, public_key_pem}
|
||||||
|
|
||||||
|
# for when we get a subset of the user object
|
||||||
|
%{
|
||||||
|
"id" => _user_id,
|
||||||
|
"publicKey" => _public_key,
|
||||||
|
"type" => actor_type
|
||||||
|
}
|
||||||
|
when actor_type in Pleroma.Constants.actor_types() ->
|
||||||
extract_key_details(body)
|
extract_key_details(body)
|
||||||
|
|
||||||
{:ok, %{"error" => error}} ->
|
%{"error" => error} ->
|
||||||
{:error, error}
|
{:error, error}
|
||||||
|
|
||||||
{:error, _} ->
|
|
||||||
{:error, "Could not parse key"}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -34,16 +34,34 @@ defp check_reject(message, actions) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec delete_and_count(list(), term()) :: {integer(), list()}
|
||||||
|
defp delete_and_count(list, element), do: delete_and_count(list, element, {0, [], list})
|
||||||
|
|
||||||
|
defp delete_and_count([], _element, {0, _nlist, olist}), do: {0, olist}
|
||||||
|
defp delete_and_count([], _element, {count, nlist, _olist}), do: {count, Enum.reverse(nlist)}
|
||||||
|
|
||||||
|
defp delete_and_count([h | r], h, {count, nlist, olist}),
|
||||||
|
do: delete_and_count(r, h, {count + 1, nlist, olist})
|
||||||
|
|
||||||
|
defp delete_and_count([h | r], element, {count, nlist, olist}),
|
||||||
|
do: delete_and_count(r, element, {count, [h | nlist], olist})
|
||||||
|
|
||||||
|
defp insert_if_needed(list, oldcount, element) do
|
||||||
|
if oldcount <= 0 || Enum.member?(list, element) do
|
||||||
|
list
|
||||||
|
else
|
||||||
|
[element | list]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp check_delist(message, actions) do
|
defp check_delist(message, actions) do
|
||||||
if :delist in actions do
|
if :delist in actions do
|
||||||
with %User{} = user <- User.get_cached_by_ap_id(message["actor"]) do
|
with %User{} = user <- User.get_cached_by_ap_id(message["actor"]) do
|
||||||
to =
|
{pubcnt, to} = delete_and_count(message["to"] || [], Pleroma.Constants.as_public())
|
||||||
List.delete(message["to"] || [], Pleroma.Constants.as_public()) ++
|
{flwcnt, cc} = delete_and_count(message["cc"] || [], user.follower_address)
|
||||||
[user.follower_address]
|
|
||||||
|
|
||||||
cc =
|
cc = insert_if_needed(cc, pubcnt, Pleroma.Constants.as_public())
|
||||||
List.delete(message["cc"] || [], user.follower_address) ++
|
to = insert_if_needed(to, flwcnt, user.follower_address)
|
||||||
[Pleroma.Constants.as_public()]
|
|
||||||
|
|
||||||
message =
|
message =
|
||||||
message
|
message
|
||||||
|
@ -65,8 +83,8 @@ defp check_delist(message, actions) do
|
||||||
defp check_strip_followers(message, actions) do
|
defp check_strip_followers(message, actions) do
|
||||||
if :strip_followers in actions do
|
if :strip_followers in actions do
|
||||||
with %User{} = user <- User.get_cached_by_ap_id(message["actor"]) do
|
with %User{} = user <- User.get_cached_by_ap_id(message["actor"]) do
|
||||||
to = List.delete(message["to"] || [], user.follower_address)
|
{_, to} = delete_and_count(message["to"] || [], user.follower_address)
|
||||||
cc = List.delete(message["cc"] || [], user.follower_address)
|
{_, cc} = delete_and_count(message["cc"] || [], user.follower_address)
|
||||||
|
|
||||||
message =
|
message =
|
||||||
message
|
message
|
||||||
|
|
|
@ -112,7 +112,7 @@ defp allowed_instances do
|
||||||
Config.get([:mrf_simple, :accept])
|
Config.get([:mrf_simple, :accept])
|
||||||
end
|
end
|
||||||
|
|
||||||
def should_federate?(url) do
|
def should_federate?(url) when is_binary(url) do
|
||||||
%{host: host} = URI.parse(url)
|
%{host: host} = URI.parse(url)
|
||||||
|
|
||||||
with {nil, false} <- {nil, is_nil(host)},
|
with {nil, false} <- {nil, is_nil(host)},
|
||||||
|
@ -137,6 +137,8 @@ def should_federate?(url) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def should_federate?(_), do: false
|
||||||
|
|
||||||
@spec recipients(User.t(), Activity.t()) :: list(User.t()) | []
|
@spec recipients(User.t(), Activity.t()) :: list(User.t()) | []
|
||||||
defp recipients(actor, activity) do
|
defp recipients(actor, activity) do
|
||||||
followers =
|
followers =
|
||||||
|
|
|
@ -950,8 +950,7 @@ defp build_emoji_tag({name, url}) do
|
||||||
"icon" => %{"url" => "#{URI.encode(url)}", "type" => "Image"},
|
"icon" => %{"url" => "#{URI.encode(url)}", "type" => "Image"},
|
||||||
"name" => ":" <> name <> ":",
|
"name" => ":" <> name <> ":",
|
||||||
"type" => "Emoji",
|
"type" => "Emoji",
|
||||||
"updated" => "1970-01-01T00:00:00Z",
|
"updated" => "1970-01-01T00:00:00Z"
|
||||||
"id" => url
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ def render("service.json", %{user: user}) do
|
||||||
"url" => user.ap_id,
|
"url" => user.ap_id,
|
||||||
"manuallyApprovesFollowers" => false,
|
"manuallyApprovesFollowers" => false,
|
||||||
"publicKey" => %{
|
"publicKey" => %{
|
||||||
"id" => "#{user.ap_id}#main-key",
|
"id" => User.SigningKey.local_key_id(user.ap_id),
|
||||||
"owner" => user.ap_id,
|
"owner" => user.ap_id,
|
||||||
"publicKeyPem" => public_key
|
"publicKeyPem" => public_key
|
||||||
},
|
},
|
||||||
|
@ -97,7 +97,7 @@ def render("user.json", %{user: user}) do
|
||||||
"url" => user.ap_id,
|
"url" => user.ap_id,
|
||||||
"manuallyApprovesFollowers" => user.is_locked,
|
"manuallyApprovesFollowers" => user.is_locked,
|
||||||
"publicKey" => %{
|
"publicKey" => %{
|
||||||
"id" => "#{user.ap_id}#main-key",
|
"id" => User.SigningKey.local_key_id(user.ap_id),
|
||||||
"owner" => user.ap_id,
|
"owner" => user.ap_id,
|
||||||
"publicKeyPem" => public_key
|
"publicKeyPem" => public_key
|
||||||
},
|
},
|
||||||
|
|
|
@ -32,7 +32,9 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Poll do
|
||||||
},
|
},
|
||||||
voters_count: %Schema{
|
voters_count: %Schema{
|
||||||
type: :integer,
|
type: :integer,
|
||||||
description: "How many unique accounts have voted. Number."
|
nullable: true,
|
||||||
|
description:
|
||||||
|
"How many unique accounts have voted for a multi-selection poll. Number, or null if single-selection poll."
|
||||||
},
|
},
|
||||||
voted: %Schema{
|
voted: %Schema{
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
|
|
|
@ -66,10 +66,10 @@ defmodule Pleroma.Web.Endpoint do
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
plug(Plug.Static.IndexHtml, at: "/akkoma/swaggerui")
|
plug(Plug.Static.IndexHtml, at: "/pleroma/swaggerui/")
|
||||||
|
|
||||||
plug(Pleroma.Web.Plugs.FrontendStatic,
|
plug(Pleroma.Web.Plugs.FrontendStatic,
|
||||||
at: "/akkoma/swaggerui",
|
at: "/pleroma/swaggerui",
|
||||||
frontend_type: :swagger,
|
frontend_type: :swagger,
|
||||||
gzip: true,
|
gzip: true,
|
||||||
if: &Pleroma.Web.Swagger.ui_enabled?/0,
|
if: &Pleroma.Web.Swagger.ui_enabled?/0,
|
||||||
|
|
|
@ -19,7 +19,7 @@ def render("show.json", %{object: object, multiple: multiple, options: options}
|
||||||
expired: expired,
|
expired: expired,
|
||||||
multiple: multiple,
|
multiple: multiple,
|
||||||
votes_count: votes_count,
|
votes_count: votes_count,
|
||||||
voters_count: voters_count(object),
|
voters_count: voters_count(multiple, object),
|
||||||
options: options,
|
options: options,
|
||||||
emojis: Pleroma.Web.MastodonAPI.StatusView.build_emojis(object.data["emoji"])
|
emojis: Pleroma.Web.MastodonAPI.StatusView.build_emojis(object.data["emoji"])
|
||||||
}
|
}
|
||||||
|
@ -68,11 +68,19 @@ defp options_and_votes_count(options) do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp voters_count(%{data: %{"voters" => voters}}) when is_list(voters) do
|
defp voters_count(false, _poll_data) do
|
||||||
|
# Mastodon always sets voter count to "null" unless multiple options were selectable
|
||||||
|
# Some clients may rely on this to detect multiple selection polls and it can mess
|
||||||
|
# up percentages for some clients if we never got a correct remote voter count and
|
||||||
|
# only count local voters here; see https://akkoma.dev/AkkomaGang/akkoma/issues/190
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
defp voters_count(_multiple, %{data: %{"voters" => voters}}) when is_list(voters) do
|
||||||
length(voters)
|
length(voters)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp voters_count(_), do: 0
|
defp voters_count(_, _), do: 0
|
||||||
|
|
||||||
defp voted_and_own_votes(%{object: object} = params, options) do
|
defp voted_and_own_votes(%{object: object} = params, options) do
|
||||||
if params[:for] do
|
if params[:for] do
|
||||||
|
|
|
@ -52,11 +52,11 @@ def url(url) do
|
||||||
|
|
||||||
@spec url_proxiable?(String.t()) :: boolean()
|
@spec url_proxiable?(String.t()) :: boolean()
|
||||||
def url_proxiable?(url) do
|
def url_proxiable?(url) do
|
||||||
not local?(url) and not whitelisted?(url) and not blocked?(url)
|
not local?(url) and not whitelisted?(url) and not blocked?(url) and http_scheme?(url)
|
||||||
end
|
end
|
||||||
|
|
||||||
def preview_url(url, preview_params \\ []) do
|
def preview_url(url, preview_params \\ []) do
|
||||||
if preview_enabled?() do
|
if preview_enabled?() and url_proxiable?(url) do
|
||||||
encode_preview_url(url, preview_params)
|
encode_preview_url(url, preview_params)
|
||||||
else
|
else
|
||||||
url(url)
|
url(url)
|
||||||
|
@ -71,6 +71,8 @@ def preview_enabled?, do: enabled?() and !!Config.get([:media_preview_proxy, :en
|
||||||
|
|
||||||
def local?(url), do: String.starts_with?(url, Endpoint.url())
|
def local?(url), do: String.starts_with?(url, Endpoint.url())
|
||||||
|
|
||||||
|
def http_scheme?(url), do: String.starts_with?(url, ["http:", "https:"])
|
||||||
|
|
||||||
def whitelisted?(url) do
|
def whitelisted?(url) do
|
||||||
%{host: domain} = URI.parse(url)
|
%{host: domain} = URI.parse(url)
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ def nodeinfo(conn, %{"version" => version}) when version in ["2.0", "2.1"] do
|
||||||
conn
|
conn
|
||||||
|> put_resp_header(
|
|> put_resp_header(
|
||||||
"content-type",
|
"content-type",
|
||||||
"application/json; profile=http://nodeinfo.diaspora.software/ns/schema/2.0#; charset=utf-8"
|
"application/json; profile=\"http://nodeinfo.diaspora.software/ns/schema/#{version}#\"; charset=utf-8"
|
||||||
)
|
)
|
||||||
|> json(Nodeinfo.get_nodeinfo(version))
|
|> json(Nodeinfo.get_nodeinfo(version))
|
||||||
end
|
end
|
||||||
|
|
|
@ -52,6 +52,14 @@ defp filter_allowed_user_by_ap_id(ap_ids, excluded_ap_ids) do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp filter_allowed_users_by_domain(ap_ids, %User{} = for_user) do
|
||||||
|
Enum.reject(ap_ids, fn ap_id ->
|
||||||
|
User.blocks_domain?(for_user, ap_id)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp filter_allowed_users_by_domain(ap_ids, nil), do: ap_ids
|
||||||
|
|
||||||
def filter_allowed_users(reactions, user, with_muted) do
|
def filter_allowed_users(reactions, user, with_muted) do
|
||||||
exclude_ap_ids =
|
exclude_ap_ids =
|
||||||
if is_nil(user) do
|
if is_nil(user) do
|
||||||
|
@ -62,7 +70,10 @@ def filter_allowed_users(reactions, user, with_muted) do
|
||||||
end
|
end
|
||||||
|
|
||||||
filter_emoji = fn emoji, users, url ->
|
filter_emoji = fn emoji, users, url ->
|
||||||
case filter_allowed_user_by_ap_id(users, exclude_ap_ids) do
|
users
|
||||||
|
|> filter_allowed_user_by_ap_id(exclude_ap_ids)
|
||||||
|
|> filter_allowed_users_by_domain(user)
|
||||||
|
|> case do
|
||||||
[] -> nil
|
[] -> nil
|
||||||
users -> {emoji, users, url}
|
users -> {emoji, users, url}
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,8 +4,6 @@ defmodule Pleroma.Web.Plugs.EnsureUserPublicKeyPlug do
|
||||||
We _should_ be able to request the URL from the key URL...
|
We _should_ be able to request the URL from the key URL...
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import Plug.Conn
|
|
||||||
|
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
|
||||||
def init(options), do: options
|
def init(options), do: options
|
||||||
|
@ -14,7 +12,7 @@ def call(conn, _opts) do
|
||||||
key_id = key_id_from_conn(conn)
|
key_id = key_id_from_conn(conn)
|
||||||
|
|
||||||
unless is_nil(key_id) do
|
unless is_nil(key_id) do
|
||||||
User.SigningKey.fetch_remote_key(key_id)
|
User.SigningKey.get_or_fetch_by_key_id(key_id)
|
||||||
# now we SHOULD have the user that owns the key locally. maybe.
|
# now we SHOULD have the user that owns the key locally. maybe.
|
||||||
# if we don't, we'll error out when we try to validate.
|
# if we don't, we'll error out when we try to validate.
|
||||||
end
|
end
|
||||||
|
|
|
@ -67,7 +67,8 @@ def call(%{assigns: %{valid_signature: true}} = conn, _opts) do
|
||||||
Logger.debug("Failed to map identity from signature (lookup failure)")
|
Logger.debug("Failed to map identity from signature (lookup failure)")
|
||||||
Logger.debug("key_id=#{inspect(key_id_from_conn(conn))}")
|
Logger.debug("key_id=#{inspect(key_id_from_conn(conn))}")
|
||||||
|
|
||||||
only_permit_user_routes(conn)
|
conn
|
||||||
|
|> assign(:valid_signature, false)
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
Logger.debug("Failed to map identity from signature (no payload actor mismatch)")
|
Logger.debug("Failed to map identity from signature (no payload actor mismatch)")
|
||||||
|
@ -81,16 +82,6 @@ def call(%{assigns: %{valid_signature: true}} = conn, _opts) do
|
||||||
# no signature at all
|
# no signature at all
|
||||||
def call(conn, _opts), do: conn
|
def call(conn, _opts), do: conn
|
||||||
|
|
||||||
defp only_permit_user_routes(%{path_info: ["users", _]} = conn) do
|
|
||||||
conn
|
|
||||||
|> assign(:limited_ap, true)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp only_permit_user_routes(conn) do
|
|
||||||
conn
|
|
||||||
|> assign(:valid_signature, false)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp key_id_from_conn(conn) do
|
defp key_id_from_conn(conn) do
|
||||||
case HTTPSignatures.signature_for_conn(conn) do
|
case HTTPSignatures.signature_for_conn(conn) do
|
||||||
%{"keyId" => key_id} when is_binary(key_id) ->
|
%{"keyId" => key_id} when is_binary(key_id) ->
|
||||||
|
|
|
@ -5,30 +5,65 @@
|
||||||
defmodule Pleroma.Workers.AttachmentsCleanupWorker do
|
defmodule Pleroma.Workers.AttachmentsCleanupWorker do
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
|
alias Pleroma.Config
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
|
|
||||||
use Pleroma.Workers.WorkerHelper, queue: "attachments_cleanup"
|
use Pleroma.Workers.WorkerHelper, queue: "attachments_cleanup"
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Takes object data and if necessary enqueues a job,
|
||||||
|
deleting all attachments of the post eligible for cleanup
|
||||||
|
"""
|
||||||
|
@spec enqueue_if_needed(map()) :: {:ok, Oban.Job.t()} | {:ok, :skip} | {:error, any()}
|
||||||
|
def enqueue_if_needed(%{
|
||||||
|
"actor" => actor,
|
||||||
|
"attachment" => [_ | _] = attachments
|
||||||
|
}) do
|
||||||
|
with true <- Config.get([:instance, :cleanup_attachments]),
|
||||||
|
true <- URI.parse(actor).host == Pleroma.Web.Endpoint.host(),
|
||||||
|
[_ | _] <- attachments do
|
||||||
|
enqueue(
|
||||||
|
"cleanup_attachments",
|
||||||
|
%{"actor" => actor, "attachments" => attachments},
|
||||||
|
schedule_in: Config.get!([:instance, :cleanup_attachments_delay])
|
||||||
|
)
|
||||||
|
else
|
||||||
|
_ -> {:ok, :skip}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def enqueue_if_needed(_), do: {:ok, :skip}
|
||||||
|
|
||||||
@impl Oban.Worker
|
@impl Oban.Worker
|
||||||
def perform(%Job{
|
def perform(%Job{
|
||||||
args: %{
|
args: %{
|
||||||
"op" => "cleanup_attachments",
|
"op" => "cleanup_attachments",
|
||||||
"object" => %{"data" => %{"attachment" => [_ | _] = attachments, "actor" => actor}}
|
"attachments" => [_ | _] = attachments,
|
||||||
|
"actor" => actor
|
||||||
}
|
}
|
||||||
}) do
|
}) do
|
||||||
if Pleroma.Config.get([:instance, :cleanup_attachments], false) do
|
attachments
|
||||||
attachments
|
|> Enum.flat_map(fn item -> Enum.map(item["url"], & &1["href"]) end)
|
||||||
|> Enum.flat_map(fn item -> Enum.map(item["url"], & &1["href"]) end)
|
|> fetch_objects
|
||||||
|> fetch_objects
|
|> prepare_objects(actor, Enum.map(attachments, & &1["name"]))
|
||||||
|> prepare_objects(actor, Enum.map(attachments, & &1["name"]))
|
|> filter_objects
|
||||||
|> filter_objects
|
|> do_clean
|
||||||
|> do_clean
|
|
||||||
end
|
|
||||||
|
|
||||||
{:ok, :success}
|
{:ok, :success}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Left over already enqueued jobs in the old format
|
||||||
|
# This function clause can be deleted once sufficient time passed after 3.14
|
||||||
|
def perform(%Job{
|
||||||
|
args: %{
|
||||||
|
"op" => "cleanup_attachments",
|
||||||
|
"object" => %{"data" => data}
|
||||||
|
}
|
||||||
|
}) do
|
||||||
|
enqueue_if_needed(data)
|
||||||
|
end
|
||||||
|
|
||||||
def perform(%Job{args: %{"op" => "cleanup_attachments", "object" => _object}}), do: {:ok, :skip}
|
def perform(%Job{args: %{"op" => "cleanup_attachments", "object" => _object}}), do: {:ok, :skip}
|
||||||
|
|
||||||
defp do_clean({object_ids, attachment_urls}) do
|
defp do_clean({object_ids, attachment_urls}) do
|
||||||
|
|
6
mix.exs
6
mix.exs
|
@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do
|
||||||
def project do
|
def project do
|
||||||
[
|
[
|
||||||
app: :pleroma,
|
app: :pleroma,
|
||||||
version: version("3.13.2"),
|
version: version("3.14.1"),
|
||||||
elixir: "~> 1.14",
|
elixir: "~> 1.14",
|
||||||
elixirc_paths: elixirc_paths(Mix.env()),
|
elixirc_paths: elixirc_paths(Mix.env()),
|
||||||
compilers: Mix.compilers(),
|
compilers: Mix.compilers(),
|
||||||
|
@ -144,7 +144,7 @@ defp deps do
|
||||||
{:ex_aws, "~> 2.4"},
|
{:ex_aws, "~> 2.4"},
|
||||||
{:ex_aws_s3, "~> 2.4"},
|
{:ex_aws_s3, "~> 2.4"},
|
||||||
{:sweet_xml, "~> 0.7"},
|
{:sweet_xml, "~> 0.7"},
|
||||||
{:earmark, "~> 1.4"},
|
{:earmark, "1.4.46"},
|
||||||
{:bbcode_pleroma, "~> 0.2.0"},
|
{:bbcode_pleroma, "~> 0.2.0"},
|
||||||
{:argon2_elixir, "~> 3.1"},
|
{:argon2_elixir, "~> 3.1"},
|
||||||
{:cors_plug, "~> 3.0"},
|
{:cors_plug, "~> 3.0"},
|
||||||
|
@ -180,7 +180,7 @@ defp deps do
|
||||||
{:remote_ip, "~> 1.1.0"},
|
{:remote_ip, "~> 1.1.0"},
|
||||||
{:captcha,
|
{:captcha,
|
||||||
git: "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git",
|
git: "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git",
|
||||||
ref: "90f6ce7672f70f56708792a98d98bd05176c9176"},
|
ref: "6630c42aaaab124e697b4e513190c89d8b64e410"},
|
||||||
{:restarter, path: "./restarter"},
|
{:restarter, path: "./restarter"},
|
||||||
{:majic,
|
{:majic,
|
||||||
git: "https://akkoma.dev/AkkomaGang/majic.git",
|
git: "https://akkoma.dev/AkkomaGang/majic.git",
|
||||||
|
|
57
mix.lock
57
mix.lock
|
@ -7,29 +7,29 @@
|
||||||
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
|
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
|
||||||
"cachex": {:hex, :cachex, "3.6.0", "14a1bfbeee060dd9bec25a5b6f4e4691e3670ebda28c8ba2884b12fe30b36bf8", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "ebf24e373883bc8e0c8d894a63bbe102ae13d918f790121f5cfe6e485cc8e2e2"},
|
"cachex": {:hex, :cachex, "3.6.0", "14a1bfbeee060dd9bec25a5b6f4e4691e3670ebda28c8ba2884b12fe30b36bf8", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "ebf24e373883bc8e0c8d894a63bbe102ae13d918f790121f5cfe6e485cc8e2e2"},
|
||||||
"calendar": {:hex, :calendar, "1.0.0", "f52073a708528482ec33d0a171954ca610fe2bd28f1e871f247dc7f1565fa807", [:mix], [{:tzdata, "~> 0.1.201603 or ~> 0.5.20 or ~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "990e9581920c82912a5ee50e62ff5ef96da6b15949a2ee4734f935fdef0f0a6f"},
|
"calendar": {:hex, :calendar, "1.0.0", "f52073a708528482ec33d0a171954ca610fe2bd28f1e871f247dc7f1565fa807", [:mix], [{:tzdata, "~> 0.1.201603 or ~> 0.5.20 or ~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "990e9581920c82912a5ee50e62ff5ef96da6b15949a2ee4734f935fdef0f0a6f"},
|
||||||
"captcha": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git", "90f6ce7672f70f56708792a98d98bd05176c9176", [ref: "90f6ce7672f70f56708792a98d98bd05176c9176"]},
|
"captcha": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git", "6630c42aaaab124e697b4e513190c89d8b64e410", [ref: "6630c42aaaab124e697b4e513190c89d8b64e410"]},
|
||||||
"castore": {:hex, :castore, "1.0.7", "b651241514e5f6956028147fe6637f7ac13802537e895a724f90bf3e36ddd1dd", [:mix], [], "hexpm", "da7785a4b0d2a021cd1292a60875a784b6caef71e76bf4917bdee1f390455cf5"},
|
"castore": {:hex, :castore, "1.0.9", "5cc77474afadf02c7c017823f460a17daa7908e991b0cc917febc90e466a375c", [:mix], [], "hexpm", "5ea956504f1ba6f2b4eb707061d8e17870de2bee95fb59d512872c2ef06925e7"},
|
||||||
"certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
|
"certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
|
||||||
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
|
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
|
||||||
"comeonin": {:hex, :comeonin, "5.4.0", "246a56ca3f41d404380fc6465650ddaa532c7f98be4bda1b4656b3a37cc13abe", [:mix], [], "hexpm", "796393a9e50d01999d56b7b8420ab0481a7538d0caf80919da493b4a6e51faf1"},
|
"comeonin": {:hex, :comeonin, "5.5.0", "364d00df52545c44a139bad919d7eacb55abf39e86565878e17cebb787977368", [:mix], [], "hexpm", "6287fc3ba0aad34883cbe3f7949fc1d1e738e5ccdce77165bc99490aa69f47fb"},
|
||||||
"concurrent_limiter": {:git, "https://akkoma.dev/AkkomaGang/concurrent-limiter.git", "a9e0b3d64574bdba761f429bb4fba0cf687b3338", [ref: "a9e0b3d64574bdba761f429bb4fba0cf687b3338"]},
|
"concurrent_limiter": {:git, "https://akkoma.dev/AkkomaGang/concurrent-limiter.git", "a9e0b3d64574bdba761f429bb4fba0cf687b3338", [ref: "a9e0b3d64574bdba761f429bb4fba0cf687b3338"]},
|
||||||
"connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
|
"connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
|
||||||
"cors_plug": {:hex, :cors_plug, "3.0.3", "7c3ac52b39624bc616db2e937c282f3f623f25f8d550068b6710e58d04a0e330", [:mix], [{:plug, "~> 1.13", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "3f2d759e8c272ed3835fab2ef11b46bddab8c1ab9528167bd463b6452edf830d"},
|
"cors_plug": {:hex, :cors_plug, "3.0.3", "7c3ac52b39624bc616db2e937c282f3f623f25f8d550068b6710e58d04a0e330", [:mix], [{:plug, "~> 1.13", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "3f2d759e8c272ed3835fab2ef11b46bddab8c1ab9528167bd463b6452edf830d"},
|
||||||
"cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"},
|
"cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"},
|
||||||
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
|
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
|
||||||
"cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"},
|
"cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"},
|
||||||
"credo": {:hex, :credo, "1.7.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"},
|
"credo": {:hex, :credo, "1.7.8", "9722ba1681e973025908d542ec3d95db5f9c549251ba5b028e251ad8c24ab8c5", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cb9e87cc64f152f3ed1c6e325e7b894dea8f5ef2e41123bd864e3cd5ceb44968"},
|
||||||
"custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"},
|
"custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"},
|
||||||
"db_connection": {:hex, :db_connection, "2.6.0", "77d835c472b5b67fc4f29556dee74bf511bbafecdcaf98c27d27fa5918152086", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c2f992d15725e721ec7fbc1189d4ecdb8afef76648c746a8e1cad35e3b8a35f3"},
|
"db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"},
|
||||||
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
|
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
|
||||||
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
|
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
|
||||||
"dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"},
|
"dialyxir": {:hex, :dialyxir, "1.4.4", "fb3ce8741edeaea59c9ae84d5cec75da00fa89fe401c72d6e047d11a61f65f70", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "cd6111e8017ccd563e65621a4d9a4a1c5cd333df30cebc7face8029cacb4eff6"},
|
||||||
"earmark": {:hex, :earmark, "1.4.46", "8c7287bd3137e99d26ae4643e5b7ef2129a260e3dcf41f251750cb4563c8fb81", [:mix], [], "hexpm", "798d86db3d79964e759ddc0c077d5eb254968ed426399fbf5a62de2b5ff8910a"},
|
"earmark": {:hex, :earmark, "1.4.46", "8c7287bd3137e99d26ae4643e5b7ef2129a260e3dcf41f251750cb4563c8fb81", [:mix], [], "hexpm", "798d86db3d79964e759ddc0c077d5eb254968ed426399fbf5a62de2b5ff8910a"},
|
||||||
"earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"},
|
"earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"},
|
||||||
"eblurhash": {:hex, :eblurhash, "1.2.2", "7da4255aaea984b31bb71155f673257353b0e0554d0d30dcf859547e74602582", [:rebar3], [], "hexpm", "8c20ca00904de023a835a9dcb7b7762fed32264c85a80c3cafa85288e405044c"},
|
"eblurhash": {:hex, :eblurhash, "1.2.2", "7da4255aaea984b31bb71155f673257353b0e0554d0d30dcf859547e74602582", [:rebar3], [], "hexpm", "8c20ca00904de023a835a9dcb7b7762fed32264c85a80c3cafa85288e405044c"},
|
||||||
"ecto": {:hex, :ecto, "3.10.3", "eb2ae2eecd210b4eb8bece1217b297ad4ff824b4384c0e3fdd28aaf96edd6135", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "44bec74e2364d491d70f7e42cd0d690922659d329f6465e89feb8a34e8cd3433"},
|
"ecto": {:hex, :ecto, "3.10.3", "eb2ae2eecd210b4eb8bece1217b297ad4ff824b4384c0e3fdd28aaf96edd6135", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "44bec74e2364d491d70f7e42cd0d690922659d329f6465e89feb8a34e8cd3433"},
|
||||||
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},
|
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},
|
||||||
"ecto_psql_extras": {:hex, :ecto_psql_extras, "0.8.0", "440719cd74f09b3f01c84455707a2c3972b725c513808e68eb6c5b0ab82bf523", [:mix], [{:ecto_sql, "~> 3.7", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 0.18.0", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1 or ~> 4.0.0", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "f1512812dc196bcb932a96c82e55f69b543dc125e9d39f5e3631a9c4ec65ef12"},
|
"ecto_psql_extras": {:hex, :ecto_psql_extras, "0.8.2", "79350a53246ac5ec27326d208496aebceb77fa82a91744f66a9154560f0759d3", [:mix], [{:ecto_sql, "~> 3.7", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, "> 0.16.0 and < 0.20.0", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1 or ~> 4.0.0", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "6149c1c4a5ba6602a76cb09ee7a269eb60dab9694a1dbbb797f032555212de75"},
|
||||||
"ecto_sql": {:hex, :ecto_sql, "3.10.2", "6b98b46534b5c2f8b8b5f03f126e75e2a73c64f3c071149d32987a5378b0fdbd", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.10.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "68c018debca57cb9235e3889affdaec7a10616a4e3a80c99fa1d01fdafaa9007"},
|
"ecto_sql": {:hex, :ecto_sql, "3.10.2", "6b98b46534b5c2f8b8b5f03f126e75e2a73c64f3c071149d32987a5378b0fdbd", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.10.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "68c018debca57cb9235e3889affdaec7a10616a4e3a80c99fa1d01fdafaa9007"},
|
||||||
"elasticsearch": {:git, "https://akkoma.dev/AkkomaGang/elasticsearch-elixir.git", "6cd946f75f6ab9042521a009d1d32d29a90113ca", [ref: "main"]},
|
"elasticsearch": {:git, "https://akkoma.dev/AkkomaGang/elasticsearch-elixir.git", "6cd946f75f6ab9042521a009d1d32d29a90113ca", [ref: "main"]},
|
||||||
"elixir_make": {:hex, :elixir_make, "0.8.4", "4960a03ce79081dee8fe119d80ad372c4e7badb84c493cc75983f9d3bc8bde0f", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.0", [hex: :certifi, repo: "hexpm", optional: true]}], "hexpm", "6e7f1d619b5f61dfabd0a20aa268e575572b542ac31723293a4c1a567d5ef040"},
|
"elixir_make": {:hex, :elixir_make, "0.8.4", "4960a03ce79081dee8fe119d80ad372c4e7badb84c493cc75983f9d3bc8bde0f", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.0", [hex: :certifi, repo: "hexpm", optional: true]}], "hexpm", "6e7f1d619b5f61dfabd0a20aa268e575572b542ac31723293a4c1a567d5ef040"},
|
||||||
|
@ -37,10 +37,10 @@
|
||||||
"erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"},
|
"erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"},
|
||||||
"erlsom": {:hex, :erlsom, "1.5.1", "c8fe2babd33ff0846403f6522328b8ab676f896b793634cfe7ef181c05316c03", [:rebar3], [], "hexpm", "7965485494c5844dd127656ac40f141aadfa174839ec1be1074e7edf5b4239eb"},
|
"erlsom": {:hex, :erlsom, "1.5.1", "c8fe2babd33ff0846403f6522328b8ab676f896b793634cfe7ef181c05316c03", [:rebar3], [], "hexpm", "7965485494c5844dd127656ac40f141aadfa174839ec1be1074e7edf5b4239eb"},
|
||||||
"eternal": {:hex, :eternal, "1.2.2", "d1641c86368de99375b98d183042dd6c2b234262b8d08dfd72b9eeaafc2a1abd", [:mix], [], "hexpm", "2c9fe32b9c3726703ba5e1d43a1d255a4f3f2d8f8f9bc19f094c7cb1a7a9e782"},
|
"eternal": {:hex, :eternal, "1.2.2", "d1641c86368de99375b98d183042dd6c2b234262b8d08dfd72b9eeaafc2a1abd", [:mix], [], "hexpm", "2c9fe32b9c3726703ba5e1d43a1d255a4f3f2d8f8f9bc19f094c7cb1a7a9e782"},
|
||||||
"ex_aws": {:hex, :ex_aws, "2.5.4", "86c5bb870a49e0ab6f5aa5dd58cf505f09d2624ebe17530db3c1b61c88a673af", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8 or ~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e82bd0091bb9a5bb190139599f922ff3fc7aebcca4374d65c99c4e23aa6d1625"},
|
"ex_aws": {:hex, :ex_aws, "2.5.6", "6f642e0f82eff10a9b470044f084b81a791cf15b393d647ea5f3e65da2794e3d", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8 or ~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:req, "~> 0.3", [hex: :req, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c69eec59e31fdd89d0beeb1d97e16518dd1b23ad95b3d5c9f1dcfec23d97f960"},
|
||||||
"ex_aws_s3": {:hex, :ex_aws_s3, "2.5.3", "422468e5c3e1a4da5298e66c3468b465cfd354b842e512cb1f6fbbe4e2f5bdaf", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "4f09dd372cc386550e484808c5ac5027766c8d0cd8271ccc578b82ee6ef4f3b8"},
|
"ex_aws_s3": {:hex, :ex_aws_s3, "2.5.4", "87aaf4a2f24a48f516d7f5aaced9d128dd5d0f655c4431f9037a11a85c71109c", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "c06e7f68b33f7c0acba1361dbd951c79661a28f85aa2e0582990fccca4425355"},
|
||||||
"ex_const": {:hex, :ex_const, "0.3.0", "9d79516679991baf540ef445438eef1455ca91cf1a3c2680d8fb9e5bea2fe4de", [:mix], [], "hexpm", "76546322abb9e40ee4a2f454cf1c8a5b25c3672fa79bed1ea52c31e0d2428ca9"},
|
"ex_const": {:hex, :ex_const, "0.3.0", "9d79516679991baf540ef445438eef1455ca91cf1a3c2680d8fb9e5bea2fe4de", [:mix], [], "hexpm", "76546322abb9e40ee4a2f454cf1c8a5b25c3672fa79bed1ea52c31e0d2428ca9"},
|
||||||
"ex_doc": {:hex, :ex_doc, "0.34.1", "9751a0419bc15bc7580c73fde506b17b07f6402a1e5243be9e0f05a68c723368", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "d441f1a86a235f59088978eff870de2e815e290e44a8bd976fe5d64470a4c9d2"},
|
"ex_doc": {:hex, :ex_doc, "0.34.2", "13eedf3844ccdce25cfd837b99bea9ad92c4e511233199440488d217c92571e8", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "5ce5f16b41208a50106afed3de6a2ed34f4acfd65715b82a0b84b49d995f95c1"},
|
||||||
"ex_machina": {:hex, :ex_machina, "2.8.0", "a0e847b5712065055ec3255840e2c78ef9366634d62390839d4880483be38abe", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "79fe1a9c64c0c1c1fab6c4fa5d871682cb90de5885320c187d117004627a7729"},
|
"ex_machina": {:hex, :ex_machina, "2.8.0", "a0e847b5712065055ec3255840e2c78ef9366634d62390839d4880483be38abe", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "79fe1a9c64c0c1c1fab6c4fa5d871682cb90de5885320c187d117004627a7729"},
|
||||||
"ex_syslogger": {:hex, :ex_syslogger, "2.0.0", "de6de5c5472a9c4fdafb28fa6610e381ae79ebc17da6490b81d785d68bd124c9", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}, {:syslog, "~> 1.1.0", [hex: :syslog, repo: "hexpm", optional: false]}], "hexpm", "a52b2fe71764e9e6ecd149ab66635812f68e39279cbeee27c52c0e35e8b8019e"},
|
"ex_syslogger": {:hex, :ex_syslogger, "2.0.0", "de6de5c5472a9c4fdafb28fa6610e381ae79ebc17da6490b81d785d68bd124c9", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}, {:syslog, "~> 1.1.0", [hex: :syslog, repo: "hexpm", optional: false]}], "hexpm", "a52b2fe71764e9e6ecd149ab66635812f68e39279cbeee27c52c0e35e8b8019e"},
|
||||||
"excoveralls": {:hex, :excoveralls, "0.16.1", "0bd42ed05c7d2f4d180331a20113ec537be509da31fed5c8f7047ce59ee5a7c5", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "dae763468e2008cf7075a64cb1249c97cb4bc71e236c5c2b5e5cdf1cfa2bf138"},
|
"excoveralls": {:hex, :excoveralls, "0.16.1", "0bd42ed05c7d2f4d180331a20113ec537be509da31fed5c8f7047ce59ee5a7c5", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "dae763468e2008cf7075a64cb1249c97cb4bc71e236c5c2b5e5cdf1cfa2bf138"},
|
||||||
|
@ -48,10 +48,10 @@
|
||||||
"fast_html": {:hex, :fast_html, "2.3.0", "08c1d8ead840dd3060ba02c761bed9f37f456a1ddfe30bcdcfee8f651cec06a6", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "f18e3c7668f82d3ae0b15f48d48feeb257e28aa5ab1b0dbf781c7312e5da029d"},
|
"fast_html": {:hex, :fast_html, "2.3.0", "08c1d8ead840dd3060ba02c761bed9f37f456a1ddfe30bcdcfee8f651cec06a6", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "f18e3c7668f82d3ae0b15f48d48feeb257e28aa5ab1b0dbf781c7312e5da029d"},
|
||||||
"fast_sanitize": {:hex, :fast_sanitize, "0.2.3", "67b93dfb34e302bef49fec3aaab74951e0f0602fd9fa99085987af05bd91c7a5", [:mix], [{:fast_html, "~> 2.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "e8ad286d10d0386e15d67d0ee125245ebcfbc7d7290b08712ba9013c8c5e56e2"},
|
"fast_sanitize": {:hex, :fast_sanitize, "0.2.3", "67b93dfb34e302bef49fec3aaab74951e0f0602fd9fa99085987af05bd91c7a5", [:mix], [{:fast_html, "~> 2.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "e8ad286d10d0386e15d67d0ee125245ebcfbc7d7290b08712ba9013c8c5e56e2"},
|
||||||
"file_ex": {:git, "https://akkoma.dev/AkkomaGang/file_ex.git", "cc7067c7d446c2526e9ecf91d40896b088851569", [ref: "cc7067c7d446c2526e9ecf91d40896b088851569"]},
|
"file_ex": {:git, "https://akkoma.dev/AkkomaGang/file_ex.git", "cc7067c7d446c2526e9ecf91d40896b088851569", [ref: "cc7067c7d446c2526e9ecf91d40896b088851569"]},
|
||||||
"file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"},
|
"file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"},
|
||||||
"finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"},
|
"finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"},
|
||||||
"flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "31fc8090fde1acd267c07c36ea7365b8604055f897d3a53dd967658c691bd827"},
|
"flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "31fc8090fde1acd267c07c36ea7365b8604055f897d3a53dd967658c691bd827"},
|
||||||
"floki": {:hex, :floki, "0.36.2", "a7da0193538c93f937714a6704369711998a51a6164a222d710ebd54020aa7a3", [:mix], [], "hexpm", "a8766c0bc92f074e5cb36c4f9961982eda84c5d2b8e979ca67f5c268ec8ed580"},
|
"floki": {:hex, :floki, "0.36.3", "1102f93b16a55bc5383b85ae3ec470f82dee056eaeff9195e8afdf0ef2a43c30", [:mix], [], "hexpm", "fe0158bff509e407735f6d40b3ee0d7deb47f3f3ee7c6c182ad28599f9f6b27a"},
|
||||||
"gen_smtp": {:hex, :gen_smtp, "1.2.0", "9cfc75c72a8821588b9b9fe947ae5ab2aed95a052b81237e0928633a13276fd3", [:rebar3], [{:ranch, ">= 1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "5ee0375680bca8f20c4d85f58c2894441443a743355430ff33a783fe03296779"},
|
"gen_smtp": {:hex, :gen_smtp, "1.2.0", "9cfc75c72a8821588b9b9fe947ae5ab2aed95a052b81237e0928633a13276fd3", [:rebar3], [{:ranch, ">= 1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "5ee0375680bca8f20c4d85f58c2894441443a743355430ff33a783fe03296779"},
|
||||||
"gettext": {:hex, :gettext, "0.22.3", "c8273e78db4a0bb6fba7e9f0fd881112f349a3117f7f7c598fa18c66c888e524", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "935f23447713954a6866f1bb28c3a878c4c011e802bcd68a726f5e558e4b64bd"},
|
"gettext": {:hex, :gettext, "0.22.3", "c8273e78db4a0bb6fba7e9f0fd881112f349a3117f7f7c598fa18c66c888e524", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "935f23447713954a6866f1bb28c3a878c4c011e802bcd68a726f5e558e4b64bd"},
|
||||||
"hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"},
|
"hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"},
|
||||||
|
@ -61,33 +61,34 @@
|
||||||
"httpoison": {:hex, :httpoison, "1.8.2", "9eb9c63ae289296a544842ef816a85d881d4a31f518a0fec089aaa744beae290", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "2bb350d26972e30c96e2ca74a1aaf8293d61d0742ff17f01e0279fef11599921"},
|
"httpoison": {:hex, :httpoison, "1.8.2", "9eb9c63ae289296a544842ef816a85d881d4a31f518a0fec089aaa744beae290", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "2bb350d26972e30c96e2ca74a1aaf8293d61d0742ff17f01e0279fef11599921"},
|
||||||
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
|
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
|
||||||
"inet_cidr": {:hex, :inet_cidr, "1.0.8", "d26bb7bdbdf21ae401ead2092bf2bb4bf57fe44a62f5eaa5025280720ace8a40", [:mix], [], "hexpm", "d5b26da66603bb56c933c65214c72152f0de9a6ea53618b56d63302a68f6a90e"},
|
"inet_cidr": {:hex, :inet_cidr, "1.0.8", "d26bb7bdbdf21ae401ead2092bf2bb4bf57fe44a62f5eaa5025280720ace8a40", [:mix], [], "hexpm", "d5b26da66603bb56c933c65214c72152f0de9a6ea53618b56d63302a68f6a90e"},
|
||||||
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
|
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
|
||||||
"joken": {:hex, :joken, "2.6.1", "2ca3d8d7f83bf7196296a3d9b2ecda421a404634bfc618159981a960020480a1", [:mix], [{:jose, "~> 1.11.9", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "ab26122c400b3d254ce7d86ed066d6afad27e70416df947cdcb01e13a7382e68"},
|
"joken": {:hex, :joken, "2.6.2", "5daaf82259ca603af4f0b065475099ada1b2b849ff140ccd37f4b6828ca6892a", [:mix], [{:jose, "~> 1.11.10", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "5134b5b0a6e37494e46dbf9e4dad53808e5e787904b7c73972651b51cce3d72b"},
|
||||||
"jose": {:hex, :jose, "1.11.10", "a903f5227417bd2a08c8a00a0cbcc458118be84480955e8d251297a425723f83", [:mix, :rebar3], [], "hexpm", "0d6cd36ff8ba174db29148fc112b5842186b68a90ce9fc2b3ec3afe76593e614"},
|
"jose": {:hex, :jose, "1.11.10", "a903f5227417bd2a08c8a00a0cbcc458118be84480955e8d251297a425723f83", [:mix, :rebar3], [], "hexpm", "0d6cd36ff8ba174db29148fc112b5842186b68a90ce9fc2b3ec3afe76593e614"},
|
||||||
"jumper": {:hex, :jumper, "1.0.2", "68cdcd84472a00ac596b4e6459a41b3062d4427cbd4f1e8c8793c5b54f1406a7", [:mix], [], "hexpm", "9b7782409021e01ab3c08270e26f36eb62976a38c1aa64b2eaf6348422f165e1"},
|
"jumper": {:hex, :jumper, "1.0.2", "68cdcd84472a00ac596b4e6459a41b3062d4427cbd4f1e8c8793c5b54f1406a7", [:mix], [], "hexpm", "9b7782409021e01ab3c08270e26f36eb62976a38c1aa64b2eaf6348422f165e1"},
|
||||||
"linkify": {:hex, :linkify, "0.5.3", "5f8143d8f61f5ff08d3aeeff47ef6509492b4948d8f08007fbf66e4d2246a7f2", [:mix], [], "hexpm", "3ef35a1377d47c25506e07c1c005ea9d38d700699d92ee92825f024434258177"},
|
"linkify": {:hex, :linkify, "0.5.3", "5f8143d8f61f5ff08d3aeeff47ef6509492b4948d8f08007fbf66e4d2246a7f2", [:mix], [], "hexpm", "3ef35a1377d47c25506e07c1c005ea9d38d700699d92ee92825f024434258177"},
|
||||||
"mail": {:hex, :mail, "0.3.1", "cb0a14e4ed8904e4e5a08214e686ccf6f9099346885db17d8c309381f865cc5c", [:mix], [], "hexpm", "1db701e89865c1d5fa296b2b57b1cd587587cca8d8a1a22892b35ef5a8e352a6"},
|
"mail": {:hex, :mail, "0.4.2", "959229676ef11dfdfb1269ce4a611622cb70415a1d6f925d79e547848bafc14d", [:mix], [], "hexpm", "08e5b70c72b8d1605cb88ef2df2c7e41d002210a621503ea1c13f1a7916b6bd3"},
|
||||||
"majic": {:git, "https://akkoma.dev/AkkomaGang/majic.git", "80540b36939ec83f48e76c61e5000e0fd67706f0", [ref: "80540b36939ec83f48e76c61e5000e0fd67706f0"]},
|
"majic": {:git, "https://akkoma.dev/AkkomaGang/majic.git", "80540b36939ec83f48e76c61e5000e0fd67706f0", [ref: "80540b36939ec83f48e76c61e5000e0fd67706f0"]},
|
||||||
"makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"},
|
"makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"},
|
||||||
"makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"},
|
"makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"},
|
||||||
"makeup_erlang": {:hex, :makeup_erlang, "1.0.0", "6f0eff9c9c489f26b69b61440bf1b238d95badae49adac77973cbacae87e3c2e", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "ea7a9307de9d1548d2a72d299058d1fd2339e3d398560a0e46c27dab4891e4d2"},
|
"makeup_erlang": {:hex, :makeup_erlang, "1.0.1", "c7f58c120b2b5aa5fd80d540a89fdf866ed42f1f3994e4fe189abebeab610839", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "8a89a1eeccc2d798d6ea15496a6e4870b75e014d1af514b1b71fa33134f57814"},
|
||||||
"meck": {:hex, :meck, "0.9.2", "85ccbab053f1db86c7ca240e9fc718170ee5bda03810a6292b5306bf31bae5f5", [:rebar3], [], "hexpm", "81344f561357dc40a8344afa53767c32669153355b626ea9fcbc8da6b3045826"},
|
"meck": {:hex, :meck, "0.9.2", "85ccbab053f1db86c7ca240e9fc718170ee5bda03810a6292b5306bf31bae5f5", [:rebar3], [], "hexpm", "81344f561357dc40a8344afa53767c32669153355b626ea9fcbc8da6b3045826"},
|
||||||
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
|
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
|
||||||
"mfm_parser": {:git, "https://akkoma.dev/AkkomaGang/mfm-parser.git", "b21ab7754024af096f2d14247574f55f0063295b", [ref: "b21ab7754024af096f2d14247574f55f0063295b"]},
|
"mfm_parser": {:git, "https://akkoma.dev/AkkomaGang/mfm-parser.git", "b21ab7754024af096f2d14247574f55f0063295b", [ref: "b21ab7754024af096f2d14247574f55f0063295b"]},
|
||||||
"mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"},
|
"mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"},
|
||||||
"mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"},
|
"mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"},
|
||||||
"mint": {:hex, :mint, "1.5.2", "4805e059f96028948870d23d7783613b7e6b0e2fb4e98d720383852a760067fd", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "d77d9e9ce4eb35941907f1d3df38d8f750c357865353e21d335bdcdf6d892a02"},
|
"mint": {:hex, :mint, "1.5.2", "4805e059f96028948870d23d7783613b7e6b0e2fb4e98d720383852a760067fd", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "d77d9e9ce4eb35941907f1d3df38d8f750c357865353e21d335bdcdf6d892a02"},
|
||||||
"mock": {:hex, :mock, "0.3.8", "7046a306b71db2488ef54395eeb74df0a7f335a7caca4a3d3875d1fc81c884dd", [:mix], [{:meck, "~> 0.9.2", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "7fa82364c97617d79bb7d15571193fc0c4fe5afd0c932cef09426b3ee6fe2022"},
|
"mock": {:hex, :mock, "0.3.8", "7046a306b71db2488ef54395eeb74df0a7f335a7caca4a3d3875d1fc81c884dd", [:mix], [{:meck, "~> 0.9.2", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "7fa82364c97617d79bb7d15571193fc0c4fe5afd0c932cef09426b3ee6fe2022"},
|
||||||
"mogrify": {:hex, :mogrify, "0.9.3", "238c782f00271dace01369ad35ae2e9dd020feee3443b9299ea5ea6bed559841", [:mix], [], "hexpm", "0189b1e1de27455f2b9ae8cf88239cefd23d38de9276eb5add7159aea51731e6"},
|
"mogrify": {:hex, :mogrify, "0.9.3", "238c782f00271dace01369ad35ae2e9dd020feee3443b9299ea5ea6bed559841", [:mix], [], "hexpm", "0189b1e1de27455f2b9ae8cf88239cefd23d38de9276eb5add7159aea51731e6"},
|
||||||
"mox": {:hex, :mox, "1.1.0", "0f5e399649ce9ab7602f72e718305c0f9cdc351190f72844599545e4996af73c", [:mix], [], "hexpm", "d44474c50be02d5b72131070281a5d3895c0e7a95c780e90bc0cfe712f633a13"},
|
"mox": {:hex, :mox, "1.2.0", "a2cd96b4b80a3883e3100a221e8adc1b98e4c3a332a8fc434c39526babafd5b3", [:mix], [{:nimble_ownership, "~> 1.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}], "hexpm", "c7b92b3cc69ee24a7eeeaf944cd7be22013c52fcb580c1f33f50845ec821089a"},
|
||||||
"nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"},
|
"nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"},
|
||||||
|
"nimble_ownership": {:hex, :nimble_ownership, "1.0.0", "3f87744d42c21b2042a0aa1d48c83c77e6dd9dd357e425a038dd4b49ba8b79a1", [:mix], [], "hexpm", "7c16cc74f4e952464220a73055b557a273e8b1b7ace8489ec9d86e9ad56cb2cc"},
|
||||||
"nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"},
|
"nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"},
|
||||||
"nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"},
|
"nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"},
|
||||||
"oban": {:hex, :oban, "2.17.11", "7a641f9f737b626030c3e2209b53df6db83740ac5537208bac7d3b9871c2d5e7", [:mix], [{:ecto_sql, "~> 3.10", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c445c488151939d64265a5efea51973fa0b42ee4ebbb31aa83fac26543b8ac6d"},
|
"oban": {:hex, :oban, "2.17.12", "33fb0cbfb92b910d48dd91a908590fe3698bb85eacec8cd0d9bc6aa13dddd6d6", [:mix], [{:ecto_sql, "~> 3.10", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7a647d6cd6bb300073db17faabce22d80ae135da3baf3180a064fa7c4fa046e3"},
|
||||||
"open_api_spex": {:hex, :open_api_spex, "3.19.1", "65ccb5d06e3d664d1eec7c5ea2af2289bd2f37897094a74d7219fb03fc2b5994", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "392895827ce2984a3459c91a484e70708132d8c2c6c5363972b4b91d6bbac3dd"},
|
"open_api_spex": {:hex, :open_api_spex, "3.21.2", "6a704f3777761feeb5657340250d6d7332c545755116ca98f33d4b875777e1e5", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0 or ~> 6.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "f42ae6ed668b895ebba3e02773cfb4b41050df26f803f2ef634c72a7687dc387"},
|
||||||
"parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
|
"parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
|
||||||
"phoenix": {:hex, :phoenix, "1.7.14", "a7d0b3f1bc95987044ddada111e77bd7f75646a08518942c72a8440278ae7825", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "c7859bc56cc5dfef19ecfc240775dae358cbaa530231118a9e014df392ace61a"},
|
"phoenix": {:hex, :phoenix, "1.7.14", "a7d0b3f1bc95987044ddada111e77bd7f75646a08518942c72a8440278ae7825", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "c7859bc56cc5dfef19ecfc240775dae358cbaa530231118a9e014df392ace61a"},
|
||||||
"phoenix_ecto": {:hex, :phoenix_ecto, "4.6.1", "96798325fab2fed5a824ca204e877b81f9afd2e480f581e81f7b4b64a5a477f2", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.17", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "0ae544ff99f3c482b0807c5cec2c8289e810ecacabc04959d82c3337f4703391"},
|
"phoenix_ecto": {:hex, :phoenix_ecto, "4.6.3", "f686701b0499a07f2e3b122d84d52ff8a31f5def386e03706c916f6feddf69ef", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "909502956916a657a197f94cc1206d9a65247538de8a5e186f7537c895d95764"},
|
||||||
"phoenix_html": {:hex, :phoenix_html, "3.3.4", "42a09fc443bbc1da37e372a5c8e6755d046f22b9b11343bf885067357da21cb3", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0249d3abec3714aff3415e7ee3d9786cb325be3151e6c4b3021502c585bf53fb"},
|
"phoenix_html": {:hex, :phoenix_html, "3.3.4", "42a09fc443bbc1da37e372a5c8e6755d046f22b9b11343bf885067357da21cb3", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0249d3abec3714aff3415e7ee3d9786cb325be3151e6c4b3021502c585bf53fb"},
|
||||||
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.7.2", "97cc4ff2dba1ebe504db72cb45098cb8e91f11160528b980bd282cc45c73b29c", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.18.3", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "0e5fdf063c7a3b620c566a30fcf68b7ee02e5e46fe48ee46a6ec3ba382dc05b7"},
|
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.7.2", "97cc4ff2dba1ebe504db72cb45098cb8e91f11160528b980bd282cc45c73b29c", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.18.3", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "0e5fdf063c7a3b620c566a30fcf68b7ee02e5e46fe48ee46a6ec3ba382dc05b7"},
|
||||||
"phoenix_live_view": {:hex, :phoenix_live_view, "0.18.18", "1f38fbd7c363723f19aad1a04b5490ff3a178e37daaf6999594d5f34796c47fc", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a5810d0472f3189ede6d2a95bda7f31c6113156b91784a3426cb0ab6a6d85214"},
|
"phoenix_live_view": {:hex, :phoenix_live_view, "0.18.18", "1f38fbd7c363723f19aad1a04b5490ff3a178e37daaf6999594d5f34796c47fc", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a5810d0472f3189ede6d2a95bda7f31c6113156b91784a3426cb0ab6a6d85214"},
|
||||||
|
@ -96,7 +97,7 @@
|
||||||
"phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},
|
"phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},
|
||||||
"phoenix_view": {:hex, :phoenix_view, "2.0.4", "b45c9d9cf15b3a1af5fb555c674b525391b6a1fe975f040fb4d913397b31abf4", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "4e992022ce14f31fe57335db27a28154afcc94e9983266835bb3040243eb620b"},
|
"phoenix_view": {:hex, :phoenix_view, "2.0.4", "b45c9d9cf15b3a1af5fb555c674b525391b6a1fe975f040fb4d913397b31abf4", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "4e992022ce14f31fe57335db27a28154afcc94e9983266835bb3040243eb620b"},
|
||||||
"plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"},
|
"plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"},
|
||||||
"plug_cowboy": {:hex, :plug_cowboy, "2.7.1", "87677ffe3b765bc96a89be7960f81703223fe2e21efa42c125fcd0127dd9d6b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "02dbd5f9ab571b864ae39418db7811618506256f6d13b4a45037e5fe78dc5de3"},
|
"plug_cowboy": {:hex, :plug_cowboy, "2.7.2", "fdadb973799ae691bf9ecad99125b16625b1c6039999da5fe544d99218e662e4", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "245d8a11ee2306094840c000e8816f0cbed69a23fc0ac2bcf8d7835ae019bb2f"},
|
||||||
"plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"},
|
"plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"},
|
||||||
"plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "79fd4fcf34d110605c26560cbae8f23c603ec4158c08298bd4360fdea90bb5cf"},
|
"plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "79fd4fcf34d110605c26560cbae8f23c603ec4158c08298bd4360fdea90bb5cf"},
|
||||||
"poison": {:hex, :poison, "5.0.0", "d2b54589ab4157bbb82ec2050757779bfed724463a544b6e20d79855a9e43b24", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "11dc6117c501b80c62a7594f941d043982a1bd05a1184280c0d9166eb4d8d3fc"},
|
"poison": {:hex, :poison, "5.0.0", "d2b54589ab4157bbb82ec2050757779bfed724463a544b6e20d79855a9e43b24", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "11dc6117c501b80c62a7594f941d043982a1bd05a1184280c0d9166eb4d8d3fc"},
|
||||||
|
@ -104,7 +105,7 @@
|
||||||
"postgrex": {:hex, :postgrex, "0.17.5", "0483d054938a8dc069b21bdd636bf56c487404c241ce6c319c1f43588246b281", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "50b8b11afbb2c4095a3ba675b4f055c416d0f3d7de6633a595fc131a828a67eb"},
|
"postgrex": {:hex, :postgrex, "0.17.5", "0483d054938a8dc069b21bdd636bf56c487404c241ce6c319c1f43588246b281", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "50b8b11afbb2c4095a3ba675b4f055c416d0f3d7de6633a595fc131a828a67eb"},
|
||||||
"pot": {:hex, :pot, "1.0.2", "13abb849139fdc04ab8154986abbcb63bdee5de6ed2ba7e1713527e33df923dd", [:rebar3], [], "hexpm", "78fe127f5a4f5f919d6ea5a2a671827bd53eb9d37e5b4128c0ad3df99856c2e0"},
|
"pot": {:hex, :pot, "1.0.2", "13abb849139fdc04ab8154986abbcb63bdee5de6ed2ba7e1713527e33df923dd", [:rebar3], [], "hexpm", "78fe127f5a4f5f919d6ea5a2a671827bd53eb9d37e5b4128c0ad3df99856c2e0"},
|
||||||
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
|
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
|
||||||
"recon": {:hex, :recon, "2.5.5", "c108a4c406fa301a529151a3bb53158cadc4064ec0c5f99b03ddb8c0e4281bdf", [:mix, :rebar3], [], "hexpm", "632a6f447df7ccc1a4a10bdcfce71514412b16660fe59deca0fcf0aa3c054404"},
|
"recon": {:hex, :recon, "2.5.6", "9052588e83bfedfd9b72e1034532aee2a5369d9d9343b61aeb7fbce761010741", [:mix, :rebar3], [], "hexpm", "96c6799792d735cc0f0fd0f86267e9d351e63339cbe03df9d162010cefc26bb0"},
|
||||||
"remote_ip": {:hex, :remote_ip, "1.1.0", "cb308841595d15df3f9073b7c39243a1dd6ca56e5020295cb012c76fbec50f2d", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "616ffdf66aaad6a72fc546dabf42eed87e2a99e97b09cbd92b10cc180d02ed74"},
|
"remote_ip": {:hex, :remote_ip, "1.1.0", "cb308841595d15df3f9073b7c39243a1dd6ca56e5020295cb012c76fbec50f2d", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "616ffdf66aaad6a72fc546dabf42eed87e2a99e97b09cbd92b10cc180d02ed74"},
|
||||||
"search_parser": {:git, "https://github.com/FloatingGhost/pleroma-contrib-search-parser.git", "08971a81e68686f9ac465cfb6661d51c5e4e1e7f", [ref: "08971a81e68686f9ac465cfb6661d51c5e4e1e7f"]},
|
"search_parser": {:git, "https://github.com/FloatingGhost/pleroma-contrib-search-parser.git", "08971a81e68686f9ac465cfb6661d51c5e4e1e7f", [ref: "08971a81e68686f9ac465cfb6661d51c5e4e1e7f"]},
|
||||||
"sleeplocks": {:hex, :sleeplocks, "1.1.3", "96a86460cc33b435c7310dbd27ec82ca2c1f24ae38e34f8edde97f756503441a", [:rebar3], [], "hexpm", "d3b3958552e6eb16f463921e70ae7c767519ef8f5be46d7696cc1ed649421321"},
|
"sleeplocks": {:hex, :sleeplocks, "1.1.3", "96a86460cc33b435c7310dbd27ec82ca2c1f24ae38e34f8edde97f756503441a", [:rebar3], [], "hexpm", "d3b3958552e6eb16f463921e70ae7c767519ef8f5be46d7696cc1ed649421321"},
|
||||||
|
@ -114,22 +115,22 @@
|
||||||
"swoosh": {:hex, :swoosh, "1.14.4", "94e9dba91f7695a10f49b0172c4a4cb658ef24abef7e8140394521b7f3bbb2d4", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.4 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "081c5a590e4ba85cc89baddf7b2beecf6c13f7f84a958f1cd969290815f0f026"},
|
"swoosh": {:hex, :swoosh, "1.14.4", "94e9dba91f7695a10f49b0172c4a4cb658ef24abef7e8140394521b7f3bbb2d4", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.4 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "081c5a590e4ba85cc89baddf7b2beecf6c13f7f84a958f1cd969290815f0f026"},
|
||||||
"syslog": {:hex, :syslog, "1.1.0", "6419a232bea84f07b56dc575225007ffe34d9fdc91abe6f1b2f254fd71d8efc2", [:rebar3], [], "hexpm", "4c6a41373c7e20587be33ef841d3de6f3beba08519809329ecc4d27b15b659e1"},
|
"syslog": {:hex, :syslog, "1.1.0", "6419a232bea84f07b56dc575225007ffe34d9fdc91abe6f1b2f254fd71d8efc2", [:rebar3], [], "hexpm", "4c6a41373c7e20587be33ef841d3de6f3beba08519809329ecc4d27b15b659e1"},
|
||||||
"table_rex": {:hex, :table_rex, "4.0.0", "3c613a68ebdc6d4d1e731bc973c233500974ec3993c99fcdabb210407b90959b", [:mix], [], "hexpm", "c35c4d5612ca49ebb0344ea10387da4d2afe278387d4019e4d8111e815df8f55"},
|
"table_rex": {:hex, :table_rex, "4.0.0", "3c613a68ebdc6d4d1e731bc973c233500974ec3993c99fcdabb210407b90959b", [:mix], [], "hexpm", "c35c4d5612ca49ebb0344ea10387da4d2afe278387d4019e4d8111e815df8f55"},
|
||||||
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
|
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
|
||||||
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.2", "2caabe9344ec17eafe5403304771c3539f3b6e2f7fb6a6f602558c825d0d0bfb", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9b43db0dc33863930b9ef9d27137e78974756f5f198cae18409970ed6fa5b561"},
|
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.2", "2caabe9344ec17eafe5403304771c3539f3b6e2f7fb6a6f602558c825d0d0bfb", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9b43db0dc33863930b9ef9d27137e78974756f5f198cae18409970ed6fa5b561"},
|
||||||
"telemetry_metrics_prometheus": {:hex, :telemetry_metrics_prometheus, "1.1.0", "1cc23e932c1ef9aa3b91db257ead31ea58d53229d407e059b29bb962c1505a13", [:mix], [{:plug_cowboy, "~> 2.1", [hex: :plug_cowboy, repo: "hexpm", optional: false]}, {:telemetry_metrics_prometheus_core, "~> 1.0", [hex: :telemetry_metrics_prometheus_core, repo: "hexpm", optional: false]}], "hexpm", "d43b3659b3244da44fe0275b717701542365d4519b79d9ce895b9719c1ce4d26"},
|
"telemetry_metrics_prometheus": {:hex, :telemetry_metrics_prometheus, "1.1.0", "1cc23e932c1ef9aa3b91db257ead31ea58d53229d407e059b29bb962c1505a13", [:mix], [{:plug_cowboy, "~> 2.1", [hex: :plug_cowboy, repo: "hexpm", optional: false]}, {:telemetry_metrics_prometheus_core, "~> 1.0", [hex: :telemetry_metrics_prometheus_core, repo: "hexpm", optional: false]}], "hexpm", "d43b3659b3244da44fe0275b717701542365d4519b79d9ce895b9719c1ce4d26"},
|
||||||
"telemetry_metrics_prometheus_core": {:hex, :telemetry_metrics_prometheus_core, "1.1.0", "4e15f6d7dbedb3a4e3aed2262b7e1407f166fcb9c30ca3f96635dfbbef99965c", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "0dd10e7fe8070095df063798f82709b0a1224c31b8baf6278b423898d591a069"},
|
"telemetry_metrics_prometheus_core": {:hex, :telemetry_metrics_prometheus_core, "1.1.0", "4e15f6d7dbedb3a4e3aed2262b7e1407f166fcb9c30ca3f96635dfbbef99965c", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "0dd10e7fe8070095df063798f82709b0a1224c31b8baf6278b423898d591a069"},
|
||||||
"telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"},
|
"telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"},
|
||||||
"temple": {:git, "https://akkoma.dev/AkkomaGang/temple.git", "066a699ade472d8fa42a9d730b29a61af9bc8b59", [ref: "066a699ade472d8fa42a9d730b29a61af9bc8b59"]},
|
"temple": {:git, "https://akkoma.dev/AkkomaGang/temple.git", "066a699ade472d8fa42a9d730b29a61af9bc8b59", [ref: "066a699ade472d8fa42a9d730b29a61af9bc8b59"]},
|
||||||
"tesla": {:hex, :tesla, "1.11.0", "81b2b10213dddb27105ec6102d9eb0cc93d7097a918a0b1594f2dfd1a4601190", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, ">= 1.0.0", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.2", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "b83ab5d4c2d202e1ea2b7e17a49f788d49a699513d7c4f08f2aef2c281be69db"},
|
"tesla": {:hex, :tesla, "1.13.0", "24a068a48d107080dd7c943a593997eee265977a38020eb2ab657cca78a12502", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, ">= 1.0.0", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.2", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:mox, "~> 1.0", [hex: :mox, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "7b8fc8f6b0640fa0d090af7889d12eb396460e044b6f8688a8e55e30406a2200"},
|
||||||
"timex": {:hex, :timex, "3.7.11", "bb95cb4eb1d06e27346325de506bcc6c30f9c6dea40d1ebe390b262fad1862d1", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.20", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "8b9024f7efbabaf9bd7aa04f65cf8dcd7c9818ca5737677c7b76acbc6a94d1aa"},
|
"timex": {:hex, :timex, "3.7.11", "bb95cb4eb1d06e27346325de506bcc6c30f9c6dea40d1ebe390b262fad1862d1", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.20", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "8b9024f7efbabaf9bd7aa04f65cf8dcd7c9818ca5737677c7b76acbc6a94d1aa"},
|
||||||
"trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bd4fde4c15f3e993a999e019d64347489b91b7a9096af68b2bdadd192afa693f"},
|
"trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bd4fde4c15f3e993a999e019d64347489b91b7a9096af68b2bdadd192afa693f"},
|
||||||
"tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"},
|
"tzdata": {:hex, :tzdata, "1.1.2", "45e5f1fcf8729525ec27c65e163be5b3d247ab1702581a94674e008413eef50b", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "cec7b286e608371602318c414f344941d5eb0375e14cfdab605cca2fe66cba8b"},
|
||||||
"ueberauth": {:hex, :ueberauth, "0.10.5", "806adb703df87e55b5615cf365e809f84c20c68aa8c08ff8a416a5a6644c4b02", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "3efd1f31d490a125c7ed453b926f7c31d78b97b8a854c755f5c40064bf3ac9e1"},
|
"ueberauth": {:hex, :ueberauth, "0.10.5", "806adb703df87e55b5615cf365e809f84c20c68aa8c08ff8a416a5a6644c4b02", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "3efd1f31d490a125c7ed453b926f7c31d78b97b8a854c755f5c40064bf3ac9e1"},
|
||||||
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
|
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
|
||||||
"unsafe": {:hex, :unsafe, "1.0.2", "23c6be12f6c1605364801f4b47007c0c159497d0446ad378b5cf05f1855c0581", [:mix], [], "hexpm", "b485231683c3ab01a9cd44cb4a79f152c6f3bb87358439c6f68791b85c2df675"},
|
"unsafe": {:hex, :unsafe, "1.0.2", "23c6be12f6c1605364801f4b47007c0c159497d0446ad378b5cf05f1855c0581", [:mix], [], "hexpm", "b485231683c3ab01a9cd44cb4a79f152c6f3bb87358439c6f68791b85c2df675"},
|
||||||
"vex": {:hex, :vex, "0.9.2", "fe061acc9e0907d983d46b51bf35d58176f0fe6eb7ba3b33c9336401bf42b6d1", [:mix], [], "hexpm", "76e709a9762e98c6b462dfce92e9b5dfbf712839227f2da8add6dd11549b12cb"},
|
"vex": {:hex, :vex, "0.9.2", "fe061acc9e0907d983d46b51bf35d58176f0fe6eb7ba3b33c9336401bf42b6d1", [:mix], [], "hexpm", "76e709a9762e98c6b462dfce92e9b5dfbf712839227f2da8add6dd11549b12cb"},
|
||||||
"web_push_encryption": {:hex, :web_push_encryption, "0.3.1", "76d0e7375142dfee67391e7690e89f92578889cbcf2879377900b5620ee4708d", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jose, "~> 1.11.1", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "4f82b2e57622fb9337559058e8797cb0df7e7c9790793bdc4e40bc895f70e2a2"},
|
"web_push_encryption": {:hex, :web_push_encryption, "0.3.1", "76d0e7375142dfee67391e7690e89f92578889cbcf2879377900b5620ee4708d", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jose, "~> 1.11.1", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "4f82b2e57622fb9337559058e8797cb0df7e7c9790793bdc4e40bc895f70e2a2"},
|
||||||
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
|
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
|
||||||
"websock_adapter": {:hex, :websock_adapter, "0.5.6", "0437fe56e093fd4ac422de33bf8fc89f7bc1416a3f2d732d8b2c8fd54792fe60", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "e04378d26b0af627817ae84c92083b7e97aca3121196679b73c73b99d0d133ea"},
|
"websock_adapter": {:hex, :websock_adapter, "0.5.7", "65fa74042530064ef0570b75b43f5c49bb8b235d6515671b3d250022cb8a1f9e", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "d0f478ee64deddfec64b800673fd6e0c8888b079d9f3444dd96d2a98383bdbd1"},
|
||||||
"websockex": {:hex, :websockex, "0.4.3", "92b7905769c79c6480c02daacaca2ddd49de936d912976a4d3c923723b647bf0", [:mix], [], "hexpm", "95f2e7072b85a3a4cc385602d42115b73ce0b74a9121d0d6dbbf557645ac53e4"},
|
"websockex": {:hex, :websockex, "0.4.3", "92b7905769c79c6480c02daacaca2ddd49de936d912976a4d3c923723b647bf0", [:mix], [], "hexpm", "95f2e7072b85a3a4cc385602d42115b73ce0b74a9121d0d6dbbf557645ac53e4"},
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,5 @@ def change do
|
||||||
add :private_key, :text
|
add :private_key, :text
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
||||||
create unique_index(:signing_keys, [:key_id])
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,13 +8,15 @@ def up do
|
||||||
# we do not handle remote users here!
|
# we do not handle remote users here!
|
||||||
# because we want to store a key id -> user id mapping, and we don't
|
# because we want to store a key id -> user id mapping, and we don't
|
||||||
# currently store key ids for remote users...
|
# currently store key ids for remote users...
|
||||||
query =
|
# Also this MUST use select, else the migration will fail in future installs with new user fields!
|
||||||
from(u in User)
|
from(u in Pleroma.User,
|
||||||
|> where(local: true)
|
where: u.local == true,
|
||||||
|
select: {u.id, u.keys, u.ap_id}
|
||||||
Repo.stream(query, timeout: :infinity)
|
)
|
||||||
|
|> Repo.stream(timeout: :infinity)
|
||||||
|> Enum.each(fn
|
|> Enum.each(fn
|
||||||
%User{id: user_id, keys: private_key, local: true} ->
|
{user_id, private_key, ap_id} ->
|
||||||
|
IO.puts("Migrating user #{user_id}")
|
||||||
# we can precompute the public key here...
|
# we can precompute the public key here...
|
||||||
# we do use it on every user view which makes it a bit of a dos attack vector
|
# we do use it on every user view which makes it a bit of a dos attack vector
|
||||||
# so we should probably cache it
|
# so we should probably cache it
|
||||||
|
@ -23,6 +25,7 @@ def up do
|
||||||
key = %User.SigningKey{
|
key = %User.SigningKey{
|
||||||
user_id: user_id,
|
user_id: user_id,
|
||||||
public_key: public_key,
|
public_key: public_key,
|
||||||
|
key_id: User.SigningKey.local_key_id(ap_id),
|
||||||
private_key: private_key
|
private_key: private_key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.AddSigningKeyIndex do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
create_if_not_exists(index(:signing_keys, [:user_id], name: :signing_keys_user_id_index))
|
||||||
|
end
|
||||||
|
end
|
|
@ -124,6 +124,119 @@ defmodule Pleroma.HTML.Scrubber.Default do
|
||||||
Meta.allow_tag_with_these_attributes(:font, ["face"])
|
Meta.allow_tag_with_these_attributes(:font, ["face"])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if Pleroma.Config.get!([:markup, :allow_math]) do
|
||||||
|
Meta.allow_tag_with_these_attributes("annotation", ["encoding"])
|
||||||
|
Meta.allow_tag_with_these_attributes(:"annotation-xml", ["encoding"])
|
||||||
|
|
||||||
|
Meta.allow_tag_with_these_attributes(:math, [
|
||||||
|
"display",
|
||||||
|
"displaystyle",
|
||||||
|
"mathvariant",
|
||||||
|
"scriptlevel"
|
||||||
|
])
|
||||||
|
|
||||||
|
basic_math_tags = [
|
||||||
|
"maction",
|
||||||
|
"merror",
|
||||||
|
:mi,
|
||||||
|
"mmultiscripts",
|
||||||
|
:mn,
|
||||||
|
"mphantom",
|
||||||
|
"mprescripts",
|
||||||
|
"mroot",
|
||||||
|
"mrow",
|
||||||
|
"ms",
|
||||||
|
"msqrt",
|
||||||
|
"mstyle",
|
||||||
|
"msub",
|
||||||
|
"msubsup",
|
||||||
|
"msup",
|
||||||
|
"mtable",
|
||||||
|
"mtext",
|
||||||
|
"mtr",
|
||||||
|
"semantics"
|
||||||
|
]
|
||||||
|
|
||||||
|
for tag <- basic_math_tags do
|
||||||
|
Meta.allow_tag_with_these_attributes(unquote(tag), [
|
||||||
|
"mathvariant",
|
||||||
|
"displaystyle",
|
||||||
|
"scriptlevel"
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
Meta.allow_tag_with_these_attributes("mfrac", [
|
||||||
|
"displaystyle",
|
||||||
|
"linethickness",
|
||||||
|
"mathvariant",
|
||||||
|
"scriptlevel"
|
||||||
|
])
|
||||||
|
|
||||||
|
Meta.allow_tag_with_these_attributes(:mo, [
|
||||||
|
"displaystyle",
|
||||||
|
"form",
|
||||||
|
"largeop",
|
||||||
|
"lspace",
|
||||||
|
"mathvariant",
|
||||||
|
"minsize",
|
||||||
|
"movablelimits",
|
||||||
|
"rspace",
|
||||||
|
"scriptlevel",
|
||||||
|
"stretchy",
|
||||||
|
"symmetric"
|
||||||
|
])
|
||||||
|
|
||||||
|
Meta.allow_tag_with_these_attributes("mover", [
|
||||||
|
"accent",
|
||||||
|
"displaystyle",
|
||||||
|
"mathvariant",
|
||||||
|
"scriptlevel"
|
||||||
|
])
|
||||||
|
|
||||||
|
Meta.allow_tag_with_these_attributes("mpadded", [
|
||||||
|
"depth",
|
||||||
|
"displaystyle",
|
||||||
|
"height",
|
||||||
|
"lspace",
|
||||||
|
"mathvariant",
|
||||||
|
"scriptlevel",
|
||||||
|
"voffset",
|
||||||
|
"width"
|
||||||
|
])
|
||||||
|
|
||||||
|
Meta.allow_tag_with_these_attributes("mspace", [
|
||||||
|
"depth",
|
||||||
|
"displaystyle",
|
||||||
|
"height",
|
||||||
|
"mathvariant",
|
||||||
|
"scriptlevel",
|
||||||
|
"width"
|
||||||
|
])
|
||||||
|
|
||||||
|
Meta.allow_tag_with_these_attributes("mtd", [
|
||||||
|
"columnspan",
|
||||||
|
"displaystyle",
|
||||||
|
"mathvariant",
|
||||||
|
"rowspan",
|
||||||
|
"scriptlevel"
|
||||||
|
])
|
||||||
|
|
||||||
|
Meta.allow_tag_with_these_attributes("munder", [
|
||||||
|
"accentunder",
|
||||||
|
"displaystyle",
|
||||||
|
"mathvariant",
|
||||||
|
"scriptlevel"
|
||||||
|
])
|
||||||
|
|
||||||
|
Meta.allow_tag_with_these_attributes("munderover", [
|
||||||
|
"accent",
|
||||||
|
"accentunder",
|
||||||
|
"displaystyle",
|
||||||
|
"mathvariant",
|
||||||
|
"scriptlevel"
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
Meta.allow_tag_with_these_attributes(:center, [])
|
Meta.allow_tag_with_these_attributes(:center, [])
|
||||||
Meta.allow_tag_with_these_attributes(:small, [])
|
Meta.allow_tag_with_these_attributes(:small, [])
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,6 @@ test "error if file with custom settings doesn't exist" do
|
||||||
clear_config(:configurable_from_database, true)
|
clear_config(:configurable_from_database, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag capture_log: true
|
|
||||||
test "config migration refused when deprecated settings are found" do
|
test "config migration refused when deprecated settings are found" do
|
||||||
clear_config([:media_proxy, :whitelist], ["domain_without_scheme.com"])
|
clear_config([:media_proxy, :whitelist], ["domain_without_scheme.com"])
|
||||||
assert config_records() == []
|
assert config_records() == []
|
||||||
|
|
|
@ -64,7 +64,10 @@ test "returns error when zip file is bad", %{pack: pack} do
|
||||||
path: Path.absname("test/instance_static/emoji/test_pack/blank.png")
|
path: Path.absname("test/instance_static/emoji/test_pack/blank.png")
|
||||||
}
|
}
|
||||||
|
|
||||||
assert Pack.add_file(pack, nil, nil, file) == {:error, :einval}
|
# this varies by erlang OTP
|
||||||
|
possible_error_codes = [:bad_eocd, :einval]
|
||||||
|
{:error, code} = Pack.add_file(pack, nil, nil, file)
|
||||||
|
assert Enum.member?(possible_error_codes, code)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns pack when zip file is empty", %{pack: pack} do
|
test "returns pack when zip file is empty", %{pack: pack} do
|
||||||
|
|
|
@ -9,7 +9,6 @@ defmodule Pleroma.Object.ContainmentTest do
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
import ExUnit.CaptureLog
|
|
||||||
|
|
||||||
setup_all do
|
setup_all do
|
||||||
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||||
|
@ -136,23 +135,17 @@ test "contain_id_to_fetch() allows matching IDs" do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "contain_id_to_fetch() allows display URLs" do
|
test "contain_id_to_fetch() allows fragments and normalises domain casing" do
|
||||||
data = %{
|
data = %{
|
||||||
"id" => "http://example.com/~alyssa/activities/1234.json",
|
"id" => "http://example.com/users/capybara",
|
||||||
"url" => "http://example.com/@alyssa/status/1234"
|
"url" => "http://example.com/@capybara"
|
||||||
}
|
}
|
||||||
|
|
||||||
:ok =
|
assert :ok ==
|
||||||
Containment.contain_id_to_fetch(
|
Containment.contain_id_to_fetch(
|
||||||
"http://example.com/@alyssa/status/1234",
|
"http://EXAMPLE.com/users/capybara#key",
|
||||||
data
|
data
|
||||||
)
|
)
|
||||||
|
|
||||||
:ok =
|
|
||||||
Containment.contain_id_to_fetch(
|
|
||||||
"http://example.com/@alyssa/status/1234/",
|
|
||||||
data
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "users cannot be collided through fake direction spoofing attempts" do
|
test "users cannot be collided through fake direction spoofing attempts" do
|
||||||
|
@ -164,10 +157,14 @@ test "users cannot be collided through fake direction spoofing attempts" do
|
||||||
follower_address: User.ap_followers(%User{nickname: "rye@niu.moe"})
|
follower_address: User.ap_followers(%User{nickname: "rye@niu.moe"})
|
||||||
})
|
})
|
||||||
|
|
||||||
assert capture_log(fn ->
|
# Fetch from an attempted spoof id will suceed, but automatically retrieve
|
||||||
{:error, _} = User.get_or_fetch_by_ap_id("https://n1u.moe/users/rye")
|
# the real data from the homeserver instead of naïvely using the spoof
|
||||||
end) =~
|
{:ok, fetched_user} = User.get_or_fetch_by_ap_id("https://n1u.moe/users/rye")
|
||||||
"[error] Could not decode user at fetch https://n1u.moe/users/rye"
|
|
||||||
|
refute fetched_user.name == "evil rye"
|
||||||
|
refute fetched_user.raw_bio == "boooo!"
|
||||||
|
assert fetched_user.name == "♡ rye ♡"
|
||||||
|
assert fetched_user.nickname == "rye@niu.moe"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "contain_origin_from_id() gracefully handles cases where no ID is present" do
|
test "contain_origin_from_id() gracefully handles cases where no ID is present" do
|
||||||
|
|
|
@ -22,6 +22,7 @@ defp spoofed_object_with_ids(
|
||||||
|> Jason.decode!()
|
|> Jason.decode!()
|
||||||
|> Map.put("id", id)
|
|> Map.put("id", id)
|
||||||
|> Map.put("actor", actor_id)
|
|> Map.put("actor", actor_id)
|
||||||
|
|> Map.put("attributedTo", actor_id)
|
||||||
|> Jason.encode!()
|
|> Jason.encode!()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -109,7 +110,7 @@ defp spoofed_object_with_ids(
|
||||||
body: spoofed_object_with_ids("https://patch.cx/objects/spoof_media_redirect1")
|
body: spoofed_object_with_ids("https://patch.cx/objects/spoof_media_redirect1")
|
||||||
}
|
}
|
||||||
|
|
||||||
# Spoof: cross-domain redirect with final domain id
|
# Spoof: cross-domain redirect with final domain id, but original id actor
|
||||||
%{method: :get, url: "https://patch.cx/objects/spoof_media_redirect2"} ->
|
%{method: :get, url: "https://patch.cx/objects/spoof_media_redirect2"} ->
|
||||||
%Tesla.Env{
|
%Tesla.Env{
|
||||||
status: 200,
|
status: 200,
|
||||||
|
@ -118,6 +119,19 @@ defp spoofed_object_with_ids(
|
||||||
body: spoofed_object_with_ids("https://media.patch.cx/objects/spoof_media_redirect2")
|
body: spoofed_object_with_ids("https://media.patch.cx/objects/spoof_media_redirect2")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# No-Spoof: cross-domain redirect with id and actor from final domain
|
||||||
|
%{method: :get, url: "https://patch.cx/objects/spoof_media_redirect3"} ->
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
url: "https://media.patch.cx/objects/spoof_media_redirect3",
|
||||||
|
headers: [{"content-type", "application/activity+json"}],
|
||||||
|
body:
|
||||||
|
spoofed_object_with_ids(
|
||||||
|
"https://media.patch.cx/objects/spoof_media_redirect3",
|
||||||
|
"https://media.patch.cx/users/rin"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
# No-Spoof: same domain redirect
|
# No-Spoof: same domain redirect
|
||||||
%{method: :get, url: "https://patch.cx/objects/spoof_redirect"} ->
|
%{method: :get, url: "https://patch.cx/objects/spoof_redirect"} ->
|
||||||
%Tesla.Env{
|
%Tesla.Env{
|
||||||
|
@ -189,7 +203,6 @@ defp spoofed_object_with_ids(
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag capture_log: true
|
|
||||||
test "it works when fetching the OP actor errors out" do
|
test "it works when fetching the OP actor errors out" do
|
||||||
# Here we simulate a case where the author of the OP can't be read
|
# Here we simulate a case where the author of the OP can't be read
|
||||||
assert {:ok, _} =
|
assert {:ok, _} =
|
||||||
|
@ -252,7 +265,7 @@ test "it does not fetch a spoofed object with wrong content type" do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it does not fetch a spoofed object with id different from URL" do
|
test "it does not fetch a spoofed object with id different from URL" do
|
||||||
assert {:error, :id_mismatch} =
|
assert {:error, :not_found} =
|
||||||
Fetcher.fetch_and_contain_remote_object_from_id(
|
Fetcher.fetch_and_contain_remote_object_from_id(
|
||||||
"https://patch.cx/media/03ca3c8b4ac3ddd08bf0f84be7885f2f88de0f709112131a22d83650819e36c2.json"
|
"https://patch.cx/media/03ca3c8b4ac3ddd08bf0f84be7885f2f88de0f709112131a22d83650819e36c2.json"
|
||||||
)
|
)
|
||||||
|
@ -264,19 +277,29 @@ test "it does not fetch a spoofed object with id different from URL" do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it does not fetch an object via cross-domain redirects (initial id)" do
|
test "it does not fetch an object via cross-domain redirects (initial id)" do
|
||||||
assert {:error, {:cross_domain_redirect, true}} =
|
assert {:error, {:containment, _}} =
|
||||||
Fetcher.fetch_and_contain_remote_object_from_id(
|
Fetcher.fetch_and_contain_remote_object_from_id(
|
||||||
"https://patch.cx/objects/spoof_media_redirect1"
|
"https://patch.cx/objects/spoof_media_redirect1"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it does not fetch an object via cross-domain redirects (final id)" do
|
test "it does not fetch an object via cross-domain redirect if the actor is from the original domain" do
|
||||||
assert {:error, {:cross_domain_redirect, true}} =
|
assert {:error, {:containment, :error}} =
|
||||||
Fetcher.fetch_and_contain_remote_object_from_id(
|
Fetcher.fetch_and_contain_remote_object_from_id(
|
||||||
"https://patch.cx/objects/spoof_media_redirect2"
|
"https://patch.cx/objects/spoof_media_redirect2"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "it allows cross-domain redirects when id and author are from final domain" do
|
||||||
|
assert {:ok, %{"id" => id, "attributedTo" => author}} =
|
||||||
|
Fetcher.fetch_and_contain_remote_object_from_id(
|
||||||
|
"https://patch.cx/objects/spoof_media_redirect3"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert URI.parse(id).host == "media.patch.cx"
|
||||||
|
assert URI.parse(author).host == "media.patch.cx"
|
||||||
|
end
|
||||||
|
|
||||||
test "it accepts same-domain redirects" do
|
test "it accepts same-domain redirects" do
|
||||||
assert {:ok, %{"id" => id} = _object} =
|
assert {:ok, %{"id" => id} = _object} =
|
||||||
Fetcher.fetch_and_contain_remote_object_from_id(
|
Fetcher.fetch_and_contain_remote_object_from_id(
|
||||||
|
@ -755,7 +778,7 @@ test "should return ok if the content type is application/activity+json" do
|
||||||
assert {:ok, _, "{}"} = Fetcher.get_object("https://mastodon.social/2")
|
assert {:ok, _, "{}"} = Fetcher.get_object("https://mastodon.social/2")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "should return ok if the content type is application/ld+json with a profile" do
|
test "should return ok if the content type is application/ld+json with the ActivityStream profile" do
|
||||||
Tesla.Mock.mock(fn
|
Tesla.Mock.mock(fn
|
||||||
%{
|
%{
|
||||||
method: :get,
|
method: :get,
|
||||||
|
@ -775,6 +798,26 @@ test "should return ok if the content type is application/ld+json with a profile
|
||||||
assert {:ok, _, "{}"} = Fetcher.get_object("https://mastodon.social/2")
|
assert {:ok, _, "{}"} = Fetcher.get_object("https://mastodon.social/2")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "should return ok if the content type is application/ld+json with several profiles" do
|
||||||
|
Tesla.Mock.mock(fn
|
||||||
|
%{
|
||||||
|
method: :get,
|
||||||
|
url: "https://mastodon.social/2"
|
||||||
|
} ->
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
url: "https://mastodon.social/2",
|
||||||
|
headers: [
|
||||||
|
{"content-type",
|
||||||
|
"application/ld+json; profile=\"https://example.org/ns/superduperspec https://www.w3.org/ns/activitystreams\""}
|
||||||
|
],
|
||||||
|
body: "{}"
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert {:ok, _, "{}"} = Fetcher.get_object("https://mastodon.social/2")
|
||||||
|
end
|
||||||
|
|
||||||
test "should not return ok with other content types" do
|
test "should not return ok with other content types" do
|
||||||
Tesla.Mock.mock(fn
|
Tesla.Mock.mock(fn
|
||||||
%{
|
%{
|
||||||
|
|
|
@ -6,7 +6,6 @@ defmodule Pleroma.SignatureTest do
|
||||||
use Pleroma.DataCase, async: false
|
use Pleroma.DataCase, async: false
|
||||||
@moduletag :mocked
|
@moduletag :mocked
|
||||||
|
|
||||||
import ExUnit.CaptureLog
|
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
import Tesla.Mock
|
import Tesla.Mock
|
||||||
import Mock
|
import Mock
|
||||||
|
|
|
@ -115,6 +115,15 @@ test "verify webp files are skipped" do
|
||||||
assert Filter.Exiftool.StripMetadata.filter(upload) == {:ok, :noop}
|
assert Filter.Exiftool.StripMetadata.filter(upload) == {:ok, :noop}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "verify bmp files are skipped" do
|
||||||
|
upload = %Pleroma.Upload{
|
||||||
|
name: "sample.bmp",
|
||||||
|
content_type: "image/bmp"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert Filter.Exiftool.StripMetadata.filter(upload) == {:ok, :noop}
|
||||||
|
end
|
||||||
|
|
||||||
test "verify svg files are skipped" do
|
test "verify svg files are skipped" do
|
||||||
upload = %Pleroma.Upload{
|
upload = %Pleroma.Upload{
|
||||||
name: "sample.svg",
|
name: "sample.svg",
|
||||||
|
|
|
@ -815,7 +815,6 @@ test "gets an existing user by fully qualified nickname, case insensitive" do
|
||||||
assert user == fetched_user
|
assert user == fetched_user
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag capture_log: true
|
|
||||||
test "returns nil if no user could be fetched" do
|
test "returns nil if no user could be fetched" do
|
||||||
{:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
|
{:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
|
||||||
assert fetched_user == "not found nonexistant@social.heldscal.la"
|
assert fetched_user == "not found nonexistant@social.heldscal.la"
|
||||||
|
@ -872,7 +871,6 @@ test "if nicknames clash, the old user gets a prefix with the old id to the nick
|
||||||
assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
|
assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag capture_log: true
|
|
||||||
test "it returns the old user if stale, but unfetchable" do
|
test "it returns the old user if stale, but unfetchable" do
|
||||||
a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
|
a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
|
||||||
|
|
||||||
|
@ -968,6 +966,21 @@ test "it is invalid given a local user" do
|
||||||
|
|
||||||
refute cs.valid?
|
refute cs.valid?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "it truncates fields" do
|
||||||
|
clear_config([:instance, :max_remote_account_fields], 2)
|
||||||
|
|
||||||
|
fields = [
|
||||||
|
%{"name" => "One", "value" => "Uno"},
|
||||||
|
%{"name" => "Two", "value" => "Dos"},
|
||||||
|
%{"name" => "Three", "value" => "Tres"}
|
||||||
|
]
|
||||||
|
|
||||||
|
cs = User.remote_user_changeset(@valid_remote |> Map.put(:fields, fields))
|
||||||
|
|
||||||
|
assert [%{"name" => "One", "value" => "Uno"}, %{"name" => "Two", "value" => "Dos"}] ==
|
||||||
|
Ecto.Changeset.get_field(cs, :fields)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "followers and friends" do
|
describe "followers and friends" do
|
||||||
|
@ -1150,6 +1163,18 @@ test "it blocks people" do
|
||||||
assert User.blocks?(user, blocked_user)
|
assert User.blocks?(user, blocked_user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "it blocks domains" do
|
||||||
|
user = insert(:user)
|
||||||
|
blocked_user = insert(:user)
|
||||||
|
|
||||||
|
refute User.blocks_domain?(user, blocked_user)
|
||||||
|
|
||||||
|
url = URI.parse(blocked_user.ap_id)
|
||||||
|
{:ok, user} = User.block_domain(user, url.host)
|
||||||
|
|
||||||
|
assert User.blocks_domain?(user, blocked_user)
|
||||||
|
end
|
||||||
|
|
||||||
test "it unblocks users" do
|
test "it unblocks users" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
blocked_user = insert(:user)
|
blocked_user = insert(:user)
|
||||||
|
@ -1160,6 +1185,17 @@ test "it unblocks users" do
|
||||||
refute User.blocks?(user, blocked_user)
|
refute User.blocks?(user, blocked_user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "it unblocks domains" do
|
||||||
|
user = insert(:user)
|
||||||
|
blocked_user = insert(:user)
|
||||||
|
|
||||||
|
url = URI.parse(blocked_user.ap_id)
|
||||||
|
{:ok, user} = User.block_domain(user, url.host)
|
||||||
|
{:ok, user} = User.unblock_domain(user, url.host)
|
||||||
|
|
||||||
|
refute User.blocks_domain?(user, blocked_user)
|
||||||
|
end
|
||||||
|
|
||||||
test "blocks tear down cyclical follow relationships" do
|
test "blocks tear down cyclical follow relationships" do
|
||||||
blocker = insert(:user)
|
blocker = insert(:user)
|
||||||
blocked = insert(:user)
|
blocked = insert(:user)
|
||||||
|
|
|
@ -573,7 +573,6 @@ test "it inserts an incoming activity into the database", %{conn: conn} do
|
||||||
assert Activity.get_by_ap_id(data["id"])
|
assert Activity.get_by_ap_id(data["id"])
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag capture_log: true
|
|
||||||
test "it inserts an incoming activity into the database" <>
|
test "it inserts an incoming activity into the database" <>
|
||||||
"even if we can't fetch the user but have it in our db",
|
"even if we can't fetch the user but have it in our db",
|
||||||
%{conn: conn} do
|
%{conn: conn} do
|
||||||
|
@ -1094,7 +1093,7 @@ test "it returns a note activity in a collection", %{conn: conn} do
|
||||||
|
|
||||||
test "it clears `unreachable` federation status of the sender", %{conn: conn, data: data} do
|
test "it clears `unreachable` federation status of the sender", %{conn: conn, data: data} do
|
||||||
user =
|
user =
|
||||||
insert(:user)
|
insert(:user, ap_id: data["actor"])
|
||||||
|> with_signing_key()
|
|> with_signing_key()
|
||||||
|
|
||||||
data = Map.put(data, "bcc", [user.ap_id])
|
data = Map.put(data, "bcc", [user.ap_id])
|
||||||
|
@ -1114,7 +1113,6 @@ test "it clears `unreachable` federation status of the sender", %{conn: conn, da
|
||||||
assert Instances.reachable?(sender_host)
|
assert Instances.reachable?(sender_host)
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag capture_log: true
|
|
||||||
test "it removes all follower collections but actor's", %{conn: conn} do
|
test "it removes all follower collections but actor's", %{conn: conn} do
|
||||||
[actor, recipient] = insert_pair(:user)
|
[actor, recipient] = insert_pair(:user)
|
||||||
actor = with_signing_key(actor)
|
actor = with_signing_key(actor)
|
||||||
|
@ -1179,7 +1177,6 @@ test "it requires authentication", %{conn: conn} do
|
||||||
assert json_response(ret_conn, 200)
|
assert json_response(ret_conn, 200)
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag capture_log: true
|
|
||||||
test "forwarded report", %{conn: conn} do
|
test "forwarded report", %{conn: conn} do
|
||||||
admin = insert(:user, is_admin: true)
|
admin = insert(:user, is_admin: true)
|
||||||
|
|
||||||
|
@ -1260,7 +1257,6 @@ test "forwarded report", %{conn: conn} do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag capture_log: true
|
|
||||||
test "forwarded report from mastodon", %{conn: conn} do
|
test "forwarded report from mastodon", %{conn: conn} do
|
||||||
admin = insert(:user, is_admin: true)
|
admin = insert(:user, is_admin: true)
|
||||||
actor = insert(:user, local: false)
|
actor = insert(:user, local: false)
|
||||||
|
@ -1277,12 +1273,22 @@ test "forwarded report from mastodon", %{conn: conn} do
|
||||||
|> File.read!()
|
|> File.read!()
|
||||||
|> String.replace("{{DOMAIN}}", remote_domain)
|
|> String.replace("{{DOMAIN}}", remote_domain)
|
||||||
|
|
||||||
Tesla.Mock.mock(fn %{url: ^remote_actor} ->
|
key_url = "#{remote_actor}#main-key"
|
||||||
%Tesla.Env{
|
|
||||||
status: 200,
|
Tesla.Mock.mock(fn
|
||||||
body: mock_json_body,
|
%{url: ^remote_actor} ->
|
||||||
headers: [{"content-type", "application/activity+json"}]
|
%Tesla.Env{
|
||||||
}
|
status: 200,
|
||||||
|
body: mock_json_body,
|
||||||
|
headers: [{"content-type", "application/activity+json"}]
|
||||||
|
}
|
||||||
|
|
||||||
|
%{url: ^key_url} ->
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body: mock_json_body,
|
||||||
|
headers: [{"content-type", "application/activity+json"}]
|
||||||
|
}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
data = %{
|
data = %{
|
||||||
|
|
|
@ -79,7 +79,7 @@ test "works with objects with empty to or cc fields" do
|
||||||
|
|
||||||
{:ok, data} = ObjectAgePolicy.filter(data)
|
{:ok, data} = ObjectAgePolicy.filter(data)
|
||||||
|
|
||||||
assert Visibility.get_visibility(%{data: data}) == "unlisted"
|
assert Visibility.get_visibility(%{data: data}) == "direct"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it delists an old post" do
|
test "it delists an old post" do
|
||||||
|
|
|
@ -519,6 +519,9 @@ test "publish to url with with different ports" do
|
||||||
test "should not obliterate itself if the inbox URL is bad" do
|
test "should not obliterate itself if the inbox URL is bad" do
|
||||||
url = "/inbox"
|
url = "/inbox"
|
||||||
refute Pleroma.Web.ActivityPub.Publisher.should_federate?(url)
|
refute Pleroma.Web.ActivityPub.Publisher.should_federate?(url)
|
||||||
|
|
||||||
|
url = nil
|
||||||
|
refute Pleroma.Web.ActivityPub.Publisher.should_federate?(url)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -114,7 +114,6 @@ test "returns error when activity not `Create` type" do
|
||||||
assert Relay.publish(activity) == {:error, "Not implemented"}
|
assert Relay.publish(activity) == {:error, "Not implemented"}
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag capture_log: true
|
|
||||||
test "returns error when activity not public" do
|
test "returns error when activity not public" do
|
||||||
activity = insert(:direct_note_activity)
|
activity = insert(:direct_note_activity)
|
||||||
assert Relay.publish(activity) == {:error, false}
|
assert Relay.publish(activity) == {:error, false}
|
||||||
|
|
|
@ -83,7 +83,6 @@ test "it works for incoming announces, fetching the announced object" do
|
||||||
assert(Activity.get_create_by_object_ap_id(data["object"]))
|
assert(Activity.get_create_by_object_ap_id(data["object"]))
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag capture_log: true
|
|
||||||
test "it works for incoming announces with an existing activity" do
|
test "it works for incoming announces with an existing activity" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
|
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
|
||||||
|
@ -136,7 +135,6 @@ test "it works for incoming announces with an inlined activity" do
|
||||||
assert object.data["content"] == "this is a private toot"
|
assert object.data["content"] == "this is a private toot"
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag capture_log: true
|
|
||||||
test "it rejects incoming announces with an inlined activity from another origin" do
|
test "it rejects incoming announces with an inlined activity from another origin" do
|
||||||
Tesla.Mock.mock(fn
|
Tesla.Mock.mock(fn
|
||||||
%{method: :get} -> %Tesla.Env{status: 404, body: ""}
|
%{method: :get} -> %Tesla.Env{status: 404, body: ""}
|
||||||
|
|
|
@ -86,7 +86,6 @@ test "it fails for incoming deletes with spoofed origin" do
|
||||||
assert match?({:error, _}, Transmogrifier.handle_incoming(data))
|
assert match?({:error, _}, Transmogrifier.handle_incoming(data))
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag capture_log: true
|
|
||||||
test "it works for incoming user deletes" do
|
test "it works for incoming user deletes" do
|
||||||
%{ap_id: ap_id} = insert(:user, ap_id: "http://mastodon.example.org/users/admin")
|
%{ap_id: ap_id} = insert(:user, ap_id: "http://mastodon.example.org/users/admin")
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,6 @@ test "it ignores an incoming notice if we already have it" do
|
||||||
assert activity == returned_activity
|
assert activity == returned_activity
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag capture_log: true
|
|
||||||
test "it fetches reply-to activities if we don't have them" do
|
test "it fetches reply-to activities if we don't have them" do
|
||||||
data =
|
data =
|
||||||
File.read!("test/fixtures/mastodon-post-activity.json")
|
File.read!("test/fixtures/mastodon-post-activity.json")
|
||||||
|
@ -537,7 +536,6 @@ test "returns object with inReplyTo when denied incoming reply", %{data: data} d
|
||||||
assert modified_object["inReplyTo"] == []
|
assert modified_object["inReplyTo"] == []
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag capture_log: true
|
|
||||||
test "returns modified object when allowed incoming reply", %{data: data} do
|
test "returns modified object when allowed incoming reply", %{data: data} do
|
||||||
object_with_reply =
|
object_with_reply =
|
||||||
Map.put(
|
Map.put(
|
||||||
|
@ -700,7 +698,6 @@ test "take_emoji_tags/1" do
|
||||||
assert Transmogrifier.take_emoji_tags(user) == [
|
assert Transmogrifier.take_emoji_tags(user) == [
|
||||||
%{
|
%{
|
||||||
"icon" => %{"type" => "Image", "url" => "https://example.org/firefox.png"},
|
"icon" => %{"type" => "Image", "url" => "https://example.org/firefox.png"},
|
||||||
"id" => "https://example.org/firefox.png",
|
|
||||||
"name" => ":firefox:",
|
"name" => ":firefox:",
|
||||||
"type" => "Emoji",
|
"type" => "Emoji",
|
||||||
"updated" => "1970-01-01T00:00:00Z"
|
"updated" => "1970-01-01T00:00:00Z"
|
||||||
|
|
|
@ -119,8 +119,8 @@ test "it works with custom profile fields" do
|
||||||
user = User.get_cached_by_ap_id(user.ap_id)
|
user = User.get_cached_by_ap_id(user.ap_id)
|
||||||
|
|
||||||
assert user.fields == [
|
assert user.fields == [
|
||||||
%{"name" => "foo", "value" => "updated"},
|
%{"name" => "foo", "value" => "bar"},
|
||||||
%{"name" => "foo1", "value" => "updated"}
|
%{"name" => "foo11", "value" => "bar11"}
|
||||||
]
|
]
|
||||||
|
|
||||||
update_data =
|
update_data =
|
||||||
|
|
|
@ -561,7 +561,6 @@ test "returns nil when cannot normalize object" do
|
||||||
end) =~ ":valid_uri_scheme"
|
end) =~ ":valid_uri_scheme"
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag capture_log: true
|
|
||||||
test "returns {:ok, %Object{}} for success case" do
|
test "returns {:ok, %Object{}} for success case" do
|
||||||
assert {:ok, %Object{}} =
|
assert {:ok, %Object{}} =
|
||||||
Transmogrifier.get_obj_helper(
|
Transmogrifier.get_obj_helper(
|
||||||
|
|
|
@ -11,7 +11,9 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
|
|
||||||
test "Renders a user, including the public key" do
|
test "Renders a user, including the public key" do
|
||||||
user = insert(:user)
|
user =
|
||||||
|
insert(:user)
|
||||||
|
|> with_signing_key()
|
||||||
|
|
||||||
result = UserView.render("user.json", %{user: user})
|
result = UserView.render("user.json", %{user: user})
|
||||||
|
|
||||||
|
@ -37,13 +39,14 @@ test "Renders profile fields" do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "Renders with emoji tags" do
|
test "Renders with emoji tags" do
|
||||||
user = insert(:user, emoji: %{"bib" => "/test"})
|
user =
|
||||||
|
insert(:user, emoji: %{"bib" => "/test"})
|
||||||
|
|> with_signing_key()
|
||||||
|
|
||||||
assert %{
|
assert %{
|
||||||
"tag" => [
|
"tag" => [
|
||||||
%{
|
%{
|
||||||
"icon" => %{"type" => "Image", "url" => "/test"},
|
"icon" => %{"type" => "Image", "url" => "/test"},
|
||||||
"id" => "/test",
|
|
||||||
"name" => ":bib:",
|
"name" => ":bib:",
|
||||||
"type" => "Emoji",
|
"type" => "Emoji",
|
||||||
"updated" => "1970-01-01T00:00:00Z"
|
"updated" => "1970-01-01T00:00:00Z"
|
||||||
|
@ -74,13 +77,18 @@ test "Does not add an avatar image if the user hasn't set one" do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "renders an invisible user with the invisible property set to true" do
|
test "renders an invisible user with the invisible property set to true" do
|
||||||
user = insert(:user, invisible: true)
|
user =
|
||||||
|
insert(:user, invisible: true)
|
||||||
|
|> with_signing_key()
|
||||||
|
|
||||||
assert %{"invisible" => true} = UserView.render("service.json", %{user: user})
|
assert %{"invisible" => true} = UserView.render("service.json", %{user: user})
|
||||||
end
|
end
|
||||||
|
|
||||||
test "service has a few essential fields" do
|
test "service has a few essential fields" do
|
||||||
user = insert(:user)
|
user =
|
||||||
|
insert(:user)
|
||||||
|
|> with_signing_key()
|
||||||
|
|
||||||
result = UserView.render("service.json", %{user: user})
|
result = UserView.render("service.json", %{user: user})
|
||||||
assert result["id"]
|
assert result["id"]
|
||||||
assert result["type"] == "Application"
|
assert result["type"] == "Application"
|
||||||
|
@ -120,7 +128,9 @@ test "remote users have an empty endpoints structure" do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "instance users do not expose oAuth endpoints" do
|
test "instance users do not expose oAuth endpoints" do
|
||||||
user = insert(:user, nickname: nil, local: true)
|
user =
|
||||||
|
insert(:user, nickname: nil, local: true)
|
||||||
|
|> with_signing_key()
|
||||||
|
|
||||||
result = UserView.render("user.json", %{user: user})
|
result = UserView.render("user.json", %{user: user})
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,6 @@ test "search", %{conn: conn} do
|
||||||
assert status["id"] == to_string(activity.id)
|
assert status["id"] == to_string(activity.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag capture_log: true
|
|
||||||
test "constructs hashtags from search query", %{conn: conn} do
|
test "constructs hashtags from search query", %{conn: conn} do
|
||||||
results =
|
results =
|
||||||
conn
|
conn
|
||||||
|
|
|
@ -152,7 +152,6 @@ test "filtering", %{conn: conn, user: user} do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "public" do
|
describe "public" do
|
||||||
@tag capture_log: true
|
|
||||||
test "the public timeline", %{conn: conn} do
|
test "the public timeline", %{conn: conn} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
||||||
|
@ -810,7 +809,6 @@ test "filtering", %{user: user, conn: conn} do
|
||||||
describe "hashtag" do
|
describe "hashtag" do
|
||||||
setup do: oauth_access(["n/a"])
|
setup do: oauth_access(["n/a"])
|
||||||
|
|
||||||
@tag capture_log: true
|
|
||||||
test "hashtag timeline", %{conn: conn} do
|
test "hashtag timeline", %{conn: conn} do
|
||||||
following = insert(:user)
|
following = insert(:user)
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ test "renders a poll" do
|
||||||
%{title: "why are you even asking?", votes_count: 0}
|
%{title: "why are you even asking?", votes_count: 0}
|
||||||
],
|
],
|
||||||
votes_count: 0,
|
votes_count: 0,
|
||||||
voters_count: 0
|
voters_count: nil
|
||||||
}
|
}
|
||||||
|
|
||||||
result = PollView.render("show.json", %{object: object})
|
result = PollView.render("show.json", %{object: object})
|
||||||
|
|
|
@ -33,6 +33,10 @@ test "has an emoji reaction list" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
other_user = insert(:user)
|
other_user = insert(:user)
|
||||||
third_user = insert(:user)
|
third_user = insert(:user)
|
||||||
|
domain_blocked_user = insert(:user, %{ap_id: "https://blocked.com/@blocked"})
|
||||||
|
|
||||||
|
{:ok, user} = User.block_domain(user, "blocked.com")
|
||||||
|
|
||||||
{:ok, activity} = CommonAPI.post(user, %{status: "dae cofe??"})
|
{:ok, activity} = CommonAPI.post(user, %{status: "dae cofe??"})
|
||||||
|
|
||||||
{:ok, _} = CommonAPI.react_with_emoji(activity.id, user, "☕")
|
{:ok, _} = CommonAPI.react_with_emoji(activity.id, user, "☕")
|
||||||
|
@ -40,6 +44,8 @@ test "has an emoji reaction list" do
|
||||||
{:ok, _} = CommonAPI.react_with_emoji(activity.id, third_user, "🍵")
|
{:ok, _} = CommonAPI.react_with_emoji(activity.id, third_user, "🍵")
|
||||||
{:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
|
{:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
|
||||||
{:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, ":dinosaur:")
|
{:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, ":dinosaur:")
|
||||||
|
# this should not show up when the user is viewing the status
|
||||||
|
{:ok, _} = CommonAPI.react_with_emoji(activity.id, domain_blocked_user, "😈")
|
||||||
|
|
||||||
activity = Repo.get(Activity, activity.id)
|
activity = Repo.get(Activity, activity.id)
|
||||||
status = StatusView.render("show.json", activity: activity)
|
status = StatusView.render("show.json", activity: activity)
|
||||||
|
@ -55,7 +61,8 @@ test "has an emoji reaction list" do
|
||||||
url: "http://localhost:4001/emoji/dino walking.gif",
|
url: "http://localhost:4001/emoji/dino walking.gif",
|
||||||
account_ids: [other_user.id, user.id]
|
account_ids: [other_user.id, user.id]
|
||||||
},
|
},
|
||||||
%{name: "🍵", count: 1, me: false, url: nil, account_ids: [third_user.id]}
|
%{name: "🍵", count: 1, me: false, url: nil, account_ids: [third_user.id]},
|
||||||
|
%{name: "😈", count: 1, me: false, url: nil, account_ids: [domain_blocked_user.id]}
|
||||||
]
|
]
|
||||||
|
|
||||||
status = StatusView.render("show.json", activity: activity, for: user)
|
status = StatusView.render("show.json", activity: activity, for: user)
|
||||||
|
@ -73,6 +80,8 @@ test "has an emoji reaction list" do
|
||||||
},
|
},
|
||||||
%{name: "🍵", count: 1, me: false, url: nil, account_ids: [third_user.id]}
|
%{name: "🍵", count: 1, me: false, url: nil, account_ids: [third_user.id]}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
refute Enum.any?(status[:pleroma][:emoji_reactions], fn reaction -> reaction[:name] == "😈" end)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "works correctly with badly formatted emojis" do
|
test "works correctly with badly formatted emojis" do
|
||||||
|
@ -579,6 +588,7 @@ test "attachments" do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "put the url advertised in the Activity in to the url attribute" do
|
test "put the url advertised in the Activity in to the url attribute" do
|
||||||
|
Pleroma.Config.put([:instance, :limit_to_local_content], false)
|
||||||
id = "https://wedistribute.org/wp-json/pterotype/v1/object/85810"
|
id = "https://wedistribute.org/wp-json/pterotype/v1/object/85810"
|
||||||
[activity] = Activity.search(nil, id)
|
[activity] = Activity.search(nil, id)
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,10 @@ test "ignores local url" do
|
||||||
assert MediaProxy.url(local_root) == local_root
|
assert MediaProxy.url(local_root) == local_root
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "ignores data url" do
|
||||||
|
assert MediaProxy.url("data:image/png;base64,") == "data:image/png;base64,"
|
||||||
|
end
|
||||||
|
|
||||||
test "encodes and decodes URL" do
|
test "encodes and decodes URL" do
|
||||||
url = "https://pleroma.soykaf.com/static/logo.png"
|
url = "https://pleroma.soykaf.com/static/logo.png"
|
||||||
encoded = MediaProxy.url(url)
|
encoded = MediaProxy.url(url)
|
||||||
|
|
|
@ -67,7 +67,6 @@ test "performs sending notifications" do
|
||||||
assert Impl.perform(notif) == {:ok, [:ok, :ok]}
|
assert Impl.perform(notif) == {:ok, [:ok, :ok]}
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag capture_log: true
|
|
||||||
test "returns error if notif does not match " do
|
test "returns error if notif does not match " do
|
||||||
assert Impl.perform(%{}) == {:error, :unknown_type}
|
assert Impl.perform(%{}) == {:error, :unknown_type}
|
||||||
end
|
end
|
||||||
|
@ -76,7 +75,6 @@ test "successful message sending" do
|
||||||
assert Impl.push_message(@message, @sub, @api_key, %Subscription{}) == :ok
|
assert Impl.push_message(@message, @sub, @api_key, %Subscription{}) == :ok
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag capture_log: true
|
|
||||||
test "fail message sending" do
|
test "fail message sending" do
|
||||||
assert Impl.push_message(
|
assert Impl.push_message(
|
||||||
@message,
|
@message,
|
||||||
|
|
|
@ -190,7 +190,6 @@ test "prevents spoofing" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag capture_log: true
|
|
||||||
test "prevents forgeries" do
|
test "prevents forgeries" do
|
||||||
Tesla.Mock.mock(fn
|
Tesla.Mock.mock(fn
|
||||||
%{url: "https://bad.com/.well-known/webfinger?resource=acct:meanie@bad.com"} ->
|
%{url: "https://bad.com/.well-known/webfinger?resource=acct:meanie@bad.com"} ->
|
||||||
|
|
86
test/pleroma/workers/attachments_cleanup_worker_test.exs
Normal file
86
test/pleroma/workers/attachments_cleanup_worker_test.exs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
# Akkoma: Magically expressive social media
|
||||||
|
# Copyright © 2024 Akkoma Authors <https://akkoma.dev/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Workers.AttachmentsCleanupWorkerTest do
|
||||||
|
use Pleroma.DataCase, async: false
|
||||||
|
use Oban.Testing, repo: Pleroma.Repo
|
||||||
|
|
||||||
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
alias Pleroma.Object
|
||||||
|
alias Pleroma.Workers.AttachmentsCleanupWorker
|
||||||
|
alias Pleroma.Tests.ObanHelpers
|
||||||
|
|
||||||
|
setup do
|
||||||
|
clear_config([:instance, :cleanup_attachments], true)
|
||||||
|
|
||||||
|
file = %Plug.Upload{
|
||||||
|
content_type: "image/jpeg",
|
||||||
|
path: Path.absname("test/fixtures/image.jpg"),
|
||||||
|
filename: "an_image.jpg"
|
||||||
|
}
|
||||||
|
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, %Pleroma.Object{} = attachment} =
|
||||||
|
Pleroma.Web.ActivityPub.ActivityPub.upload(file, actor: user.ap_id)
|
||||||
|
|
||||||
|
{:ok, attachment: attachment, user: user}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "does not enqueue remote post" do
|
||||||
|
remote_data = %{
|
||||||
|
"id" => "https://remote.example/obj/123",
|
||||||
|
"actor" => "https://remote.example/user/1",
|
||||||
|
"content" => "content",
|
||||||
|
"attachment" => [
|
||||||
|
%{
|
||||||
|
"type" => "Document",
|
||||||
|
"mediaType" => "image/png",
|
||||||
|
"name" => "marvellous image",
|
||||||
|
"url" => "https://remote.example/files/image.png"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {:ok, :skip} = AttachmentsCleanupWorker.enqueue_if_needed(remote_data)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "enqueues local post", %{attachment: attachment, user: user} do
|
||||||
|
local_url = Pleroma.Web.Endpoint.url()
|
||||||
|
|
||||||
|
local_data = %{
|
||||||
|
"id" => local_url <> "/obj/123",
|
||||||
|
"actor" => user.ap_id,
|
||||||
|
"content" => "content",
|
||||||
|
"attachment" => [attachment.data]
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {:ok, %Oban.Job{}} = AttachmentsCleanupWorker.enqueue_if_needed(local_data)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "doesn't delete immediately", %{attachment: attachment, user: user} do
|
||||||
|
delay = 6000
|
||||||
|
clear_config([:instance, :cleanup_attachments_delay], delay)
|
||||||
|
|
||||||
|
note = insert(:note, %{user: user, data: %{"attachment" => [attachment.data]}})
|
||||||
|
|
||||||
|
uploads_dir = Pleroma.Config.get!([Pleroma.Uploaders.Local, :uploads])
|
||||||
|
%{"url" => [%{"href" => href}]} = attachment.data
|
||||||
|
path = "#{uploads_dir}/#{Path.basename(href)}"
|
||||||
|
|
||||||
|
assert File.exists?(path)
|
||||||
|
|
||||||
|
Object.delete(note)
|
||||||
|
Process.sleep(2000)
|
||||||
|
|
||||||
|
assert File.exists?(path)
|
||||||
|
|
||||||
|
ObanHelpers.perform(all_enqueued(worker: Pleroma.Workers.AttachmentsCleanupWorker))
|
||||||
|
|
||||||
|
assert Object.get_by_id(note.id).data["deleted"]
|
||||||
|
assert Object.get_by_id(attachment.id) == nil
|
||||||
|
refute File.exists?(path)
|
||||||
|
end
|
||||||
|
end
|
|
@ -263,7 +263,12 @@ def get("https://n1u.moe/users/rye", _, _, @activitypub_accept_headers) do
|
||||||
{:ok,
|
{:ok,
|
||||||
%Tesla.Env{
|
%Tesla.Env{
|
||||||
status: 200,
|
status: 200,
|
||||||
body: File.read!("test/fixtures/tesla_mock/rye.json"),
|
body:
|
||||||
|
File.read!("test/fixtures/tesla_mock/rye.json")
|
||||||
|
|> Jason.decode!()
|
||||||
|
|> Map.put("name", "evil rye")
|
||||||
|
|> Map.put("bio", "boooo!")
|
||||||
|
|> Jason.encode!(),
|
||||||
headers: activitypub_object_headers()
|
headers: activitypub_object_headers()
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,11 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
os_exclude = if :os.type() == {:unix, :darwin}, do: [skip_on_mac: true], else: []
|
os_exclude = if :os.type() == {:unix, :darwin}, do: [skip_on_mac: true], else: []
|
||||||
ExUnit.start(exclude: [:federated, :erratic] ++ os_exclude)
|
|
||||||
|
ExUnit.start(
|
||||||
|
capture_log: true,
|
||||||
|
exclude: [:federated, :erratic] ++ os_exclude
|
||||||
|
)
|
||||||
|
|
||||||
Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, :manual)
|
Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, :manual)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue