chronoscope/lib/chronoscope_web/controllers/api/nts/key_exchange_controller.ex

64 lines
1.9 KiB
Elixir

defmodule ChronoscopeWeb.API.NTS.KeyExchangeController do
use ChronoscopeWeb, :controller
require Logger
@default_port "4460"
@timeout_in_milliseconds 3000
def get(conn, params) do
host = to_charlist(params["host"])
port = String.to_integer(params["port"] || @default_port)
tls_options = :tls_certificate_check.options(host) ++ [alpn_advertised_protocols: ["ntse/1"]]
case :ssl.connect(host, port, tls_options, @timeout_in_milliseconds) do
{:ok, socket} ->
key_exchange_request =
<<0x80, 0x01, 0x00, 0x02, 0x00, 0x00, 0x80, 0x04, 0x00, 0x04, 0x00, 0x1E, 0x00, 0x0F,
0x80, 0x00, 0x00, 0x00>>
:ok = :ssl.send(socket, key_exchange_request)
receive do
{:ssl, _socket, data} ->
:ssl.close(socket)
ok_response(conn, %{status: :ok, response: parse_response(data)})
msg ->
:ssl.close(socket)
Logger.error("received unexpected message: #{inspect(msg)}")
ok_response(conn, %{status: :error, reason: :no_response})
after
@timeout_in_milliseconds ->
:ssl.close(socket)
Logger.error("timed out waiting for response")
ok_response(conn, %{status: :error, reason: :timeout})
end
{:error, {:tls_alert, {:handshake_failure, error}}} ->
ok_response(conn, %{status: :error, reason: to_string(error)})
{:error, error} ->
ok_response(conn, %{status: :error, reason: inspect(error)})
error ->
ok_response(conn, %{status: :error, reason: inspect(error)})
end
end
defp parse_response([0x80 | _] = _data) do
"success"
end
defp parse_response(_data) do
"failure"
end
defp ok_response(conn, body) do
conn
|> Plug.Conn.put_resp_content_type("application/json")
|> Plug.Conn.send_resp(:ok, Jason.encode!(body))
end
end