Compare commits

...

67 Commits

Author SHA1 Message Date
Haelwenn (lanodan) Monnier
1d49a440b2
CommonAPI: Allow URLs into media_ids 2021-08-28 05:41:34 +02:00
Haelwenn
84ec0fbeaa Merge branch 'show_frontends_also_when_no_static_frontends_folder_is_created_yet' into 'develop'
List available frontends also when no static/frontends folder is present yet

Closes admin-fe#201

See merge request pleroma/pleroma!3510
2021-08-14 18:42:12 +00:00
Ilja
f9bafc17fb List available frontends also when no static/frontends folder is present yet
* To see what front ends are installed, it ls static/frontends. When this folder doesn't exists yet, it will return an empty array.
* Installing still works since the folder is created during installation already
2021-08-14 18:42:12 +00:00
Haelwenn
2d9f803dc6 Merge branch 'StealEmojiMRF_add_adminFE' into 'develop'
Add Admin-FE menu for StealEmojiPolicy

See merge request pleroma/pleroma!3512
2021-08-14 18:40:24 +00:00
Haelwenn
773708cfe8 Merge branch 'builder-note' into 'develop'
CommonAPI.Utils.make_note_data/1 --> ActivityPub.Builder.note/1

See merge request pleroma/pleroma!3511
2021-08-14 18:32:40 +00:00
Alex Gleason
ba6049aa81
Builder.note/1: return {:ok, map(), keyword()} like other Builder functions 2021-08-14 11:24:55 -05:00
Sam Therapy
b901b73057
Add Admin-FE menu for StealEmojiPolicy 2021-08-14 11:08:39 -05:00
Alex Gleason
a2eacfc525
CommonAPI.Utils.make_note_data/1 --> ActivityPub.Builder.note/1 2021-08-14 11:01:06 -05:00
Haelwenn
97eb160c3e Merge branch 'weblate-pleroma-pleroma' into 'develop'
Translations update from Weblate

See merge request pleroma/pleroma!3491
2021-08-13 15:55:33 +00:00
marcin mikołajczak
edd2a38e53 Translated using Weblate (Polish)
Currently translated at 98.0% (102 of 104 strings)

Translation: Pleroma/Pleroma backend
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma/pl/
2021-08-13 15:42:21 +00:00
marcin mikołajczak
7a9113deb1 Translated using Weblate (Polish)
Currently translated at 75.0% (78 of 104 strings)

Translation: Pleroma/Pleroma backend
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma/pl/
2021-08-13 15:42:21 +00:00
Haelwenn
61ba54897e Merge branch 'streamer-crash-fix' into 'develop'
Streamer crash fix

See merge request pleroma/pleroma!3508
2021-08-13 15:42:12 +00:00
Alex Gleason
b7bbf42acd
Streamer: fix crash in MastodonAPI.StatusView 2021-08-13 10:25:42 -05:00
rinpatch
21720db859 Merge branch 'dkuku-develop-patch-66061' into 'develop'
Update dev.exs error message to write to stderr.

See merge request pleroma/pleroma!3492
2021-08-13 12:10:52 +00:00
rinpatch
7afabe1cc6 Merge branch 'bugfix/status-search-fallback' into 'develop'
Activity.Search: resolve status on DB Timeout

Closes #2566

See merge request pleroma/pleroma!3507
2021-08-13 12:09:39 +00:00
Haelwenn (lanodan) Monnier
6455b967ec
Activity.Search: fallback on status resolution on DB Timeout 2021-08-12 10:35:32 +02:00
Haelwenn
3a7b54be4a Merge branch 'nil-report-object-hotfix' into 'develop'
AdminAPI: hotfix for nil report objects

See merge request pleroma/pleroma!3504
2021-08-11 20:30:43 +00:00
Haelwenn
3ca39ccf69 Merge branch 'bugfix/subscriptions-replies' into 'develop'
maybe_notify_subscribers: Normalize Object to check inReplyTo presence

Closes #2732

See merge request pleroma/pleroma!3505
2021-08-11 18:50:39 +00:00
Haelwenn (lanodan) Monnier
436fac3bac
maybe_notify_subscribers: Don't create notifications from ingested messages 2021-08-11 20:49:38 +02:00
Alex Gleason
7247c29653
AdminAPI: hotfix for nil report objects 2021-08-11 09:42:19 -05:00
Haelwenn
7c1243178b Merge branch 'bugfix/change_password' into 'develop'
TwitterAPI: Make change_password require body params instead of query

Closes #2740

See merge request pleroma/pleroma!3503
2021-08-10 18:40:13 +00:00
Haelwenn (lanodan) Monnier
197cdebca9
TwitterAPI: Make change_email require body params instead of query 2021-08-10 20:33:00 +02:00
Haelwenn
8679a57a71 Merge branch 'bugfix/object-age-create' into 'develop'
ObjectAgePolicy: Fix pattern matching on published

See merge request pleroma/pleroma!3500
2021-08-10 18:16:02 +00:00
Haelwenn (lanodan) Monnier
09dcb2b522
TwitterAPI: Make change_password require body params instead of query
Closes: https://git.pleroma.social/pleroma/pleroma/-/issues/2740
2021-08-10 20:01:11 +02:00
Haelwenn
6c0ebc65fd Merge branch 'docs_make_otp_recommendation_clearer' into 'develop'
Make the OPT recomendation clearer

See merge request pleroma/pleroma!3485
2021-08-10 06:09:31 +00:00
Ilja
438ad0d3f9 Make the OPT recomendation clearer
AFAIK OTP releases are the recomended way of installing, but

  * People seem unaware of that and use from source installations because they use the guide with the name of their distro
  * People don't know what OTP releases are or what it means

I added a warning on all installation-from-source guides and added the same explanation on the two OTP pages (the miigration to OTP and installing OTP)
2021-08-10 06:09:31 +00:00
Haelwenn (lanodan) Monnier
c64eae40a2
ObjectAgePolicy: Fix pattern matching on published 2021-08-10 07:41:06 +02:00
Haelwenn
f4af74b0fc Merge branch 'fix/streaming-api-for-create-activity' into 'develop'
fix: stream out Create Activity

Closes #2691

See merge request pleroma/pleroma!3499
2021-08-09 19:10:05 +00:00
Haelwenn
901204df22 Merge branch 'poll-notification' into 'develop'
MastodonAPI: Support poll notification

See merge request pleroma/pleroma!3484
2021-08-09 10:02:37 +00:00
Haelwenn
6384d78035 Merge branch 'simple_policy_reasons_for_instance_specific_policies' into 'develop'
Simple policy reasons for instance specific policies

See merge request pleroma/pleroma!3314
2021-08-09 09:37:59 +00:00
kPherox
ee5def34da
fix: stream out Create Activity 2021-08-09 18:37:48 +09:00
Haelwenn
c45b3bde94 Merge branch 'chores/2.4.0-develop' into 'develop'
Mergeback: 2.4.0

See merge request pleroma/pleroma!3494
2021-08-08 14:40:51 +00:00
Haelwenn (lanodan) Monnier
8f730f70cb
mix.exs: 2.4.50 2021-08-08 16:00:10 +02:00
Egor Kislitsyn
ad09bdb376
Improve readability 2021-08-06 07:59:54 +02:00
Ilja
ee26f2c91b
Quarantine placeholders
* kePlaceholder and valuePlaceholder of quarantined_instances where in wrong case, should be snake_case
* The mrf simple and transparency exclusion were already OK
2021-08-06 07:59:54 +02:00
Ilja
cd706c0335
improve changelog entry 2021-08-06 07:59:54 +02:00
Ilja
b0926a71b2
Make transparency_exclusions use tuples in admin-fe
* Make it use tuples
* I also changed the keys for key_placeholder and value_placeholder to use snake_case instead of camelCase
2021-08-06 07:59:53 +02:00
Ilja
f4028c908c
Add key- and valuePlaceholders for quarantined_instances and mrf_simple
* I also added for keywordpolicy as well now. It was done in the admin-fe, but is better to be done here
* I also added comments to explain why we did the _info keys (backwards compatibility)
2021-08-06 07:59:53 +02:00
Ilja
9418424048
Add transparency_exclusions also to the breaking changes 2021-08-06 07:59:53 +02:00
Ilja
506bf16363
Change docs
* ./configuration/mrf.md
  * Change example
* ./configuration/cheatsheet.md
  * Change descriptions to include that a reason is given
* CHANGELOG.md
  * Add as breaking change
2021-08-06 07:59:53 +02:00
Ilja
03030b47c2
quarantine instances info
Added a new field in the nodeinfo called quarantined_instances_info
This holds an object like `"quarantined_instances_info":{"quarantined_instances":{"quar.inst":{"reason":"whatever reason"}}}}`
2021-08-06 07:59:53 +02:00
Ilja
47fc57bbcc
Change what nodeinfo returns without breaking backwards compatibility
* Only for SimplePolicy for now
* I added an extra mrf_simple_info key that has an object as value. The object contains only relevant extra info
2021-08-06 07:59:53 +02:00
Ilja
7fdc3cde06
Return maps in node_info
It's easiest (and imo most proper) to use tuples {"instance, "reason"} in BE,
but for FE maps like %{"instance": "instance", "reason", "reason"} are better.
I changed it so that node_info returns maps now for simple_policy and quarantined instances.
2021-08-06 07:59:53 +02:00
Ilja
1f52246a02
Add database migrations
* SimplePolicy
* quarentine
* transparency_exclusions
2021-08-06 07:59:53 +02:00
Ilja
c0489f9fac
Fixed deprecation warning checks
When a setting was deprecated, the code would stop checking for the rest of the possible deprications. This also meant that the settings weren't rewritten to the new settings for deprecated settings besides the first one.
2021-08-06 07:59:53 +02:00
Ilja
64002e92ad
config/description.exs: Update quarantine settings to tuples 2021-08-06 07:59:53 +02:00
Ilja
b674ba658b
make linter happy 2021-08-06 07:59:52 +02:00
Ilja
3c5a497b19
Deprecate transparency_exclusions
* Give deprecation message
* Rewrite configs
2021-08-06 07:59:52 +02:00
Ilja
dfeb3862da
config :mrf, :transparency_exclusions works with tumples now 2021-08-06 07:59:52 +02:00
Ilja
e0c7d77197
Deprecate and rewrite settings for quarentine settings
* This is for the settings, not yet a DB migration
2021-08-06 07:59:52 +02:00
Ilja
27fe7b0274
Make quarentine work with list of tuples instead of strings 2021-08-06 07:59:52 +02:00
Ilja
dd947d9bc8
Add tests for setting :instance, :quarantined_instances
No test was done for quarantined instances yet. I added a factory for followers_only notes and checked
* That no followers only post is send when the target server is quarantined
* That a followers only post is send when the target server is not quarantined
2021-08-06 07:59:52 +02:00
Ilja
4ba0beb60c
Make mrfSimple work with tuples
* Changed SimplePolicy
* I also grepped in test/ for ':mrf_simple' to see what other things could be affected
2021-08-06 07:58:58 +02:00
Ilja
647087d7fd
Deprectate strings for SimplePolicy
When strings are detected in the simplepolicy, a warning will be given and the config will be changed to use tuples instead
2021-08-06 05:01:44 +02:00
Haelwenn
5f5dc24027 Merge branch 'staff-plug' into 'develop'
Moderators: add UserIsStaffPlug

See merge request pleroma/pleroma!3495
2021-08-05 05:51:22 +00:00
Alex Gleason
44ede0657f
Merge remote-tracking branch 'pleroma/develop' into staff-plug 2021-08-04 11:48:57 -05:00
Daniel
5c5571c668 use puts instead warn 2021-07-27 21:01:41 +00:00
Daniel
69ebfb29fb Update dev.exs error message to write to stderr. Currently it dumps this message at the beginnig of the file when using vim-autoformat with mix format 2021-07-27 20:41:36 +00:00
Alex Gleason
85d71d4f1d
CHANGELOG: Support poll notification type 2021-07-18 11:49:25 -05:00
Alex Gleason
62bf6d67e3
Merge remote-tracking branch 'pleroma/develop' into poll-notification-fixes 2021-07-18 11:49:22 -05:00
Alex Gleason
70f1496eb8
Poll notification: only notify local users 2021-07-18 11:10:23 -05:00
Alex Gleason
0b1c05ca1e
Poll notification: trigger PollWorker through common_pipeline 2021-07-18 11:10:23 -05:00
Alex Gleason
6a6e42c9bf
PollWorker defensive checks 2021-07-18 11:10:22 -05:00
Alex Gleason
cbd1a10c16
Poll notification: notify for polls even when block_from_strangers is set 2021-07-18 11:10:04 -05:00
Alex Gleason
0114754db2
MastodonAPI: Support poll notification 2021-07-17 22:19:38 -05:00
Alex Gleason
1f093cb216
Moderators: reorganize :admin_api pipeline in Router 2021-07-12 22:11:32 -05:00
Alex Gleason
9bc1e79c56
Moderators: add UserIsStaffPlug 2021-07-12 21:57:52 -05:00
70 changed files with 1739 additions and 464 deletions

View File

@ -7,18 +7,24 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## Unreleased ## Unreleased
### Changed ### Changed
- MastodonAPI: Allow to pass arbitrary URLs when creating a status
### Added ### Added
### Fixed ### Fixed
- Subscription(Bell) Notifications: Don't create from Pipeline Ingested replies
### Removed ### Removed
## Unreleased-patch
- Mastodon API: Activity Search fallbacks on status fetching after a DB Timeout/Error
## 2.4.0 - 2021-08-xx ## 2.4.0 - 2021-08-xx
### Changed ### Changed
- **Breaking:** Configuration: `:chat, enabled` moved to `:shout, enabled` and `:instance, chat_limit` moved to `:shout, limit` - **Breaking:** Configuration: `:chat, enabled` moved to `:shout, enabled` and `:instance, chat_limit` moved to `:shout, limit`
- **Breaking** Entries for simple_policy, transparency_exclusions and quarantined_instances now list both the instance and a reason.
- Support for Erlang/OTP 24 - Support for Erlang/OTP 24
- The `application` metadata returned with statuses is no longer hardcoded. Apps that want to display these details will now have valid data for new posts after this change. - The `application` metadata returned with statuses is no longer hardcoded. Apps that want to display these details will now have valid data for new posts after this change.
- HTTPSecurityPlug now sends a response header to opt out of Google's FLoC (Federated Learning of Cohorts) targeted advertising. - HTTPSecurityPlug now sends a response header to opt out of Google's FLoC (Federated Learning of Cohorts) targeted advertising.
@ -34,6 +40,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- AdminAPI: return `created_at` date with users. - AdminAPI: return `created_at` date with users.
- `AnalyzeMetadata` upload filter for extracting image/video attachment dimensions and generating blurhashes for images. Blurhashes for videos are not generated at this time. - `AnalyzeMetadata` upload filter for extracting image/video attachment dimensions and generating blurhashes for images. Blurhashes for videos are not generated at this time.
- Attachment dimensions and blurhashes are federated when available. - Attachment dimensions and blurhashes are federated when available.
- Mastodon API: support `poll` notification.
- Pinned posts federation - Pinned posts federation
### Fixed ### Fixed

View File

@ -560,6 +560,7 @@ config :pleroma, Oban,
mailer: 10, mailer: 10,
transmogrifier: 20, transmogrifier: 20,
scheduled_activities: 10, scheduled_activities: 10,
poll_notifications: 10,
background: 5, background: 5,
remote_fetcher: 2, remote_fetcher: 2,
attachments_cleanup: 1, attachments_cleanup: 1,

View File

@ -687,12 +687,14 @@ config :pleroma, :config_description, [
}, },
%{ %{
key: :quarantined_instances, key: :quarantined_instances,
type: {:list, :string}, type: {:list, :tuple},
key_placeholder: "instance",
value_placeholder: "reason",
description: description:
"List of ActivityPub instances where private (DMs, followers-only) activities will not be sent", "List of ActivityPub instances where private (DMs, followers-only) activities will not be sent and the reason for doing so",
suggestions: [ suggestions: [
"quarantined.com", {"quarantined.com", "Reason"},
"*.quarantined.com" {"*.quarantined.com", "Reason"}
] ]
}, },
%{ %{

View File

@ -62,6 +62,7 @@ if File.exists?("./config/dev.secret.exs") do
import_config "dev.secret.exs" import_config "dev.secret.exs"
else else
IO.puts( IO.puts(
:stderr,
"!!! RUNNING IN LOCALHOST DEV MODE! !!!\nFEDERATION WON'T WORK UNTIL YOU CONFIGURE A dev.secret.exs" "!!! RUNNING IN LOCALHOST DEV MODE! !!!\nFEDERATION WON'T WORK UNTIL YOU CONFIGURE A dev.secret.exs"
) )
end end

View File

@ -39,7 +39,7 @@ To add configuration to your config file, you can copy it from the base config.
* `federation_reachability_timeout_days`: Timeout (in days) of each external federation target being unreachable prior to pausing federating to it. * `federation_reachability_timeout_days`: Timeout (in days) of each external federation target being unreachable prior to pausing federating to it.
* `allow_relay`: Permits remote instances to subscribe to all public posts of your instance. This may increase the visibility of your instance. * `allow_relay`: Permits remote instances to subscribe to all public posts of your instance. This may increase the visibility of your instance.
* `public`: Makes the client API in authenticated mode-only except for user-profiles. Useful for disabling the Local Timeline and The Whole Known Network. Note that there is a dependent setting restricting or allowing unauthenticated access to specific resources, see `restrict_unauthenticated` for more details. * `public`: Makes the client API in authenticated mode-only except for user-profiles. Useful for disabling the Local Timeline and The Whole Known Network. Note that there is a dependent setting restricting or allowing unauthenticated access to specific resources, see `restrict_unauthenticated` for more details.
* `quarantined_instances`: List of ActivityPub instances where private (DMs, followers-only) activities will not be send. * `quarantined_instances`: ActivityPub instances where private (DMs, followers-only) activities will not be send.
* `allowed_post_formats`: MIME-type list of formats allowed to be posted (transformed into HTML). * `allowed_post_formats`: MIME-type list of formats allowed to be posted (transformed into HTML).
* `extended_nickname_format`: Set to `true` to use extended local nicknames format (allows underscores/dashes). This will break federation with * `extended_nickname_format`: Set to `true` to use extended local nicknames format (allows underscores/dashes). This will break federation with
older software for theses nicknames. older software for theses nicknames.
@ -135,15 +135,16 @@ To add configuration to your config file, you can copy it from the base config.
Configuring MRF policies is not enough for them to take effect. You have to enable them by specifying their module in `policies` under [:mrf](#mrf) section. Configuring MRF policies is not enough for them to take effect. You have to enable them by specifying their module in `policies` under [:mrf](#mrf) section.
#### :mrf_simple #### :mrf_simple
* `media_removal`: List of instances to remove media from. * `media_removal`: List of instances to strip media attachments from and the reason for doing so.
* `media_nsfw`: List of instances to put media as NSFW(sensitive) from. * `media_nsfw`: List of instances to tag all media as NSFW (sensitive) from and the reason for doing so.
* `federated_timeline_removal`: List of instances to remove from Federated (aka The Whole Known Network) Timeline. * `federated_timeline_removal`: List of instances to remove from the Federated Timeline (aka The Whole Known Network) and the reason for doing so.
* `reject`: List of instances to reject any activities from. * `reject`: List of instances to reject activities (except deletes) from and the reason for doing so.
* `accept`: List of instances to accept any activities from. * `accept`: List of instances to only accept activities (except deletes) from and the reason for doing so.
* `followers_only`: List of instances to decrease post visibility to only the followers, including for DM mentions. * `followers_only`: Force posts from the given instances to be visible by followers only and the reason for doing so.
* `report_removal`: List of instances to reject reports from. * `report_removal`: List of instances to reject reports from and the reason for doing so.
* `avatar_removal`: List of instances to strip avatars from. * `avatar_removal`: List of instances to strip avatars from and the reason for doing so.
* `banner_removal`: List of instances to strip banners from. * `banner_removal`: List of instances to strip banners from and the reason for doing so.
* `reject_deletes`: List of instances to reject deletions from and the reason for doing so.
#### :mrf_subchain #### :mrf_subchain
This policy processes messages through an alternate pipeline when a given message matches certain criteria. This policy processes messages through an alternate pipeline when a given message matches certain criteria.

View File

@ -55,18 +55,18 @@ Servers should be configured as lists.
### Example ### Example
This example will enable `SimplePolicy`, block media from `illegalporn.biz`, mark media as NSFW from `porn.biz` and `porn.business`, reject messages from `spam.com`, remove messages from `spam.university` from the federated timeline and block reports (flags) from `whiny.whiner`: This example will enable `SimplePolicy`, block media from `illegalporn.biz`, mark media as NSFW from `porn.biz` and `porn.business`, reject messages from `spam.com`, remove messages from `spam.university` from the federated timeline and block reports (flags) from `whiny.whiner`. We also give a reason why the moderation was done:
```elixir ```elixir
config :pleroma, :mrf, config :pleroma, :mrf,
policies: [Pleroma.Web.ActivityPub.MRF.SimplePolicy] policies: [Pleroma.Web.ActivityPub.MRF.SimplePolicy]
config :pleroma, :mrf_simple, config :pleroma, :mrf_simple,
media_removal: ["illegalporn.biz"], media_removal: [{"illegalporn.biz", "Media can contain illegal contant"}],
media_nsfw: ["porn.biz", "porn.business"], media_nsfw: [{"porn.biz", "unmarked nsfw media"}, {"porn.business", "A lot of unmarked nsfw media"}],
reject: ["spam.com"], reject: [{"spam.com", "They keep spamming our users"}],
federated_timeline_removal: ["spam.university"], federated_timeline_removal: [{"spam.university", "Annoying low-quality posts who otherwise fill up TWKN"}],
report_removal: ["whiny.whiner"] report_removal: [{"whiny.whiner", "Keep spamming us with irrelevant reports"}]
``` ```
### Use with Care ### Use with Care

View File

@ -1,4 +1,7 @@
# Installing on Alpine Linux # Installing on Alpine Linux
{! backend/installation/otp_vs_from_source_source.include !}
## Installation ## Installation
This guide is a step-by-step installation guide for Alpine Linux. The instructions were verified against Alpine v3.10 standard image. You might miss additional dependencies if you use `netboot` instead. This guide is a step-by-step installation guide for Alpine Linux. The instructions were verified against Alpine v3.10 standard image. You might miss additional dependencies if you use `netboot` instead.

View File

@ -1,4 +1,7 @@
# Installing on Arch Linux # Installing on Arch Linux
{! backend/installation/otp_vs_from_source_source.include !}
## Installation ## Installation
This guide will assume that you have administrative rights, either as root or a user with [sudo permissions](https://wiki.archlinux.org/index.php/Sudo). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su <username> -s $SHELL -c 'command'` instead. This guide will assume that you have administrative rights, either as root or a user with [sudo permissions](https://wiki.archlinux.org/index.php/Sudo). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su <username> -s $SHELL -c 'command'` instead.

View File

@ -1,4 +1,7 @@
# Installing on Debian Based Distributions # Installing on Debian Based Distributions
{! backend/installation/otp_vs_from_source_source.include !}
## Installation ## Installation
This guide will assume you are on Debian 11 (“bullseye”) or later. This guide should also work with Ubuntu 18.04 (“Bionic Beaver”) and later. It also assumes that you have administrative rights, either as root or a user with [sudo permissions](https://www.digitalocean.com/community/tutorials/how-to-add-delete-and-grant-sudo-privileges-to-users-on-a-debian-vps). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su <username> -s $SHELL -c 'command'` instead. This guide will assume you are on Debian 11 (“bullseye”) or later. This guide should also work with Ubuntu 18.04 (“Bionic Beaver”) and later. It also assumes that you have administrative rights, either as root or a user with [sudo permissions](https://www.digitalocean.com/community/tutorials/how-to-add-delete-and-grant-sudo-privileges-to-users-on-a-debian-vps). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su <username> -s $SHELL -c 'command'` instead.

View File

@ -1,4 +1,7 @@
# Installing on Gentoo GNU/Linux # Installing on Gentoo GNU/Linux
{! backend/installation/otp_vs_from_source_source.include !}
## Installation ## Installation
This guide will assume that you have administrative rights, either as root or a user with [sudo permissions](https://wiki.gentoo.org/wiki/Sudo). Lines that begin with `#` indicate that they should be run as the superuser. Lines using `$` should be run as the indicated user, e.g. `pleroma$` should be run as the `pleroma` user. This guide will assume that you have administrative rights, either as root or a user with [sudo permissions](https://wiki.gentoo.org/wiki/Sudo). Lines that begin with `#` indicate that they should be run as the superuser. Lines using `$` should be run as the indicated user, e.g. `pleroma$` should be run as the `pleroma` user.

View File

@ -1,7 +1,8 @@
# Switching a from-source install to OTP releases # Switching a from-source install to OTP releases
## What are OTP releases? {! backend/installation/otp_vs_from_source.include !}
OTP releases are as close as you can get to binary releases with Erlang/Elixir. The release is self-contained, and provides everything needed to boot it, it is easily administered via the provided shell script to open up a remote console, start/stop/restart the release, start in the background, send remote commands, and more.
In this guide we cover how you can migrate from a from source installation to one using OTP releases.
## Pre-requisites ## Pre-requisites
You will be running commands as root. If you aren't root already, please elevate your priviledges by executing `sudo su`/`su`. You will be running commands as root. If you aren't root already, please elevate your priviledges by executing `sudo su`/`su`.

View File

@ -1,5 +1,9 @@
# Installing on Linux using OTP releases # Installing on Linux using OTP releases
{! backend/installation/otp_vs_from_source.include !}
This guide covers a installation using an OTP release. To install Pleroma from source, please check out the corresponding guide for your distro.
## Pre-requisites ## Pre-requisites
* A machine running Linux with GNU (e.g. Debian, Ubuntu) or musl (e.g. Alpine) libc and `x86_64`, `aarch64` or `armv7l` CPU, you have root access to. If you are not sure if it's compatible see [Detecting flavour section](#detecting-flavour) below * A machine running Linux with GNU (e.g. Debian, Ubuntu) or musl (e.g. Alpine) libc and `x86_64`, `aarch64` or `armv7l` CPU, you have root access to. If you are not sure if it's compatible see [Detecting flavour section](#detecting-flavour) below
* A (sub)domain pointed to the machine * A (sub)domain pointed to the machine

View File

@ -0,0 +1,3 @@
## OTP releases vs from-source installations
There are two ways to install Pleroma. You can use OTP releases or do a from-source installation. OTP releases are as close as you can get to binary releases with Erlang/Elixir. The release is self-contained, and provides everything needed to boot it, it is easily administered via the provided shell script to open up a remote console, start/stop/restart the release, start in the background, send remote commands, and more. With from source installations you install Pleroma from source, meaning you have to install certain dependencies like Erlang+Elixir and compile Pleroma yourself.

View File

@ -0,0 +1,3 @@
{! backend/installation/otp_vs_from_source.include !}
This guide covers a from-source installation. To install using OTP releases, please check out [the OTP guide](./otp_en.md).

View File

@ -26,19 +26,23 @@ defmodule Pleroma.Activity.Search do
:plain :plain
end end
Activity try do
|> Activity.with_preloaded_object() Activity
|> Activity.restrict_deactivated_users() |> Activity.with_preloaded_object()
|> restrict_public() |> Activity.restrict_deactivated_users()
|> query_with(index_type, search_query, search_function) |> restrict_public()
|> maybe_restrict_local(user) |> query_with(index_type, search_query, search_function)
|> maybe_restrict_author(author) |> maybe_restrict_local(user)
|> maybe_restrict_blocked(user) |> maybe_restrict_author(author)
|> Pagination.fetch_paginated( |> maybe_restrict_blocked(user)
%{"offset" => offset, "limit" => limit, "skip_order" => index_type == :rum}, |> Pagination.fetch_paginated(
:offset %{"offset" => offset, "limit" => limit, "skip_order" => index_type == :rum},
) :offset
|> maybe_fetch(user, search_query) )
|> maybe_fetch(user, search_query)
rescue
_ -> maybe_fetch([], user, search_query)
end
end end
def maybe_restrict_author(query, %User{} = author) do def maybe_restrict_author(query, %User{} = author) do

View File

@ -20,6 +20,140 @@ defmodule Pleroma.Config.DeprecationWarnings do
"\n* `config :pleroma, :instance, mrf_transparency_exclusions` is now `config :pleroma, :mrf, transparency_exclusions`"} "\n* `config :pleroma, :instance, mrf_transparency_exclusions` is now `config :pleroma, :mrf, transparency_exclusions`"}
] ]
def check_simple_policy_tuples do
has_strings =
Config.get([:mrf_simple])
|> Enum.any?(fn {_, v} -> Enum.any?(v, &is_binary/1) end)
if has_strings do
Logger.warn("""
!!!DEPRECATION WARNING!!!
Your config is using strings in the SimplePolicy configuration instead of tuples. They should work for now, but you are advised to change to the new configuration to prevent possible issues later:
```
config :pleroma, :mrf_simple,
media_removal: ["instance.tld"],
media_nsfw: ["instance.tld"],
federated_timeline_removal: ["instance.tld"],
report_removal: ["instance.tld"],
reject: ["instance.tld"],
followers_only: ["instance.tld"],
accept: ["instance.tld"],
avatar_removal: ["instance.tld"],
banner_removal: ["instance.tld"],
reject_deletes: ["instance.tld"]
```
Is now
```
config :pleroma, :mrf_simple,
media_removal: [{"instance.tld", "Reason for media removal"}],
media_nsfw: [{"instance.tld", "Reason for media nsfw"}],
federated_timeline_removal: [{"instance.tld", "Reason for federated timeline removal"}],
report_removal: [{"instance.tld", "Reason for report removal"}],
reject: [{"instance.tld", "Reason for reject"}],
followers_only: [{"instance.tld", "Reason for followers only"}],
accept: [{"instance.tld", "Reason for accept"}],
avatar_removal: [{"instance.tld", "Reason for avatar removal"}],
banner_removal: [{"instance.tld", "Reason for banner removal"}],
reject_deletes: [{"instance.tld", "Reason for reject deletes"}]
```
""")
new_config =
Config.get([:mrf_simple])
|> Enum.map(fn {k, v} ->
{k,
Enum.map(v, fn
{instance, reason} -> {instance, reason}
instance -> {instance, ""}
end)}
end)
Config.put([:mrf_simple], new_config)
:error
else
:ok
end
end
def check_quarantined_instances_tuples do
has_strings = Config.get([:instance, :quarantined_instances]) |> Enum.any?(&is_binary/1)
if has_strings do
Logger.warn("""
!!!DEPRECATION WARNING!!!
Your config is using strings in the quarantined_instances configuration instead of tuples. They should work for now, but you are advised to change to the new configuration to prevent possible issues later:
```
config :pleroma, :instance,
quarantined_instances: ["instance.tld"]
```
Is now
```
config :pleroma, :instance,
quarantined_instances: [{"instance.tld", "Reason for quarantine"}]
```
""")
new_config =
Config.get([:instance, :quarantined_instances])
|> Enum.map(fn
{instance, reason} -> {instance, reason}
instance -> {instance, ""}
end)
Config.put([:instance, :quarantined_instances], new_config)
:error
else
:ok
end
end
def check_transparency_exclusions_tuples do
has_strings = Config.get([:mrf, :transparency_exclusions]) |> Enum.any?(&is_binary/1)
if has_strings do
Logger.warn("""
!!!DEPRECATION WARNING!!!
Your config is using strings in the transparency_exclusions configuration instead of tuples. They should work for now, but you are advised to change to the new configuration to prevent possible issues later:
```
config :pleroma, :mrf,
transparency_exclusions: ["instance.tld"]
```
Is now
```
config :pleroma, :mrf,
transparency_exclusions: [{"instance.tld", "Reason to exlude transparency"}]
```
""")
new_config =
Config.get([:mrf, :transparency_exclusions])
|> Enum.map(fn
{instance, reason} -> {instance, reason}
instance -> {instance, ""}
end)
Config.put([:mrf, :transparency_exclusions], new_config)
:error
else
:ok
end
end
def check_hellthread_threshold do def check_hellthread_threshold do
if Config.get([:mrf_hellthread, :threshold]) do if Config.get([:mrf_hellthread, :threshold]) do
Logger.warn(""" Logger.warn("""
@ -34,20 +168,24 @@ defmodule Pleroma.Config.DeprecationWarnings do
end end
def warn do def warn do
with :ok <- check_hellthread_threshold(), [
:ok <- check_old_mrf_config(), check_hellthread_threshold(),
:ok <- check_media_proxy_whitelist_config(), check_old_mrf_config(),
:ok <- check_welcome_message_config(), check_media_proxy_whitelist_config(),
:ok <- check_gun_pool_options(), check_welcome_message_config(),
:ok <- check_activity_expiration_config(), check_gun_pool_options(),
:ok <- check_remote_ip_plug_name(), check_activity_expiration_config(),
:ok <- check_uploders_s3_public_endpoint(), check_remote_ip_plug_name(),
:ok <- check_old_chat_shoutbox() do check_uploders_s3_public_endpoint(),
:ok check_old_chat_shoutbox(),
else check_quarantined_instances_tuples(),
_ -> check_transparency_exclusions_tuples(),
:error check_simple_policy_tuples()
end ]
|> Enum.reduce(:ok, fn
:ok, :ok -> :ok
_, _ -> :error
end)
end end
def check_welcome_message_config do def check_welcome_message_config do

View File

@ -72,6 +72,7 @@ defmodule Pleroma.Notification do
pleroma:emoji_reaction pleroma:emoji_reaction
pleroma:report pleroma:report
reblog reblog
poll
} }
def changeset(%Notification{} = notification, attrs) do def changeset(%Notification{} = notification, attrs) do
@ -379,7 +380,7 @@ defmodule Pleroma.Notification do
notifications = notifications =
Enum.map(potential_receivers, fn user -> Enum.map(potential_receivers, fn user ->
do_send = do_send && user in enabled_receivers do_send = do_send && user in enabled_receivers
create_notification(activity, user, do_send) create_notification(activity, user, do_send: do_send)
end) end)
|> Enum.reject(&is_nil/1) |> Enum.reject(&is_nil/1)
@ -435,15 +436,18 @@ defmodule Pleroma.Notification do
end end
# TODO move to sql, too. # TODO move to sql, too.
def create_notification(%Activity{} = activity, %User{} = user, do_send \\ true) do def create_notification(%Activity{} = activity, %User{} = user, opts \\ []) do
unless skip?(activity, user) do do_send = Keyword.get(opts, :do_send, true)
type = Keyword.get(opts, :type, type_from_activity(activity))
unless skip?(activity, user, opts) do
{:ok, %{notification: notification}} = {:ok, %{notification: notification}} =
Multi.new() Multi.new()
|> Multi.insert(:notification, %Notification{ |> Multi.insert(:notification, %Notification{
user_id: user.id, user_id: user.id,
activity: activity, activity: activity,
seen: mark_as_read?(activity, user), seen: mark_as_read?(activity, user),
type: type_from_activity(activity) type: type
}) })
|> Marker.multi_set_last_read_id(user, "notifications") |> Marker.multi_set_last_read_id(user, "notifications")
|> Repo.transaction() |> Repo.transaction()
@ -457,6 +461,28 @@ defmodule Pleroma.Notification do
end end
end end
def create_poll_notifications(%Activity{} = activity) do
with %Object{data: %{"type" => "Question", "actor" => actor} = data} <-
Object.normalize(activity) do
voters =
case data do
%{"voters" => voters} when is_list(voters) -> voters
_ -> []
end
notifications =
Enum.reduce([actor | voters], [], fn ap_id, acc ->
with %User{local: true} = user <- User.get_by_ap_id(ap_id) do
[create_notification(activity, user, type: "poll") | acc]
else
_ -> acc
end
end)
{:ok, notifications}
end
end
@doc """ @doc """
Returns a tuple with 2 elements: Returns a tuple with 2 elements:
{notification-enabled receivers, currently disabled receivers (blocking / [thread] muting)} {notification-enabled receivers, currently disabled receivers (blocking / [thread] muting)}
@ -572,8 +598,10 @@ defmodule Pleroma.Notification do
Enum.uniq(ap_ids) -- thread_muter_ap_ids Enum.uniq(ap_ids) -- thread_muter_ap_ids
end end
@spec skip?(Activity.t(), User.t()) :: boolean() def skip?(activity, user, opts \\ [])
def skip?(%Activity{} = activity, %User{} = user) do
@spec skip?(Activity.t(), User.t(), Keyword.t()) :: boolean()
def skip?(%Activity{} = activity, %User{} = user, opts) do
[ [
:self, :self,
:invisible, :invisible,
@ -581,17 +609,21 @@ defmodule Pleroma.Notification do
:recently_followed, :recently_followed,
:filtered :filtered
] ]
|> Enum.find(&skip?(&1, activity, user)) |> Enum.find(&skip?(&1, activity, user, opts))
end end
def skip?(_, _), do: false def skip?(_activity, _user, _opts), do: false
@spec skip?(atom(), Activity.t(), User.t()) :: boolean() @spec skip?(atom(), Activity.t(), User.t(), Keyword.t()) :: boolean()
def skip?(:self, %Activity{} = activity, %User{} = user) do def skip?(:self, %Activity{} = activity, %User{} = user, opts) do
activity.data["actor"] == user.ap_id cond do
opts[:type] == "poll" -> false
activity.data["actor"] == user.ap_id -> true
true -> false
end
end end
def skip?(:invisible, %Activity{} = activity, _) do def skip?(:invisible, %Activity{} = activity, _user, _opts) do
actor = activity.data["actor"] actor = activity.data["actor"]
user = User.get_cached_by_ap_id(actor) user = User.get_cached_by_ap_id(actor)
User.invisible?(user) User.invisible?(user)
@ -600,15 +632,27 @@ defmodule Pleroma.Notification do
def skip?( def skip?(
:block_from_strangers, :block_from_strangers,
%Activity{} = activity, %Activity{} = activity,
%User{notification_settings: %{block_from_strangers: true}} = user %User{notification_settings: %{block_from_strangers: true}} = user,
opts
) do ) do
actor = activity.data["actor"] actor = activity.data["actor"]
follower = User.get_cached_by_ap_id(actor) follower = User.get_cached_by_ap_id(actor)
!User.following?(follower, user)
cond do
opts[:type] == "poll" -> false
user.ap_id == actor -> false
!User.following?(follower, user) -> true
true -> false
end
end end
# To do: consider defining recency in hours and checking FollowingRelationship with a single SQL # To do: consider defining recency in hours and checking FollowingRelationship with a single SQL
def skip?(:recently_followed, %Activity{data: %{"type" => "Follow"}} = activity, %User{} = user) do def skip?(
:recently_followed,
%Activity{data: %{"type" => "Follow"}} = activity,
%User{} = user,
_opts
) do
actor = activity.data["actor"] actor = activity.data["actor"]
Notification.for_user(user) Notification.for_user(user)
@ -618,9 +662,10 @@ defmodule Pleroma.Notification do
end) end)
end end
def skip?(:filtered, %{data: %{"type" => type}}, _) when type in ["Follow", "Move"], do: false def skip?(:filtered, %{data: %{"type" => type}}, _user, _opts) when type in ["Follow", "Move"],
do: false
def skip?(:filtered, activity, user) do def skip?(:filtered, activity, user, _opts) do
object = Object.normalize(activity, fetch: false) object = Object.normalize(activity, fetch: false)
cond do cond do
@ -638,7 +683,7 @@ defmodule Pleroma.Notification do
end end
end end
def skip?(_, _, _), do: false def skip?(_type, _activity, _user, _opts), do: false
def mark_as_read?(activity, target_user) do def mark_as_read?(activity, target_user) do
user = Activity.user_actor(activity) user = Activity.user_actor(activity)

View File

@ -25,6 +25,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
alias Pleroma.Web.Streamer alias Pleroma.Web.Streamer
alias Pleroma.Web.WebFinger alias Pleroma.Web.WebFinger
alias Pleroma.Workers.BackgroundWorker alias Pleroma.Workers.BackgroundWorker
alias Pleroma.Workers.PollWorker
import Ecto.Query import Ecto.Query
import Pleroma.Web.ActivityPub.Utils import Pleroma.Web.ActivityPub.Utils
@ -288,6 +289,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
{:quick_insert, false, activity} <- {:quick_insert, quick_insert?, activity}, {:quick_insert, false, activity} <- {:quick_insert, quick_insert?, activity},
{:ok, _actor} <- increase_note_count_if_public(actor, activity), {:ok, _actor} <- increase_note_count_if_public(actor, activity),
_ <- notify_and_stream(activity), _ <- notify_and_stream(activity),
:ok <- maybe_schedule_poll_notifications(activity),
:ok <- maybe_federate(activity) do :ok <- maybe_federate(activity) do
{:ok, activity} {:ok, activity}
else else
@ -302,6 +304,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end end
end end
defp maybe_schedule_poll_notifications(activity) do
PollWorker.schedule_poll_end(activity)
:ok
end
@spec listen(map()) :: {:ok, Activity.t()} | {:error, any()} @spec listen(map()) :: {:ok, Activity.t()} | {:error, any()}
def listen(%{to: to, actor: actor, context: context, object: object} = params) do def listen(%{to: to, actor: actor, context: context, object: object} = params) do
additional = params[:additional] || %{} additional = params[:additional] || %{}

View File

@ -15,6 +15,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.CommonAPI.ActivityDraft
require Pleroma.Constants require Pleroma.Constants
@ -125,6 +126,37 @@ defmodule Pleroma.Web.ActivityPub.Builder do
|> Pleroma.Maps.put_if_present("context", context), []} |> Pleroma.Maps.put_if_present("context", context), []}
end end
@spec note(ActivityDraft.t()) :: {:ok, map(), keyword()}
def note(%ActivityDraft{} = draft) do
data =
%{
"type" => "Note",
"to" => draft.to,
"cc" => draft.cc,
"content" => draft.content_html,
"summary" => draft.summary,
"sensitive" => draft.sensitive,
"context" => draft.context,
"attachment" => draft.attachments,
"actor" => draft.user.ap_id,
"tag" => Keyword.values(draft.tags) |> Enum.uniq()
}
|> add_in_reply_to(draft.in_reply_to)
|> Map.merge(draft.extra)
{:ok, data, []}
end
defp add_in_reply_to(object, nil), do: object
defp add_in_reply_to(object, in_reply_to) do
with %Object{} = in_reply_to_object <- Object.normalize(in_reply_to, fetch: false) do
Map.put(object, "inReplyTo", in_reply_to_object.data["id"])
else
_ -> object
end
end
def chat_message(actor, recipient, content, opts \\ []) do def chat_message(actor, recipient, content, opts \\ []) do
basic = %{ basic = %{
"id" => Utils.generate_object_id(), "id" => Utils.generate_object_id(),

View File

@ -33,9 +33,11 @@ defmodule Pleroma.Web.ActivityPub.MRF do
%{ %{
key: :transparency_exclusions, key: :transparency_exclusions,
label: "MRF transparency exclusions", label: "MRF transparency exclusions",
type: {:list, :string}, type: {:list, :tuple},
key_placeholder: "instance",
value_placeholder: "reason",
description: description:
"Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value.", "Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value. You can also provide a reason for excluding these instance names. The instances and reasons won't be publicly disclosed.",
suggestions: [ suggestions: [
"exclusion.com" "exclusion.com"
] ]
@ -100,6 +102,11 @@ defmodule Pleroma.Web.ActivityPub.MRF do
Enum.any?(domains, fn domain -> Regex.match?(domain, host) end) Enum.any?(domains, fn domain -> Regex.match?(domain, host) end)
end end
@spec instance_list_from_tuples([{String.t(), String.t()}]) :: [String.t()]
def instance_list_from_tuples(list) do
Enum.map(list, fn {instance, _} -> instance end)
end
def describe(policies) do def describe(policies) do
{:ok, policy_configs} = {:ok, policy_configs} =
policies policies

View File

@ -159,6 +159,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
%{ %{
key: :replace, key: :replace,
type: {:list, :tuple}, type: {:list, :tuple},
key_placeholder: "instance",
value_placeholder: "reason",
description: """ description: """
**Pattern**: a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`. **Pattern**: a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.

View File

@ -49,6 +49,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do
message message
|> Map.put("to", to) |> Map.put("to", to)
|> Map.put("cc", cc) |> Map.put("cc", cc)
|> Kernel.put_in(["object", "to"], to)
|> Kernel.put_in(["object", "cc"], cc)
{:ok, message} {:ok, message}
else else
@ -70,6 +72,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do
message message
|> Map.put("to", to) |> Map.put("to", to)
|> Map.put("cc", cc) |> Map.put("cc", cc)
|> Kernel.put_in(["object", "to"], to)
|> Kernel.put_in(["object", "cc"], cc)
{:ok, message} {:ok, message}
else else
@ -82,7 +86,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do
end end
@impl true @impl true
def filter(%{"type" => "Create", "published" => _} = message) do def filter(%{"type" => "Create", "object" => %{"published" => _}} = message) do
with actions <- Config.get([:mrf_object_age, :actions]), with actions <- Config.get([:mrf_object_age, :actions]),
{:reject, _} <- check_date(message), {:reject, _} <- check_date(message),
{:ok, message} <- check_reject(message, actions), {:ok, message} <- check_reject(message, actions),

View File

@ -47,7 +47,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do
@impl true @impl true
def describe, def describe,
do: {:ok, %{mrf_rejectnonpublic: Config.get(:mrf_rejectnonpublic) |> Enum.into(%{})}} do: {:ok, %{mrf_rejectnonpublic: Config.get(:mrf_rejectnonpublic) |> Map.new()}}
@impl true @impl true
def config_description do def config_description do

View File

@ -15,7 +15,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
defp check_accept(%{host: actor_host} = _actor_info, object) do defp check_accept(%{host: actor_host} = _actor_info, object) do
accepts = accepts =
Config.get([:mrf_simple, :accept]) instance_list(:accept)
|> MRF.subdomains_regex() |> MRF.subdomains_regex()
cond do cond do
@ -28,7 +28,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
defp check_reject(%{host: actor_host} = _actor_info, object) do defp check_reject(%{host: actor_host} = _actor_info, object) do
rejects = rejects =
Config.get([:mrf_simple, :reject]) instance_list(:reject)
|> MRF.subdomains_regex() |> MRF.subdomains_regex()
if MRF.subdomain_match?(rejects, actor_host) do if MRF.subdomain_match?(rejects, actor_host) do
@ -44,7 +44,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
) )
when length(child_attachment) > 0 do when length(child_attachment) > 0 do
media_removal = media_removal =
Config.get([:mrf_simple, :media_removal]) instance_list(:media_removal)
|> MRF.subdomains_regex() |> MRF.subdomains_regex()
object = object =
@ -68,7 +68,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
} = object } = object
) do ) do
media_nsfw = media_nsfw =
Config.get([:mrf_simple, :media_nsfw]) instance_list(:media_nsfw)
|> MRF.subdomains_regex() |> MRF.subdomains_regex()
object = object =
@ -85,7 +85,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
defp check_ftl_removal(%{host: actor_host} = _actor_info, object) do defp check_ftl_removal(%{host: actor_host} = _actor_info, object) do
timeline_removal = timeline_removal =
Config.get([:mrf_simple, :federated_timeline_removal]) instance_list(:federated_timeline_removal)
|> MRF.subdomains_regex() |> MRF.subdomains_regex()
object = object =
@ -112,7 +112,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
defp check_followers_only(%{host: actor_host} = _actor_info, object) do defp check_followers_only(%{host: actor_host} = _actor_info, object) do
followers_only = followers_only =
Config.get([:mrf_simple, :followers_only]) instance_list(:followers_only)
|> MRF.subdomains_regex() |> MRF.subdomains_regex()
object = object =
@ -137,7 +137,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
defp check_report_removal(%{host: actor_host} = _actor_info, %{"type" => "Flag"} = object) do defp check_report_removal(%{host: actor_host} = _actor_info, %{"type" => "Flag"} = object) do
report_removal = report_removal =
Config.get([:mrf_simple, :report_removal]) instance_list(:report_removal)
|> MRF.subdomains_regex() |> MRF.subdomains_regex()
if MRF.subdomain_match?(report_removal, actor_host) do if MRF.subdomain_match?(report_removal, actor_host) do
@ -151,7 +151,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
defp check_avatar_removal(%{host: actor_host} = _actor_info, %{"icon" => _icon} = object) do defp check_avatar_removal(%{host: actor_host} = _actor_info, %{"icon" => _icon} = object) do
avatar_removal = avatar_removal =
Config.get([:mrf_simple, :avatar_removal]) instance_list(:avatar_removal)
|> MRF.subdomains_regex() |> MRF.subdomains_regex()
if MRF.subdomain_match?(avatar_removal, actor_host) do if MRF.subdomain_match?(avatar_removal, actor_host) do
@ -165,7 +165,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
defp check_banner_removal(%{host: actor_host} = _actor_info, %{"image" => _image} = object) do defp check_banner_removal(%{host: actor_host} = _actor_info, %{"image" => _image} = object) do
banner_removal = banner_removal =
Config.get([:mrf_simple, :banner_removal]) instance_list(:banner_removal)
|> MRF.subdomains_regex() |> MRF.subdomains_regex()
if MRF.subdomain_match?(banner_removal, actor_host) do if MRF.subdomain_match?(banner_removal, actor_host) do
@ -185,12 +185,17 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
defp check_object(object), do: {:ok, object} defp check_object(object), do: {:ok, object}
defp instance_list(config_key) do
Config.get([:mrf_simple, config_key])
|> MRF.instance_list_from_tuples()
end
@impl true @impl true
def filter(%{"type" => "Delete", "actor" => actor} = object) do def filter(%{"type" => "Delete", "actor" => actor} = object) do
%{host: actor_host} = URI.parse(actor) %{host: actor_host} = URI.parse(actor)
reject_deletes = reject_deletes =
Config.get([:mrf_simple, :reject_deletes]) instance_list(:reject_deletes)
|> MRF.subdomains_regex() |> MRF.subdomains_regex()
if MRF.subdomain_match?(reject_deletes, actor_host) do if MRF.subdomain_match?(reject_deletes, actor_host) do
@ -253,14 +258,42 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
@impl true @impl true
def describe do def describe do
exclusions = Config.get([:mrf, :transparency_exclusions]) exclusions = Config.get([:mrf, :transparency_exclusions]) |> MRF.instance_list_from_tuples()
mrf_simple_excluded =
Config.get(:mrf_simple)
|> Enum.map(fn {rule, instances} ->
{rule, Enum.reject(instances, fn {host, _} -> host in exclusions end)}
end)
mrf_simple = mrf_simple =
Config.get(:mrf_simple) mrf_simple_excluded
|> Enum.map(fn {k, v} -> {k, Enum.reject(v, fn v -> v in exclusions end)} end) |> Enum.map(fn {rule, instances} ->
|> Enum.into(%{}) {rule, Enum.map(instances, fn {host, _} -> host end)}
end)
|> Map.new()
{:ok, %{mrf_simple: mrf_simple}} # This is for backwards compatibility. We originally didn't sent
# extra info like a reason why an instance was rejected/quarantined/etc.
# Because we didn't want to break backwards compatibility it was decided
# to add an extra "info" key.
mrf_simple_info =
mrf_simple_excluded
|> Enum.map(fn {rule, instances} ->
{rule, Enum.reject(instances, fn {_, reason} -> reason == "" end)}
end)
|> Enum.reject(fn {_, instances} -> instances == [] end)
|> Enum.map(fn {rule, instances} ->
instances =
instances
|> Enum.map(fn {host, reason} -> {host, %{"reason" => reason}} end)
|> Map.new()
{rule, instances}
end)
|> Map.new()
{:ok, %{mrf_simple: mrf_simple, mrf_simple_info: mrf_simple_info}}
end end
@impl true @impl true
@ -270,70 +303,67 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
related_policy: "Pleroma.Web.ActivityPub.MRF.SimplePolicy", related_policy: "Pleroma.Web.ActivityPub.MRF.SimplePolicy",
label: "MRF Simple", label: "MRF Simple",
description: "Simple ingress policies", description: "Simple ingress policies",
children: [ children:
%{ [
key: :media_removal, %{
type: {:list, :string}, key: :media_removal,
description: "List of instances to strip media attachments from", description:
suggestions: ["example.com", "*.example.com"] "List of instances to strip media attachments from and the reason for doing so"
}, },
%{ %{
key: :media_nsfw, key: :media_nsfw,
label: "Media NSFW", label: "Media NSFW",
type: {:list, :string}, description:
description: "List of instances to tag all media as NSFW (sensitive) from", "List of instances to tag all media as NSFW (sensitive) from and the reason for doing so"
suggestions: ["example.com", "*.example.com"] },
}, %{
%{ key: :federated_timeline_removal,
key: :federated_timeline_removal, description:
type: {:list, :string}, "List of instances to remove from the Federated (aka The Whole Known Network) Timeline and the reason for doing so"
description: },
"List of instances to remove from the Federated (aka The Whole Known Network) Timeline", %{
suggestions: ["example.com", "*.example.com"] key: :reject,
}, description:
%{ "List of instances to reject activities from (except deletes) and the reason for doing so"
key: :reject, },
type: {:list, :string}, %{
description: "List of instances to reject activities from (except deletes)", key: :accept,
suggestions: ["example.com", "*.example.com"] description:
}, "List of instances to only accept activities from (except deletes) and the reason for doing so"
%{ },
key: :accept, %{
type: {:list, :string}, key: :followers_only,
description: "List of instances to only accept activities from (except deletes)", description:
suggestions: ["example.com", "*.example.com"] "Force posts from the given instances to be visible by followers only and the reason for doing so"
}, },
%{ %{
key: :followers_only, key: :report_removal,
type: {:list, :string}, description: "List of instances to reject reports from and the reason for doing so"
description: "Force posts from the given instances to be visible by followers only", },
suggestions: ["example.com", "*.example.com"] %{
}, key: :avatar_removal,
%{ description: "List of instances to strip avatars from and the reason for doing so"
key: :report_removal, },
type: {:list, :string}, %{
description: "List of instances to reject reports from", key: :banner_removal,
suggestions: ["example.com", "*.example.com"] description: "List of instances to strip banners from and the reason for doing so"
}, },
%{ %{
key: :avatar_removal, key: :reject_deletes,
type: {:list, :string}, description: "List of instances to reject deletions from and the reason for doing so"
description: "List of instances to strip avatars from", }
suggestions: ["example.com", "*.example.com"] ]
}, |> Enum.map(fn setting ->
%{ Map.merge(
key: :banner_removal, setting,
type: {:list, :string}, %{
description: "List of instances to strip banners from", type: {:list, :tuple},
suggestions: ["example.com", "*.example.com"] key_placeholder: "instance",
}, value_placeholder: "reason",
%{ suggestions: [{"example.com", "Some reason"}, {"*.example.com", "Another reason"}]
key: :reject_deletes, }
type: {:list, :string}, )
description: "List of instances to reject deletions from", end)
suggestions: ["example.com", "*.example.com"]
}
]
} }
end end
end end

View File

@ -93,6 +93,51 @@ defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy do
def filter(message), do: {:ok, message} def filter(message), do: {:ok, message}
@impl true @impl true
@spec config_description :: %{
children: [
%{
description: <<_::272, _::_*256>>,
key: :hosts | :rejected_shortcodes | :size_limit,
suggestions: [any(), ...],
type: {:list, :string} | {:list, :string} | :integer
},
...
],
description: <<_::448>>,
key: :mrf_steal_emoji,
label: <<_::80>>,
related_policy: <<_::352>>
}
def config_description do
%{
key: :mrf_steal_emoji,
related_policy: "Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy",
label: "MRF Emojis",
description: "Steals emojis from selected instances when it sees them.",
children: [
%{
key: :hosts,
type: {:list, :string},
description: "List of hosts to steal emojis from",
suggestions: [""]
},
%{
key: :rejected_shortcodes,
type: {:list, :string},
description: "Regex-list of shortcodes to reject",
suggestions: [""]
},
%{
key: :size_limit,
type: :integer,
description: "File size limit (in bytes), checked before an emoji is saved to the disk",
suggestions: ["100000"]
}
]
}
end
@impl true
def describe do def describe do
{:ok, %{}} {:ok, %{}}
end end

View File

@ -37,7 +37,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy do
def describe do def describe do
mrf_user_allowlist = mrf_user_allowlist =
Config.get([:mrf_user_allowlist], []) Config.get([:mrf_user_allowlist], [])
|> Enum.into(%{}, fn {k, v} -> {k, length(v)} end) |> Map.new(fn {k, v} -> {k, length(v)} end)
{:ok, %{mrf_user_allowlist: mrf_user_allowlist}} {:ok, %{mrf_user_allowlist: mrf_user_allowlist}}
end end

View File

@ -39,7 +39,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicy do
@impl true @impl true
def describe, def describe,
do: {:ok, %{mrf_vocabulary: Pleroma.Config.get(:mrf_vocabulary) |> Enum.into(%{})}} do: {:ok, %{mrf_vocabulary: Pleroma.Config.get(:mrf_vocabulary) |> Map.new()}}
@impl true @impl true
def config_description do def config_description do

View File

@ -112,6 +112,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
quarantined_instances = quarantined_instances =
Config.get([:instance, :quarantined_instances], []) Config.get([:instance, :quarantined_instances], [])
|> Pleroma.Web.ActivityPub.MRF.instance_list_from_tuples()
|> Pleroma.Web.ActivityPub.MRF.subdomains_regex() |> Pleroma.Web.ActivityPub.MRF.subdomains_regex()
!Pleroma.Web.ActivityPub.MRF.subdomain_match?(quarantined_instances, host) !Pleroma.Web.ActivityPub.MRF.subdomain_match?(quarantined_instances, host)

View File

@ -10,7 +10,6 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
collection, and so on. collection, and so on.
""" """
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Activity.Ir.Topics
alias Pleroma.Chat alias Pleroma.Chat
alias Pleroma.Chat.MessageReference alias Pleroma.Chat.MessageReference
alias Pleroma.FollowingRelationship alias Pleroma.FollowingRelationship
@ -24,6 +23,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.Push alias Pleroma.Web.Push
alias Pleroma.Web.Streamer alias Pleroma.Web.Streamer
alias Pleroma.Workers.PollWorker
require Logger require Logger
@ -195,7 +195,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
# - Set up notifications # - Set up notifications
@impl true @impl true
def handle(%{data: %{"type" => "Create"}} = activity, meta) do def handle(%{data: %{"type" => "Create"}} = activity, meta) do
with {:ok, object, meta} <- handle_object_creation(meta[:object_data], meta), with {:ok, object, meta} <- handle_object_creation(meta[:object_data], activity, meta),
%User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
{:ok, notifications} = Notification.create_notifications(activity, do_send: false) {:ok, notifications} = Notification.create_notifications(activity, do_send: false)
{:ok, _user} = ActivityPub.increase_note_count_if_public(user, object) {:ok, _user} = ActivityPub.increase_note_count_if_public(user, object)
@ -225,6 +225,8 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
meta meta
|> add_notifications(notifications) |> add_notifications(notifications)
ap_streamer().stream_out(activity)
{:ok, activity, meta} {:ok, activity, meta}
else else
e -> Repo.rollback(e) e -> Repo.rollback(e)
@ -245,9 +247,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
if !User.is_internal_user?(user) do if !User.is_internal_user?(user) do
Notification.create_notifications(object) Notification.create_notifications(object)
object ap_streamer().stream_out(object)
|> Topics.get_activity_topics()
|> Streamer.stream(object)
end end
{:ok, object, meta} {:ok, object, meta}
@ -389,7 +389,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
{:ok, object, meta} {:ok, object, meta}
end end
def handle_object_creation(%{"type" => "ChatMessage"} = object, meta) do def handle_object_creation(%{"type" => "ChatMessage"} = object, _activity, meta) do
with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
actor = User.get_cached_by_ap_id(object.data["actor"]) actor = User.get_cached_by_ap_id(object.data["actor"])
recipient = User.get_cached_by_ap_id(hd(object.data["to"])) recipient = User.get_cached_by_ap_id(hd(object.data["to"]))
@ -424,7 +424,14 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
end end
end end
def handle_object_creation(%{"type" => "Answer"} = object_map, meta) do def handle_object_creation(%{"type" => "Question"} = object, activity, meta) do
with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
PollWorker.schedule_poll_end(activity)
{:ok, object, meta}
end
end
def handle_object_creation(%{"type" => "Answer"} = object_map, _activity, meta) do
with {:ok, object, meta} <- Pipeline.common_pipeline(object_map, meta) do with {:ok, object, meta} <- Pipeline.common_pipeline(object_map, meta) do
Object.increase_vote_count( Object.increase_vote_count(
object.data["inReplyTo"], object.data["inReplyTo"],
@ -436,15 +443,15 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
end end
end end
def handle_object_creation(%{"type" => objtype} = object, meta) def handle_object_creation(%{"type" => objtype} = object, _activity, meta)
when objtype in ~w[Audio Video Question Event Article Note Page] do when objtype in ~w[Audio Video Event Article Note Page] do
with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
{:ok, object, meta} {:ok, object, meta}
end end
end end
# Nothing to do # Nothing to do
def handle_object_creation(object, meta) do def handle_object_creation(object, _activity, meta) do
{:ok, object, meta} {:ok, object, meta}
end end

View File

@ -35,6 +35,12 @@ defmodule Pleroma.Web.AdminAPI.FrontendController do
end end
defp installed do defp installed do
File.ls!(Pleroma.Frontend.dir()) frontend_directory = Pleroma.Frontend.dir()
if File.exists?(frontend_directory) do
File.ls!(frontend_directory)
else
[]
end
end end
end end

View File

@ -13,7 +13,9 @@ defmodule Pleroma.Web.AdminAPI.Report do
account = User.get_cached_by_ap_id(account_ap_id) account = User.get_cached_by_ap_id(account_ap_id)
statuses = statuses =
Enum.map(status_ap_ids, fn status_ap_ids
|> Enum.reject(&is_nil(&1))
|> Enum.map(fn
act when is_map(act) -> Activity.get_by_ap_id_with_object(act["id"]) act when is_map(act) -> Activity.get_by_ap_id_with_object(act["id"])
act when is_binary(act) -> Activity.get_by_ap_id_with_object(act) act when is_binary(act) -> Activity.get_by_ap_id_with_object(act)
end) end)

View File

@ -195,7 +195,8 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do
"pleroma:chat_mention", "pleroma:chat_mention",
"pleroma:report", "pleroma:report",
"move", "move",
"follow_request" "follow_request",
"poll"
], ],
description: """ description: """
The type of event that resulted in the notification. The type of event that resulted in the notification.

View File

@ -453,7 +453,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
nullable: true, nullable: true,
type: :array, type: :array,
items: %Schema{type: :string}, items: %Schema{type: :string},
description: "Array of Attachment ids to be attached as media." description: "Array of Attachment ids or URLs to be attached as media."
}, },
poll: poll_params(), poll: poll_params(),
in_reply_to_id: %Schema{ in_reply_to_id: %Schema{

View File

@ -8,6 +8,8 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
alias Pleroma.Web.ApiSpec.Schemas.ApiError alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
import Pleroma.Web.ApiSpec.Helpers
def open_api_operation(action) do def open_api_operation(action) do
operation = String.to_existing_atom("#{action}_operation") operation = String.to_existing_atom("#{action}_operation")
apply(__MODULE__, operation, []) apply(__MODULE__, operation, [])
@ -63,17 +65,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
summary: "Change account password", summary: "Change account password",
security: [%{"oAuth" => ["write:accounts"]}], security: [%{"oAuth" => ["write:accounts"]}],
operationId: "UtilController.change_password", operationId: "UtilController.change_password",
parameters: [ requestBody: request_body("Parameters", change_password_request(), required: true),
Operation.parameter(:password, :query, :string, "Current password", required: true),
Operation.parameter(:new_password, :query, :string, "New password", required: true),
Operation.parameter(
:new_password_confirmation,
:query,
:string,
"New password, confirmation",
required: true
)
],
responses: %{ responses: %{
200 => 200 =>
Operation.response("Success", "application/json", %Schema{ Operation.response("Success", "application/json", %Schema{
@ -86,17 +78,30 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
} }
end end
defp change_password_request do
%Schema{
title: "ChangePasswordRequest",
description: "POST body for changing the account's passowrd",
type: :object,
required: [:password, :new_password, :new_password_confirmation],
properties: %{
password: %Schema{type: :string, description: "Current password"},
new_password: %Schema{type: :string, description: "New password"},
new_password_confirmation: %Schema{
type: :string,
description: "New password, confirmation"
}
}
}
end
def change_email_operation do def change_email_operation do
%Operation{ %Operation{
tags: ["Account credentials"], tags: ["Account credentials"],
summary: "Change account email", summary: "Change account email",
security: [%{"oAuth" => ["write:accounts"]}], security: [%{"oAuth" => ["write:accounts"]}],
operationId: "UtilController.change_email", operationId: "UtilController.change_email",
parameters: [ requestBody: request_body("Parameters", change_email_request(), required: true),
Operation.parameter(:password, :query, :string, "Current password", required: true),
Operation.parameter(:email, :query, :string, "New email", required: true)
],
requestBody: nil,
responses: %{ responses: %{
200 => 200 =>
Operation.response("Success", "application/json", %Schema{ Operation.response("Success", "application/json", %Schema{
@ -109,6 +114,19 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
} }
end end
defp change_email_request do
%Schema{
title: "ChangeEmailRequest",
description: "POST body for changing the account's email",
type: :object,
required: [:email, :password],
properties: %{
email: %Schema{type: :string, description: "New email"},
password: %Schema{type: :string, description: "Current password"}
}
}
end
def update_notificaton_settings_operation do def update_notificaton_settings_operation do
%Operation{ %Operation{
tags: ["Accounts"], tags: ["Accounts"],

View File

@ -6,6 +6,7 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Conversation.Participation alias Pleroma.Conversation.Participation
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.CommonAPI alias Pleroma.Web.CommonAPI
alias Pleroma.Web.CommonAPI.Utils alias Pleroma.Web.CommonAPI.Utils
@ -213,8 +214,10 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
emoji = Map.merge(emoji, summary_emoji) emoji = Map.merge(emoji, summary_emoji)
{:ok, note_data, _meta} = Builder.note(draft)
object = object =
Utils.make_note_data(draft) note_data
|> Map.put("emoji", emoji) |> Map.put("emoji", emoji)
|> Map.put("source", draft.status) |> Map.put("source", draft.status)
|> Map.put("generator", draft.params[:generator]) |> Map.put("generator", draft.params[:generator])

View File

@ -23,6 +23,19 @@ defmodule Pleroma.Web.CommonAPI.Utils do
require Logger require Logger
require Pleroma.Constants require Pleroma.Constants
defp raw_url_to_attachment(url, desc \\ nil) do
%{
"type" => "Document",
"name" => desc,
"url" => [
%{
"type" => "Link",
"href" => url
}
]
}
end
def attachments_from_ids(%{media_ids: ids, descriptions: desc}) do def attachments_from_ids(%{media_ids: ids, descriptions: desc}) do
attachments_from_ids_descs(ids, desc) attachments_from_ids_descs(ids, desc)
end end
@ -36,11 +49,15 @@ defmodule Pleroma.Web.CommonAPI.Utils do
def attachments_from_ids_no_descs([]), do: [] def attachments_from_ids_no_descs([]), do: []
def attachments_from_ids_no_descs(ids) do def attachments_from_ids_no_descs(ids) do
Enum.map(ids, fn media_id -> Enum.map(ids, fn
case Repo.get(Object, media_id) do "http" <> _ = id ->
%Object{data: data} -> data raw_url_to_attachment(id)
_ -> nil
end media_id ->
case Repo.get(Object, media_id) do
%Object{data: data} -> data
_ -> nil
end
end) end)
|> Enum.reject(&is_nil/1) |> Enum.reject(&is_nil/1)
end end
@ -50,10 +67,14 @@ defmodule Pleroma.Web.CommonAPI.Utils do
def attachments_from_ids_descs(ids, descs_str) do def attachments_from_ids_descs(ids, descs_str) do
{_, descs} = Jason.decode(descs_str) {_, descs} = Jason.decode(descs_str)
Enum.map(ids, fn media_id -> Enum.map(ids, fn
with %Object{data: data} <- Repo.get(Object, media_id) do "http" <> _ = media_id ->
Map.put(data, "name", descs[media_id]) raw_url_to_attachment(media_id, descs[media_id])
end
media_id ->
with %Object{data: data} <- Repo.get(Object, media_id) do
Map.put(data, "name", descs[media_id])
end
end) end)
|> Enum.reject(&is_nil/1) |> Enum.reject(&is_nil/1)
end end
@ -291,33 +312,6 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|> Formatter.html_escape("text/html") |> Formatter.html_escape("text/html")
end end
def make_note_data(%ActivityDraft{} = draft) do
%{
"type" => "Note",
"to" => draft.to,
"cc" => draft.cc,
"content" => draft.content_html,
"summary" => draft.summary,
"sensitive" => draft.sensitive,
"context" => draft.context,
"attachment" => draft.attachments,
"actor" => draft.user.ap_id,
"tag" => Keyword.values(draft.tags) |> Enum.uniq()
}
|> add_in_reply_to(draft.in_reply_to)
|> Map.merge(draft.extra)
end
defp add_in_reply_to(object, nil), do: object
defp add_in_reply_to(object, in_reply_to) do
with %Object{} = in_reply_to_object <- Object.normalize(in_reply_to, fetch: false) do
Map.put(object, "inReplyTo", in_reply_to_object.data["id"])
else
_ -> object
end
end
def format_naive_asctime(date) do def format_naive_asctime(date) do
date |> DateTime.from_naive!("Etc/UTC") |> format_asctime date |> DateTime.from_naive!("Etc/UTC") |> format_asctime
end end
@ -412,19 +406,14 @@ defmodule Pleroma.Web.CommonAPI.Utils do
def maybe_notify_mentioned_recipients(recipients, _), do: recipients def maybe_notify_mentioned_recipients(recipients, _), do: recipients
# Do not notify subscribers if author is making a reply
def maybe_notify_subscribers(recipients, %Activity{
object: %Object{data: %{"inReplyTo" => _ap_id}}
}) do
recipients
end
def maybe_notify_subscribers( def maybe_notify_subscribers(
recipients, recipients,
%Activity{data: %{"actor" => actor, "type" => type}} = activity %Activity{data: %{"actor" => actor, "type" => "Create"}} = activity
) ) do
when type == "Create" do # Do not notify subscribers if author is making a reply
with %User{} = user <- User.get_cached_by_ap_id(actor) do with %Object{data: object} <- Object.normalize(activity, fetch: false),
nil <- object["inReplyTo"],
%User{} = user <- User.get_cached_by_ap_id(actor) do
subscriber_ids = subscriber_ids =
user user
|> User.subscriber_users() |> User.subscriber_users()

View File

@ -50,6 +50,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do
favourite favourite
move move
pleroma:emoji_reaction pleroma:emoji_reaction
poll
} }
def index(%{assigns: %{user: user}} = conn, params) do def index(%{assigns: %{user: user}} = conn, params) do
params = params =

View File

@ -95,7 +95,20 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
{:ok, data} = MRF.describe() {:ok, data} = MRF.describe()
data data
|> Map.merge(%{quarantined_instances: quarantined}) |> Map.put(
:quarantined_instances,
Enum.map(quarantined, fn {instance, _reason} -> instance end)
)
# This is for backwards compatibility. We originally didn't sent
# extra info like a reason why an instance was rejected/quarantined/etc.
# Because we didn't want to break backwards compatibility it was decided
# to add an extra "info" key.
|> Map.put(:quarantined_instances_info, %{
"quarantined_instances" =>
quarantined
|> Enum.map(fn {instance, reason} -> {instance, %{"reason" => reason}} end)
|> Map.new()
})
else else
%{} %{}
end end

View File

@ -112,6 +112,9 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
"move" -> "move" ->
put_target(response, activity, reading_user, %{}) put_target(response, activity, reading_user, %{})
"poll" ->
put_status(response, activity, reading_user, status_render_opts)
"pleroma:emoji_reaction" -> "pleroma:emoji_reaction" ->
response response
|> put_status(parent_activity_fn.(), reading_user, status_render_opts) |> put_status(parent_activity_fn.(), reading_user, status_render_opts)

View File

@ -65,11 +65,19 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
defp get_context_id(_), do: nil defp get_context_id(_), do: nil
defp reblogged?(activity, user) do # Check if the user reblogged this status
object = Object.normalize(activity, fetch: false) || %{} defp reblogged?(activity, %User{ap_id: ap_id}) do
present?(user && user.ap_id in (object.data["announcements"] || [])) with %Object{data: %{"announcements" => announcements}} when is_list(announcements) <-
Object.normalize(activity, fetch: false) do
ap_id in announcements
else
_ -> false
end
end end
# False if the user is logged out
defp reblogged?(_activity, _user), do: false
def render("index.json", opts) do def render("index.json", opts) do
reading_user = opts[:for] reading_user = opts[:for]

View File

@ -0,0 +1,23 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Plugs.UserIsStaffPlug do
import Pleroma.Web.TranslationHelpers
import Plug.Conn
alias Pleroma.User
def init(options) do
options
end
def call(%{assigns: %{user: %User{is_admin: true}}} = conn, _), do: conn
def call(%{assigns: %{user: %User{is_moderator: true}}} = conn, _), do: conn
def call(conn, _) do
conn
|> render_error(:forbidden, "User is not a staff member.")
|> halt()
end
end

View File

@ -26,7 +26,7 @@ defmodule Pleroma.Web.Push.Subscription do
end end
# credo:disable-for-next-line Credo.Check.Readability.MaxLineLength # credo:disable-for-next-line Credo.Check.Readability.MaxLineLength
@supported_alert_types ~w[follow favourite mention reblog pleroma:chat_mention pleroma:emoji_reaction]a @supported_alert_types ~w[follow favourite mention reblog poll pleroma:chat_mention pleroma:emoji_reaction]a
defp alerts(%{data: %{alerts: alerts}}) do defp alerts(%{data: %{alerts: alerts}}) do
alerts = Map.take(alerts, @supported_alert_types) alerts = Map.take(alerts, @supported_alert_types)

View File

@ -96,10 +96,14 @@ defmodule Pleroma.Web.Router do
plug(Pleroma.Web.Plugs.AdminSecretAuthenticationPlug) plug(Pleroma.Web.Plugs.AdminSecretAuthenticationPlug)
plug(:after_auth) plug(:after_auth)
plug(Pleroma.Web.Plugs.EnsureAuthenticatedPlug) plug(Pleroma.Web.Plugs.EnsureAuthenticatedPlug)
plug(Pleroma.Web.Plugs.UserIsAdminPlug) plug(Pleroma.Web.Plugs.UserIsStaffPlug)
plug(Pleroma.Web.Plugs.IdempotencyPlug) plug(Pleroma.Web.Plugs.IdempotencyPlug)
end end
pipeline :require_admin do
plug(Pleroma.Web.Plugs.UserIsAdminPlug)
end
pipeline :mastodon_html do pipeline :mastodon_html do
plug(:browser) plug(:browser)
plug(:authenticate) plug(:authenticate)
@ -160,7 +164,7 @@ defmodule Pleroma.Web.Router do
end end
scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do
pipe_through(:admin_api) pipe_through([:admin_api, :require_admin])
put("/users/disable_mfa", AdminAPIController, :disable_mfa) put("/users/disable_mfa", AdminAPIController, :disable_mfa)
put("/users/tag", AdminAPIController, :tag_users) put("/users/tag", AdminAPIController, :tag_users)
@ -265,7 +269,7 @@ defmodule Pleroma.Web.Router do
scope "/api/v1/pleroma/emoji", Pleroma.Web.PleromaAPI do scope "/api/v1/pleroma/emoji", Pleroma.Web.PleromaAPI do
scope "/pack" do scope "/pack" do
pipe_through(:admin_api) pipe_through([:admin_api, :require_admin])
post("/", EmojiPackController, :create) post("/", EmojiPackController, :create)
patch("/", EmojiPackController, :update) patch("/", EmojiPackController, :update)
@ -280,7 +284,7 @@ defmodule Pleroma.Web.Router do
# Modifying packs # Modifying packs
scope "/packs" do scope "/packs" do
pipe_through(:admin_api) pipe_through([:admin_api, :require_admin])
get("/import", EmojiPackController, :import_from_filesystem) get("/import", EmojiPackController, :import_from_filesystem)
get("/remote", EmojiPackController, :remote) get("/remote", EmojiPackController, :remote)

View File

@ -81,17 +81,13 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end end
end end
def change_password(%{assigns: %{user: user}} = conn, %{ def change_password(%{assigns: %{user: user}, body_params: body_params} = conn, %{}) do
password: password, case CommonAPI.Utils.confirm_current_password(user, body_params.password) do
new_password: new_password,
new_password_confirmation: new_password_confirmation
}) do
case CommonAPI.Utils.confirm_current_password(user, password) do
{:ok, user} -> {:ok, user} ->
with {:ok, _user} <- with {:ok, _user} <-
User.reset_password(user, %{ User.reset_password(user, %{
password: new_password, password: body_params.new_password,
password_confirmation: new_password_confirmation password_confirmation: body_params.new_password_confirmation
}) do }) do
json(conn, %{status: "success"}) json(conn, %{status: "success"})
else else
@ -108,10 +104,10 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end end
end end
def change_email(%{assigns: %{user: user}} = conn, %{password: password, email: email}) do def change_email(%{assigns: %{user: user}, body_params: body_params} = conn, %{}) do
case CommonAPI.Utils.confirm_current_password(user, password) do case CommonAPI.Utils.confirm_current_password(user, body_params.password) do
{:ok, user} -> {:ok, user} ->
with {:ok, _user} <- User.change_email(user, email) do with {:ok, _user} <- User.change_email(user, body_params.email) do
json(conn, %{status: "success"}) json(conn, %{status: "success"})
else else
{:error, changeset} -> {:error, changeset} ->

View File

@ -0,0 +1,45 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Workers.PollWorker do
@moduledoc """
Generates notifications when a poll ends.
"""
use Pleroma.Workers.WorkerHelper, queue: "poll_notifications"
alias Pleroma.Activity
alias Pleroma.Notification
alias Pleroma.Object
@impl Oban.Worker
def perform(%Job{args: %{"op" => "poll_end", "activity_id" => activity_id}}) do
with %Activity{} = activity <- find_poll_activity(activity_id) do
Notification.create_poll_notifications(activity)
end
end
defp find_poll_activity(activity_id) do
with nil <- Activity.get_by_id(activity_id) do
{:error, :poll_activity_not_found}
end
end
def schedule_poll_end(%Activity{data: %{"type" => "Create"}, id: activity_id} = activity) do
with %Object{data: %{"type" => "Question", "closed" => closed}} when is_binary(closed) <-
Object.normalize(activity),
{:ok, end_time} <- NaiveDateTime.from_iso8601(closed),
:gt <- NaiveDateTime.compare(end_time, NaiveDateTime.utc_now()) do
%{
op: "poll_end",
activity_id: activity_id
}
|> new(scheduled_at: end_time)
|> Oban.insert()
else
_ -> {:error, activity}
end
end
def schedule_poll_end(activity), do: {:error, activity}
end

View File

@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do
def project do def project do
[ [
app: :pleroma, app: :pleroma,
version: version("2.4.0"), version: version("2.4.50"),
elixir: "~> 1.9", elixir: "~> 1.9",
elixirc_paths: elixirc_paths(Mix.env()), elixirc_paths: elixirc_paths(Mix.env()),
compilers: [:phoenix, :gettext] ++ Mix.compilers(), compilers: [:phoenix, :gettext] ++ Mix.compilers(),

View File

@ -3,8 +3,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-13 16:37+0000\n" "POT-Creation-Date: 2020-05-13 16:37+0000\n"
"PO-Revision-Date: 2020-07-09 14:40+0000\n" "PO-Revision-Date: 2021-08-13 15:42+0000\n"
"Last-Translator: Ben Is <srsbzns@cock.li>\n" "Last-Translator: marcin mikołajczak <me@mkljczk.pl>\n"
"Language-Team: Polish <https://translate.pleroma.social/projects/pleroma/" "Language-Team: Polish <https://translate.pleroma.social/projects/pleroma/"
"pleroma/pl/>\n" "pleroma/pl/>\n"
"Language: pl\n" "Language: pl\n"
@ -13,7 +13,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2;\n" "|| n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 4.0.4\n" "X-Generator: Weblate 4.6.2\n"
## This file is a PO Template file. ## This file is a PO Template file.
## ##
@ -68,49 +68,49 @@ msgstr[2] "powinno mieć %{count} znaków"
msgid "should have %{count} item(s)" msgid "should have %{count} item(s)"
msgid_plural "should have %{count} item(s)" msgid_plural "should have %{count} item(s)"
msgstr[0] "" msgstr[0] "powinno zawierać %{count} element"
msgstr[1] "" msgstr[1] "powinno zawierać %{count} elementy"
msgstr[2] "" msgstr[2] "powinno zawierać %{count} elementów"
msgid "should be at least %{count} character(s)" msgid "should be at least %{count} character(s)"
msgid_plural "should be at least %{count} character(s)" msgid_plural "should be at least %{count} character(s)"
msgstr[0] "" msgstr[0] "powinno zawierać przynajmniej %{count} znak"
msgstr[1] "" msgstr[1] "powinno zawierać przynajmniej %{count} znaki"
msgstr[2] "" msgstr[2] "powinno zawierać przynajmniej %{count} znaków"
msgid "should have at least %{count} item(s)" msgid "should have at least %{count} item(s)"
msgid_plural "should have at least %{count} item(s)" msgid_plural "should have at least %{count} item(s)"
msgstr[0] "" msgstr[0] "powinno zawierać przynajmniej %{count} element"
msgstr[1] "" msgstr[1] "powinno zawierać przynajmniej %{count} elementy"
msgstr[2] "" msgstr[2] "powinno zawierać przynajmniej %{count} elementów"
msgid "should be at most %{count} character(s)" msgid "should be at most %{count} character(s)"
msgid_plural "should be at most %{count} character(s)" msgid_plural "should be at most %{count} character(s)"
msgstr[0] "" msgstr[0] "powinno zawierać najwyżej %{count} znak"
msgstr[1] "" msgstr[1] "powinno zawierać najwyżej %{count} znaki"
msgstr[2] "" msgstr[2] "powinno zawierać najwyżej %{count} znaków"
msgid "should have at most %{count} item(s)" msgid "should have at most %{count} item(s)"
msgid_plural "should have at most %{count} item(s)" msgid_plural "should have at most %{count} item(s)"
msgstr[0] "" msgstr[0] "powinno zawierać najwyżej %{count} element"
msgstr[1] "" msgstr[1] "powinno zawierać najwyżej %{count} elementy"
msgstr[2] "" msgstr[2] "powinno zawierać najwyżej %{count} elementów"
## From Ecto.Changeset.validate_number/3 ## From Ecto.Changeset.validate_number/3
msgid "must be less than %{number}" msgid "must be less than %{number}"
msgstr "" msgstr "musi wynosić mniej niż %{number}"
msgid "must be greater than %{number}" msgid "must be greater than %{number}"
msgstr "" msgstr "musi wynosić więcej niż %{number}"
msgid "must be less than or equal to %{number}" msgid "must be less than or equal to %{number}"
msgstr "" msgstr "musi być mniejsze lub równe %{number}"
msgid "must be greater than or equal to %{number}" msgid "must be greater than or equal to %{number}"
msgstr "" msgstr "musi być większe lub równe %{number}"
msgid "must be equal to %{number}" msgid "must be equal to %{number}"
msgstr "" msgstr "musi być równe %{number}"
#: lib/pleroma/web/common_api/common_api.ex:421 #: lib/pleroma/web/common_api/common_api.ex:421
#, elixir-format #, elixir-format
@ -152,7 +152,7 @@ msgstr "Nie znaleziono użytkownika"
#: lib/pleroma/web/pleroma_api/controllers/account_controller.ex:114 #: lib/pleroma/web/pleroma_api/controllers/account_controller.ex:114
#, elixir-format #, elixir-format
msgid "Can't get favorites" msgid "Can't get favorites"
msgstr "" msgstr "Nie można uzyskać ulubionych"
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:437 #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:437
#, elixir-format #, elixir-format
@ -172,7 +172,7 @@ msgstr "Komentarz może mieć co najwyżej %{max_size} znaków"
#: lib/pleroma/config/config_db.ex:222 #: lib/pleroma/config/config_db.ex:222
#, elixir-format #, elixir-format
msgid "Config with params %{params} not found" msgid "Config with params %{params} not found"
msgstr "" msgstr "Nie znaleziono konfiguracji z parametrami %{params}"
#: lib/pleroma/web/common_api/common_api.ex:95 #: lib/pleroma/web/common_api/common_api.ex:95
#, elixir-format #, elixir-format
@ -213,38 +213,38 @@ msgstr "Nie udało się cofnąć powtórzenia"
#: lib/pleroma/web/common_api/common_api.ex:437 #: lib/pleroma/web/common_api/common_api.ex:437
#, elixir-format #, elixir-format
msgid "Could not update state" msgid "Could not update state"
msgstr "" msgstr "Nie można zaktualizować stanu"
#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:202 #: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:202
#, elixir-format #, elixir-format
msgid "Error." msgid "Error."
msgstr "" msgstr "Błąd."
#: lib/pleroma/web/twitter_api/twitter_api.ex:106 #: lib/pleroma/web/twitter_api/twitter_api.ex:106
#, elixir-format #, elixir-format
msgid "Invalid CAPTCHA" msgid "Invalid CAPTCHA"
msgstr "" msgstr "Niewłaściwa CAPTCHA"
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:117 #: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:117
#: lib/pleroma/web/oauth/oauth_controller.ex:569 #: lib/pleroma/web/oauth/oauth_controller.ex:569
#, elixir-format #, elixir-format
msgid "Invalid credentials" msgid "Invalid credentials"
msgstr "" msgstr "Nieprawidłowe dane uwierzytelniania"
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:38 #: lib/pleroma/plugs/ensure_authenticated_plug.ex:38
#, elixir-format #, elixir-format
msgid "Invalid credentials." msgid "Invalid credentials."
msgstr "" msgstr "Nieprawidłowe dane uwierzytelniania."
#: lib/pleroma/web/common_api/common_api.ex:265 #: lib/pleroma/web/common_api/common_api.ex:265
#, elixir-format #, elixir-format
msgid "Invalid indices" msgid "Invalid indices"
msgstr "" msgstr "Nieprawidłowe indeksy"
#: lib/pleroma/web/admin_api/admin_api_controller.ex:1147 #: lib/pleroma/web/admin_api/admin_api_controller.ex:1147
#, elixir-format #, elixir-format
msgid "Invalid parameters" msgid "Invalid parameters"
msgstr "" msgstr "Nieprawidłowe parametry"
#: lib/pleroma/web/common_api/utils.ex:411 #: lib/pleroma/web/common_api/utils.ex:411
#, elixir-format #, elixir-format
@ -307,7 +307,7 @@ msgstr "Coś się zepsuło"
#: lib/pleroma/web/common_api/activity_draft.ex:107 #: lib/pleroma/web/common_api/activity_draft.ex:107
#, elixir-format #, elixir-format
msgid "The message visibility must be direct" msgid "The message visibility must be direct"
msgstr "" msgstr "Widoczność wiadomości musi być „Bezpośrednia”"
#: lib/pleroma/web/common_api/utils.ex:566 #: lib/pleroma/web/common_api/utils.ex:566
#, elixir-format #, elixir-format
@ -317,17 +317,17 @@ msgstr "Ten status przekracza limit znaków"
#: lib/pleroma/plugs/ensure_public_or_authenticated_plug.ex:31 #: lib/pleroma/plugs/ensure_public_or_authenticated_plug.ex:31
#, elixir-format #, elixir-format
msgid "This resource requires authentication." msgid "This resource requires authentication."
msgstr "" msgstr "Ten zasób wymaga uwierzytelnienia."
#: lib/pleroma/plugs/rate_limiter/rate_limiter.ex:206 #: lib/pleroma/plugs/rate_limiter/rate_limiter.ex:206
#, elixir-format #, elixir-format
msgid "Throttled" msgid "Throttled"
msgstr "" msgstr "Ograniczono"
#: lib/pleroma/web/common_api/common_api.ex:266 #: lib/pleroma/web/common_api/common_api.ex:266
#, elixir-format #, elixir-format
msgid "Too many choices" msgid "Too many choices"
msgstr "" msgstr "Zbyt wiele wyborów"
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:442 #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:442
#, elixir-format #, elixir-format
@ -349,17 +349,18 @@ msgstr "Twoje konto jest obecnie nieaktywne"
#: lib/pleroma/web/oauth/oauth_controller.ex:332 #: lib/pleroma/web/oauth/oauth_controller.ex:332
#, elixir-format #, elixir-format
msgid "Your login is missing a confirmed e-mail address" msgid "Your login is missing a confirmed e-mail address"
msgstr "" msgstr "Twój adres e-mail nie został potwierdzony"
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:389 #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:389
#, elixir-format #, elixir-format
msgid "can't read inbox of %{nickname} as %{as_nickname}" msgid "can't read inbox of %{nickname} as %{as_nickname}"
msgstr "" msgstr "Nie można odczytać skrzynki odbiorczej %{nickname} jako %{as_nickname}"
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:472 #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:472
#, elixir-format #, elixir-format
msgid "can't update outbox of %{nickname} as %{as_nickname}" msgid "can't update outbox of %{nickname} as %{as_nickname}"
msgstr "" msgstr ""
"Nie można zaktualizować skrzynki nadawczcej %{nickname} jako %{as_nickname}"
#: lib/pleroma/web/common_api/common_api.ex:388 #: lib/pleroma/web/common_api/common_api.ex:388
#, elixir-format #, elixir-format
@ -405,12 +406,12 @@ msgstr "Nie udało się"
#: lib/pleroma/web/oauth/oauth_controller.ex:411 #: lib/pleroma/web/oauth/oauth_controller.ex:411
#, elixir-format #, elixir-format
msgid "Failed to authenticate: %{message}." msgid "Failed to authenticate: %{message}."
msgstr "" msgstr "Nie udało się uwierzytelnić: %{message}."
#: lib/pleroma/web/oauth/oauth_controller.ex:442 #: lib/pleroma/web/oauth/oauth_controller.ex:442
#, elixir-format #, elixir-format
msgid "Failed to set up user account." msgid "Failed to set up user account."
msgstr "" msgstr "Nie udało się skonfigurować konta użytkownika."
#: lib/pleroma/plugs/oauth_scopes_plug.ex:38 #: lib/pleroma/plugs/oauth_scopes_plug.ex:38
#, elixir-format #, elixir-format
@ -431,7 +432,7 @@ msgstr "Nieprawidłowa nazwa użytkownika lub hasło"
#: lib/pleroma/web/twitter_api/twitter_api.ex:118 #: lib/pleroma/web/twitter_api/twitter_api.ex:118
#, elixir-format #, elixir-format
msgid "Invalid answer data" msgid "Invalid answer data"
msgstr "" msgstr "Nieprawidłowe dane odpowiedzi"
#: lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:128 #: lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:128
#, elixir-format #, elixir-format
@ -441,7 +442,7 @@ msgstr "Nieobsługiwana wersja schematu Nodeinfo"
#: lib/pleroma/web/oauth/oauth_controller.ex:169 #: lib/pleroma/web/oauth/oauth_controller.ex:169
#, elixir-format #, elixir-format
msgid "This action is outside the authorized scopes" msgid "This action is outside the authorized scopes"
msgstr "" msgstr "Ta akcja wykracza poza dozwolone zakresy"
#: lib/pleroma/web/oauth/fallback_controller.ex:14 #: lib/pleroma/web/oauth/fallback_controller.ex:14
#, elixir-format #, elixir-format
@ -477,12 +478,12 @@ msgstr "Błąd CAPTCHA"
#: lib/pleroma/web/common_api/common_api.ex:200 #: lib/pleroma/web/common_api/common_api.ex:200
#, elixir-format #, elixir-format
msgid "Could not add reaction emoji" msgid "Could not add reaction emoji"
msgstr "" msgstr "Nie można dodać reakcji emoji"
#: lib/pleroma/web/common_api/common_api.ex:211 #: lib/pleroma/web/common_api/common_api.ex:211
#, elixir-format #, elixir-format
msgid "Could not remove reaction emoji" msgid "Could not remove reaction emoji"
msgstr "" msgstr "Nie można usunąć reakcji emoji"
#: lib/pleroma/web/twitter_api/twitter_api.ex:129 #: lib/pleroma/web/twitter_api/twitter_api.ex:129
#, elixir-format #, elixir-format
@ -535,6 +536,8 @@ msgstr "Wymagany reset hasła"
#, elixir-format #, elixir-format
msgid "Security violation: OAuth scopes check was neither handled nor explicitly skipped." msgid "Security violation: OAuth scopes check was neither handled nor explicitly skipped."
msgstr "" msgstr ""
"Naruszenie bezpieczeństwa: sprawdzanie zakresów OAuth nie zostało ani "
"wykonane, ani celowo pominięte."
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:28 #: lib/pleroma/plugs/ensure_authenticated_plug.ex:28
#, elixir-format #, elixir-format
@ -569,7 +572,7 @@ msgstr "Nieoczekiwany błąd podczas zmieniania metadanych paczki."
#: lib/pleroma/plugs/user_is_admin_plug.ex:21 #: lib/pleroma/plugs/user_is_admin_plug.ex:21
#, elixir-format #, elixir-format
msgid "User is not an admin." msgid "User is not an admin."
msgstr "" msgstr "Użytkownik nie jest administratorem."
#: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:61 #: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:61
#, elixir-format #, elixir-format

View File

@ -0,0 +1,40 @@
defmodule Pleroma.Repo.Migrations.SimplePolicyStringToTuple do
use Ecto.Migration
alias Pleroma.ConfigDB
def up, do: ConfigDB.get_by_params(%{group: :pleroma, key: :mrf_simple}) |> update_to_tuples
def down, do: ConfigDB.get_by_params(%{group: :pleroma, key: :mrf_simple}) |> update_to_strings
defp update_to_tuples(%{value: value}) do
new_value =
value
|> Enum.map(fn {k, v} ->
{k,
Enum.map(v, fn
{instance, reason} -> {instance, reason}
instance -> {instance, ""}
end)}
end)
ConfigDB.update_or_create(%{group: :pleroma, key: :mrf_simple, value: new_value})
end
defp update_to_tuples(nil), do: {:ok, nil}
defp update_to_strings(%{value: value}) do
new_value =
value
|> Enum.map(fn {k, v} ->
{k,
Enum.map(v, fn
{instance, _} -> instance
instance -> instance
end)}
end)
ConfigDB.update_or_create(%{group: :pleroma, key: :mrf_simple, value: new_value})
end
defp update_to_strings(nil), do: {:ok, nil}
end

View File

@ -0,0 +1,61 @@
defmodule Pleroma.Repo.Migrations.QuarantainedStringToTuple do
use Ecto.Migration
alias Pleroma.ConfigDB
def up,
do:
ConfigDB.get_by_params(%{group: :pleroma, key: :instance})
|> update_quarantined_instances_to_tuples
def down,
do:
ConfigDB.get_by_params(%{group: :pleroma, key: :instance})
|> update_quarantined_instances_to_strings
defp update_quarantined_instances_to_tuples(%{value: settings}) do
settings |> List.keyfind(:quarantined_instances, 0) |> update_to_tuples
end
defp update_quarantined_instances_to_tuples(nil), do: {:ok, nil}
defp update_to_tuples({:quarantined_instances, instance_list}) do
new_value =
instance_list
|> Enum.map(fn
{v, r} -> {v, r}
v -> {v, ""}
end)
ConfigDB.update_or_create(%{
group: :pleroma,
key: :instance,
value: [quarantined_instances: new_value]
})
end
defp update_to_tuples(nil), do: {:ok, nil}
defp update_quarantined_instances_to_strings(%{value: settings}) do
settings |> List.keyfind(:quarantined_instances, 0) |> update_to_strings
end
defp update_quarantined_instances_to_strings(nil), do: {:ok, nil}
defp update_to_strings({:quarantined_instances, instance_list}) do
new_value =
instance_list
|> Enum.map(fn
{v, _} -> v
v -> v
end)
ConfigDB.update_or_create(%{
group: :pleroma,
key: :instance,
value: [quarantined_instances: new_value]
})
end
defp update_to_strings(nil), do: {:ok, nil}
end

View File

@ -0,0 +1,61 @@
defmodule Pleroma.Repo.Migrations.TransparencyExclusionsStringToTuple do
use Ecto.Migration
alias Pleroma.ConfigDB
def up,
do:
ConfigDB.get_by_params(%{group: :pleroma, key: :mrf})
|> update_transparency_exclusions_instances_to_tuples
def down,
do:
ConfigDB.get_by_params(%{group: :pleroma, key: :mrf})
|> update_transparency_exclusions_instances_to_strings
defp update_transparency_exclusions_instances_to_tuples(%{value: settings}) do
settings |> List.keyfind(:transparency_exclusions, 0) |> update_to_tuples
end
defp update_transparency_exclusions_instances_to_tuples(nil), do: {:ok, nil}
defp update_to_tuples({:transparency_exclusions, instance_list}) do
new_value =
instance_list
|> Enum.map(fn
{v, r} -> {v, r}
v -> {v, ""}
end)
ConfigDB.update_or_create(%{
group: :pleroma,
key: :mrf,
value: [transparency_exclusions: new_value]
})
end
defp update_to_tuples(nil), do: {:ok, nil}
defp update_transparency_exclusions_instances_to_strings(%{value: settings}) do
settings |> List.keyfind(:transparency_exclusions, 0) |> update_to_strings
end
defp update_transparency_exclusions_instances_to_strings(nil), do: {:ok, nil}
defp update_to_strings({:transparency_exclusions, instance_list}) do
new_value =
instance_list
|> Enum.map(fn
{v, _} -> v
v -> v
end)
ConfigDB.update_or_create(%{
group: :pleroma,
key: :mrf,
value: [transparency_exclusions: new_value]
})
end
defp update_to_strings(nil), do: {:ok, nil}
end

View File

@ -0,0 +1,49 @@
defmodule Pleroma.Repo.Migrations.AddPollToNotificationsEnum do
use Ecto.Migration
@disable_ddl_transaction true
def up do
"""
alter type notification_type add value 'poll'
"""
|> execute()
end
def down do
alter table(:notifications) do
modify(:type, :string)
end
"""
delete from notifications where type = 'poll'
"""
|> execute()
"""
drop type if exists notification_type
"""
|> execute()
"""
create type notification_type as enum (
'follow',
'follow_request',
'mention',
'move',
'pleroma:emoji_reaction',
'pleroma:chat_mention',
'reblog',
'favourite',
'pleroma:report'
)
"""
|> execute()
"""
alter table notifications
alter column type type notification_type using (type::notification_type)
"""
|> execute()
end
end

View File

@ -11,6 +11,183 @@ defmodule Pleroma.Config.DeprecationWarningsTest do
alias Pleroma.Config alias Pleroma.Config
alias Pleroma.Config.DeprecationWarnings alias Pleroma.Config.DeprecationWarnings
describe "simple policy tuples" do
test "gives warning when there are still strings" do
clear_config([:mrf_simple],
media_removal: ["some.removal"],
media_nsfw: ["some.nsfw"],
federated_timeline_removal: ["some.tl.removal"],
report_removal: ["some.report.removal"],
reject: ["some.reject"],
followers_only: ["some.followers.only"],
accept: ["some.accept"],
avatar_removal: ["some.avatar.removal"],
banner_removal: ["some.banner.removal"],
reject_deletes: ["some.reject.deletes"]
)
assert capture_log(fn -> DeprecationWarnings.check_simple_policy_tuples() end) =~
"""
!!!DEPRECATION WARNING!!!
Your config is using strings in the SimplePolicy configuration instead of tuples. They should work for now, but you are advised to change to the new configuration to prevent possible issues later:
```
config :pleroma, :mrf_simple,
media_removal: ["instance.tld"],
media_nsfw: ["instance.tld"],
federated_timeline_removal: ["instance.tld"],
report_removal: ["instance.tld"],
reject: ["instance.tld"],
followers_only: ["instance.tld"],
accept: ["instance.tld"],
avatar_removal: ["instance.tld"],
banner_removal: ["instance.tld"],
reject_deletes: ["instance.tld"]
```
Is now
```
config :pleroma, :mrf_simple,
media_removal: [{"instance.tld", "Reason for media removal"}],
media_nsfw: [{"instance.tld", "Reason for media nsfw"}],
federated_timeline_removal: [{"instance.tld", "Reason for federated timeline removal"}],
report_removal: [{"instance.tld", "Reason for report removal"}],
reject: [{"instance.tld", "Reason for reject"}],
followers_only: [{"instance.tld", "Reason for followers only"}],
accept: [{"instance.tld", "Reason for accept"}],
avatar_removal: [{"instance.tld", "Reason for avatar removal"}],
banner_removal: [{"instance.tld", "Reason for banner removal"}],
reject_deletes: [{"instance.tld", "Reason for reject deletes"}]
```
"""
end
test "transforms config to tuples" do
clear_config([:mrf_simple],
media_removal: ["some.removal", {"some.other.instance", "Some reason"}]
)
expected_config = [
{:media_removal, [{"some.removal", ""}, {"some.other.instance", "Some reason"}]}
]
capture_log(fn -> DeprecationWarnings.warn() end)
assert Config.get([:mrf_simple]) == expected_config
end
test "doesn't give a warning with correct config" do
clear_config([:mrf_simple],
media_removal: [{"some.removal", ""}, {"some.other.instance", "Some reason"}]
)
assert capture_log(fn -> DeprecationWarnings.check_simple_policy_tuples() end) == ""
end
end
describe "quarantined_instances tuples" do
test "gives warning when there are still strings" do
clear_config([:instance, :quarantined_instances], [
{"domain.com", "some reason"},
"somedomain.tld"
])
assert capture_log(fn -> DeprecationWarnings.check_quarantined_instances_tuples() end) =~
"""
!!!DEPRECATION WARNING!!!
Your config is using strings in the quarantined_instances configuration instead of tuples. They should work for now, but you are advised to change to the new configuration to prevent possible issues later:
```
config :pleroma, :instance,
quarantined_instances: ["instance.tld"]
```
Is now
```
config :pleroma, :instance,
quarantined_instances: [{"instance.tld", "Reason for quarantine"}]
```
"""
end
test "transforms config to tuples" do
clear_config([:instance, :quarantined_instances], [
{"domain.com", "some reason"},
"some.tld"
])
expected_config = [{"domain.com", "some reason"}, {"some.tld", ""}]
capture_log(fn -> DeprecationWarnings.warn() end)
assert Config.get([:instance, :quarantined_instances]) == expected_config
end
test "doesn't give a warning with correct config" do
clear_config([:instance, :quarantined_instances], [
{"domain.com", "some reason"},
{"some.tld", ""}
])
assert capture_log(fn -> DeprecationWarnings.check_quarantined_instances_tuples() end) == ""
end
end
describe "transparency_exclusions tuples" do
test "gives warning when there are still strings" do
clear_config([:mrf, :transparency_exclusions], [
{"domain.com", "some reason"},
"somedomain.tld"
])
assert capture_log(fn -> DeprecationWarnings.check_transparency_exclusions_tuples() end) =~
"""
!!!DEPRECATION WARNING!!!
Your config is using strings in the transparency_exclusions configuration instead of tuples. They should work for now, but you are advised to change to the new configuration to prevent possible issues later:
```
config :pleroma, :mrf,
transparency_exclusions: ["instance.tld"]
```
Is now
```
config :pleroma, :mrf,
transparency_exclusions: [{"instance.tld", "Reason to exlude transparency"}]
```
"""
end
test "transforms config to tuples" do
clear_config([:mrf, :transparency_exclusions], [
{"domain.com", "some reason"},
"some.tld"
])
expected_config = [{"domain.com", "some reason"}, {"some.tld", ""}]
capture_log(fn -> DeprecationWarnings.warn() end)
assert Config.get([:mrf, :transparency_exclusions]) == expected_config
end
test "doesn't give a warning with correct config" do
clear_config([:mrf, :transparency_exclusions], [
{"domain.com", "some reason"},
{"some.tld", ""}
])
assert capture_log(fn -> DeprecationWarnings.check_transparency_exclusions_tuples() end) ==
""
end
end
test "check_old_mrf_config/0" do test "check_old_mrf_config/0" do
clear_config([:instance, :rewrite_policy], []) clear_config([:instance, :rewrite_policy], [])
clear_config([:instance, :mrf_transparency], true) clear_config([:instance, :mrf_transparency], true)

View File

@ -129,6 +129,19 @@ defmodule Pleroma.NotificationTest do
end end
end end
test "create_poll_notifications/1" do
[user1, user2, user3, _, _] = insert_list(5, :user)
question = insert(:question, user: user1)
activity = insert(:question_activity, question: question)
{:ok, _, _} = CommonAPI.vote(user2, question, [0])
{:ok, _, _} = CommonAPI.vote(user3, question, [1])
{:ok, notifications} = Notification.create_poll_notifications(activity)
assert [user2.id, user3.id, user1.id] == Enum.map(notifications, & &1.user_id)
end
describe "CommonApi.post/2 notification-related functionality" do describe "CommonApi.post/2 notification-related functionality" do
test_with_mock "creates but does NOT send notification to blocker user", test_with_mock "creates but does NOT send notification to blocker user",
Push, Push,

View File

@ -480,7 +480,7 @@ defmodule Pleroma.UserTest do
) )
test "it sends a welcome chat message when Simple policy applied to local instance" do test "it sends a welcome chat message when Simple policy applied to local instance" do
clear_config([:mrf_simple, :media_nsfw], ["localhost"]) clear_config([:mrf_simple, :media_nsfw], [{"localhost", ""}])
welcome_user = insert(:user) welcome_user = insert(:user)
clear_config([:welcome, :chat_message, :enabled], true) clear_config([:welcome, :chat_message, :enabled], true)

View File

@ -0,0 +1,48 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.BuilderTest do
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.CommonAPI.ActivityDraft
use Pleroma.DataCase
import Pleroma.Factory
describe "note/1" do
test "returns note data" do
user = insert(:user)
note = insert(:note)
user2 = insert(:user)
user3 = insert(:user)
draft = %ActivityDraft{
user: user,
to: [user2.ap_id],
context: "2hu",
content_html: "<h1>This is :moominmamma: note</h1>",
in_reply_to: note.id,
tags: [name: "jimm"],
summary: "test summary",
cc: [user3.ap_id],
extra: %{"custom_tag" => "test"}
}
expected = %{
"actor" => user.ap_id,
"attachment" => [],
"cc" => [user3.ap_id],
"content" => "<h1>This is :moominmamma: note</h1>",
"context" => "2hu",
"sensitive" => false,
"summary" => "test summary",
"tag" => ["jimm"],
"to" => [user2.ap_id],
"type" => "Note",
"custom_tag" => "test"
}
assert {:ok, ^expected, []} = Builder.note(draft)
end
end
end

View File

@ -22,6 +22,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do
defp get_old_message do defp get_old_message do
File.read!("test/fixtures/mastodon-post-activity.json") File.read!("test/fixtures/mastodon-post-activity.json")
|> Jason.decode!() |> Jason.decode!()
|> Map.drop(["published"])
end end
defp get_new_message do defp get_new_message do

View File

@ -33,7 +33,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "has a matching host" do test "has a matching host" do
clear_config([:mrf_simple, :media_removal], ["remote.instance"]) clear_config([:mrf_simple, :media_removal], [{"remote.instance", "Some reason"}])
media_message = build_media_message() media_message = build_media_message()
local_message = build_local_message() local_message = build_local_message()
@ -46,7 +46,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "match with wildcard domain" do test "match with wildcard domain" do
clear_config([:mrf_simple, :media_removal], ["*.remote.instance"]) clear_config([:mrf_simple, :media_removal], [{"*.remote.instance", "Whatever reason"}])
media_message = build_media_message() media_message = build_media_message()
local_message = build_local_message() local_message = build_local_message()
@ -70,7 +70,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "has a matching host" do test "has a matching host" do
clear_config([:mrf_simple, :media_nsfw], ["remote.instance"]) clear_config([:mrf_simple, :media_nsfw], [{"remote.instance", "Whetever"}])
media_message = build_media_message() media_message = build_media_message()
local_message = build_local_message() local_message = build_local_message()
@ -81,7 +81,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "match with wildcard domain" do test "match with wildcard domain" do
clear_config([:mrf_simple, :media_nsfw], ["*.remote.instance"]) clear_config([:mrf_simple, :media_nsfw], [{"*.remote.instance", "yeah yeah"}])
media_message = build_media_message() media_message = build_media_message()
local_message = build_local_message() local_message = build_local_message()
@ -115,7 +115,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "has a matching host" do test "has a matching host" do
clear_config([:mrf_simple, :report_removal], ["remote.instance"]) clear_config([:mrf_simple, :report_removal], [{"remote.instance", "muh"}])
report_message = build_report_message() report_message = build_report_message()
local_message = build_local_message() local_message = build_local_message()
@ -124,7 +124,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "match with wildcard domain" do test "match with wildcard domain" do
clear_config([:mrf_simple, :report_removal], ["*.remote.instance"]) clear_config([:mrf_simple, :report_removal], [{"*.remote.instance", "suya"}])
report_message = build_report_message() report_message = build_report_message()
local_message = build_local_message() local_message = build_local_message()
@ -159,7 +159,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|> URI.parse() |> URI.parse()
|> Map.fetch!(:host) |> Map.fetch!(:host)
clear_config([:mrf_simple, :federated_timeline_removal], [ftl_message_actor_host]) clear_config([:mrf_simple, :federated_timeline_removal], [{ftl_message_actor_host, "uwu"}])
local_message = build_local_message() local_message = build_local_message()
assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message) assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
@ -180,7 +180,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|> URI.parse() |> URI.parse()
|> Map.fetch!(:host) |> Map.fetch!(:host)
clear_config([:mrf_simple, :federated_timeline_removal], ["*." <> ftl_message_actor_host]) clear_config([:mrf_simple, :federated_timeline_removal], [
{"*." <> ftl_message_actor_host, "owo"}
])
local_message = build_local_message() local_message = build_local_message()
assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message) assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
@ -203,7 +206,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
ftl_message = Map.put(ftl_message, "cc", []) ftl_message = Map.put(ftl_message, "cc", [])
clear_config([:mrf_simple, :federated_timeline_removal], [ftl_message_actor_host]) clear_config([:mrf_simple, :federated_timeline_removal], [
{ftl_message_actor_host, "spiderwaifu goes 88w88"}
])
assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message) assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"] refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"]
@ -232,7 +237,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "activity has a matching host" do test "activity has a matching host" do
clear_config([:mrf_simple, :reject], ["remote.instance"]) clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
remote_message = build_remote_message() remote_message = build_remote_message()
@ -240,7 +245,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "activity matches with wildcard domain" do test "activity matches with wildcard domain" do
clear_config([:mrf_simple, :reject], ["*.remote.instance"]) clear_config([:mrf_simple, :reject], [{"*.remote.instance", ""}])
remote_message = build_remote_message() remote_message = build_remote_message()
@ -248,7 +253,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "actor has a matching host" do test "actor has a matching host" do
clear_config([:mrf_simple, :reject], ["remote.instance"]) clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
remote_user = build_remote_user() remote_user = build_remote_user()
@ -256,7 +261,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "reject Announce when object would be rejected" do test "reject Announce when object would be rejected" do
clear_config([:mrf_simple, :reject], ["blocked.tld"]) clear_config([:mrf_simple, :reject], [{"blocked.tld", ""}])
announce = %{ announce = %{
"type" => "Announce", "type" => "Announce",
@ -268,7 +273,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "reject by URI object" do test "reject by URI object" do
clear_config([:mrf_simple, :reject], ["blocked.tld"]) clear_config([:mrf_simple, :reject], [{"blocked.tld", ""}])
announce = %{ announce = %{
"type" => "Announce", "type" => "Announce",
@ -322,7 +327,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|> URI.parse() |> URI.parse()
|> Map.fetch!(:host) |> Map.fetch!(:host)
clear_config([:mrf_simple, :followers_only], [actor_domain]) clear_config([:mrf_simple, :followers_only], [{actor_domain, ""}])
assert {:ok, new_activity} = SimplePolicy.filter(activity) assert {:ok, new_activity} = SimplePolicy.filter(activity)
assert actor.follower_address in new_activity["cc"] assert actor.follower_address in new_activity["cc"]
@ -350,7 +355,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "is not empty but activity doesn't have a matching host" do test "is not empty but activity doesn't have a matching host" do
clear_config([:mrf_simple, :accept], ["non.matching.remote"]) clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}])
local_message = build_local_message() local_message = build_local_message()
remote_message = build_remote_message() remote_message = build_remote_message()
@ -360,7 +365,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "activity has a matching host" do test "activity has a matching host" do
clear_config([:mrf_simple, :accept], ["remote.instance"]) clear_config([:mrf_simple, :accept], [{"remote.instance", ""}])
local_message = build_local_message() local_message = build_local_message()
remote_message = build_remote_message() remote_message = build_remote_message()
@ -370,7 +375,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "activity matches with wildcard domain" do test "activity matches with wildcard domain" do
clear_config([:mrf_simple, :accept], ["*.remote.instance"]) clear_config([:mrf_simple, :accept], [{"*.remote.instance", ""}])
local_message = build_local_message() local_message = build_local_message()
remote_message = build_remote_message() remote_message = build_remote_message()
@ -380,7 +385,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "actor has a matching host" do test "actor has a matching host" do
clear_config([:mrf_simple, :accept], ["remote.instance"]) clear_config([:mrf_simple, :accept], [{"remote.instance", ""}])
remote_user = build_remote_user() remote_user = build_remote_user()
@ -398,7 +403,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "is not empty but it doesn't have a matching host" do test "is not empty but it doesn't have a matching host" do
clear_config([:mrf_simple, :avatar_removal], ["non.matching.remote"]) clear_config([:mrf_simple, :avatar_removal], [{"non.matching.remote", ""}])
remote_user = build_remote_user() remote_user = build_remote_user()
@ -406,7 +411,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "has a matching host" do test "has a matching host" do
clear_config([:mrf_simple, :avatar_removal], ["remote.instance"]) clear_config([:mrf_simple, :avatar_removal], [{"remote.instance", ""}])
remote_user = build_remote_user() remote_user = build_remote_user()
{:ok, filtered} = SimplePolicy.filter(remote_user) {:ok, filtered} = SimplePolicy.filter(remote_user)
@ -415,7 +420,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "match with wildcard domain" do test "match with wildcard domain" do
clear_config([:mrf_simple, :avatar_removal], ["*.remote.instance"]) clear_config([:mrf_simple, :avatar_removal], [{"*.remote.instance", ""}])
remote_user = build_remote_user() remote_user = build_remote_user()
{:ok, filtered} = SimplePolicy.filter(remote_user) {:ok, filtered} = SimplePolicy.filter(remote_user)
@ -434,7 +439,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "is not empty but it doesn't have a matching host" do test "is not empty but it doesn't have a matching host" do
clear_config([:mrf_simple, :banner_removal], ["non.matching.remote"]) clear_config([:mrf_simple, :banner_removal], [{"non.matching.remote", ""}])
remote_user = build_remote_user() remote_user = build_remote_user()
@ -442,7 +447,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "has a matching host" do test "has a matching host" do
clear_config([:mrf_simple, :banner_removal], ["remote.instance"]) clear_config([:mrf_simple, :banner_removal], [{"remote.instance", ""}])
remote_user = build_remote_user() remote_user = build_remote_user()
{:ok, filtered} = SimplePolicy.filter(remote_user) {:ok, filtered} = SimplePolicy.filter(remote_user)
@ -451,7 +456,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "match with wildcard domain" do test "match with wildcard domain" do
clear_config([:mrf_simple, :banner_removal], ["*.remote.instance"]) clear_config([:mrf_simple, :banner_removal], [{"*.remote.instance", ""}])
remote_user = build_remote_user() remote_user = build_remote_user()
{:ok, filtered} = SimplePolicy.filter(remote_user) {:ok, filtered} = SimplePolicy.filter(remote_user)
@ -464,7 +469,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
setup do: clear_config([:mrf_simple, :reject_deletes], []) setup do: clear_config([:mrf_simple, :reject_deletes], [])
test "it accepts deletions even from rejected servers" do test "it accepts deletions even from rejected servers" do
clear_config([:mrf_simple, :reject], ["remote.instance"]) clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
deletion_message = build_remote_deletion_message() deletion_message = build_remote_deletion_message()
@ -472,7 +477,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "it accepts deletions even from non-whitelisted servers" do test "it accepts deletions even from non-whitelisted servers" do
clear_config([:mrf_simple, :accept], ["non.matching.remote"]) clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}])
deletion_message = build_remote_deletion_message() deletion_message = build_remote_deletion_message()
@ -481,10 +486,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
describe "when :reject_deletes is not empty but it doesn't have a matching host" do describe "when :reject_deletes is not empty but it doesn't have a matching host" do
setup do: clear_config([:mrf_simple, :reject_deletes], ["non.matching.remote"]) setup do: clear_config([:mrf_simple, :reject_deletes], [{"non.matching.remote", ""}])
test "it accepts deletions even from rejected servers" do test "it accepts deletions even from rejected servers" do
clear_config([:mrf_simple, :reject], ["remote.instance"]) clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
deletion_message = build_remote_deletion_message() deletion_message = build_remote_deletion_message()
@ -492,7 +497,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
test "it accepts deletions even from non-whitelisted servers" do test "it accepts deletions even from non-whitelisted servers" do
clear_config([:mrf_simple, :accept], ["non.matching.remote"]) clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}])
deletion_message = build_remote_deletion_message() deletion_message = build_remote_deletion_message()
@ -501,7 +506,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
describe "when :reject_deletes has a matching host" do describe "when :reject_deletes has a matching host" do
setup do: clear_config([:mrf_simple, :reject_deletes], ["remote.instance"]) setup do: clear_config([:mrf_simple, :reject_deletes], [{"remote.instance", ""}])
test "it rejects the deletion" do test "it rejects the deletion" do
deletion_message = build_remote_deletion_message() deletion_message = build_remote_deletion_message()
@ -511,7 +516,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end end
describe "when :reject_deletes match with wildcard domain" do describe "when :reject_deletes match with wildcard domain" do
setup do: clear_config([:mrf_simple, :reject_deletes], ["*.remote.instance"]) setup do: clear_config([:mrf_simple, :reject_deletes], [{"*.remote.instance", ""}])
test "it rejects the deletion" do test "it rejects the deletion" do
deletion_message = build_remote_deletion_message() deletion_message = build_remote_deletion_message()

View File

@ -63,6 +63,15 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do
end end
end end
describe "instance_list_from_tuples/1" do
test "returns a list of instances from a list of {instance, reason} tuples" do
list = [{"some.tld", "a reason"}, {"other.tld", "another reason"}]
expected = ["some.tld", "other.tld"]
assert MRF.instance_list_from_tuples(list) == expected
end
end
describe "describe/0" do describe "describe/0" do
test "it works as expected with noop policy" do test "it works as expected with noop policy" do
clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.NoOpPolicy]) clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.NoOpPolicy])

View File

@ -267,6 +267,80 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
end end
describe "publish/2" do describe "publish/2" do
test_with_mock "doesn't publish a non-public activity to quarantined instances.",
Pleroma.Web.Federator.Publisher,
[:passthrough],
[] do
Config.put([:instance, :quarantined_instances], [{"domain.com", "some reason"}])
follower =
insert(:user, %{
local: false,
inbox: "https://domain.com/users/nick1/inbox",
ap_enabled: true
})
actor = insert(:user, follower_address: follower.ap_id)
{:ok, follower, actor} = Pleroma.User.follow(follower, actor)
actor = refresh_record(actor)
note_activity =
insert(:followers_only_note_activity,
user: actor,
recipients: [follower.ap_id]
)
res = Publisher.publish(actor, note_activity)
assert res == :ok
assert not called(
Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{
inbox: "https://domain.com/users/nick1/inbox",
actor_id: actor.id,
id: note_activity.data["id"]
})
)
end
test_with_mock "Publishes a non-public activity to non-quarantined instances.",
Pleroma.Web.Federator.Publisher,
[:passthrough],
[] do
Config.put([:instance, :quarantined_instances], [{"somedomain.com", "some reason"}])
follower =
insert(:user, %{
local: false,
inbox: "https://domain.com/users/nick1/inbox",
ap_enabled: true
})
actor = insert(:user, follower_address: follower.ap_id)
{:ok, follower, actor} = Pleroma.User.follow(follower, actor)
actor = refresh_record(actor)
note_activity =
insert(:followers_only_note_activity,
user: actor,
recipients: [follower.ap_id]
)
res = Publisher.publish(actor, note_activity)
assert res == :ok
assert called(
Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{
inbox: "https://domain.com/users/nick1/inbox",
actor_id: actor.id,
id: note_activity.data["id"]
})
)
end
test_with_mock "publishes an activity with BCC to all relevant peers.", test_with_mock "publishes an activity with BCC to all relevant peers.",
Pleroma.Web.Federator.Publisher, Pleroma.Web.Federator.Publisher,
[:passthrough], [:passthrough],

View File

@ -157,6 +157,30 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
end end
end end
describe "Question objects" do
setup do
user = insert(:user)
question = build(:question, user: user)
question_activity = build(:question_activity, question: question)
activity_data = Map.put(question_activity.data, "object", question.data["id"])
meta = [object_data: question.data, local: false]
{:ok, activity, meta} = ActivityPub.persist(activity_data, meta)
%{activity: activity, meta: meta}
end
test "enqueues the poll end", %{activity: activity, meta: meta} do
{:ok, activity, meta} = SideEffects.handle(activity, meta)
assert_enqueued(
worker: Pleroma.Workers.PollWorker,
args: %{op: "poll_end", activity_id: activity.id},
scheduled_at: NaiveDateTime.from_iso8601!(meta[:object_data]["closed"])
)
end
end
describe "delete users with confirmation pending" do describe "delete users with confirmation pending" do
setup do setup do
user = insert(:user, is_confirmed: false) user = insert(:user, is_confirmed: false)

View File

@ -42,6 +42,20 @@ defmodule Pleroma.Web.AdminAPI.FrontendControllerTest do
refute Enum.any?(response, fn frontend -> frontend["installed"] == true end) refute Enum.any?(response, fn frontend -> frontend["installed"] == true end)
end end
test "it lists available frontends when no frontend folder was created yet", %{conn: conn} do
File.rm_rf(@dir)
response =
conn
|> get("/api/pleroma/admin/frontends")
|> json_response_and_validate_schema(:ok)
assert Enum.map(response, & &1["name"]) ==
Enum.map(Config.get([:frontends, :available]), fn {_, map} -> map["name"] end)
refute Enum.any?(response, fn frontend -> frontend["installed"] == true end)
end
end end
describe "POST /api/pleroma/admin/frontends/install" do describe "POST /api/pleroma/admin/frontends/install" do

View File

@ -305,7 +305,7 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do
|> get("/api/pleroma/admin/reports") |> get("/api/pleroma/admin/reports")
assert json_response(conn, :forbidden) == assert json_response(conn, :forbidden) ==
%{"error" => "User is not an admin."} %{"error" => "User is not a staff member."}
end end
test "returns 403 when requested by anonymous" do test "returns 403 when requested by anonymous" do

View File

@ -655,6 +655,16 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
assert Utils.attachments_from_ids(%{media_ids: ["#{object.id}"]}) == [object.data] assert Utils.attachments_from_ids(%{media_ids: ["#{object.id}"]}) == [object.data]
end end
test "returns attachment object with raw URL" do
assert Utils.attachments_from_ids(%{media_ids: ["https://example.org/corndog.jpeg"]}) == [
%{
"name" => nil,
"type" => "Document",
"url" => [%{"href" => "https://example.org/corndog.jpeg", "type" => "Link"}]
}
]
end
test "returns [] when not pass media_ids" do test "returns [] when not pass media_ids" do
assert Utils.attachments_from_ids(%{}) == [] assert Utils.attachments_from_ids(%{}) == []
end end
@ -681,41 +691,6 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
end end
end end
describe "make_note_data/1" do
test "returns note data" do
user = insert(:user)
note = insert(:note)
user2 = insert(:user)
user3 = insert(:user)
draft = %ActivityDraft{
user: user,
to: [user2.ap_id],
context: "2hu",
content_html: "<h1>This is :moominmamma: note</h1>",
in_reply_to: note.id,
tags: [name: "jimm"],
summary: "test summary",
cc: [user3.ap_id],
extra: %{"custom_tag" => "test"}
}
assert Utils.make_note_data(draft) == %{
"actor" => user.ap_id,
"attachment" => [],
"cc" => [user3.ap_id],
"content" => "<h1>This is :moominmamma: note</h1>",
"context" => "2hu",
"sensitive" => false,
"summary" => "test summary",
"tag" => ["jimm"],
"to" => [user2.ap_id],
"type" => "Note",
"custom_tag" => "test"
}
end
end
describe "maybe_add_attachments/3" do describe "maybe_add_attachments/3" do
test "returns parsed results when attachment_links is false" do test "returns parsed results when attachment_links is false" do
assert Utils.maybe_add_attachments( assert Utils.maybe_add_attachments(

View File

@ -18,6 +18,7 @@ defmodule Pleroma.Web.CommonAPITest do
alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.AdminAPI.AccountView alias Pleroma.Web.AdminAPI.AccountView
alias Pleroma.Web.CommonAPI alias Pleroma.Web.CommonAPI
alias Pleroma.Workers.PollWorker
import Pleroma.Factory import Pleroma.Factory
import Mock import Mock
@ -48,6 +49,12 @@ defmodule Pleroma.Web.CommonAPITest do
assert object.data["type"] == "Question" assert object.data["type"] == "Question"
assert object.data["oneOf"] |> length() == 2 assert object.data["oneOf"] |> length() == 2
assert_enqueued(
worker: PollWorker,
args: %{op: "poll_end", activity_id: activity.id},
scheduled_at: NaiveDateTime.from_iso8601!(object.data["closed"])
)
end end
end end

View File

@ -16,6 +16,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.CommonAPI alias Pleroma.Web.CommonAPI
alias Pleroma.Workers.ScheduledActivityWorker
import Pleroma.Factory import Pleroma.Factory
@ -181,6 +182,18 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
assert json_response_and_validate_schema(conn, 200) assert json_response_and_validate_schema(conn, 200)
end end
test "posting an undefined status with arbitrary URL as attachment", %{conn: conn} do
assert response =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/statuses", %{
"media_ids" => ["https://example.org/corndog.jpeg"]
})
|> json_response_and_validate_schema(200)
assert [%{"url" => "https://example.org/corndog.jpeg"}] = response["media_attachments"]
end
test "replying to a status", %{user: user, conn: conn} do test "replying to a status", %{user: user, conn: conn} do
{:ok, replied_to} = CommonAPI.post(user, %{status: "cofe"}) {:ok, replied_to} = CommonAPI.post(user, %{status: "cofe"})
@ -705,11 +718,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert {:ok, %{id: activity_id}} = assert {:ok, %{id: activity_id}} =
perform_job(Pleroma.Workers.ScheduledActivityWorker, %{ perform_job(ScheduledActivityWorker, %{
activity_id: scheduled_id activity_id: scheduled_id
}) })
assert Repo.all(Oban.Job) == [] refute_enqueued(worker: ScheduledActivityWorker)
object = object =
Activity Activity

View File

@ -196,6 +196,27 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
test_notifications_rendering([notification], user, [expected]) test_notifications_rendering([notification], user, [expected])
end end
test "Poll notification" do
user = insert(:user)
activity = insert(:question_activity, user: user)
{:ok, [notification]} = Notification.create_poll_notifications(activity)
expected = %{
id: to_string(notification.id),
pleroma: %{is_seen: false, is_muted: false},
type: "poll",
account:
AccountView.render("show.json", %{
user: user,
for: user
}),
status: StatusView.render("show.json", %{activity: activity, for: user}),
created_at: Utils.to_masto_date(notification.inserted_at)
}
test_notifications_rendering([notification], user, [expected])
end
test "Report notification" do test "Report notification" do
reporting_user = insert(:user) reporting_user = insert(:user)
reported_user = insert(:user) reported_user = insert(:user)

View File

@ -150,37 +150,127 @@ defmodule Pleroma.Web.NodeInfoTest do
) )
end end
test "it shows MRF transparency data if enabled", %{conn: conn} do describe "Quarantined instances" do
clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy]) setup do
clear_config([:mrf, :transparency], true) clear_config([:mrf, :transparency], true)
quarantined_instances = [{"example.com", "reason to quarantine"}]
clear_config([:instance, :quarantined_instances], quarantined_instances)
end
simple_config = %{"reject" => ["example.com"]} test "shows quarantined instances data if enabled", %{conn: conn} do
clear_config(:mrf_simple, simple_config) expected_config = ["example.com"]
response = response =
conn conn
|> get("/nodeinfo/2.1.json") |> get("/nodeinfo/2.1.json")
|> json_response(:ok) |> json_response(:ok)
assert response["metadata"]["federation"]["mrf_simple"] == simple_config assert response["metadata"]["federation"]["quarantined_instances"] == expected_config
end
test "shows extra information in the quarantined_info field for relevant entries", %{
conn: conn
} do
clear_config([:mrf, :transparency], true)
expected_config = %{
"quarantined_instances" => %{
"example.com" => %{"reason" => "reason to quarantine"}
}
}
response =
conn
|> get("/nodeinfo/2.1.json")
|> json_response(:ok)
assert response["metadata"]["federation"]["quarantined_instances_info"] == expected_config
end
end end
test "it performs exclusions from MRF transparency data if configured", %{conn: conn} do describe "MRF SimplePolicy" do
clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy]) setup do
clear_config([:mrf, :transparency], true) clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
clear_config([:mrf, :transparency_exclusions], ["other.site"]) clear_config([:mrf, :transparency], true)
end
simple_config = %{"reject" => ["example.com", "other.site"]} test "shows MRF transparency data if enabled", %{conn: conn} do
clear_config(:mrf_simple, simple_config) simple_config = %{"reject" => [{"example.com", ""}]}
clear_config(:mrf_simple, simple_config)
expected_config = %{"reject" => ["example.com"]} expected_config = %{"reject" => ["example.com"]}
response = response =
conn conn
|> get("/nodeinfo/2.1.json") |> get("/nodeinfo/2.1.json")
|> json_response(:ok) |> json_response(:ok)
assert response["metadata"]["federation"]["mrf_simple"] == expected_config assert response["metadata"]["federation"]["mrf_simple"] == expected_config
assert response["metadata"]["federation"]["exclusions"] == true end
test "performs exclusions from MRF transparency data if configured", %{conn: conn} do
clear_config([:mrf, :transparency_exclusions], [
{"other.site", "We don't want them to know"}
])
simple_config = %{"reject" => [{"example.com", ""}, {"other.site", ""}]}
clear_config(:mrf_simple, simple_config)
expected_config = %{"reject" => ["example.com"]}
response =
conn
|> get("/nodeinfo/2.1.json")
|> json_response(:ok)
assert response["metadata"]["federation"]["mrf_simple"] == expected_config
assert response["metadata"]["federation"]["exclusions"] == true
end
test "shows extra information in the mrf_simple_info field for relevant entries", %{
conn: conn
} do
simple_config = %{
media_removal: [{"no.media", "LEEWWWDD >//<"}],
media_nsfw: [],
federated_timeline_removal: [{"no.ftl", ""}],
report_removal: [],
reject: [
{"example.instance", "Some reason"},
{"uwu.owo", "awoo to much"},
{"no.reason", ""}
],
followers_only: [],
accept: [],
avatar_removal: [],
banner_removal: [],
reject_deletes: [
{"peak.me", "I want to peak at what they don't want me to see, eheh"}
]
}
clear_config(:mrf_simple, simple_config)
clear_config([:mrf, :transparency_exclusions], [
{"peak.me", "I don't want them to know"}
])
expected_config = %{
"media_removal" => %{
"no.media" => %{"reason" => "LEEWWWDD >//<"}
},
"reject" => %{
"example.instance" => %{"reason" => "Some reason"},
"uwu.owo" => %{"reason" => "awoo to much"}
}
}
response =
conn
|> get("/nodeinfo/2.1.json")
|> json_response(:ok)
assert response["metadata"]["federation"]["mrf_simple_info"] == expected_config
end
end end
end end

View File

@ -0,0 +1,47 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Plugs.UserIsStaffPlugTest do
use Pleroma.Web.ConnCase, async: true
alias Pleroma.Web.Plugs.UserIsStaffPlug
import Pleroma.Factory
test "accepts a user that is an admin" do
user = insert(:user, is_admin: true)
conn = assign(build_conn(), :user, user)
ret_conn = UserIsStaffPlug.call(conn, %{})
assert conn == ret_conn
end
test "accepts a user that is a moderator" do
user = insert(:user, is_moderator: true)
conn = assign(build_conn(), :user, user)
ret_conn = UserIsStaffPlug.call(conn, %{})
assert conn == ret_conn
end
test "denies a user that isn't a staff member" do
user = insert(:user)
conn =
build_conn()
|> assign(:user, user)
|> UserIsStaffPlug.call(%{})
assert conn.status == 403
end
test "denies when a user isn't set" do
conn = UserIsStaffPlug.call(build_conn(), %{})
assert conn.status == 403
end
end

View File

@ -261,11 +261,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
conn = conn =
conn conn
|> assign(:token, nil) |> assign(:token, nil)
|> post( |> put_req_header("content-type", "multipart/form-data")
"/api/pleroma/change_email?#{ |> post("/api/pleroma/change_email", %{password: "hi", email: "test@test.com"})
URI.encode_query(%{password: "hi", email: "test@test.com"})
}"
)
assert json_response_and_validate_schema(conn, 403) == %{ assert json_response_and_validate_schema(conn, 403) == %{
"error" => "Insufficient permissions: write:accounts." "error" => "Insufficient permissions: write:accounts."
@ -274,12 +271,9 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
test "with proper permissions and invalid password", %{conn: conn} do test "with proper permissions and invalid password", %{conn: conn} do
conn = conn =
post( conn
conn, |> put_req_header("content-type", "multipart/form-data")
"/api/pleroma/change_email?#{ |> post("/api/pleroma/change_email", %{password: "hi", email: "test@test.com"})
URI.encode_query(%{password: "hi", email: "test@test.com"})
}"
)
assert json_response_and_validate_schema(conn, 200) == %{"error" => "Invalid password."} assert json_response_and_validate_schema(conn, 200) == %{"error" => "Invalid password."}
end end
@ -288,10 +282,9 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
conn: conn conn: conn
} do } do
conn = conn =
post( conn
conn, |> put_req_header("content-type", "multipart/form-data")
"/api/pleroma/change_email?#{URI.encode_query(%{password: "test", email: "foobar"})}" |> post("/api/pleroma/change_email", %{password: "test", email: "foobar"})
)
assert json_response_and_validate_schema(conn, 200) == %{ assert json_response_and_validate_schema(conn, 200) == %{
"error" => "Email has invalid format." "error" => "Email has invalid format."
@ -301,7 +294,10 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
test "with proper permissions, valid password and no email", %{ test "with proper permissions, valid password and no email", %{
conn: conn conn: conn
} do } do
conn = post(conn, "/api/pleroma/change_email?#{URI.encode_query(%{password: "test"})}") conn =
conn
|> put_req_header("content-type", "multipart/form-data")
|> post("/api/pleroma/change_email", %{password: "test"})
assert %{"error" => "Missing field: email."} = json_response_and_validate_schema(conn, 400) assert %{"error" => "Missing field: email."} = json_response_and_validate_schema(conn, 400)
end end
@ -310,10 +306,9 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
conn: conn conn: conn
} do } do
conn = conn =
post( conn
conn, |> put_req_header("content-type", "multipart/form-data")
"/api/pleroma/change_email?#{URI.encode_query(%{password: "test", email: ""})}" |> post("/api/pleroma/change_email", %{password: "test", email: ""})
)
assert json_response_and_validate_schema(conn, 200) == %{"error" => "Email can't be blank."} assert json_response_and_validate_schema(conn, 200) == %{"error" => "Email can't be blank."}
end end
@ -324,10 +319,9 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
user = insert(:user) user = insert(:user)
conn = conn =
post( conn
conn, |> put_req_header("content-type", "multipart/form-data")
"/api/pleroma/change_email?#{URI.encode_query(%{password: "test", email: user.email})}" |> post("/api/pleroma/change_email", %{password: "test", email: user.email})
)
assert json_response_and_validate_schema(conn, 200) == %{ assert json_response_and_validate_schema(conn, 200) == %{
"error" => "Email has already been taken." "error" => "Email has already been taken."
@ -338,12 +332,9 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
conn: conn conn: conn
} do } do
conn = conn =
post( conn
conn, |> put_req_header("content-type", "multipart/form-data")
"/api/pleroma/change_email?#{ |> post("/api/pleroma/change_email", %{password: "test", email: "cofe@foobar.com"})
URI.encode_query(%{password: "test", email: "cofe@foobar.com"})
}"
)
assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"} assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"}
end end
@ -356,15 +347,12 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
conn = conn =
conn conn
|> assign(:token, nil) |> assign(:token, nil)
|> post( |> put_req_header("content-type", "multipart/form-data")
"/api/pleroma/change_password?#{ |> post("/api/pleroma/change_password", %{
URI.encode_query(%{ "password" => "hi",
password: "hi", "new_password" => "newpass",
new_password: "newpass", "new_password_confirmation" => "newpass"
new_password_confirmation: "newpass" })
})
}"
)
assert json_response_and_validate_schema(conn, 403) == %{ assert json_response_and_validate_schema(conn, 403) == %{
"error" => "Insufficient permissions: write:accounts." "error" => "Insufficient permissions: write:accounts."
@ -373,16 +361,13 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
test "with proper permissions and invalid password", %{conn: conn} do test "with proper permissions and invalid password", %{conn: conn} do
conn = conn =
post( conn
conn, |> put_req_header("content-type", "multipart/form-data")
"/api/pleroma/change_password?#{ |> post("/api/pleroma/change_password", %{
URI.encode_query(%{ "password" => "hi",
password: "hi", "new_password" => "newpass",
new_password: "newpass", "new_password_confirmation" => "newpass"
new_password_confirmation: "newpass" })
})
}"
)
assert json_response_and_validate_schema(conn, 200) == %{"error" => "Invalid password."} assert json_response_and_validate_schema(conn, 200) == %{"error" => "Invalid password."}
end end
@ -392,16 +377,13 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
conn: conn conn: conn
} do } do
conn = conn =
post( conn
conn, |> put_req_header("content-type", "multipart/form-data")
"/api/pleroma/change_password?#{ |> post("/api/pleroma/change_password", %{
URI.encode_query(%{ "password" => "test",
password: "test", "new_password" => "newpass",
new_password: "newpass", "new_password_confirmation" => "notnewpass"
new_password_confirmation: "notnewpass" })
})
}"
)
assert json_response_and_validate_schema(conn, 200) == %{ assert json_response_and_validate_schema(conn, 200) == %{
"error" => "New password does not match confirmation." "error" => "New password does not match confirmation."
@ -412,12 +394,13 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
conn: conn conn: conn
} do } do
conn = conn =
post( conn
conn, |> put_req_header("content-type", "multipart/form-data")
"/api/pleroma/change_password?#{ |> post("/api/pleroma/change_password", %{
URI.encode_query(%{password: "test", new_password: "", new_password_confirmation: ""}) password: "test",
}" new_password: "",
) new_password_confirmation: ""
})
assert json_response_and_validate_schema(conn, 200) == %{ assert json_response_and_validate_schema(conn, 200) == %{
"error" => "New password can't be blank." "error" => "New password can't be blank."
@ -429,15 +412,15 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
user: user user: user
} do } do
conn = conn =
post( conn
conn, |> put_req_header("content-type", "multipart/form-data")
"/api/pleroma/change_password?#{ |> post(
URI.encode_query(%{ "/api/pleroma/change_password",
password: "test", %{
new_password: "newpass", password: "test",
new_password_confirmation: "newpass" new_password: "newpass",
}) new_password_confirmation: "newpass"
}" }
) )
assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"} assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"}

View File

@ -142,6 +142,11 @@ defmodule Pleroma.Factory do
} }
end end
def followers_only_note_factory(attrs \\ %{}) do
%Pleroma.Object{data: data} = note_factory(attrs)
%Pleroma.Object{data: Map.merge(data, %{"to" => [data["actor"] <> "/followers"]})}
end
def audio_factory(attrs \\ %{}) do def audio_factory(attrs \\ %{}) do
text = sequence(:text, &"lain radio episode #{&1}") text = sequence(:text, &"lain radio episode #{&1}")
@ -208,6 +213,38 @@ defmodule Pleroma.Factory do
} }
end end
def question_factory(attrs \\ %{}) do
user = attrs[:user] || insert(:user)
data = %{
"id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
"type" => "Question",
"actor" => user.ap_id,
"attributedTo" => user.ap_id,
"attachment" => [],
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
"cc" => [user.follower_address],
"context" => Pleroma.Web.ActivityPub.Utils.generate_context_id(),
"closed" => DateTime.utc_now() |> DateTime.add(86_400) |> DateTime.to_iso8601(),
"oneOf" => [
%{
"type" => "Note",
"name" => "chocolate",
"replies" => %{"totalItems" => 0, "type" => "Collection"}
},
%{
"type" => "Note",
"name" => "vanilla",
"replies" => %{"totalItems" => 0, "type" => "Collection"}
}
]
}
%Pleroma.Object{
data: merge_attributes(data, Map.get(attrs, :data, %{}))
}
end
def direct_note_activity_factory do def direct_note_activity_factory do
dm = insert(:direct_note) dm = insert(:direct_note)
@ -267,6 +304,33 @@ defmodule Pleroma.Factory do
|> Map.merge(attrs) |> Map.merge(attrs)
end end
def followers_only_note_activity_factory(attrs \\ %{}) do
user = attrs[:user] || insert(:user)
note = insert(:followers_only_note, user: user)
data_attrs = attrs[:data_attrs] || %{}
attrs = Map.drop(attrs, [:user, :note, :data_attrs])
data =
%{
"id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
"type" => "Create",
"actor" => note.data["actor"],
"to" => note.data["to"],
"object" => note.data,
"published" => DateTime.utc_now() |> DateTime.to_iso8601(),
"context" => note.data["context"]
}
|> Map.merge(data_attrs)
%Pleroma.Activity{
data: data,
actor: data["actor"],
recipients: data["to"]
}
|> Map.merge(attrs)
end
def note_activity_factory(attrs \\ %{}) do def note_activity_factory(attrs \\ %{}) do
user = attrs[:user] || insert(:user) user = attrs[:user] || insert(:user)
note = attrs[:note] || insert(:note, user: user) note = attrs[:note] || insert(:note, user: user)
@ -396,6 +460,33 @@ defmodule Pleroma.Factory do
} }
end end
def question_activity_factory(attrs \\ %{}) do
user = attrs[:user] || insert(:user)
question = attrs[:question] || insert(:question, user: user)
data_attrs = attrs[:data_attrs] || %{}
attrs = Map.drop(attrs, [:user, :question, :data_attrs])
data =
%{
"id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
"type" => "Create",
"actor" => question.data["actor"],
"to" => question.data["to"],
"object" => question.data["id"],
"published" => DateTime.utc_now() |> DateTime.to_iso8601(),
"context" => question.data["context"]
}
|> Map.merge(data_attrs)
%Pleroma.Activity{
data: data,
actor: data["actor"],
recipients: data["to"]
}
|> Map.merge(attrs)
end
def oauth_app_factory do def oauth_app_factory do
%Pleroma.Web.OAuth.App{ %Pleroma.Web.OAuth.App{
client_name: sequence(:client_name, &"Some client #{&1}"), client_name: sequence(:client_name, &"Some client #{&1}"),