forked from AkkomaGang/akkoma
Purge Rejected Follow requests in daily task (#334)
Co-authored-by: FloatingGhost <hannah@coffee-and-dreams.uk> Reviewed-on: AkkomaGang/akkoma#334
This commit is contained in:
parent
0c2c057c75
commit
6b882a2c0b
11 changed files with 87 additions and 26 deletions
|
@ -691,8 +691,8 @@
|
||||||
key: :public,
|
key: :public,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description:
|
description:
|
||||||
"Makes the client API in authenticated mode-only except for user-profiles." <>
|
"Switching this on will allow unauthenticated users access to all public resources on your instance" <>
|
||||||
" Useful for disabling the Local Timeline and The Whole Known Network. " <>
|
" 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."
|
" Note: when setting to `false`, please also check `:restrict_unauthenticated` setting."
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
|
@ -2998,8 +2998,7 @@
|
||||||
key: :restrict_unauthenticated,
|
key: :restrict_unauthenticated,
|
||||||
label: "Restrict Unauthenticated",
|
label: "Restrict Unauthenticated",
|
||||||
type: :group,
|
type: :group,
|
||||||
description:
|
description: "Disallow unauthenticated viewing of timelines, user profiles and statuses.",
|
||||||
"Disallow viewing timelines, user profiles and statuses for unauthenticated users.",
|
|
||||||
children: [
|
children: [
|
||||||
%{
|
%{
|
||||||
key: :timelines,
|
key: :timelines,
|
||||||
|
@ -3009,12 +3008,12 @@
|
||||||
%{
|
%{
|
||||||
key: :local,
|
key: :local,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Disallow view public timeline."
|
description: "Disallow viewing the public timeline."
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :federated,
|
key: :federated,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Disallow view federated timeline."
|
description: "Disallow viewing the whole known network timeline."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -3026,29 +3025,29 @@
|
||||||
%{
|
%{
|
||||||
key: :local,
|
key: :local,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Disallow view local user profiles."
|
description: "Disallow viewing local user profiles."
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :remote,
|
key: :remote,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Disallow view remote user profiles."
|
description: "Disallow viewing remote user profiles."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :activities,
|
key: :activities,
|
||||||
type: :map,
|
type: :map,
|
||||||
description: "Settings for statuses.",
|
description: "Settings for posts.",
|
||||||
children: [
|
children: [
|
||||||
%{
|
%{
|
||||||
key: :local,
|
key: :local,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Disallow view local statuses."
|
description: "Disallow viewing local posts."
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :remote,
|
key: :remote,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Disallow view remote statuses."
|
description: "Disallow viewing remote posts."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_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.
|
* `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`: 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.
|
* `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).
|
* `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
|
||||||
|
@ -1094,7 +1095,7 @@ config :pleroma, :database_config_whitelist, [
|
||||||
|
|
||||||
### :restrict_unauthenticated
|
### :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
|
* `timelines`: public and federated timelines
|
||||||
* `local`: public timeline
|
* `local`: public timeline
|
||||||
|
@ -1102,13 +1103,24 @@ Restrict access for unauthenticated users to timelines (public and federated), u
|
||||||
* `profiles`: user profiles
|
* `profiles`: user profiles
|
||||||
* `local`
|
* `local`
|
||||||
* `remote`
|
* `remote`
|
||||||
* `activities`: statuses
|
* `activities`: posts
|
||||||
* `local`
|
* `local`
|
||||||
* `remote`
|
* `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
|
## Pleroma.Web.ApiSpec.CastAndValidate
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ def run(["gen" | rest]) do
|
||||||
get_option(
|
get_option(
|
||||||
options,
|
options,
|
||||||
:domain,
|
:domain,
|
||||||
"What domain will your instance use? (e.g pleroma.soykaf.com)"
|
"What domain will your instance use? (e.g akkoma.example.com)"
|
||||||
),
|
),
|
||||||
":"
|
":"
|
||||||
) ++ [443]
|
) ++ [443]
|
||||||
|
|
|
@ -35,6 +35,17 @@ def prune_removes do
|
||||||
|> Repo.delete_all(timeout: :infinity)
|
|> Repo.delete_all(timeout: :infinity)
|
||||||
end
|
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
|
defp cutoff do
|
||||||
DateTime.utc_now() |> Timex.shift(days: -@cutoff)
|
DateTime.utc_now() |> Timex.shift(days: -@cutoff)
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,7 +6,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AcceptRejectValidator do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.Object
|
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
|
|
@ -13,14 +13,14 @@ def render("manifest.json", _params) do
|
||||||
description: Config.get([:instance, :description]),
|
description: Config.get([:instance, :description]),
|
||||||
icons: [
|
icons: [
|
||||||
%{
|
%{
|
||||||
src: "/static/logo.svg",
|
src: "/static/logo.svg",
|
||||||
type: "image/svg+xml"
|
type: "image/svg+xml"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
src: "/static/logo-512.png",
|
src: "/static/logo-512.png",
|
||||||
sizes: "512x512",
|
sizes: "512x512",
|
||||||
type: "image/png",
|
type: "image/png",
|
||||||
purpose: "maskable"
|
purpose: "maskable"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
theme_color: Config.get([:manifest, :theme_color]),
|
theme_color: Config.get([:manifest, :theme_color]),
|
||||||
|
|
|
@ -15,6 +15,9 @@ def perform(_job) do
|
||||||
Logger.info("Pruning old deletes")
|
Logger.info("Pruning old deletes")
|
||||||
ActivityPruner.prune_deletes()
|
ActivityPruner.prune_deletes()
|
||||||
|
|
||||||
|
Logger.info("Pruning old follow requests")
|
||||||
|
ActivityPruner.prune_stale_follow_requests()
|
||||||
|
|
||||||
Logger.info("Pruning old undos")
|
Logger.info("Pruning old undos")
|
||||||
ActivityPruner.prune_undos()
|
ActivityPruner.prune_undos()
|
||||||
|
|
||||||
|
|
|
@ -24,4 +24,40 @@ test "it prunes old delete objects" do
|
||||||
refute Activity.get_by_id(old_delete.id)
|
refute Activity.get_by_id(old_delete.id)
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Web.PleromaAPI.EmojiFileControllerTest do
|
defmodule Pleroma.Web.PleromaAPI.EmojiFileControllerTest do
|
||||||
use Pleroma.Web.ConnCase
|
use Pleroma.Web.ConnCase, async: false
|
||||||
|
|
||||||
import Mock
|
import Mock
|
||||||
import Tesla.Mock
|
import Tesla.Mock
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
|
defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
|
||||||
use Pleroma.Web.ConnCase, async: true
|
use Pleroma.Web.ConnCase, async: false
|
||||||
|
|
||||||
alias Pleroma.MFA
|
alias Pleroma.MFA
|
||||||
alias Pleroma.MFA.TOTP
|
alias Pleroma.MFA.TOTP
|
||||||
|
|
|
@ -469,6 +469,7 @@ def follow_activity_factory(attrs \\ %{}) do
|
||||||
data: data,
|
data: data,
|
||||||
actor: follower.ap_id
|
actor: follower.ap_id
|
||||||
}
|
}
|
||||||
|
|> Map.merge(attrs)
|
||||||
end
|
end
|
||||||
|
|
||||||
def report_activity_factory(attrs \\ %{}) do
|
def report_activity_factory(attrs \\ %{}) do
|
||||||
|
|
Loading…
Reference in a new issue