maybe key loading works now
This commit is contained in:
parent
d19a228dca
commit
bf5c9046e2
|
@ -25,4 +25,6 @@ vonbraun-*.tar
|
||||||
# Temporary files, for example, from tests.
|
# Temporary files, for example, from tests.
|
||||||
/tmp/
|
/tmp/
|
||||||
|
|
||||||
*.sqlite3*
|
*.sqlite3*
|
||||||
|
|
||||||
|
*.pem
|
|
@ -8,6 +8,7 @@ defmodule Vonbraun.Application do
|
||||||
@impl true
|
@impl true
|
||||||
def start(_type, _args) do
|
def start(_type, _args) do
|
||||||
children = [
|
children = [
|
||||||
|
Vonbraun.KeyAgent,
|
||||||
Vonbraun.Repo,
|
Vonbraun.Repo,
|
||||||
{Bandit, scheme: :http, plug: Vonbraun.MyRouter, port: 4012}
|
{Bandit, scheme: :http, plug: Vonbraun.MyRouter, port: 4012}
|
||||||
]
|
]
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
defmodule HTTPSignature do
|
||||||
|
@moduledoc """
|
||||||
|
Implements RFC 9421 HTTP Signatures using the Digest header.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@algo :sha256
|
||||||
|
# Load this securely in production
|
||||||
|
@key "secret_key"
|
||||||
|
|
||||||
|
@spec create_signature_header(map(), list(), String.t(), binary()) :: String.t()
|
||||||
|
def create_signature_header(headers, include_headers, key_id, body) do
|
||||||
|
digest = compute_digest(body)
|
||||||
|
headers = Map.put(headers, "digest", digest)
|
||||||
|
signing_string = construct_signing_string(headers, include_headers)
|
||||||
|
signature = sign(signing_string)
|
||||||
|
build_signature_header(key_id, signature, include_headers)
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec verify_signature(map(), String.t(), list(), binary()) :: boolean()
|
||||||
|
def verify_signature(headers, signature_header, include_headers, body) do
|
||||||
|
{_key_id, signature} = parse_signature_header(signature_header)
|
||||||
|
digest = compute_digest(body)
|
||||||
|
headers = Map.put(headers, "digest", digest)
|
||||||
|
signing_string = construct_signing_string(headers, include_headers)
|
||||||
|
expected_signature = sign(signing_string)
|
||||||
|
|
||||||
|
SecureCompare.compare(expected_signature, Base.decode64!(signature))
|
||||||
|
end
|
||||||
|
|
||||||
|
defp compute_digest(body) do
|
||||||
|
:crypto.hash(:sha256, body)
|
||||||
|
|> Base.encode64()
|
||||||
|
|> (&("SHA-256=" <> &1)).()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp construct_signing_string(headers, include_headers) do
|
||||||
|
include_headers
|
||||||
|
|> Enum.map(fn header ->
|
||||||
|
"#{header}: #{Map.fetch!(headers, header)}"
|
||||||
|
end)
|
||||||
|
|> Enum.join("\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
defp sign(data) do
|
||||||
|
:crypto.hash(@algo, [@key, data])
|
||||||
|
|> Base.encode64()
|
||||||
|
|> String.downcase()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp build_signature_header(key_id, signature, headers) do
|
||||||
|
"Signature keyId=\"#{key_id}\",algorithm=\"hmac-sha256\",headers=\"#{Enum.join(headers, " ")}\",signature=\"#{signature}\""
|
||||||
|
end
|
||||||
|
|
||||||
|
defp parse_signature_header(header) do
|
||||||
|
[_, key_id, _, _, _headers, _, signature] =
|
||||||
|
Regex.scan(
|
||||||
|
~r/keyId="([^"]+)",algorithm="([^"]+)",headers="([^"]+)",signature="([^"]+)"/,
|
||||||
|
header
|
||||||
|
)
|
||||||
|
|> List.first()
|
||||||
|
|
||||||
|
{key_id, signature}
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,29 @@
|
||||||
|
defmodule Vonbraun.KeyAgent do
|
||||||
|
use Agent
|
||||||
|
|
||||||
|
def start_link(_opts) do
|
||||||
|
Agent.start_link(fn -> load_keys() end, name: __MODULE__)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp load_keys() do
|
||||||
|
{:ok, private_key} = ExPublicKey.load("config/key-dev.pem", nil)
|
||||||
|
|
||||||
|
{:ok, public_pem} =
|
||||||
|
with {:ok, public_key} <- ExPublicKey.public_key_from_private_key(private_key) do
|
||||||
|
ExPublicKey.pem_encode(public_key)
|
||||||
|
end
|
||||||
|
|
||||||
|
%{
|
||||||
|
private_key: private_key,
|
||||||
|
public_pem: public_pem
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_public_pem() do
|
||||||
|
Agent.get(__MODULE__, fn state -> state.public_pem end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_private_key() do
|
||||||
|
Agent.get(__MODULE__, fn state -> state.private_key end)
|
||||||
|
end
|
||||||
|
end
|
|
@ -167,9 +167,10 @@ defmodule Vonbraun.MyRouter do
|
||||||
domain = Application.fetch_env!(:vonbraun, :domain)
|
domain = Application.fetch_env!(:vonbraun, :domain)
|
||||||
name = Application.fetch_env!(:vonbraun, :name)
|
name = Application.fetch_env!(:vonbraun, :name)
|
||||||
summary = Application.fetch_env!(:vonbraun, :summary)
|
summary = Application.fetch_env!(:vonbraun, :summary)
|
||||||
|
public_pem = Vonbraun.KeyAgent.get_public_pem() |> String.replace("\n", "\\n")
|
||||||
|
|
||||||
conn = Plug.Conn.put_resp_content_type(conn, "application/activity+json")
|
conn = Plug.Conn.put_resp_content_type(conn, "application/activity+json")
|
||||||
send_resp(conn, 200, render_user(nickname, domain, name, summary, ""))
|
send_resp(conn, 200, render_user(nickname, domain, name, summary, public_pem))
|
||||||
else
|
else
|
||||||
send_resp(conn, 404, "fuck off")
|
send_resp(conn, 404, "fuck off")
|
||||||
end
|
end
|
||||||
|
|
4
mix.exs
4
mix.exs
|
@ -23,7 +23,9 @@ defmodule Vonbraun.MixProject do
|
||||||
defp deps do
|
defp deps do
|
||||||
[
|
[
|
||||||
{:bandit, "~> 1.5.7"},
|
{:bandit, "~> 1.5.7"},
|
||||||
{:ecto_sqlite3, "~> 0.17"}
|
{:ecto_sqlite3, "~> 0.17"},
|
||||||
|
{:secure_compare, "~> 0.1.0"},
|
||||||
|
{:ex_crypto, "~> 0.10.0"}
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
3
mix.lock
3
mix.lock
|
@ -7,11 +7,14 @@
|
||||||
"ecto_sql": {:hex, :ecto_sql, "3.12.0", "73cea17edfa54bde76ee8561b30d29ea08f630959685006d9c6e7d1e59113b7d", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dc9e4d206f274f3947e96142a8fdc5f69a2a6a9abb4649ef5c882323b6d512f0"},
|
"ecto_sql": {:hex, :ecto_sql, "3.12.0", "73cea17edfa54bde76ee8561b30d29ea08f630959685006d9c6e7d1e59113b7d", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dc9e4d206f274f3947e96142a8fdc5f69a2a6a9abb4649ef5c882323b6d512f0"},
|
||||||
"ecto_sqlite3": {:hex, :ecto_sqlite3, "0.17.1", "96d08639aa1fb07a087daa2220ebc68d9f4f5dbb8aed930e771d848d8d472d32", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.12", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:exqlite, "~> 0.22", [hex: :exqlite, repo: "hexpm", optional: false]}], "hexpm", "dbd6a68b5364fe6e9ce5d70336709d62edaebbb4cb4acb5f13ec825f64fa48cc"},
|
"ecto_sqlite3": {:hex, :ecto_sqlite3, "0.17.1", "96d08639aa1fb07a087daa2220ebc68d9f4f5dbb8aed930e771d848d8d472d32", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.12", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:exqlite, "~> 0.22", [hex: :exqlite, repo: "hexpm", optional: false]}], "hexpm", "dbd6a68b5364fe6e9ce5d70336709d62edaebbb4cb4acb5f13ec825f64fa48cc"},
|
||||||
"elixir_make": {:hex, :elixir_make, "0.8.4", "4960a03ce79081dee8fe119d80ad372c4e7badb84c493cc75983f9d3bc8bde0f", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.0", [hex: :certifi, repo: "hexpm", optional: true]}], "hexpm", "6e7f1d619b5f61dfabd0a20aa268e575572b542ac31723293a4c1a567d5ef040"},
|
"elixir_make": {:hex, :elixir_make, "0.8.4", "4960a03ce79081dee8fe119d80ad372c4e7badb84c493cc75983f9d3bc8bde0f", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.0", [hex: :certifi, repo: "hexpm", optional: true]}], "hexpm", "6e7f1d619b5f61dfabd0a20aa268e575572b542ac31723293a4c1a567d5ef040"},
|
||||||
|
"ex_crypto": {:hex, :ex_crypto, "0.10.0", "af600a89b784b36613a989da6e998c1b200ff1214c3cfbaf8deca4aa2f0a1739", [:mix], [{:poison, ">= 2.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm", "ccc7472cfe8a0f4565f97dce7e9280119bf15a5ea51c6535e5b65f00660cde1c"},
|
||||||
"exqlite": {:hex, :exqlite, "0.23.0", "6e851c937a033299d0784994c66da24845415072adbc455a337e20087bce9033", [:make, :mix], [{:cc_precompiler, "~> 0.1", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.8", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "404341cceec5e6466aaed160cf0b58be2019b60af82588c215e1224ebd3ec831"},
|
"exqlite": {:hex, :exqlite, "0.23.0", "6e851c937a033299d0784994c66da24845415072adbc455a337e20087bce9033", [:make, :mix], [{:cc_precompiler, "~> 0.1", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.8", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "404341cceec5e6466aaed160cf0b58be2019b60af82588c215e1224ebd3ec831"},
|
||||||
"hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"},
|
"hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"},
|
||||||
"mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"},
|
"mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"},
|
||||||
"plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"},
|
"plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"},
|
||||||
"plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"},
|
"plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"},
|
||||||
|
"poison": {:hex, :poison, "6.0.0", "9bbe86722355e36ffb62c51a552719534257ba53f3271dacd20fbbd6621a583a", [:mix], [{:decimal, "~> 2.1", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "bb9064632b94775a3964642d6a78281c07b7be1319e0016e1643790704e739a2"},
|
||||||
|
"secure_compare": {:hex, :secure_compare, "0.1.0", "01b3c93c8edb696e8a5b38397ed48e10958c8a5ec740606656445bcbec0aadb8", [:mix], [], "hexpm", "6391a49eb4a6182f0d7425842fc774bbed715e78b2bfb0c83b99c94e02c78b5c"},
|
||||||
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
|
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
|
||||||
"thousand_island": {:hex, :thousand_island, "1.3.5", "6022b6338f1635b3d32406ff98d68b843ba73b3aa95cfc27154223244f3a6ca5", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2be6954916fdfe4756af3239fb6b6d75d0b8063b5df03ba76fd8a4c87849e180"},
|
"thousand_island": {:hex, :thousand_island, "1.3.5", "6022b6338f1635b3d32406ff98d68b843ba73b3aa95cfc27154223244f3a6ca5", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2be6954916fdfe4756af3239fb6b6d75d0b8063b5df03ba76fd8a4c87849e180"},
|
||||||
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
|
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
|
||||||
|
|
Loading…
Reference in New Issue