Add migration cooldown period

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2022-09-28 22:56:38 +02:00
parent 54daefaecc
commit c6fddd6e0a
9 changed files with 100 additions and 3 deletions

View file

@ -262,7 +262,8 @@
max_endorsed_users: 20,
birthday_required: false,
birthday_min_age: 0,
max_media_attachments: 1_000
max_media_attachments: 1_000,
migration_cooldown_period: 30
config :pleroma, :welcome,
direct_message: [

View file

@ -1015,6 +1015,13 @@
description:
"Minimum required age (in days) for users to create account. Only used if birthday is required.",
suggestions: [6570]
},
%{
key: :migration_cooldown_period,
type: :integer,
description:
"Number of days for which users won't be able to migrate account again after successful migration.",
suggestions: [30]
}
]
},

View file

@ -160,6 +160,7 @@ defmodule Pleroma.User do
field(:show_birthday, :boolean, default: false)
field(:location, :string)
field(:language, :string)
field(:last_move_at, :naive_datetime)
embeds_one(
:notification_settings,
@ -2707,4 +2708,10 @@ def get_friends_birthdays_query(%User{} = user, day, month) do
birthday_month: month
})
end
def update_last_move_at(%__MODULE__{local: true} = user) do
user
|> cast(%{last_move_at: NaiveDateTime.utc_now()}, [:last_move_at])
|> update_and_set_cache()
end
end

View file

@ -450,6 +450,8 @@ def move(%User{} = origin, %User{} = target, local \\ true) do
"target_id" => target.id
})
User.update_last_move_at(origin)
{:ok, activity}
else
false -> {:error, "Target account must have the origin in `alsoKnownAs`"}

View file

@ -229,7 +229,8 @@ def move_account_operation do
}),
400 => Operation.response("Error", "application/json", ApiError),
403 => Operation.response("Error", "application/json", ApiError),
404 => Operation.response("Error", "application/json", ApiError)
404 => Operation.response("Error", "application/json", ApiError),
429 => Operation.response("Error", "application/json", ApiError)
}
}
end

View file

@ -51,7 +51,8 @@ def render("show.json", _) do
post_formats: Config.get([:instance, :allowed_post_formats]),
privileged_staff: Config.get([:instance, :privileged_staff]),
birthday_required: Config.get([:instance, :birthday_required]),
birthday_min_age: Config.get([:instance, :birthday_min_age])
birthday_min_age: Config.get([:instance, :birthday_min_age]),
migration_cooldown_period: Config.get([:instance, :migration_cooldown_period])
},
stats: %{mau: Pleroma.User.active_user_count()},
vapid_public_key: Keyword.get(Pleroma.Web.Push.vapid_config(), :public_key),

View file

@ -259,6 +259,7 @@ def move_account(%{assigns: %{user: user}, body_params: body_params} = conn, %{}
case CommonAPI.Utils.confirm_current_password(user, body_params.password) do
{:ok, user} ->
with {:ok, target_user} <- find_or_fetch_user_by_nickname(body_params.target_account),
{:period, false} <- {:period, within_cooldown?(user)},
{:ok, _user} <- ActivityPub.move(user, target_user) do
json(conn, %{status: "success"})
else
@ -267,6 +268,11 @@ def move_account(%{assigns: %{user: user}, body_params: body_params} = conn, %{}
|> put_status(404)
|> json(%{error: "Target account not found."})
{:period, true} ->
conn
|> put_status(429)
|> json(%{error: "You are within cooldown period."})
{:error, error} ->
json(conn, %{error: error})
end
@ -276,6 +282,19 @@ def move_account(%{assigns: %{user: user}, body_params: body_params} = conn, %{}
end
end
defp within_cooldown?(%{last_move_at: nil}), do: false
defp within_cooldown?(user) do
cooldown_period =
Pleroma.Config.get([:instance, :migration_cooldown_period], 0) * 60 * 60 * 24
now = NaiveDateTime.utc_now()
difference = NaiveDateTime.diff(now, user.last_move_at)
difference < cooldown_period
end
def add_alias(%{assigns: %{user: user}, body_params: body_params} = conn, _) do
with {:ok, alias_user} <- find_user_by_nickname(body_params.alias),
{:ok, _user} <- user |> User.add_alias(alias_user) do

View file

@ -0,0 +1,13 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Repo.Migrations.AddLastMoveAtToUsers do
use Ecto.Migration
def change do
alter table(:users) do
add(:last_move_at, :naive_datetime)
end
end
end

View file

@ -6,9 +6,11 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
use Pleroma.Web.ConnCase
use Oban.Testing, repo: Pleroma.Repo
alias Pleroma.Repo
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
import Ecto.Changeset
import Pleroma.Factory
import Mock
@ -838,6 +840,50 @@ test "prefix nickname by @ should work", %{
refute User.following?(follower, user)
assert User.following?(follower, target_user)
end
test "do not allow to migrate account within cooldown period", %{conn: conn, user: user} do
user
|> cast(
%{last_move_at: NaiveDateTime.utc_now() |> NaiveDateTime.add(-1 * 24 * 60 * 60, :second)},
[:last_move_at]
)
|> Repo.update()
target_user = insert(:user, also_known_as: [user.ap_id])
target_nick = target_user |> User.full_nickname()
conn =
conn
|> put_req_header("content-type", "multipart/form-data")
|> post("/api/pleroma/move_account", %{password: "test", target_account: target_nick})
assert json_response_and_validate_schema(conn, 429) == %{
"error" => "You are within cooldown period."
}
end
test "allow to migrate account after cooldown period", %{conn: conn, user: user} do
user
|> cast(
%{
last_move_at: NaiveDateTime.utc_now() |> NaiveDateTime.add(-31 * 24 * 60 * 60, :second)
},
[:last_move_at]
)
|> Repo.update()
target_user = insert(:user, also_known_as: [user.ap_id])
target_nick = target_user |> User.full_nickname()
conn =
conn
|> put_req_header("content-type", "multipart/form-data")
|> post("/api/pleroma/move_account", %{password: "test", target_account: target_nick})
assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"}
end
end
describe "GET /api/pleroma/aliases" do