# 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"])
scopes: scopes,
redirect_uri: params["redirect_uri"],
state: params["state"],
- params: params
+ params: params,
+ view_module: OAuthView
})
end
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)
# Enforcing the view to reuse the template when calling from other controllers
conn
|> put_view(OAuthView)
- |> render("oob_authorization_created.html", %{auth: auth})
+ |> render("oob_authorization_created.html", %{auth: auth, view_module: OAuthView})
end
def after_create_authorization(%Plug.Conn{} = conn, %Authorization{} = auth, %{
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 ->
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
end
end
+ # Special case: Local MastodonFE
+ defp redirect_uri(%Plug.Conn{} = conn, "."), do: Routes.auth_url(conn, :login)
+
defp redirect_uri(%Plug.Conn{}, redirect_uri), do: redirect_uri
defp get_session_registration_id(%Plug.Conn{} = conn), do: get_session(conn, :registration_id)