From a06e471db7d731b148184d17746cf75edd31f696 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Fri, 6 Nov 2026 18:59:56 +0200 Subject: [PATCH 01/15] Attempt at adding a last active field to tokens --- lib/pleroma/web/o_auth/token.ex | 9 +++++++++ lib/pleroma/web/o_auth/token_view.ex | 1 + lib/pleroma/web/plugs/o_auth_plug.ex | 1 + .../20170906152508_create_o_auth_token.exs | 1 + .../migrations/202611061856_add_token_activity.exs | 13 +++++++++++++ test/pleroma/web/o_auth/token_controller_test.exs | 2 +- 6 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 priv/repo/migrations/202611061856_add_token_activity.exs diff --git a/lib/pleroma/web/o_auth/token.ex b/lib/pleroma/web/o_auth/token.ex index d96425094..28f1f2dee 100644 --- a/lib/pleroma/web/o_auth/token.ex +++ b/lib/pleroma/web/o_auth/token.ex @@ -21,6 +21,7 @@ defmodule Pleroma.Web.OAuth.Token do field(:refresh_token, :string) field(:scopes, {:array, :string}, default: []) field(:valid_until, :naive_datetime_usec) + field(:last_active, :naive_datetime_usec) belongs_to(:user, User, type: FlakeId.Ecto.CompatType) belongs_to(:app, App) @@ -96,6 +97,14 @@ defmodule Pleroma.Web.OAuth.Token do |> validate_required([:valid_until]) end + defp update_activity() do + last_active = NaiveDateTime.utc_now() + + changeset + |> change(%{last_active: last_active}) + |> validate_required([:last_active]) + end + @spec create(App.t(), User.t(), map()) :: {:ok, Token.t()} | {:error, Ecto.Changeset.t()} def create(%App{} = app, %User{} = user, attrs \\ %{}) do with {:ok, token} <- do_create(app, user, attrs) do diff --git a/lib/pleroma/web/o_auth/token_view.ex b/lib/pleroma/web/o_auth/token_view.ex index ee54280ec..09e0a18bc 100644 --- a/lib/pleroma/web/o_auth/token_view.ex +++ b/lib/pleroma/web/o_auth/token_view.ex @@ -17,6 +17,7 @@ defmodule Pleroma.Web.OAuth.TokenView do %{ id: token_entry.id, valid_until: token_entry.valid_until, + last_active: token_entry.last_active, app_name: token_entry.app.client_name, scopes: token_entry.scopes, is_current_token: token_entry.id == current_token.id diff --git a/lib/pleroma/web/plugs/o_auth_plug.ex b/lib/pleroma/web/plugs/o_auth_plug.ex index b59ac9d3e..6f366d3cb 100644 --- a/lib/pleroma/web/plugs/o_auth_plug.ex +++ b/lib/pleroma/web/plugs/o_auth_plug.ex @@ -24,6 +24,7 @@ defmodule Pleroma.Web.Plugs.OAuthPlug do with {:ok, token_str} <- fetch_token_str(conn) do with {:ok, user, user_token} <- fetch_user_and_token(token_str), false <- Token.expired?(user_token) do + Token.update_activity() conn |> assign(:token, user_token) |> assign(:user, user) diff --git a/priv/repo/migrations/20170906152508_create_o_auth_token.exs b/priv/repo/migrations/20170906152508_create_o_auth_token.exs index 14ce55b5a..5b662a5a3 100644 --- a/priv/repo/migrations/20170906152508_create_o_auth_token.exs +++ b/priv/repo/migrations/20170906152508_create_o_auth_token.exs @@ -12,6 +12,7 @@ defmodule Pleroma.Repo.Migrations.CreateOAuthToken do add(:token, :string) add(:refresh_token, :string) add(:valid_until, :naive_datetime_usec) + add(:last_active, :naive_datetime_usec) timestamps() end diff --git a/priv/repo/migrations/202611061856_add_token_activity.exs b/priv/repo/migrations/202611061856_add_token_activity.exs new file mode 100644 index 000000000..98f4b0184 --- /dev/null +++ b/priv/repo/migrations/202611061856_add_token_activity.exs @@ -0,0 +1,13 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Repo.Migrations.AddTokenActivity do + use Ecto.Migration + + def change do + alter table(:oauth_tokens) do + add_if_not_exists(:last_active, :naive_datetime_usec) + end + end +end diff --git a/test/pleroma/web/o_auth/token_controller_test.exs b/test/pleroma/web/o_auth/token_controller_test.exs index e41584cd0..75167c346 100644 --- a/test/pleroma/web/o_auth/token_controller_test.exs +++ b/test/pleroma/web/o_auth/token_controller_test.exs @@ -63,7 +63,7 @@ defmodule Pleroma.Web.OAuth.TokenControllerTest do |> Map.keys() assert Enum.sort(keys) == - Enum.sort(["id", "app_name", "valid_until", "scopes", "is_current_token"]) + Enum.sort(["id", "app_name", "valid_until", "scopes", "is_current_token", "last_active"]) end test "marks which token is being used for the request" do From a20b22f5a978509a2d264b1bedfa1dcb689d4ac0 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Fri, 6 Nov 2026 19:01:09 +0200 Subject: [PATCH 02/15] changelog --- changelog.d/token-activity.add | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/token-activity.add diff --git a/changelog.d/token-activity.add b/changelog.d/token-activity.add new file mode 100644 index 000000000..258f283eb --- /dev/null +++ b/changelog.d/token-activity.add @@ -0,0 +1 @@ +Added "last active at" field to OAuth token management From ae6e32c63516843e06bfba1412db72b8c0b7bd0f Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Fri, 6 Nov 2026 19:10:57 +0200 Subject: [PATCH 03/15] lint --- test/pleroma/web/o_auth/token_controller_test.exs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/pleroma/web/o_auth/token_controller_test.exs b/test/pleroma/web/o_auth/token_controller_test.exs index 75167c346..6b2b0aeec 100644 --- a/test/pleroma/web/o_auth/token_controller_test.exs +++ b/test/pleroma/web/o_auth/token_controller_test.exs @@ -63,7 +63,14 @@ defmodule Pleroma.Web.OAuth.TokenControllerTest do |> Map.keys() assert Enum.sort(keys) == - Enum.sort(["id", "app_name", "valid_until", "scopes", "is_current_token", "last_active"]) + Enum.sort([ + "id", + "app_name", + "valid_until", + "scopes", + "is_current_token", + "last_active" + ]) end test "marks which token is being used for the request" do From ff89b67d551663c82ae9c5e8cd603e89adc3d315 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Fri, 6 Nov 2026 19:16:15 +0200 Subject: [PATCH 04/15] lint --- lib/pleroma/web/plugs/o_auth_plug.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pleroma/web/plugs/o_auth_plug.ex b/lib/pleroma/web/plugs/o_auth_plug.ex index 6f366d3cb..e3035df0c 100644 --- a/lib/pleroma/web/plugs/o_auth_plug.ex +++ b/lib/pleroma/web/plugs/o_auth_plug.ex @@ -25,6 +25,7 @@ defmodule Pleroma.Web.Plugs.OAuthPlug do with {:ok, user, user_token} <- fetch_user_and_token(token_str), false <- Token.expired?(user_token) do Token.update_activity() + conn |> assign(:token, user_token) |> assign(:user, user) From 74ab1769d1280078591535514b579621f9e765a3 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Fri, 6 Nov 2026 19:26:24 +0200 Subject: [PATCH 05/15] lint? --- lib/pleroma/web/o_auth/token.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/o_auth/token.ex b/lib/pleroma/web/o_auth/token.ex index 28f1f2dee..d076d4a83 100644 --- a/lib/pleroma/web/o_auth/token.ex +++ b/lib/pleroma/web/o_auth/token.ex @@ -97,7 +97,7 @@ defmodule Pleroma.Web.OAuth.Token do |> validate_required([:valid_until]) end - defp update_activity() do + defp update_activity do last_active = NaiveDateTime.utc_now() changeset From 226135e2e1e2d24337f99e88a9e8452b129ecfa4 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 9 Nov 2026 16:23:19 +0200 Subject: [PATCH 06/15] i'm learning --- lib/pleroma/web/o_auth/token.ex | 8 +++++++- lib/pleroma/web/plugs/o_auth_plug.ex | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/web/o_auth/token.ex b/lib/pleroma/web/o_auth/token.ex index d076d4a83..0c53f3938 100644 --- a/lib/pleroma/web/o_auth/token.ex +++ b/lib/pleroma/web/o_auth/token.ex @@ -97,12 +97,18 @@ defmodule Pleroma.Web.OAuth.Token do |> validate_required([:valid_until]) end - defp update_activity do + @spec update_activity(Token.t()) :: {:ok, Token.t()} | {:error, Ecto.Changeset.t()} + def update_activity(token) do last_active = NaiveDateTime.utc_now() + changeset = Ecto.Changeset.change(token) + changeset |> change(%{last_active: last_active}) |> validate_required([:last_active]) + |> Repo.insert() + + {: ok, token} end @spec create(App.t(), User.t(), map()) :: {:ok, Token.t()} | {:error, Ecto.Changeset.t()} diff --git a/lib/pleroma/web/plugs/o_auth_plug.ex b/lib/pleroma/web/plugs/o_auth_plug.ex index e3035df0c..4246a9c75 100644 --- a/lib/pleroma/web/plugs/o_auth_plug.ex +++ b/lib/pleroma/web/plugs/o_auth_plug.ex @@ -24,7 +24,7 @@ defmodule Pleroma.Web.Plugs.OAuthPlug do with {:ok, token_str} <- fetch_token_str(conn) do with {:ok, user, user_token} <- fetch_user_and_token(token_str), false <- Token.expired?(user_token) do - Token.update_activity() + Token.update_activity(user_token) conn |> assign(:token, user_token) From 02d6262a08d1829c00f04aeba96c3d9e17b67a33 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 9 Nov 2026 16:29:34 +0200 Subject: [PATCH 07/15] oops --- lib/pleroma/web/o_auth/token.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/o_auth/token.ex b/lib/pleroma/web/o_auth/token.ex index 0c53f3938..1457a7997 100644 --- a/lib/pleroma/web/o_auth/token.ex +++ b/lib/pleroma/web/o_auth/token.ex @@ -108,7 +108,7 @@ defmodule Pleroma.Web.OAuth.Token do |> validate_required([:last_active]) |> Repo.insert() - {: ok, token} + {:ok, token} end @spec create(App.t(), User.t(), map()) :: {:ok, Token.t()} | {:error, Ecto.Changeset.t()} From 4baafe313dcb24a3807c5c634e308fbab63153f4 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 9 Nov 2026 16:51:09 +0200 Subject: [PATCH 08/15] oc fixes --- lib/pleroma/web/o_auth/token.ex | 13 +++---------- .../20170906152508_create_o_auth_token.exs | 1 - ...ty.exs => 20261106185600_add_token_activity.exs} | 0 3 files changed, 3 insertions(+), 11 deletions(-) rename priv/repo/migrations/{202611061856_add_token_activity.exs => 20261106185600_add_token_activity.exs} (100%) diff --git a/lib/pleroma/web/o_auth/token.ex b/lib/pleroma/web/o_auth/token.ex index 1457a7997..50dd399ca 100644 --- a/lib/pleroma/web/o_auth/token.ex +++ b/lib/pleroma/web/o_auth/token.ex @@ -99,16 +99,9 @@ defmodule Pleroma.Web.OAuth.Token do @spec update_activity(Token.t()) :: {:ok, Token.t()} | {:error, Ecto.Changeset.t()} def update_activity(token) do - last_active = NaiveDateTime.utc_now() - - changeset = Ecto.Changeset.change(token) - - changeset - |> change(%{last_active: last_active}) - |> validate_required([:last_active]) - |> Repo.insert() - - {:ok, token} + token + |> Ecto.Changeset.change(last_active: NaiveDateTime.utc_now()) + |> Repo.update() end @spec create(App.t(), User.t(), map()) :: {:ok, Token.t()} | {:error, Ecto.Changeset.t()} diff --git a/priv/repo/migrations/20170906152508_create_o_auth_token.exs b/priv/repo/migrations/20170906152508_create_o_auth_token.exs index 5b662a5a3..14ce55b5a 100644 --- a/priv/repo/migrations/20170906152508_create_o_auth_token.exs +++ b/priv/repo/migrations/20170906152508_create_o_auth_token.exs @@ -12,7 +12,6 @@ defmodule Pleroma.Repo.Migrations.CreateOAuthToken do add(:token, :string) add(:refresh_token, :string) add(:valid_until, :naive_datetime_usec) - add(:last_active, :naive_datetime_usec) timestamps() end diff --git a/priv/repo/migrations/202611061856_add_token_activity.exs b/priv/repo/migrations/20261106185600_add_token_activity.exs similarity index 100% rename from priv/repo/migrations/202611061856_add_token_activity.exs rename to priv/repo/migrations/20261106185600_add_token_activity.exs From 278f66a6830c6a9763aa0fb76ed9e73d2076f37b Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 9 Nov 2026 19:15:02 +0200 Subject: [PATCH 09/15] throttle --- lib/pleroma/web/plugs/o_auth_plug.ex | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/plugs/o_auth_plug.ex b/lib/pleroma/web/plugs/o_auth_plug.ex index 4246a9c75..9d402182a 100644 --- a/lib/pleroma/web/plugs/o_auth_plug.ex +++ b/lib/pleroma/web/plugs/o_auth_plug.ex @@ -16,6 +16,8 @@ defmodule Pleroma.Web.Plugs.OAuthPlug do @realm_reg Regex.compile!("Bearer\:?\s+(.*)$", "i") + @update_interval :timer.hours(1) + def init(options), do: options def call(%{assigns: %{user: %User{}}} = conn, _), do: conn @@ -24,17 +26,29 @@ defmodule Pleroma.Web.Plugs.OAuthPlug do with {:ok, token_str} <- fetch_token_str(conn) do with {:ok, user, user_token} <- fetch_user_and_token(token_str), false <- Token.expired?(user_token) do - Token.update_activity(user_token) + with true <- needs_update?(token), + {:ok, updated_token} <- Token.update_activity(user_token) do + + assign(conn, :token, updated_token) + else + assign(conn, :token, user_token) + end conn - |> assign(:token, user_token) |> assign(:user, user) else _ -> with {:ok, app, app_token} <- fetch_app_and_token(token_str), false <- Token.expired?(app_token) do + with true <- needs_update?(token), + {:ok, updated_token} <- Token.update_activity(app_token) do + + assign(conn, :token, updated_token) + else + assign(conn, :token, app_token) + end + conn - |> assign(:token, app_token) |> assign(:app, app) else _ -> conn @@ -45,6 +59,12 @@ defmodule Pleroma.Web.Plugs.OAuthPlug do end end + defp needs_update?(Token{last_active: nil}), do: true + + defp needs_update?(Token{last_active: last_active}) do + NaiveDateTime.diff(NaiveDateTime.utc_now(), last_active, :millisecond) >= @update_interval + end + # Gets user by token # @spec fetch_user_and_token(String.t()) :: {:ok, User.t(), Token.t()} | nil From bc92e97175a1d8654a5fbafc7403373f0864e219 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 9 Nov 2026 19:25:05 +0200 Subject: [PATCH 10/15] oops --- lib/pleroma/web/plugs/o_auth_plug.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/web/plugs/o_auth_plug.ex b/lib/pleroma/web/plugs/o_auth_plug.ex index 9d402182a..8688095ca 100644 --- a/lib/pleroma/web/plugs/o_auth_plug.ex +++ b/lib/pleroma/web/plugs/o_auth_plug.ex @@ -59,9 +59,9 @@ defmodule Pleroma.Web.Plugs.OAuthPlug do end end - defp needs_update?(Token{last_active: nil}), do: true + defp needs_update?(%Token{last_active: nil}), do: true - defp needs_update?(Token{last_active: last_active}) do + defp needs_update?(%Token{last_active: last_active}) do NaiveDateTime.diff(NaiveDateTime.utc_now(), last_active, :millisecond) >= @update_interval end From a8665e0ba1c3ca3eed311f485999dd0812807646 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 9 Nov 2026 19:35:18 +0200 Subject: [PATCH 11/15] lint --- lib/pleroma/web/plugs/o_auth_plug.ex | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/pleroma/web/plugs/o_auth_plug.ex b/lib/pleroma/web/plugs/o_auth_plug.ex index 8688095ca..be5b4ded6 100644 --- a/lib/pleroma/web/plugs/o_auth_plug.ex +++ b/lib/pleroma/web/plugs/o_auth_plug.ex @@ -27,8 +27,7 @@ defmodule Pleroma.Web.Plugs.OAuthPlug do with {:ok, user, user_token} <- fetch_user_and_token(token_str), false <- Token.expired?(user_token) do with true <- needs_update?(token), - {:ok, updated_token} <- Token.update_activity(user_token) do - + {:ok, updated_token} <- Token.update_activity(user_token) do assign(conn, :token, updated_token) else assign(conn, :token, user_token) @@ -41,8 +40,7 @@ defmodule Pleroma.Web.Plugs.OAuthPlug do with {:ok, app, app_token} <- fetch_app_and_token(token_str), false <- Token.expired?(app_token) do with true <- needs_update?(token), - {:ok, updated_token} <- Token.update_activity(app_token) do - + {:ok, updated_token} <- Token.update_activity(app_token) do assign(conn, :token, updated_token) else assign(conn, :token, app_token) From 50593392d95924a723ca07986501654534a12957 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 9 Nov 2026 19:55:49 +0200 Subject: [PATCH 12/15] else --- lib/pleroma/web/plugs/o_auth_plug.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/plugs/o_auth_plug.ex b/lib/pleroma/web/plugs/o_auth_plug.ex index be5b4ded6..038140df7 100644 --- a/lib/pleroma/web/plugs/o_auth_plug.ex +++ b/lib/pleroma/web/plugs/o_auth_plug.ex @@ -30,7 +30,7 @@ defmodule Pleroma.Web.Plugs.OAuthPlug do {:ok, updated_token} <- Token.update_activity(user_token) do assign(conn, :token, updated_token) else - assign(conn, :token, user_token) + _ -> assign(conn, :token, user_token) end conn @@ -39,11 +39,11 @@ defmodule Pleroma.Web.Plugs.OAuthPlug do _ -> with {:ok, app, app_token} <- fetch_app_and_token(token_str), false <- Token.expired?(app_token) do - with true <- needs_update?(token), + with true <- needs_update?(app_token), {:ok, updated_token} <- Token.update_activity(app_token) do assign(conn, :token, updated_token) else - assign(conn, :token, app_token) + _ -> assign(conn, :token, app_token) end conn From b8669dd01f8f2a275f8c1e084926196834fc1f0a Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 9 Nov 2026 20:13:39 +0200 Subject: [PATCH 13/15] fix --- lib/pleroma/web/plugs/o_auth_plug.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/plugs/o_auth_plug.ex b/lib/pleroma/web/plugs/o_auth_plug.ex index 038140df7..99952843d 100644 --- a/lib/pleroma/web/plugs/o_auth_plug.ex +++ b/lib/pleroma/web/plugs/o_auth_plug.ex @@ -26,7 +26,7 @@ defmodule Pleroma.Web.Plugs.OAuthPlug do with {:ok, token_str} <- fetch_token_str(conn) do with {:ok, user, user_token} <- fetch_user_and_token(token_str), false <- Token.expired?(user_token) do - with true <- needs_update?(token), + with true <- needs_update?(user_token), {:ok, updated_token} <- Token.update_activity(user_token) do assign(conn, :token, updated_token) else From bbdbf58b66f7a0cfc58f3ac8d5f9895c339a1d5e Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 9 Nov 2026 20:29:37 +0200 Subject: [PATCH 14/15] i don't know what exactly i'm doing --- lib/pleroma/web/plugs/o_auth_plug.ex | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/pleroma/web/plugs/o_auth_plug.ex b/lib/pleroma/web/plugs/o_auth_plug.ex index 99952843d..c0e05c7b0 100644 --- a/lib/pleroma/web/plugs/o_auth_plug.ex +++ b/lib/pleroma/web/plugs/o_auth_plug.ex @@ -28,26 +28,30 @@ defmodule Pleroma.Web.Plugs.OAuthPlug do false <- Token.expired?(user_token) do with true <- needs_update?(user_token), {:ok, updated_token} <- Token.update_activity(user_token) do - assign(conn, :token, updated_token) + conn + |> assign(conn, :token, updated_token) + |> assign(:user, user) else - _ -> assign(conn, :token, user_token) + _ -> + conn + |> assign(:token, user_token) + |> assign(:user, user) end - - conn - |> assign(:user, user) else _ -> with {:ok, app, app_token} <- fetch_app_and_token(token_str), false <- Token.expired?(app_token) do with true <- needs_update?(app_token), {:ok, updated_token} <- Token.update_activity(app_token) do - assign(conn, :token, updated_token) + conn + |> assign(:token, updated_token) + |> assign(:app, app) else - _ -> assign(conn, :token, app_token) + _ -> + conn + |> assign(:token, app_token) + |> assign(:app, app) end - - conn - |> assign(:app, app) else _ -> conn end From f308f4dccf5e59264c106880abf87a2d1136cf4d Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 9 Nov 2026 20:44:56 +0200 Subject: [PATCH 15/15] oops --- lib/pleroma/web/plugs/o_auth_plug.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/plugs/o_auth_plug.ex b/lib/pleroma/web/plugs/o_auth_plug.ex index c0e05c7b0..b63a20068 100644 --- a/lib/pleroma/web/plugs/o_auth_plug.ex +++ b/lib/pleroma/web/plugs/o_auth_plug.ex @@ -29,7 +29,7 @@ defmodule Pleroma.Web.Plugs.OAuthPlug do with true <- needs_update?(user_token), {:ok, updated_token} <- Token.update_activity(user_token) do conn - |> assign(conn, :token, updated_token) + |> assign(:token, updated_token) |> assign(:user, user) else _ ->