reuse valid oauth tokens (#182)
[akkoma] / lib / pleroma / web / o_auth / o_auth_controller.ex
index 358120fe6c375bd98d8c7d056e59c0635da5b17e..455af11d720210994d64aedee4e486f22e29c10e 100644 (file)
@@ -59,18 +59,39 @@ defmodule Pleroma.Web.OAuth.OAuthController do
   # after user already authorized to MastodonFE.
   # So we have to check client and token.
   def authorize(
-        %Plug.Conn{assigns: %{token: %Token{} = token}} = conn,
+        %Plug.Conn{assigns: %{token: %Token{} = token, user: %User{} = user}} = conn,
         %{"client_id" => client_id} = params
       ) do
     with %Token{} = t <- Repo.get_by(Token, token: token.token) |> Repo.preload(:app),
          ^client_id <- t.app.client_id do
       handle_existing_authorization(conn, params)
+    else
+      _ ->
+        maybe_reuse_token(conn, params, user.id)
+    end
+  end
+
+  def authorize(%Plug.Conn{} = conn, params) do
+    # if we have a user in the session, attempt to authenticate as them
+    # otherwise show the login form
+    maybe_reuse_token(conn, params, AuthHelper.get_session_user(conn))
+  end
+
+  defp maybe_reuse_token(conn, params, user_id) when is_binary(user_id) do
+    with %User{} = user <- User.get_cached_by_id(user_id),
+         %App{} = app <- Repo.get_by(App, client_id: params["client_id"]),
+         {:ok, %Token{} = token} <- Token.get_preeexisting_by_app_and_user(app, user),
+         {:ok, %Authorization{} = auth} <-
+           Authorization.get_preeexisting_by_app_and_user(app, user) do
+      conn
+      |> assign(:token, token)
+      |> after_create_authorization(auth, %{"authorization" => params})
     else
       _ -> do_authorize(conn, params)
     end
   end
 
-  def authorize(%Plug.Conn{} = conn, params), do: do_authorize(conn, params)
+  defp maybe_reuse_token(conn, params, _user), do: do_authorize(conn, params)
 
   defp do_authorize(%Plug.Conn{} = conn, params) do
     app = Repo.get_by(App, client_id: params["client_id"])
@@ -148,7 +169,9 @@ defmodule Pleroma.Web.OAuth.OAuthController do
   def create_authorization(%Plug.Conn{} = conn, %{"authorization" => _} = params, opts) do
     with {:ok, auth, user} <- do_create_authorization(conn, params, opts[:user]),
          {:mfa_required, _, _, false} <- {:mfa_required, user, auth, MFA.require?(user)} do
-      after_create_authorization(conn, auth, params)
+      conn
+      |> AuthHelper.put_session_user(user.id)
+      |> after_create_authorization(auth, params)
     else
       error ->
         handle_create_authorization_error(conn, error, params)
@@ -269,7 +292,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
          fixed_token = Token.Utils.fix_padding(params["code"]),
          {:ok, auth} <- Authorization.get_by_token(app, fixed_token),
          %User{} = user <- User.get_cached_by_id(auth.user_id),
-         {:ok, token} <- Token.exchange_token(app, auth) do
+         {:ok, token} <- Token.get_or_exchange_token(auth, app, user) do
       after_token_exchange(conn, %{user: user, token: token})
     else
       error ->
@@ -321,6 +344,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
   def after_token_exchange(%Plug.Conn{} = conn, %{token: token} = view_params) do
     conn
     |> AuthHelper.put_session_token(token.token)
+    |> AuthHelper.put_session_user(token.user_id)
     |> json(OAuthView.render("token.json", view_params))
   end