aboutsummaryrefslogtreecommitdiff
path: root/lib/pleroma/web/plugs/o_auth_plug.ex
diff options
context:
space:
mode:
authorAlex Gleason <alex@alexgleason.me>2022-01-03 13:40:19 -0600
committerAlex Gleason <alex@alexgleason.me>2022-01-03 13:40:19 -0600
commit4081be0001332bac402faec7565807df088b0117 (patch)
treea5305404e9bb31b3613dbc9631d36f8827be81c2 /lib/pleroma/web/plugs/o_auth_plug.ex
parentd00f74e036735c1c238f661076f2925b39daa6ac (diff)
parenta3094b64df344622f1bcb03091ef2ff4dce6da82 (diff)
downloadpleroma-matrix.tar.gz
Merge remote-tracking branch 'origin/develop' into matrixmatrix
Diffstat (limited to 'lib/pleroma/web/plugs/o_auth_plug.ex')
-rw-r--r--lib/pleroma/web/plugs/o_auth_plug.ex107
1 files changed, 107 insertions, 0 deletions
diff --git a/lib/pleroma/web/plugs/o_auth_plug.ex b/lib/pleroma/web/plugs/o_auth_plug.ex
new file mode 100644
index 000000000..5e06ac3f6
--- /dev/null
+++ b/lib/pleroma/web/plugs/o_auth_plug.ex
@@ -0,0 +1,107 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Plugs.OAuthPlug do
+ @moduledoc "Performs OAuth authentication by token from params / headers / cookies."
+
+ import Plug.Conn
+ import Ecto.Query
+
+ alias Pleroma.Helpers.AuthHelper
+ alias Pleroma.Repo
+ alias Pleroma.User
+ alias Pleroma.Web.OAuth.App
+ alias Pleroma.Web.OAuth.Token
+
+ @realm_reg Regex.compile!("Bearer\:?\s+(.*)$", "i")
+
+ def init(options), do: options
+
+ def call(%{assigns: %{user: %User{}}} = conn, _), do: conn
+
+ def call(conn, _) do
+ with {:ok, token_str} <- fetch_token_str(conn) do
+ with {:ok, user, user_token} <- fetch_user_and_token(token_str),
+ false <- Token.is_expired?(user_token) do
+ conn
+ |> assign(:token, user_token)
+ |> assign(:user, user)
+ else
+ _ ->
+ with {:ok, app, app_token} <- fetch_app_and_token(token_str),
+ false <- Token.is_expired?(app_token) do
+ conn
+ |> assign(:token, app_token)
+ |> assign(:app, app)
+ else
+ _ -> conn
+ end
+ end
+ else
+ _ -> conn
+ end
+ end
+
+ # Gets user by token
+ #
+ @spec fetch_user_and_token(String.t()) :: {:ok, User.t(), Token.t()} | nil
+ defp fetch_user_and_token(token) do
+ query =
+ from(t in Token,
+ where: t.token == ^token,
+ join: user in assoc(t, :user),
+ preload: [user: user]
+ )
+
+ with %Token{user: user} = token_record <- Repo.one(query) do
+ {:ok, user, token_record}
+ end
+ end
+
+ @spec fetch_app_and_token(String.t()) :: {:ok, App.t(), Token.t()} | nil
+ defp fetch_app_and_token(token) do
+ query =
+ from(t in Token, where: t.token == ^token, join: app in assoc(t, :app), preload: [app: app])
+
+ with %Token{app: app} = token_record <- Repo.one(query) do
+ {:ok, app, token_record}
+ end
+ end
+
+ # Gets token string from conn (in params / headers / session)
+ #
+ @spec fetch_token_str(Plug.Conn.t() | list(String.t())) :: :no_token_found | {:ok, String.t()}
+ defp fetch_token_str(%Plug.Conn{params: %{"access_token" => access_token}} = _conn) do
+ {:ok, access_token}
+ end
+
+ defp fetch_token_str(%Plug.Conn{} = conn) do
+ headers = get_req_header(conn, "authorization")
+
+ with {:ok, token} <- fetch_token_str(headers) do
+ {:ok, token}
+ else
+ _ -> fetch_token_from_session(conn)
+ end
+ end
+
+ defp fetch_token_str([token | tail]) do
+ trimmed_token = String.trim(token)
+
+ case Regex.run(@realm_reg, trimmed_token) do
+ [_, match] -> {:ok, String.trim(match)}
+ _ -> fetch_token_str(tail)
+ end
+ end
+
+ defp fetch_token_str([]), do: :no_token_found
+
+ @spec fetch_token_from_session(Plug.Conn.t()) :: :no_token_found | {:ok, String.t()}
+ defp fetch_token_from_session(conn) do
+ case AuthHelper.get_session_token(conn) do
+ nil -> :no_token_found
+ token -> {:ok, token}
+ end
+ end
+end