diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 675d0e067..39947c75e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -2,7 +2,7 @@ image: git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.14.5-otp-25
variables: &global_variables
# Only used for the release
- ELIXIR_VER: 1.17.3
+ ELIXIR_VER: 1.14.5
POSTGRES_DB: pleroma_test
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
@@ -272,8 +272,7 @@ stop_review_app:
amd64:
stage: release
- image:
- name: hexpm/elixir-amd64:1.17.3-erlang-26.2.5.6-ubuntu-focal-20241011
+ image: elixir:$ELIXIR_VER
only: &release-only
- stable@pleroma/pleroma
- develop@pleroma/pleroma
@@ -298,9 +297,8 @@ amd64:
variables: &release-variables
MIX_ENV: prod
VIX_COMPILATION_MODE: PLATFORM_PROVIDED_LIBVIPS
- DEBIAN_FRONTEND: noninteractive
before_script: &before-release
- - apt-get update && apt-get install -y cmake libmagic-dev libvips-dev erlang-dev git
+ - apt-get update && apt-get install -y cmake libmagic-dev libvips-dev erlang-dev
- echo "import Config" > config/prod.secret.exs
- mix local.hex --force
- mix local.rebar --force
@@ -315,8 +313,7 @@ amd64-musl:
stage: release
artifacts: *release-artifacts
only: *release-only
- image:
- name: hexpm/elixir-amd64:1.17.3-erlang-26.2.5.6-alpine-3.17.9
+ image: elixir:$ELIXIR_VER-alpine
tags:
- amd64
cache: *release-cache
@@ -330,7 +327,6 @@ amd64-musl:
arm:
stage: release
- allow_failure: true
artifacts: *release-artifacts
only: *release-only
tags:
@@ -359,8 +355,7 @@ arm64:
only: *release-only
tags:
- arm
- image:
- name: hexpm/elixir-arm64:1.17.3-erlang-26.2.5.6-ubuntu-focal-20241011
+ image: arm64v8/elixir:$ELIXIR_VER
cache: *release-cache
variables: *release-variables
before_script: *before-release
@@ -372,8 +367,7 @@ arm64-musl:
only: *release-only
tags:
- arm
- image:
- name: hexpm/elixir-arm64:1.17.3-erlang-26.2.5.6-alpine-3.17.9
+ image: arm64v8/elixir:$ELIXIR_VER-alpine
cache: *release-cache
variables: *release-variables
before_script: *before-release-musl
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 19b87f09a..424a9afbb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,109 +4,6 @@ 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/).
-## 2.9.1
-
-### Security
-- Fix authorization checks for C2S Update activities to prevent unauthorized modifications of other users' content.
-- Fix content-type spoofing vulnerability that could allow users to upload ActivityPub objects as attachments
-- Reject cross-domain redirects when fetching ActivityPub objects to prevent bypassing domain-based security controls.
-- Limit emoji shortcodes to alphanumeric, dash, or underscore characters to prevent potential abuse.
-- Block attempts to fetch activities from the local instance to prevent spoofing.
-- Sanitize Content-Type headers in media proxy to prevent serving malicious ActivityPub content through proxied media.
-- Validate Content-Type headers when fetching remote ActivityPub objects to prevent spoofing attacks.
-
-### Changed
-- Include `pl-fe` in available frontends
-
-### Fixed
-- Remove trailing ` from end of line 75 which caused issues copy-pasting
-
-## 2.9.0
-
-### Security
-- Require HTTP signatures (if enabled) for routes used by both C2S and S2S AP API
-- Fix several spoofing vectors
-
-### Changed
-- Performance: Use 301 (permanent) redirect instead of 302 (temporary) when redirecting small images in media proxy. This allows browsers to cache the redirect response.
-
-### Added
-- Include "published" in actor view
-- Link to exported outbox/followers/following collections in backup actor.json
-- Hashtag following
-- Allow to specify post language
-
-### Fixed
-- Verify a local Update sent through AP C2S so users can only update their own objects
-- Fix Mastodon incoming edits with inlined "likes"
-- Allow incoming "Listen" activities
-- Fix missing check for domain presence in rich media ignore_host configuration
-- Fix Rich Media parsing of TwitterCards/OpenGraph to adhere to the spec and always choose the first image if multiple are provided.
-- Fix OpenGraph/TwitterCard meta tag ordering for posts with multiple attachments
-- Fix blurhash generation crashes
-
-### Removed
-- Retire MRFs DNSRBL, FODirectReply, and QuietReply
-
-## 2.8.0
-
-### Changed
-- Metadata: Do not include .atom feed links for remote accounts
-- Bumped `fast_html` to v2.3.0, which notably allows to use system-installed lexbor with passing `WITH_SYSTEM_LEXBOR=1` environment variable at build-time
-- Dedupe upload filter now uses a three-level sharding directory structure
-- Deprecate `/api/v1/pleroma/accounts/:id/subscribe`/`unsubscribe`
-- Restrict incoming activities from unknown actors to a subset that does not imply a previous relationship and early rejection of unrecognized activity types.
-- Elixir 1.14 and Erlang/OTP 23 is now the minimum supported release
-- Support `id` param in `GET /api/v1/statuses`
-- LDAP authentication has been refactored to operate as a GenServer process which will maintain an active connection to the LDAP server.
-- Fix 'Setting a marker should mark notifications as read'
-- Adjust more Oban workers to enforce unique job constraints.
-- Oban updated to 2.18.3
-- Publisher behavior improvement when snoozing Oban jobs due to Gun connection pool contention.
-- Poll results refreshing is handled asynchronously and will not attempt to keep fetching updates to a closed poll.
-- Tuning for release builds to lower CPU usage.
-- Rich Media preview fetching will skip making an HTTP HEAD request to check a URL for allowed content type and length if the Tesla adapter is Gun or Finch
-- Fix nonexisting user will not generate metadata for search engine opt-out
-- Update Oban to 2.18
-- Worker configuration is no longer available. This only affects custom max_retries values for a couple Oban queues.
-
-### Added
-- Add metadata provider for ActivityPub alternate links
-- Added support for argon2 passwords and their conversion for migration from Akkoma fork to upstream.
-- Respect :restrict_unauthenticated for hashtag rss/atom feeds
-- LDAP configuration now permits overriding the CA root certificate file for TLS validation.
-- LDAP now supports users changing their passwords
-- Include list id in StatusView
-- Added MRF.FODirectReply which changes replies to followers-only posts to be direct.
-- Add `id_filter` to MRF to filter URLs and their domain prior to fetching
-- Added MRF.QuietReply which prevents replies to public posts from being published to the timelines
-- Add `group_key` to notifications
-- Allow providing avatar/header descriptions
-- Added RemoteReportPolicy from Rebased for handling bogus federated reports
-- scrubbers/default: Allow "mention hashtag" classes used by Mastodon
-- Added dependencies for Swoosh's Mua mail adapter
-- Include session scopes in TokenView
-
-### Fixed
-- Verify a local Update sent through AP C2S so users can only update their own objects
-- Fixed malformed follow requests that cause them to appear stuck pending due to the recipient being unable to process them.
-- Fix incoming Block activities being rejected
-- STARTTLS certificate and hostname verification for LDAP authentication
-- LDAPS connections (implicit TLS) are now supported.
-- Fix /api/v2/media returning the wrong status code (202) for media processed synchronously
-- Miscellaneous fixes for Meilisearch support
-- Fix pleroma_ctl mix task calls sometimes not being found
-- Add a rate limiter to the OAuth App creation endpoint and ensure registered apps are assigned to users.
-- ReceiverWorker will cancel processing jobs instead of retrying if the user cannot be fetched due to 403, 404, or 410 errors or if the account is disabled locally.
-- Address case where instance reachability status couldn't be updated
-- Remote Fetcher Worker recognizes more permanent failure errors
-- StreamerView: Do not leak follows count if hidden
-- Imports of blocks, mutes, and follows would retry repeatedly due to incorrect error handling and all work executed in a single job
-- Make vapid_config return empty array, fixing preloading for instances without push notifications configured
-
-### Removed
-- Remove stub for /api/v1/accounts/:id/identity_proofs (deprecated by Mastodon 3.5.0)
-
## 2.7.1
### Changed
diff --git a/changelog.d/activity-pub-metadata.add b/changelog.d/activity-pub-metadata.add
new file mode 100644
index 000000000..2ad3d7b2d
--- /dev/null
+++ b/changelog.d/activity-pub-metadata.add
@@ -0,0 +1 @@
+Add metadata provider for ActivityPub alternate links
diff --git a/changelog.d/argon2-passwords.add b/changelog.d/argon2-passwords.add
new file mode 100644
index 000000000..36fd7faf2
--- /dev/null
+++ b/changelog.d/argon2-passwords.add
@@ -0,0 +1 @@
+Added support for argon2 passwords and their conversion for migration from Akkoma fork to upstream.
diff --git a/changelog.d/atom-tag.change b/changelog.d/atom-tag.change
new file mode 100644
index 000000000..1b3590dea
--- /dev/null
+++ b/changelog.d/atom-tag.change
@@ -0,0 +1 @@
+Metadata: Do not include .atom feed links for remote accounts
diff --git a/changelog.d/bump-lexbor.change b/changelog.d/bump-lexbor.change
new file mode 100644
index 000000000..2c7061a81
--- /dev/null
+++ b/changelog.d/bump-lexbor.change
@@ -0,0 +1 @@
+- Bumped `fast_html` to v2.3.0, which notably allows to use system-installed lexbor with passing `WITH_SYSTEM_LEXBOR=1` environment variable at build-time
\ No newline at end of file
diff --git a/changelog.d/ci-git-fetch.skip b/changelog.d/ci-git-fetch.skip
new file mode 100644
index 000000000..e69de29bb
diff --git a/changelog.d/commonapi.skip b/changelog.d/commonapi.skip
new file mode 100644
index 000000000..e69de29bb
diff --git a/changelog.d/debian-install-improve.skip b/changelog.d/debian-install-improve.skip
new file mode 100644
index 000000000..6068a3066
--- /dev/null
+++ b/changelog.d/debian-install-improve.skip
@@ -0,0 +1 @@
+Fixed a formatting issue that had a required commend embedded in a textblock, and change the language to make it a bit more idiomatic.
\ No newline at end of file
diff --git a/changelog.d/dedupe-sharding.change b/changelog.d/dedupe-sharding.change
new file mode 100644
index 000000000..2e140d8a2
--- /dev/null
+++ b/changelog.d/dedupe-sharding.change
@@ -0,0 +1 @@
+Dedupe upload filter now uses a three-level sharding directory structure
diff --git a/changelog.d/deprecate-subscribe.change b/changelog.d/deprecate-subscribe.change
new file mode 100644
index 000000000..bd7e8aec7
--- /dev/null
+++ b/changelog.d/deprecate-subscribe.change
@@ -0,0 +1 @@
+Deprecate `/api/v1/pleroma/accounts/:id/subscribe`/`unsubscribe`
\ No newline at end of file
diff --git a/changelog.d/dialyzer.skip b/changelog.d/dialyzer.skip
new file mode 100644
index 000000000..e69de29bb
diff --git a/changelog.d/docs-fix.skip b/changelog.d/docs-fix.skip
new file mode 100644
index 000000000..e69de29bb
diff --git a/changelog.d/docs-vips.skip b/changelog.d/docs-vips.skip
new file mode 100644
index 000000000..e69de29bb
diff --git a/changelog.d/drop-unwanted.change b/changelog.d/drop-unwanted.change
new file mode 100644
index 000000000..459d4bfe6
--- /dev/null
+++ b/changelog.d/drop-unwanted.change
@@ -0,0 +1 @@
+Restrict incoming activities from unknown actors to a subset that does not imply a previous relationship and early rejection of unrecognized activity types.
diff --git a/changelog.d/elixir-1.14-docker.skip b/changelog.d/elixir-1.14-docker.skip
new file mode 100644
index 000000000..e69de29bb
diff --git a/changelog.d/elixir.change b/changelog.d/elixir.change
new file mode 100644
index 000000000..779c01562
--- /dev/null
+++ b/changelog.d/elixir.change
@@ -0,0 +1 @@
+Elixir 1.14 and Erlang/OTP 23 is now the minimum supported release
diff --git a/changelog.d/follow-request.fix b/changelog.d/follow-request.fix
new file mode 100644
index 000000000..59d34e9bf
--- /dev/null
+++ b/changelog.d/follow-request.fix
@@ -0,0 +1 @@
+Fixed malformed follow requests that cause them to appear stuck pending due to the recipient being unable to process them.
diff --git a/changelog.d/freebsd-docs.skip b/changelog.d/freebsd-docs.skip
new file mode 100644
index 000000000..e69de29bb
diff --git a/changelog.d/get-statuses-param.change b/changelog.d/get-statuses-param.change
new file mode 100644
index 000000000..3edcad268
--- /dev/null
+++ b/changelog.d/get-statuses-param.change
@@ -0,0 +1 @@
+Support `id` param in `GET /api/v1/statuses`
\ No newline at end of file
diff --git a/changelog.d/hashtag-feeds-restricted.add b/changelog.d/hashtag-feeds-restricted.add
new file mode 100644
index 000000000..accac9c9c
--- /dev/null
+++ b/changelog.d/hashtag-feeds-restricted.add
@@ -0,0 +1 @@
+Repesct :restrict_unauthenticated for hashtag rss/atom feeds
\ No newline at end of file
diff --git a/changelog.d/identity-proofs.remove b/changelog.d/identity-proofs.remove
new file mode 100644
index 000000000..efe1c34f5
--- /dev/null
+++ b/changelog.d/identity-proofs.remove
@@ -0,0 +1 @@
+Remove stub for /api/v1/accounts/:id/identity_proofs (deprecated by Mastodon 3.5.0)
\ No newline at end of file
diff --git a/changelog.d/incoming-blocks.fix b/changelog.d/incoming-blocks.fix
new file mode 100644
index 000000000..3228d7318
--- /dev/null
+++ b/changelog.d/incoming-blocks.fix
@@ -0,0 +1 @@
+Fix incoming Block activities being rejected
diff --git a/changelog.d/ldap-ca.add b/changelog.d/ldap-ca.add
new file mode 100644
index 000000000..32ecbb5c0
--- /dev/null
+++ b/changelog.d/ldap-ca.add
@@ -0,0 +1 @@
+LDAP configuration now permits overriding the CA root certificate file for TLS validation.
diff --git a/changelog.d/ldap-password-change.add b/changelog.d/ldap-password-change.add
new file mode 100644
index 000000000..7ca555ee4
--- /dev/null
+++ b/changelog.d/ldap-password-change.add
@@ -0,0 +1 @@
+LDAP now supports users changing their passwords
diff --git a/changelog.d/ldap-refactor.change b/changelog.d/ldap-refactor.change
new file mode 100644
index 000000000..1510eea6a
--- /dev/null
+++ b/changelog.d/ldap-refactor.change
@@ -0,0 +1 @@
+LDAP authentication has been refactored to operate as a GenServer process which will maintain an active connection to the LDAP server.
diff --git a/changelog.d/ldap-tls.fix b/changelog.d/ldap-tls.fix
new file mode 100644
index 000000000..b15137d77
--- /dev/null
+++ b/changelog.d/ldap-tls.fix
@@ -0,0 +1 @@
+STARTTLS certificate and hostname verification for LDAP authentication
diff --git a/changelog.d/ldap-warning.skip b/changelog.d/ldap-warning.skip
new file mode 100644
index 000000000..e69de29bb
diff --git a/changelog.d/ldaps.fix b/changelog.d/ldaps.fix
new file mode 100644
index 000000000..a1dc901ab
--- /dev/null
+++ b/changelog.d/ldaps.fix
@@ -0,0 +1 @@
+LDAPS connections (implicit TLS) are now supported.
diff --git a/changelog.d/list-id-visibility.add b/changelog.d/list-id-visibility.add
new file mode 100644
index 000000000..2fea2d771
--- /dev/null
+++ b/changelog.d/list-id-visibility.add
@@ -0,0 +1 @@
+Include list id in StatusView
\ No newline at end of file
diff --git a/changelog.d/manifest-icon-size.skip b/changelog.d/manifest-icon-size.skip
new file mode 100644
index 000000000..e69de29bb
diff --git a/changelog.d/mediav2_status.fix b/changelog.d/mediav2_status.fix
new file mode 100644
index 000000000..28e93e030
--- /dev/null
+++ b/changelog.d/mediav2_status.fix
@@ -0,0 +1 @@
+Fix /api/v2/media returning the wrong status code (202) for media processed synchronously
diff --git a/changelog.d/meilisearch-misc-fixes.fix b/changelog.d/meilisearch-misc-fixes.fix
new file mode 100644
index 000000000..0f127d3a8
--- /dev/null
+++ b/changelog.d/meilisearch-misc-fixes.fix
@@ -0,0 +1 @@
+Miscellaneous fixes for Meilisearch support
diff --git a/changelog.d/module-search-in-pleroma-ctl.fix b/changelog.d/module-search-in-pleroma-ctl.fix
new file mode 100644
index 000000000..d32fe3f33
--- /dev/null
+++ b/changelog.d/module-search-in-pleroma-ctl.fix
@@ -0,0 +1 @@
+Fix pleroma_ctl mix task calls sometimes not being found
diff --git a/changelog.d/mogrify.skip b/changelog.d/mogrify.skip
new file mode 100644
index 000000000..e69de29bb
diff --git a/changelog.d/mrf-cleanup.skip b/changelog.d/mrf-cleanup.skip
new file mode 100644
index 000000000..e69de29bb
diff --git a/changelog.d/mrf-fodirectreply.add b/changelog.d/mrf-fodirectreply.add
new file mode 100644
index 000000000..10fd5d16a
--- /dev/null
+++ b/changelog.d/mrf-fodirectreply.add
@@ -0,0 +1 @@
+Added MRF.FODirectReply which changes replies to followers-only posts to be direct.
diff --git a/changelog.d/mrf-id_filter.add b/changelog.d/mrf-id_filter.add
new file mode 100644
index 000000000..f556f9bc4
--- /dev/null
+++ b/changelog.d/mrf-id_filter.add
@@ -0,0 +1 @@
+Add `id_filter` to MRF to filter URLs and their domain prior to fetching
\ No newline at end of file
diff --git a/changelog.d/mrf-quietreply.add b/changelog.d/mrf-quietreply.add
new file mode 100644
index 000000000..4ed20bce6
--- /dev/null
+++ b/changelog.d/mrf-quietreply.add
@@ -0,0 +1 @@
+Added MRF.QuietReply which prevents replies to public posts from being published to the timelines
diff --git a/changelog.d/notifications-group-key.add b/changelog.d/notifications-group-key.add
new file mode 100644
index 000000000..386927f4a
--- /dev/null
+++ b/changelog.d/notifications-group-key.add
@@ -0,0 +1 @@
+Add `group_key` to notifications
\ No newline at end of file
diff --git a/changelog.d/notifications-marker.change b/changelog.d/notifications-marker.change
new file mode 100644
index 000000000..9e350a95c
--- /dev/null
+++ b/changelog.d/notifications-marker.change
@@ -0,0 +1 @@
+Fix 'Setting a marker should mark notifications as read'
\ No newline at end of file
diff --git a/changelog.d/oauth-app-spam.fix b/changelog.d/oauth-app-spam.fix
new file mode 100644
index 000000000..cdc2e816d
--- /dev/null
+++ b/changelog.d/oauth-app-spam.fix
@@ -0,0 +1 @@
+Add a rate limiter to the OAuth App creation endpoint and ensure registered apps are assigned to users.
diff --git a/changelog.d/oban-recevier-improvements.fix b/changelog.d/oban-recevier-improvements.fix
new file mode 100644
index 000000000..f91502ed2
--- /dev/null
+++ b/changelog.d/oban-recevier-improvements.fix
@@ -0,0 +1 @@
+ReceiverWorker will cancel processing jobs instead of retrying if the user cannot be fetched due to 403, 404, or 410 errors or if the account is disabled locally.
diff --git a/changelog.d/oban-uniques.change b/changelog.d/oban-uniques.change
new file mode 100644
index 000000000..d9deb4696
--- /dev/null
+++ b/changelog.d/oban-uniques.change
@@ -0,0 +1 @@
+Adjust more Oban workers to enforce unique job constraints.
diff --git a/changelog.d/oban-update.change b/changelog.d/oban-update.change
new file mode 100644
index 000000000..48a54ed2d
--- /dev/null
+++ b/changelog.d/oban-update.change
@@ -0,0 +1 @@
+Oban updated to 2.18.3
diff --git a/changelog.d/oban_gun_snooze.change b/changelog.d/oban_gun_snooze.change
new file mode 100644
index 000000000..c94525b2a
--- /dev/null
+++ b/changelog.d/oban_gun_snooze.change
@@ -0,0 +1 @@
+Publisher behavior improvement when snoozing Oban jobs due to Gun connection pool contention.
diff --git a/changelog.d/poll-refresh.change b/changelog.d/poll-refresh.change
new file mode 100644
index 000000000..b755128a1
--- /dev/null
+++ b/changelog.d/poll-refresh.change
@@ -0,0 +1 @@
+Poll results refreshing is handled asynchronously and will not attempt to keep fetching updates to a closed poll.
diff --git a/changelog.d/profile-image-descriptions.add b/changelog.d/profile-image-descriptions.add
new file mode 100644
index 000000000..85cc48083
--- /dev/null
+++ b/changelog.d/profile-image-descriptions.add
@@ -0,0 +1 @@
+Allow providing avatar/header descriptions
\ No newline at end of file
diff --git a/changelog.d/profile-image-descriptions.skip b/changelog.d/profile-image-descriptions.skip
new file mode 100644
index 000000000..e69de29bb
diff --git a/changelog.d/publisher-reachability.fix b/changelog.d/publisher-reachability.fix
new file mode 100644
index 000000000..3f50be581
--- /dev/null
+++ b/changelog.d/publisher-reachability.fix
@@ -0,0 +1 @@
+Address case where instance reachability status couldn't be updated
diff --git a/changelog.d/release-tuning.change b/changelog.d/release-tuning.change
new file mode 100644
index 000000000..bf9abc3ad
--- /dev/null
+++ b/changelog.d/release-tuning.change
@@ -0,0 +1 @@
+Tuning for release builds to lower CPU usage.
diff --git a/changelog.d/remote-object-fetcher.fix b/changelog.d/remote-object-fetcher.fix
new file mode 100644
index 000000000..dcf2b1b31
--- /dev/null
+++ b/changelog.d/remote-object-fetcher.fix
@@ -0,0 +1 @@
+Remote Fetcher Worker recognizes more permanent failure errors
diff --git a/changelog.d/remote-report-policy.add b/changelog.d/remote-report-policy.add
new file mode 100644
index 000000000..1cf25b1a8
--- /dev/null
+++ b/changelog.d/remote-report-policy.add
@@ -0,0 +1 @@
+Added RemoteReportPolicy from Rebased for handling bogus federated reports
diff --git a/changelog.d/rich-media-no-heads.change b/changelog.d/rich-media-no-heads.change
new file mode 100644
index 000000000..0bab323aa
--- /dev/null
+++ b/changelog.d/rich-media-no-heads.change
@@ -0,0 +1 @@
+Rich Media preview fetching will skip making an HTTP HEAD request to check a URL for allowed content type and length if the Tesla adapter is Gun or Finch
diff --git a/changelog.d/scrubbers-allow-mention-hashtag.add b/changelog.d/scrubbers-allow-mention-hashtag.add
new file mode 100644
index 000000000..c12ab1ffb
--- /dev/null
+++ b/changelog.d/scrubbers-allow-mention-hashtag.add
@@ -0,0 +1 @@
+scrubbers/default: Allow "mention hashtag" classes used by Mastodon
\ No newline at end of file
diff --git a/changelog.d/se-opt-out.change b/changelog.d/se-opt-out.change
new file mode 100644
index 000000000..dd694033f
--- /dev/null
+++ b/changelog.d/se-opt-out.change
@@ -0,0 +1 @@
+Fix nonexisting user will not generate metadata for search engine opt-out
diff --git a/changelog.d/stream-follow-relationships-count.fix b/changelog.d/stream-follow-relationships-count.fix
new file mode 100644
index 000000000..68452a88b
--- /dev/null
+++ b/changelog.d/stream-follow-relationships-count.fix
@@ -0,0 +1 @@
+StreamerView: Do not leak follows count if hidden
\ No newline at end of file
diff --git a/changelog.d/swoosh-mua.add b/changelog.d/swoosh-mua.add
new file mode 100644
index 000000000..d4c4bbd08
--- /dev/null
+++ b/changelog.d/swoosh-mua.add
@@ -0,0 +1 @@
+Added dependencies for Swoosh's Mua mail adapter
diff --git a/changelog.d/text-extensions.skip b/changelog.d/text-extensions.skip
new file mode 100644
index 000000000..e69de29bb
diff --git a/changelog.d/todo-cleanup.skip b/changelog.d/todo-cleanup.skip
new file mode 100644
index 000000000..e69de29bb
diff --git a/changelog.d/token-view-scopes.add b/changelog.d/token-view-scopes.add
new file mode 100644
index 000000000..e24fa38e6
--- /dev/null
+++ b/changelog.d/token-view-scopes.add
@@ -0,0 +1 @@
+Include session scopes in TokenView
\ No newline at end of file
diff --git a/changelog.d/update-oban.change b/changelog.d/update-oban.change
new file mode 100644
index 000000000..a67b3e3cf
--- /dev/null
+++ b/changelog.d/update-oban.change
@@ -0,0 +1 @@
+Update Oban to 2.18
diff --git a/changelog.d/user-factory.skip b/changelog.d/user-factory.skip
new file mode 100644
index 000000000..e69de29bb
diff --git a/changelog.d/user-imports.fix b/changelog.d/user-imports.fix
new file mode 100644
index 000000000..0076c73d7
--- /dev/null
+++ b/changelog.d/user-imports.fix
@@ -0,0 +1 @@
+Imports of blocks, mutes, and follows would retry repeatedly due to incorrect error handling and all work executed in a single job
diff --git a/changelog.d/vapid_keyword_fallback.fix b/changelog.d/vapid_keyword_fallback.fix
new file mode 100644
index 000000000..aa48f8938
--- /dev/null
+++ b/changelog.d/vapid_keyword_fallback.fix
@@ -0,0 +1 @@
+Make vapid_config return empty array, fixing preloading for instances without push notifications configured
\ No newline at end of file
diff --git a/changelog.d/workerhelper.change b/changelog.d/workerhelper.change
new file mode 100644
index 000000000..539c9b54f
--- /dev/null
+++ b/changelog.d/workerhelper.change
@@ -0,0 +1 @@
+Worker configuration is no longer available. This only affects custom max_retries values for a couple Oban queues.
diff --git a/config/config.exs b/config/config.exs
index 3e50b4207..cecb6b424 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -66,7 +66,6 @@ config :pleroma, Pleroma.Upload,
filename_display_max_length: 30,
default_description: :filename,
base_url: nil
- allowed_mime_types: ["image", "audio", "video"]
config :pleroma, Pleroma.Uploaders.Local, uploads: "uploads"
@@ -151,10 +150,7 @@ config :mime, :types, %{
"application/xrd+xml" => ["xrd+xml"],
"application/jrd+json" => ["jrd+json"],
"application/activity+json" => ["activity+json"],
- "application/ld+json" => ["activity+json"],
- # Can be removed when bumping MIME past 2.0.5
- # see https://akkoma.dev/AkkomaGang/akkoma/issues/657
- "image/apng" => ["apng"]
+ "application/ld+json" => ["activity+json"]
}
config :tesla, adapter: Tesla.Adapter.Hackney
@@ -361,8 +357,7 @@ config :pleroma, :activitypub,
follow_handshake_timeout: 500,
note_replies_output_limit: 5,
sign_object_fetches: true,
- authorized_fetch_mode: false,
- client_api_enabled: false
+ authorized_fetch_mode: false
config :pleroma, :streamer,
workers: 3,
@@ -431,6 +426,11 @@ config :pleroma, :mrf_vocabulary,
accept: [],
reject: []
+config :pleroma, :mrf_dnsrbl,
+ nameserver: "127.0.0.1",
+ port: 53,
+ zone: "bl.pleroma.com"
+
# threshold of 7 days
config :pleroma, :mrf_object_age,
threshold: 604_800,
@@ -820,13 +820,6 @@ config :pleroma, :frontends,
"https://lily-is.land/infra/glitch-lily/-/jobs/artifacts/${ref}/download?job=build",
"ref" => "servant",
"build_dir" => "public"
- },
- "pl-fe" => %{
- "name" => "pl-fe",
- "git" => "https://github.com/mkljczk/pl-fe",
- "build_url" => "https://pl.mkljczk.pl/pl-fe.zip",
- "ref" => "develop",
- "build_dir" => "."
}
}
diff --git a/config/description.exs b/config/description.exs
index 996978298..47f4771eb 100644
--- a/config/description.exs
+++ b/config/description.exs
@@ -117,19 +117,6 @@ config :pleroma, :config_description, [
key: :filename_display_max_length,
type: :integer,
description: "Set max length of a filename to display. 0 = no limit. Default: 30"
- },
- %{
- key: :allowed_mime_types,
- label: "Allowed MIME types",
- type: {:list, :string},
- description:
- "List of MIME (main) types uploads are allowed to identify themselves with. Other types may still be uploaded, but will identify as a generic binary to clients. WARNING: Loosening this over the defaults can lead to security issues. Removing types is safe, but only add to the list if you are sure you know what you are doing.",
- suggestions: [
- "image",
- "audio",
- "video",
- "font"
- ]
}
]
},
@@ -1785,11 +1772,6 @@ config :pleroma, :config_description, [
type: :integer,
description: "Following handshake timeout",
suggestions: [500]
- },
- %{
- key: :client_api_enabled,
- type: :boolean,
- description: "Allow client to server ActivityPub interactions"
}
]
},
@@ -3320,7 +3302,8 @@ config :pleroma, :config_description, [
suggestions: [
Pleroma.Web.Preload.Providers.Instance,
Pleroma.Web.Preload.Providers.User,
- Pleroma.Web.Preload.Providers.Timelines
+ Pleroma.Web.Preload.Providers.Timelines,
+ Pleroma.Web.Preload.Providers.StatusNet
]
}
]
diff --git a/config/test.exs b/config/test.exs
index 0f8b12ffe..6fe84478a 100644
--- a/config/test.exs
+++ b/config/test.exs
@@ -38,10 +38,7 @@ config :pleroma, :instance,
external_user_synchronization: false,
static_dir: "test/instance_static/"
-config :pleroma, :activitypub,
- sign_object_fetches: false,
- follow_handshake_timeout: 0,
- client_api_enabled: true
+config :pleroma, :activitypub, sign_object_fetches: false, follow_handshake_timeout: 0
# Configure your database
config :pleroma, Pleroma.Repo,
@@ -147,7 +144,6 @@ config :pleroma, Pleroma.Search.Meilisearch, url: "http://127.0.0.1:7700/", priv
config :phoenix, :plug_init_mode, :runtime
config :pleroma, :config_impl, Pleroma.UnstubbedConfigMock
-config :pleroma, :datetime_impl, Pleroma.DateTimeMock
config :pleroma, Pleroma.PromEx, disabled: true
@@ -162,12 +158,6 @@ config :pleroma, Pleroma.Uploaders.IPFS, config_impl: Pleroma.UnstubbedConfigMoc
config :pleroma, Pleroma.Web.Plugs.HTTPSecurityPlug, config_impl: Pleroma.StaticStubbedConfigMock
config :pleroma, Pleroma.Web.Plugs.HTTPSignaturePlug, config_impl: Pleroma.StaticStubbedConfigMock
-config :pleroma, Pleroma.Upload.Filter.AnonymizeFilename,
- config_impl: Pleroma.StaticStubbedConfigMock
-
-config :pleroma, Pleroma.Upload.Filter.Mogrify, config_impl: Pleroma.StaticStubbedConfigMock
-config :pleroma, Pleroma.Upload.Filter.Mogrify, mogrify_impl: Pleroma.MogrifyMock
-
config :pleroma, Pleroma.Signature, http_signatures_impl: Pleroma.StubbedHTTPSignaturesMock
peer_module =
diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md
index 6e2fddcb6..36e9cbba2 100644
--- a/docs/configuration/cheatsheet.md
+++ b/docs/configuration/cheatsheet.md
@@ -98,7 +98,7 @@ To add configuration to your config file, you can copy it from the base config.
* `moderator_privileges`: A list of privileges a moderator has (e.g. delete messages, manage reports...)
* Possible values are the same as for `admin_privileges`
-## :features
+## :database
* `improved_hashtag_timeline`: Setting to force toggle / force disable improved hashtags timeline. `:enabled` forces hashtags to be fetched from `hashtags` table for hashtags timeline. `:disabled` forces object-embedded hashtags to be used (slower). Keep it `:auto` for automatic behaviour (it is auto-set to `:enabled` [unless overridden] when HashtagsTableMigrator completes).
## Background migrations
diff --git a/docs/installation/debian_based_en.md b/docs/installation/debian_based_en.md
index 30f48792d..21cfe2bff 100644
--- a/docs/installation/debian_based_en.md
+++ b/docs/installation/debian_based_en.md
@@ -72,7 +72,7 @@ sudo -Hu pleroma mix deps.get
* Generate the configuration:
```shell
-sudo -Hu pleroma MIX_ENV=prod mix pleroma.instance gen
+sudo -Hu pleroma MIX_ENV=prod mix pleroma.instance gen`
```
* During this process:
diff --git a/lib/mix/tasks/pleroma/emoji.ex b/lib/mix/tasks/pleroma/emoji.ex
index b656f161f..8b9c921c8 100644
--- a/lib/mix/tasks/pleroma/emoji.ex
+++ b/lib/mix/tasks/pleroma/emoji.ex
@@ -93,7 +93,6 @@ defmodule Mix.Tasks.Pleroma.Emoji do
)
files = fetch_and_decode!(files_loc)
- files_to_unzip = for({_, f} <- files, do: f)
IO.puts(IO.ANSI.format(["Unpacking ", :bright, pack_name]))
@@ -104,7 +103,17 @@ defmodule Mix.Tasks.Pleroma.Emoji do
pack_name
])
- {:ok, _} = Pleroma.SafeZip.unzip_data(binary_archive, pack_path, files_to_unzip)
+ files_to_unzip =
+ Enum.map(
+ files,
+ fn {_, f} -> to_charlist(f) end
+ )
+
+ {:ok, _} =
+ :zip.unzip(binary_archive,
+ cwd: String.to_charlist(pack_path),
+ file_list: files_to_unzip
+ )
IO.puts(IO.ANSI.format(["Writing pack.json for ", :bright, pack_name]))
@@ -192,7 +201,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do
tmp_pack_dir = Path.join(System.tmp_dir!(), "emoji-pack-#{name}")
- {:ok, _} = Pleroma.SafeZip.unzip_data(binary_archive, tmp_pack_dir)
+ {:ok, _} = :zip.unzip(binary_archive, cwd: String.to_charlist(tmp_pack_dir))
emoji_map = Pleroma.Emoji.Loader.make_shortcode_to_file_map(tmp_pack_dir, exts)
diff --git a/lib/pleroma/config.ex b/lib/pleroma/config.ex
index 1bc371dec..cf1453c9b 100644
--- a/lib/pleroma/config.ex
+++ b/lib/pleroma/config.ex
@@ -27,7 +27,6 @@ defmodule Pleroma.Config do
Application.get_env(:pleroma, key, default)
end
- @impl true
def get!(key) do
value = get(key, nil)
diff --git a/lib/pleroma/config/getting.ex b/lib/pleroma/config/getting.ex
index adf764f89..ec93fd02a 100644
--- a/lib/pleroma/config/getting.ex
+++ b/lib/pleroma/config/getting.ex
@@ -5,13 +5,10 @@
defmodule Pleroma.Config.Getting do
@callback get(any()) :: any()
@callback get(any(), any()) :: any()
- @callback get!(any()) :: any()
def get(key), do: get(key, nil)
def get(key, default), do: impl().get(key, default)
- def get!(key), do: impl().get!(key)
-
def impl do
Application.get_env(:pleroma, :config_impl, Pleroma.Config)
end
diff --git a/lib/pleroma/constants.ex b/lib/pleroma/constants.ex
index 2cb8112ec..46c87182f 100644
--- a/lib/pleroma/constants.ex
+++ b/lib/pleroma/constants.ex
@@ -20,8 +20,7 @@ defmodule Pleroma.Constants do
"deleted_activity_id",
"pleroma_internal",
"generator",
- "rules",
- "language"
+ "rules"
]
)
@@ -37,12 +36,10 @@ defmodule Pleroma.Constants do
"updated",
"emoji",
"content",
- "contentMap",
"summary",
"sensitive",
"attachment",
- "generator",
- "language"
+ "generator"
]
)
@@ -103,8 +100,7 @@ defmodule Pleroma.Constants do
"Announce",
"Undo",
"Flag",
- "EmojiReact",
- "Listen"
+ "EmojiReact"
]
)
diff --git a/lib/pleroma/date_time.ex b/lib/pleroma/date_time.ex
deleted file mode 100644
index d79cb848b..000000000
--- a/lib/pleroma/date_time.ex
+++ /dev/null
@@ -1,3 +0,0 @@
-defmodule Pleroma.DateTime do
- @callback utc_now() :: NaiveDateTime.t()
-end
diff --git a/lib/pleroma/date_time/impl.ex b/lib/pleroma/date_time/impl.ex
deleted file mode 100644
index 102be047b..000000000
--- a/lib/pleroma/date_time/impl.ex
+++ /dev/null
@@ -1,6 +0,0 @@
-defmodule Pleroma.DateTime.Impl do
- @behaviour Pleroma.DateTime
-
- @impl true
- def utc_now, do: NaiveDateTime.utc_now()
-end
diff --git a/lib/pleroma/ecto_type/activity_pub/object_validators/content_language_map.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/content_language_map.ex
deleted file mode 100644
index dcdab19f8..000000000
--- a/lib/pleroma/ecto_type/activity_pub/object_validators/content_language_map.ex
+++ /dev/null
@@ -1,49 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2023 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.ContentLanguageMap do
- use Ecto.Type
-
- import Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode,
- only: [good_locale_code?: 1]
-
- def type, do: :map
-
- def cast(%{} = object) do
- with {status, %{} = data} when status in [:modified, :ok] <- validate_map(object) do
- {:ok, data}
- else
- {_, nil} -> {:ok, nil}
- {:error, _} -> :error
- end
- end
-
- def cast(_), do: :error
-
- def dump(data), do: {:ok, data}
-
- def load(data), do: {:ok, data}
-
- defp validate_map(%{} = object) do
- {status, data} =
- object
- |> Enum.reduce({:ok, %{}}, fn
- {lang, value}, {status, acc} when is_binary(lang) and is_binary(value) ->
- if good_locale_code?(lang) do
- {status, Map.put(acc, lang, value)}
- else
- {:modified, acc}
- end
-
- _, {_status, acc} ->
- {:modified, acc}
- end)
-
- if data == %{} do
- {status, nil}
- else
- {status, data}
- end
- end
-end
diff --git a/lib/pleroma/ecto_type/activity_pub/object_validators/language_code.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/language_code.ex
deleted file mode 100644
index 4779deeb0..000000000
--- a/lib/pleroma/ecto_type/activity_pub/object_validators/language_code.ex
+++ /dev/null
@@ -1,27 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2023 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode do
- use Ecto.Type
-
- def type, do: :string
-
- def cast(language) when is_binary(language) do
- if good_locale_code?(language) do
- {:ok, language}
- else
- {:error, :invalid_language}
- end
- end
-
- def cast(_), do: :error
-
- def dump(data), do: {:ok, data}
-
- def load(data), do: {:ok, data}
-
- def good_locale_code?(code) when is_binary(code), do: code =~ ~r<^[a-zA-Z0-9\-]+\z$>
-
- def good_locale_code?(_code), do: false
-end
diff --git a/lib/pleroma/emoji/pack.ex b/lib/pleroma/emoji/pack.ex
index c58748d3c..785fdb8b2 100644
--- a/lib/pleroma/emoji/pack.ex
+++ b/lib/pleroma/emoji/pack.ex
@@ -24,13 +24,12 @@ defmodule Pleroma.Emoji.Pack do
alias Pleroma.Emoji
alias Pleroma.Emoji.Pack
- alias Pleroma.SafeZip
alias Pleroma.Utils
@spec create(String.t()) :: {:ok, t()} | {:error, File.posix()} | {:error, :empty_values}
def create(name) do
with :ok <- validate_not_empty([name]),
- dir <- path_join_name_safe(emoji_path(), name),
+ dir <- Path.join(emoji_path(), name),
:ok <- File.mkdir(dir) do
save_pack(%__MODULE__{pack_file: Path.join(dir, "pack.json")})
end
@@ -66,21 +65,43 @@ defmodule Pleroma.Emoji.Pack do
{:ok, [binary()]} | {:error, File.posix(), binary()} | {:error, :empty_values}
def delete(name) do
with :ok <- validate_not_empty([name]),
- pack_path <- path_join_name_safe(emoji_path(), name) do
+ pack_path <- Path.join(emoji_path(), name) do
File.rm_rf(pack_path)
end
end
+ @spec unpack_zip_emojies(list(tuple())) :: list(map())
+ defp unpack_zip_emojies(zip_files) do
+ Enum.reduce(zip_files, [], fn
+ {_, path, s, _, _, _}, acc when elem(s, 2) == :regular ->
+ with(
+ filename <- Path.basename(path),
+ shortcode <- Path.basename(filename, Path.extname(filename)),
+ false <- Emoji.exist?(shortcode)
+ ) do
+ [%{path: path, filename: path, shortcode: shortcode} | acc]
+ else
+ _ -> acc
+ end
+
+ _, acc ->
+ acc
+ end)
+ end
+
@spec add_file(t(), String.t(), Path.t(), Plug.Upload.t()) ::
{:ok, t()}
| {:error, File.posix() | atom()}
def add_file(%Pack{} = pack, _, _, %Plug.Upload{content_type: "application/zip"} = file) do
- with {:ok, zip_files} <- SafeZip.list_dir_file(file.path),
- [_ | _] = emojies <- map_zip_emojies(zip_files),
+ with {:ok, zip_files} <- :zip.table(to_charlist(file.path)),
+ [_ | _] = emojies <- unpack_zip_emojies(zip_files),
{:ok, tmp_dir} <- Utils.tmp_dir("emoji") do
try do
{:ok, _emoji_files} =
- SafeZip.unzip_file(file.path, tmp_dir, Enum.map(emojies, & &1[:path]))
+ :zip.unzip(
+ to_charlist(file.path),
+ [{:file_list, Enum.map(emojies, & &1[:path])}, {:cwd, String.to_charlist(tmp_dir)}]
+ )
{_, updated_pack} =
Enum.map_reduce(emojies, pack, fn item, emoji_pack ->
@@ -271,7 +292,7 @@ defmodule Pleroma.Emoji.Pack do
@spec load_pack(String.t()) :: {:ok, t()} | {:error, :file.posix()}
def load_pack(name) do
name = Path.basename(name)
- pack_file = path_join_name_safe(emoji_path(), name) |> Path.join("pack.json")
+ pack_file = Path.join([emoji_path(), name, "pack.json"])
with {:ok, _} <- File.stat(pack_file),
{:ok, pack_data} <- File.read(pack_file) do
@@ -395,9 +416,10 @@ defmodule Pleroma.Emoji.Pack do
end
defp create_archive_and_cache(pack, hash) do
- pack_file_list = Enum.into(pack.files, [], fn {_, f} -> f end)
- files = ["pack.json" | pack_file_list]
- {:ok, {_, result}} = SafeZip.zip("#{pack.name}.zip", files, pack.path, true)
+ files = [~c"pack.json" | Enum.map(pack.files, fn {_, file} -> to_charlist(file) end)]
+
+ {:ok, {_, result}} =
+ :zip.zip(~c"#{pack.name}.zip", files, [:memory, cwd: to_charlist(pack.path)])
ttl_per_file = Pleroma.Config.get!([:emoji, :shared_pack_cache_seconds_per_file])
overall_ttl = :timer.seconds(ttl_per_file * Enum.count(files))
@@ -456,7 +478,7 @@ defmodule Pleroma.Emoji.Pack do
end
defp save_file(%Plug.Upload{path: upload_path}, pack, filename) do
- file_path = path_join_safe(pack.path, filename)
+ file_path = Path.join(pack.path, filename)
create_subdirs(file_path)
with {:ok, _} <- File.copy(upload_path, file_path) do
@@ -475,8 +497,8 @@ defmodule Pleroma.Emoji.Pack do
end
defp rename_file(pack, filename, new_filename) do
- old_path = path_join_safe(pack.path, filename)
- new_path = path_join_safe(pack.path, new_filename)
+ old_path = Path.join(pack.path, filename)
+ new_path = Path.join(pack.path, new_filename)
create_subdirs(new_path)
with :ok <- File.rename(old_path, new_path) do
@@ -494,7 +516,7 @@ defmodule Pleroma.Emoji.Pack do
defp remove_file(pack, shortcode) do
with {:ok, filename} <- get_filename(pack, shortcode),
- emoji <- path_join_safe(pack.path, filename),
+ emoji <- Path.join(pack.path, filename),
:ok <- File.rm(emoji) do
remove_dir_if_empty(emoji, filename)
end
@@ -512,7 +534,7 @@ defmodule Pleroma.Emoji.Pack do
defp get_filename(pack, shortcode) do
with %{^shortcode => filename} when is_binary(filename) <- pack.files,
- file_path <- path_join_safe(pack.path, filename),
+ file_path <- Path.join(pack.path, filename),
{:ok, _} <- File.stat(file_path) do
{:ok, filename}
else
@@ -562,10 +584,11 @@ defmodule Pleroma.Emoji.Pack do
defp unzip(archive, pack_info, remote_pack, local_pack) do
with :ok <- File.mkdir_p!(local_pack.path) do
- files = Enum.map(remote_pack["files"], fn {_, path} -> path end)
+ files = Enum.map(remote_pack["files"], fn {_, path} -> to_charlist(path) end)
# Fallback cannot contain a pack.json file
- files = if pack_info[:fallback], do: files, else: ["pack.json" | files]
- SafeZip.unzip_data(archive, local_pack.path, files)
+ files = if pack_info[:fallback], do: files, else: [~c"pack.json" | files]
+
+ :zip.unzip(archive, cwd: to_charlist(local_pack.path), file_list: files)
end
end
@@ -626,43 +649,13 @@ defmodule Pleroma.Emoji.Pack do
end
defp validate_has_all_files(pack, zip) do
- # Check if all files from the pack.json are in the archive
- eset =
- Enum.reduce(pack.files, MapSet.new(), fn
- {_, file}, s -> MapSet.put(s, to_charlist(file))
+ with {:ok, f_list} <- :zip.unzip(zip, [:memory]) do
+ # Check if all files from the pack.json are in the archive
+ pack.files
+ |> Enum.all?(fn {_, from_manifest} ->
+ List.keyfind(f_list, to_charlist(from_manifest), 0)
end)
-
- if SafeZip.contains_all_data?(zip, eset),
- do: :ok,
- else: {:error, :incomplete}
- end
-
- defp path_join_name_safe(dir, name) do
- if to_string(name) != Path.basename(name) or name in ["..", ".", ""] do
- raise "Invalid or malicious pack name: #{name}"
- else
- Path.join(dir, name)
+ |> if(do: :ok, else: {:error, :incomplete})
end
end
-
- defp path_join_safe(dir, path) do
- {:ok, safe_path} = Path.safe_relative(path)
- Path.join(dir, safe_path)
- end
-
- defp map_zip_emojies(zip_files) do
- Enum.reduce(zip_files, [], fn path, acc ->
- with(
- filename <- Path.basename(path),
- shortcode <- Path.basename(filename, Path.extname(filename)),
- # note: this only checks the shortcode, if an emoji already exists on the same path, but
- # with a different shortcode, the existing one will be degraded to an alias of the new
- false <- Emoji.exist?(shortcode)
- ) do
- [%{path: path, filename: path, shortcode: shortcode} | acc]
- else
- _ -> acc
- end
- end)
- end
end
diff --git a/lib/pleroma/frontend.ex b/lib/pleroma/frontend.ex
index fe7f525ea..a4f427ae5 100644
--- a/lib/pleroma/frontend.ex
+++ b/lib/pleroma/frontend.ex
@@ -65,12 +65,24 @@ defmodule Pleroma.Frontend do
end
def unzip(zip, dest) do
- File.rm_rf!(dest)
- File.mkdir_p!(dest)
+ with {:ok, unzipped} <- :zip.unzip(zip, [:memory]) do
+ File.rm_rf!(dest)
+ File.mkdir_p!(dest)
- case Pleroma.SafeZip.unzip_data(zip, dest) do
- {:ok, _} -> :ok
- error -> error
+ Enum.each(unzipped, fn {filename, data} ->
+ path = filename
+
+ new_file_path = Path.join(dest, path)
+
+ path
+ |> Path.dirname()
+ |> then(&Path.join(dest, &1))
+ |> File.mkdir_p!()
+
+ if not File.dir?(new_file_path) do
+ File.write!(new_file_path, data)
+ end
+ end)
end
end
diff --git a/lib/pleroma/hashtag.ex b/lib/pleroma/hashtag.ex
index 3682f0c14..a43d88220 100644
--- a/lib/pleroma/hashtag.ex
+++ b/lib/pleroma/hashtag.ex
@@ -12,7 +12,6 @@ defmodule Pleroma.Hashtag do
alias Pleroma.Hashtag
alias Pleroma.Object
alias Pleroma.Repo
- alias Pleroma.User.HashtagFollow
schema "hashtags" do
field(:name, :string)
@@ -28,14 +27,6 @@ defmodule Pleroma.Hashtag do
|> String.trim()
end
- def get_by_id(id) do
- Repo.get(Hashtag, id)
- end
-
- def get_by_name(name) do
- Repo.get_by(Hashtag, name: normalize_name(name))
- end
-
def get_or_create_by_name(name) do
changeset = changeset(%Hashtag{}, %{name: name})
@@ -112,22 +103,4 @@ defmodule Pleroma.Hashtag do
{:ok, deleted_count}
end
end
-
- def get_followers(%Hashtag{id: hashtag_id}) do
- from(hf in HashtagFollow)
- |> where([hf], hf.hashtag_id == ^hashtag_id)
- |> join(:inner, [hf], u in assoc(hf, :user))
- |> select([hf, u], u.id)
- |> Repo.all()
- end
-
- def get_recipients_for_activity(%Pleroma.Activity{object: %{hashtags: tags}})
- when is_list(tags) do
- tags
- |> Enum.map(&get_followers/1)
- |> List.flatten()
- |> Enum.uniq()
- end
-
- def get_recipients_for_activity(_activity), do: []
end
diff --git a/lib/pleroma/mogrify_behaviour.ex b/lib/pleroma/mogrify_behaviour.ex
deleted file mode 100644
index 234cb86cf..000000000
--- a/lib/pleroma/mogrify_behaviour.ex
+++ /dev/null
@@ -1,15 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.MogrifyBehaviour do
- @moduledoc """
- Behaviour for Mogrify operations.
- This module defines the interface for Mogrify operations that can be mocked in tests.
- """
-
- @callback open(binary()) :: map()
- @callback custom(map(), binary()) :: map()
- @callback custom(map(), binary(), binary()) :: map()
- @callback save(map(), keyword()) :: map()
-end
diff --git a/lib/pleroma/mogrify_wrapper.ex b/lib/pleroma/mogrify_wrapper.ex
deleted file mode 100644
index 17174fd97..000000000
--- a/lib/pleroma/mogrify_wrapper.ex
+++ /dev/null
@@ -1,30 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.MogrifyWrapper do
- @moduledoc """
- Default implementation of MogrifyBehaviour that delegates to Mogrify.
- """
- @behaviour Pleroma.MogrifyBehaviour
-
- @impl true
- def open(file) do
- Mogrify.open(file)
- end
-
- @impl true
- def custom(image, action) do
- Mogrify.custom(image, action)
- end
-
- @impl true
- def custom(image, action, options) do
- Mogrify.custom(image, action, options)
- end
-
- @impl true
- def save(image, opts) do
- Mogrify.save(image, opts)
- end
-end
diff --git a/lib/pleroma/object/containment.ex b/lib/pleroma/object/containment.ex
index 77fac12c0..f6106cb3f 100644
--- a/lib/pleroma/object/containment.ex
+++ b/lib/pleroma/object/containment.ex
@@ -47,19 +47,6 @@ defmodule Pleroma.Object.Containment do
defp compare_uris(%URI{host: host} = _id_uri, %URI{host: host} = _other_uri), do: :ok
defp compare_uris(_id_uri, _other_uri), do: :error
- @doc """
- Checks whether an URL to fetch from is from the local server.
-
- We never want to fetch from ourselves; if it's not in the database
- it can't be authentic and must be a counterfeit.
- """
- def contain_local_fetch(id) do
- case compare_uris(URI.parse(id), Pleroma.Web.Endpoint.struct_url()) do
- :ok -> :error
- _ -> :ok
- end
- end
-
@doc """
Checks that an imported AP object's actor matches the host it came from.
"""
diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex
index b54ef9ce5..c85a8b09f 100644
--- a/lib/pleroma/object/fetcher.ex
+++ b/lib/pleroma/object/fetcher.ex
@@ -19,8 +19,6 @@ defmodule Pleroma.Object.Fetcher do
require Logger
require Pleroma.Constants
- @mix_env Mix.env()
-
@spec reinject_object(struct(), map()) :: {:ok, Object.t()} | {:error, any()}
defp reinject_object(%Object{data: %{}} = object, new_data) do
Logger.debug("Reinjecting object #{new_data["id"]}")
@@ -148,7 +146,6 @@ defmodule Pleroma.Object.Fetcher do
with {:scheme, true} <- {:scheme, String.starts_with?(id, "http")},
{_, true} <- {:mrf, MRF.id_filter(id)},
- {_, :ok} <- {:local_fetch, Containment.contain_local_fetch(id)},
{:ok, body} <- get_object(id),
{:ok, data} <- safe_json_decode(body),
:ok <- Containment.contain_origin_from_id(id, data) do
@@ -161,9 +158,6 @@ defmodule Pleroma.Object.Fetcher do
{:scheme, _} ->
{:error, "Unsupported URI scheme"}
- {:local_fetch, _} ->
- {:error, "Trying to fetch local resource"}
-
{:error, e} ->
{:error, e}
@@ -178,19 +172,6 @@ defmodule Pleroma.Object.Fetcher do
def fetch_and_contain_remote_object_from_id(_id),
do: {:error, "id must be a string"}
- defp check_crossdomain_redirect(final_host, original_url)
-
- # Handle the common case in tests where responses don't include URLs
- if @mix_env == :test do
- defp check_crossdomain_redirect(nil, _) do
- {:cross_domain_redirect, false}
- end
- end
-
- defp check_crossdomain_redirect(final_host, original_url) do
- {:cross_domain_redirect, final_host != URI.parse(original_url).host}
- end
-
defp get_object(id) do
date = Pleroma.Signature.signed_date()
@@ -200,29 +181,19 @@ defmodule Pleroma.Object.Fetcher do
|> sign_fetch(id, date)
case HTTP.get(id, headers) do
- {:ok, %{body: body, status: code, headers: headers, url: final_url}}
- when code in 200..299 ->
- remote_host = if final_url, do: URI.parse(final_url).host, else: nil
-
- with {:cross_domain_redirect, false} <- check_crossdomain_redirect(remote_host, id),
- {_, content_type} <- List.keyfind(headers, "content-type", 0),
- {:ok, _media_type} <- verify_content_type(content_type) do
- {:ok, body}
- else
- {:cross_domain_redirect, true} ->
- {:error, {:cross_domain_redirect, true}}
-
- error ->
- error
- end
-
- # Handle the case where URL is not in the response (older HTTP library versions)
{:ok, %{body: body, status: code, headers: headers}} when code in 200..299 ->
case List.keyfind(headers, "content-type", 0) do
{_, content_type} ->
- case verify_content_type(content_type) do
- {:ok, _} -> {:ok, body}
- error -> error
+ case Plug.Conn.Utils.media_type(content_type) do
+ {:ok, "application", "activity+json", _} ->
+ {:ok, body}
+
+ {:ok, "application", "ld+json",
+ %{"profile" => "https://www.w3.org/ns/activitystreams"}} ->
+ {:ok, body}
+
+ _ ->
+ {:error, {:content_type, content_type}}
end
_ ->
@@ -245,17 +216,4 @@ defmodule Pleroma.Object.Fetcher do
defp safe_json_decode(nil), do: {:ok, nil}
defp safe_json_decode(json), do: Jason.decode(json)
-
- defp verify_content_type(content_type) do
- case Plug.Conn.Utils.media_type(content_type) do
- {:ok, "application", "activity+json", _} ->
- {:ok, :activity_json}
-
- {:ok, "application", "ld+json", %{"profile" => "https://www.w3.org/ns/activitystreams"}} ->
- {:ok, :ld_json}
-
- _ ->
- {:error, {:content_type, content_type}}
- end
- end
end
diff --git a/lib/pleroma/pagination.ex b/lib/pleroma/pagination.ex
index 66812b17b..8db732cc9 100644
--- a/lib/pleroma/pagination.ex
+++ b/lib/pleroma/pagination.ex
@@ -89,9 +89,9 @@ defmodule Pleroma.Pagination do
defp cast_params(params) do
param_types = %{
- min_id: params[:id_type] || :string,
- since_id: params[:id_type] || :string,
- max_id: params[:id_type] || :string,
+ min_id: :string,
+ since_id: :string,
+ max_id: :string,
offset: :integer,
limit: :integer,
skip_extra_order: :boolean,
diff --git a/lib/pleroma/reverse_proxy.ex b/lib/pleroma/reverse_proxy.ex
index 3c82f9996..8aec4ae58 100644
--- a/lib/pleroma/reverse_proxy.ex
+++ b/lib/pleroma/reverse_proxy.ex
@@ -17,8 +17,6 @@ defmodule Pleroma.ReverseProxy do
@failed_request_ttl :timer.seconds(60)
@methods ~w(GET HEAD)
- @allowed_mime_types Pleroma.Config.get([Pleroma.Upload, :allowed_mime_types], [])
-
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
def max_read_duration_default, do: @max_read_duration
@@ -303,26 +301,10 @@ defmodule Pleroma.ReverseProxy do
headers
|> Enum.filter(fn {k, _} -> k in @keep_resp_headers end)
|> build_resp_cache_headers(opts)
- |> sanitise_content_type()
|> build_resp_content_disposition_header(opts)
|> Keyword.merge(Keyword.get(opts, :resp_headers, []))
end
- defp sanitise_content_type(headers) do
- original_ct = get_content_type(headers)
-
- safe_ct =
- Pleroma.Web.Plugs.Utils.get_safe_mime_type(
- %{allowed_mime_types: @allowed_mime_types},
- original_ct
- )
-
- [
- {"content-type", safe_ct}
- | Enum.filter(headers, fn {k, _v} -> k != "content-type" end)
- ]
- end
-
defp build_resp_cache_headers(headers, _opts) do
has_cache? = Enum.any?(headers, fn {k, _} -> k in @resp_cache_headers end)
diff --git a/lib/pleroma/safe_zip.ex b/lib/pleroma/safe_zip.ex
deleted file mode 100644
index 25fe434d6..000000000
--- a/lib/pleroma/safe_zip.ex
+++ /dev/null
@@ -1,216 +0,0 @@
-# Akkoma: Magically expressive social media
-# Copyright © 2024 Akkoma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.SafeZip do
- @moduledoc """
- Wraps the subset of Erlang's zip module we’d like to use
- but enforces path-traversal safety everywhere and other checks.
-
- For convenience almost all functions accept both elixir strings and charlists,
- but output elixir strings themselves. However, this means the input parameter type
- can no longer be used to distinguish archive file paths from archive binary data in memory,
- thus where needed both a _data and _file variant are provided.
- """
-
- @type text() :: String.t() | [char()]
-
- defp safe_path?(path) do
- # Path accepts elixir’s chardata()
- case Path.safe_relative(path) do
- {:ok, _} -> true
- _ -> false
- end
- end
-
- defp safe_type?(file_type) do
- if file_type in [:regular, :directory] do
- true
- else
- false
- end
- end
-
- defp maybe_add_file(_type, _path_charlist, nil), do: nil
-
- defp maybe_add_file(:regular, path_charlist, file_list),
- do: [to_string(path_charlist) | file_list]
-
- defp maybe_add_file(_type, _path_charlist, file_list), do: file_list
-
- @spec check_safe_archive_and_maybe_list_files(binary() | [char()], [term()], boolean()) ::
- {:ok, [String.t()]} | {:error, reason :: term()}
- defp check_safe_archive_and_maybe_list_files(archive, opts, list) do
- acc = if list, do: [], else: nil
-
- with {:ok, table} <- :zip.table(archive, opts) do
- Enum.reduce_while(table, {:ok, acc}, fn
- # ZIP comment
- {:zip_comment, _}, acc ->
- {:cont, acc}
-
- # File entry
- {:zip_file, path, info, _comment, _offset, _comp_size}, {:ok, fl} ->
- with {_, type} <- {:get_type, elem(info, 2)},
- {_, true} <- {:type, safe_type?(type)},
- {_, true} <- {:safe_path, safe_path?(path)} do
- {:cont, {:ok, maybe_add_file(type, path, fl)}}
- else
- {:get_type, e} ->
- {:halt,
- {:error, "Couldn't determine file type of ZIP entry at #{path} (#{inspect(e)})"}}
-
- {:type, _} ->
- {:halt, {:error, "Potentially unsafe file type in ZIP at: #{path}"}}
-
- {:safe_path, _} ->
- {:halt, {:error, "Unsafe path in ZIP: #{path}"}}
- end
-
- # new OTP version?
- _, _acc ->
- {:halt, {:error, "Unknown ZIP record type"}}
- end)
- end
- end
-
- @spec check_safe_archive_and_list_files(binary() | [char()], [term()]) ::
- {:ok, [String.t()]} | {:error, reason :: term()}
- defp check_safe_archive_and_list_files(archive, opts \\ []) do
- check_safe_archive_and_maybe_list_files(archive, opts, true)
- end
-
- @spec check_safe_archive(binary() | [char()], [term()]) :: :ok | {:error, reason :: term()}
- defp check_safe_archive(archive, opts \\ []) do
- case check_safe_archive_and_maybe_list_files(archive, opts, false) do
- {:ok, _} -> :ok
- error -> error
- end
- end
-
- @spec check_safe_file_list([text()], text()) :: :ok | {:error, term()}
- defp check_safe_file_list([], _), do: :ok
-
- defp check_safe_file_list([path | tail], cwd) do
- with {_, true} <- {:path, safe_path?(path)},
- {_, {:ok, fstat}} <- {:stat, File.stat(Path.expand(path, cwd))},
- {_, true} <- {:type, safe_type?(fstat.type)} do
- check_safe_file_list(tail, cwd)
- else
- {:path, _} ->
- {:error, "Unsafe path escaping cwd: #{path}"}
-
- {:stat, e} ->
- {:error, "Unable to check file type of #{path}: #{inspect(e)}"}
-
- {:type, _} ->
- {:error, "Unsafe type at #{path}"}
- end
- end
-
- defp check_safe_file_list(_, _), do: {:error, "Malformed file_list"}
-
- @doc """
- Checks whether the archive data contais file entries for all paths from fset
-
- Note this really only accepts entries corresponding to regular _files_,
- if a path is contained as for example an directory, this does not count as a match.
- """
- @spec contains_all_data?(binary(), MapSet.t()) :: true | false
- def contains_all_data?(archive_data, fset) do
- with {:ok, table} <- :zip.table(archive_data) do
- remaining =
- Enum.reduce(table, fset, fn
- {:zip_file, path, info, _comment, _offset, _comp_size}, fset ->
- if elem(info, 2) == :regular do
- MapSet.delete(fset, path)
- else
- fset
- end
-
- _, _ ->
- fset
- end)
- |> MapSet.size()
-
- if remaining == 0, do: true, else: false
- else
- _ -> false
- end
- end
-
- @doc """
- List all file entries in ZIP, or error if invalid or unsafe.
-
- Note this really only lists regular files, no directories, ZIP comments or other types!
- """
- @spec list_dir_file(text()) :: {:ok, [String.t()]} | {:error, reason :: term()}
- def list_dir_file(archive) do
- path = to_charlist(archive)
- check_safe_archive_and_list_files(path)
- end
-
- defp stringify_zip({:ok, {fname, data}}), do: {:ok, {to_string(fname), data}}
- defp stringify_zip({:ok, fname}), do: {:ok, to_string(fname)}
- defp stringify_zip(ret), do: ret
-
- @spec zip(text(), text(), [text()], boolean()) ::
- {:ok, file_name :: String.t()}
- | {:ok, {file_name :: String.t(), file_data :: binary()}}
- | {:error, reason :: term()}
- def zip(name, file_list, cwd, memory \\ false) do
- opts = [{:cwd, to_charlist(cwd)}]
- opts = if memory, do: [:memory | opts], else: opts
-
- with :ok <- check_safe_file_list(file_list, cwd) do
- file_list = for f <- file_list, do: to_charlist(f)
- name = to_charlist(name)
- stringify_zip(:zip.zip(name, file_list, opts))
- end
- end
-
- @spec unzip_file(text(), text(), [text()] | nil) ::
- {:ok, [String.t()]}
- | {:error, reason :: term()}
- | {:error, {name :: text(), reason :: term()}}
- def unzip_file(archive, target_dir, file_list \\ nil) do
- do_unzip(to_charlist(archive), to_charlist(target_dir), file_list)
- end
-
- @spec unzip_data(binary(), text(), [text()] | nil) ::
- {:ok, [String.t()]}
- | {:error, reason :: term()}
- | {:error, {name :: text(), reason :: term()}}
- def unzip_data(archive, target_dir, file_list \\ nil) do
- do_unzip(archive, to_charlist(target_dir), file_list)
- end
-
- defp stringify_unzip({:ok, [{_fname, _data} | _] = filebinlist}),
- do: {:ok, Enum.map(filebinlist, fn {fname, data} -> {to_string(fname), data} end)}
-
- defp stringify_unzip({:ok, [_fname | _] = filelist}),
- do: {:ok, Enum.map(filelist, fn fname -> to_string(fname) end)}
-
- defp stringify_unzip({:error, {fname, term}}), do: {:error, {to_string(fname), term}}
- defp stringify_unzip(ret), do: ret
-
- @spec do_unzip(binary() | [char()], text(), [text()] | nil) ::
- {:ok, [String.t()]}
- | {:error, reason :: term()}
- | {:error, {name :: text(), reason :: term()}}
- defp do_unzip(archive, target_dir, file_list) do
- opts =
- if file_list != nil do
- [
- file_list: for(f <- file_list, do: to_charlist(f)),
- cwd: target_dir
- ]
- else
- [cwd: target_dir]
- end
-
- with :ok <- check_safe_archive(archive) do
- stringify_unzip(:zip.unzip(archive, opts))
- end
- end
-end
diff --git a/lib/pleroma/upload/filter/analyze_metadata.ex b/lib/pleroma/upload/filter/analyze_metadata.ex
index a8480bf36..7ee643277 100644
--- a/lib/pleroma/upload/filter/analyze_metadata.ex
+++ b/lib/pleroma/upload/filter/analyze_metadata.ex
@@ -90,13 +90,9 @@ defmodule Pleroma.Upload.Filter.AnalyzeMetadata do
{:ok, rgb} =
if Image.has_alpha?(resized_image) do
# remove alpha channel
- case Operation.extract_band(resized_image, 0, n: 3) do
- {:ok, data} ->
- Image.write_to_binary(data)
-
- _ ->
- Image.write_to_binary(resized_image)
- end
+ resized_image
+ |> Operation.extract_band!(0, n: 3)
+ |> Image.write_to_binary()
else
Image.write_to_binary(resized_image)
end
diff --git a/lib/pleroma/upload/filter/anonymize_filename.ex b/lib/pleroma/upload/filter/anonymize_filename.ex
index c0ad70368..234ccb6bb 100644
--- a/lib/pleroma/upload/filter/anonymize_filename.ex
+++ b/lib/pleroma/upload/filter/anonymize_filename.ex
@@ -10,7 +10,7 @@ defmodule Pleroma.Upload.Filter.AnonymizeFilename do
"""
@behaviour Pleroma.Upload.Filter
- @config_impl Application.compile_env(:pleroma, [__MODULE__, :config_impl], Pleroma.Config)
+ alias Pleroma.Config
alias Pleroma.Upload
def filter(%Upload{name: name} = upload) do
@@ -23,7 +23,7 @@ defmodule Pleroma.Upload.Filter.AnonymizeFilename do
@spec predefined_name(String.t()) :: String.t() | nil
defp predefined_name(extension) do
- with name when not is_nil(name) <- @config_impl.get([__MODULE__, :text]),
+ with name when not is_nil(name) <- Config.get([__MODULE__, :text]),
do: String.replace(name, "{extension}", extension)
end
diff --git a/lib/pleroma/upload/filter/mogrify.ex b/lib/pleroma/upload/filter/mogrify.ex
index 7c7431db6..d1e166022 100644
--- a/lib/pleroma/upload/filter/mogrify.ex
+++ b/lib/pleroma/upload/filter/mogrify.ex
@@ -8,16 +8,9 @@ defmodule Pleroma.Upload.Filter.Mogrify do
@type conversion :: action :: String.t() | {action :: String.t(), opts :: String.t()}
@type conversions :: conversion() | [conversion()]
- @config_impl Application.compile_env(:pleroma, [__MODULE__, :config_impl], Pleroma.Config)
- @mogrify_impl Application.compile_env(
- :pleroma,
- [__MODULE__, :mogrify_impl],
- Pleroma.MogrifyWrapper
- )
-
def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _}) do
try do
- do_filter(file, @config_impl.get!([__MODULE__, :args]))
+ do_filter(file, Pleroma.Config.get!([__MODULE__, :args]))
{:ok, :filtered}
rescue
e in ErlangError ->
@@ -29,9 +22,9 @@ defmodule Pleroma.Upload.Filter.Mogrify do
def do_filter(file, filters) do
file
- |> @mogrify_impl.open()
+ |> Mogrify.open()
|> mogrify_filter(filters)
- |> @mogrify_impl.save(in_place: true)
+ |> Mogrify.save(in_place: true)
end
defp mogrify_filter(mogrify, nil), do: mogrify
@@ -45,10 +38,10 @@ defmodule Pleroma.Upload.Filter.Mogrify do
defp mogrify_filter(mogrify, []), do: mogrify
defp mogrify_filter(mogrify, {action, options}) do
- @mogrify_impl.custom(mogrify, action, options)
+ Mogrify.custom(mogrify, action, options)
end
defp mogrify_filter(mogrify, action) when is_binary(action) do
- @mogrify_impl.custom(mogrify, action)
+ Mogrify.custom(mogrify, action)
end
end
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index d9da9ede1..7a36ece77 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -19,7 +19,6 @@ defmodule Pleroma.User do
alias Pleroma.Emoji
alias Pleroma.FollowingRelationship
alias Pleroma.Formatter
- alias Pleroma.Hashtag
alias Pleroma.HTML
alias Pleroma.Keys
alias Pleroma.MFA
@@ -28,7 +27,6 @@ defmodule Pleroma.User do
alias Pleroma.Registration
alias Pleroma.Repo
alias Pleroma.User
- alias Pleroma.User.HashtagFollow
alias Pleroma.UserRelationship
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Builder
@@ -176,12 +174,6 @@ defmodule Pleroma.User do
has_many(:outgoing_relationships, UserRelationship, foreign_key: :source_id)
has_many(:incoming_relationships, UserRelationship, foreign_key: :target_id)
- many_to_many(:followed_hashtags, Hashtag,
- on_replace: :delete,
- on_delete: :delete_all,
- join_through: HashtagFollow
- )
-
for {relationship_type,
[
{outgoing_relation, outgoing_relation_target},
@@ -2869,54 +2861,4 @@ defmodule Pleroma.User do
birthday_month: month
})
end
-
- defp maybe_load_followed_hashtags(%User{followed_hashtags: follows} = user)
- when is_list(follows),
- do: user
-
- defp maybe_load_followed_hashtags(%User{} = user) do
- followed_hashtags = HashtagFollow.get_by_user(user)
- %{user | followed_hashtags: followed_hashtags}
- end
-
- def followed_hashtags(%User{followed_hashtags: follows})
- when is_list(follows),
- do: follows
-
- def followed_hashtags(%User{} = user) do
- {:ok, user} =
- user
- |> maybe_load_followed_hashtags()
- |> set_cache()
-
- user.followed_hashtags
- end
-
- def follow_hashtag(%User{} = user, %Hashtag{} = hashtag) do
- Logger.debug("Follow hashtag #{hashtag.name} for user #{user.nickname}")
- user = maybe_load_followed_hashtags(user)
-
- with {:ok, _} <- HashtagFollow.new(user, hashtag),
- follows <- HashtagFollow.get_by_user(user),
- %User{} = user <- user |> Map.put(:followed_hashtags, follows) do
- user
- |> set_cache()
- end
- end
-
- def unfollow_hashtag(%User{} = user, %Hashtag{} = hashtag) do
- Logger.debug("Unfollow hashtag #{hashtag.name} for user #{user.nickname}")
- user = maybe_load_followed_hashtags(user)
-
- with {:ok, _} <- HashtagFollow.delete(user, hashtag),
- follows <- HashtagFollow.get_by_user(user),
- %User{} = user <- user |> Map.put(:followed_hashtags, follows) do
- user
- |> set_cache()
- end
- end
-
- def following_hashtag?(%User{} = user, %Hashtag{} = hashtag) do
- not is_nil(HashtagFollow.get(user, hashtag))
- end
end
diff --git a/lib/pleroma/user/backup.ex b/lib/pleroma/user/backup.ex
index 244b08adb..d77d49890 100644
--- a/lib/pleroma/user/backup.ex
+++ b/lib/pleroma/user/backup.ex
@@ -16,7 +16,6 @@ defmodule Pleroma.User.Backup do
alias Pleroma.Bookmark
alias Pleroma.Config
alias Pleroma.Repo
- alias Pleroma.SafeZip
alias Pleroma.Uploaders.Uploader
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
@@ -180,12 +179,12 @@ defmodule Pleroma.User.Backup do
end
@files [
- "actor.json",
- "outbox.json",
- "likes.json",
- "bookmarks.json",
- "followers.json",
- "following.json"
+ ~c"actor.json",
+ ~c"outbox.json",
+ ~c"likes.json",
+ ~c"bookmarks.json",
+ ~c"followers.json",
+ ~c"following.json"
]
@spec run(t()) :: {:ok, t()} | {:error, :failed}
@@ -201,7 +200,7 @@ defmodule Pleroma.User.Backup do
{_, :ok} <- {:followers, followers(backup.tempdir, backup.user)},
{_, :ok} <- {:following, following(backup.tempdir, backup.user)},
{_, {:ok, _zip_path}} <-
- {:zip, SafeZip.zip(tempfile, @files, backup.tempdir)},
+ {:zip, :zip.create(to_charlist(tempfile), @files, cwd: to_charlist(backup.tempdir))},
{_, {:ok, %File.Stat{size: zip_size}}} <- {:filestat, File.stat(tempfile)},
{:ok, updated_backup} <- update_record(backup, %{file_size: zip_size}) do
{:ok, updated_backup}
@@ -247,13 +246,7 @@ defmodule Pleroma.User.Backup do
defp actor(dir, user) do
with {:ok, json} <-
UserView.render("user.json", %{user: user})
- |> Map.merge(%{
- "bookmarks" => "bookmarks.json",
- "likes" => "likes.json",
- "outbox" => "outbox.json",
- "followers" => "followers.json",
- "following" => "following.json"
- })
+ |> Map.merge(%{"likes" => "likes.json", "bookmarks" => "bookmarks.json"})
|> Jason.encode() do
File.write(Path.join(dir, "actor.json"), json)
end
diff --git a/lib/pleroma/user/hashtag_follow.ex b/lib/pleroma/user/hashtag_follow.ex
deleted file mode 100644
index 3e28b130b..000000000
--- a/lib/pleroma/user/hashtag_follow.ex
+++ /dev/null
@@ -1,55 +0,0 @@
-defmodule Pleroma.User.HashtagFollow do
- use Ecto.Schema
- import Ecto.Query
- import Ecto.Changeset
-
- alias Pleroma.Hashtag
- alias Pleroma.Repo
- alias Pleroma.User
-
- schema "user_follows_hashtag" do
- belongs_to(:user, User, type: FlakeId.Ecto.CompatType)
- belongs_to(:hashtag, Hashtag)
- end
-
- def changeset(%__MODULE__{} = user_hashtag_follow, attrs) do
- user_hashtag_follow
- |> cast(attrs, [:user_id, :hashtag_id])
- |> unique_constraint(:hashtag_id,
- name: :user_hashtag_follows_user_id_hashtag_id_index,
- message: "already following"
- )
- |> validate_required([:user_id, :hashtag_id])
- end
-
- def new(%User{} = user, %Hashtag{} = hashtag) do
- %__MODULE__{}
- |> changeset(%{user_id: user.id, hashtag_id: hashtag.id})
- |> Repo.insert(on_conflict: :nothing)
- end
-
- def delete(%User{} = user, %Hashtag{} = hashtag) do
- with %__MODULE__{} = user_hashtag_follow <- get(user, hashtag) do
- Repo.delete(user_hashtag_follow)
- else
- _ -> {:ok, nil}
- end
- end
-
- def get(%User{} = user, %Hashtag{} = hashtag) do
- from(hf in __MODULE__)
- |> where([hf], hf.user_id == ^user.id and hf.hashtag_id == ^hashtag.id)
- |> Repo.one()
- end
-
- def get_by_user(%User{} = user) do
- user
- |> followed_hashtags_query()
- |> Repo.all()
- end
-
- def followed_hashtags_query(%User{} = user) do
- Ecto.assoc(user, :followed_hashtags)
- |> Ecto.Query.order_by([h], desc: h.id)
- end
-end
diff --git a/lib/pleroma/user_relationship.ex b/lib/pleroma/user_relationship.ex
index 5b48d321a..82fcc1cdd 100644
--- a/lib/pleroma/user_relationship.ex
+++ b/lib/pleroma/user_relationship.ex
@@ -55,13 +55,9 @@ defmodule Pleroma.UserRelationship do
def user_relationship_mappings, do: Pleroma.UserRelationship.Type.__enum_map__()
- def datetime_impl do
- Application.get_env(:pleroma, :datetime_impl, Pleroma.DateTime.Impl)
- end
-
def changeset(%UserRelationship{} = user_relationship, params \\ %{}) do
user_relationship
- |> cast(params, [:relationship_type, :source_id, :target_id, :expires_at, :inserted_at])
+ |> cast(params, [:relationship_type, :source_id, :target_id, :expires_at])
|> validate_required([:relationship_type, :source_id, :target_id])
|> unique_constraint(:relationship_type,
name: :user_relationships_source_id_relationship_type_target_id_index
@@ -69,7 +65,6 @@ defmodule Pleroma.UserRelationship do
|> validate_not_self_relationship()
end
- @spec exists?(any(), Pleroma.User.t(), Pleroma.User.t()) :: boolean()
def exists?(relationship_type, %User{} = source, %User{} = target) do
UserRelationship
|> where(relationship_type: ^relationship_type, source_id: ^source.id, target_id: ^target.id)
@@ -95,8 +90,7 @@ defmodule Pleroma.UserRelationship do
relationship_type: relationship_type,
source_id: source.id,
target_id: target.id,
- expires_at: expires_at,
- inserted_at: datetime_impl().utc_now()
+ expires_at: expires_at
})
|> Repo.insert(
on_conflict: {:replace_all_except, [:id, :inserted_at]},
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 62c7a7b31..df8795fe4 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -924,31 +924,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
)
end
- # Essentially, either look for activities addressed to `recipients`, _OR_ ones
- # that reference a hashtag that the user follows
- # Firstly, two fallbacks in case there's no hashtag constraint, or the user doesn't
- # follow any
- defp restrict_recipients_or_hashtags(query, recipients, user, nil) do
- restrict_recipients(query, recipients, user)
- end
-
- defp restrict_recipients_or_hashtags(query, recipients, user, []) do
- restrict_recipients(query, recipients, user)
- end
-
- defp restrict_recipients_or_hashtags(query, recipients, _user, hashtag_ids) do
- from([activity, object] in query)
- |> join(:left, [activity, object], hto in "hashtags_objects",
- on: hto.object_id == object.id,
- as: :hto
- )
- |> where(
- [activity, object, hto: hto],
- (hto.hashtag_id in ^hashtag_ids and ^Constants.as_public() in activity.recipients) or
- fragment("? && ?", ^recipients, activity.recipients)
- )
- end
-
defp restrict_local(query, %{local_only: true}) do
from(activity in query, where: activity.local == true)
end
@@ -1439,7 +1414,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|> maybe_preload_report_notes(opts)
|> maybe_set_thread_muted_field(opts)
|> maybe_order(opts)
- |> restrict_recipients_or_hashtags(recipients, opts[:user], opts[:followed_hashtags])
+ |> restrict_recipients(recipients, opts[:user])
|> restrict_replies(opts)
|> restrict_since(opts)
|> restrict_local(opts)
diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
index 7ac0bbab4..a08eda5f4 100644
--- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
@@ -482,7 +482,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|> put_status(:forbidden)
|> json(message)
- {:error, message} when is_binary(message) ->
+ {:error, message} ->
conn
|> put_status(:bad_request)
|> json(message)
diff --git a/lib/pleroma/web/activity_pub/mrf/dnsrbl_policy.ex b/lib/pleroma/web/activity_pub/mrf/dnsrbl_policy.ex
new file mode 100644
index 000000000..ca41c464c
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/mrf/dnsrbl_policy.ex
@@ -0,0 +1,146 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2024 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.DNSRBLPolicy do
+ @moduledoc """
+ Dynamic activity filtering based on an RBL database
+
+ This MRF makes queries to a custom DNS server which will
+ respond with values indicating the classification of the domain
+ the activity originated from. This method has been widely used
+ in the email anti-spam industry for very fast reputation checks.
+
+ e.g., if the DNS response is 127.0.0.1 or empty, the domain is OK
+ Other values such as 127.0.0.2 may be used for specific classifications.
+
+ Information for why the host is blocked can be stored in a corresponding TXT record.
+
+ This method is fail-open so if the queries fail the activites are accepted.
+
+ An example of software meant for this purpsoe is rbldnsd which can be found
+ at http://www.corpit.ru/mjt/rbldnsd.html or mirrored at
+ https://git.pleroma.social/feld/rbldnsd
+
+ It is highly recommended that you run your own copy of rbldnsd and use an
+ external mechanism to sync/share the contents of the zone file. This is
+ important to keep the latency on the queries as low as possible and prevent
+ your DNS server from being attacked so it fails and content is permitted.
+ """
+
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
+
+ alias Pleroma.Config
+
+ require Logger
+
+ @query_retries 1
+ @query_timeout 500
+
+ @impl true
+ def filter(%{"actor" => actor} = activity) do
+ actor_info = URI.parse(actor)
+
+ with {:ok, activity} <- check_rbl(actor_info, activity) do
+ {:ok, activity}
+ else
+ _ -> {:reject, "[DNSRBLPolicy]"}
+ end
+ end
+
+ @impl true
+ def filter(activity), do: {:ok, activity}
+
+ @impl true
+ def describe do
+ mrf_dnsrbl =
+ Config.get(:mrf_dnsrbl)
+ |> Enum.into(%{})
+
+ {:ok, %{mrf_dnsrbl: mrf_dnsrbl}}
+ end
+
+ @impl true
+ def config_description do
+ %{
+ key: :mrf_dnsrbl,
+ related_policy: "Pleroma.Web.ActivityPub.MRF.DNSRBLPolicy",
+ label: "MRF DNSRBL",
+ description: "DNS RealTime Blackhole Policy",
+ children: [
+ %{
+ key: :nameserver,
+ type: {:string},
+ description: "DNSRBL Nameserver to Query (IP or hostame)",
+ suggestions: ["127.0.0.1"]
+ },
+ %{
+ key: :port,
+ type: {:string},
+ description: "Nameserver port",
+ suggestions: ["53"]
+ },
+ %{
+ key: :zone,
+ type: {:string},
+ description: "Root zone for querying",
+ suggestions: ["bl.pleroma.com"]
+ }
+ ]
+ }
+ end
+
+ defp check_rbl(%{host: actor_host}, activity) do
+ with false <- match?(^actor_host, Pleroma.Web.Endpoint.host()),
+ zone when not is_nil(zone) <- Keyword.get(Config.get([:mrf_dnsrbl]), :zone) do
+ query =
+ Enum.join([actor_host, zone], ".")
+ |> String.to_charlist()
+
+ rbl_response = rblquery(query)
+
+ if Enum.empty?(rbl_response) do
+ {:ok, activity}
+ else
+ Task.start(fn ->
+ reason =
+ case rblquery(query, :txt) do
+ [[result]] -> result
+ _ -> "undefined"
+ end
+
+ Logger.warning(
+ "DNSRBL Rejected activity from #{actor_host} for reason: #{inspect(reason)}"
+ )
+ end)
+
+ :error
+ end
+ else
+ _ -> {:ok, activity}
+ end
+ end
+
+ defp get_rblhost_ip(rblhost) do
+ case rblhost |> String.to_charlist() |> :inet_parse.address() do
+ {:ok, _} -> rblhost |> String.to_charlist() |> :inet_parse.address()
+ _ -> {:ok, rblhost |> String.to_charlist() |> :inet_res.lookup(:in, :a) |> Enum.random()}
+ end
+ end
+
+ defp rblquery(query, type \\ :a) do
+ config = Config.get([:mrf_dnsrbl])
+
+ case get_rblhost_ip(config[:nameserver]) do
+ {:ok, rblnsip} ->
+ :inet_res.lookup(query, :in, type,
+ nameservers: [{rblnsip, config[:port]}],
+ timeout: @query_timeout,
+ retry: @query_retries
+ )
+
+ _ ->
+ []
+ end
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/mrf/fo_direct_reply.ex b/lib/pleroma/web/activity_pub/mrf/fo_direct_reply.ex
new file mode 100644
index 000000000..2cf22745a
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/mrf/fo_direct_reply.ex
@@ -0,0 +1,53 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2024 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.FODirectReply do
+ @moduledoc """
+ FODirectReply alters the scope of replies to activities which are Followers Only to be Direct. The purpose of this policy is to prevent broken threads for followers of the reply author because their response was to a user that they are not also following.
+ """
+
+ alias Pleroma.Object
+ alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.Visibility
+
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
+
+ @impl true
+ def filter(
+ %{
+ "type" => "Create",
+ "to" => to,
+ "object" => %{
+ "actor" => actor,
+ "type" => "Note",
+ "inReplyTo" => in_reply_to
+ }
+ } = activity
+ ) do
+ with true <- is_binary(in_reply_to),
+ %User{follower_address: followers_collection, local: true} <- User.get_by_ap_id(actor),
+ %Object{} = in_reply_to_object <- Object.get_by_ap_id(in_reply_to),
+ "private" <- Visibility.get_visibility(in_reply_to_object) do
+ direct_to = to -- [followers_collection]
+
+ updated_activity =
+ activity
+ |> Map.put("cc", [])
+ |> Map.put("to", direct_to)
+ |> Map.put("directMessage", true)
+ |> put_in(["object", "cc"], [])
+ |> put_in(["object", "to"], direct_to)
+
+ {:ok, updated_activity}
+ else
+ _ -> {:ok, activity}
+ end
+ end
+
+ @impl true
+ def filter(activity), do: {:ok, activity}
+
+ @impl true
+ def describe, do: {:ok, %{}}
+end
diff --git a/lib/pleroma/web/activity_pub/mrf/quiet_reply.ex b/lib/pleroma/web/activity_pub/mrf/quiet_reply.ex
new file mode 100644
index 000000000..b07dc3b56
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/mrf/quiet_reply.ex
@@ -0,0 +1,60 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2023 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.QuietReply do
+ @moduledoc """
+ QuietReply alters the scope of activities from local users when replying by enforcing them to be "Unlisted" or "Quiet Public". This delivers the activity to all the expected recipients and instances, but it will not be published in the Federated / The Whole Known Network timelines. It will still be published to the Home timelines of the user's followers and visible to anyone who opens the thread.
+ """
+ require Pleroma.Constants
+
+ alias Pleroma.User
+
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
+
+ @impl true
+ def history_awareness, do: :auto
+
+ @impl true
+ def filter(
+ %{
+ "type" => "Create",
+ "to" => to,
+ "cc" => cc,
+ "object" => %{
+ "actor" => actor,
+ "type" => "Note",
+ "inReplyTo" => in_reply_to
+ }
+ } = activity
+ ) do
+ with true <- is_binary(in_reply_to),
+ false <- match?([], cc),
+ %User{follower_address: followers_collection, local: true} <-
+ User.get_by_ap_id(actor) do
+ updated_to =
+ to
+ |> Kernel.++([followers_collection])
+ |> Kernel.--([Pleroma.Constants.as_public()])
+
+ updated_cc = [Pleroma.Constants.as_public()]
+
+ updated_activity =
+ activity
+ |> Map.put("to", updated_to)
+ |> Map.put("cc", updated_cc)
+ |> put_in(["object", "to"], updated_to)
+ |> put_in(["object", "cc"], updated_cc)
+
+ {:ok, updated_activity}
+ else
+ _ -> {:ok, activity}
+ end
+ end
+
+ @impl true
+ def filter(activity), do: {:ok, activity}
+
+ @impl true
+ def describe, do: {:ok, %{}}
+end
diff --git a/lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex b/lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex
index 49d17d8b9..6edfb124e 100644
--- a/lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex
@@ -20,19 +20,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy do
String.match?(shortcode, pattern)
end
- defp reject_emoji?({shortcode, _url}, installed_emoji) do
- valid_shortcode? = String.match?(shortcode, ~r/^[a-zA-Z0-9_-]+$/)
-
- rejected_shortcode? =
- [:mrf_steal_emoji, :rejected_shortcodes]
- |> Config.get([])
- |> Enum.any?(fn pattern -> shortcode_matches?(shortcode, pattern) end)
-
- emoji_installed? = Enum.member?(installed_emoji, shortcode)
-
- !valid_shortcode? or rejected_shortcode? or emoji_installed?
- end
-
defp steal_emoji({shortcode, url}, emoji_dir_path) do
url = Pleroma.Web.MediaProxy.url(url)
@@ -91,7 +78,16 @@ defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy do
new_emojis =
foreign_emojis
- |> Enum.reject(&reject_emoji?(&1, installed_emoji))
+ |> Enum.reject(fn {shortcode, _url} -> shortcode in installed_emoji end)
+ |> Enum.reject(fn {shortcode, _url} -> String.contains?(shortcode, ["/", "\\"]) end)
+ |> Enum.filter(fn {shortcode, _url} ->
+ reject_emoji? =
+ [:mrf_steal_emoji, :rejected_shortcodes]
+ |> Config.get([])
+ |> Enum.find(false, fn pattern -> shortcode_matches?(shortcode, pattern) end)
+
+ !reject_emoji?
+ end)
|> Enum.map(&steal_emoji(&1, emoji_dir_path))
|> Enum.filter(& &1)
diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
index ee12f3ebf..35774d410 100644
--- a/lib/pleroma/web/activity_pub/object_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validator.ex
@@ -26,7 +26,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
alias Pleroma.Web.ActivityPub.ObjectValidators.AudioImageVideoValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.BlockValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.ChatMessageValidator
- alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
alias Pleroma.Web.ActivityPub.ObjectValidators.CreateChatMessageValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator
@@ -116,10 +115,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
meta
)
when objtype in ~w[Question Answer Audio Video Image Event Article Note Page] do
- with {:ok, object_data} <-
- object
- |> CommonFixes.maybe_add_language_from_activity(create_activity)
- |> cast_and_apply_and_stringify_with_history(),
+ with {:ok, object_data} <- cast_and_apply_and_stringify_with_history(object),
meta = Keyword.put(meta, :object_data, object_data),
{:ok, create_activity} <-
create_activity
@@ -169,15 +165,11 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
)
when objtype in ~w[Question Answer Audio Video Event Article Note Page] do
with {_, false} <- {:local, Access.get(meta, :local, false)},
- {_, {:ok, object_data, _}} <-
- {:object_validation,
- object
- |> CommonFixes.maybe_add_language_from_activity(update_activity)
- |> validate(meta)},
+ {_, {:ok, object_data, _}} <- {:object_validation, validate(object, meta)},
meta = Keyword.put(meta, :object_data, object_data),
{:ok, update_activity} <-
update_activity
- |> UpdateValidator.cast_and_validate(meta)
+ |> UpdateValidator.cast_and_validate()
|> Ecto.Changeset.apply_action(:insert) do
update_activity = stringify_keys(update_activity)
{:ok, update_activity, meta}
@@ -185,7 +177,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
{:local, _} ->
with {:ok, object} <-
update_activity
- |> UpdateValidator.cast_and_validate(meta)
+ |> UpdateValidator.cast_and_validate()
|> Ecto.Changeset.apply_action(:insert) do
object = stringify_keys(object)
{:ok, object, meta}
@@ -215,16 +207,9 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
"Answer" -> AnswerValidator
end
- cast_func =
- if type == "Update" do
- fn o -> validator.cast_and_validate(o, meta) end
- else
- fn o -> validator.cast_and_validate(o) end
- end
-
with {:ok, object} <-
object
- |> cast_func.()
+ |> validator.cast_and_validate()
|> Ecto.Changeset.apply_action(:insert) do
object = stringify_keys(object)
{:ok, object, meta}
diff --git a/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex b/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex
index 81ab354fe..1b5b2e8fb 100644
--- a/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex
@@ -30,7 +30,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do
def cast_and_apply(data) do
data
- |> cast_data()
+ |> cast_data
|> apply_action(:insert)
end
@@ -85,11 +85,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do
|> fix_replies()
|> fix_attachments()
|> CommonFixes.fix_quote_url()
- |> CommonFixes.fix_likes()
|> Transmogrifier.fix_emoji()
|> Transmogrifier.fix_content_map()
- |> CommonFixes.maybe_add_language()
- |> CommonFixes.maybe_add_content_map()
end
def changeset(struct, data) do
diff --git a/lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex b/lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex
index 034c6f33f..65ac6bb93 100644
--- a/lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex
@@ -100,7 +100,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioImageVideoValidator do
|> CommonFixes.fix_actor()
|> CommonFixes.fix_object_defaults()
|> CommonFixes.fix_quote_url()
- |> CommonFixes.fix_likes()
|> Transmogrifier.fix_emoji()
|> fix_url()
|> fix_content()
diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex
index 22cf0cc05..1a5d02601 100644
--- a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex
@@ -31,7 +31,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFields do
defmacro object_fields do
quote bind_quoted: binding() do
field(:content, :string)
- field(:contentMap, ObjectValidators.ContentLanguageMap)
field(:published, ObjectValidators.DateTime)
field(:updated, ObjectValidators.DateTime)
@@ -59,7 +58,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFields do
field(:like_count, :integer, default: 0)
field(:announcement_count, :integer, default: 0)
field(:quotes_count, :integer, default: 0)
- field(:language, ObjectValidators.LanguageCode)
field(:inReplyTo, ObjectValidators.ObjectID)
field(:quoteUrl, ObjectValidators.ObjectID)
field(:url, ObjectValidators.BareUri)
diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex
index 87d3e0c8f..4699029d4 100644
--- a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex
@@ -11,11 +11,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.Utils
- import Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode,
- only: [good_locale_code?: 1]
-
- import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1]
-
require Pleroma.Constants
def cast_and_filter_recipients(message, field, follower_collection, field_fallback \\ []) do
@@ -119,13 +114,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
def fix_quote_url(data), do: data
- # On Mastodon, `"likes"` attribute includes an inlined `Collection` with `totalItems`,
- # not a list of users.
- # https://github.com/mastodon/mastodon/pull/32007
- def fix_likes(%{"likes" => %{}} = data), do: Map.drop(data, ["likes"])
-
- def fix_likes(data), do: data
-
# https://codeberg.org/fediverse/fep/src/branch/main/fep/e232/fep-e232.md
def object_link_tag?(%{
"type" => "Link",
@@ -137,60 +125,4 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
end
def object_link_tag?(_), do: false
-
- def maybe_add_language_from_activity(object, activity) do
- language = get_language_from_context(activity)
-
- if language do
- Map.put(object, "language", language)
- else
- object
- end
- end
-
- def maybe_add_language(object) do
- language =
- [
- get_language_from_context(object),
- get_language_from_content_map(object)
- ]
- |> Enum.find(&good_locale_code?(&1))
-
- if language do
- Map.put(object, "language", language)
- else
- object
- end
- end
-
- defp get_language_from_context(%{"@context" => context}) when is_list(context) do
- case context
- |> Enum.find(fn
- %{"@language" => language} -> language != "und"
- _ -> nil
- end) do
- %{"@language" => language} -> language
- _ -> nil
- end
- end
-
- defp get_language_from_context(_), do: nil
-
- defp get_language_from_content_map(%{"contentMap" => content_map, "content" => source_content}) do
- content_groups = Map.to_list(content_map)
-
- case Enum.find(content_groups, fn {_, content} -> content == source_content end) do
- {language, _} -> language
- _ -> nil
- end
- end
-
- defp get_language_from_content_map(_), do: nil
-
- def maybe_add_content_map(%{"language" => language, "content" => content} = object)
- when not_empty_string(language) do
- Map.put(object, "contentMap", Map.put(%{}, language, content))
- end
-
- def maybe_add_content_map(object), do: object
end
diff --git a/lib/pleroma/web/activity_pub/object_validators/event_validator.ex b/lib/pleroma/web/activity_pub/object_validators/event_validator.ex
index ea14d6aca..ab204f69a 100644
--- a/lib/pleroma/web/activity_pub/object_validators/event_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/event_validator.ex
@@ -28,7 +28,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EventValidator do
def cast_and_apply(data) do
data
- |> cast_data()
+ |> cast_data
|> apply_action(:insert)
end
@@ -38,7 +38,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EventValidator do
|> validate_data()
end
- @spec cast_data(map()) :: map()
def cast_data(data) do
%__MODULE__{}
|> changeset(data)
@@ -48,10 +47,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EventValidator do
data
|> CommonFixes.fix_actor()
|> CommonFixes.fix_object_defaults()
- |> CommonFixes.fix_likes()
|> Transmogrifier.fix_emoji()
- |> CommonFixes.maybe_add_language()
- |> CommonFixes.maybe_add_content_map()
end
def changeset(struct, data) do
diff --git a/lib/pleroma/web/activity_pub/object_validators/question_validator.ex b/lib/pleroma/web/activity_pub/object_validators/question_validator.ex
index 21940f4f1..7f9d4d648 100644
--- a/lib/pleroma/web/activity_pub/object_validators/question_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/question_validator.ex
@@ -64,7 +64,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator do
|> CommonFixes.fix_actor()
|> CommonFixes.fix_object_defaults()
|> CommonFixes.fix_quote_url()
- |> CommonFixes.fix_likes()
|> Transmogrifier.fix_emoji()
|> fix_closed()
end
diff --git a/lib/pleroma/web/activity_pub/object_validators/update_validator.ex b/lib/pleroma/web/activity_pub/object_validators/update_validator.ex
index aab90235f..1e940a400 100644
--- a/lib/pleroma/web/activity_pub/object_validators/update_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/update_validator.ex
@@ -6,8 +6,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.UpdateValidator do
use Ecto.Schema
alias Pleroma.EctoType.ActivityPub.ObjectValidators
- alias Pleroma.Object
- alias Pleroma.User
import Ecto.Changeset
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
@@ -33,50 +31,23 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.UpdateValidator do
|> cast(data, __schema__(:fields))
end
- defp validate_data(cng, meta) do
+ defp validate_data(cng) do
cng
|> validate_required([:id, :type, :actor, :to, :cc, :object])
|> validate_inclusion(:type, ["Update"])
|> validate_actor_presence()
- |> validate_updating_rights(meta)
+ |> validate_updating_rights()
end
- def cast_and_validate(data, meta \\ []) do
+ def cast_and_validate(data) do
data
|> cast_data
- |> validate_data(meta)
+ |> validate_data
end
- def validate_updating_rights(cng, meta) do
- if meta[:local] do
- validate_updating_rights_local(cng)
- else
- validate_updating_rights_remote(cng)
- end
- end
-
- # For local Updates, verify the actor can edit the object
- def validate_updating_rights_local(cng) do
- actor = get_field(cng, :actor)
- updated_object = get_field(cng, :object)
-
- if {:ok, actor} == ObjectValidators.ObjectID.cast(updated_object) do
- cng
- else
- with %User{} = user <- User.get_cached_by_ap_id(actor),
- {_, %Object{} = orig_object} <- {:object, Object.normalize(updated_object)},
- :ok <- Object.authorize_access(orig_object, user) do
- cng
- else
- _e ->
- cng
- |> add_error(:object, "Can't be updated by this actor")
- end
- end
- end
-
- # For remote Updates, verify the host is the same.
- def validate_updating_rights_remote(cng) do
+ # For now we only support updating users, and here the rule is easy:
+ # object id == actor id
+ def validate_updating_rights(cng) do
with actor = get_field(cng, :actor),
object = get_field(cng, :object),
{:ok, object_id} <- ObjectValidators.ObjectID.cast(object),
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 1e6ee7dc8..2f8a7f8f2 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -16,14 +16,12 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.ObjectValidator
- alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
alias Pleroma.Web.ActivityPub.Pipeline
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.Federator
import Ecto.Query
- import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1]
require Pleroma.Constants
@@ -43,38 +41,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> fix_content_map()
|> fix_addressing()
|> fix_summary()
- |> fix_history(&fix_object/1)
- end
-
- defp maybe_fix_object(%{"attributedTo" => _} = object), do: fix_object(object)
- defp maybe_fix_object(object), do: object
-
- defp fix_history(%{"formerRepresentations" => %{"orderedItems" => list}} = obj, fix_fun)
- when is_list(list) do
- update_in(obj["formerRepresentations"]["orderedItems"], fn h -> Enum.map(h, fix_fun) end)
- end
-
- defp fix_history(obj, _), do: obj
-
- defp fix_recursive(obj, fun) do
- # unlike Erlang, Elixir does not support recursive inline functions
- # which would allow us to avoid reconstructing this on every recursion
- rec_fun = fn
- obj when is_map(obj) -> fix_recursive(obj, fun)
- # there may be simple AP IDs in history (or object field)
- obj -> obj
- end
-
- obj
- |> fun.()
- |> fix_history(rec_fun)
- |> then(fn
- %{"object" => object} = doc when is_map(object) ->
- update_in(doc["object"], rec_fun)
-
- apdoc ->
- apdoc
- end)
end
def fix_summary(%{"summary" => nil} = object) do
@@ -200,7 +166,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def fix_quote_url_and_maybe_fetch(object, options \\ []) do
quote_url =
- case CommonFixes.fix_quote_url(object) do
+ case Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes.fix_quote_url(object) do
%{"quoteUrl" => quote_url} -> quote_url
_ -> nil
end
@@ -370,9 +336,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def fix_tag(object), do: object
- # prefer content over contentMap
- def fix_content_map(%{"content" => content} = object) when not_empty_string(content), do: object
-
# content map usually only has one language so this will do for now.
def fix_content_map(%{"contentMap" => content_map} = object) do
content_groups = Map.to_list(content_map)
@@ -407,18 +370,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end)
end
- def handle_incoming(data, options \\ []) do
- data
- |> fix_recursive(&strip_internal_fields/1)
- |> handle_incoming_normalized(options)
- end
+ def handle_incoming(data, options \\ [])
# Flag objects are placed ahead of the ID check because Mastodon 2.8 and earlier send them
# with nil ID.
- defp handle_incoming_normalized(
- %{"type" => "Flag", "object" => objects, "actor" => actor} = data,
- _options
- ) do
+ def handle_incoming(%{"type" => "Flag", "object" => objects, "actor" => actor} = data, _options) do
with context <- data["context"] || Utils.generate_context_id(),
content <- data["content"] || "",
%User{} = actor <- User.get_cached_by_ap_id(actor),
@@ -439,17 +395,16 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
# disallow objects with bogus IDs
- defp handle_incoming_normalized(%{"id" => nil}, _options), do: :error
- defp handle_incoming_normalized(%{"id" => ""}, _options), do: :error
+ def handle_incoming(%{"id" => nil}, _options), do: :error
+ def handle_incoming(%{"id" => ""}, _options), do: :error
# length of https:// = 8, should validate better, but good enough for now.
- defp handle_incoming_normalized(%{"id" => id}, _options)
- when is_binary(id) and byte_size(id) < 8,
- do: :error
+ def handle_incoming(%{"id" => id}, _options) when is_binary(id) and byte_size(id) < 8,
+ do: :error
- defp handle_incoming_normalized(
- %{"type" => "Listen", "object" => %{"type" => "Audio"} = object} = data,
- options
- ) do
+ def handle_incoming(
+ %{"type" => "Listen", "object" => %{"type" => "Audio"} = object} = data,
+ options
+ ) do
actor = Containment.get_actor(data)
data =
@@ -491,25 +446,25 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
"star" => "⭐"
}
- # Rewrite misskey likes into EmojiReacts
- defp handle_incoming_normalized(
- %{
- "type" => "Like",
- "_misskey_reaction" => reaction
- } = data,
- options
- ) do
+ @doc "Rewrite misskey likes into EmojiReacts"
+ def handle_incoming(
+ %{
+ "type" => "Like",
+ "_misskey_reaction" => reaction
+ } = data,
+ options
+ ) do
data
|> Map.put("type", "EmojiReact")
|> Map.put("content", @misskey_reactions[reaction] || reaction)
- |> handle_incoming_normalized(options)
+ |> handle_incoming(options)
end
- defp handle_incoming_normalized(
- %{"type" => "Create", "object" => %{"type" => objtype, "id" => obj_id}} = data,
- options
- )
- when objtype in ~w{Question Answer ChatMessage Audio Video Event Article Note Page Image} do
+ def handle_incoming(
+ %{"type" => "Create", "object" => %{"type" => objtype, "id" => obj_id}} = data,
+ options
+ )
+ when objtype in ~w{Question Answer ChatMessage Audio Video Event Article Note Page Image} do
fetch_options = Keyword.put(options, :depth, (options[:depth] || 0) + 1)
object =
@@ -532,8 +487,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
end
- defp handle_incoming_normalized(%{"type" => type} = data, _options)
- when type in ~w{Like EmojiReact Announce Add Remove} do
+ def handle_incoming(%{"type" => type} = data, _options)
+ when type in ~w{Like EmojiReact Announce Add Remove} do
with :ok <- ObjectValidator.fetch_actor_and_object(data),
{:ok, activity, _meta} <-
Pipeline.common_pipeline(data, local: false) do
@@ -543,14 +498,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
end
- defp handle_incoming_normalized(
- %{"type" => type} = data,
- _options
- )
- when type in ~w{Update Block Follow Accept Reject} do
- fixed_obj = maybe_fix_object(data["object"])
- data = if fixed_obj != nil, do: %{data | "object" => fixed_obj}, else: data
-
+ def handle_incoming(
+ %{"type" => type} = data,
+ _options
+ )
+ when type in ~w{Update Block Follow Accept Reject} do
with {:ok, %User{}} <- ObjectValidator.fetch_actor(data),
{:ok, activity, _} <-
Pipeline.common_pipeline(data, local: false) do
@@ -558,10 +510,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
end
- defp handle_incoming_normalized(
- %{"type" => "Delete"} = data,
- _options
- ) do
+ def handle_incoming(
+ %{"type" => "Delete"} = data,
+ _options
+ ) do
with {:ok, activity, _} <-
Pipeline.common_pipeline(data, local: false) do
{:ok, activity}
@@ -584,15 +536,15 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
end
- defp handle_incoming_normalized(
- %{
- "type" => "Undo",
- "object" => %{"type" => "Follow", "object" => followed},
- "actor" => follower,
- "id" => id
- } = _data,
- _options
- ) do
+ def handle_incoming(
+ %{
+ "type" => "Undo",
+ "object" => %{"type" => "Follow", "object" => followed},
+ "actor" => follower,
+ "id" => id
+ } = _data,
+ _options
+ ) do
with %User{local: true} = followed <- User.get_cached_by_ap_id(followed),
{:ok, %User{} = follower} <- User.get_or_fetch_by_ap_id(follower),
{:ok, activity} <- ActivityPub.unfollow(follower, followed, id, false) do
@@ -603,46 +555,46 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
end
- defp handle_incoming_normalized(
- %{
- "type" => "Undo",
- "object" => %{"type" => type}
- } = data,
- _options
- )
- when type in ["Like", "EmojiReact", "Announce", "Block"] do
+ def handle_incoming(
+ %{
+ "type" => "Undo",
+ "object" => %{"type" => type}
+ } = data,
+ _options
+ )
+ when type in ["Like", "EmojiReact", "Announce", "Block"] do
with {:ok, activity, _} <- Pipeline.common_pipeline(data, local: false) do
{:ok, activity}
end
end
# For Undos that don't have the complete object attached, try to find it in our database.
- defp handle_incoming_normalized(
- %{
- "type" => "Undo",
- "object" => object
- } = activity,
- options
- )
- when is_binary(object) do
+ def handle_incoming(
+ %{
+ "type" => "Undo",
+ "object" => object
+ } = activity,
+ options
+ )
+ when is_binary(object) do
with %Activity{data: data} <- Activity.get_by_ap_id(object) do
activity
|> Map.put("object", data)
- |> handle_incoming_normalized(options)
+ |> handle_incoming(options)
else
_e -> :error
end
end
- defp handle_incoming_normalized(
- %{
- "type" => "Move",
- "actor" => origin_actor,
- "object" => origin_actor,
- "target" => target_actor
- },
- _options
- ) do
+ def handle_incoming(
+ %{
+ "type" => "Move",
+ "actor" => origin_actor,
+ "object" => origin_actor,
+ "target" => target_actor
+ },
+ _options
+ ) do
with %User{} = origin_user <- User.get_cached_by_ap_id(origin_actor),
{:ok, %User{} = target_user} <- User.get_or_fetch_by_ap_id(target_actor),
true <- origin_actor in target_user.also_known_as do
@@ -652,7 +604,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
end
- defp handle_incoming_normalized(_, _), do: :error
+ def handle_incoming(_, _), do: :error
@spec get_obj_helper(String.t(), Keyword.t()) :: {:ok, Object.t()} | nil
def get_obj_helper(id, options \\ []) do
@@ -764,7 +716,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> set_reply_to_uri
|> set_quote_url
|> set_replies
- |> CommonFixes.maybe_add_content_map()
|> strip_internal_fields
|> strip_internal_tags
|> set_type
@@ -799,11 +750,12 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
object_id
|> Object.normalize(fetch: false)
|> Map.get(:data)
+ |> prepare_object
data =
data
- |> Map.put("object", prepare_object(object))
- |> Map.merge(Utils.make_json_ld_header(object))
+ |> Map.put("object", object)
+ |> Map.merge(Utils.make_json_ld_header())
|> Map.delete("bcc")
{:ok, data}
@@ -811,10 +763,14 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def prepare_outgoing(%{"type" => "Update", "object" => %{"type" => objtype} = object} = data)
when objtype in Pleroma.Constants.updatable_object_types() do
+ object =
+ object
+ |> prepare_object
+
data =
data
- |> Map.put("object", prepare_object(object))
- |> Map.merge(Utils.make_json_ld_header(object))
+ |> Map.put("object", object)
+ |> Map.merge(Utils.make_json_ld_header())
|> Map.delete("bcc")
{:ok, data}
@@ -884,7 +840,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
data
|> strip_internal_fields
|> maybe_fix_object_url
- |> Map.merge(Utils.make_json_ld_header(data))
+ |> Map.merge(Utils.make_json_ld_header())
{:ok, data}
end
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index f30c92abf..6c792804d 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -20,7 +20,6 @@ defmodule Pleroma.Web.ActivityPub.Utils do
alias Pleroma.Web.Router.Helpers
import Ecto.Query
- import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1]
require Logger
require Pleroma.Constants
@@ -110,24 +109,18 @@ defmodule Pleroma.Web.ActivityPub.Utils do
end
end
- def make_json_ld_header(data \\ %{}) do
+ def make_json_ld_header do
%{
"@context" => [
"https://www.w3.org/ns/activitystreams",
"#{Endpoint.url()}/schemas/litepub-0.1.jsonld",
%{
- "@language" => get_language(data)
+ "@language" => "und"
}
]
}
end
- defp get_language(%{"language" => language}) when not_empty_string(language) do
- language
- end
-
- defp get_language(_), do: "und"
-
def make_date do
DateTime.utc_now() |> DateTime.to_iso8601()
end
diff --git a/lib/pleroma/web/activity_pub/views/object_view.ex b/lib/pleroma/web/activity_pub/views/object_view.ex
index 13b5b2542..63caa915c 100644
--- a/lib/pleroma/web/activity_pub/views/object_view.ex
+++ b/lib/pleroma/web/activity_pub/views/object_view.ex
@@ -9,7 +9,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectView do
alias Pleroma.Web.ActivityPub.Transmogrifier
def render("object.json", %{object: %Object{} = object}) do
- base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header(object.data)
+ base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header()
additional = Transmogrifier.prepare_object(object.data)
Map.merge(base, additional)
@@ -17,7 +17,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectView do
def render("object.json", %{object: %Activity{data: %{"type" => activity_type}} = activity})
when activity_type in ["Create", "Listen"] do
- base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header(activity.data)
+ base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header()
object = Object.normalize(activity, fetch: false)
additional =
@@ -28,7 +28,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectView do
end
def render("object.json", %{object: %Activity{} = activity}) do
- base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header(activity.data)
+ base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header()
object_id = Object.normalize(activity, id_only: true)
additional =
diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex
index 61975387b..cd485ed64 100644
--- a/lib/pleroma/web/activity_pub/views/user_view.ex
+++ b/lib/pleroma/web/activity_pub/views/user_view.ex
@@ -127,8 +127,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
"capabilities" => capabilities,
"alsoKnownAs" => user.also_known_as,
"vcard:bday" => birthday,
- "webfinger" => "acct:#{User.full_nickname(user)}",
- "published" => Pleroma.Web.CommonAPI.Utils.to_masto_date(user.inserted_at)
+ "webfinger" => "acct:#{User.full_nickname(user)}"
}
|> Map.merge(
maybe_make_image(
diff --git a/lib/pleroma/web/api_spec.ex b/lib/pleroma/web/api_spec.ex
index 63409870e..314782818 100644
--- a/lib/pleroma/web/api_spec.ex
+++ b/lib/pleroma/web/api_spec.ex
@@ -139,8 +139,7 @@ defmodule Pleroma.Web.ApiSpec do
"Search",
"Status actions",
"Media attachments",
- "Bookmark folders",
- "Tags"
+ "Bookmark folders"
]
},
%{
diff --git a/lib/pleroma/web/api_spec/operations/tag_operation.ex b/lib/pleroma/web/api_spec/operations/tag_operation.ex
deleted file mode 100644
index ce4f4ad5b..000000000
--- a/lib/pleroma/web/api_spec/operations/tag_operation.ex
+++ /dev/null
@@ -1,103 +0,0 @@
-defmodule Pleroma.Web.ApiSpec.TagOperation do
- alias OpenApiSpex.Operation
- alias OpenApiSpex.Schema
- alias Pleroma.Web.ApiSpec.Schemas.ApiError
- alias Pleroma.Web.ApiSpec.Schemas.Tag
-
- def open_api_operation(action) do
- operation = String.to_existing_atom("#{action}_operation")
- apply(__MODULE__, operation, [])
- end
-
- def show_operation do
- %Operation{
- tags: ["Tags"],
- summary: "Hashtag",
- description: "View a hashtag",
- security: [%{"oAuth" => ["read"]}],
- parameters: [id_param()],
- operationId: "TagController.show",
- responses: %{
- 200 => Operation.response("Hashtag", "application/json", Tag),
- 404 => Operation.response("Not Found", "application/json", ApiError)
- }
- }
- end
-
- def follow_operation do
- %Operation{
- tags: ["Tags"],
- summary: "Follow a hashtag",
- description: "Follow a hashtag",
- security: [%{"oAuth" => ["write:follows"]}],
- parameters: [id_param()],
- operationId: "TagController.follow",
- responses: %{
- 200 => Operation.response("Hashtag", "application/json", Tag),
- 404 => Operation.response("Not Found", "application/json", ApiError)
- }
- }
- end
-
- def unfollow_operation do
- %Operation{
- tags: ["Tags"],
- summary: "Unfollow a hashtag",
- description: "Unfollow a hashtag",
- security: [%{"oAuth" => ["write:follows"]}],
- parameters: [id_param()],
- operationId: "TagController.unfollow",
- responses: %{
- 200 => Operation.response("Hashtag", "application/json", Tag),
- 404 => Operation.response("Not Found", "application/json", ApiError)
- }
- }
- end
-
- def show_followed_operation do
- %Operation{
- tags: ["Tags"],
- summary: "Followed hashtags",
- description: "View a list of hashtags the currently authenticated user is following",
- parameters: pagination_params(),
- security: [%{"oAuth" => ["read:follows"]}],
- operationId: "TagController.show_followed",
- responses: %{
- 200 =>
- Operation.response("Hashtags", "application/json", %Schema{
- type: :array,
- items: Tag
- }),
- 403 => Operation.response("Forbidden", "application/json", ApiError),
- 404 => Operation.response("Not Found", "application/json", ApiError)
- }
- }
- end
-
- defp id_param do
- Operation.parameter(
- :id,
- :path,
- %Schema{type: :string},
- "Name of the hashtag"
- )
- end
-
- def pagination_params do
- [
- Operation.parameter(:max_id, :query, :integer, "Return items older than this ID"),
- Operation.parameter(
- :min_id,
- :query,
- :integer,
- "Return the oldest items newer than this ID"
- ),
- Operation.parameter(
- :limit,
- :query,
- %Schema{type: :integer, default: 20},
- "Maximum number of items to return. Will be ignored if it's more than 40"
- )
- ]
- end
-end
diff --git a/lib/pleroma/web/api_spec/schemas/tag.ex b/lib/pleroma/web/api_spec/schemas/tag.ex
index 05ff10cd3..66bf0ca71 100644
--- a/lib/pleroma/web/api_spec/schemas/tag.ex
+++ b/lib/pleroma/web/api_spec/schemas/tag.ex
@@ -17,22 +17,11 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Tag do
type: :string,
format: :uri,
description: "A link to the hashtag on the instance"
- },
- following: %Schema{
- type: :boolean,
- description: "Whether the authenticated user is following the hashtag"
- },
- history: %Schema{
- type: :array,
- items: %Schema{type: :string},
- description:
- "A list of historical uses of the hashtag (not implemented, for compatibility only)"
}
},
example: %{
name: "cofe",
- url: "https://lain.com/tag/cofe",
- following: false
+ url: "https://lain.com/tag/cofe"
}
})
end
diff --git a/lib/pleroma/web/common_api/activity_draft.ex b/lib/pleroma/web/common_api/activity_draft.ex
index 4220757df..8aa1e258d 100644
--- a/lib/pleroma/web/common_api/activity_draft.ex
+++ b/lib/pleroma/web/common_api/activity_draft.ex
@@ -11,9 +11,6 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.CommonAPI.Utils
- import Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode,
- only: [good_locale_code?: 1]
-
import Pleroma.Web.Gettext
import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1]
@@ -41,7 +38,6 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
cc: [],
context: nil,
sensitive: false,
- language: nil,
object: nil,
preview?: false,
changes: %{}
@@ -68,7 +64,6 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
|> content()
|> with_valid(&to_and_cc/1)
|> with_valid(&context/1)
- |> with_valid(&language/1)
|> sensitive()
|> with_valid(&object/1)
|> preview?()
@@ -254,16 +249,6 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
%__MODULE__{draft | sensitive: sensitive}
end
- defp language(draft) do
- language = draft.params[:language]
-
- if good_locale_code?(language) do
- %__MODULE__{draft | language: language}
- else
- draft
- end
- end
-
defp object(draft) do
emoji = Map.merge(Pleroma.Emoji.Formatter.get_emoji_map(draft.full_payload), draft.emoji)
@@ -303,7 +288,6 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
"mediaType" => Utils.get_content_type(draft.params[:content_type])
})
|> Map.put("generator", draft.params[:generator])
- |> Map.put("language", draft.language)
%__MODULE__{draft | object: object}
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/tag_controller.ex b/lib/pleroma/web/mastodon_api/controllers/tag_controller.ex
deleted file mode 100644
index 21c21e984..000000000
--- a/lib/pleroma/web/mastodon_api/controllers/tag_controller.ex
+++ /dev/null
@@ -1,77 +0,0 @@
-defmodule Pleroma.Web.MastodonAPI.TagController do
- @moduledoc "Hashtag routes for mastodon API"
- use Pleroma.Web, :controller
-
- alias Pleroma.Hashtag
- alias Pleroma.Pagination
- alias Pleroma.User
-
- import Pleroma.Web.ControllerHelper,
- only: [
- add_link_headers: 2
- ]
-
- plug(Pleroma.Web.ApiSpec.CastAndValidate)
-
- plug(
- Pleroma.Web.Plugs.OAuthScopesPlug,
- %{scopes: ["read"]} when action in [:show]
- )
-
- plug(
- Pleroma.Web.Plugs.OAuthScopesPlug,
- %{scopes: ["read:follows"]} when action in [:show_followed]
- )
-
- plug(
- Pleroma.Web.Plugs.OAuthScopesPlug,
- %{scopes: ["write:follows"]} when action in [:follow, :unfollow]
- )
-
- defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.TagOperation
-
- def show(conn, %{id: id}) do
- with %Hashtag{} = hashtag <- Hashtag.get_by_name(id) do
- render(conn, "show.json", tag: hashtag, for_user: conn.assigns.user)
- else
- _ -> conn |> render_error(:not_found, "Hashtag not found")
- end
- end
-
- def follow(conn, %{id: id}) do
- with %Hashtag{} = hashtag <- Hashtag.get_by_name(id),
- %User{} = user <- conn.assigns.user,
- {:ok, _} <-
- User.follow_hashtag(user, hashtag) do
- render(conn, "show.json", tag: hashtag, for_user: user)
- else
- _ -> render_error(conn, :not_found, "Hashtag not found")
- end
- end
-
- def unfollow(conn, %{id: id}) do
- with %Hashtag{} = hashtag <- Hashtag.get_by_name(id),
- %User{} = user <- conn.assigns.user,
- {:ok, _} <-
- User.unfollow_hashtag(user, hashtag) do
- render(conn, "show.json", tag: hashtag, for_user: user)
- else
- _ -> render_error(conn, :not_found, "Hashtag not found")
- end
- end
-
- def show_followed(conn, params) do
- with %{assigns: %{user: %User{} = user}} <- conn do
- params = Map.put(params, :id_type, :integer)
-
- hashtags =
- user
- |> User.HashtagFollow.followed_hashtags_query()
- |> Pagination.fetch_paginated(params)
-
- conn
- |> add_link_headers(hashtags)
- |> render("index.json", tags: hashtags, for_user: user)
- end
- end
-end
diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
index 5ee74a80e..293c61b41 100644
--- a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
@@ -40,11 +40,6 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
# GET /api/v1/timelines/home
def home(%{assigns: %{user: user}} = conn, params) do
- followed_hashtags =
- user
- |> User.followed_hashtags()
- |> Enum.map(& &1.id)
-
params =
params
|> Map.put(:type, ["Create", "Announce"])
@@ -54,7 +49,6 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|> Map.put(:announce_filtering_user, user)
|> Map.put(:user, user)
|> Map.put(:local_only, params[:local])
- |> Map.put(:followed_hashtags, followed_hashtags)
|> Map.delete(:local)
activities =
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index 10966edd6..3bf870c24 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -227,7 +227,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
mentions: mentions,
tags: reblogged[:tags] || [],
application: build_application(object.data["generator"]),
- language: get_language(object),
+ language: nil,
emojis: [],
pleroma: %{
local: activity.local,
@@ -445,7 +445,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
mentions: mentions,
tags: build_tags(tags),
application: build_application(object.data["generator"]),
- language: get_language(object),
+ language: nil,
emojis: build_emojis(object.data["emoji"]),
pleroma: %{
local: activity.local,
@@ -829,10 +829,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
Utils.get_content_type(nil)
end
- defp get_language(%{data: %{"language" => "und"}}), do: nil
-
- defp get_language(object), do: object.data["language"]
-
defp proxied_url(url, page_url_data) do
if is_binary(url) do
build_image_url(URI.parse(url), page_url_data) |> MediaProxy.url()
diff --git a/lib/pleroma/web/mastodon_api/views/tag_view.ex b/lib/pleroma/web/mastodon_api/views/tag_view.ex
deleted file mode 100644
index e24d423c2..000000000
--- a/lib/pleroma/web/mastodon_api/views/tag_view.ex
+++ /dev/null
@@ -1,25 +0,0 @@
-defmodule Pleroma.Web.MastodonAPI.TagView do
- use Pleroma.Web, :view
- alias Pleroma.User
- alias Pleroma.Web.Router.Helpers
-
- def render("index.json", %{tags: tags, for_user: user}) do
- safe_render_many(tags, __MODULE__, "show.json", %{for_user: user})
- end
-
- def render("show.json", %{tag: tag, for_user: user}) do
- following =
- with %User{} <- user do
- User.following_hashtag?(user, tag)
- else
- _ -> false
- end
-
- %{
- name: tag.name,
- url: Helpers.tag_feed_url(Pleroma.Web.Endpoint, :feed, tag.name),
- history: [],
- following: following
- }
- end
-end
diff --git a/lib/pleroma/web/media_proxy/media_proxy_controller.ex b/lib/pleroma/web/media_proxy/media_proxy_controller.ex
index a0aafc32e..0b446e0a6 100644
--- a/lib/pleroma/web/media_proxy/media_proxy_controller.ex
+++ b/lib/pleroma/web/media_proxy/media_proxy_controller.ex
@@ -71,15 +71,11 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyController do
drop_static_param_and_redirect(conn)
content_type == "image/gif" ->
- conn
- |> put_status(301)
- |> redirect(external: media_proxy_url)
+ redirect(conn, external: media_proxy_url)
min_content_length_for_preview() > 0 and content_length > 0 and
content_length < min_content_length_for_preview() ->
- conn
- |> put_status(301)
- |> redirect(external: media_proxy_url)
+ redirect(conn, external: media_proxy_url)
true ->
handle_preview(content_type, conn, media_proxy_url)
diff --git a/lib/pleroma/web/metadata/providers/open_graph.ex b/lib/pleroma/web/metadata/providers/open_graph.ex
index 604434df2..fa5fbe553 100644
--- a/lib/pleroma/web/metadata/providers/open_graph.ex
+++ b/lib/pleroma/web/metadata/providers/open_graph.ex
@@ -78,10 +78,10 @@ defmodule Pleroma.Web.Metadata.Providers.OpenGraph do
# object when a Video or GIF is attached it will display that in Whatsapp Rich Preview.
case Utils.fetch_media_type(@media_types, url["mediaType"]) do
"audio" ->
- acc ++
- [
- {:meta, [property: "og:audio", content: MediaProxy.url(url["href"])], []}
- ]
+ [
+ {:meta, [property: "og:audio", content: MediaProxy.url(url["href"])], []}
+ | acc
+ ]
# Not using preview_url for this. It saves bandwidth, but the image dimensions will
# be wrong. We generate it on the fly and have no way to capture or analyze the
@@ -89,18 +89,18 @@ defmodule Pleroma.Web.Metadata.Providers.OpenGraph do
# in timelines too, but you can get clever with the aspect ratio metadata as a
# workaround.
"image" ->
- (acc ++
- [
- {:meta, [property: "og:image", content: MediaProxy.url(url["href"])], []},
- {:meta, [property: "og:image:alt", content: attachment["name"]], []}
- ])
+ [
+ {:meta, [property: "og:image", content: MediaProxy.url(url["href"])], []},
+ {:meta, [property: "og:image:alt", content: attachment["name"]], []}
+ | acc
+ ]
|> maybe_add_dimensions(url)
"video" ->
- (acc ++
- [
- {:meta, [property: "og:video", content: MediaProxy.url(url["href"])], []}
- ])
+ [
+ {:meta, [property: "og:video", content: MediaProxy.url(url["href"])], []}
+ | acc
+ ]
|> maybe_add_dimensions(url)
|> maybe_add_video_thumbnail(url)
diff --git a/lib/pleroma/web/metadata/providers/twitter_card.ex b/lib/pleroma/web/metadata/providers/twitter_card.ex
index 212fa85ed..7f50877c3 100644
--- a/lib/pleroma/web/metadata/providers/twitter_card.ex
+++ b/lib/pleroma/web/metadata/providers/twitter_card.ex
@@ -61,13 +61,13 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
Enum.reduce(attachment["url"], [], fn url, acc ->
case Utils.fetch_media_type(@media_types, url["mediaType"]) do
"audio" ->
- acc ++
- [
- {:meta, [name: "twitter:card", content: "player"], []},
- {:meta, [name: "twitter:player:width", content: "480"], []},
- {:meta, [name: "twitter:player:height", content: "80"], []},
- {:meta, [name: "twitter:player", content: player_url(id)], []}
- ]
+ [
+ {:meta, [name: "twitter:card", content: "player"], []},
+ {:meta, [name: "twitter:player:width", content: "480"], []},
+ {:meta, [name: "twitter:player:height", content: "80"], []},
+ {:meta, [name: "twitter:player", content: player_url(id)], []}
+ | acc
+ ]
# Not using preview_url for this. It saves bandwidth, but the image dimensions will
# be wrong. We generate it on the fly and have no way to capture or analyze the
@@ -75,16 +75,16 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
# in timelines too, but you can get clever with the aspect ratio metadata as a
# workaround.
"image" ->
- (acc ++
+ [
+ {:meta, [name: "twitter:card", content: "summary_large_image"], []},
+ {:meta,
[
- {:meta, [name: "twitter:card", content: "summary_large_image"], []},
- {:meta,
- [
- name: "twitter:image",
- content: MediaProxy.url(url["href"])
- ], []},
- {:meta, [name: "twitter:image:alt", content: truncate(attachment["name"])], []}
- ])
+ name: "twitter:image",
+ content: MediaProxy.url(url["href"])
+ ], []},
+ {:meta, [name: "twitter:image:alt", content: truncate(attachment["name"])], []}
+ | acc
+ ]
|> maybe_add_dimensions(url)
"video" ->
@@ -92,17 +92,17 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
height = url["height"] || 480
width = url["width"] || 480
- acc ++
- [
- {:meta, [name: "twitter:card", content: "player"], []},
- {:meta, [name: "twitter:player", content: player_url(id)], []},
- {:meta, [name: "twitter:player:width", content: "#{width}"], []},
- {:meta, [name: "twitter:player:height", content: "#{height}"], []},
- {:meta, [name: "twitter:player:stream", content: MediaProxy.url(url["href"])],
- []},
- {:meta, [name: "twitter:player:stream:content_type", content: url["mediaType"]],
- []}
- ]
+ [
+ {:meta, [name: "twitter:card", content: "player"], []},
+ {:meta, [name: "twitter:player", content: player_url(id)], []},
+ {:meta, [name: "twitter:player:width", content: "#{width}"], []},
+ {:meta, [name: "twitter:player:height", content: "#{height}"], []},
+ {:meta, [name: "twitter:player:stream", content: MediaProxy.url(url["href"])],
+ []},
+ {:meta, [name: "twitter:player:stream:content_type", content: url["mediaType"]],
+ []}
+ | acc
+ ]
_ ->
acc
diff --git a/lib/pleroma/web/plugs/ap_client_api_enabled_plug.ex b/lib/pleroma/web/plugs/ap_client_api_enabled_plug.ex
deleted file mode 100644
index 6807673f9..000000000
--- a/lib/pleroma/web/plugs/ap_client_api_enabled_plug.ex
+++ /dev/null
@@ -1,34 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2024 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.Plugs.APClientApiEnabledPlug do
- import Plug.Conn
- import Phoenix.Controller, only: [text: 2]
-
- @config_impl Application.compile_env(:pleroma, [__MODULE__, :config_impl], Pleroma.Config)
- @enabled_path [:activitypub, :client_api_enabled]
-
- def init(options \\ []), do: Map.new(options)
-
- def call(conn, %{allow_server: true}) do
- if @config_impl.get(@enabled_path, false) do
- conn
- else
- conn
- |> assign(:user, nil)
- |> assign(:token, nil)
- end
- end
-
- def call(conn, _) do
- if @config_impl.get(@enabled_path, false) do
- conn
- else
- conn
- |> put_status(:forbidden)
- |> text("C2S not enabled")
- |> halt()
- end
- end
-end
diff --git a/lib/pleroma/web/plugs/http_signature_plug.ex b/lib/pleroma/web/plugs/http_signature_plug.ex
index 2e16212ce..67974599a 100644
--- a/lib/pleroma/web/plugs/http_signature_plug.ex
+++ b/lib/pleroma/web/plugs/http_signature_plug.ex
@@ -19,16 +19,8 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do
options
end
- def call(%{assigns: %{valid_signature: true}} = conn, _opts), do: conn
-
- # skip for C2S requests from authenticated users
- def call(%{assigns: %{user: %Pleroma.User{}}} = conn, _opts) do
- if get_format(conn) in ["json", "activity+json"] do
- # ensure access token is provided for 2FA
- Pleroma.Web.Plugs.EnsureAuthenticatedPlug.call(conn, %{})
- else
- conn
- end
+ def call(%{assigns: %{valid_signature: true}} = conn, _opts) do
+ conn
end
def call(conn, _opts) do
diff --git a/lib/pleroma/web/plugs/instance_static.ex b/lib/pleroma/web/plugs/instance_static.ex
index f82b9a098..75bfdd65b 100644
--- a/lib/pleroma/web/plugs/instance_static.ex
+++ b/lib/pleroma/web/plugs/instance_static.ex
@@ -4,7 +4,6 @@
defmodule Pleroma.Web.Plugs.InstanceStatic do
require Pleroma.Constants
- import Plug.Conn, only: [put_resp_header: 3]
@moduledoc """
This is a shim to call `Plug.Static` but with runtime `from` configuration.
@@ -45,31 +44,10 @@ defmodule Pleroma.Web.Plugs.InstanceStatic do
end
defp call_static(conn, opts, from) do
- # Prevent content-type spoofing by setting content_types: false
opts =
opts
|> Map.put(:from, from)
- |> Map.put(:content_types, false)
- conn = set_content_type(conn, conn.request_path)
-
- # Call Plug.Static with our sanitized content-type
Plug.Static.call(conn, opts)
end
-
- defp set_content_type(conn, "/emoji/" <> filepath) do
- real_mime = MIME.from_path(filepath)
-
- clean_mime =
- Pleroma.Web.Plugs.Utils.get_safe_mime_type(%{allowed_mime_types: ["image"]}, real_mime)
-
- put_resp_header(conn, "content-type", clean_mime)
- end
-
- defp set_content_type(conn, filepath) do
- real_mime = MIME.from_path(filepath)
- put_resp_header(conn, "content-type", real_mime)
- end
end
-
-# I think this needs to be uncleaned except for emoji.
diff --git a/lib/pleroma/web/plugs/uploaded_media.ex b/lib/pleroma/web/plugs/uploaded_media.ex
index abacf965b..f1076da1b 100644
--- a/lib/pleroma/web/plugs/uploaded_media.ex
+++ b/lib/pleroma/web/plugs/uploaded_media.ex
@@ -11,7 +11,6 @@ defmodule Pleroma.Web.Plugs.UploadedMedia do
require Logger
alias Pleroma.Web.MediaProxy
- alias Pleroma.Web.Plugs.Utils
@behaviour Plug
# no slashes
@@ -29,9 +28,7 @@ defmodule Pleroma.Web.Plugs.UploadedMedia do
|> Keyword.put(:at, "/__unconfigured_media_plug")
|> Plug.Static.init()
- allowed_mime_types = Pleroma.Config.get([Pleroma.Upload, :allowed_mime_types])
-
- %{static_plug_opts: static_plug_opts, allowed_mime_types: allowed_mime_types}
+ %{static_plug_opts: static_plug_opts}
end
def call(%{request_path: <<"/", @path, "/", file::binary>>} = conn, opts) do
@@ -72,23 +69,13 @@ defmodule Pleroma.Web.Plugs.UploadedMedia do
defp media_is_banned(_, _), do: false
- defp set_content_type(conn, opts, filepath) do
- real_mime = MIME.from_path(filepath)
- clean_mime = Utils.get_safe_mime_type(opts, real_mime)
- put_resp_header(conn, "content-type", clean_mime)
- end
-
defp get_media(conn, {:static_dir, directory}, _, opts) do
static_opts =
Map.get(opts, :static_plug_opts)
|> Map.put(:at, [@path])
|> Map.put(:from, directory)
- |> Map.put(:content_types, false)
- conn =
- conn
- |> set_content_type(opts, conn.request_path)
- |> Plug.Static.call(static_opts)
+ conn = Plug.Static.call(conn, static_opts)
if conn.halted do
conn
diff --git a/lib/pleroma/web/plugs/utils.ex b/lib/pleroma/web/plugs/utils.ex
deleted file mode 100644
index 05e0fbe84..000000000
--- a/lib/pleroma/web/plugs/utils.ex
+++ /dev/null
@@ -1,14 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.Plugs.Utils do
- @moduledoc """
- Some helper functions shared across several plugs
- """
-
- def get_safe_mime_type(%{allowed_mime_types: allowed_mime_types} = _opts, mime) do
- [maintype | _] = String.split(mime, "/", parts: 2)
- if maintype in allowed_mime_types, do: mime, else: "application/octet-stream"
- end
-end
diff --git a/lib/pleroma/web/rich_media/card.ex b/lib/pleroma/web/rich_media/card.ex
index 6b4bb9555..abad4957e 100644
--- a/lib/pleroma/web/rich_media/card.ex
+++ b/lib/pleroma/web/rich_media/card.ex
@@ -54,10 +54,7 @@ defmodule Pleroma.Web.RichMedia.Card do
@spec get_by_url(String.t() | nil) :: t() | nil | :error
def get_by_url(url) when is_binary(url) do
- host = URI.parse(url).host
-
- with true <- @config_impl.get([:rich_media, :enabled]),
- true <- host not in @config_impl.get([:rich_media, :ignore_hosts], []) do
+ if @config_impl.get([:rich_media, :enabled]) do
url_hash = url_to_hash(url)
@cachex.fetch!(:rich_media_cache, url_hash, fn _ ->
@@ -72,7 +69,7 @@ defmodule Pleroma.Web.RichMedia.Card do
end
end)
else
- false -> :error
+ :error
end
end
@@ -80,10 +77,7 @@ defmodule Pleroma.Web.RichMedia.Card do
@spec get_or_backfill_by_url(String.t(), keyword()) :: t() | nil
def get_or_backfill_by_url(url, opts \\ []) do
- host = URI.parse(url).host
-
- with true <- @config_impl.get([:rich_media, :enabled]),
- true <- host not in @config_impl.get([:rich_media, :ignore_hosts], []) do
+ if @config_impl.get([:rich_media, :enabled]) do
case get_by_url(url) do
%__MODULE__{} = card ->
card
@@ -100,7 +94,7 @@ defmodule Pleroma.Web.RichMedia.Card do
nil
end
else
- false -> nil
+ nil
end
end
diff --git a/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex b/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex
index c42e2c96b..320a5f515 100644
--- a/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex
+++ b/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex
@@ -9,7 +9,7 @@ defmodule Pleroma.Web.RichMedia.Parsers.MetaTagsParser do
|> Enum.reduce(data, fn el, acc ->
attributes = normalize_attributes(el, prefix, key_name, value_name)
- Map.merge(attributes, acc)
+ Map.merge(acc, attributes)
end)
|> maybe_put_title(html)
end
diff --git a/lib/pleroma/web/rich_media/parsers/twitter_card.ex b/lib/pleroma/web/rich_media/parsers/twitter_card.ex
index 6f6f8b2ae..cc653729d 100644
--- a/lib/pleroma/web/rich_media/parsers/twitter_card.ex
+++ b/lib/pleroma/web/rich_media/parsers/twitter_card.ex
@@ -11,16 +11,5 @@ defmodule Pleroma.Web.RichMedia.Parsers.TwitterCard do
|> MetaTagsParser.parse(html, "og", "property")
|> MetaTagsParser.parse(html, "twitter", "name")
|> MetaTagsParser.parse(html, "twitter", "property")
- |> filter_tags()
- end
-
- defp filter_tags(tags) do
- Map.filter(tags, fn {k, _v} ->
- cond do
- k in ["card", "description", "image", "title", "ttl", "type", "url"] -> true
- String.starts_with?(k, "image:") -> true
- true -> false
- end
- end)
end
end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index bf8ebf3e4..0423ca9e2 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -755,11 +755,6 @@ defmodule Pleroma.Web.Router do
get("/announcements", AnnouncementController, :index)
post("/announcements/:id/dismiss", AnnouncementController, :mark_read)
-
- get("/tags/:id", TagController, :show)
- post("/tags/:id/follow", TagController, :follow)
- post("/tags/:id/unfollow", TagController, :unfollow)
- get("/followed_tags", TagController, :show_followed)
end
scope "/api/v1", Pleroma.Web.MastodonAPI do
@@ -907,37 +902,22 @@ defmodule Pleroma.Web.Router do
# Client to Server (C2S) AP interactions
pipeline :activitypub_client do
plug(:ap_service_actor)
- plug(Pleroma.Web.Plugs.APClientApiEnabledPlug)
plug(:fetch_session)
plug(:authenticate)
plug(:after_auth)
end
- # AP interactions used by both S2S and C2S
- pipeline :activitypub_server_or_client do
- plug(:ap_service_actor)
- plug(:fetch_session)
- plug(:authenticate)
- plug(Pleroma.Web.Plugs.APClientApiEnabledPlug, allow_server: true)
- plug(:after_auth)
- plug(:http_signature)
- end
-
scope "/", Pleroma.Web.ActivityPub do
pipe_through([:activitypub_client])
get("/api/ap/whoami", ActivityPubController, :whoami)
get("/users/:nickname/inbox", ActivityPubController, :read_inbox)
+ get("/users/:nickname/outbox", ActivityPubController, :outbox)
post("/users/:nickname/outbox", ActivityPubController, :update_outbox)
post("/api/ap/upload_media", ActivityPubController, :upload_media)
- end
-
- scope "/", Pleroma.Web.ActivityPub do
- pipe_through([:activitypub_server_or_client])
-
- get("/users/:nickname/outbox", ActivityPubController, :outbox)
+ # The following two are S2S as well, see `ActivityPub.fetch_follow_information_for_user/1`:
get("/users/:nickname/followers", ActivityPubController, :followers)
get("/users/:nickname/following", ActivityPubController, :following)
get("/users/:nickname/collections/featured", ActivityPubController, :pinned)
diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex
index cc149e04c..76dc0f42d 100644
--- a/lib/pleroma/web/streamer.ex
+++ b/lib/pleroma/web/streamer.ex
@@ -19,7 +19,6 @@ defmodule Pleroma.Web.Streamer do
alias Pleroma.Web.OAuth.Token
alias Pleroma.Web.Plugs.OAuthScopesPlug
alias Pleroma.Web.StreamerView
- require Pleroma.Constants
@registry Pleroma.Web.StreamerRegistry
@@ -306,17 +305,7 @@ defmodule Pleroma.Web.Streamer do
User.get_recipients_from_activity(item)
|> Enum.map(fn %{id: id} -> "user:#{id}" end)
- hashtag_recipients =
- if Pleroma.Constants.as_public() in item.recipients do
- Pleroma.Hashtag.get_recipients_for_activity(item)
- |> Enum.map(fn id -> "user:#{id}" end)
- else
- []
- end
-
- all_recipients = Enum.uniq(recipient_topics ++ hashtag_recipients)
-
- Enum.each(all_recipients, fn topic ->
+ Enum.each(recipient_topics, fn topic ->
push_to_socket(topic, item)
end)
end
diff --git a/mix.exs b/mix.exs
index 808a2b12c..6e071cd1f 100644
--- a/mix.exs
+++ b/mix.exs
@@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do
def project do
[
app: :pleroma,
- version: version("2.9.1"),
+ version: version("2.7.51"),
elixir: "~> 1.14",
elixirc_paths: elixirc_paths(Mix.env()),
compilers: Mix.compilers(),
diff --git a/priv/repo/migrations/20221203232118_add_user_follows_hashtag.exs b/priv/repo/migrations/20221203232118_add_user_follows_hashtag.exs
deleted file mode 100644
index 2b5ae91be..000000000
--- a/priv/repo/migrations/20221203232118_add_user_follows_hashtag.exs
+++ /dev/null
@@ -1,14 +0,0 @@
-defmodule Pleroma.Repo.Migrations.AddUserFollowsHashtag do
- use Ecto.Migration
-
- def change do
- create table(:user_follows_hashtag) do
- add(:hashtag_id, references(:hashtags))
- add(:user_id, references(:users, type: :uuid, on_delete: :delete_all))
- end
-
- create(unique_index(:user_follows_hashtag, [:user_id, :hashtag_id]))
-
- create_if_not_exists(index(:user_follows_hashtag, [:hashtag_id]))
- end
-end
diff --git a/test/fixtures/break_analyze.png b/test/fixtures/break_analyze.png
deleted file mode 100644
index b5e91b08a..000000000
Binary files a/test/fixtures/break_analyze.png and /dev/null differ
diff --git a/test/fixtures/fulmo.html b/test/fixtures/fulmo.html
deleted file mode 100644
index e54eaf8d8..000000000
--- a/test/fixtures/fulmo.html
+++ /dev/null
@@ -1,151 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
- Fulmo
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Ceteraj rakontoj
- Bildosignoj
- Eseoj
- Ludoj
- Poemoj
- Vortaroj
-
-
-
-
- Fulmo
- Skribis Tirifto
- 2025-01-31
-
- »Kial ĉiam mi? Tio ne justas! Oni kulpigas min, sed ja ne mi kulpas!« La nubofeo lamentis, dum ĝi ordigis restaĵojn de falinta arbo. Plejparto el la pingloj estis brulintaj, kaj el la trunko ankoraŭ leviĝis fumo.
- Subite aŭdeblis ekstraj kraketoj deapude. Ĝi rigardis flanken, kaj vidis iun kaŭri apud la arbo, derompi branĉetojn, kaj orde ilin amasigi. Ŝajnis, ke ekde sia rimarkiĝo, la nekonatulo laŭeble kuntiriĝis, kaj strebis labori kiel eble plej silente.
- »Saluton…?« La nubofeo stariĝis, alporolante la eston. Tiu kvazaŭ frostiĝis, sed timeme ankaŭ stariĝis.
- »S- Saluton…« Ĝi respondis sen kuraĝo rigardi ĝiadirekten. Nun stare, videblis ke ĝi estas verdanta florofeo.
- »… kion vi faras tie ĉi?« La nubofeo demandis.
- »Nu… tiel kaj tiel… mi ordigas.«
- »Ho. Mi ricevis taskon ordigi ĉi tie… se vi povas atendi, vi ne bezonas peni!«
- »N- Nu… mi tamen volus…« Parolis la florofeo, plu deturnante la kapon.
- »Nu… bone, se vi tion deziras… dankon!« La nubofeo dankis, kaj returniĝis al sia laboro.
- Fojfoje ĝi scivole rigardis al sia nova kunlaboranto, kaj fojfoje renkontis similan rigardon de ĝia flanko, kiuokaze ambaŭ rigardoj rapide revenis al la ordigataj pingloj kaj branĉetoj. »(Kial tiom volonte helpi min?)« Pensis al si la nubofeo. »(Ĉu ĝi simple tiom bonkoras? Ĝi ja tre bele floras; eble ankaŭ ĝia koro tiel same belas…)« Kaj vere, ĝiaj surfloroj grandanime malfermis siajn belkolorajn folietojn, kaj bonodoris al mondo.
-
-
-
-
-
-
- Pinglordigado
-
- © 2025 Tirifto
-
-
-
-
- Post iom da tempo, ĉiu feo tralaboris ĝis la trunkomezo, kaj proksimiĝis al la alia feo. Kaj tiam ekpezis sur ili devosento rompi la silenton.
- »… kia bela vetero, ĉu ne?« Diris la nubofeo, tuj rimarkonte, ke mallumiĝas, kaj la ĉielo restas kovrita de nuboj.
- »Jes ja! Tre nube. Mi ŝatas nubojn!« Respondis la alia entuziasme, sed tuj haltetis kaj deturnis la kapon. Ambaŭ feoj daŭrigis laboron silente, kaj plu proksimiĝis, ĝis tiu preskaŭ estis finita.
- »H… H… Ho ne…!« Subite ekdiris la nubofeo urĝe.
- »Kio okazas?!«
- »T… Tern…!«
- »Jen! Tenu!« La florofeo etendis manon kun granda folio. La nubofeo ĝin prenis, kaj tien ternis. Aperis ekfulmo, kaj la cindriĝinta folio disfalis.
- »Pardonu… mi ne volis…« Bedaŭris la nubofeo. »Mi ne scias, kial tio ĉiam okazas! Tiom plaĉas al mi promeni tere, sed ĉiuj diras, ke mi maldevus, ĉar ial ĝi ĉiam finiĝas tiel ĉi.« Ĝi montris al la arbo. »Eble ili pravas…«
- »Nu…« diris la florofeo bedaŭre, kaj etendis la manon.
- »H… H… Ne ree…!«
- Ekfulmis. Alia ĵus metita folio cindriĝis en la manoj de la florofeo, time ferminta la okulojn.
- »Dankegon… mi tre ŝatas vian helpon! Kaj mi ne… ne…«
- Metiĝis. Ekfulmis. Cindriĝis.
- »Io tre iritas mian nazon!« Plendis la nubofeo. Poste ĝi rimarkis la florpolvon, kiu disŝutiĝis el la florofeo en la tutan ĉirkaŭaĵon, kaj eĉ tuj antaŭ la nubofeon.
- »N- Nu…« Diris la florofeo, honte rigardanta la teron. »… pardonu.«
-
- Ĉu vi ŝatas la verkon? Subtenu min aŭ kopiu adreson de la verko por diskonigi ĝin!
-
-
- Historio
-
- 2025-01-31
- Unua publikigo.
-
-
-
- Permesilo
- Ĉi tiun verkon vi rajtas libere kopii, disdoni, kaj ŝanĝi, laŭ kondiĉoj de la Permesilo de arto libera . (Resume: Vi devas mencii la aŭtoron kaj doni ligilon al la verko. Se vi ŝanĝas la verkon, vi devas laŭeble noti la faritajn ŝanĝojn, ilian daton, kaj eldoni ilin sub la sama permesilo.)
-
-
-
-
-
-
-
-
-
diff --git a/test/fixtures/mastodon-update-with-likes.json b/test/fixtures/mastodon-update-with-likes.json
deleted file mode 100644
index 3bdb3ba3d..000000000
--- a/test/fixtures/mastodon-update-with-likes.json
+++ /dev/null
@@ -1,90 +0,0 @@
-{
- "@context": [
- "https://www.w3.org/ns/activitystreams",
- {
- "atomUri": "ostatus:atomUri",
- "conversation": "ostatus:conversation",
- "inReplyToAtomUri": "ostatus:inReplyToAtomUri",
- "ostatus": "http://ostatus.org#",
- "sensitive": "as:sensitive",
- "toot": "http://joinmastodon.org/ns#",
- "votersCount": "toot:votersCount"
- },
- "https://w3id.org/security/v1"
- ],
- "actor": "https://pol.social/users/mkljczk",
- "cc": ["https://www.w3.org/ns/activitystreams#Public",
- "https://pol.social/users/aemstuz", "https://gts.mkljczk.pl/users/mkljczk",
- "https://pl.fediverse.pl/users/mkljczk",
- "https://fedi.kutno.pl/users/mkljczk"],
- "id": "https://pol.social/users/mkljczk/statuses/113907871635572263#updates/1738096776",
- "object": {
- "atomUri": "https://pol.social/users/mkljczk/statuses/113907871635572263",
- "attachment": [],
- "attributedTo": "https://pol.social/users/mkljczk",
- "cc": ["https://www.w3.org/ns/activitystreams#Public",
- "https://pol.social/users/aemstuz", "https://gts.mkljczk.pl/users/mkljczk",
- "https://pl.fediverse.pl/users/mkljczk",
- "https://fedi.kutno.pl/users/mkljczk"],
- "content": "test
",
- "contentMap": {
- "pl": "test
"
- },
- "conversation": "https://fedi.kutno.pl/contexts/43c14c70-d3fb-42b4-a36d-4eacfab9695a",
- "id": "https://pol.social/users/mkljczk/statuses/113907871635572263",
- "inReplyTo": "https://pol.social/users/aemstuz/statuses/113907854282654767",
- "inReplyToAtomUri": "https://pol.social/users/aemstuz/statuses/113907854282654767",
- "likes": {
- "id": "https://pol.social/users/mkljczk/statuses/113907871635572263/likes",
- "totalItems": 1,
- "type": "Collection"
- },
- "published": "2025-01-28T20:29:45Z",
- "replies": {
- "first": {
- "items": [],
- "next": "https://pol.social/users/mkljczk/statuses/113907871635572263/replies?only_other_accounts=true&page=true",
- "partOf": "https://pol.social/users/mkljczk/statuses/113907871635572263/replies",
- "type": "CollectionPage"
- },
- "id": "https://pol.social/users/mkljczk/statuses/113907871635572263/replies",
- "type": "Collection"
- },
- "sensitive": false,
- "shares": {
- "id": "https://pol.social/users/mkljczk/statuses/113907871635572263/shares",
- "totalItems": 0,
- "type": "Collection"
- },
- "summary": null,
- "tag": [
- {
- "href": "https://pol.social/users/aemstuz",
- "name": "@aemstuz",
- "type": "Mention"
- },
- {
- "href": "https://gts.mkljczk.pl/users/mkljczk",
- "name": "@mkljczk@gts.mkljczk.pl",
- "type": "Mention"
- },
- {
- "href": "https://pl.fediverse.pl/users/mkljczk",
- "name": "@mkljczk@fediverse.pl",
- "type": "Mention"
- },
- {
- "href": "https://fedi.kutno.pl/users/mkljczk",
- "name": "@mkljczk@fedi.kutno.pl",
- "type": "Mention"
- }
- ],
- "to": ["https://pol.social/users/mkljczk/followers"],
- "type": "Note",
- "updated": "2025-01-28T20:39:36Z",
- "url": "https://pol.social/@mkljczk/113907871635572263"
- },
- "published": "2025-01-28T20:39:36Z",
- "to": ["https://pol.social/users/mkljczk/followers"],
- "type": "Update"
-}
diff --git a/test/fixtures/users_mock/friendica_followers.json b/test/fixtures/users_mock/friendica_followers.json
index f58c1d56c..7b86b5fe2 100644
--- a/test/fixtures/users_mock/friendica_followers.json
+++ b/test/fixtures/users_mock/friendica_followers.json
@@ -13,7 +13,7 @@
"directMessage": "litepub:directMessage"
}
],
- "id": "https://remote.org/followers/fuser3",
+ "id": "http://localhost:8080/followers/fuser3",
"type": "OrderedCollection",
"totalItems": 296
}
diff --git a/test/fixtures/users_mock/friendica_following.json b/test/fixtures/users_mock/friendica_following.json
index f3930f42c..7c526befc 100644
--- a/test/fixtures/users_mock/friendica_following.json
+++ b/test/fixtures/users_mock/friendica_following.json
@@ -13,7 +13,7 @@
"directMessage": "litepub:directMessage"
}
],
- "id": "https://remote.org/following/fuser3",
+ "id": "http://localhost:8080/following/fuser3",
"type": "OrderedCollection",
"totalItems": 32
}
diff --git a/test/fixtures/users_mock/masto_closed_followers.json b/test/fixtures/users_mock/masto_closed_followers.json
index 89bb9cba9..da296892d 100644
--- a/test/fixtures/users_mock/masto_closed_followers.json
+++ b/test/fixtures/users_mock/masto_closed_followers.json
@@ -1,7 +1,7 @@
{
"@context": "https://www.w3.org/ns/activitystreams",
- "id": "https://remote.org/users/masto_closed/followers",
+ "id": "http://localhost:4001/users/masto_closed/followers",
"type": "OrderedCollection",
"totalItems": 437,
- "first": "https://remote.org/users/masto_closed/followers?page=1"
+ "first": "http://localhost:4001/users/masto_closed/followers?page=1"
}
diff --git a/test/fixtures/users_mock/masto_closed_followers_page.json b/test/fixtures/users_mock/masto_closed_followers_page.json
index 4e9cb315f..04ab0c4d3 100644
--- a/test/fixtures/users_mock/masto_closed_followers_page.json
+++ b/test/fixtures/users_mock/masto_closed_followers_page.json
@@ -1 +1 @@
-{"@context":"https://www.w3.org/ns/activitystreams","id":"https://remote.org/users/masto_closed/followers?page=1","type":"OrderedCollectionPage","totalItems":437,"next":"https://remote.org/users/masto_closed/followers?page=2","partOf":"https://remote.org/users/masto_closed/followers","orderedItems":["https://testing.uguu.ltd/users/rin","https://patch.cx/users/rin","https://letsalllovela.in/users/xoxo","https://pleroma.site/users/crushv","https://aria.company/users/boris","https://kawen.space/users/crushv","https://freespeech.host/users/cvcvcv","https://pleroma.site/users/picpub","https://pixelfed.social/users/nosleep","https://boopsnoot.gq/users/5c1896d162f7d337f90492a3","https://pikachu.rocks/users/waifu","https://royal.crablettesare.life/users/crablettes"]}
+{"@context":"https://www.w3.org/ns/activitystreams","id":"http://localhost:4001/users/masto_closed/followers?page=1","type":"OrderedCollectionPage","totalItems":437,"next":"http://localhost:4001/users/masto_closed/followers?page=2","partOf":"http://localhost:4001/users/masto_closed/followers","orderedItems":["https://testing.uguu.ltd/users/rin","https://patch.cx/users/rin","https://letsalllovela.in/users/xoxo","https://pleroma.site/users/crushv","https://aria.company/users/boris","https://kawen.space/users/crushv","https://freespeech.host/users/cvcvcv","https://pleroma.site/users/picpub","https://pixelfed.social/users/nosleep","https://boopsnoot.gq/users/5c1896d162f7d337f90492a3","https://pikachu.rocks/users/waifu","https://royal.crablettesare.life/users/crablettes"]}
diff --git a/test/fixtures/users_mock/masto_closed_following.json b/test/fixtures/users_mock/masto_closed_following.json
index aa74f8e78..146d49f9c 100644
--- a/test/fixtures/users_mock/masto_closed_following.json
+++ b/test/fixtures/users_mock/masto_closed_following.json
@@ -1,7 +1,7 @@
{
"@context": "https://www.w3.org/ns/activitystreams",
- "id": "https://remote.org/users/masto_closed/following",
+ "id": "http://localhost:4001/users/masto_closed/following",
"type": "OrderedCollection",
"totalItems": 152,
- "first": "https://remote.org/users/masto_closed/following?page=1"
+ "first": "http://localhost:4001/users/masto_closed/following?page=1"
}
diff --git a/test/fixtures/users_mock/masto_closed_following_page.json b/test/fixtures/users_mock/masto_closed_following_page.json
index b017413cc..8d8324699 100644
--- a/test/fixtures/users_mock/masto_closed_following_page.json
+++ b/test/fixtures/users_mock/masto_closed_following_page.json
@@ -1 +1 @@
-{"@context":"https://www.w3.org/ns/activitystreams","id":"https://remote.org/users/masto_closed/following?page=1","type":"OrderedCollectionPage","totalItems":152,"next":"https://remote.org/users/masto_closed/following?page=2","partOf":"https://remote.org/users/masto_closed/following","orderedItems":["https://testing.uguu.ltd/users/rin","https://patch.cx/users/rin","https://letsalllovela.in/users/xoxo","https://pleroma.site/users/crushv","https://aria.company/users/boris","https://kawen.space/users/crushv","https://freespeech.host/users/cvcvcv","https://pleroma.site/users/picpub","https://pixelfed.social/users/nosleep","https://boopsnoot.gq/users/5c1896d162f7d337f90492a3","https://pikachu.rocks/users/waifu","https://royal.crablettesare.life/users/crablettes"]}
+{"@context":"https://www.w3.org/ns/activitystreams","id":"http://localhost:4001/users/masto_closed/following?page=1","type":"OrderedCollectionPage","totalItems":152,"next":"http://localhost:4001/users/masto_closed/following?page=2","partOf":"http://localhost:4001/users/masto_closed/following","orderedItems":["https://testing.uguu.ltd/users/rin","https://patch.cx/users/rin","https://letsalllovela.in/users/xoxo","https://pleroma.site/users/crushv","https://aria.company/users/boris","https://kawen.space/users/crushv","https://freespeech.host/users/cvcvcv","https://pleroma.site/users/picpub","https://pixelfed.social/users/nosleep","https://boopsnoot.gq/users/5c1896d162f7d337f90492a3","https://pikachu.rocks/users/waifu","https://royal.crablettesare.life/users/crablettes"]}
diff --git a/test/fixtures/users_mock/pleroma_followers.json b/test/fixtures/users_mock/pleroma_followers.json
index 6ac3bfee0..db71d084b 100644
--- a/test/fixtures/users_mock/pleroma_followers.json
+++ b/test/fixtures/users_mock/pleroma_followers.json
@@ -1,18 +1,18 @@
{
"type": "OrderedCollection",
"totalItems": 527,
- "id": "https://remote.org/users/fuser2/followers",
+ "id": "http://localhost:4001/users/fuser2/followers",
"first": {
"type": "OrderedCollectionPage",
"totalItems": 527,
- "partOf": "https://remote.org/users/fuser2/followers",
+ "partOf": "http://localhost:4001/users/fuser2/followers",
"orderedItems": [],
- "next": "https://remote.org/users/fuser2/followers?page=2",
- "id": "https://remote.org/users/fuser2/followers?page=1"
+ "next": "http://localhost:4001/users/fuser2/followers?page=2",
+ "id": "http://localhost:4001/users/fuser2/followers?page=1"
},
"@context": [
"https://www.w3.org/ns/activitystreams",
- "https://remote.org/schemas/litepub-0.1.jsonld",
+ "http://localhost:4001/schemas/litepub-0.1.jsonld",
{
"@language": "und"
}
diff --git a/test/fixtures/users_mock/pleroma_following.json b/test/fixtures/users_mock/pleroma_following.json
index c8306806a..33d087703 100644
--- a/test/fixtures/users_mock/pleroma_following.json
+++ b/test/fixtures/users_mock/pleroma_following.json
@@ -1,18 +1,18 @@
{
"type": "OrderedCollection",
"totalItems": 267,
- "id": "https://remote.org/users/fuser2/following",
+ "id": "http://localhost:4001/users/fuser2/following",
"first": {
"type": "OrderedCollectionPage",
"totalItems": 267,
- "partOf": "https://remote.org/users/fuser2/following",
+ "partOf": "http://localhost:4001/users/fuser2/following",
"orderedItems": [],
- "next": "https://remote.org/users/fuser2/following?page=2",
- "id": "https://remote.org/users/fuser2/following?page=1"
+ "next": "http://localhost:4001/users/fuser2/following?page=2",
+ "id": "http://localhost:4001/users/fuser2/following?page=1"
},
"@context": [
"https://www.w3.org/ns/activitystreams",
- "https://remote.org/schemas/litepub-0.1.jsonld",
+ "http://localhost:4001/schemas/litepub-0.1.jsonld",
{
"@language": "und"
}
diff --git a/test/mix/tasks/pleroma/database_test.exs b/test/mix/tasks/pleroma/database_test.exs
index 38ed096ae..96a925528 100644
--- a/test/mix/tasks/pleroma/database_test.exs
+++ b/test/mix/tasks/pleroma/database_test.exs
@@ -411,7 +411,7 @@ defmodule Mix.Tasks.Pleroma.DatabaseTest do
["scheduled_activities"],
["schema_migrations"],
["thread_mutes"],
- ["user_follows_hashtag"],
+ # ["user_follows_hashtag"], # not in pleroma
# ["user_frontend_setting_profiles"], # not in pleroma
["user_invite_tokens"],
["user_notes"],
diff --git a/test/mix/tasks/pleroma/digest_test.exs b/test/mix/tasks/pleroma/digest_test.exs
index 0d1804cdb..08482aadb 100644
--- a/test/mix/tasks/pleroma/digest_test.exs
+++ b/test/mix/tasks/pleroma/digest_test.exs
@@ -24,7 +24,7 @@ defmodule Mix.Tasks.Pleroma.DigestTest do
setup do: clear_config([Pleroma.Emails.Mailer, :enabled], true)
setup do
- Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Test.StaticConfig)
+ Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
:ok
end
diff --git a/test/mix/tasks/pleroma/user_test.exs b/test/mix/tasks/pleroma/user_test.exs
index 7ce5e92cb..c9bcf2951 100644
--- a/test/mix/tasks/pleroma/user_test.exs
+++ b/test/mix/tasks/pleroma/user_test.exs
@@ -21,7 +21,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do
import Pleroma.Factory
setup do
- Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Test.StaticConfig)
+ Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
:ok
end
diff --git a/test/pleroma/conversation_test.exs b/test/pleroma/conversation_test.exs
index 02b5de615..809c1951a 100644
--- a/test/pleroma/conversation_test.exs
+++ b/test/pleroma/conversation_test.exs
@@ -14,7 +14,7 @@ defmodule Pleroma.ConversationTest do
setup_all do: clear_config([:instance, :federating], true)
setup do
- Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Test.StaticConfig)
+ Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
:ok
end
diff --git a/test/pleroma/ecto_type/activity_pub/object_validators/content_language_map_test.exs b/test/pleroma/ecto_type/activity_pub/object_validators/content_language_map_test.exs
deleted file mode 100644
index a05871a6f..000000000
--- a/test/pleroma/ecto_type/activity_pub/object_validators/content_language_map_test.exs
+++ /dev/null
@@ -1,56 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2023 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.ContentLanguageMapTest do
- use Pleroma.DataCase, async: true
-
- alias Pleroma.EctoType.ActivityPub.ObjectValidators.ContentLanguageMap
-
- test "it validates" do
- data = %{
- "en-US" => "mew mew",
- "en-GB" => "meow meow"
- }
-
- assert {:ok, ^data} = ContentLanguageMap.cast(data)
- end
-
- test "it validates empty strings" do
- data = %{
- "en-US" => "mew mew",
- "en-GB" => ""
- }
-
- assert {:ok, ^data} = ContentLanguageMap.cast(data)
- end
-
- test "it ignores non-strings within the map" do
- data = %{
- "en-US" => "mew mew",
- "en-GB" => 123
- }
-
- assert {:ok, validated_data} = ContentLanguageMap.cast(data)
-
- assert validated_data == %{"en-US" => "mew mew"}
- end
-
- test "it ignores bad locale codes" do
- data = %{
- "en-US" => "mew mew",
- "en_GB" => "meow meow",
- "en<<#@!$#!@%!GB" => "meow meow"
- }
-
- assert {:ok, validated_data} = ContentLanguageMap.cast(data)
-
- assert validated_data == %{"en-US" => "mew mew"}
- end
-
- test "it complains with non-map data" do
- assert :error = ContentLanguageMap.cast("mew")
- assert :error = ContentLanguageMap.cast(["mew"])
- assert :error = ContentLanguageMap.cast([%{"en-US" => "mew"}])
- end
-end
diff --git a/test/pleroma/ecto_type/activity_pub/object_validators/language_code_test.exs b/test/pleroma/ecto_type/activity_pub/object_validators/language_code_test.exs
deleted file mode 100644
index 086bb3e97..000000000
--- a/test/pleroma/ecto_type/activity_pub/object_validators/language_code_test.exs
+++ /dev/null
@@ -1,29 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2023 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCodeTest do
- use Pleroma.DataCase, async: true
-
- alias Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode
-
- test "it accepts language code" do
- text = "pl"
- assert {:ok, ^text} = LanguageCode.cast(text)
- end
-
- test "it accepts language code with region" do
- text = "pl-PL"
- assert {:ok, ^text} = LanguageCode.cast(text)
- end
-
- test "errors for invalid language code" do
- assert {:error, :invalid_language} = LanguageCode.cast("ru_RU")
- assert {:error, :invalid_language} = LanguageCode.cast(" ")
- assert {:error, :invalid_language} = LanguageCode.cast("en-US\n")
- end
-
- test "errors for non-text" do
- assert :error == LanguageCode.cast(42)
- end
-end
diff --git a/test/pleroma/emoji/pack_test.exs b/test/pleroma/emoji/pack_test.exs
index 6ab3e657e..00001abfc 100644
--- a/test/pleroma/emoji/pack_test.exs
+++ b/test/pleroma/emoji/pack_test.exs
@@ -4,7 +4,6 @@
defmodule Pleroma.Emoji.PackTest do
use Pleroma.DataCase
- alias Pleroma.Emoji
alias Pleroma.Emoji.Pack
@emoji_path Path.join(
@@ -54,63 +53,6 @@ defmodule Pleroma.Emoji.PackTest do
assert updated_pack.files_count == 5
end
-
- test "skips existing emojis when adding from zip file", %{pack: pack} do
- # First, let's create a test pack with a "bear" emoji
- test_pack_path = Path.join(@emoji_path, "test_bear_pack")
- File.mkdir_p(test_pack_path)
-
- # Create a pack.json file
- File.write!(Path.join(test_pack_path, "pack.json"), """
- {
- "files": { "bear": "bear.png" },
- "pack": {
- "description": "Bear Pack", "homepage": "https://pleroma.social",
- "license": "Test license", "share-files": true
- }}
- """)
-
- # Copy a test image to use as the bear emoji
- File.cp!(
- Path.absname("test/instance_static/emoji/test_pack/blank.png"),
- Path.join(test_pack_path, "bear.png")
- )
-
- # Load the pack to register the "bear" emoji in the global registry
- {:ok, _bear_pack} = Pleroma.Emoji.Pack.load_pack("test_bear_pack")
-
- # Reload emoji to make sure the bear emoji is in the global registry
- Emoji.reload()
-
- # Verify that the bear emoji exists in the global registry
- assert Emoji.exist?("bear")
-
- # Now try to add a zip file that contains an emoji with the same shortcode
- file = %Plug.Upload{
- content_type: "application/zip",
- filename: "emojis.zip",
- path: Path.absname("test/fixtures/emojis.zip")
- }
-
- {:ok, updated_pack} = Pack.add_file(pack, nil, nil, file)
-
- # Verify that the "bear" emoji was skipped
- refute Map.has_key?(updated_pack.files, "bear")
-
- # Other emojis should be added
- assert Map.has_key?(updated_pack.files, "a_trusted_friend-128")
- assert Map.has_key?(updated_pack.files, "auroraborealis")
- assert Map.has_key?(updated_pack.files, "baby_in_a_box")
- assert Map.has_key?(updated_pack.files, "bear-128")
-
- # Total count should be 4 (all emojis except "bear")
- assert updated_pack.files_count == 4
-
- # Clean up the test pack
- on_exit(fn ->
- File.rm_rf!(test_pack_path)
- end)
- end
end
test "returns error when zip file is bad", %{pack: pack} do
@@ -120,7 +62,7 @@ defmodule Pleroma.Emoji.PackTest do
path: Path.absname("test/instance_static/emoji/test_pack/blank.png")
}
- assert {:error, _} = Pack.add_file(pack, nil, nil, file)
+ assert Pack.add_file(pack, nil, nil, file) == {:error, :einval}
end
test "returns pack when zip file is empty", %{pack: pack} do
diff --git a/test/pleroma/notification_test.exs b/test/pleroma/notification_test.exs
index 4b20e07cf..e595c5c53 100644
--- a/test/pleroma/notification_test.exs
+++ b/test/pleroma/notification_test.exs
@@ -19,7 +19,7 @@ defmodule Pleroma.NotificationTest do
alias Pleroma.Web.MastodonAPI.NotificationView
setup do
- Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Test.StaticConfig)
+ Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
:ok
end
diff --git a/test/pleroma/object/fetcher_test.exs b/test/pleroma/object/fetcher_test.exs
index 7ba5090e1..215fca570 100644
--- a/test/pleroma/object/fetcher_test.exs
+++ b/test/pleroma/object/fetcher_test.exs
@@ -166,91 +166,6 @@ defmodule Pleroma.Object.FetcherTest do
)
end
- test "it does not fetch from local instance" do
- local_url = Pleroma.Web.Endpoint.url() <> "/objects/local_resource"
-
- assert {:fetch, {:error, "Trying to fetch local resource"}} =
- Fetcher.fetch_object_from_id(local_url)
- end
-
- test "it validates content-type headers according to ActivityPub spec" do
- # Setup a mock for an object with invalid content-type
- mock(fn
- %{method: :get, url: "https://example.com/objects/invalid-content-type"} ->
- %Tesla.Env{
- status: 200,
- # Not a valid AP content-type
- headers: [{"content-type", "application/json"}],
- body:
- Jason.encode!(%{
- "id" => "https://example.com/objects/invalid-content-type",
- "type" => "Note",
- "content" => "This has an invalid content type",
- "actor" => "https://example.com/users/actor",
- "attributedTo" => "https://example.com/users/actor"
- })
- }
- end)
-
- assert {:fetch, {:error, {:content_type, "application/json"}}} =
- Fetcher.fetch_object_from_id("https://example.com/objects/invalid-content-type")
- end
-
- test "it accepts objects with application/ld+json and ActivityStreams profile" do
- # Setup a mock for an object with ld+json content-type and AS profile
- mock(fn
- %{method: :get, url: "https://example.com/objects/valid-ld-json"} ->
- %Tesla.Env{
- status: 200,
- headers: [
- {"content-type",
- "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""}
- ],
- body:
- Jason.encode!(%{
- "id" => "https://example.com/objects/valid-ld-json",
- "type" => "Note",
- "content" => "This has a valid ld+json content type",
- "actor" => "https://example.com/users/actor",
- "attributedTo" => "https://example.com/users/actor"
- })
- }
- end)
-
- # This should pass if content-type validation works correctly
- assert {:ok, object} =
- Fetcher.fetch_and_contain_remote_object_from_id(
- "https://example.com/objects/valid-ld-json"
- )
-
- assert object["content"] == "This has a valid ld+json content type"
- end
-
- test "it rejects objects with no content-type header" do
- # Setup a mock for an object with no content-type header
- mock(fn
- %{method: :get, url: "https://example.com/objects/no-content-type"} ->
- %Tesla.Env{
- status: 200,
- # No content-type header
- headers: [],
- body:
- Jason.encode!(%{
- "id" => "https://example.com/objects/no-content-type",
- "type" => "Note",
- "content" => "This has no content type header",
- "actor" => "https://example.com/users/actor",
- "attributedTo" => "https://example.com/users/actor"
- })
- }
- end)
-
- # We want to test that the request fails with a missing content-type error
- # but the actual error is {:fetch, {:error, nil}} - we'll check for this format
- result = Fetcher.fetch_object_from_id("https://example.com/objects/no-content-type")
- assert {:fetch, {:error, nil}} = result
- end
-
test "it resets instance reachability on successful fetch" do
id = "http://mastodon.example.org/@admin/99541947525187367"
Instances.set_consistently_unreachable(id)
@@ -619,110 +534,6 @@ defmodule Pleroma.Object.FetcherTest do
end
end
- describe "cross-domain redirect handling" do
- setup do
- mock(fn
- # Cross-domain redirect with original domain in id
- %{method: :get, url: "https://original.test/objects/123"} ->
- %Tesla.Env{
- status: 200,
- url: "https://media.test/objects/123",
- headers: [{"content-type", "application/activity+json"}],
- body:
- Jason.encode!(%{
- "id" => "https://original.test/objects/123",
- "type" => "Note",
- "content" => "This is redirected content",
- "actor" => "https://original.test/users/actor",
- "attributedTo" => "https://original.test/users/actor"
- })
- }
-
- # Cross-domain redirect with final domain in id
- %{method: :get, url: "https://original.test/objects/final-domain-id"} ->
- %Tesla.Env{
- status: 200,
- url: "https://media.test/objects/final-domain-id",
- headers: [{"content-type", "application/activity+json"}],
- body:
- Jason.encode!(%{
- "id" => "https://media.test/objects/final-domain-id",
- "type" => "Note",
- "content" => "This has final domain in id",
- "actor" => "https://original.test/users/actor",
- "attributedTo" => "https://original.test/users/actor"
- })
- }
-
- # No redirect - same domain
- %{method: :get, url: "https://original.test/objects/same-domain-redirect"} ->
- %Tesla.Env{
- status: 200,
- url: "https://original.test/objects/different-path",
- headers: [{"content-type", "application/activity+json"}],
- body:
- Jason.encode!(%{
- "id" => "https://original.test/objects/same-domain-redirect",
- "type" => "Note",
- "content" => "This has a same-domain redirect",
- "actor" => "https://original.test/users/actor",
- "attributedTo" => "https://original.test/users/actor"
- })
- }
-
- # Test case with missing url field in response (common in tests)
- %{method: :get, url: "https://original.test/objects/missing-url"} ->
- %Tesla.Env{
- status: 200,
- # No url field
- headers: [{"content-type", "application/activity+json"}],
- body:
- Jason.encode!(%{
- "id" => "https://original.test/objects/missing-url",
- "type" => "Note",
- "content" => "This has no URL field in response",
- "actor" => "https://original.test/users/actor",
- "attributedTo" => "https://original.test/users/actor"
- })
- }
- end)
-
- :ok
- end
-
- test "it rejects objects from cross-domain redirects with original domain in id" do
- assert {:error, {:cross_domain_redirect, true}} =
- Fetcher.fetch_and_contain_remote_object_from_id(
- "https://original.test/objects/123"
- )
- end
-
- test "it rejects objects from cross-domain redirects with final domain in id" do
- assert {:error, {:cross_domain_redirect, true}} =
- Fetcher.fetch_and_contain_remote_object_from_id(
- "https://original.test/objects/final-domain-id"
- )
- end
-
- test "it accepts objects with same-domain redirects" do
- assert {:ok, data} =
- Fetcher.fetch_and_contain_remote_object_from_id(
- "https://original.test/objects/same-domain-redirect"
- )
-
- assert data["content"] == "This has a same-domain redirect"
- end
-
- test "it handles responses without URL field (common in tests)" do
- assert {:ok, data} =
- Fetcher.fetch_and_contain_remote_object_from_id(
- "https://original.test/objects/missing-url"
- )
-
- assert data["content"] == "This has no URL field in response"
- end
- end
-
describe "fetch with history" do
setup do
object2 = %{
diff --git a/test/pleroma/repo/migrations/autolinker_to_linkify_test.exs b/test/pleroma/repo/migrations/autolinker_to_linkify_test.exs
index 99522994a..9847781f0 100644
--- a/test/pleroma/repo/migrations/autolinker_to_linkify_test.exs
+++ b/test/pleroma/repo/migrations/autolinker_to_linkify_test.exs
@@ -3,11 +3,12 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Repo.Migrations.AutolinkerToLinkifyTest do
- use Pleroma.DataCase, async: true
+ use Pleroma.DataCase
import Pleroma.Factory
import Pleroma.Tests.Helpers
alias Pleroma.ConfigDB
+ setup do: clear_config(Pleroma.Formatter)
setup_all do: require_migration("20200716195806_autolinker_to_linkify")
test "change/0 converts auto_linker opts for Pleroma.Formatter", %{migration: migration} do
diff --git a/test/pleroma/reverse_proxy_test.exs b/test/pleroma/reverse_proxy_test.exs
index 85e1d0910..fb330232a 100644
--- a/test/pleroma/reverse_proxy_test.exs
+++ b/test/pleroma/reverse_proxy_test.exs
@@ -63,11 +63,7 @@ defmodule Pleroma.ReverseProxyTest do
|> Plug.Conn.put_req_header("user-agent", "fake/1.0")
|> ReverseProxy.call("/user-agent")
- # Convert the response to a map without relying on json_response
- body = conn.resp_body
- assert conn.status == 200
- response = Jason.decode!(body)
- assert response == %{"user-agent" => Pleroma.Application.user_agent()}
+ assert json_response(conn, 200) == %{"user-agent" => Pleroma.Application.user_agent()}
end
test "closed connection", %{conn: conn} do
@@ -142,14 +138,11 @@ defmodule Pleroma.ReverseProxyTest do
test "common", %{conn: conn} do
ClientMock
|> expect(:request, fn :head, "/head", _, _, _ ->
- {:ok, 200, [{"content-type", "image/png"}]}
+ {:ok, 200, [{"content-type", "text/html; charset=utf-8"}]}
end)
conn = ReverseProxy.call(Map.put(conn, :method, "HEAD"), "/head")
-
- assert conn.status == 200
- assert Conn.get_resp_header(conn, "content-type") == ["image/png"]
- assert conn.resp_body == ""
+ assert html_response(conn, 200) == ""
end
end
@@ -256,10 +249,7 @@ defmodule Pleroma.ReverseProxyTest do
)
|> ReverseProxy.call("/headers")
- body = conn.resp_body
- assert conn.status == 200
- response = Jason.decode!(body)
- headers = response["headers"]
+ %{"headers" => headers} = json_response(conn, 200)
assert headers["Accept"] == "text/html"
end
@@ -272,10 +262,7 @@ defmodule Pleroma.ReverseProxyTest do
)
|> ReverseProxy.call("/headers")
- body = conn.resp_body
- assert conn.status == 200
- response = Jason.decode!(body)
- headers = response["headers"]
+ %{"headers" => headers} = json_response(conn, 200)
refute headers["Accept-Language"]
end
end
@@ -341,58 +328,4 @@ defmodule Pleroma.ReverseProxyTest do
assert {"content-disposition", "attachment; filename=\"filename.jpg\""} in conn.resp_headers
end
end
-
- describe "content-type sanitisation" do
- test "preserves allowed image type", %{conn: conn} do
- ClientMock
- |> expect(:request, fn :get, "/content", _, _, _ ->
- {:ok, 200, [{"content-type", "image/png"}], %{url: "/content"}}
- end)
- |> expect(:stream_body, fn _ -> :done end)
-
- conn = ReverseProxy.call(conn, "/content")
-
- assert conn.status == 200
- assert Conn.get_resp_header(conn, "content-type") == ["image/png"]
- end
-
- test "preserves allowed video type", %{conn: conn} do
- ClientMock
- |> expect(:request, fn :get, "/content", _, _, _ ->
- {:ok, 200, [{"content-type", "video/mp4"}], %{url: "/content"}}
- end)
- |> expect(:stream_body, fn _ -> :done end)
-
- conn = ReverseProxy.call(conn, "/content")
-
- assert conn.status == 200
- assert Conn.get_resp_header(conn, "content-type") == ["video/mp4"]
- end
-
- test "sanitizes ActivityPub content type", %{conn: conn} do
- ClientMock
- |> expect(:request, fn :get, "/content", _, _, _ ->
- {:ok, 200, [{"content-type", "application/activity+json"}], %{url: "/content"}}
- end)
- |> expect(:stream_body, fn _ -> :done end)
-
- conn = ReverseProxy.call(conn, "/content")
-
- assert conn.status == 200
- assert Conn.get_resp_header(conn, "content-type") == ["application/octet-stream"]
- end
-
- test "sanitizes LD-JSON content type", %{conn: conn} do
- ClientMock
- |> expect(:request, fn :get, "/content", _, _, _ ->
- {:ok, 200, [{"content-type", "application/ld+json"}], %{url: "/content"}}
- end)
- |> expect(:stream_body, fn _ -> :done end)
-
- conn = ReverseProxy.call(conn, "/content")
-
- assert conn.status == 200
- assert Conn.get_resp_header(conn, "content-type") == ["application/octet-stream"]
- end
- end
end
diff --git a/test/pleroma/safe_zip_test.exs b/test/pleroma/safe_zip_test.exs
deleted file mode 100644
index 3312d4e63..000000000
--- a/test/pleroma/safe_zip_test.exs
+++ /dev/null
@@ -1,496 +0,0 @@
-defmodule Pleroma.SafeZipTest do
- # Not making this async because it creates and deletes files
- use ExUnit.Case
-
- alias Pleroma.SafeZip
-
- @fixtures_dir "test/fixtures"
- @tmp_dir "test/zip_tmp"
-
- setup do
- # Ensure tmp directory exists
- File.mkdir_p!(@tmp_dir)
-
- on_exit(fn ->
- # Clean up any files created during tests
- File.rm_rf!(@tmp_dir)
- File.mkdir_p!(@tmp_dir)
- end)
-
- :ok
- end
-
- describe "list_dir_file/1" do
- test "lists files in a valid zip" do
- {:ok, files} = SafeZip.list_dir_file(Path.join(@fixtures_dir, "emojis.zip"))
- assert is_list(files)
- assert length(files) > 0
- end
-
- test "returns an empty list for empty zip" do
- {:ok, files} = SafeZip.list_dir_file(Path.join(@fixtures_dir, "empty.zip"))
- assert files == []
- end
-
- test "returns error for non-existent file" do
- assert {:error, _} = SafeZip.list_dir_file(Path.join(@fixtures_dir, "nonexistent.zip"))
- end
-
- test "only lists regular files, not directories" do
- # Create a zip with both files and directories
- zip_path = create_zip_with_directory()
-
- # List files with SafeZip
- {:ok, files} = SafeZip.list_dir_file(zip_path)
-
- # Verify only regular files are listed, not directories
- assert "file_in_dir/test_file.txt" in files
- assert "root_file.txt" in files
-
- # Directory entries should not be included in the list
- refute "file_in_dir/" in files
- end
- end
-
- describe "contains_all_data?/2" do
- test "returns true when all files are in the archive" do
- # For this test, we'll create our own zip file with known content
- # to ensure we can test the contains_all_data? function properly
- zip_path = create_zip_with_directory()
- archive_data = File.read!(zip_path)
-
- # Check if the archive contains the root file
- # Note: The function expects charlists (Erlang strings) in the MapSet
- assert SafeZip.contains_all_data?(archive_data, MapSet.new([~c"root_file.txt"]))
- end
-
- test "returns false when files are missing" do
- archive_path = Path.join(@fixtures_dir, "emojis.zip")
- archive_data = File.read!(archive_path)
-
- # Create a MapSet with non-existent files
- fset = MapSet.new([~c"nonexistent.txt"])
-
- refute SafeZip.contains_all_data?(archive_data, fset)
- end
-
- test "returns false for invalid archive data" do
- refute SafeZip.contains_all_data?("invalid data", MapSet.new([~c"file.txt"]))
- end
-
- test "only checks for regular files, not directories" do
- # Create a zip with both files and directories
- zip_path = create_zip_with_directory()
- archive_data = File.read!(zip_path)
-
- # Check if the archive contains a directory (should return false)
- refute SafeZip.contains_all_data?(archive_data, MapSet.new([~c"file_in_dir/"]))
-
- # For this test, we'll manually check if the file exists in the archive
- # by extracting it and verifying it exists
- extract_dir = Path.join(@tmp_dir, "extract_check")
- File.mkdir_p!(extract_dir)
- {:ok, files} = SafeZip.unzip_file(zip_path, extract_dir)
-
- # Verify the root file was extracted
- assert Enum.any?(files, fn file ->
- Path.basename(file) == "root_file.txt"
- end)
-
- # Verify the file exists on disk
- assert File.exists?(Path.join(extract_dir, "root_file.txt"))
- end
- end
-
- describe "zip/4" do
- test "creates a zip file on disk" do
- # Create a test file
- test_file_path = Path.join(@tmp_dir, "test_file.txt")
- File.write!(test_file_path, "test content")
-
- # Create a zip file
- zip_path = Path.join(@tmp_dir, "test.zip")
- assert {:ok, ^zip_path} = SafeZip.zip(zip_path, ["test_file.txt"], @tmp_dir, false)
-
- # Verify the zip file exists
- assert File.exists?(zip_path)
- end
-
- test "creates a zip file in memory" do
- # Create a test file
- test_file_path = Path.join(@tmp_dir, "test_file.txt")
- File.write!(test_file_path, "test content")
-
- # Create a zip file in memory
- zip_name = Path.join(@tmp_dir, "test.zip")
-
- assert {:ok, {^zip_name, zip_data}} =
- SafeZip.zip(zip_name, ["test_file.txt"], @tmp_dir, true)
-
- # Verify the zip data is binary
- assert is_binary(zip_data)
- end
-
- test "returns error for unsafe paths" do
- # Try to zip a file with path traversal
- assert {:error, _} =
- SafeZip.zip(
- Path.join(@tmp_dir, "test.zip"),
- ["../fixtures/test.txt"],
- @tmp_dir,
- false
- )
- end
-
- test "can create zip with directories" do
- # Create a directory structure
- dir_path = Path.join(@tmp_dir, "test_dir")
- File.mkdir_p!(dir_path)
-
- file_in_dir_path = Path.join(dir_path, "file_in_dir.txt")
- File.write!(file_in_dir_path, "file in directory")
-
- # Create a zip file
- zip_path = Path.join(@tmp_dir, "dir_test.zip")
-
- assert {:ok, ^zip_path} =
- SafeZip.zip(
- zip_path,
- ["test_dir/file_in_dir.txt"],
- @tmp_dir,
- false
- )
-
- # Verify the zip file exists
- assert File.exists?(zip_path)
-
- # Extract and verify the directory structure is preserved
- extract_dir = Path.join(@tmp_dir, "extract")
- {:ok, files} = SafeZip.unzip_file(zip_path, extract_dir)
-
- # Check if the file path is in the list, accounting for possible full paths
- assert Enum.any?(files, fn file ->
- String.ends_with?(file, "file_in_dir.txt")
- end)
-
- # Verify the file exists in the expected location
- assert File.exists?(Path.join([extract_dir, "test_dir", "file_in_dir.txt"]))
- end
- end
-
- describe "unzip_file/3" do
- test "extracts files from a zip archive" do
- archive_path = Path.join(@fixtures_dir, "emojis.zip")
-
- # Extract the archive
- assert {:ok, files} = SafeZip.unzip_file(archive_path, @tmp_dir)
-
- # Verify files were extracted
- assert is_list(files)
- assert length(files) > 0
-
- # Verify at least one file exists
- first_file = List.first(files)
-
- # Simply check that the file exists in the tmp directory
- assert File.exists?(first_file)
- end
-
- test "extracts specific files from a zip archive" do
- archive_path = Path.join(@fixtures_dir, "emojis.zip")
-
- # Get list of files in the archive
- {:ok, all_files} = SafeZip.list_dir_file(archive_path)
- file_to_extract = List.first(all_files)
-
- # Extract only one file
- assert {:ok, [extracted_file]} =
- SafeZip.unzip_file(archive_path, @tmp_dir, [file_to_extract])
-
- # Verify only the specified file was extracted
- assert Path.basename(extracted_file) == Path.basename(file_to_extract)
-
- # Check that the file exists in the tmp directory
- assert File.exists?(Path.join(@tmp_dir, Path.basename(file_to_extract)))
- end
-
- test "returns error for invalid zip file" do
- invalid_path = Path.join(@tmp_dir, "invalid.zip")
- File.write!(invalid_path, "not a zip file")
-
- assert {:error, _} = SafeZip.unzip_file(invalid_path, @tmp_dir)
- end
-
- test "creates directories when extracting files in subdirectories" do
- # Create a zip with files in subdirectories
- zip_path = create_zip_with_directory()
-
- # Extract the archive
- assert {:ok, files} = SafeZip.unzip_file(zip_path, @tmp_dir)
-
- # Verify files were extracted - handle both relative and absolute paths
- assert Enum.any?(files, fn file ->
- Path.basename(file) == "test_file.txt" &&
- String.contains?(file, "file_in_dir")
- end)
-
- assert Enum.any?(files, fn file ->
- Path.basename(file) == "root_file.txt"
- end)
-
- # Verify directory was created
- dir_path = Path.join(@tmp_dir, "file_in_dir")
- assert File.exists?(dir_path)
- assert File.dir?(dir_path)
-
- # Verify file in directory was extracted
- file_path = Path.join(dir_path, "test_file.txt")
- assert File.exists?(file_path)
- end
- end
-
- describe "unzip_data/3" do
- test "extracts files from zip data" do
- archive_path = Path.join(@fixtures_dir, "emojis.zip")
- archive_data = File.read!(archive_path)
-
- # Extract the archive from data
- assert {:ok, files} = SafeZip.unzip_data(archive_data, @tmp_dir)
-
- # Verify files were extracted
- assert is_list(files)
- assert length(files) > 0
-
- # Verify at least one file exists
- first_file = List.first(files)
-
- # Simply check that the file exists in the tmp directory
- assert File.exists?(first_file)
- end
-
- test "extracts specific files from zip data" do
- archive_path = Path.join(@fixtures_dir, "emojis.zip")
- archive_data = File.read!(archive_path)
-
- # Get list of files in the archive
- {:ok, all_files} = SafeZip.list_dir_file(archive_path)
- file_to_extract = List.first(all_files)
-
- # Extract only one file
- assert {:ok, extracted_files} =
- SafeZip.unzip_data(archive_data, @tmp_dir, [file_to_extract])
-
- # Verify only the specified file was extracted
- assert Enum.any?(extracted_files, fn path ->
- Path.basename(path) == Path.basename(file_to_extract)
- end)
-
- # Simply check that the file exists in the tmp directory
- assert File.exists?(Path.join(@tmp_dir, Path.basename(file_to_extract)))
- end
-
- test "returns error for invalid zip data" do
- assert {:error, _} = SafeZip.unzip_data("not a zip file", @tmp_dir)
- end
-
- test "creates directories when extracting files in subdirectories from data" do
- # Create a zip with files in subdirectories
- zip_path = create_zip_with_directory()
- archive_data = File.read!(zip_path)
-
- # Extract the archive from data
- assert {:ok, files} = SafeZip.unzip_data(archive_data, @tmp_dir)
-
- # Verify files were extracted - handle both relative and absolute paths
- assert Enum.any?(files, fn file ->
- Path.basename(file) == "test_file.txt" &&
- String.contains?(file, "file_in_dir")
- end)
-
- assert Enum.any?(files, fn file ->
- Path.basename(file) == "root_file.txt"
- end)
-
- # Verify directory was created
- dir_path = Path.join(@tmp_dir, "file_in_dir")
- assert File.exists?(dir_path)
- assert File.dir?(dir_path)
-
- # Verify file in directory was extracted
- file_path = Path.join(dir_path, "test_file.txt")
- assert File.exists?(file_path)
- end
- end
-
- # Security tests
- describe "security checks" do
- test "prevents path traversal in zip extraction" do
- # Create a malicious zip file with path traversal
- malicious_zip_path = create_malicious_zip_with_path_traversal()
-
- # Try to extract it with SafeZip
- assert {:error, _} = SafeZip.unzip_file(malicious_zip_path, @tmp_dir)
-
- # Verify the file was not extracted outside the target directory
- refute File.exists?(Path.join(Path.dirname(@tmp_dir), "traversal_attempt.txt"))
- end
-
- test "prevents directory traversal in zip listing" do
- # Create a malicious zip file with path traversal
- malicious_zip_path = create_malicious_zip_with_path_traversal()
-
- # Try to list files with SafeZip
- assert {:error, _} = SafeZip.list_dir_file(malicious_zip_path)
- end
-
- test "prevents path traversal in zip data extraction" do
- # Create a malicious zip file with path traversal
- malicious_zip_path = create_malicious_zip_with_path_traversal()
- malicious_data = File.read!(malicious_zip_path)
-
- # Try to extract it with SafeZip
- assert {:error, _} = SafeZip.unzip_data(malicious_data, @tmp_dir)
-
- # Verify the file was not extracted outside the target directory
- refute File.exists?(Path.join(Path.dirname(@tmp_dir), "traversal_attempt.txt"))
- end
-
- test "handles zip bomb attempts" do
- # Create a zip bomb (a zip with many files or large files)
- zip_bomb_path = create_zip_bomb()
-
- # The SafeZip module should handle this gracefully
- # Either by successfully extracting it (if it's not too large)
- # or by returning an error (if it detects a potential zip bomb)
- result = SafeZip.unzip_file(zip_bomb_path, @tmp_dir)
-
- case result do
- {:ok, _} ->
- # If it successfully extracts, make sure it didn't fill up the disk
- # This is a simple check to ensure the extraction was controlled
- assert File.exists?(@tmp_dir)
-
- {:error, _} ->
- # If it returns an error, that's also acceptable
- # The important thing is that it doesn't crash or hang
- assert true
- end
- end
-
- test "handles deeply nested directory structures" do
- # Create a zip with deeply nested directories
- deep_nest_path = create_deeply_nested_zip()
-
- # The SafeZip module should handle this gracefully
- result = SafeZip.unzip_file(deep_nest_path, @tmp_dir)
-
- case result do
- {:ok, files} ->
- # If it successfully extracts, verify the files were extracted
- assert is_list(files)
- assert length(files) > 0
-
- {:error, _} ->
- # If it returns an error, that's also acceptable
- # The important thing is that it doesn't crash or hang
- assert true
- end
- end
- end
-
- # Helper functions to create test fixtures
-
- # Creates a zip file with a path traversal attempt
- defp create_malicious_zip_with_path_traversal do
- malicious_zip_path = Path.join(@tmp_dir, "path_traversal.zip")
-
- # Create a file to include in the zip
- test_file_path = Path.join(@tmp_dir, "test_file.txt")
- File.write!(test_file_path, "malicious content")
-
- # Use Erlang's zip module directly to create a zip with path traversal
- {:ok, charlist_path} =
- :zip.create(
- String.to_charlist(malicious_zip_path),
- [{String.to_charlist("../traversal_attempt.txt"), File.read!(test_file_path)}]
- )
-
- to_string(charlist_path)
- end
-
- # Creates a zip file with directory entries
- defp create_zip_with_directory do
- zip_path = Path.join(@tmp_dir, "with_directory.zip")
-
- # Create files to include in the zip
- root_file_path = Path.join(@tmp_dir, "root_file.txt")
- File.write!(root_file_path, "root file content")
-
- # Create a directory and a file in it
- dir_path = Path.join(@tmp_dir, "file_in_dir")
- File.mkdir_p!(dir_path)
-
- file_in_dir_path = Path.join(dir_path, "test_file.txt")
- File.write!(file_in_dir_path, "file in directory content")
-
- # Use Erlang's zip module to create a zip with directory structure
- {:ok, charlist_path} =
- :zip.create(
- String.to_charlist(zip_path),
- [
- {String.to_charlist("root_file.txt"), File.read!(root_file_path)},
- {String.to_charlist("file_in_dir/test_file.txt"), File.read!(file_in_dir_path)}
- ]
- )
-
- to_string(charlist_path)
- end
-
- # Creates a zip bomb (a zip with many small files)
- defp create_zip_bomb do
- zip_path = Path.join(@tmp_dir, "zip_bomb.zip")
-
- # Create a small file to duplicate many times
- small_file_path = Path.join(@tmp_dir, "small_file.txt")
- File.write!(small_file_path, String.duplicate("A", 100))
-
- # Create a list of many files to include in the zip
- file_entries =
- for i <- 1..100 do
- {String.to_charlist("file_#{i}.txt"), File.read!(small_file_path)}
- end
-
- # Use Erlang's zip module to create a zip with many files
- {:ok, charlist_path} =
- :zip.create(
- String.to_charlist(zip_path),
- file_entries
- )
-
- to_string(charlist_path)
- end
-
- # Creates a zip with deeply nested directories
- defp create_deeply_nested_zip do
- zip_path = Path.join(@tmp_dir, "deep_nest.zip")
-
- # Create a file to include in the zip
- file_content = "test content"
-
- # Create a list of deeply nested files
- file_entries =
- for i <- 1..10 do
- nested_path = Enum.reduce(1..i, "nested", fn j, acc -> "#{acc}/level_#{j}" end)
- {String.to_charlist("#{nested_path}/file.txt"), file_content}
- end
-
- # Use Erlang's zip module to create a zip with deeply nested directories
- {:ok, charlist_path} =
- :zip.create(
- String.to_charlist(zip_path),
- file_entries
- )
-
- to_string(charlist_path)
- end
-end
diff --git a/test/pleroma/upload/filter/analyze_metadata_test.exs b/test/pleroma/upload/filter/analyze_metadata_test.exs
index 6e1f2afaf..e4ac673b2 100644
--- a/test/pleroma/upload/filter/analyze_metadata_test.exs
+++ b/test/pleroma/upload/filter/analyze_metadata_test.exs
@@ -34,20 +34,6 @@ defmodule Pleroma.Upload.Filter.AnalyzeMetadataTest do
assert meta.blurhash == "eXJi-E:SwCEm5rCmn$+YWYn+15K#5A$xxCi{SiV]s*W:Efa#s.jE-T"
end
- test "it gets dimensions for grayscale images" do
- upload = %Pleroma.Upload{
- name: "break_analyze.png",
- content_type: "image/png",
- path: Path.absname("test/fixtures/break_analyze.png"),
- tempfile: Path.absname("test/fixtures/break_analyze.png")
- }
-
- {:ok, :filtered, meta} = AnalyzeMetadata.filter(upload)
-
- assert %{width: 1410, height: 2048} = meta
- assert is_nil(meta.blurhash)
- end
-
test "adds the dimensions for videos" do
upload = %Pleroma.Upload{
name: "coolvideo.mp4",
diff --git a/test/pleroma/upload/filter/anonymize_filename_test.exs b/test/pleroma/upload/filter/anonymize_filename_test.exs
index 5dae62003..9b94b91c3 100644
--- a/test/pleroma/upload/filter/anonymize_filename_test.exs
+++ b/test/pleroma/upload/filter/anonymize_filename_test.exs
@@ -3,10 +3,8 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Upload.Filter.AnonymizeFilenameTest do
- use Pleroma.DataCase, async: true
+ use Pleroma.DataCase
- import Mox
- alias Pleroma.StaticStubbedConfigMock, as: ConfigMock
alias Pleroma.Upload
setup do
@@ -21,26 +19,21 @@ defmodule Pleroma.Upload.Filter.AnonymizeFilenameTest do
%{upload_file: upload_file}
end
- test "it replaces filename on pre-defined text", %{upload_file: upload_file} do
- ConfigMock
- |> stub(:get, fn [Upload.Filter.AnonymizeFilename, :text] -> "custom-file.png" end)
+ setup do: clear_config([Pleroma.Upload.Filter.AnonymizeFilename, :text])
+ test "it replaces filename on pre-defined text", %{upload_file: upload_file} do
+ clear_config([Upload.Filter.AnonymizeFilename, :text], "custom-file.png")
{:ok, :filtered, %Upload{name: name}} = Upload.Filter.AnonymizeFilename.filter(upload_file)
assert name == "custom-file.png"
end
test "it replaces filename on pre-defined text expression", %{upload_file: upload_file} do
- ConfigMock
- |> stub(:get, fn [Upload.Filter.AnonymizeFilename, :text] -> "custom-file.{extension}" end)
-
+ clear_config([Upload.Filter.AnonymizeFilename, :text], "custom-file.{extension}")
{:ok, :filtered, %Upload{name: name}} = Upload.Filter.AnonymizeFilename.filter(upload_file)
assert name == "custom-file.jpg"
end
test "it replaces filename on random text", %{upload_file: upload_file} do
- ConfigMock
- |> stub(:get, fn [Upload.Filter.AnonymizeFilename, :text] -> nil end)
-
{:ok, :filtered, %Upload{name: name}} = Upload.Filter.AnonymizeFilename.filter(upload_file)
assert <<_::bytes-size(14)>> <> ".jpg" = name
refute name == "an… image.jpg"
diff --git a/test/pleroma/upload/filter/mogrifun_test.exs b/test/pleroma/upload/filter/mogrifun_test.exs
index 77a9c1666..bf9b65589 100644
--- a/test/pleroma/upload/filter/mogrifun_test.exs
+++ b/test/pleroma/upload/filter/mogrifun_test.exs
@@ -3,10 +3,9 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Upload.Filter.MogrifunTest do
- use Pleroma.DataCase, async: true
- import Mox
+ use Pleroma.DataCase
+ import Mock
- alias Pleroma.MogrifyMock
alias Pleroma.Upload
alias Pleroma.Upload.Filter
@@ -23,12 +22,23 @@ defmodule Pleroma.Upload.Filter.MogrifunTest do
tempfile: Path.absname("test/fixtures/image_tmp.jpg")
}
- MogrifyMock
- |> stub(:open, fn _file -> %{} end)
- |> stub(:custom, fn _image, _action -> %{} end)
- |> stub(:custom, fn _image, _action, _options -> %{} end)
- |> stub(:save, fn _image, [in_place: true] -> :ok end)
+ task =
+ Task.async(fn ->
+ assert_receive {:apply_filter, {}}, 4_000
+ end)
- assert Filter.Mogrifun.filter(upload) == {:ok, :filtered}
+ with_mocks([
+ {Mogrify, [],
+ [
+ open: fn _f -> %Mogrify.Image{} end,
+ custom: fn _m, _a -> send(task.pid, {:apply_filter, {}}) end,
+ custom: fn _m, _a, _o -> send(task.pid, {:apply_filter, {}}) end,
+ save: fn _f, _o -> :ok end
+ ]}
+ ]) do
+ assert Filter.Mogrifun.filter(upload) == {:ok, :filtered}
+ end
+
+ Task.await(task)
end
end
diff --git a/test/pleroma/upload/filter/mogrify_test.exs b/test/pleroma/upload/filter/mogrify_test.exs
index f8ed6e8dd..208da57ca 100644
--- a/test/pleroma/upload/filter/mogrify_test.exs
+++ b/test/pleroma/upload/filter/mogrify_test.exs
@@ -3,18 +3,13 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Upload.Filter.MogrifyTest do
- use Pleroma.DataCase, async: true
- import Mox
+ use Pleroma.DataCase
+ import Mock
- alias Pleroma.MogrifyMock
- alias Pleroma.StaticStubbedConfigMock, as: ConfigMock
alias Pleroma.Upload.Filter
- setup :verify_on_exit!
-
test "apply mogrify filter" do
- ConfigMock
- |> stub(:get!, fn [Filter.Mogrify, :args] -> [{"tint", "40"}] end)
+ clear_config(Filter.Mogrify, args: [{"tint", "40"}])
File.cp!(
"test/fixtures/image.jpg",
@@ -28,11 +23,19 @@ defmodule Pleroma.Upload.Filter.MogrifyTest do
tempfile: Path.absname("test/fixtures/image_tmp.jpg")
}
- MogrifyMock
- |> expect(:open, fn _file -> %{} end)
- |> expect(:custom, fn _image, "tint", "40" -> %{} end)
- |> expect(:save, fn _image, [in_place: true] -> :ok end)
+ task =
+ Task.async(fn ->
+ assert_receive {:apply_filter, {_, "tint", "40"}}, 4_000
+ end)
- assert Filter.Mogrify.filter(upload) == {:ok, :filtered}
+ with_mock Mogrify,
+ open: fn _f -> %Mogrify.Image{} end,
+ custom: fn _m, _a -> :ok end,
+ custom: fn m, a, o -> send(task.pid, {:apply_filter, {m, a, o}}) end,
+ save: fn _f, _o -> :ok end do
+ assert Filter.Mogrify.filter(upload) == {:ok, :filtered}
+ end
+
+ Task.await(task)
end
end
diff --git a/test/pleroma/upload/filter_test.exs b/test/pleroma/upload/filter_test.exs
index a369a723a..706fc9ac7 100644
--- a/test/pleroma/upload/filter_test.exs
+++ b/test/pleroma/upload/filter_test.exs
@@ -5,13 +5,12 @@
defmodule Pleroma.Upload.FilterTest do
use Pleroma.DataCase
- import Mox
- alias Pleroma.StaticStubbedConfigMock, as: ConfigMock
alias Pleroma.Upload.Filter
+ setup do: clear_config([Pleroma.Upload.Filter.AnonymizeFilename, :text])
+
test "applies filters" do
- ConfigMock
- |> stub(:get, fn [Pleroma.Upload.Filter.AnonymizeFilename, :text] -> "custom-file.png" end)
+ clear_config([Pleroma.Upload.Filter.AnonymizeFilename, :text], "custom-file.png")
File.cp!(
"test/fixtures/image.jpg",
diff --git a/test/pleroma/user/backup_test.exs b/test/pleroma/user/backup_test.exs
index f4b92adf8..24fe09f7e 100644
--- a/test/pleroma/user/backup_test.exs
+++ b/test/pleroma/user/backup_test.exs
@@ -185,13 +185,13 @@ defmodule Pleroma.User.BackupTest do
%{"@language" => "und"}
],
"bookmarks" => "bookmarks.json",
- "followers" => "followers.json",
- "following" => "following.json",
+ "followers" => "http://cofe.io/users/cofe/followers",
+ "following" => "http://cofe.io/users/cofe/following",
"id" => "http://cofe.io/users/cofe",
"inbox" => "http://cofe.io/users/cofe/inbox",
"likes" => "likes.json",
"name" => "Cofe",
- "outbox" => "outbox.json",
+ "outbox" => "http://cofe.io/users/cofe/outbox",
"preferredUsername" => "cofe",
"publicKey" => %{
"id" => "http://cofe.io/users/cofe#main-key",
diff --git a/test/pleroma/user_relationship_test.exs b/test/pleroma/user_relationship_test.exs
index 5b43cb2b6..7d205a746 100644
--- a/test/pleroma/user_relationship_test.exs
+++ b/test/pleroma/user_relationship_test.exs
@@ -3,12 +3,11 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.UserRelationshipTest do
- alias Pleroma.DateTimeMock
alias Pleroma.UserRelationship
- use Pleroma.DataCase, async: true
+ use Pleroma.DataCase, async: false
- import Mox
+ import Mock
import Pleroma.Factory
describe "*_exists?/2" do
@@ -53,9 +52,6 @@ defmodule Pleroma.UserRelationshipTest do
end
test "creates user relationship record if it doesn't exist", %{users: [user1, user2]} do
- DateTimeMock
- |> stub_with(Pleroma.DateTime.Impl)
-
for relationship_type <- [
:block,
:mute,
@@ -84,15 +80,13 @@ defmodule Pleroma.UserRelationshipTest do
end
test "if record already exists, returns it", %{users: [user1, user2]} do
- fixed_datetime = ~N[2017-03-17 17:09:58]
+ user_block =
+ with_mock NaiveDateTime, [:passthrough], utc_now: fn -> ~N[2017-03-17 17:09:58] end do
+ {:ok, %{inserted_at: ~N[2017-03-17 17:09:58]}} =
+ UserRelationship.create_block(user1, user2)
+ end
- Pleroma.DateTimeMock
- |> expect(:utc_now, 2, fn -> fixed_datetime end)
-
- {:ok, %{inserted_at: ^fixed_datetime}} = UserRelationship.create_block(user1, user2)
-
- # Test the idempotency without caring about the exact time
- assert {:ok, _} = UserRelationship.create_block(user1, user2)
+ assert user_block == UserRelationship.create_block(user1, user2)
end
end
diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs
index 176e70ef9..06afc0709 100644
--- a/test/pleroma/user_test.exs
+++ b/test/pleroma/user_test.exs
@@ -20,7 +20,7 @@ defmodule Pleroma.UserTest do
import Swoosh.TestAssertions
setup do
- Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Test.StaticConfig)
+ Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
:ok
end
@@ -2405,8 +2405,8 @@ defmodule Pleroma.UserTest do
other_user =
insert(:user,
local: false,
- follower_address: "https://remote.org/users/masto_closed/followers",
- following_address: "https://remote.org/users/masto_closed/following"
+ follower_address: "http://localhost:4001/users/masto_closed/followers",
+ following_address: "http://localhost:4001/users/masto_closed/following"
)
assert other_user.following_count == 0
@@ -2426,8 +2426,8 @@ defmodule Pleroma.UserTest do
other_user =
insert(:user,
local: false,
- follower_address: "https://remote.org/users/masto_closed/followers",
- following_address: "https://remote.org/users/masto_closed/following"
+ follower_address: "http://localhost:4001/users/masto_closed/followers",
+ following_address: "http://localhost:4001/users/masto_closed/following"
)
assert other_user.following_count == 0
@@ -2447,8 +2447,8 @@ defmodule Pleroma.UserTest do
other_user =
insert(:user,
local: false,
- follower_address: "https://remote.org/users/masto_closed/followers",
- following_address: "https://remote.org/users/masto_closed/following"
+ follower_address: "http://localhost:4001/users/masto_closed/followers",
+ following_address: "http://localhost:4001/users/masto_closed/following"
)
assert other_user.following_count == 0
@@ -2919,74 +2919,4 @@ defmodule Pleroma.UserTest do
assert [%{"verified_at" => ^verified_at}] = user.fields
end
-
- describe "follow_hashtag/2" do
- test "should follow a hashtag" do
- user = insert(:user)
- hashtag = insert(:hashtag)
-
- assert {:ok, _} = user |> User.follow_hashtag(hashtag)
-
- user = User.get_cached_by_ap_id(user.ap_id)
-
- assert user.followed_hashtags |> Enum.count() == 1
- assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end)
- end
-
- test "should not follow a hashtag twice" do
- user = insert(:user)
- hashtag = insert(:hashtag)
-
- assert {:ok, _} = user |> User.follow_hashtag(hashtag)
-
- assert {:ok, _} = user |> User.follow_hashtag(hashtag)
-
- user = User.get_cached_by_ap_id(user.ap_id)
-
- assert user.followed_hashtags |> Enum.count() == 1
- assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end)
- end
-
- test "can follow multiple hashtags" do
- user = insert(:user)
- hashtag = insert(:hashtag)
- other_hashtag = insert(:hashtag)
-
- assert {:ok, _} = user |> User.follow_hashtag(hashtag)
- assert {:ok, _} = user |> User.follow_hashtag(other_hashtag)
-
- user = User.get_cached_by_ap_id(user.ap_id)
-
- assert user.followed_hashtags |> Enum.count() == 2
- assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end)
- assert other_hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end)
- end
- end
-
- describe "unfollow_hashtag/2" do
- test "should unfollow a hashtag" do
- user = insert(:user)
- hashtag = insert(:hashtag)
-
- assert {:ok, _} = user |> User.follow_hashtag(hashtag)
- assert {:ok, _} = user |> User.unfollow_hashtag(hashtag)
-
- user = User.get_cached_by_ap_id(user.ap_id)
-
- assert user.followed_hashtags |> Enum.count() == 0
- end
-
- test "should not error when trying to unfollow a hashtag twice" do
- user = insert(:user)
- hashtag = insert(:hashtag)
-
- assert {:ok, _} = user |> User.follow_hashtag(hashtag)
- assert {:ok, _} = user |> User.unfollow_hashtag(hashtag)
- assert {:ok, _} = user |> User.unfollow_hashtag(hashtag)
-
- user = User.get_cached_by_ap_id(user.ap_id)
-
- assert user.followed_hashtags |> Enum.count() == 0
- end
- end
end
diff --git a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
index 46b3d5f0d..d4175b56f 100644
--- a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
+++ b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
@@ -26,7 +26,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
require Pleroma.Constants
setup do
- Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Test.StaticConfig)
+ Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
:ok
end
@@ -1344,11 +1344,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
end
describe "GET /users/:nickname/outbox" do
- setup do
- Mox.stub_with(Pleroma.StaticStubbedConfigMock, Pleroma.Config)
- :ok
- end
-
test "it paginates correctly", %{conn: conn} do
user = insert(:user)
conn = assign(conn, :user, user)
@@ -1437,22 +1432,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert %{"orderedItems" => []} = resp
end
- test "it does not return a local note activity when C2S API is disabled", %{conn: conn} do
- clear_config([:activitypub, :client_api_enabled], false)
- user = insert(:user)
- reader = insert(:user)
- {:ok, _note_activity} = CommonAPI.post(user, %{status: "mew mew", visibility: "local"})
-
- resp =
- conn
- |> assign(:user, reader)
- |> put_req_header("accept", "application/activity+json")
- |> get("/users/#{user.nickname}/outbox?page=true")
- |> json_response(200)
-
- assert %{"orderedItems" => []} = resp
- end
-
test "it returns a note activity in a collection", %{conn: conn} do
note_activity = insert(:note_activity)
note_object = Object.normalize(note_activity, fetch: false)
@@ -1504,35 +1483,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert [answer_outbox] = outbox_get["orderedItems"]
assert answer_outbox["id"] == activity.data["id"]
end
-
- test "it works with authorized fetch forced when authenticated" do
- clear_config([:activitypub, :authorized_fetch_mode], true)
-
- user = insert(:user)
- outbox_endpoint = user.ap_id <> "/outbox"
-
- conn =
- build_conn()
- |> assign(:user, user)
- |> put_req_header("accept", "application/activity+json")
- |> get(outbox_endpoint)
-
- assert json_response(conn, 200)
- end
-
- test "it fails with authorized fetch forced when unauthenticated", %{conn: conn} do
- clear_config([:activitypub, :authorized_fetch_mode], true)
-
- user = insert(:user)
- outbox_endpoint = user.ap_id <> "/outbox"
-
- conn =
- conn
- |> put_req_header("accept", "application/activity+json")
- |> get(outbox_endpoint)
-
- assert response(conn, 401)
- end
end
describe "POST /users/:nickname/outbox (C2S)" do
@@ -1694,28 +1644,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert json_response(conn, 403)
end
- test "it rejects update activity of object from other actor", %{conn: conn} do
- note_activity = insert(:note_activity)
- note_object = Object.normalize(note_activity, fetch: false)
- user = insert(:user)
-
- data = %{
- type: "Update",
- object: %{
- id: note_object.data["id"]
- }
- }
-
- conn =
- conn
- |> assign(:user, user)
- |> put_req_header("content-type", "application/activity+json")
- |> post("/users/#{user.nickname}/outbox", data)
-
- assert json_response(conn, 400)
- assert note_object == Object.normalize(note_activity, fetch: false)
- end
-
test "it increases like count when receiving a like action", %{conn: conn} do
note_activity = insert(:note_activity)
note_object = Object.normalize(note_activity, fetch: false)
@@ -2203,30 +2131,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|> post("/api/ap/upload_media", %{"file" => image, "description" => desc})
|> json_response(403)
end
-
- test "they don't work when C2S API is disabled", %{conn: conn} do
- clear_config([:activitypub, :client_api_enabled], false)
-
- user = insert(:user)
-
- assert conn
- |> assign(:user, user)
- |> get("/api/ap/whoami")
- |> response(403)
-
- desc = "Description of the image"
-
- image = %Plug.Upload{
- content_type: "image/jpeg",
- path: Path.absname("test/fixtures/image.jpg"),
- filename: "an_image.jpg"
- }
-
- assert conn
- |> assign(:user, user)
- |> post("/api/ap/upload_media", %{"file" => image, "description" => desc})
- |> response(403)
- end
end
test "pinned collection", %{conn: conn} do
diff --git a/test/pleroma/web/activity_pub/activity_pub_test.exs b/test/pleroma/web/activity_pub/activity_pub_test.exs
index dbc3aa532..72222ae88 100644
--- a/test/pleroma/web/activity_pub/activity_pub_test.exs
+++ b/test/pleroma/web/activity_pub/activity_pub_test.exs
@@ -867,33 +867,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
end
end
- describe "fetch activities for followed hashtags" do
- test "it should return public activities that reference a given hashtag" do
- hashtag = insert(:hashtag, name: "tenshi")
- user = insert(:user)
- other_user = insert(:user)
-
- {:ok, normally_visible} =
- CommonAPI.post(other_user, %{status: "hello :)", visibility: "public"})
-
- {:ok, public} = CommonAPI.post(user, %{status: "maji #tenshi", visibility: "public"})
- {:ok, _unrelated} = CommonAPI.post(user, %{status: "dai #tensh", visibility: "public"})
- {:ok, unlisted} = CommonAPI.post(user, %{status: "maji #tenshi", visibility: "unlisted"})
- {:ok, _private} = CommonAPI.post(user, %{status: "maji #tenshi", visibility: "private"})
-
- activities =
- ActivityPub.fetch_activities([other_user.follower_address], %{
- followed_hashtags: [hashtag.id]
- })
-
- assert length(activities) == 3
- normal_id = normally_visible.id
- public_id = public.id
- unlisted_id = unlisted.id
- assert [%{id: ^normal_id}, %{id: ^public_id}, %{id: ^unlisted_id}] = activities
- end
- end
-
describe "fetch activities in context" do
test "retrieves activities that have a given context" do
{:ok, activity} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})
@@ -1785,8 +1758,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
user =
insert(:user,
local: false,
- follower_address: "https://remote.org/users/fuser2/followers",
- following_address: "https://remote.org/users/fuser2/following"
+ follower_address: "http://localhost:4001/users/fuser2/followers",
+ following_address: "http://localhost:4001/users/fuser2/following"
)
{:ok, info} = ActivityPub.fetch_follow_information_for_user(user)
@@ -1797,7 +1770,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
test "detects hidden followers" do
mock(fn env ->
case env.url do
- "https://remote.org/users/masto_closed/followers?page=1" ->
+ "http://localhost:4001/users/masto_closed/followers?page=1" ->
%Tesla.Env{status: 403, body: ""}
_ ->
@@ -1808,8 +1781,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
user =
insert(:user,
local: false,
- follower_address: "https://remote.org/users/masto_closed/followers",
- following_address: "https://remote.org/users/masto_closed/following"
+ follower_address: "http://localhost:4001/users/masto_closed/followers",
+ following_address: "http://localhost:4001/users/masto_closed/following"
)
{:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
@@ -1820,7 +1793,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
test "detects hidden follows" do
mock(fn env ->
case env.url do
- "https://remote.org/users/masto_closed/following?page=1" ->
+ "http://localhost:4001/users/masto_closed/following?page=1" ->
%Tesla.Env{status: 403, body: ""}
_ ->
@@ -1831,8 +1804,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
user =
insert(:user,
local: false,
- follower_address: "https://remote.org/users/masto_closed/followers",
- following_address: "https://remote.org/users/masto_closed/following"
+ follower_address: "http://localhost:4001/users/masto_closed/followers",
+ following_address: "http://localhost:4001/users/masto_closed/following"
)
{:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
@@ -1844,8 +1817,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
user =
insert(:user,
local: false,
- follower_address: "https://remote.org/followers/fuser3",
- following_address: "https://remote.org/following/fuser3"
+ follower_address: "http://localhost:8080/followers/fuser3",
+ following_address: "http://localhost:8080/following/fuser3"
)
{:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
@@ -1858,28 +1831,28 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
test "doesn't crash when follower and following counters are hidden" do
mock(fn env ->
case env.url do
- "https://remote.org/users/masto_hidden_counters/following" ->
+ "http://localhost:4001/users/masto_hidden_counters/following" ->
json(
%{
"@context" => "https://www.w3.org/ns/activitystreams",
- "id" => "https://remote.org/users/masto_hidden_counters/followers"
+ "id" => "http://localhost:4001/users/masto_hidden_counters/followers"
},
headers: HttpRequestMock.activitypub_object_headers()
)
- "https://remote.org/users/masto_hidden_counters/following?page=1" ->
+ "http://localhost:4001/users/masto_hidden_counters/following?page=1" ->
%Tesla.Env{status: 403, body: ""}
- "https://remote.org/users/masto_hidden_counters/followers" ->
+ "http://localhost:4001/users/masto_hidden_counters/followers" ->
json(
%{
"@context" => "https://www.w3.org/ns/activitystreams",
- "id" => "https://remote.org/users/masto_hidden_counters/following"
+ "id" => "http://localhost:4001/users/masto_hidden_counters/following"
},
headers: HttpRequestMock.activitypub_object_headers()
)
- "https://remote.org/users/masto_hidden_counters/followers?page=1" ->
+ "http://localhost:4001/users/masto_hidden_counters/followers?page=1" ->
%Tesla.Env{status: 403, body: ""}
end
end)
@@ -1887,8 +1860,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
user =
insert(:user,
local: false,
- follower_address: "https://remote.org/users/masto_hidden_counters/followers",
- following_address: "https://remote.org/users/masto_hidden_counters/following"
+ follower_address: "http://localhost:4001/users/masto_hidden_counters/followers",
+ following_address: "http://localhost:4001/users/masto_hidden_counters/following"
)
{:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
diff --git a/test/pleroma/web/activity_pub/mrf/fo_direct_reply_test.exs b/test/pleroma/web/activity_pub/mrf/fo_direct_reply_test.exs
new file mode 100644
index 000000000..2d6af3b68
--- /dev/null
+++ b/test/pleroma/web/activity_pub/mrf/fo_direct_reply_test.exs
@@ -0,0 +1,117 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.FODirectReplyTest do
+ use Pleroma.DataCase
+ import Pleroma.Factory
+
+ require Pleroma.Constants
+
+ alias Pleroma.Object
+ alias Pleroma.Web.ActivityPub.MRF.FODirectReply
+ alias Pleroma.Web.CommonAPI
+
+ test "replying to followers-only/private is changed to direct" do
+ batman = insert(:user, nickname: "batman")
+ robin = insert(:user, nickname: "robin")
+
+ {:ok, post} =
+ CommonAPI.post(batman, %{
+ status: "Has anyone seen Selina Kyle's latest selfies?",
+ visibility: "private"
+ })
+
+ reply = %{
+ "type" => "Create",
+ "actor" => robin.ap_id,
+ "to" => [batman.ap_id, robin.follower_address],
+ "cc" => [],
+ "object" => %{
+ "type" => "Note",
+ "actor" => robin.ap_id,
+ "content" => "@batman 🤤 ❤️ 🐈⬛",
+ "to" => [batman.ap_id, robin.follower_address],
+ "cc" => [],
+ "inReplyTo" => Object.normalize(post).data["id"]
+ }
+ }
+
+ expected_to = [batman.ap_id]
+ expected_cc = []
+
+ assert {:ok, filtered} = FODirectReply.filter(reply)
+
+ assert expected_to == filtered["to"]
+ assert expected_cc == filtered["cc"]
+ assert expected_to == filtered["object"]["to"]
+ assert expected_cc == filtered["object"]["cc"]
+ end
+
+ test "replies to unlisted posts are unmodified" do
+ batman = insert(:user, nickname: "batman")
+ robin = insert(:user, nickname: "robin")
+
+ {:ok, post} =
+ CommonAPI.post(batman, %{
+ status: "Has anyone seen Selina Kyle's latest selfies?",
+ visibility: "unlisted"
+ })
+
+ reply = %{
+ "type" => "Create",
+ "actor" => robin.ap_id,
+ "to" => [batman.ap_id, robin.follower_address],
+ "cc" => [],
+ "object" => %{
+ "type" => "Note",
+ "actor" => robin.ap_id,
+ "content" => "@batman 🤤 ❤️ 🐈<200d>⬛",
+ "to" => [batman.ap_id, robin.follower_address],
+ "cc" => [],
+ "inReplyTo" => Object.normalize(post).data["id"]
+ }
+ }
+
+ assert {:ok, filtered} = FODirectReply.filter(reply)
+
+ assert match?(^filtered, reply)
+ end
+
+ test "replies to public posts are unmodified" do
+ batman = insert(:user, nickname: "batman")
+ robin = insert(:user, nickname: "robin")
+
+ {:ok, post} =
+ CommonAPI.post(batman, %{status: "Has anyone seen Selina Kyle's latest selfies?"})
+
+ reply = %{
+ "type" => "Create",
+ "actor" => robin.ap_id,
+ "to" => [batman.ap_id, robin.follower_address],
+ "cc" => [],
+ "object" => %{
+ "type" => "Note",
+ "actor" => robin.ap_id,
+ "content" => "@batman 🤤 ❤️ 🐈<200d>⬛",
+ "to" => [batman.ap_id, robin.follower_address],
+ "cc" => [],
+ "inReplyTo" => Object.normalize(post).data["id"]
+ }
+ }
+
+ assert {:ok, filtered} = FODirectReply.filter(reply)
+
+ assert match?(^filtered, reply)
+ end
+
+ test "non-reply posts are unmodified" do
+ batman = insert(:user, nickname: "batman")
+
+ {:ok, post} = CommonAPI.post(batman, %{status: "To the Batmobile!"})
+
+ assert {:ok, filtered} = FODirectReply.filter(post)
+
+ assert match?(^filtered, post)
+ end
+end
diff --git a/test/pleroma/web/activity_pub/mrf/quiet_reply_test.exs b/test/pleroma/web/activity_pub/mrf/quiet_reply_test.exs
new file mode 100644
index 000000000..79e64d650
--- /dev/null
+++ b/test/pleroma/web/activity_pub/mrf/quiet_reply_test.exs
@@ -0,0 +1,140 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.QuietReplyTest do
+ use Pleroma.DataCase
+ import Pleroma.Factory
+
+ require Pleroma.Constants
+
+ alias Pleroma.Object
+ alias Pleroma.Web.ActivityPub.MRF.QuietReply
+ alias Pleroma.Web.CommonAPI
+
+ test "replying to public post is forced to be quiet" do
+ batman = insert(:user, nickname: "batman")
+ robin = insert(:user, nickname: "robin")
+
+ {:ok, post} = CommonAPI.post(batman, %{status: "To the Batmobile!"})
+
+ reply = %{
+ "type" => "Create",
+ "actor" => robin.ap_id,
+ "to" => [
+ batman.ap_id,
+ Pleroma.Constants.as_public()
+ ],
+ "cc" => [robin.follower_address],
+ "object" => %{
+ "type" => "Note",
+ "actor" => robin.ap_id,
+ "content" => "@batman Wait up, I forgot my spandex!",
+ "to" => [
+ batman.ap_id,
+ Pleroma.Constants.as_public()
+ ],
+ "cc" => [robin.follower_address],
+ "inReplyTo" => Object.normalize(post).data["id"]
+ }
+ }
+
+ expected_to = [batman.ap_id, robin.follower_address]
+ expected_cc = [Pleroma.Constants.as_public()]
+
+ assert {:ok, filtered} = QuietReply.filter(reply)
+
+ assert expected_to == filtered["to"]
+ assert expected_cc == filtered["cc"]
+ assert expected_to == filtered["object"]["to"]
+ assert expected_cc == filtered["object"]["cc"]
+ end
+
+ test "replying to unlisted post is unmodified" do
+ batman = insert(:user, nickname: "batman")
+ robin = insert(:user, nickname: "robin")
+
+ {:ok, post} = CommonAPI.post(batman, %{status: "To the Batmobile!", visibility: "private"})
+
+ reply = %{
+ "type" => "Create",
+ "actor" => robin.ap_id,
+ "to" => [batman.ap_id],
+ "cc" => [],
+ "object" => %{
+ "type" => "Note",
+ "actor" => robin.ap_id,
+ "content" => "@batman Wait up, I forgot my spandex!",
+ "to" => [batman.ap_id],
+ "cc" => [],
+ "inReplyTo" => Object.normalize(post).data["id"]
+ }
+ }
+
+ assert {:ok, filtered} = QuietReply.filter(reply)
+
+ assert match?(^filtered, reply)
+ end
+
+ test "replying direct is unmodified" do
+ batman = insert(:user, nickname: "batman")
+ robin = insert(:user, nickname: "robin")
+
+ {:ok, post} = CommonAPI.post(batman, %{status: "To the Batmobile!"})
+
+ reply = %{
+ "type" => "Create",
+ "actor" => robin.ap_id,
+ "to" => [batman.ap_id],
+ "cc" => [],
+ "object" => %{
+ "type" => "Note",
+ "actor" => robin.ap_id,
+ "content" => "@batman Wait up, I forgot my spandex!",
+ "to" => [batman.ap_id],
+ "cc" => [],
+ "inReplyTo" => Object.normalize(post).data["id"]
+ }
+ }
+
+ assert {:ok, filtered} = QuietReply.filter(reply)
+
+ assert match?(^filtered, reply)
+ end
+
+ test "replying followers-only is unmodified" do
+ batman = insert(:user, nickname: "batman")
+ robin = insert(:user, nickname: "robin")
+
+ {:ok, post} = CommonAPI.post(batman, %{status: "To the Batmobile!"})
+
+ reply = %{
+ "type" => "Create",
+ "actor" => robin.ap_id,
+ "to" => [batman.ap_id, robin.follower_address],
+ "cc" => [],
+ "object" => %{
+ "type" => "Note",
+ "actor" => robin.ap_id,
+ "content" => "@batman Wait up, I forgot my spandex!",
+ "to" => [batman.ap_id, robin.follower_address],
+ "cc" => [],
+ "inReplyTo" => Object.normalize(post).data["id"]
+ }
+ }
+
+ assert {:ok, filtered} = QuietReply.filter(reply)
+
+ assert match?(^filtered, reply)
+ end
+
+ test "non-reply posts are unmodified" do
+ batman = insert(:user, nickname: "batman")
+
+ {:ok, post} = CommonAPI.post(batman, %{status: "To the Batmobile!"})
+
+ assert {:ok, filtered} = QuietReply.filter(post)
+
+ assert match?(^filtered, post)
+ end
+end
diff --git a/test/pleroma/web/activity_pub/mrf/steal_emoji_policy_test.exs b/test/pleroma/web/activity_pub/mrf/steal_emoji_policy_test.exs
index 61c162bc9..2c7497da5 100644
--- a/test/pleroma/web/activity_pub/mrf/steal_emoji_policy_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/steal_emoji_policy_test.exs
@@ -87,7 +87,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicyTest do
assert File.exists?(fullpath)
end
- test "rejects invalid shortcodes with slashes", %{path: path} do
+ test "rejects invalid shortcodes", %{path: path} do
message = %{
"type" => "Create",
"object" => %{
@@ -113,58 +113,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicyTest do
refute File.exists?(fullpath)
end
- test "rejects invalid shortcodes with dots", %{path: path} do
- message = %{
- "type" => "Create",
- "object" => %{
- "emoji" => [{"fired.fox", "https://example.org/emoji/firedfox"}],
- "actor" => "https://example.org/users/admin"
- }
- }
-
- fullpath = Path.join(path, "fired.fox.png")
-
- Tesla.Mock.mock(fn %{method: :get, url: "https://example.org/emoji/firedfox"} ->
- %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.jpg")}
- end)
-
- clear_config(:mrf_steal_emoji, hosts: ["example.org"], size_limit: 284_468)
-
- refute "fired.fox" in installed()
- refute File.exists?(path)
-
- assert {:ok, _message} = StealEmojiPolicy.filter(message)
-
- refute "fired.fox" in installed()
- refute File.exists?(fullpath)
- end
-
- test "rejects invalid shortcodes with special characters", %{path: path} do
- message = %{
- "type" => "Create",
- "object" => %{
- "emoji" => [{"fired:fox", "https://example.org/emoji/firedfox"}],
- "actor" => "https://example.org/users/admin"
- }
- }
-
- fullpath = Path.join(path, "fired:fox.png")
-
- Tesla.Mock.mock(fn %{method: :get, url: "https://example.org/emoji/firedfox"} ->
- %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.jpg")}
- end)
-
- clear_config(:mrf_steal_emoji, hosts: ["example.org"], size_limit: 284_468)
-
- refute "fired:fox" in installed()
- refute File.exists?(path)
-
- assert {:ok, _message} = StealEmojiPolicy.filter(message)
-
- refute "fired:fox" in installed()
- refute File.exists?(fullpath)
- end
-
test "reject regex shortcode", %{message: message} do
refute "firedfox" in installed()
@@ -223,74 +171,5 @@ defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicyTest do
refute "firedfox" in installed()
end
- test "accepts valid alphanum shortcodes", %{path: path} do
- message = %{
- "type" => "Create",
- "object" => %{
- "emoji" => [{"fire1fox", "https://example.org/emoji/fire1fox.png"}],
- "actor" => "https://example.org/users/admin"
- }
- }
-
- Tesla.Mock.mock(fn %{method: :get, url: "https://example.org/emoji/fire1fox.png"} ->
- %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.jpg")}
- end)
-
- clear_config(:mrf_steal_emoji, hosts: ["example.org"], size_limit: 284_468)
-
- refute "fire1fox" in installed()
- refute File.exists?(path)
-
- assert {:ok, _message} = StealEmojiPolicy.filter(message)
-
- assert "fire1fox" in installed()
- end
-
- test "accepts valid shortcodes with underscores", %{path: path} do
- message = %{
- "type" => "Create",
- "object" => %{
- "emoji" => [{"fire_fox", "https://example.org/emoji/fire_fox.png"}],
- "actor" => "https://example.org/users/admin"
- }
- }
-
- Tesla.Mock.mock(fn %{method: :get, url: "https://example.org/emoji/fire_fox.png"} ->
- %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.jpg")}
- end)
-
- clear_config(:mrf_steal_emoji, hosts: ["example.org"], size_limit: 284_468)
-
- refute "fire_fox" in installed()
- refute File.exists?(path)
-
- assert {:ok, _message} = StealEmojiPolicy.filter(message)
-
- assert "fire_fox" in installed()
- end
-
- test "accepts valid shortcodes with hyphens", %{path: path} do
- message = %{
- "type" => "Create",
- "object" => %{
- "emoji" => [{"fire-fox", "https://example.org/emoji/fire-fox.png"}],
- "actor" => "https://example.org/users/admin"
- }
- }
-
- Tesla.Mock.mock(fn %{method: :get, url: "https://example.org/emoji/fire-fox.png"} ->
- %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.jpg")}
- end)
-
- clear_config(:mrf_steal_emoji, hosts: ["example.org"], size_limit: 284_468)
-
- refute "fire-fox" in installed()
- refute File.exists?(path)
-
- assert {:ok, _message} = StealEmojiPolicy.filter(message)
-
- assert "fire-fox" in installed()
- end
-
defp installed, do: Emoji.get_all() |> Enum.map(fn {k, _} -> k end)
end
diff --git a/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs b/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs
index 829598246..e1dbb20c3 100644
--- a/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs
+++ b/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs
@@ -128,17 +128,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidatorTest
%{valid?: true} = ArticleNotePageValidator.cast_and_validate(note)
end
- test "a Note with validated likes collection validates" do
- insert(:user, ap_id: "https://pol.social/users/mkljczk")
-
- %{"object" => note} =
- "test/fixtures/mastodon-update-with-likes.json"
- |> File.read!()
- |> Jason.decode!()
-
- %{valid?: true} = ArticleNotePageValidator.cast_and_validate(note)
- end
-
test "Fedibird quote post" do
insert(:user, ap_id: "https://fedibird.com/users/noellabo")
@@ -187,71 +176,4 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidatorTest
name: "RE: https://server.example/objects/123"
}
end
-
- describe "Note language" do
- test "it detects language from JSON-LD context" do
- user = insert(:user)
-
- note_activity = %{
- "@context" => ["https://www.w3.org/ns/activitystreams", %{"@language" => "pl"}],
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "cc" => [],
- "type" => "Create",
- "object" => %{
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "cc" => [],
- "id" => Utils.generate_object_id(),
- "type" => "Note",
- "content" => "Szczęść Boże",
- "attributedTo" => user.ap_id
- },
- "actor" => user.ap_id
- }
-
- {:ok, _create_activity, meta} = ObjectValidator.validate(note_activity, [])
-
- assert meta[:object_data]["language"] == "pl"
- end
-
- test "it detects language from contentMap" do
- user = insert(:user)
-
- note = %{
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "cc" => [],
- "id" => Utils.generate_object_id(),
- "type" => "Note",
- "content" => "Szczęść Boże",
- "contentMap" => %{
- "de" => "Gott segne",
- "pl" => "Szczęść Boże"
- },
- "attributedTo" => user.ap_id
- }
-
- {:ok, object} = ArticleNotePageValidator.cast_and_apply(note)
-
- assert object.language == "pl"
- end
-
- test "it adds contentMap if language is specified" do
- user = insert(:user)
-
- note = %{
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "cc" => [],
- "id" => Utils.generate_object_id(),
- "type" => "Note",
- "content" => "тест",
- "language" => "uk",
- "attributedTo" => user.ap_id
- }
-
- {:ok, object} = ArticleNotePageValidator.cast_and_apply(note)
-
- assert object.contentMap == %{
- "uk" => "тест"
- }
- end
- end
end
diff --git a/test/pleroma/web/activity_pub/object_validators/attachment_validator_test.exs b/test/pleroma/web/activity_pub/object_validators/attachment_validator_test.exs
index 744ae8704..6627fa6db 100644
--- a/test/pleroma/web/activity_pub/object_validators/attachment_validator_test.exs
+++ b/test/pleroma/web/activity_pub/object_validators/attachment_validator_test.exs
@@ -13,23 +13,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidatorTest do
import Pleroma.Factory
describe "attachments" do
- test "works with apng" do
- attachment =
- %{
- "mediaType" => "image/apng",
- "name" => "",
- "type" => "Document",
- "url" =>
- "https://media.misskeyusercontent.com/io/2859c26e-cd43-4550-848b-b6243bc3fe28.apng"
- }
-
- assert {:ok, attachment} =
- AttachmentValidator.cast_and_validate(attachment)
- |> Ecto.Changeset.apply_action(:insert)
-
- assert attachment.mediaType == "image/apng"
- end
-
test "fails without url" do
attachment = %{
"mediaType" => "",
diff --git a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs
index fd7a3c772..ed71dcb90 100644
--- a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs
@@ -219,36 +219,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do
"@lain
"
end
- test "it only uses contentMap if content is not present" do
- user = insert(:user)
-
- message = %{
- "@context" => "https://www.w3.org/ns/activitystreams",
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "cc" => [],
- "type" => "Create",
- "object" => %{
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "cc" => [],
- "id" => Utils.generate_object_id(),
- "type" => "Note",
- "content" => "Hi",
- "contentMap" => %{
- "de" => "Hallo",
- "uk" => "Привіт"
- },
- "inReplyTo" => nil,
- "attributedTo" => user.ap_id
- },
- "actor" => user.ap_id
- }
-
- {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(message)
- object = Object.normalize(data["object"], fetch: false)
-
- assert object.data["content"] == "Hi"
- end
-
test "it works for incoming notices with a nil contentMap (firefish)" do
data =
File.read!("test/fixtures/mastodon-post-activity-contentmap.json")
diff --git a/test/pleroma/web/activity_pub/transmogrifier_test.exs b/test/pleroma/web/activity_pub/transmogrifier_test.exs
index e0395d7bb..6da7e4a89 100644
--- a/test/pleroma/web/activity_pub/transmogrifier_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier_test.exs
@@ -156,246 +156,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
# It fetched the quoted post
assert Object.normalize("https://misskey.io/notes/8vs6wxufd0")
end
-
- test "doesn't allow remote edits to fake local likes" do
- # as a spot check for no internal fields getting injected
- now = DateTime.utc_now()
- pub_date = DateTime.to_iso8601(Timex.subtract(now, Timex.Duration.from_minutes(3)))
- edit_date = DateTime.to_iso8601(now)
-
- local_user = insert(:user)
-
- create_data = %{
- "type" => "Create",
- "id" => "http://mastodon.example.org/users/admin/statuses/2619539638/activity",
- "actor" => "http://mastodon.example.org/users/admin",
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "cc" => [],
- "object" => %{
- "type" => "Note",
- "id" => "http://mastodon.example.org/users/admin/statuses/2619539638",
- "attributedTo" => "http://mastodon.example.org/users/admin",
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "cc" => [],
- "published" => pub_date,
- "content" => "miaow",
- "likes" => [local_user.ap_id]
- }
- }
-
- update_data =
- create_data
- |> Map.put("type", "Update")
- |> Map.put("id", create_data["object"]["id"] <> "/update/1")
- |> put_in(["object", "content"], "miaow :3")
- |> put_in(["object", "updated"], edit_date)
- |> put_in(["object", "formerRepresentations"], %{
- "type" => "OrderedCollection",
- "totalItems" => 1,
- "orderedItems" => [create_data["object"]]
- })
-
- {:ok, %Pleroma.Activity{} = activity} = Transmogrifier.handle_incoming(create_data)
- %Pleroma.Object{} = object = Object.get_by_ap_id(activity.data["object"])
- assert object.data["content"] == "miaow"
- assert object.data["likes"] == []
- assert object.data["like_count"] == 0
-
- {:ok, %Pleroma.Activity{} = activity} = Transmogrifier.handle_incoming(update_data)
- %Pleroma.Object{} = object = Object.get_by_ap_id(activity.data["object"]["id"])
- assert object.data["content"] == "miaow :3"
- assert object.data["likes"] == []
- assert object.data["like_count"] == 0
- end
-
- test "strips internal fields from history items in edited notes" do
- now = DateTime.utc_now()
- pub_date = DateTime.to_iso8601(Timex.subtract(now, Timex.Duration.from_minutes(3)))
- edit_date = DateTime.to_iso8601(now)
-
- local_user = insert(:user)
-
- create_data = %{
- "type" => "Create",
- "id" => "http://mastodon.example.org/users/admin/statuses/2619539638/activity",
- "actor" => "http://mastodon.example.org/users/admin",
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "cc" => [],
- "object" => %{
- "type" => "Note",
- "id" => "http://mastodon.example.org/users/admin/statuses/2619539638",
- "attributedTo" => "http://mastodon.example.org/users/admin",
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "cc" => [],
- "published" => pub_date,
- "content" => "miaow",
- "likes" => [],
- "like_count" => 0
- }
- }
-
- update_data =
- create_data
- |> Map.put("type", "Update")
- |> Map.put("id", create_data["object"]["id"] <> "/update/1")
- |> put_in(["object", "content"], "miaow :3")
- |> put_in(["object", "updated"], edit_date)
- |> put_in(["object", "formerRepresentations"], %{
- "type" => "OrderedCollection",
- "totalItems" => 1,
- "orderedItems" => [
- Map.merge(create_data["object"], %{
- "likes" => [local_user.ap_id],
- "like_count" => 1,
- "pleroma" => %{"internal_field" => "should_be_stripped"}
- })
- ]
- })
-
- {:ok, %Pleroma.Activity{} = activity} = Transmogrifier.handle_incoming(create_data)
- %Pleroma.Object{} = object = Object.get_by_ap_id(activity.data["object"])
- assert object.data["content"] == "miaow"
- assert object.data["likes"] == []
- assert object.data["like_count"] == 0
-
- {:ok, %Pleroma.Activity{} = activity} = Transmogrifier.handle_incoming(update_data)
- %Pleroma.Object{} = object = Object.get_by_ap_id(activity.data["object"]["id"])
- assert object.data["content"] == "miaow :3"
- assert object.data["likes"] == []
- assert object.data["like_count"] == 0
-
- # Check that internal fields are stripped from history items
- history_item = List.first(object.data["formerRepresentations"]["orderedItems"])
- assert history_item["likes"] == []
- assert history_item["like_count"] == 0
- refute Map.has_key?(history_item, "pleroma")
- end
-
- test "doesn't trip over remote likes in notes" do
- now = DateTime.utc_now()
- pub_date = DateTime.to_iso8601(Timex.subtract(now, Timex.Duration.from_minutes(3)))
- edit_date = DateTime.to_iso8601(now)
-
- create_data = %{
- "type" => "Create",
- "id" => "http://mastodon.example.org/users/admin/statuses/3409297097/activity",
- "actor" => "http://mastodon.example.org/users/admin",
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "cc" => [],
- "object" => %{
- "type" => "Note",
- "id" => "http://mastodon.example.org/users/admin/statuses/3409297097",
- "attributedTo" => "http://mastodon.example.org/users/admin",
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "cc" => [],
- "published" => pub_date,
- "content" => "miaow",
- "likes" => %{
- "id" => "http://mastodon.example.org/users/admin/statuses/3409297097/likes",
- "totalItems" => 0,
- "type" => "Collection"
- }
- }
- }
-
- update_data =
- create_data
- |> Map.put("type", "Update")
- |> Map.put("id", create_data["object"]["id"] <> "/update/1")
- |> put_in(["object", "content"], "miaow :3")
- |> put_in(["object", "updated"], edit_date)
- |> put_in(["object", "likes", "totalItems"], 666)
- |> put_in(["object", "formerRepresentations"], %{
- "type" => "OrderedCollection",
- "totalItems" => 1,
- "orderedItems" => [create_data["object"]]
- })
-
- {:ok, %Pleroma.Activity{} = activity} = Transmogrifier.handle_incoming(create_data)
- %Pleroma.Object{} = object = Object.get_by_ap_id(activity.data["object"])
- assert object.data["content"] == "miaow"
- assert object.data["likes"] == []
- assert object.data["like_count"] == 0
-
- {:ok, %Pleroma.Activity{} = activity} = Transmogrifier.handle_incoming(update_data)
- %Pleroma.Object{} = object = Object.get_by_ap_id(activity.data["object"]["id"])
- assert object.data["content"] == "miaow :3"
- assert object.data["likes"] == []
- # in the future this should retain remote likes, but for now:
- assert object.data["like_count"] == 0
- end
-
- test "doesn't trip over remote likes in polls" do
- now = DateTime.utc_now()
- pub_date = DateTime.to_iso8601(Timex.subtract(now, Timex.Duration.from_minutes(3)))
- edit_date = DateTime.to_iso8601(now)
-
- create_data = %{
- "type" => "Create",
- "id" => "http://mastodon.example.org/users/admin/statuses/2471790073/activity",
- "actor" => "http://mastodon.example.org/users/admin",
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "cc" => [],
- "object" => %{
- "type" => "Question",
- "id" => "http://mastodon.example.org/users/admin/statuses/2471790073",
- "attributedTo" => "http://mastodon.example.org/users/admin",
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "cc" => [],
- "published" => pub_date,
- "content" => "vote!",
- "anyOf" => [
- %{
- "type" => "Note",
- "name" => "a",
- "replies" => %{
- "type" => "Collection",
- "totalItems" => 3
- }
- },
- %{
- "type" => "Note",
- "name" => "b",
- "replies" => %{
- "type" => "Collection",
- "totalItems" => 1
- }
- }
- ],
- "likes" => %{
- "id" => "http://mastodon.example.org/users/admin/statuses/2471790073/likes",
- "totalItems" => 0,
- "type" => "Collection"
- }
- }
- }
-
- update_data =
- create_data
- |> Map.put("type", "Update")
- |> Map.put("id", create_data["object"]["id"] <> "/update/1")
- |> put_in(["object", "content"], "vote now!")
- |> put_in(["object", "updated"], edit_date)
- |> put_in(["object", "likes", "totalItems"], 666)
- |> put_in(["object", "formerRepresentations"], %{
- "type" => "OrderedCollection",
- "totalItems" => 1,
- "orderedItems" => [create_data["object"]]
- })
-
- {:ok, %Pleroma.Activity{} = activity} = Transmogrifier.handle_incoming(create_data)
- %Pleroma.Object{} = object = Object.get_by_ap_id(activity.data["object"])
- assert object.data["content"] == "vote!"
- assert object.data["likes"] == []
- assert object.data["like_count"] == 0
-
- {:ok, %Pleroma.Activity{} = activity} = Transmogrifier.handle_incoming(update_data)
- %Pleroma.Object{} = object = Object.get_by_ap_id(activity.data["object"]["id"])
- assert object.data["content"] == "vote now!"
- assert object.data["likes"] == []
- # in the future this should retain remote likes, but for now:
- assert object.data["like_count"] == 0
- end
end
describe "prepare outgoing" do
@@ -624,24 +384,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert modified["object"]["quoteUrl"] == quote_id
assert modified["object"]["quoteUri"] == quote_id
end
-
- test "it adds language of the object to its json-ld context" do
- user = insert(:user)
-
- {:ok, activity} = CommonAPI.post(user, %{status: "Cześć", language: "pl"})
- {:ok, modified} = Transmogrifier.prepare_outgoing(activity.object.data)
-
- assert [_, _, %{"@language" => "pl"}] = modified["@context"]
- end
-
- test "it adds language of the object to Create activity json-ld context" do
- user = insert(:user)
-
- {:ok, activity} = CommonAPI.post(user, %{status: "Cześć", language: "pl"})
- {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
-
- assert [_, _, %{"@language" => "pl"}] = modified["@context"]
- end
end
describe "actor rewriting" do
@@ -879,14 +621,5 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
processed = Transmogrifier.prepare_object(original)
assert processed["formerRepresentations"] == original["formerRepresentations"]
end
-
- test "it uses contentMap to specify post language" do
- user = insert(:user)
-
- {:ok, activity} = CommonAPI.post(user, %{status: "Cześć", language: "pl"})
- object = Transmogrifier.prepare_object(activity.object.data)
-
- assert %{"contentMap" => %{"pl" => "Cześć"}} = object
- end
end
end
diff --git a/test/pleroma/web/activity_pub/utils_test.exs b/test/pleroma/web/activity_pub/utils_test.exs
index 45fef154e..872a440cb 100644
--- a/test/pleroma/web/activity_pub/utils_test.exs
+++ b/test/pleroma/web/activity_pub/utils_test.exs
@@ -173,30 +173,16 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
end
end
- describe "make_json_ld_header/1" do
- test "makes jsonld header" do
- assert Utils.make_json_ld_header() == %{
- "@context" => [
- "https://www.w3.org/ns/activitystreams",
- "http://localhost:4001/schemas/litepub-0.1.jsonld",
- %{
- "@language" => "und"
- }
- ]
- }
- end
-
- test "includes language if specified" do
- assert Utils.make_json_ld_header(%{"language" => "pl"}) == %{
- "@context" => [
- "https://www.w3.org/ns/activitystreams",
- "http://localhost:4001/schemas/litepub-0.1.jsonld",
- %{
- "@language" => "pl"
- }
- ]
- }
- end
+ test "make_json_ld_header/0" do
+ assert Utils.make_json_ld_header() == %{
+ "@context" => [
+ "https://www.w3.org/ns/activitystreams",
+ "http://localhost:4001/schemas/litepub-0.1.jsonld",
+ %{
+ "@language" => "und"
+ }
+ ]
+ }
end
describe "get_existing_votes" do
diff --git a/test/pleroma/web/admin_api/controllers/config_controller_test.exs b/test/pleroma/web/admin_api/controllers/config_controller_test.exs
index e12115ea1..dc12155f5 100644
--- a/test/pleroma/web/admin_api/controllers/config_controller_test.exs
+++ b/test/pleroma/web/admin_api/controllers/config_controller_test.exs
@@ -1211,6 +1211,8 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do
end
test "args for Pleroma.Upload.Filter.Mogrify with custom tuples", %{conn: conn} do
+ clear_config(Pleroma.Upload.Filter.Mogrify)
+
assert conn
|> put_req_header("content-type", "application/json")
|> post("/api/pleroma/admin/config", %{
@@ -1238,8 +1240,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do
"need_reboot" => false
}
- config = Config.get(Pleroma.Upload.Filter.Mogrify)
- assert {:args, ["auto-orient", "strip"]} in config
+ assert Config.get(Pleroma.Upload.Filter.Mogrify) == [args: ["auto-orient", "strip"]]
assert conn
|> put_req_header("content-type", "application/json")
@@ -1288,9 +1289,9 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do
"need_reboot" => false
}
- config = Config.get(Pleroma.Upload.Filter.Mogrify)
-
- assert {:args, ["auto-orient", "strip", {"implode", "1"}, {"resize", "3840x1080>"}]} in config
+ assert Config.get(Pleroma.Upload.Filter.Mogrify) == [
+ args: ["auto-orient", "strip", {"implode", "1"}, {"resize", "3840x1080>"}]
+ ]
end
test "enables the welcome messages", %{conn: conn} do
diff --git a/test/pleroma/web/admin_api/controllers/user_controller_test.exs b/test/pleroma/web/admin_api/controllers/user_controller_test.exs
index 0e5650285..c8495c477 100644
--- a/test/pleroma/web/admin_api/controllers/user_controller_test.exs
+++ b/test/pleroma/web/admin_api/controllers/user_controller_test.exs
@@ -20,7 +20,7 @@ defmodule Pleroma.Web.AdminAPI.UserControllerTest do
alias Pleroma.Web.MediaProxy
setup do
- Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Test.StaticConfig)
+ Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
:ok
end
diff --git a/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs
index cd3107f32..54f6818bd 100644
--- a/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs
@@ -19,7 +19,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
import Pleroma.Factory
setup do
- Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Test.StaticConfig)
+ Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
:ok
end
diff --git a/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs
index ae86078d7..3f696d94d 100644
--- a/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs
@@ -227,93 +227,4 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do
|> json_response_and_validate_schema(403)
end
end
-
- describe "Content-Type sanitization" do
- setup do: oauth_access(["write:media", "read:media"])
-
- setup do
- ConfigMock
- |> stub_with(Pleroma.Test.StaticConfig)
-
- config =
- Pleroma.Config.get([Pleroma.Upload])
- |> Keyword.put(:uploader, Pleroma.Uploaders.Local)
-
- clear_config([Pleroma.Upload], config)
- clear_config([Pleroma.Upload, :allowed_mime_types], ["image", "audio", "video"])
-
- # Create a file with a malicious content type and dangerous extension
- malicious_file = %Plug.Upload{
- content_type: "application/activity+json",
- path: Path.absname("test/fixtures/image.jpg"),
- # JSON extension to make MIME.from_path detect application/json
- filename: "malicious.json"
- }
-
- [malicious_file: malicious_file]
- end
-
- test "sanitizes malicious content types when serving media", %{
- conn: conn,
- malicious_file: malicious_file
- } do
- # First upload the file with the malicious content type
- media =
- conn
- |> put_req_header("content-type", "multipart/form-data")
- |> post("/api/v1/media", %{"file" => malicious_file})
- |> json_response_and_validate_schema(:ok)
-
- # Get the file URL from the response
- url = media["url"]
-
- # Now make a direct request to the media URL and check the content-type header
- response =
- build_conn()
- |> get(URI.parse(url).path)
-
- # Find the content-type header
- content_type_header =
- Enum.find(response.resp_headers, fn {name, _} -> name == "content-type" end)
-
- # The server should detect the application/json MIME type from the .json extension
- # and replace it with application/octet-stream since it's not in allowed_mime_types
- assert content_type_header == {"content-type", "application/octet-stream"}
-
- # Verify that the file was still served correctly
- assert response.status == 200
- end
-
- test "allows safe content types", %{conn: conn} do
- safe_image = %Plug.Upload{
- content_type: "image/jpeg",
- path: Path.absname("test/fixtures/image.jpg"),
- filename: "safe_image.jpg"
- }
-
- # Upload a file with a safe content type
- media =
- conn
- |> put_req_header("content-type", "multipart/form-data")
- |> post("/api/v1/media", %{"file" => safe_image})
- |> json_response_and_validate_schema(:ok)
-
- # Get the file URL from the response
- url = media["url"]
-
- # Make a direct request to the media URL and check the content-type header
- response =
- build_conn()
- |> get(URI.parse(url).path)
-
- # The server should preserve the image/jpeg MIME type since it's allowed
- content_type_header =
- Enum.find(response.resp_headers, fn {name, _} -> name == "content-type" end)
-
- assert content_type_header == {"content-type", "image/jpeg"}
-
- # Verify that the file was served correctly
- assert response.status == 200
- end
- end
end
diff --git a/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs
index 88f2fb7af..8fc22dde1 100644
--- a/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs
@@ -13,7 +13,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
import Pleroma.Factory
setup do
- Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Test.StaticConfig)
+ Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
:ok
end
diff --git a/test/pleroma/web/mastodon_api/controllers/search_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/search_controller_test.exs
index d8263dfad..d38767c96 100644
--- a/test/pleroma/web/mastodon_api/controllers/search_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/search_controller_test.exs
@@ -14,7 +14,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do
import Mock
setup do
- Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Test.StaticConfig)
+ Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
:ok
end
diff --git a/test/pleroma/web/mastodon_api/controllers/tag_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/tag_controller_test.exs
deleted file mode 100644
index 71c8e7fc0..000000000
--- a/test/pleroma/web/mastodon_api/controllers/tag_controller_test.exs
+++ /dev/null
@@ -1,159 +0,0 @@
-defmodule Pleroma.Web.MastodonAPI.TagControllerTest do
- use Pleroma.Web.ConnCase
-
- import Pleroma.Factory
- import Tesla.Mock
-
- alias Pleroma.User
-
- setup do
- mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
- :ok
- end
-
- describe "GET /api/v1/tags/:id" do
- test "returns 200 with tag" do
- %{user: user, conn: conn} = oauth_access(["read"])
-
- tag = insert(:hashtag, name: "jubjub")
- {:ok, _user} = User.follow_hashtag(user, tag)
-
- response =
- conn
- |> get("/api/v1/tags/jubjub")
- |> json_response_and_validate_schema(200)
-
- assert %{
- "name" => "jubjub",
- "url" => "http://localhost:4001/tags/jubjub",
- "history" => [],
- "following" => true
- } = response
- end
-
- test "returns 404 with unknown tag" do
- %{conn: conn} = oauth_access(["read"])
-
- conn
- |> get("/api/v1/tags/jubjub")
- |> json_response_and_validate_schema(404)
- end
- end
-
- describe "POST /api/v1/tags/:id/follow" do
- test "should follow a hashtag" do
- %{user: user, conn: conn} = oauth_access(["write:follows"])
- hashtag = insert(:hashtag, name: "jubjub")
-
- response =
- conn
- |> post("/api/v1/tags/jubjub/follow")
- |> json_response_and_validate_schema(200)
-
- assert response["following"] == true
- user = User.get_cached_by_ap_id(user.ap_id)
- assert User.following_hashtag?(user, hashtag)
- end
-
- test "should 404 if hashtag doesn't exist" do
- %{conn: conn} = oauth_access(["write:follows"])
-
- response =
- conn
- |> post("/api/v1/tags/rubrub/follow")
- |> json_response_and_validate_schema(404)
-
- assert response["error"] == "Hashtag not found"
- end
- end
-
- describe "POST /api/v1/tags/:id/unfollow" do
- test "should unfollow a hashtag" do
- %{user: user, conn: conn} = oauth_access(["write:follows"])
- hashtag = insert(:hashtag, name: "jubjub")
- {:ok, user} = User.follow_hashtag(user, hashtag)
-
- response =
- conn
- |> post("/api/v1/tags/jubjub/unfollow")
- |> json_response_and_validate_schema(200)
-
- assert response["following"] == false
- user = User.get_cached_by_ap_id(user.ap_id)
- refute User.following_hashtag?(user, hashtag)
- end
-
- test "should 404 if hashtag doesn't exist" do
- %{conn: conn} = oauth_access(["write:follows"])
-
- response =
- conn
- |> post("/api/v1/tags/rubrub/unfollow")
- |> json_response_and_validate_schema(404)
-
- assert response["error"] == "Hashtag not found"
- end
- end
-
- describe "GET /api/v1/followed_tags" do
- test "should list followed tags" do
- %{user: user, conn: conn} = oauth_access(["read:follows"])
-
- response =
- conn
- |> get("/api/v1/followed_tags")
- |> json_response_and_validate_schema(200)
-
- assert Enum.empty?(response)
-
- hashtag = insert(:hashtag, name: "jubjub")
- {:ok, _user} = User.follow_hashtag(user, hashtag)
-
- response =
- conn
- |> get("/api/v1/followed_tags")
- |> json_response_and_validate_schema(200)
-
- assert [%{"name" => "jubjub"}] = response
- end
-
- test "should include a link header to paginate" do
- %{user: user, conn: conn} = oauth_access(["read:follows"])
-
- for i <- 1..21 do
- hashtag = insert(:hashtag, name: "jubjub#{i}}")
- {:ok, _user} = User.follow_hashtag(user, hashtag)
- end
-
- response =
- conn
- |> get("/api/v1/followed_tags")
-
- json = json_response_and_validate_schema(response, 200)
- assert Enum.count(json) == 20
- assert [link_header] = get_resp_header(response, "link")
- assert link_header =~ "rel=\"next\""
- next_link = extract_next_link_header(link_header)
-
- response =
- conn
- |> get(next_link)
- |> json_response_and_validate_schema(200)
-
- assert Enum.count(response) == 1
- end
-
- test "should refuse access without read:follows scope" do
- %{conn: conn} = oauth_access(["write"])
-
- conn
- |> get("/api/v1/followed_tags")
- |> json_response_and_validate_schema(403)
- end
- end
-
- defp extract_next_link_header(header) do
- [_, next_link] = Regex.run(~r{<(?.*)>; rel="next"}, header)
- next_link
- end
-end
diff --git a/test/pleroma/web/mastodon_api/views/notification_view_test.exs b/test/pleroma/web/mastodon_api/views/notification_view_test.exs
index ce5ddd0fc..b1f3523ac 100644
--- a/test/pleroma/web/mastodon_api/views/notification_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/notification_view_test.exs
@@ -23,7 +23,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
import Pleroma.Factory
setup do
- Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Test.StaticConfig)
+ Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
:ok
end
diff --git a/test/pleroma/web/mastodon_api/views/status_view_test.exs b/test/pleroma/web/mastodon_api/views/status_view_test.exs
index e6a164d72..bc6dec32a 100644
--- a/test/pleroma/web/mastodon_api/views/status_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/status_view_test.exs
@@ -951,26 +951,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
assert status.edited_at
end
- test "it shows post language" do
- user = insert(:user)
-
- {:ok, post} = CommonAPI.post(user, %{status: "Szczęść Boże", language: "pl"})
-
- status = StatusView.render("show.json", activity: post)
-
- assert status.language == "pl"
- end
-
- test "doesn't show post language if it's 'und'" do
- user = insert(:user)
-
- {:ok, post} = CommonAPI.post(user, %{status: "sdifjogijodfg", language: "und"})
-
- status = StatusView.render("show.json", activity: post)
-
- assert status.language == nil
- end
-
test "with a source object" do
note =
insert(:note,
diff --git a/test/pleroma/web/media_proxy/media_proxy_controller_test.exs b/test/pleroma/web/media_proxy/media_proxy_controller_test.exs
index f7e52483c..f0c1dd640 100644
--- a/test/pleroma/web/media_proxy/media_proxy_controller_test.exs
+++ b/test/pleroma/web/media_proxy/media_proxy_controller_test.exs
@@ -248,8 +248,8 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
response = get(conn, url)
- assert response.status == 301
- assert redirected_to(response, 301) == media_proxy_url
+ assert response.status == 302
+ assert redirected_to(response) == media_proxy_url
end
test "with `static` param and non-GIF image preview requested, " <>
@@ -290,8 +290,8 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
response = get(conn, url)
- assert response.status == 301
- assert redirected_to(response, 301) == media_proxy_url
+ assert response.status == 302
+ assert redirected_to(response) == media_proxy_url
end
test "thumbnails PNG images into PNG", %{
@@ -356,32 +356,5 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
assert response.status == 302
assert redirected_to(response) == media_proxy_url
end
-
- test "redirects to media proxy URI with 301 when image is too small for preview", %{
- conn: conn,
- url: url,
- media_proxy_url: media_proxy_url
- } do
- clear_config([:media_preview_proxy],
- enabled: true,
- min_content_length: 1000,
- image_quality: 85,
- thumbnail_max_width: 100,
- thumbnail_max_height: 100
- )
-
- Tesla.Mock.mock(fn
- %{method: :head, url: ^media_proxy_url} ->
- %Tesla.Env{
- status: 200,
- body: "",
- headers: [{"content-type", "image/png"}, {"content-length", "500"}]
- }
- end)
-
- response = get(conn, url)
- assert response.status == 301
- assert redirected_to(response, 301) == media_proxy_url
- end
end
end
diff --git a/test/pleroma/web/metadata/providers/open_graph_test.exs b/test/pleroma/web/metadata/providers/open_graph_test.exs
index 29cc036ba..6a0fc9b10 100644
--- a/test/pleroma/web/metadata/providers/open_graph_test.exs
+++ b/test/pleroma/web/metadata/providers/open_graph_test.exs
@@ -9,7 +9,6 @@ defmodule Pleroma.Web.Metadata.Providers.OpenGraphTest do
alias Pleroma.UnstubbedConfigMock, as: ConfigMock
alias Pleroma.Web.Metadata.Providers.OpenGraph
- alias Pleroma.Web.Metadata.Utils
setup do
ConfigMock
@@ -198,58 +197,4 @@ defmodule Pleroma.Web.Metadata.Providers.OpenGraphTest do
"http://localhost:4001/proxy/preview/LzAnlke-l5oZbNzWsrHfprX1rGw/aHR0cHM6Ly9wbGVyb21hLmdvdi9hYm91dC9qdWNoZS53ZWJt/juche.webm"
], []} in result
end
-
- test "meta tag ordering matches attachment order" do
- user = insert(:user, name: "Jimmy Hendriks", bio: "born 19 March 1994")
-
- note =
- insert(:note, %{
- data: %{
- "actor" => user.ap_id,
- "tag" => [],
- "id" => "https://pleroma.gov/objects/whatever",
- "summary" => "",
- "content" => "pleroma in a nutshell",
- "attachment" => [
- %{
- "url" => [
- %{
- "mediaType" => "image/png",
- "href" => "https://example.com/first.png",
- "height" => 1024,
- "width" => 1280
- }
- ]
- },
- %{
- "url" => [
- %{
- "mediaType" => "image/png",
- "href" => "https://example.com/second.png",
- "height" => 1024,
- "width" => 1280
- }
- ]
- }
- ]
- }
- })
-
- result = OpenGraph.build_tags(%{object: note, url: note.data["id"], user: user})
-
- assert [
- {:meta, [property: "og:title", content: Utils.user_name_string(user)], []},
- {:meta, [property: "og:url", content: "https://pleroma.gov/objects/whatever"], []},
- {:meta, [property: "og:description", content: "pleroma in a nutshell"], []},
- {:meta, [property: "og:type", content: "article"], []},
- {:meta, [property: "og:image", content: "https://example.com/first.png"], []},
- {:meta, [property: "og:image:alt", content: nil], []},
- {:meta, [property: "og:image:width", content: "1280"], []},
- {:meta, [property: "og:image:height", content: "1024"], []},
- {:meta, [property: "og:image", content: "https://example.com/second.png"], []},
- {:meta, [property: "og:image:alt", content: nil], []},
- {:meta, [property: "og:image:width", content: "1280"], []},
- {:meta, [property: "og:image:height", content: "1024"], []}
- ] == result
- end
end
diff --git a/test/pleroma/web/metadata/providers/twitter_card_test.exs b/test/pleroma/web/metadata/providers/twitter_card_test.exs
index f9e917719..f8d01c5c8 100644
--- a/test/pleroma/web/metadata/providers/twitter_card_test.exs
+++ b/test/pleroma/web/metadata/providers/twitter_card_test.exs
@@ -202,58 +202,4 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do
{:meta, [name: "twitter:player:stream:content_type", content: "video/webm"], []}
] == result
end
-
- test "meta tag ordering matches attachment order" do
- user = insert(:user, name: "Jimmy Hendriks", bio: "born 19 March 1994")
-
- note =
- insert(:note, %{
- data: %{
- "actor" => user.ap_id,
- "tag" => [],
- "id" => "https://pleroma.gov/objects/whatever",
- "summary" => "",
- "content" => "pleroma in a nutshell",
- "attachment" => [
- %{
- "url" => [
- %{
- "mediaType" => "image/png",
- "href" => "https://example.com/first.png",
- "height" => 1024,
- "width" => 1280
- }
- ]
- },
- %{
- "url" => [
- %{
- "mediaType" => "image/png",
- "href" => "https://example.com/second.png",
- "height" => 1024,
- "width" => 1280
- }
- ]
- }
- ]
- }
- })
-
- result = TwitterCard.build_tags(%{object: note, activity_id: note.data["id"], user: user})
-
- assert [
- {:meta, [name: "twitter:title", content: Utils.user_name_string(user)], []},
- {:meta, [name: "twitter:description", content: "pleroma in a nutshell"], []},
- {:meta, [name: "twitter:card", content: "summary_large_image"], []},
- {:meta, [name: "twitter:image", content: "https://example.com/first.png"], []},
- {:meta, [name: "twitter:image:alt", content: ""], []},
- {:meta, [name: "twitter:player:width", content: "1280"], []},
- {:meta, [name: "twitter:player:height", content: "1024"], []},
- {:meta, [name: "twitter:card", content: "summary_large_image"], []},
- {:meta, [name: "twitter:image", content: "https://example.com/second.png"], []},
- {:meta, [name: "twitter:image:alt", content: ""], []},
- {:meta, [name: "twitter:player:width", content: "1280"], []},
- {:meta, [name: "twitter:player:height", content: "1024"], []}
- ] == result
- end
end
diff --git a/test/pleroma/web/o_auth/app_test.exs b/test/pleroma/web/o_auth/app_test.exs
index a69ba371e..44219cf90 100644
--- a/test/pleroma/web/o_auth/app_test.exs
+++ b/test/pleroma/web/o_auth/app_test.exs
@@ -58,28 +58,16 @@ defmodule Pleroma.Web.OAuth.AppTest do
attrs = %{client_name: "Mastodon-Local", redirect_uris: "."}
{:ok, %App{} = old_app} = App.get_or_make(attrs, ["write"])
- # backdate the old app so it's within the threshold for being cleaned up
- one_hour_ago = DateTime.add(DateTime.utc_now(), -3600)
-
- {:ok, _} =
- "UPDATE apps SET inserted_at = $1, updated_at = $1 WHERE id = $2"
- |> Pleroma.Repo.query([one_hour_ago, old_app.id])
-
- # Create the new app after backdating the old one
attrs = %{client_name: "PleromaFE", redirect_uris: "."}
{:ok, %App{} = app} = App.get_or_make(attrs, ["write"])
- # Ensure the new app has a recent timestamp
- now = DateTime.utc_now()
-
+ # backdate the old app so it's within the threshold for being cleaned up
{:ok, _} =
- "UPDATE apps SET inserted_at = $1, updated_at = $1 WHERE id = $2"
- |> Pleroma.Repo.query([now, app.id])
+ "UPDATE apps SET inserted_at = now() - interval '1 hour' WHERE id = #{old_app.id}"
+ |> Pleroma.Repo.query()
App.remove_orphans()
- assert [returned_app] = Pleroma.Repo.all(App)
- assert returned_app.client_name == "PleromaFE"
- assert returned_app.id == app.id
+ assert [app] == Pleroma.Repo.all(App)
end
end
diff --git a/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs
index c1e452a1e..8c2dcc1bb 100644
--- a/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs
+++ b/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs
@@ -14,7 +14,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do
import Pleroma.Factory
setup do
- Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Test.StaticConfig)
+ Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
:ok
end
diff --git a/test/pleroma/web/plugs/instance_static_test.exs b/test/pleroma/web/plugs/instance_static_test.exs
index 33b74dcf0..f91021a16 100644
--- a/test/pleroma/web/plugs/instance_static_test.exs
+++ b/test/pleroma/web/plugs/instance_static_test.exs
@@ -62,79 +62,4 @@ defmodule Pleroma.Web.Plugs.InstanceStaticTest do
index = get(build_conn(), "/static/kaniini.html")
assert html_response(index, 200) == "rabbit hugs as a service "
end
-
- test "does not sanitize dangerous files in general, as there can be html and javascript files legitimately in this folder" do
- # Create a file with a potentially dangerous extension (.json)
- # This mimics an attacker trying to serve ActivityPub JSON with a static file
- File.mkdir!(@dir <> "/static")
- File.write!(@dir <> "/static/malicious.json", "{\"type\": \"ActivityPub\"}")
-
- conn = get(build_conn(), "/static/malicious.json")
-
- assert conn.status == 200
-
- content_type =
- Enum.find_value(conn.resp_headers, fn
- {"content-type", value} -> value
- _ -> nil
- end)
-
- assert content_type == "application/json"
-
- File.write!(@dir <> "/static/safe.jpg", "fake image data")
-
- conn = get(build_conn(), "/static/safe.jpg")
-
- assert conn.status == 200
-
- # Get the content-type
- content_type =
- Enum.find_value(conn.resp_headers, fn
- {"content-type", value} -> value
- _ -> nil
- end)
-
- assert content_type == "image/jpeg"
- end
-
- test "always sanitizes emojis to images" do
- File.mkdir!(@dir <> "/emoji")
- File.write!(@dir <> "/emoji/malicious.html", "")
-
- # Request the malicious file
- conn = get(build_conn(), "/emoji/malicious.html")
-
- # Verify the file was served (status 200)
- assert conn.status == 200
-
- # The content should be served, but with a sanitized content-type
- content_type =
- Enum.find_value(conn.resp_headers, fn
- {"content-type", value} -> value
- _ -> nil
- end)
-
- # It should have been sanitized to application/octet-stream because "application"
- # is not in the allowed_mime_types list
- assert content_type == "application/octet-stream"
-
- # Create a file with an allowed extension (.jpg)
- File.write!(@dir <> "/emoji/safe.jpg", "fake image data")
-
- # Request the safe file
- conn = get(build_conn(), "/emoji/safe.jpg")
-
- # Verify the file was served (status 200)
- assert conn.status == 200
-
- # Get the content-type
- content_type =
- Enum.find_value(conn.resp_headers, fn
- {"content-type", value} -> value
- _ -> nil
- end)
-
- # It should be preserved because "image" is in the allowed_mime_types list
- assert content_type == "image/jpeg"
- end
end
diff --git a/test/pleroma/web/plugs/uploaded_media_test.exs b/test/pleroma/web/plugs/uploaded_media_test.exs
deleted file mode 100644
index 69affa019..000000000
--- a/test/pleroma/web/plugs/uploaded_media_test.exs
+++ /dev/null
@@ -1,53 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.Plugs.UploadedMediaTest do
- use ExUnit.Case, async: true
-
- alias Pleroma.Web.Plugs.Utils
-
- describe "content-type sanitization with Utils.get_safe_mime_type/2" do
- test "it allows safe MIME types" do
- opts = %{allowed_mime_types: ["image", "audio", "video"]}
-
- assert Utils.get_safe_mime_type(opts, "image/jpeg") == "image/jpeg"
- assert Utils.get_safe_mime_type(opts, "audio/mpeg") == "audio/mpeg"
- assert Utils.get_safe_mime_type(opts, "video/mp4") == "video/mp4"
- end
-
- test "it sanitizes potentially dangerous content-types" do
- opts = %{allowed_mime_types: ["image", "audio", "video"]}
-
- assert Utils.get_safe_mime_type(opts, "application/activity+json") ==
- "application/octet-stream"
-
- assert Utils.get_safe_mime_type(opts, "text/html") == "application/octet-stream"
-
- assert Utils.get_safe_mime_type(opts, "application/javascript") ==
- "application/octet-stream"
- end
-
- test "it sanitizes ActivityPub content types" do
- opts = %{allowed_mime_types: ["image", "audio", "video"]}
-
- assert Utils.get_safe_mime_type(opts, "application/activity+json") ==
- "application/octet-stream"
-
- assert Utils.get_safe_mime_type(opts, "application/ld+json") == "application/octet-stream"
- assert Utils.get_safe_mime_type(opts, "application/jrd+json") == "application/octet-stream"
- end
-
- test "it sanitizes other potentially dangerous types" do
- opts = %{allowed_mime_types: ["image", "audio", "video"]}
-
- assert Utils.get_safe_mime_type(opts, "text/html") == "application/octet-stream"
-
- assert Utils.get_safe_mime_type(opts, "application/javascript") ==
- "application/octet-stream"
-
- assert Utils.get_safe_mime_type(opts, "text/javascript") == "application/octet-stream"
- assert Utils.get_safe_mime_type(opts, "application/xhtml+xml") == "application/octet-stream"
- end
- end
-end
diff --git a/test/pleroma/web/rich_media/card_test.exs b/test/pleroma/web/rich_media/card_test.exs
index c69f85323..387defc8c 100644
--- a/test/pleroma/web/rich_media/card_test.exs
+++ b/test/pleroma/web/rich_media/card_test.exs
@@ -83,23 +83,4 @@ defmodule Pleroma.Web.RichMedia.CardTest do
Card.get_by_activity(activity)
)
end
-
- test "refuses to crawl URL in activity from ignored host/domain" do
- clear_config([:rich_media, :ignore_hosts], ["example.com"])
-
- user = insert(:user)
-
- url = "https://example.com/ogp"
-
- {:ok, activity} =
- CommonAPI.post(user, %{
- status: "[test](#{url})",
- content_type: "text/markdown"
- })
-
- refute_enqueued(
- worker: RichMediaWorker,
- args: %{"url" => url, "activity_id" => activity.id}
- )
- end
end
diff --git a/test/pleroma/web/rich_media/parser_test.exs b/test/pleroma/web/rich_media/parser_test.exs
index 20f61badc..8fd75b57a 100644
--- a/test/pleroma/web/rich_media/parser_test.exs
+++ b/test/pleroma/web/rich_media/parser_test.exs
@@ -54,6 +54,7 @@ defmodule Pleroma.Web.RichMedia.ParserTest do
{:ok,
%{
"card" => "summary",
+ "site" => "@flickr",
"image" => "https://farm6.staticflickr.com/5510/14338202952_93595258ff_z.jpg",
"title" => "Small Island Developing States Photo Submission",
"description" => "View the album on Flickr.",
diff --git a/test/pleroma/web/rich_media/parsers/twitter_card_test.exs b/test/pleroma/web/rich_media/parsers/twitter_card_test.exs
index 15b272ff2..e84a4e50a 100644
--- a/test/pleroma/web/rich_media/parsers/twitter_card_test.exs
+++ b/test/pleroma/web/rich_media/parsers/twitter_card_test.exs
@@ -17,6 +17,10 @@ defmodule Pleroma.Web.RichMedia.Parsers.TwitterCardTest do
assert TwitterCard.parse(html, %{}) ==
%{
+ "app:id:googleplay" => "com.nytimes.android",
+ "app:name:googleplay" => "NYTimes",
+ "app:url:googleplay" => "nytimes://reader/id/100000006583622",
+ "site" => nil,
"description" =>
"With little oversight, the N.Y.P.D. has been using powerful surveillance technology on photos of children and teenagers.",
"image" =>
@@ -40,7 +44,7 @@ defmodule Pleroma.Web.RichMedia.Parsers.TwitterCardTest do
"description" =>
"With little oversight, the N.Y.P.D. has been using powerful surveillance technology on photos of children and teenagers.",
"image" =>
- "https://static01.nyt.com/images/2019/08/01/nyregion/01nypd-juveniles-promo/01nypd-juveniles-promo-facebookJumbo.jpg",
+ "https://static01.nyt.com/images/2019/08/01/nyregion/01nypd-juveniles-promo/01nypd-juveniles-promo-videoSixteenByNineJumbo1600.jpg",
"image:alt" => "",
"title" =>
"She Was Arrested at 14. Then Her Photo Went to a Facial Recognition Database.",
@@ -57,12 +61,16 @@ defmodule Pleroma.Web.RichMedia.Parsers.TwitterCardTest do
assert TwitterCard.parse(html, %{}) ==
%{
+ "app:id:googleplay" => "com.nytimes.android",
+ "app:name:googleplay" => "NYTimes",
+ "app:url:googleplay" => "nytimes://reader/id/100000006583622",
"card" => "summary_large_image",
"description" =>
"With little oversight, the N.Y.P.D. has been using powerful surveillance technology on photos of children and teenagers.",
"image" =>
- "https://static01.nyt.com/images/2019/08/01/nyregion/01nypd-juveniles-promo/01nypd-juveniles-promo-facebookJumbo.jpg",
+ "https://static01.nyt.com/images/2019/08/01/nyregion/01nypd-juveniles-promo/01nypd-juveniles-promo-videoSixteenByNineJumbo1600.jpg",
"image:alt" => "",
+ "site" => nil,
"title" =>
"She Was Arrested at 14. Then Her Photo Went to a Facial Recognition Database.",
"url" =>
@@ -82,11 +90,13 @@ defmodule Pleroma.Web.RichMedia.Parsers.TwitterCardTest do
assert TwitterCard.parse(html, %{}) ==
%{
+ "site" => "@atlasobscura",
"title" => "The Missing Grave of Margaret Corbin, Revolutionary War Veteran",
"card" => "summary_large_image",
"image" => image_path,
"description" =>
"She's the only woman veteran honored with a monument at West Point. But where was she buried?",
+ "site_name" => "Atlas Obscura",
"type" => "article",
"url" => "http://www.atlasobscura.com/articles/margaret-corbin-grave-west-point"
}
@@ -99,8 +109,12 @@ defmodule Pleroma.Web.RichMedia.Parsers.TwitterCardTest do
assert TwitterCard.parse(html, %{}) ==
%{
+ "site" => nil,
"title" =>
"She Was Arrested at 14. Then Her Photo Went to a Facial Recognition Database.",
+ "app:id:googleplay" => "com.nytimes.android",
+ "app:name:googleplay" => "NYTimes",
+ "app:url:googleplay" => "nytimes://reader/id/100000006583622",
"description" =>
"With little oversight, the N.Y.P.D. has been using powerful surveillance technology on photos of children and teenagers.",
"image" =>
@@ -110,23 +124,4 @@ defmodule Pleroma.Web.RichMedia.Parsers.TwitterCardTest do
"https://www.nytimes.com/2019/08/01/nyregion/nypd-facial-recognition-children-teenagers.html"
}
end
-
- test "takes first image if multiple are specified" do
- html =
- File.read!("test/fixtures/fulmo.html")
- |> Floki.parse_document!()
-
- assert TwitterCard.parse(html, %{}) ==
- %{
- "description" => "Pri feoj, kiuj devis ordigi falintan arbon.",
- "image" => "https://tirifto.xwx.moe/r/ilustrajhoj/pinglordigado.png",
- "title" => "Fulmo",
- "type" => "website",
- "url" => "https://tirifto.xwx.moe/eo/rakontoj/fulmo.html",
- "image:alt" =>
- "Meze de arbaro kuŝas falinta trunko, sen pingloj kaj kun branĉoj derompitaj. Post ĝi videblas du feoj: florofeo maldekstre kaj nubofeo dekstre. La florofeo iom kaŝas sin post la trunko. La nubofeo staras kaj tenas amason da pigloj. Ili iom rigardas al si.",
- "image:height" => "630",
- "image:width" => "1200"
- }
- end
end
diff --git a/test/pleroma/web/streamer_test.exs b/test/pleroma/web/streamer_test.exs
index 85978e824..262ff11d2 100644
--- a/test/pleroma/web/streamer_test.exs
+++ b/test/pleroma/web/streamer_test.exs
@@ -558,36 +558,6 @@ defmodule Pleroma.Web.StreamerTest do
assert_receive {:render_with_user, _, "status_update.json", ^create, _}
refute Streamer.filtered_by_user?(user, edited)
end
-
- test "it streams posts containing followed hashtags on the 'user' stream", %{
- user: user,
- token: oauth_token
- } do
- hashtag = insert(:hashtag, %{name: "tenshi"})
- other_user = insert(:user)
- {:ok, user} = User.follow_hashtag(user, hashtag)
-
- Streamer.get_topic_and_add_socket("user", user, oauth_token)
- {:ok, activity} = CommonAPI.post(other_user, %{status: "hey #tenshi"})
-
- assert_receive {:render_with_user, _, "update.json", ^activity, _}
- end
-
- test "should not stream private posts containing followed hashtags on the 'user' stream", %{
- user: user,
- token: oauth_token
- } do
- hashtag = insert(:hashtag, %{name: "tenshi"})
- other_user = insert(:user)
- {:ok, user} = User.follow_hashtag(user, hashtag)
-
- Streamer.get_topic_and_add_socket("user", user, oauth_token)
-
- {:ok, activity} =
- CommonAPI.post(other_user, %{status: "hey #tenshi", visibility: "private"})
-
- refute_receive {:render_with_user, _, "update.json", ^activity, _}
- end
end
describe "public streams" do
diff --git a/test/pleroma/workers/cron/digest_emails_worker_test.exs b/test/pleroma/workers/cron/digest_emails_worker_test.exs
index 46be82a4f..e0bdf303e 100644
--- a/test/pleroma/workers/cron/digest_emails_worker_test.exs
+++ b/test/pleroma/workers/cron/digest_emails_worker_test.exs
@@ -14,7 +14,7 @@ defmodule Pleroma.Workers.Cron.DigestEmailsWorkerTest do
setup do: clear_config([:email_notifications, :digest])
setup do
- Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Test.StaticConfig)
+ Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
:ok
end
diff --git a/test/pleroma/workers/cron/new_users_digest_worker_test.exs b/test/pleroma/workers/cron/new_users_digest_worker_test.exs
index ca4139eac..0e4234cc8 100644
--- a/test/pleroma/workers/cron/new_users_digest_worker_test.exs
+++ b/test/pleroma/workers/cron/new_users_digest_worker_test.exs
@@ -11,7 +11,7 @@ defmodule Pleroma.Workers.Cron.NewUsersDigestWorkerTest do
alias Pleroma.Workers.Cron.NewUsersDigestWorker
setup do
- Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Test.StaticConfig)
+ Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
:ok
end
diff --git a/test/support/data_case.ex b/test/support/data_case.ex
index 304bee5da..52d4bef1a 100644
--- a/test/support/data_case.ex
+++ b/test/support/data_case.ex
@@ -117,8 +117,6 @@ defmodule Pleroma.DataCase do
Mox.stub_with(Pleroma.ConfigMock, Pleroma.Config)
Mox.stub_with(Pleroma.StaticStubbedConfigMock, Pleroma.Test.StaticConfig)
Mox.stub_with(Pleroma.StubbedHTTPSignaturesMock, Pleroma.Test.HTTPSignaturesProxy)
-
- Mox.stub_with(Pleroma.DateTimeMock, Pleroma.DateTime.Impl)
end
def ensure_local_uploader(context) do
diff --git a/test/support/factory.ex b/test/support/factory.ex
index 88c4ed8e5..91e5805c8 100644
--- a/test/support/factory.ex
+++ b/test/support/factory.ex
@@ -668,11 +668,4 @@ defmodule Pleroma.Factory do
|> Map.merge(params)
|> Pleroma.Announcement.add_rendered_properties()
end
-
- def hashtag_factory(params \\ %{}) do
- %Pleroma.Hashtag{
- name: "test #{sequence(:hashtag_name, & &1)}"
- }
- |> Map.merge(params)
- end
end
diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex
index 1c472fca9..ed044cf98 100644
--- a/test/support/http_request_mock.ex
+++ b/test/support/http_request_mock.ex
@@ -955,7 +955,7 @@ defmodule HttpRequestMock do
{:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/ogp.html")}}
end
- def get("https://remote.org/users/masto_closed/followers", _, _, _) do
+ def get("http://localhost:4001/users/masto_closed/followers", _, _, _) do
{:ok,
%Tesla.Env{
status: 200,
@@ -964,7 +964,7 @@ defmodule HttpRequestMock do
}}
end
- def get("https://remote.org/users/masto_closed/followers?page=1", _, _, _) do
+ def get("http://localhost:4001/users/masto_closed/followers?page=1", _, _, _) do
{:ok,
%Tesla.Env{
status: 200,
@@ -973,7 +973,7 @@ defmodule HttpRequestMock do
}}
end
- def get("https://remote.org/users/masto_closed/following", _, _, _) do
+ def get("http://localhost:4001/users/masto_closed/following", _, _, _) do
{:ok,
%Tesla.Env{
status: 200,
@@ -982,7 +982,7 @@ defmodule HttpRequestMock do
}}
end
- def get("https://remote.org/users/masto_closed/following?page=1", _, _, _) do
+ def get("http://localhost:4001/users/masto_closed/following?page=1", _, _, _) do
{:ok,
%Tesla.Env{
status: 200,
@@ -991,7 +991,7 @@ defmodule HttpRequestMock do
}}
end
- def get("https://remote.org/followers/fuser3", _, _, _) do
+ def get("http://localhost:8080/followers/fuser3", _, _, _) do
{:ok,
%Tesla.Env{
status: 200,
@@ -1000,7 +1000,7 @@ defmodule HttpRequestMock do
}}
end
- def get("https://remote.org/following/fuser3", _, _, _) do
+ def get("http://localhost:8080/following/fuser3", _, _, _) do
{:ok,
%Tesla.Env{
status: 200,
@@ -1009,7 +1009,7 @@ defmodule HttpRequestMock do
}}
end
- def get("https://remote.org/users/fuser2/followers", _, _, _) do
+ def get("http://localhost:4001/users/fuser2/followers", _, _, _) do
{:ok,
%Tesla.Env{
status: 200,
@@ -1018,7 +1018,7 @@ defmodule HttpRequestMock do
}}
end
- def get("https://remote.org/users/fuser2/following", _, _, _) do
+ def get("http://localhost:4001/users/fuser2/following", _, _, _) do
{:ok,
%Tesla.Env{
status: 200,
diff --git a/test/support/mocks.ex b/test/support/mocks.ex
index ca2974504..d84958e15 100644
--- a/test/support/mocks.ex
+++ b/test/support/mocks.ex
@@ -33,6 +33,3 @@ Mox.defmock(Pleroma.StubbedHTTPSignaturesMock, for: Pleroma.HTTPSignaturesAPI)
Mox.defmock(Pleroma.LoggerMock, for: Pleroma.Logging)
Mox.defmock(Pleroma.Uploaders.S3.ExAwsMock, for: Pleroma.Uploaders.S3.ExAwsAPI)
-
-Mox.defmock(Pleroma.DateTimeMock, for: Pleroma.DateTime)
-Mox.defmock(Pleroma.MogrifyMock, for: Pleroma.MogrifyBehaviour)
diff --git a/test/test_helper.exs b/test/test_helper.exs
index 94661353b..fed7ce8a7 100644
--- a/test/test_helper.exs
+++ b/test/test_helper.exs
@@ -34,13 +34,7 @@ defmodule Pleroma.Test.StaticConfig do
@behaviour Pleroma.Config.Getting
@config Application.get_all_env(:pleroma)
- @impl true
def get(path, default \\ nil) do
get_in(@config, path) || default
end
-
- @impl true
- def get!(path) do
- get_in(@config, path)
- end
end