mirror of
https://git.youjo.love/youjo/youjo-be.git
synced 2024-11-20 13:59:55 +01:00
schedule expired oauth tokens deletion with Oban
This commit is contained in:
parent
c8c17d9c63
commit
3ce658b930
13 changed files with 76 additions and 80 deletions
|
@ -530,6 +530,7 @@ config :pleroma, Oban,
|
||||||
log: false,
|
log: false,
|
||||||
queues: [
|
queues: [
|
||||||
activity_expiration: 10,
|
activity_expiration: 10,
|
||||||
|
oauth_token_expiration: 1,
|
||||||
federator_incoming: 50,
|
federator_incoming: 50,
|
||||||
federator_outgoing: 50,
|
federator_outgoing: 50,
|
||||||
web_push: 50,
|
web_push: 50,
|
||||||
|
@ -543,7 +544,6 @@ config :pleroma, Oban,
|
||||||
],
|
],
|
||||||
plugins: [Oban.Plugins.Pruner],
|
plugins: [Oban.Plugins.Pruner],
|
||||||
crontab: [
|
crontab: [
|
||||||
{"0 0 * * *", Pleroma.Workers.Cron.ClearOauthTokenWorker},
|
|
||||||
{"* * * * *", Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker},
|
{"* * * * *", Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker},
|
||||||
{"0 0 * * 0", Pleroma.Workers.Cron.DigestEmailsWorker},
|
{"0 0 * * 0", Pleroma.Workers.Cron.DigestEmailsWorker},
|
||||||
{"0 0 * * *", Pleroma.Workers.Cron.NewUsersDigestWorker}
|
{"0 0 * * *", Pleroma.Workers.Cron.NewUsersDigestWorker}
|
||||||
|
|
|
@ -2290,7 +2290,6 @@ config :pleroma, :config_description, [
|
||||||
type: {:list, :tuple},
|
type: {:list, :tuple},
|
||||||
description: "Settings for cron background jobs",
|
description: "Settings for cron background jobs",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
{"0 0 * * *", Pleroma.Workers.Cron.ClearOauthTokenWorker},
|
|
||||||
{"* * * * *", Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker},
|
{"* * * * *", Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker},
|
||||||
{"0 0 * * 0", Pleroma.Workers.Cron.DigestEmailsWorker},
|
{"0 0 * * 0", Pleroma.Workers.Cron.DigestEmailsWorker},
|
||||||
{"0 0 * * *", Pleroma.Workers.Cron.NewUsersDigestWorker}
|
{"0 0 * * *", Pleroma.Workers.Cron.NewUsersDigestWorker}
|
||||||
|
|
|
@ -50,7 +50,7 @@ defmodule Pleroma.Web.OAuth.Token do
|
||||||
true <- auth.app_id == app.id do
|
true <- auth.app_id == app.id do
|
||||||
user = if auth.user_id, do: User.get_cached_by_id(auth.user_id), else: %User{}
|
user = if auth.user_id, do: User.get_cached_by_id(auth.user_id), else: %User{}
|
||||||
|
|
||||||
create_token(
|
create(
|
||||||
app,
|
app,
|
||||||
user,
|
user,
|
||||||
%{scopes: auth.scopes}
|
%{scopes: auth.scopes}
|
||||||
|
@ -83,8 +83,21 @@ defmodule Pleroma.Web.OAuth.Token do
|
||||||
|> validate_required([:valid_until])
|
|> validate_required([:valid_until])
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec create_token(App.t(), User.t(), map()) :: {:ok, Token} | {:error, Changeset.t()}
|
@spec create(App.t(), User.t(), map()) :: {:ok, Token} | {:error, Changeset.t()}
|
||||||
def create_token(%App{} = app, %User{} = user, attrs \\ %{}) do
|
def create(%App{} = app, %User{} = user, attrs \\ %{}) do
|
||||||
|
with {:ok, token} <- do_create(app, user, attrs) do
|
||||||
|
if Pleroma.Config.get([:oauth2, :clean_expired_tokens]) do
|
||||||
|
Pleroma.Workers.PurgeExpiredOAuthToken.enqueue(%{
|
||||||
|
token_id: token.id,
|
||||||
|
valid_until: DateTime.from_naive!(token.valid_until, "Etc/UTC")
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
{:ok, token}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp do_create(app, user, attrs) do
|
||||||
%__MODULE__{user_id: user.id, app_id: app.id}
|
%__MODULE__{user_id: user.id, app_id: app.id}
|
||||||
|> cast(%{scopes: attrs[:scopes] || app.scopes}, [:scopes])
|
|> cast(%{scopes: attrs[:scopes] || app.scopes}, [:scopes])
|
||||||
|> validate_required([:scopes, :app_id])
|
|> validate_required([:scopes, :app_id])
|
||||||
|
@ -105,11 +118,6 @@ defmodule Pleroma.Web.OAuth.Token do
|
||||||
|> Repo.delete_all()
|
|> Repo.delete_all()
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete_expired_tokens do
|
|
||||||
Query.get_expired_tokens()
|
|
||||||
|> Repo.delete_all()
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_user_tokens(%User{id: user_id}) do
|
def get_user_tokens(%User{id: user_id}) do
|
||||||
Query.get_by_user(user_id)
|
Query.get_by_user(user_id)
|
||||||
|> Query.preload([:app])
|
|> Query.preload([:app])
|
||||||
|
|
|
@ -12,7 +12,6 @@ defmodule Pleroma.Web.OAuth.Token.CleanWorker do
|
||||||
@one_day 86_400_000
|
@one_day 86_400_000
|
||||||
|
|
||||||
alias Pleroma.MFA
|
alias Pleroma.MFA
|
||||||
alias Pleroma.Web.OAuth
|
|
||||||
alias Pleroma.Workers.BackgroundWorker
|
alias Pleroma.Workers.BackgroundWorker
|
||||||
|
|
||||||
def start_link(_), do: GenServer.start_link(__MODULE__, %{})
|
def start_link(_), do: GenServer.start_link(__MODULE__, %{})
|
||||||
|
@ -32,7 +31,6 @@ defmodule Pleroma.Web.OAuth.Token.CleanWorker do
|
||||||
end
|
end
|
||||||
|
|
||||||
def perform(:clean) do
|
def perform(:clean) do
|
||||||
OAuth.Token.delete_expired_tokens()
|
|
||||||
MFA.Token.delete_expired_tokens()
|
MFA.Token.delete_expired_tokens()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -33,12 +33,6 @@ defmodule Pleroma.Web.OAuth.Token.Query do
|
||||||
from(q in query, where: q.id == ^id)
|
from(q in query, where: q.id == ^id)
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec get_expired_tokens(query, DateTime.t() | nil) :: query
|
|
||||||
def get_expired_tokens(query \\ Token, date \\ nil) do
|
|
||||||
expired_date = date || Timex.now()
|
|
||||||
from(q in query, where: fragment("?", q.valid_until) < ^expired_date)
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec get_by_user(query, String.t()) :: query
|
@spec get_by_user(query, String.t()) :: query
|
||||||
def get_by_user(query \\ Token, user_id) do
|
def get_by_user(query \\ Token, user_id) do
|
||||||
from(q in query, where: q.user_id == ^user_id)
|
from(q in query, where: q.user_id == ^user_id)
|
||||||
|
|
|
@ -46,7 +46,7 @@ defmodule Pleroma.Web.OAuth.Token.Strategy.RefreshToken do
|
||||||
defp create_access_token({:error, error}, _), do: {:error, error}
|
defp create_access_token({:error, error}, _), do: {:error, error}
|
||||||
|
|
||||||
defp create_access_token({:ok, token}, %{app: app, user: user} = token_params) do
|
defp create_access_token({:ok, token}, %{app: app, user: user} = token_params) do
|
||||||
Token.create_token(app, user, add_refresh_token(token_params, token.refresh_token))
|
Token.create(app, user, add_refresh_token(token_params, token.refresh_token))
|
||||||
end
|
end
|
||||||
|
|
||||||
defp add_refresh_token(params, token) do
|
defp add_refresh_token(params, token) do
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
defmodule Pleroma.Workers.Cron.ClearOauthTokenWorker do
|
|
||||||
@moduledoc """
|
|
||||||
The worker to cleanup expired oAuth tokens.
|
|
||||||
"""
|
|
||||||
|
|
||||||
use Oban.Worker, queue: "background"
|
|
||||||
|
|
||||||
alias Pleroma.Config
|
|
||||||
alias Pleroma.Web.OAuth.Token
|
|
||||||
|
|
||||||
@impl Oban.Worker
|
|
||||||
def perform(_job) do
|
|
||||||
if Config.get([:oauth2, :clean_expired_tokens], false) do
|
|
||||||
Token.delete_expired_tokens()
|
|
||||||
end
|
|
||||||
|
|
||||||
:ok
|
|
||||||
end
|
|
||||||
end
|
|
28
lib/pleroma/workers/purge_expired_token.ex
Normal file
28
lib/pleroma/workers/purge_expired_token.ex
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Workers.PurgeExpiredOAuthToken do
|
||||||
|
@moduledoc """
|
||||||
|
Worker which purges expired OAuth tokens
|
||||||
|
"""
|
||||||
|
|
||||||
|
use Oban.Worker, queue: :oauth_token_expiration, max_attempts: 1
|
||||||
|
|
||||||
|
@spec enqueue(%{token_id: integer(), valid_until: DateTime.t()}) ::
|
||||||
|
{:ok, Oban.Job.t()} | {:error, Ecto.Changeset.t()}
|
||||||
|
def enqueue(args) do
|
||||||
|
{scheduled_at, args} = Map.pop(args, :valid_until)
|
||||||
|
|
||||||
|
args
|
||||||
|
|> __MODULE__.new(scheduled_at: scheduled_at)
|
||||||
|
|> Oban.insert()
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def perform(%Oban.Job{args: %{"token_id" => id}}) do
|
||||||
|
Pleroma.Web.OAuth.Token
|
||||||
|
|> Pleroma.Repo.get(id)
|
||||||
|
|> Pleroma.Repo.delete()
|
||||||
|
end
|
||||||
|
end
|
|
@ -16,7 +16,7 @@ defmodule Pleroma.Plugs.OAuthPlugTest do
|
||||||
|
|
||||||
setup %{conn: conn} do
|
setup %{conn: conn} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
{:ok, %{token: token}} = Pleroma.Web.OAuth.Token.create_token(insert(:oauth_app), user)
|
{:ok, %{token: token}} = Pleroma.Web.OAuth.Token.create(insert(:oauth_app), user)
|
||||||
%{user: user, token: token, conn: conn}
|
%{user: user, token: token, conn: conn}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -69,17 +69,4 @@ defmodule Pleroma.Web.OAuth.TokenTest do
|
||||||
|
|
||||||
assert tokens == 2
|
assert tokens == 2
|
||||||
end
|
end
|
||||||
|
|
||||||
test "deletes expired tokens" do
|
|
||||||
insert(:oauth_token, valid_until: Timex.shift(Timex.now(), days: -3))
|
|
||||||
insert(:oauth_token, valid_until: Timex.shift(Timex.now(), days: -3))
|
|
||||||
t3 = insert(:oauth_token)
|
|
||||||
t4 = insert(:oauth_token, valid_until: Timex.shift(Timex.now(), minutes: 10))
|
|
||||||
{tokens, _} = Token.delete_expired_tokens()
|
|
||||||
assert tokens == 2
|
|
||||||
available_tokens = Pleroma.Repo.all(Token)
|
|
||||||
|
|
||||||
token_ids = available_tokens |> Enum.map(& &1.id)
|
|
||||||
assert token_ids == [t3.id, t4.id]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -37,7 +37,7 @@ defmodule Pleroma.Web.TwitterAPI.PasswordControllerTest do
|
||||||
test "it returns HTTP 200", %{conn: conn} do
|
test "it returns HTTP 200", %{conn: conn} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
{:ok, token} = PasswordResetToken.create_token(user)
|
{:ok, token} = PasswordResetToken.create_token(user)
|
||||||
{:ok, _access_token} = Token.create_token(insert(:oauth_app), user, %{})
|
{:ok, _access_token} = Token.create(insert(:oauth_app), user, %{})
|
||||||
|
|
||||||
params = %{
|
params = %{
|
||||||
"password" => "test",
|
"password" => "test",
|
||||||
|
@ -62,7 +62,7 @@ defmodule Pleroma.Web.TwitterAPI.PasswordControllerTest do
|
||||||
user = insert(:user, password_reset_pending: true)
|
user = insert(:user, password_reset_pending: true)
|
||||||
|
|
||||||
{:ok, token} = PasswordResetToken.create_token(user)
|
{:ok, token} = PasswordResetToken.create_token(user)
|
||||||
{:ok, _access_token} = Token.create_token(insert(:oauth_app), user, %{})
|
{:ok, _access_token} = Token.create(insert(:oauth_app), user, %{})
|
||||||
|
|
||||||
params = %{
|
params = %{
|
||||||
"password" => "test",
|
"password" => "test",
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
defmodule Pleroma.Workers.Cron.ClearOauthTokenWorkerTest do
|
|
||||||
use Pleroma.DataCase
|
|
||||||
|
|
||||||
import Pleroma.Factory
|
|
||||||
alias Pleroma.Workers.Cron.ClearOauthTokenWorker
|
|
||||||
|
|
||||||
setup do: clear_config([:oauth2, :clean_expired_tokens])
|
|
||||||
|
|
||||||
test "deletes expired tokens" do
|
|
||||||
insert(:oauth_token,
|
|
||||||
valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), -60 * 10)
|
|
||||||
)
|
|
||||||
|
|
||||||
Pleroma.Config.put([:oauth2, :clean_expired_tokens], true)
|
|
||||||
ClearOauthTokenWorker.perform(%Oban.Job{})
|
|
||||||
assert Pleroma.Repo.all(Pleroma.Web.OAuth.Token) == []
|
|
||||||
end
|
|
||||||
end
|
|
27
test/workers/purge_expired_oauth_token_test.exs
Normal file
27
test/workers/purge_expired_oauth_token_test.exs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Workers.PurgeExpiredOAuthTokenTest do
|
||||||
|
use Pleroma.DataCase, async: true
|
||||||
|
use Oban.Testing, repo: Pleroma.Repo
|
||||||
|
|
||||||
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
setup do: clear_config([:oauth2, :clean_expired_tokens], true)
|
||||||
|
|
||||||
|
test "purges expired token" do
|
||||||
|
user = insert(:user)
|
||||||
|
app = insert(:oauth_app)
|
||||||
|
|
||||||
|
{:ok, %{id: id}} = Pleroma.Web.OAuth.Token.create(app, user)
|
||||||
|
|
||||||
|
assert_enqueued(
|
||||||
|
worker: Pleroma.Workers.PurgeExpiredOAuthToken,
|
||||||
|
args: %{token_id: id}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert {:ok, %{id: ^id}} =
|
||||||
|
perform_job(Pleroma.Workers.PurgeExpiredOAuthToken, %{token_id: id})
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue