From 6b882a2c0b98bdf94bc557f86c2d16460d90f44e Mon Sep 17 00:00:00 2001 From: floatingghost Date: Sat, 3 Dec 2022 23:17:43 +0000 Subject: [PATCH] Purge Rejected Follow requests in daily task (#334) Co-authored-by: FloatingGhost Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/334 --- config/description.exs | 21 ++++++----- docs/docs/configuration/cheatsheet.md | 22 +++++++++--- lib/mix/tasks/pleroma/instance.ex | 2 +- lib/pleroma/activity/pruner.ex | 11 ++++++ .../accept_reject_validator.ex | 1 - lib/pleroma/web/views/manifest_view.ex | 12 +++---- .../workers/cron/database_prune_worker.ex | 3 ++ test/pleroma/activity/pruner_test.exs | 36 +++++++++++++++++++ .../emoji_file_controller_test.exs | 2 +- .../remote_follow_controller_test.exs | 2 +- test/support/factory.ex | 1 + 11 files changed, 87 insertions(+), 26 deletions(-) diff --git a/config/description.exs b/config/description.exs index fc10cbf81..001a21cba 100644 --- a/config/description.exs +++ b/config/description.exs @@ -691,8 +691,8 @@ key: :public, type: :boolean, description: - "Makes the client API in authenticated mode-only except for user-profiles." <> - " Useful for disabling the Local Timeline and The Whole Known Network. " <> + "Switching this on will allow unauthenticated users access to all public resources on your instance" <> + " Switching it off is useful for disabling the Local Timeline and The Whole Known Network. " <> " Note: when setting to `false`, please also check `:restrict_unauthenticated` setting." }, %{ @@ -2998,8 +2998,7 @@ key: :restrict_unauthenticated, label: "Restrict Unauthenticated", type: :group, - description: - "Disallow viewing timelines, user profiles and statuses for unauthenticated users.", + description: "Disallow unauthenticated viewing of timelines, user profiles and statuses.", children: [ %{ key: :timelines, @@ -3009,12 +3008,12 @@ %{ key: :local, type: :boolean, - description: "Disallow view public timeline." + description: "Disallow viewing the public timeline." }, %{ key: :federated, type: :boolean, - description: "Disallow view federated timeline." + description: "Disallow viewing the whole known network timeline." } ] }, @@ -3026,29 +3025,29 @@ %{ key: :local, type: :boolean, - description: "Disallow view local user profiles." + description: "Disallow viewing local user profiles." }, %{ key: :remote, type: :boolean, - description: "Disallow view remote user profiles." + description: "Disallow viewing remote user profiles." } ] }, %{ key: :activities, type: :map, - description: "Settings for statuses.", + description: "Settings for posts.", children: [ %{ key: :local, type: :boolean, - description: "Disallow view local statuses." + description: "Disallow viewing local posts." }, %{ key: :remote, type: :boolean, - description: "Disallow view remote statuses." + description: "Disallow viewing remote posts." } ] } diff --git a/docs/docs/configuration/cheatsheet.md b/docs/docs/configuration/cheatsheet.md index 517fd1993..12c044d67 100644 --- a/docs/docs/configuration/cheatsheet.md +++ b/docs/docs/configuration/cheatsheet.md @@ -33,7 +33,8 @@ To add configuration to your config file, you can copy it from the base config. * `federation_incoming_replies_max_depth`: Max. depth of reply-to activities fetching on incoming federation, to prevent out-of-memory situations while fetching very long threads. If set to `nil`, threads of any depth will be fetched. Lower this value if you experience out-of-memory crashes. * `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. -* `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`: Allows unauthenticated access to public resources on your instance. This is essentially used as the default value for `:restrict_unauthenticated`. + See `restrict_unauthenticated` for more details. * `quarantined_instances`: *DEPRECATED* ActivityPub instances where activities will not be sent. They can still reach there via other means, we just won't send them. * `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 @@ -1094,7 +1095,7 @@ config :pleroma, :database_config_whitelist, [ ### :restrict_unauthenticated -Restrict access for unauthenticated users to timelines (public and federated), user profiles and statuses. +Restrict access for unauthenticated users to timelines (public and federated), user profiles and posts. * `timelines`: public and federated timelines * `local`: public timeline @@ -1102,13 +1103,24 @@ Restrict access for unauthenticated users to timelines (public and federated), u * `profiles`: user profiles * `local` * `remote` -* `activities`: statuses +* `activities`: posts * `local` * `remote` -Note: when `:instance, :public` is set to `false`, all `:restrict_unauthenticated` items be effectively set to `true` by default. If you'd like to allow unauthenticated access to specific API endpoints on a private instance, please explicitly set `:restrict_unauthenticated` to non-default value in `config/prod.secret.exs`. +#### When :instance, :public is `true` -Note: setting `restrict_unauthenticated/timelines/local` to `true` has no practical sense if `restrict_unauthenticated/timelines/federated` is set to `false` (since local public activities will still be delivered to unauthenticated users as part of federated timeline). +When your instance is in "public" mode, all public resources (users, posts, timelines) are accessible to unauthenticated users. + +Turning any of the `:restrict_unauthenticated` options to `true` will restrict access to the corresponding resources. + +#### When :instance, :public is `false` + +When `:instance, :public` is set to `false`, all of the `:restrict_unauthenticated` options will effectively be set to `true` by default, +meaning that only authenticated users will be able to access the corresponding resources. + +If you'd like to allow unauthenticated access to specific resources, you can turn these settings to `false`. + +**Note**: setting `restrict_unauthenticated/timelines/local` to `true` has no practical sense if `restrict_unauthenticated/timelines/federated` is set to `false` (since local public activities will still be delivered to unauthenticated users as part of federated timeline). ## Pleroma.Web.ApiSpec.CastAndValidate diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex index 8954b3b7c..0647c330f 100644 --- a/lib/mix/tasks/pleroma/instance.ex +++ b/lib/mix/tasks/pleroma/instance.ex @@ -59,7 +59,7 @@ def run(["gen" | rest]) do get_option( options, :domain, - "What domain will your instance use? (e.g pleroma.soykaf.com)" + "What domain will your instance use? (e.g akkoma.example.com)" ), ":" ) ++ [443] diff --git a/lib/pleroma/activity/pruner.ex b/lib/pleroma/activity/pruner.ex index 054ee514a..7f561ebae 100644 --- a/lib/pleroma/activity/pruner.ex +++ b/lib/pleroma/activity/pruner.ex @@ -35,6 +35,17 @@ def prune_removes do |> Repo.delete_all(timeout: :infinity) end + def prune_stale_follow_requests do + before_time = cutoff() + + from(a in Activity, + where: + fragment("?->>'type' = ?", a.data, "Follow") and a.inserted_at < ^before_time and + fragment("?->>'state' = ?", a.data, "reject") + ) + |> Repo.delete_all(timeout: :infinity) + end + defp cutoff do DateTime.utc_now() |> Timex.shift(days: -@cutoff) end diff --git a/lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex b/lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex index 847d0be62..0561a9ddf 100644 --- a/lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex @@ -6,7 +6,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AcceptRejectValidator do use Ecto.Schema alias Pleroma.Activity - alias Pleroma.Object alias Pleroma.User import Ecto.Changeset diff --git a/lib/pleroma/web/views/manifest_view.ex b/lib/pleroma/web/views/manifest_view.ex index d8c736cef..5177b0eba 100644 --- a/lib/pleroma/web/views/manifest_view.ex +++ b/lib/pleroma/web/views/manifest_view.ex @@ -13,14 +13,14 @@ def render("manifest.json", _params) do description: Config.get([:instance, :description]), icons: [ %{ - src: "/static/logo.svg", - type: "image/svg+xml" + src: "/static/logo.svg", + type: "image/svg+xml" }, %{ - src: "/static/logo-512.png", - sizes: "512x512", - type: "image/png", - purpose: "maskable" + src: "/static/logo-512.png", + sizes: "512x512", + type: "image/png", + purpose: "maskable" } ], theme_color: Config.get([:manifest, :theme_color]), diff --git a/lib/pleroma/workers/cron/database_prune_worker.ex b/lib/pleroma/workers/cron/database_prune_worker.ex index 99ea2e836..58995c69a 100644 --- a/lib/pleroma/workers/cron/database_prune_worker.ex +++ b/lib/pleroma/workers/cron/database_prune_worker.ex @@ -15,6 +15,9 @@ def perform(_job) do Logger.info("Pruning old deletes") ActivityPruner.prune_deletes() + Logger.info("Pruning old follow requests") + ActivityPruner.prune_stale_follow_requests() + Logger.info("Pruning old undos") ActivityPruner.prune_undos() diff --git a/test/pleroma/activity/pruner_test.exs b/test/pleroma/activity/pruner_test.exs index 312d4f5e4..e8d4b30aa 100644 --- a/test/pleroma/activity/pruner_test.exs +++ b/test/pleroma/activity/pruner_test.exs @@ -24,4 +24,40 @@ test "it prunes old delete objects" do refute Activity.get_by_id(old_delete.id) end end + + describe "prune_stale_follow_requests" do + test "it prunes old follow requests" do + follower = insert(:user) + followee = insert(:user) + + new_follow_request = + insert( + :follow_activity, + follower: follower, + followed: followee, + state: "reject" + ) + + old_not_rejected_request = + insert(:follow_activity, + follower: follower, + followed: followee, + state: "pending", + inserted_at: DateTime.utc_now() |> DateTime.add(-31 * 24, :hour) + ) + + old_follow_request = + insert(:follow_activity, + follower: follower, + followed: followee, + inserted_at: DateTime.utc_now() |> DateTime.add(-31 * 24, :hour), + state: "reject" + ) + + Pruner.prune_stale_follow_requests() + assert Activity.get_by_id(new_follow_request.id) + assert Activity.get_by_id(old_not_rejected_request.id) + refute Activity.get_by_id(old_follow_request.id) + end + end end diff --git a/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs index 547391249..61a44b8ba 100644 --- a/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.PleromaAPI.EmojiFileControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: false import Mock import Tesla.Mock diff --git a/test/pleroma/web/twitter_api/remote_follow_controller_test.exs b/test/pleroma/web/twitter_api/remote_follow_controller_test.exs index 15e9b5884..e7c496eb0 100644 --- a/test/pleroma/web/twitter_api/remote_follow_controller_test.exs +++ b/test/pleroma/web/twitter_api/remote_follow_controller_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do - use Pleroma.Web.ConnCase, async: true + use Pleroma.Web.ConnCase, async: false alias Pleroma.MFA alias Pleroma.MFA.TOTP diff --git a/test/support/factory.ex b/test/support/factory.ex index 3e426c565..6ce4decbc 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -469,6 +469,7 @@ def follow_activity_factory(attrs \\ %{}) do data: data, actor: follower.ap_id } + |> Map.merge(attrs) end def report_activity_factory(attrs \\ %{}) do