Packages
indieweb
0.0.14
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/indieweb/auth/adapters/default.ex
defmodule IndieWeb.Auth.Adapters.Default do
@moduledoc "Provides a default implementation of IndieAuth stateful activity."
@behaviour IndieWeb.Auth.Adapter
@code_separator "/"
@code_age 60_000
@impl true
def code_generate(client_id, redirect_uri, args) do
[
:crypto.strong_rand_bytes(8),
client_id,
redirect_uri,
URI.decode_query(args)
]
|> Enum.map(&Base.url_encode64/1)
|> Enum.join(@code_separator)
end
@impl true
def code_persist(code, client_id, redirect_uri, args) do
IndieWeb.Cache.set(
do_make_key_for_client(client_id, redirect_uri, args),
code,
expire: @code_age
)
end
@impl true
def code_verify(code, client_id, redirect_uri, args) do
case IndieWeb.Cache.get(
do_make_key_for_client(client_id, redirect_uri, args)
) do
{:ok, nil} ->
{:error, :code_not_found}
{:ok, fetched_code} when is_binary(fetched_code) ->
[_token, fetched_client_id, fetched_redirect_uri, fetched_args] =
String.split(fetched_code, @code_separator)
|> Enum.map(fn value -> Base.url_decode64(value) end)
|> Enum.map(fn {:ok, value} -> value end)
cond do
code != fetched_code ->
{:error, :invalid_code}
fetched_client_id != client_id ->
{:error, :mismatched_client_id_for_code}
fetched_redirect_uri != redirect_uri ->
{:error, :mismatched_redirect_uri_for_code}
URI.decode_query(fetched_args) != args ->
{:error, :mismatched_extra_data}
true ->
:ok
end
end
end
@impl true
def code_destroy(client_id, redirect_uri, args \\ %{}) do
IndieWeb.Cache.delete(do_make_key_for_client(client_id, redirect_uri, args))
end
def scope_get(code) do
IndieWeb.Cache.get(code)
end
def scope_persist(code, scope) do
IndieWeb.Cache.set(code, scope, expire: @code_age)
end
def valid_user?(uri) do
resolve_user_fn =
Application.get_env(:indieweb, :resolve_user_fn, fn _ -> true end)
resolve_user_fn.(uri)
end
def token_info(token) do
case IndieWeb.Cache.get(token) do
data when is_binary(data) -> URI.decode_query(data)
_ -> {:error, :not_found}
end
end
def token_revoke(token) do
IndieWeb.Cache.delete(token)
end
def token_generate(client_id, scope) do
IndieWeb.Cache.set(
do_make_token(client_id, scope),
URI.encode_query(%{"scope" => scope, "client_id" => client_id})
)
end
defp do_make_key_for_client(client_id, redirect_uri, args) do
[
client_id,
redirect_uri,
args |> URI.encode_query()
]
|> Enum.join("_")
|> URI.encode_query()
|> (fn data -> :erlang.phash(:indieweb_auth_code_key, :sha256) end).()
end
defp do_make_token(client_id, scope) do
[
:crypto.strong_rand_bytes(32),
client_id,
scope
]
|> Enum.map(&Base.url_encode64/1)
|> Enum.join(@code_separator)
|> (fn data -> :crypto.hash(data, :sha256) end).()
end
end