Merge branch 'devel'
This commit is contained in:
commit
e1b75e00be
7 changed files with 160 additions and 20 deletions
|
@ -18,7 +18,8 @@ config :chiya, ChiyaWeb.Endpoint,
|
||||||
layout: false
|
layout: false
|
||||||
],
|
],
|
||||||
pubsub_server: Chiya.PubSub,
|
pubsub_server: Chiya.PubSub,
|
||||||
live_view: [signing_salt: "OJncEkwy"]
|
live_view: [signing_salt: "OJncEkwy"],
|
||||||
|
user_agent: "Chiya/0.x +https://inhji.de"
|
||||||
|
|
||||||
# Configures the mailer
|
# Configures the mailer
|
||||||
#
|
#
|
||||||
|
@ -63,6 +64,18 @@ config :waffle,
|
||||||
# Configure Timezones with :tz
|
# Configure Timezones with :tz
|
||||||
config :elixir, :time_zone_database, Tz.TimeZoneDatabase
|
config :elixir, :time_zone_database, Tz.TimeZoneDatabase
|
||||||
|
|
||||||
|
config :chiya, :indie,
|
||||||
|
token_endpoint: "https://tokens.indieauth.com/token",
|
||||||
|
auth_endpoint: "https://indieauth.com/auth",
|
||||||
|
supported_scopes: [
|
||||||
|
# Micropub scopes
|
||||||
|
"create",
|
||||||
|
"update",
|
||||||
|
"delete",
|
||||||
|
"undelete",
|
||||||
|
"media"
|
||||||
|
]
|
||||||
|
|
||||||
# Import environment specific config. This must remain at the bottom
|
# Import environment specific config. This must remain at the bottom
|
||||||
# of this file so it overrides the configuration defined above.
|
# of this file so it overrides the configuration defined above.
|
||||||
import_config "#{config_env()}.exs"
|
import_config "#{config_env()}.exs"
|
||||||
|
|
|
@ -10,6 +10,10 @@
|
||||||
|
|
||||||
<.favicon />
|
<.favicon />
|
||||||
|
|
||||||
|
<link rel="authorization_endpoint" href={@auth_endpoint} />
|
||||||
|
<link rel="token_endpoint" href={@token_endpoint} />
|
||||||
|
<link rel="micropub" href={~p"/indie/micropub"} />
|
||||||
|
|
||||||
<%= for identity <- @identities do %>
|
<%= for identity <- @identities do %>
|
||||||
<link rel="me" href={identity.url} />
|
<link rel="me" href={identity.url} />
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
defmodule ChiyaWeb.GlobalAssigns do
|
defmodule ChiyaWeb.GlobalAssigns do
|
||||||
import Plug.Conn
|
import Plug.Conn
|
||||||
|
|
||||||
|
@token_endpoint Application.compile_env!(:chiya, [:indie, :token_endpoint])
|
||||||
|
@auth_endpoint Application.compile_env!(:chiya, [:indie, :auth_endpoint])
|
||||||
|
|
||||||
def fetch_settings(conn, _opts) do
|
def fetch_settings(conn, _opts) do
|
||||||
settings = Chiya.Site.get_settings()
|
settings = Chiya.Site.get_settings()
|
||||||
assign(conn, :settings, settings)
|
|
||||||
|
conn
|
||||||
|
|> assign(:token_endpoint, @token_endpoint)
|
||||||
|
|> assign(:auth_endpoint, @auth_endpoint)
|
||||||
|
|> assign(:settings, settings)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_identities(conn, _opts) do
|
def fetch_identities(conn, _opts) do
|
||||||
|
|
26
lib/chiya_web/indie/indieauth.ex
Normal file
26
lib/chiya_web/indie/indieauth.ex
Normal 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
|
88
lib/chiya_web/indie/token.ex
Normal file
88
lib/chiya_web/indie/token.ex
Normal 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
37
mix.exs
|
@ -33,31 +33,32 @@ defmodule Chiya.MixProject do
|
||||||
defp deps do
|
defp deps do
|
||||||
[
|
[
|
||||||
{:bcrypt_elixir, "~> 3.0"},
|
{:bcrypt_elixir, "~> 3.0"},
|
||||||
{:phoenix, "~> 1.7.1"},
|
{:earmark, "~> 1.4"},
|
||||||
{:phoenix_ecto, "~> 4.4"},
|
|
||||||
{:ecto_sql, "~> 3.6"},
|
|
||||||
{:ecto_autoslug_field, "~> 3.0"},
|
{:ecto_autoslug_field, "~> 3.0"},
|
||||||
{:postgrex, ">= 0.0.0"},
|
{:ecto_sql, "~> 3.6"},
|
||||||
{: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"},
|
|
||||||
{:finch, "~> 0.16"},
|
{:finch, "~> 0.16"},
|
||||||
{:telemetry_metrics, "~> 0.6"},
|
{:floki, ">= 0.30.0", only: :test},
|
||||||
{:telemetry_poller, "~> 1.0"},
|
|
||||||
{:gettext, "~> 0.22"},
|
{:gettext, "~> 0.22"},
|
||||||
{:jason, "~> 1.2"},
|
{:jason, "~> 1.2"},
|
||||||
{:plug_cowboy, "~> 2.5"},
|
|
||||||
{:oban, "~> 2.14"},
|
{: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, "~> 1.1"},
|
||||||
{:waffle_ecto, "~> 0.0.12"},
|
{:waffle_ecto, "~> 0.0.12"},
|
||||||
{:earmark, "~> 1.4"},
|
{:yaml_front_matter, "~> 1.0.0"}
|
||||||
{:yaml_front_matter, "~> 1.0.0"},
|
|
||||||
{:tz, "~> 0.26.1"},
|
|
||||||
{:plug_micropub, git: "https://git.inhji.de/inhji/plug_micropub"}
|
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
1
mix.lock
1
mix.lock
|
@ -54,6 +54,7 @@
|
||||||
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
|
"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_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"},
|
"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"},
|
"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"},
|
"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"},
|
"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"},
|
||||||
|
|
Loading…
Reference in a new issue