Packages
indieweb
0.0.46
0.0.66
0.0.65
0.0.64
0.0.63
0.0.62
0.0.61
0.0.60
0.0.59
0.0.58
0.0.56
0.0.55
0.0.54
0.0.53
0.0.51
0.0.50
0.0.49
0.0.48
0.0.47
0.0.46
0.0.42
0.0.41
0.0.40
0.0.39
0.0.38
0.0.37
0.0.36
0.0.35
0.0.34
0.0.33
0.0.32
0.0.31
0.0.30
0.0.29
0.0.28
0.0.27
0.0.26
0.0.25
0.0.24
0.0.23
0.0.22
0.0.21
0.0.20
0.0.19
0.0.17
0.0.16
0.0.15
0.0.14
0.0.13
0.0.12
0.0.10
0.0.9
0.0.8
0.0.7
0.0.6
0.0.5
0.0.3
0.0.2
0.0.1
Collection of common IndieWeb utilites like authorship resolution, Webmention, post type discovery and IndieAuth.
Current section
Files
Jump to
Current section
Files
lib/plug/inject_credentials.ex
defmodule IndieWeb.Plug.InjectCredentials do
import Plug.Conn
require Logger
def init(opts) do
opts
end
def call(conn, _opts) do
with(
auth_token when is_binary(auth_token) and auth_token != "" <-
do_extract_from_request(conn),
me_url when is_binary(me_url) <- find_me_from_token(auth_token),
endpoint when is_binary(endpoint) <-
IndieWeb.Auth.endpoint_for(:token, me_url),
{:ok, %{"scope" => scope}} <-
IndieWeb.Clients.IndieAuth.verify_token(endpoint, auth_token)
) do
Logger.debug("Found a user and their accompanying token.",
indieauth_user: me_url
)
conn
|> put_private(:indieauth_me, me_url)
|> put_private(:indieauth_access_token, auth_token)
|> put_private(:indieauth_scope, scope)
else
nil ->
Logger.warn("The request was not authorized with IndieAuth information.")
# TODO: Make into a more OAuth2-y error.
conn
|> put_resp_content_type("application/json")
|> Explode.unauthorized()
{:error, error} ->
Logger.warn("Token provided but no user found.",
error: error
)
# TODO: Make into a more OAuth2-y error.
conn
|> put_resp_content_type("application/json")
|> Explode.bad_request()
{:error, name, data} ->
Logger.warn("Unexpected error.", error: name, data: inspect(data))
# TODO: Make into a more OAuth2-y error.
conn
|> put_resp_content_type("application/json")
|> Explode.bad_request()
end
end
defp do_extract_from_request(conn) do
[
conn
|> fetch_query_params()
|> Map.get(:params)
|> Map.get("access_token", nil),
conn
|> get_req_header("authorization")
|> List.first()
|> List.wrap()
|> List.first()
|> String.split(" ", parts: 2)
|> List.last()
]
|> Enum.reject(&is_nil/1)
|> Enum.reject(&(&1 == ""))
|> List.first()
end
@spec add(binary(), binary()) ::
{:ok, me: binary(), token: binary()}
| {:error, :failed_to_set_token}
def add(me, token) do
hashed_token = do_generate_hash(token)
Logger.info("Generated hashed token for user.",
me: me,
hashed_token: hashed_token
)
with(
:ok <- IndieWeb.Cache.set("indieauth:proxied_token:#{hashed_token}", me),
:ok <- IndieWeb.Cache.set("indieauth:proxied_me:#{me}", token)
) do
Logger.info("Added user with their provided token to the cache.", me: me)
{:ok, me: me, token: token}
else
error ->
Logger.error("Failed to insert user with their token.",
me: me,
error: inspect(error)
)
{:error, :failed_to_set_token}
end
end
@spec remove(binary()) :: :ok
def remove(token) do
hashed_token = do_generate_hash(token)
me = find_me_from_token(hashed_token)
IndieWeb.Cache.delete("indieauth:proxied_token:#{hashed_token}")
IndieWeb.Cache.delete("indieauth:proxied_me:#{me}")
Logger.info("Removed token and user from cache.", hashed_token: hashed_token)
:ok
end
@doc "Finds the user's URL from the provided IndieAuth token."
@spec find_me_from_token(binary()) :: binary() | nil
def find_me_from_token(token) do
hashed_token = do_generate_hash(token)
case IndieWeb.Cache.get("indieauth:proxied_token:#{hashed_token}") do
{:ok, me} when is_binary(me) ->
me
_ ->
nil
end
end
@doc "Finds the user's IndieAuth token from the provided me."
@spec find_token_from_me(binary()) :: binary() | nil
def find_token_from_me(me) do
case IndieWeb.Cache.get("indieauth:proxied_me:#{me}") do
{:ok, token} when is_binary(token) ->
token
_ ->
nil
end
end
defp do_generate_hash(token) do
:crypto.hash(:sha512, token)
|> Base.decode64(padding: false)
end
end