add initial indieauth logic, add tesla

This commit is contained in:
Inhji 2023-05-28 22:36:13 +02:00
parent 76185e3b57
commit a65e1a613d
4 changed files with 134 additions and 18 deletions

View file

@ -0,0 +1,26 @@
defmodule ChiyaWeb.Indie.Auth do
use Tesla
require Logger
@base_url Application.compile_env!(:chiya, [:indie, :token_endpoint])
@user_agent Application.compile_env!(:chiya, [ChiyaWeb.Endpoint, :user_agent])
def verify_token(token) do
token
|> client()
|> get("")
end
defp client(token) do
Tesla.client([
{Tesla.Middleware.BaseUrl, @base_url},
{Tesla.Middleware.JSON, [engine: Jason, engine_opts: [keys: :atoms]]},
{Tesla.Middleware.Headers,
[
{"User-Agent", @user_agent},
{"Authorization", "Bearer #{token}"},
{"Accept", "application/json"}
]}
])
end
end

View file

@ -0,0 +1,88 @@
defmodule ChiyaWeb.Indie.Token do
require Logger
@supported_scopes Application.compile_env!(:chiya, [:indie, :supported_scopes])
def verify(access_token, required_scope, own_hostname) do
case ChiyaWeb.Indie.Auth.verify_token(access_token) do
{:ok, %{status: 200, body: body}} ->
verify_token_response(body, required_scope, own_hostname)
{:ok, %{status: status}} ->
{:error, :insufficient_scope, status}
{:error, %{code: code}} ->
Logger.error("Token endpoint responded with unexpected code: #{inspect(code)}")
{:error, :insufficient_scope, code}
{:error, %{reason: reason}} ->
Logger.error("Could not reach token endpoint: #{inspect(reason)}")
{:error, :insufficient_scope, reason}
error ->
Logger.error("Unexpected error: #{inspect(error)}")
{:error, :insufficient_scope, "Internal Server Error"}
end
end
defp verify_token_response(
%{
me: host_uri,
scope: scope,
client_id: client_id,
issued_at: _issued_at,
issued_by: _issued_by,
nonce: _nonce
},
required_scope,
own_hostname
) do
Logger.info("Host-URI: '#{host_uri}'")
Logger.info("ClientId: '#{client_id}'")
Logger.info("Scopes: '#{scope}'")
with :ok <- verify_hostname_match(host_uri, own_hostname),
:ok <- verify_scope_support(scope, required_scope, @supported_scopes) do
:ok
else
{:error, name, reason} ->
Logger.error("Could not verify token response: #{reason}")
{:error, name, reason}
end
end
defp verify_hostname_match(host_uri, own_hostname) do
hostnames_match? = get_hostname(host_uri) == own_hostname
case hostnames_match? do
true ->
:ok
_ ->
Logger.warn("Hostnames do not match: Given #{host_uri}, Actual: #{own_hostname}")
{:error, "verify_hostname_match", "hostname does not match"}
end
end
defp get_hostname(host_uri) do
host_uri |> URI.parse() |> Map.get(:host)
end
defp verify_scope_support(_scopes, nil, _supported_scopes), do: :ok
defp verify_scope_support(scopes, required_scope, supported_scopes) do
required = Enum.member?(supported_scopes, required_scope)
requested = Enum.member?(String.split(scopes), required_scope)
cond do
required && requested ->
:ok
!required ->
{:error, "verify_scope_support", "scope '#{required_scope}' is not supported"}
!requested ->
{:error, "verify_scope_support", "scope '#{required_scope}' was not requested"}
end
end
end

37
mix.exs
View file

@ -33,31 +33,32 @@ defmodule Chiya.MixProject do
defp deps do
[
{:bcrypt_elixir, "~> 3.0"},
{:phoenix, "~> 1.7.1"},
{:phoenix_ecto, "~> 4.4"},
{:ecto_sql, "~> 3.6"},
{:earmark, "~> 1.4"},
{:ecto_autoslug_field, "~> 3.0"},
{:postgrex, ">= 0.0.0"},
{:phoenix_html, "~> 3.3"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:phoenix_live_view, "~> 0.18.16"},
{:floki, ">= 0.30.0", only: :test},
{:phoenix_live_dashboard, "~> 0.7.2"},
{:tailwind, "~> 0.2.0", runtime: Mix.env() == :dev},
{:swoosh, "~> 1.3"},
{:ecto_sql, "~> 3.6"},
{:finch, "~> 0.16"},
{:telemetry_metrics, "~> 0.6"},
{:telemetry_poller, "~> 1.0"},
{:floki, ">= 0.30.0", only: :test},
{:gettext, "~> 0.22"},
{:jason, "~> 1.2"},
{:plug_cowboy, "~> 2.5"},
{:oban, "~> 2.14"},
{:phoenix, "~> 1.7.1"},
{:phoenix_ecto, "~> 4.4"},
{:phoenix_html, "~> 3.3"},
{:phoenix_live_dashboard, "~> 0.7.2"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:phoenix_live_view, "~> 0.18.16"},
{:plug_cowboy, "~> 2.5"},
{:plug_micropub, git: "https://git.inhji.de/inhji/plug_micropub"},
{:postgrex, ">= 0.0.0"},
{:swoosh, "~> 1.3"},
{:tailwind, "~> 0.2.0", runtime: Mix.env() == :dev},
{:telemetry_metrics, "~> 0.6"},
{:telemetry_poller, "~> 1.0"},
{:tesla, "~> 1.7"},
{:tz, "~> 0.26.1"},
{:waffle, "~> 1.1"},
{:waffle_ecto, "~> 0.0.12"},
{:earmark, "~> 1.4"},
{:yaml_front_matter, "~> 1.0.0"},
{:tz, "~> 0.26.1"},
{:plug_micropub, git: "https://git.inhji.de/inhji/plug_micropub"}
{:yaml_front_matter, "~> 1.0.0"}
]
end

View file

@ -54,6 +54,7 @@
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"},
"telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"},
"tesla": {:hex, :tesla, "1.7.0", "a62dda2f80d4f8a925eb7b8c5b78c461e0eb996672719fe1a63b26321a5f8b4e", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "2e64f01ebfdb026209b47bc651a0e65203fcff4ae79c11efb73c4852b00dc313"},
"tz": {:hex, :tz, "0.26.1", "773555ecb9c01c87fcf969b4c2d2140e63fe6b3d7d9520fa2134ac1072b540a8", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:mint, "~> 1.5", [hex: :mint, repo: "hexpm", optional: true]}], "hexpm", "da38cea41e9cfd0deaa7f634e167a30399dcc8b84fd3da32e1d972466053f57c"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
"waffle": {:hex, :waffle, "1.1.7", "518f9bdda7b9b3d0958ad6ab16066631ce028f5f12217382822a428895fc4be3", [:mix], [{:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:ex_aws_s3, "~> 2.1", [hex: :ex_aws_s3, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "e97e7b10b7f380687b5dc5e65b391538a802eff636605ad183e0bed29b45b0ef"},