From 01c5a213b3d49914be9db18ec99810a20df71a25 Mon Sep 17 00:00:00 2001 From: Annopaolo Date: Fri, 12 Mar 2021 16:03:49 +0100 Subject: [PATCH] Add typespecs Signed-off-by: Arnaldo Cesco --- lib/cfxxl.ex | 23 +++++++++++++++++++++++ lib/cfxxl/ca_config.ex | 6 ++++++ lib/cfxxl/cert_utils.ex | 10 +++++++++- lib/cfxxl/client.ex | 7 +++++++ lib/cfxxl/dname.ex | 8 ++++++++ lib/cfxxl/key_config.ex | 5 +++++ lib/cfxxl/subject.ex | 5 +++++ mix.exs | 16 ++++++++++++++-- mix.lock | 33 +++++++++++++++++---------------- 9 files changed, 94 insertions(+), 19 deletions(-) diff --git a/lib/cfxxl.ex b/lib/cfxxl.ex index 36cfabf..f34c2f2 100644 --- a/lib/cfxxl.ex +++ b/lib/cfxxl.ex @@ -36,6 +36,8 @@ defmodule CFXXL do @scan_opts [:ip, :timeout, :family, :scanner] @sign_opts [:hosts, :subject, :serial_sequence, :label, :profile, :bundle] + @spec authsign(CFXXL.Client.t(), String.t(), String.t(), keyword() | nil) :: + {:ok, any()} | {:error, any()} @doc """ Request to sign a CSR with authentication. @@ -65,6 +67,7 @@ defmodule CFXXL do post(client, "authsign", body) end + @spec bundle(CFXXL.Client.t(), keyword()) :: {:ok, any()} | {:error, any()} @doc """ Request a certificate bundle @@ -127,6 +130,7 @@ defmodule CFXXL do def bundle(_client, _opts), do: {:error, :no_certificate_or_domain} + @spec certinfo(CFXXL.Client.t(), keyword()) :: {:ok, any()} | {:error, any()} @doc """ Request information about a certificate @@ -161,6 +165,7 @@ defmodule CFXXL do def certinfo(_client, _opts), do: {:error, :no_certificate_or_domain} + @spec crl(CFXXL.Client.t(), String.t() | nil) :: {:ok, any()} | {:error, any()} @doc """ Generate a CRL from the database @@ -181,6 +186,7 @@ defmodule CFXXL do end end + @spec get(CFXXL.Client.t(), String.t(), map() | nil) :: {:ok, any()} | {:error, any()} @doc """ Perform a generic GET to the CFSSL API. @@ -199,6 +205,7 @@ defmodule CFXXL do |> process_response() end + @spec info(CFXXL.Client.t(), String.t(), keyword() | nil) :: {:ok, any()} | {:error, any()} @doc """ Get signer information @@ -225,6 +232,8 @@ defmodule CFXXL do post(client, "info", body) end + @spec init_ca(CFXXL.Client.t(), list(String.t()), CFXXL.DName.t(), keyword() | nil) :: + {:ok, any()} | {:error, any()} @doc """ Request a new CA key/certificate pair. @@ -253,6 +262,8 @@ defmodule CFXXL do post(client, "init_ca", body) end + @spec newcert(CFXXL.Client.t(), list(String.t()), CFXXL.DName.t(), keyword() | nil) :: + {:ok, any()} | {:error, any()} @doc """ Request a new key/signed certificate pair. @@ -285,6 +296,8 @@ defmodule CFXXL do post(client, "newcert", body) end + @spec newkey(CFXXL.Client.t(), list(String.t()), CFXXL.DName.t(), keyword() | nil) :: + {:ok, any()} | {:error, any()} @doc """ Request a new key/CSR pair. @@ -309,6 +322,7 @@ defmodule CFXXL do post(client, "newkey", body) end + @spec post(CFXXL.Client.t(), String.t(), map()) :: {:ok, any()} | {:error, any()} @doc """ Perform a generic POST to the CFSSL API. @@ -328,6 +342,7 @@ defmodule CFXXL do |> process_response() end + @spec revoke(CFXXL.Client.t(), String.t(), String.t(), String.t()) :: :ok | {:error, any()} @doc """ Request to revoke a certificate. @@ -351,6 +366,7 @@ defmodule CFXXL do end end + @spec scan(CFXXL.Client.t(), String.t(), keyword() | nil) :: {:ok, any()} | {:error, any()} @doc """ Scan an host @@ -378,6 +394,7 @@ defmodule CFXXL do get(client, "scan", params) end + @spec scaninfo(CFXXL.Client.t()) :: {:ok, any()} | {:error, any()} @doc """ Get information on scan families @@ -392,6 +409,7 @@ defmodule CFXXL do get(client, "scaninfo") end + @spec sign(CFXXL.Client.t(), String.t(), keyword() | nil) :: {:ok, any()} | {:error, any()} @doc """ Request to sign a CSR. @@ -426,6 +444,8 @@ defmodule CFXXL do defp process_response({:error, _} = response), do: response defp process_response({:ok, %HTTPoison.Response{body: body}}), do: extract_result(body) + @spec extract_result(iodata) :: + {:ok, any()} | {:error, any()} defp extract_result(""), do: {:error, :empty_response} defp extract_result(body) do @@ -436,6 +456,7 @@ defmodule CFXXL do end end + @spec extract_error_message(%{required(String.t()) => list()}) :: any() defp extract_error_message(%{"errors" => errors}) do case errors do [%{"message" => msg} | _] -> msg @@ -443,12 +464,14 @@ defmodule CFXXL do end end + @spec normalize_aki(String.t()) :: String.t() defp normalize_aki(aki) do aki |> String.downcase() |> String.replace(":", "") end + @spec filter_opts(list(), list()) :: list() defp filter_opts(opts, accepted_opts) do opts |> Enum.filter(fn {k, _} -> k in accepted_opts end) diff --git a/lib/cfxxl/ca_config.ex b/lib/cfxxl/ca_config.ex index d1cff63..0b5847c 100644 --- a/lib/cfxxl/ca_config.ex +++ b/lib/cfxxl/ca_config.ex @@ -32,6 +32,12 @@ defmodule CFXXL.CAConfig do """ defstruct [:pathlength, :pathlenzero, :expiry] + @type t() :: %__MODULE__{ + pathlength: non_neg_integer(), + pathlenzero: boolean(), + expiry: String.t() + } + defimpl Jason.Encoder, for: CFXXL.CAConfig do def encode(ca_config, options) do # Encode only non-nil values diff --git a/lib/cfxxl/cert_utils.ex b/lib/cfxxl/cert_utils.ex index e6efb0a..b3b7edc 100644 --- a/lib/cfxxl/cert_utils.ex +++ b/lib/cfxxl/cert_utils.ex @@ -63,6 +63,7 @@ defmodule CFXXL.CertUtils do Record.extract(:Validity, from_lib: "public_key/include/public_key.hrl") ) + @spec serial_number!(String.t()) :: String.t() @doc """ Extracts the serial number of a certificate. @@ -77,6 +78,7 @@ defmodule CFXXL.CertUtils do |> to_string() end + @spec authority_key_identifier!(String.t()) :: String.t() @doc """ Extracts the authority key identifier of a certificate. @@ -103,6 +105,7 @@ defmodule CFXXL.CertUtils do end end + @spec common_name!(String.t()) :: String.t() | nil @doc """ Extracts the Common Name of a certificate. @@ -134,6 +137,7 @@ defmodule CFXXL.CertUtils do end end + @spec not_after!(String.t()) :: DateTime.t() @doc """ Extracts the not_after field (expiration) of a certificate. @@ -149,6 +153,7 @@ defmodule CFXXL.CertUtils do |> cert_time_tuple_to_datetime() end + @spec not_before!(String.t()) :: DateTime.t() @doc """ Extracts the not_before field of a certificate. @@ -164,6 +169,8 @@ defmodule CFXXL.CertUtils do |> cert_time_tuple_to_datetime() end + @spec cert_time_tuple_to_datetime({:utcTime | :generalTime, nonempty_list(non_neg_integer())}) :: + DateTime.t() defp cert_time_tuple_to_datetime({:utcTime, [y0, y1 | _rest] = time_charlist}) do short_year = parse_charlist_int([y0, y1]) @@ -201,7 +208,8 @@ defmodule CFXXL.CertUtils do parsed end - defp tbs(cert) do + @spec tbs(binary) :: any + def tbs(cert) do cert |> :public_key.pem_decode() |> hd() diff --git a/lib/cfxxl/client.ex b/lib/cfxxl/client.ex index cca66e3..16f9ce7 100644 --- a/lib/cfxxl/client.ex +++ b/lib/cfxxl/client.ex @@ -30,6 +30,12 @@ defmodule CFXXL.Client do """ defstruct endpoint: "http://localhost:8888/#{@api_prefix}", options: [] + @type t() :: %__MODULE__{ + endpoint: String.t(), + options: HTTPoison.Request.options() + } + + @spec new :: CFXXL.Client.t() @doc """ Returns a default client @@ -42,6 +48,7 @@ defmodule CFXXL.Client do """ def new(), do: %__MODULE__{} + @spec new(String.t(), HTTPoison.Request.options() | nil) :: CFXXL.Client.t() @doc """ Creates a client with the given parameters. diff --git a/lib/cfxxl/dname.ex b/lib/cfxxl/dname.ex index e0b8c2b..7b34ce4 100644 --- a/lib/cfxxl/dname.ex +++ b/lib/cfxxl/dname.ex @@ -33,6 +33,14 @@ defmodule CFXXL.DName do """ defstruct [:C, :L, :O, :OU, :ST] + @type t() :: %__MODULE__{ + C: String.t(), + L: String.t(), + O: String.t(), + OU: String.t(), + ST: String.t() + } + defimpl Jason.Encoder, for: CFXXL.DName do def encode(dname, options) do # Encode only non-nil values diff --git a/lib/cfxxl/key_config.ex b/lib/cfxxl/key_config.ex index 46e3d7a..b642f6a 100644 --- a/lib/cfxxl/key_config.ex +++ b/lib/cfxxl/key_config.ex @@ -43,4 +43,9 @@ defmodule CFXXL.KeyConfig do * 521 """ defstruct algo: :ecdsa, size: 256 + + @type t() :: %__MODULE__{ + algo: :ecdsa | :rsa, + size: pos_integer() + } end diff --git a/lib/cfxxl/subject.ex b/lib/cfxxl/subject.ex index 61aeee9..051402b 100644 --- a/lib/cfxxl/subject.ex +++ b/lib/cfxxl/subject.ex @@ -31,6 +31,11 @@ defmodule CFXXL.Subject do """ defstruct [:CN, :dname] + @type t() :: %__MODULE__{ + CN: String.t(), + dname: CFXXL.DName.t() + } + defimpl Jason.Encoder, for: CFXXL.Subject do def encode(subject, options) do # Encode only non-nil values and substitute dname diff --git a/mix.exs b/mix.exs index 2d598cd..d17c582 100644 --- a/mix.exs +++ b/mix.exs @@ -24,7 +24,10 @@ defmodule CFXXL.Mixfile do "coveralls.detail": :test, "coveralls.post": :test, "coveralls.html": :test - ] + ], + + # Dyalizer cache + dialyzer_cache_directory: dialyzer_cache_directory(Mix.env()) ] end @@ -36,6 +39,14 @@ defmodule CFXXL.Mixfile do [extra_applications: [:logger]] end + defp dialyzer_cache_directory(:ci) do + "dialyzer_cache" + end + + defp dialyzer_cache_directory(_) do + nil + end + # Dependencies can be Hex packages: # # {:my_dep, "~> 0.3.0"} @@ -50,7 +61,8 @@ defmodule CFXXL.Mixfile do {:httpoison, "~> 1.6"}, {:jason, "~> 1.2"}, {:ex_doc, ">= 0.0.0", only: :dev, runtime: false}, - {:excoveralls, "~> 0.12", only: :test} + {:excoveralls, "~> 0.12", only: :test}, + {:dialyzex, github: "Comcast/dialyzex", only: [:dev, :ci]} ] end diff --git a/mix.lock b/mix.lock index f8533ce..84820c6 100644 --- a/mix.lock +++ b/mix.lock @@ -1,18 +1,19 @@ %{ - "certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"}, - "earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm"}, - "ex_doc": {:hex, :ex_doc, "0.21.3", "857ec876b35a587c5d9148a2512e952e24c24345552259464b98bfbb883c7b42", [:mix], [{:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"}, - "excoveralls": {:hex, :excoveralls, "0.12.3", "2142be7cb978a3ae78385487edda6d1aff0e482ffc6123877bb7270a8ffbcfe0", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, - "hackney": {:hex, :hackney, "1.15.2", "07e33c794f8f8964ee86cebec1a8ed88db5070e52e904b8f12209773c1036085", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.5", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, - "httpoison": {:hex, :httpoison, "1.6.2", "ace7c8d3a361cebccbed19c283c349b3d26991eff73a1eaaa8abae2e3c8089b6", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, - "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, - "jason": {:hex, :jason, "1.2.0", "10043418c42d2493d0ee212d3fddd25d7ffe484380afad769a0a38795938e448", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, - "makeup": {:hex, :makeup, "1.0.1", "82f332e461dc6c79dbd82fbe2a9c10d48ed07146f0a478286e590c83c52010b5", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"}, - "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"}, - "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"}, - "nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm"}, - "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"}, - "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm"}, - "unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"}, + "certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "805abd97539caf89ec6d4732c91e62ba9da0cda51ac462380bbd28ee697a8c42"}, + "dialyzex": {:git, "https://github.com/Comcast/dialyzex.git", "cdc7cf71fe6df0ce4cf59e3f497579697a05c989", []}, + "earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm", "8cf8a291ebf1c7b9539e3cddb19e9cef066c2441b1640f13c34c1d3cfc825fec"}, + "ex_doc": {:hex, :ex_doc, "0.21.3", "857ec876b35a587c5d9148a2512e952e24c24345552259464b98bfbb883c7b42", [:mix], [{:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "0db1ee8d1547ab4877c5b5dffc6604ef9454e189928d5ba8967d4a58a801f161"}, + "excoveralls": {:hex, :excoveralls, "0.12.3", "2142be7cb978a3ae78385487edda6d1aff0e482ffc6123877bb7270a8ffbcfe0", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "568a3e616c264283f5dea5b020783ae40eef3f7ee2163f7a67cbd7b35bcadada"}, + "hackney": {:hex, :hackney, "1.15.2", "07e33c794f8f8964ee86cebec1a8ed88db5070e52e904b8f12209773c1036085", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.5", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "e0100f8ef7d1124222c11ad362c857d3df7cb5f4204054f9f0f4a728666591fc"}, + "httpoison": {:hex, :httpoison, "1.6.2", "ace7c8d3a361cebccbed19c283c349b3d26991eff73a1eaaa8abae2e3c8089b6", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "aa2c74bd271af34239a3948779612f87df2422c2fdcfdbcec28d9c105f0773fe"}, + "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "4bdd305eb64e18b0273864920695cb18d7a2021f31a11b9c5fbcd9a253f936e2"}, + "jason": {:hex, :jason, "1.2.0", "10043418c42d2493d0ee212d3fddd25d7ffe484380afad769a0a38795938e448", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "116747dbe057794c3a3e4e143b7c8390b29f634e16c78a7f59ba75bfa6852e7f"}, + "makeup": {:hex, :makeup, "1.0.1", "82f332e461dc6c79dbd82fbe2a9c10d48ed07146f0a478286e590c83c52010b5", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "49736fe5b66a08d8575bf5321d716bac5da20c8e6b97714fec2bcd6febcfa1f8"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "d4b316c7222a85bbaa2fd7c6e90e37e953257ad196dc229505137c5e505e9eff"}, + "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, + "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, + "nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm", "589b5af56f4afca65217a1f3eb3fee7e79b09c40c742fddc1c312b3ac0b3399f"}, + "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"}, + "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm", "13104d7897e38ed7f044c4de953a6c28597d1c952075eb2e328bc6d6f2bfc496"}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm", "1d1848c40487cdb0b30e8ed975e34e025860c02e419cb615d255849f3427439d"}, }