From 4d9e2a8ede6a4e52ab2975ecdeec0a8bde0a90a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonatan=20M=C3=A4nnchen?= Date: Tue, 30 Apr 2024 14:12:11 +0200 Subject: [PATCH] FAPI 2.0 Certification --- README.md | 16 +++ artifacts/GENERATION.md | 23 ++++ artifacts/client.priv.jwk | 7 ++ artifacts/client.priv.jwkset | 14 +++ artifacts/client.priv.pem | 5 + artifacts/client.pub.jwk | 6 + artifacts/client.pub.jwkset | 13 +++ artifacts/client.pub.pem | 4 + artifacts/server.priv.jwk | 7 ++ artifacts/server.priv.jwkset | 14 +++ artifacts/server.priv.pem | 5 + artifacts/server.pub.jwk | 6 + artifacts/server.pub.jwkset | 13 +++ artifacts/server.pub.pem | 4 + lib/conformance/auth_controller.ex | 160 +++++++++++++++++---------- lib/conformance/endpoint.ex | 8 +- lib/conformance/log_configuration.ex | 10 +- lib/conformance/register_client.ex | 29 ++++- lib/conformance/supervisor.ex | 12 +- lib/mix/tasks/run_certification.ex | 9 +- mix.exs | 4 +- mix.lock | 38 +++---- 22 files changed, 316 insertions(+), 91 deletions(-) create mode 100644 artifacts/GENERATION.md create mode 100644 artifacts/client.priv.jwk create mode 100644 artifacts/client.priv.jwkset create mode 100644 artifacts/client.priv.pem create mode 100644 artifacts/client.pub.jwk create mode 100644 artifacts/client.pub.jwkset create mode 100644 artifacts/client.pub.pem create mode 100644 artifacts/server.priv.jwk create mode 100644 artifacts/server.priv.jwkset create mode 100644 artifacts/server.priv.pem create mode 100644 artifacts/server.pub.jwk create mode 100644 artifacts/server.pub.jwkset create mode 100644 artifacts/server.pub.pem diff --git a/README.md b/README.md index 1645369..af83e59 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,22 @@ The certification is funded as an - Response Mode: `default` - Client Registration Type: `dynamic_client` +#### FAPI2-Security-Profile-ID2: Relying Party (client) test + +- **Relevant for Certification: Yes** +- Id: `fapi2-security-profile-id2-client-test-plan` +- Client Authentication Type: `private_key_jwt` +- Sender COnstraining: `dpop` +- FAPI Client Type: `oidc` +- FAPI Profile: `plain_fapi` +- Server + - jwks: `./artifacts/server.priv.jwkset` +- Client + - client_id: `client_id` + - scope: `openid profile` + - redirect_uri: `http://localhost:4000/callback` + - jwks: `./artifacts/client.pub.jwkset` + ## How to Execute the tests ### Setup diff --git a/artifacts/GENERATION.md b/artifacts/GENERATION.md new file mode 100644 index 0000000..3f5ea66 --- /dev/null +++ b/artifacts/GENERATION.md @@ -0,0 +1,23 @@ +# Generation of keys + +```bash +# Generate Private Keys +openssl ecparam -genkey -name prime256v1 -noout -out artifacts/client.priv.pem +openssl ecparam -genkey -name prime256v1 -noout -out artifacts/server.priv.pem + +# Generate Public Keys +openssl ec -in ./artifacts/client.priv.pem -pubout -out ./artifacts/client.pub.pem +openssl ec -in ./artifacts/server.priv.pem -pubout -out ./artifacts/server.pub.pem + +# Generate JWKs for public & private keys +npx eckles ./artifacts/client.priv.pem > ./artifacts/client.priv.jwk +npx eckles ./artifacts/client.pub.pem > ./artifacts/client.pub.jwk +npx eckles ./artifacts/server.priv.pem > ./artifacts/server.priv.jwk +npx eckles ./artifacts/server.pub.pem > ./artifacts/server.pub.jwk + +# Generate JWK sets +cat ./artifacts/client.priv.jwk| jq '{"keys": [. * {"use": "sig", "kid": "client", "alg": "ES256"}]}' > ./artifacts/client.priv.jwkset +cat ./artifacts/client.pub.jwk| jq '{"keys": [. * {"use": "sig", "kid": "client", "alg": "ES256"}]}' > ./artifacts/client.pub.jwkset +cat ./artifacts/server.priv.jwk| jq '{"keys": [. * {"use": "sig", "kid": "server", "alg": "ES256"}]}' > ./artifacts/server.priv.jwkset +cat ./artifacts/server.pub.jwk| jq '{"keys": [. * {"use": "sig", "kid": "server", "alg": "ES256"}]}' > ./artifacts/server.pub.jwkset +``` \ No newline at end of file diff --git a/artifacts/client.priv.jwk b/artifacts/client.priv.jwk new file mode 100644 index 0000000..b0ed208 --- /dev/null +++ b/artifacts/client.priv.jwk @@ -0,0 +1,7 @@ +{ + "kty": "EC", + "crv": "P-256", + "d": "I5XC9VN5oJUQpXO5LqN5jNm9NTPAo_8zUkiUhJlgoRk", + "x": "QaXzjB1aMQRoXcgFTQUneS6EBVaQHQObzaHJjKV6_fM", + "y": "fljC46dVTTQFsyB4Iap7pmTzolhLX2KOtajOI2kEh7g" +} diff --git a/artifacts/client.priv.jwkset b/artifacts/client.priv.jwkset new file mode 100644 index 0000000..be7e716 --- /dev/null +++ b/artifacts/client.priv.jwkset @@ -0,0 +1,14 @@ +{ + "keys": [ + { + "kty": "EC", + "crv": "P-256", + "d": "I5XC9VN5oJUQpXO5LqN5jNm9NTPAo_8zUkiUhJlgoRk", + "x": "QaXzjB1aMQRoXcgFTQUneS6EBVaQHQObzaHJjKV6_fM", + "y": "fljC46dVTTQFsyB4Iap7pmTzolhLX2KOtajOI2kEh7g", + "use": "sig", + "kid": "client", + "alg": "ES256" + } + ] +} diff --git a/artifacts/client.priv.pem b/artifacts/client.priv.pem new file mode 100644 index 0000000..d6281e9 --- /dev/null +++ b/artifacts/client.priv.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEICOVwvVTeaCVEKVzuS6jeYzZvTUzwKP/M1JIlISZYKEZoAoGCCqGSM49 +AwEHoUQDQgAEQaXzjB1aMQRoXcgFTQUneS6EBVaQHQObzaHJjKV6/fN+WMLjp1VN +NAWzIHghqnumZPOiWEtfYo61qM4jaQSHuA== +-----END EC PRIVATE KEY----- diff --git a/artifacts/client.pub.jwk b/artifacts/client.pub.jwk new file mode 100644 index 0000000..b85c8f6 --- /dev/null +++ b/artifacts/client.pub.jwk @@ -0,0 +1,6 @@ +{ + "kty": "EC", + "crv": "P-256", + "x": "QaXzjB1aMQRoXcgFTQUneS6EBVaQHQObzaHJjKV6_fM", + "y": "fljC46dVTTQFsyB4Iap7pmTzolhLX2KOtajOI2kEh7g" +} diff --git a/artifacts/client.pub.jwkset b/artifacts/client.pub.jwkset new file mode 100644 index 0000000..cfe313f --- /dev/null +++ b/artifacts/client.pub.jwkset @@ -0,0 +1,13 @@ +{ + "keys": [ + { + "kty": "EC", + "crv": "P-256", + "x": "QaXzjB1aMQRoXcgFTQUneS6EBVaQHQObzaHJjKV6_fM", + "y": "fljC46dVTTQFsyB4Iap7pmTzolhLX2KOtajOI2kEh7g", + "use": "sig", + "kid": "client", + "alg": "ES256" + } + ] +} diff --git a/artifacts/client.pub.pem b/artifacts/client.pub.pem new file mode 100644 index 0000000..0385d7a --- /dev/null +++ b/artifacts/client.pub.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEQaXzjB1aMQRoXcgFTQUneS6EBVaQ +HQObzaHJjKV6/fN+WMLjp1VNNAWzIHghqnumZPOiWEtfYo61qM4jaQSHuA== +-----END PUBLIC KEY----- diff --git a/artifacts/server.priv.jwk b/artifacts/server.priv.jwk new file mode 100644 index 0000000..21c82b7 --- /dev/null +++ b/artifacts/server.priv.jwk @@ -0,0 +1,7 @@ +{ + "kty": "EC", + "crv": "P-256", + "d": "6-YakWKMTt1LEZDlEuuUpKjrMuhpYEaFeors8RKdxr8", + "x": "-e56Pjr4gW6fk73WGO1hyldhEG7X4pnkD_U6Tclqe58", + "y": "RgLVVgsLbPeGZEZs2_9buxp6f8RqsJza37JQJZOySCM" +} diff --git a/artifacts/server.priv.jwkset b/artifacts/server.priv.jwkset new file mode 100644 index 0000000..7465b13 --- /dev/null +++ b/artifacts/server.priv.jwkset @@ -0,0 +1,14 @@ +{ + "keys": [ + { + "kty": "EC", + "crv": "P-256", + "d": "6-YakWKMTt1LEZDlEuuUpKjrMuhpYEaFeors8RKdxr8", + "x": "-e56Pjr4gW6fk73WGO1hyldhEG7X4pnkD_U6Tclqe58", + "y": "RgLVVgsLbPeGZEZs2_9buxp6f8RqsJza37JQJZOySCM", + "use": "sig", + "kid": "server", + "alg": "ES256" + } + ] +} diff --git a/artifacts/server.priv.pem b/artifacts/server.priv.pem new file mode 100644 index 0000000..d4cbd2d --- /dev/null +++ b/artifacts/server.priv.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIOvmGpFijE7dSxGQ5RLrlKSo6zLoaWBGhXqK7PESnca/oAoGCCqGSM49 +AwEHoUQDQgAE+e56Pjr4gW6fk73WGO1hyldhEG7X4pnkD/U6Tclqe59GAtVWCwts +94ZkRmzb/1u7Gnp/xGqwnNrfslAlk7JIIw== +-----END EC PRIVATE KEY----- diff --git a/artifacts/server.pub.jwk b/artifacts/server.pub.jwk new file mode 100644 index 0000000..db11dae --- /dev/null +++ b/artifacts/server.pub.jwk @@ -0,0 +1,6 @@ +{ + "kty": "EC", + "crv": "P-256", + "x": "-e56Pjr4gW6fk73WGO1hyldhEG7X4pnkD_U6Tclqe58", + "y": "RgLVVgsLbPeGZEZs2_9buxp6f8RqsJza37JQJZOySCM" +} diff --git a/artifacts/server.pub.jwkset b/artifacts/server.pub.jwkset new file mode 100644 index 0000000..07c7be5 --- /dev/null +++ b/artifacts/server.pub.jwkset @@ -0,0 +1,13 @@ +{ + "keys": [ + { + "kty": "EC", + "crv": "P-256", + "x": "-e56Pjr4gW6fk73WGO1hyldhEG7X4pnkD_U6Tclqe58", + "y": "RgLVVgsLbPeGZEZs2_9buxp6f8RqsJza37JQJZOySCM", + "use": "sig", + "kid": "server", + "alg": "ES256" + } + ] +} diff --git a/artifacts/server.pub.pem b/artifacts/server.pub.pem new file mode 100644 index 0000000..a3ace8a --- /dev/null +++ b/artifacts/server.pub.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE+e56Pjr4gW6fk73WGO1hyldhEG7X +4pnkD/U6Tclqe59GAtVWCwts94ZkRmzb/1u7Gnp/xGqwnNrfslAlk7JIIw== +-----END PUBLIC KEY----- diff --git a/lib/conformance/auth_controller.ex b/lib/conformance/auth_controller.ex index 4a2d91c..4ca6362 100644 --- a/lib/conformance/auth_controller.ex +++ b/lib/conformance/auth_controller.ex @@ -4,6 +4,8 @@ defmodule Conformance.AuthController do require Logger + alias Oidcc.ClientContext + alias Oidcc.ProviderConfiguration alias Oidcc.Token plug Oidcc.Plug.AuthorizationCallback, @@ -11,6 +13,8 @@ defmodule Conformance.AuthController do provider: Conformance.ConfigWorker, client_id: &Conformance.RegisterClient.client_id/0, client_secret: &Conformance.RegisterClient.client_secret/0, + client_context_opts: &Conformance.RegisterClient.client_context_opts/0, + client_profile_opts: Conformance.RegisterClient.client_profile_opts(), redirect_uri: &__MODULE__.redirect_url/0 ] when action in [:callback] @@ -20,6 +24,8 @@ defmodule Conformance.AuthController do provider: Conformance.ConfigWorker, client_id: &Conformance.RegisterClient.client_id/0, client_secret: &Conformance.RegisterClient.client_secret/0, + client_context_opts: &Conformance.RegisterClient.client_context_opts/0, + client_profile_opts: Conformance.RegisterClient.client_profile_opts(), redirect_uri: &__MODULE__.redirect_url/0, scopes: ["openid", "profile"] ] @@ -44,50 +50,52 @@ defmodule Conformance.AuthController do Logger.info("Retrieved Token: #{inspect(token, pretty: true)}") Logger.info("Retrieved Userinfo: #{inspect(userinfo, pretty: true)}") - case Oidcc.ProviderConfiguration.Worker.get_provider_configuration(Conformance.ConfigWorker) do - %Oidcc.ProviderConfiguration{end_session_endpoint: :undefined} -> - conn = - with {:ok, {refreshed_token, refreshed_userinfo}} <- maybe_refresh(token) do - send_resp( - conn, - 200, - inspect( - %{ - token: token, - userinfo: userinfo, - refreshed_token: refreshed_token, - refreshed_userinfo: refreshed_userinfo - }, - pretty: true - ) + provider_configuration = + Oidcc.ProviderConfiguration.Worker.get_provider_configuration(Conformance.ConfigWorker) + + {:ok, client_context} = + ClientContext.from_configuration_worker( + Conformance.ConfigWorker, + Conformance.RegisterClient.client_id(), + Conformance.RegisterClient.client_secret(), + Conformance.RegisterClient.client_context_opts() + ) + + conn = + with {:ok, {refreshed_token, refreshed_userinfo}} <- + maybe_refresh(token, provider_configuration), + {:ok, accounts_response} <- maybe_call_accounts(token, client_context) do + Logger.info("Refreshed Token: #{inspect(refreshed_token, pretty: true)}") + Logger.info("Refreshed Userinfo: #{inspect(refreshed_userinfo, pretty: true)}") + Logger.info("Accounts Response: #{inspect(accounts_response, pretty: true)}") + + if is_binary(provider_configuration.end_session_endpoint) do + target_uri = url(~p"/logged-out") + + {:ok, redirect_uri} = + Oidcc.initiate_logout_url( + token, + Conformance.ConfigWorker, + Conformance.RegisterClient.client_id(), + %{post_logout_redirect_uri: target_uri, state: "example_state"} ) - else - {:error, reason} -> error_response(conn, reason) - end - spawn(fn -> - Process.sleep(2_000) + redirect(conn, external: IO.iodata_to_binary(redirect_uri)) + else + send_resp(conn, 200, "OK") + end + else + {:error, reason} -> error_response(conn, reason) + end - Conformance.Screenshot.take() - Process.send(Conformance.Runner, :stop, []) - end) - - conn - - %Oidcc.ProviderConfiguration{} -> - target_uri = url(~p"/logged-out") + spawn(fn -> + Process.sleep(2_000) - {:ok, redirect_uri} = - Oidcc.initiate_logout_url( - token, - Conformance.ConfigWorker, - Conformance.RegisterClient.client_id(), - Conformance.RegisterClient.client_secret(), - %{post_logout_redirect_uri: target_uri, state: "example_state"} - ) + Conformance.Screenshot.take() + Process.send(Conformance.Runner, :stop, []) + end) - redirect(conn, external: IO.iodata_to_binary(redirect_uri)) - end + conn end def callback( @@ -131,30 +139,62 @@ defmodule Conformance.AuthController do send_resp(conn, 200, inspect(%{params: params}, pretty: true)) end - defp maybe_refresh(%Token{refresh: %Token.Refresh{token: _refresh_token}} = token) do - with {:ok, token} <- - Oidcc.refresh_token( - token, - Conformance.ConfigWorker, - Conformance.RegisterClient.client_id(), - Conformance.RegisterClient.client_secret() - ), - {:ok, userinfo} <- - Oidcc.retrieve_userinfo( - token, - Conformance.ConfigWorker, - Conformance.RegisterClient.client_id(), - Conformance.RegisterClient.client_secret(), - %{} - ) do - Logger.info("Retrieved Token: #{inspect(token, pretty: true)}") - Logger.info("Retrieved Userinfo: #{inspect(userinfo, pretty: true)}") - - {:ok, {token, userinfo}} + defp maybe_refresh( + %Token{refresh: %Token.Refresh{token: _refresh_token}} = token, + %ProviderConfiguration{grant_types_supported: grant_types_supported} + ) do + if "refresh_token" in grant_types_supported do + with {:ok, token} <- + Oidcc.refresh_token( + token, + Conformance.ConfigWorker, + Conformance.RegisterClient.client_id(), + Conformance.RegisterClient.client_secret() + ), + {:ok, userinfo} <- + Oidcc.retrieve_userinfo( + token, + Conformance.ConfigWorker, + Conformance.RegisterClient.client_id(), + Conformance.RegisterClient.client_secret(), + %{} + ) do + Logger.info("Retrieved Token: #{inspect(token, pretty: true)}") + Logger.info("Retrieved Userinfo: #{inspect(userinfo, pretty: true)}") + + {:ok, {token, userinfo}} + end + else + {:ok, {nil, nil}} end end - defp maybe_refresh(%Token{}), do: {:ok, {nil, nil}} + defp maybe_refresh(%Token{}, _config), do: {:ok, {nil, nil}} + + defp maybe_call_accounts(token, client_context) do + accounts_uri = Application.get_env(:conformance, :call_accounts, false) + + if accounts_uri do + headers = + :oidcc_auth_util.add_authorization_header( + token.access.token, + token.access.type, + :get, + accounts_uri, + %{}, + ClientContext.struct_to_record(client_context) + ) + + :oidcc_http_util.request( + :get, + {accounts_uri, headers}, + %{topic: [:conformance, :accounts]}, + %{} + ) + else + {:ok, nil} + end + end defp error_response(conn, reason) do Logger.error("OIDC Error: #{inspect(reason, pretty: true)}") diff --git a/lib/conformance/endpoint.ex b/lib/conformance/endpoint.ex index 4879bad..60eb72e 100644 --- a/lib/conformance/endpoint.ex +++ b/lib/conformance/endpoint.ex @@ -18,11 +18,11 @@ defmodule Conformance.Endpoint do plug(Conformance.Router) - @impl Phoenix.Endpoint def init(_context, config) do - %URI{host: host, port: port, scheme: scheme} = - URI.new!(Ngrok.public_url(Conformance.Ngrok)) + # %URI{host: host, port: port, scheme: scheme} = + # URI.new!(Ngrok.public_url(Conformance.Ngrok)) - {:ok, Keyword.put(config, :url, path: "/", host: host, port: port, scheme: scheme)} + # {:ok, Keyword.put(config, :url, path: "/", host: host, port: port, scheme: scheme)} + {:ok, config} end end diff --git a/lib/conformance/log_configuration.ex b/lib/conformance/log_configuration.ex index e037351..4f0ecaf 100644 --- a/lib/conformance/log_configuration.ex +++ b/lib/conformance/log_configuration.ex @@ -10,7 +10,10 @@ defmodule Conformance.LogConfiguration do ref = :telemetry_test.attach_event_handlers(self(), [ [:oidcc, :load_configuration, :stop], - [:oidcc, :load_jwks, :stop] + [:oidcc, :load_jwks, :stop], + [:oidcc, :par_request, :start], + [:oidcc, :par_request, :stop], + [:oidcc, :par_request, :exception] ]) {:ok, ref} @@ -40,4 +43,9 @@ defmodule Conformance.LogConfiguration do {:noreply, ref} end + + def handle_info({[:oidcc | _topic], ref, _measurement, _meta} = event, ref) do + Logger.info("Event Received: #{inspect(event, pretty: true)}") + {:noreply, ref} + end end diff --git a/lib/conformance/register_client.ex b/lib/conformance/register_client.ex index 763960e..d3e71b2 100644 --- a/lib/conformance/register_client.ex +++ b/lib/conformance/register_client.ex @@ -38,6 +38,31 @@ defmodule Conformance.RegisterClient do def handle_call(:client_secret, _from, {client_id, client_secret}), do: {:reply, client_secret, {client_id, client_secret}} - def client_id, do: GenServer.call(__MODULE__, :client_id) - def client_secret, do: GenServer.call(__MODULE__, :client_secret) + def client_id do + if GenServer.whereis(__MODULE__) do + GenServer.call(__MODULE__, :client_id) + else + "client_id" + end + end + + def client_secret do + if GenServer.whereis(__MODULE__) do + GenServer.call(__MODULE__, :client_secret) + else + "client_secret" + end + end + + def client_context_opts do + %{ + client_jwks: JOSE.JWK.from_file("./artifacts/client.priv.jwkset") + } + end + + def client_profile_opts do + %{ + profiles: [:fapi2_security_profile] + } + end end diff --git a/lib/conformance/supervisor.ex b/lib/conformance/supervisor.ex index a90e2b3..e1c3045 100644 --- a/lib/conformance/supervisor.ex +++ b/lib/conformance/supervisor.ex @@ -26,7 +26,17 @@ defmodule Conformance.Supervisor do {Oidcc.ProviderConfiguration.Worker, %{ issuer: "https://www.certification.openid.net/test/a/#{alias_name}/", - name: Conformance.ConfigWorker + name: Conformance.ConfigWorker, + provider_configuration_opts: %{ + quirks: %{ + document_overrides: %{ + # https://gitlab.com/openid/conformance-suite/-/issues/1323 + "subject_types_supported" => ["pairwise", "public"], + # https://gitlab.com/openid/conformance-suite/-/issues/1324 + "code_challenge_methods_supported" => ["S256"] + } + } + } }}, if(register_client?, do: {Conformance.RegisterClient, register_client_opts}), unless(start_server?, do: Conformance.AutoStopper) diff --git a/lib/mix/tasks/run_certification.ex b/lib/mix/tasks/run_certification.ex index 719799f..aeb3c23 100644 --- a/lib/mix/tasks/run_certification.ex +++ b/lib/mix/tasks/run_certification.ex @@ -19,7 +19,8 @@ defmodule Mix.Tasks.RunCertification do auto_stop: :boolean, auto_open: :boolean, auto_screenshot: :boolean, - token_endpoint_auth_method: :string + token_endpoint_auth_method: :string, + call_accounts: :string ] @project_root __ENV__.file |> Path.dirname() |> Path.join("../../..") |> Path.expand() @@ -47,7 +48,8 @@ defmodule Mix.Tasks.RunCertification do auto_stop: auto_stop?, auto_open: auto_open?, auto_screenshot: auto_screenshot?, - token_endpoint_auth_method: token_endpoint_auth_method + token_endpoint_auth_method: token_endpoint_auth_method, + call_accounts: call_accounts } = opts |> Keyword.put_new(:alias, "test") @@ -68,6 +70,7 @@ defmodule Mix.Tasks.RunCertification do |> Keyword.put_new(:auto_open, false) |> Keyword.put_new(:auto_screenshot, false) |> Keyword.put_new(:token_endpoint_auth_method, "client_secret_basic") + |> Keyword.put_new(:call_accounts, false) |> Map.new() artifact_out_dir = Path.join([@project_root, "test_plans", version, profile]) @@ -90,6 +93,8 @@ defmodule Mix.Tasks.RunCertification do path: Path.join(artifact_out_dir, "#{test_name}.png") ) + Application.put_env(:conformance, :call_accounts, call_accounts) + {:ok, _pid} = Conformance.Supervisor.start_link( alias: alias_name, diff --git a/mix.exs b/mix.exs index 7f3351c..42a90e8 100644 --- a/mix.exs +++ b/mix.exs @@ -19,8 +19,8 @@ defmodule Conformance.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:oidcc, "~> 3.0"}, - {:oidcc_plug, "~> 0.1.0"}, + {:oidcc, "~> 3.2.0"}, + {:oidcc_plug, "~> 0.2.0-beta"}, {:plug_cowboy, "~> 2.5"}, {:phoenix, "~> 1.7"}, {:jason, "~> 1.4"}, diff --git a/mix.lock b/mix.lock index e1bd81c..4f8547c 100644 --- a/mix.lock +++ b/mix.lock @@ -1,31 +1,31 @@ %{ - "castore": {:hex, :castore, "1.0.3", "7130ba6d24c8424014194676d608cb989f62ef8039efd50ff4b3f33286d06db8", [:mix], [], "hexpm", "680ab01ef5d15b161ed6a95449fac5c6b8f60055677a8e79acf01b27baa4390b"}, - "cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"}, + "castore": {:hex, :castore, "1.0.7", "b651241514e5f6956028147fe6637f7ac13802537e895a724f90bf3e36ddd1dd", [:mix], [], "hexpm", "da7785a4b0d2a021cd1292a60875a784b6caef71e76bf4917bdee1f390455cf5"}, + "cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, - "cowlib": {:hex, :cowlib, "2.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"}, - "finch": {:hex, :finch, "0.16.0", "40733f02c89f94a112518071c0a91fe86069560f5dbdb39f9150042f44dcfb1a", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f660174c4d519e5fec629016054d60edd822cdfe2b7270836739ac2f97735ec5"}, - "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, + "cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"}, + "finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"}, + "hpax": {:hex, :hpax, "0.2.0", "5a58219adcb75977b2edce5eb22051de9362f08236220c9e859a47111c194ff5", [:mix], [], "hexpm", "bea06558cdae85bed075e6c036993d43cd54d447f76d8190a8db0dc5893fa2f1"}, "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, - "jose": {:hex, :jose, "1.11.6", "613fda82552128aa6fb804682e3a616f4bc15565a048dabd05b1ebd5827ed965", [:mix, :rebar3], [], "hexpm", "6275cb75504f9c1e60eeacb771adfeee4905a9e182103aa59b53fed651ff9738"}, - "logger_file_backend": {:hex, :logger_file_backend, "0.0.13", "df07b14970e9ac1f57362985d76e6f24e3e1ab05c248055b7d223976881977c2", [:mix], [], "hexpm", "71a453a7e6e899ae4549fb147b1c6621f4233f8f48f58ca10a64ec67b6c50018"}, + "jose": {:hex, :jose, "1.11.10", "a903f5227417bd2a08c8a00a0cbcc458118be84480955e8d251297a425723f83", [:mix, :rebar3], [], "hexpm", "0d6cd36ff8ba174db29148fc112b5842186b68a90ce9fc2b3ec3afe76593e614"}, + "logger_file_backend": {:hex, :logger_file_backend, "0.0.14", "774bb661f1c3fed51b624d2859180c01e386eb1273dc22de4f4a155ef749a602", [:mix], [], "hexpm", "071354a18196468f3904ef09413af20971d55164267427f6257b52cfba03f9e6"}, "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, - "mint": {:hex, :mint, "1.5.1", "8db5239e56738552d85af398798c80648db0e90f343c8469f6c6d8898944fb6f", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "4a63e1e76a7c3956abd2c72f370a0d0aecddc3976dea5c27eccbecfa5e7d5b1e"}, + "mint": {:hex, :mint, "1.6.0", "88a4f91cd690508a04ff1c3e28952f322528934be541844d54e0ceb765f01d5e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "3c5ae85d90a5aca0a49c0d8b67360bbe407f3b54f1030a111047ff988e8fefaa"}, "ngrok": {:hex, :ngrok, "1.1.0", "7fc6a0ed419ab79fae11dcbf65a14b7a4655d10a861e28ce9d2b110f0bf182dc", [:mix], [{:rambo, "~> 0.3.4", [hex: :rambo, repo: "hexpm", optional: false]}, {:req, "~> 0.3.5", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "e7464b31ef109062da61250633d2d13f92abc8202eed62a597105db367ee7108"}, - "nimble_options": {:hex, :nimble_options, "1.0.2", "92098a74df0072ff37d0c12ace58574d26880e522c22801437151a159392270e", [:mix], [], "hexpm", "fd12a8db2021036ce12a309f26f564ec367373265b53e25403f0ee697380f1b8"}, - "nimble_pool": {:hex, :nimble_pool, "1.0.0", "5eb82705d138f4dd4423f69ceb19ac667b3b492ae570c9f5c900bb3d2f50a847", [:mix], [], "hexpm", "80be3b882d2d351882256087078e1b1952a28bf98d0a287be87e4a24a710b67a"}, - "oidcc": {:hex, :oidcc, "3.0.0", "19b3df71d1113f339fd5b4885824d7139a8eee9046227b1c85e81da3c6e86d97", [:mix, :rebar3], [{:jose, "~> 1.11", [hex: :jose, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_registry, "~> 0.3.1", [hex: :telemetry_registry, repo: "hexpm", optional: false]}], "hexpm", "37ac460b96562e58938556651d6097a07ecaf89bb1e8c7faaf6066d665c296e4"}, - "oidcc_plug": {:hex, :oidcc_plug, "0.1.0", "048e9461b653191f58c89bcebac899ec02bffd96861f2ac462a1083d40672fcc", [:mix], [{:oidcc, "~> 3.0", [hex: :oidcc, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "f3ad89ac35da544bd567eeecb1317fdf4a06a72ae1b25dc1630eca012e9f0c7c"}, - "phoenix": {:hex, :phoenix, "1.7.7", "4cc501d4d823015007ba3cdd9c41ecaaf2ffb619d6fb283199fa8ddba89191e0", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "8966e15c395e5e37591b6ed0bd2ae7f48e961f0f60ac4c733f9566b519453085"}, + "nimble_options": {:hex, :nimble_options, "1.1.0", "3b31a57ede9cb1502071fade751ab0c7b8dbe75a9a4c2b5bbb0943a690b63172", [:mix], [], "hexpm", "8bbbb3941af3ca9acc7835f5655ea062111c9c27bcac53e004460dfd19008a99"}, + "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, + "oidcc": {:hex, :oidcc, "3.2.0", "f80a4826a946ce07dc8cbd8212392b4ff436ae3c4b4cd6680fa0d84d0ff2fec1", [:mix, :rebar3], [{:jose, "~> 1.11", [hex: :jose, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_registry, "~> 0.3.1", [hex: :telemetry_registry, repo: "hexpm", optional: false]}], "hexpm", "38fd9092ab5d5d10c71b8011b019316411afe466bef07ba57f57ec3f919278c3"}, + "oidcc_plug": {:hex, :oidcc_plug, "0.2.0-beta.1", "770be8fdb467eb95394dd4894f25773cede5d4946f86ef81bff060f8e7387b4f", [:mix], [{:oidcc, "~> 3.2.0", [hex: :oidcc, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "8e95b2a47b603a049b9990d889e22e26c4f130da7f2af72d6cb72e8eefa08d69"}, + "phoenix": {:hex, :phoenix, "1.7.12", "1cc589e0eab99f593a8aa38ec45f15d25297dd6187ee801c8de8947090b5a9d3", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "d646192fbade9f485b01bc9920c139bfdd19d0f8df3d73fd8eaf2dfbe0d2837c"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, - "phoenix_template": {:hex, :phoenix_template, "1.0.3", "32de561eefcefa951aead30a1f94f1b5f0379bc9e340bb5c667f65f1edfa4326", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "16f4b6588a4152f3cc057b9d0c0ba7e82ee23afa65543da535313ad8d25d8e2c"}, - "plug": {:hex, :plug, "1.14.2", "cff7d4ec45b4ae176a227acd94a7ab536d9b37b942c8e8fa6dfc0fff98ff4d80", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "842fc50187e13cf4ac3b253d47d9474ed6c296a8732752835ce4a86acdf68d13"}, - "plug_cowboy": {:hex, :plug_cowboy, "2.6.1", "9a3bbfceeb65eff5f39dab529e5cd79137ac36e913c02067dba3963a26efe9b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "de36e1a21f451a18b790f37765db198075c25875c64834bcc82d90b309eb6613"}, - "plug_crypto": {:hex, :plug_crypto, "1.2.5", "918772575e48e81e455818229bf719d4ab4181fcbf7f85b68a35620f78d89ced", [:mix], [], "hexpm", "26549a1d6345e2172eb1c233866756ae44a9609bd33ee6f99147ab3fd87fd842"}, + "phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"}, + "plug": {:hex, :plug, "1.15.3", "712976f504418f6dff0a3e554c40d705a9bcf89a7ccef92fc6a5ef8f16a30a97", [: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", "cc4365a3c010a56af402e0809208873d113e9c38c401cabd88027ef4f5c01fd2"}, + "plug_cowboy": {:hex, :plug_cowboy, "2.7.1", "87677ffe3b765bc96a89be7960f81703223fe2e21efa42c125fcd0127dd9d6b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "02dbd5f9ab571b864ae39418db7811618506256f6d13b4a45037e5fe78dc5de3"}, + "plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"}, "rambo": {:hex, :rambo, "0.3.4", "8962ac3bd1a633ee9d0e8b44373c7913e3ce3d875b4151dcd060886092d2dce7", [:mix], [], "hexpm", "0cc54ed089fbbc84b65f4b8a774224ebfe60e5c80186fafc7910b3e379ad58f1"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, - "req": {:hex, :req, "0.3.11", "462315e50db6c6e1f61c45e8c0b267b0d22b6bd1f28444c136908dfdca8d515a", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.9", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0e4b331627fedcf90b29aa8064cd5a95619ef6134d5ab13919b6e1c4d7cccd4b"}, + "req": {:hex, :req, "0.3.12", "f84c2f9e7cc71c81d7cbeacf7c61e763e53ab5f3065703792a4ab264b4f22672", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.9", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "c91103d4d1c8edeba90c84e0ba223a59865b673eaab217bfd17da3aa54ab136c"}, "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, "telemetry_registry": {:hex, :telemetry_registry, "0.3.1", "14a3319a7d9027bdbff7ebcacf1a438f5f5c903057b93aee484cca26f05bdcba", [:mix, :rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6d0ca77b691cf854ed074b459a93b87f4c7f5512f8f7743c635ca83da81f939e"}, "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, - "websock_adapter": {:hex, :websock_adapter, "0.5.4", "7af8408e7ed9d56578539594d1ee7d8461e2dd5c3f57b0f2a5352d610ddde757", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "d2c238c79c52cbe223fcdae22ca0bb5007a735b9e933870e241fce66afb4f4ab"}, + "websock_adapter": {:hex, :websock_adapter, "0.5.6", "0437fe56e093fd4ac422de33bf8fc89f7bc1416a3f2d732d8b2c8fd54792fe60", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "e04378d26b0af627817ae84c92083b7e97aca3121196679b73c73b99d0d133ea"}, }