From fe2000600ab015551f11e4667ad3fd37c955737a Mon Sep 17 00:00:00 2001 From: Mike Cifelli Date: Sat, 4 May 2024 15:06:40 -0400 Subject: [PATCH] Allow self-signed certificates for gemini --- lib/chronoscope/gemini/client.ex | 1 + lib/chronoscope/gemini/connection_client.ex | 22 ++++++++++++++++--- lib/chronoscope/nts.ex | 1 + lib/chronoscope/nts/client.ex | 1 + .../nts/key_establishment_client.ex | 2 ++ .../api/v1/gemini/connection_controller.ex | 7 +++++- .../controllers/api/v1/health_controller.ex | 7 +++++- .../v1/nts/key_establishment_controller.ex | 1 + 8 files changed, 37 insertions(+), 5 deletions(-) diff --git a/lib/chronoscope/gemini/client.ex b/lib/chronoscope/gemini/client.ex index 6988553..13fd46c 100644 --- a/lib/chronoscope/gemini/client.ex +++ b/lib/chronoscope/gemini/client.ex @@ -5,6 +5,7 @@ defmodule Chronoscope.Gemini.Client do alias Chronoscope.Gemini.ConnectionClient @interval_in_seconds 30 + @date_time Application.compile_env(:chronoscope, :date_time, DateTime) def start_link(resource: resource, name: name) do diff --git a/lib/chronoscope/gemini/connection_client.ex b/lib/chronoscope/gemini/connection_client.ex index 37a63f2..6a77ddb 100644 --- a/lib/chronoscope/gemini/connection_client.ex +++ b/lib/chronoscope/gemini/connection_client.ex @@ -6,6 +6,7 @@ defmodule Chronoscope.Gemini.ConnectionClient do alias Chronoscope.Gemini.Response @timeout_in_milliseconds 3000 + @ssl Application.compile_env(:chronoscope, :ssl, :ssl) def connect(%{host: host, port: port, path: _} = resource) do @@ -25,9 +26,24 @@ defmodule Chronoscope.Gemini.ConnectionClient do |> @ssl.connect(port, tls_options(host), @timeout_in_milliseconds) end - defp tls_options(_host) do - # TODO - [] + defp tls_options(host) do + host + |> :tls_certificate_check.options() + |> Keyword.put(:verify_fun, {verify_fun(host), nil}) + end + + defp verify_fun(hostname) do + hostname_charlist = String.to_charlist(hostname) + + fn + certificate, {:bad_cert, :selfsigned_peer}, _state -> + :ssl_verify_hostname.verify_fun(certificate, :valid_peer, check_hostname: hostname_charlist) + {:valid, :selfsigned_peer} + + certificate, event, _state -> + IO.inspect(event) + :ssl_verify_hostname.verify_fun(certificate, event, check_hostname: hostname_charlist) + end end defp make_request(socket, url) do diff --git a/lib/chronoscope/nts.ex b/lib/chronoscope/nts.ex index 5866dde..5503a24 100644 --- a/lib/chronoscope/nts.ex +++ b/lib/chronoscope/nts.ex @@ -2,6 +2,7 @@ defmodule Chronoscope.NTS.Behaviour do @callback(key_establishment(host :: String.t(), port :: integer()) :: {:ok, Map.t()}, {:error, any()}) end +# TODO - create macro defmodule Chronoscope.NTS do @behaviour Chronoscope.NTS.Behaviour diff --git a/lib/chronoscope/nts/client.ex b/lib/chronoscope/nts/client.ex index fb20c88..d5b3a84 100644 --- a/lib/chronoscope/nts/client.ex +++ b/lib/chronoscope/nts/client.ex @@ -5,6 +5,7 @@ defmodule Chronoscope.NTS.Client do alias Chronoscope.NTS.KeyEstablishmentClient @interval_in_seconds 30 + @date_time Application.compile_env(:chronoscope, :date_time, DateTime) def start_link(server: server, name: name) do diff --git a/lib/chronoscope/nts/key_establishment_client.ex b/lib/chronoscope/nts/key_establishment_client.ex index cfea965..c6959bf 100644 --- a/lib/chronoscope/nts/key_establishment_client.ex +++ b/lib/chronoscope/nts/key_establishment_client.ex @@ -6,6 +6,7 @@ defmodule Chronoscope.NTS.KeyEstablishmentClient do alias Chronoscope.NTS.KeyEstablishmentResponse @timeout_in_milliseconds 3000 + @ssl Application.compile_env(:chronoscope, :ssl, :ssl) def key_establishment(%{host: host, port: port}) do @@ -35,6 +36,7 @@ defmodule Chronoscope.NTS.KeyEstablishmentClient do :ok = @ssl.send(socket, KeyEstablishmentRequest.create()) {:ok, peercert} = @ssl.peercert(socket) + # TODO - refactor? receive do {:ssl, _socket, response} -> @ssl.close(socket) diff --git a/lib/chronoscope_web/controllers/api/v1/gemini/connection_controller.ex b/lib/chronoscope_web/controllers/api/v1/gemini/connection_controller.ex index c4fba0b..d10bc7a 100644 --- a/lib/chronoscope_web/controllers/api/v1/gemini/connection_controller.ex +++ b/lib/chronoscope_web/controllers/api/v1/gemini/connection_controller.ex @@ -8,6 +8,7 @@ defmodule ChronoscopeWeb.API.V1.Gemini.ConnectionController do @default_port 1965 @default_path "/" @max_host_length 255 + @gemini Application.compile_env(:chronoscope, :gemini, Gemini) def get(conn, %{"host" => host, "port" => port, "path" => path}) do @@ -23,7 +24,11 @@ defmodule ChronoscopeWeb.API.V1.Gemini.ConnectionController do end def get(conn, %{"host" => host, "port" => port}) do - handle_get(conn, %{host: host, port: port, path: @default_path}) + try do + handle_get(conn, %{host: host, port: String.to_integer(port), path: @default_path}) + rescue + ArgumentError -> bad_request_response(conn, "invalid port") + end end def get(conn, %{"host" => host}) do diff --git a/lib/chronoscope_web/controllers/api/v1/health_controller.ex b/lib/chronoscope_web/controllers/api/v1/health_controller.ex index 1562ecd..36553ff 100644 --- a/lib/chronoscope_web/controllers/api/v1/health_controller.ex +++ b/lib/chronoscope_web/controllers/api/v1/health_controller.ex @@ -1,9 +1,14 @@ defmodule ChronoscopeWeb.API.V1.HealthController do use ChronoscopeWeb, :controller + alias Chronoscope.Gemini alias Chronoscope.NTS def get(conn, _params) do - json(conn, %{healthy: NTS.healthy?()}) + json(conn, %{healthy: healthy?()}) + end + + defp healthy?() do + NTS.healthy?() && Gemini.healthy?() end end diff --git a/lib/chronoscope_web/controllers/api/v1/nts/key_establishment_controller.ex b/lib/chronoscope_web/controllers/api/v1/nts/key_establishment_controller.ex index 1bcc51c..7fa4944 100644 --- a/lib/chronoscope_web/controllers/api/v1/nts/key_establishment_controller.ex +++ b/lib/chronoscope_web/controllers/api/v1/nts/key_establishment_controller.ex @@ -7,6 +7,7 @@ defmodule ChronoscopeWeb.API.V1.NTS.KeyEstablishmentController do @default_port 4460 @max_host_length 255 + @nts Application.compile_env(:chronoscope, :nts, NTS) def get(conn, %{"host" => host, "port" => port}) do