defmodule Kadena.Types.KeyPair do
@moduledoc """
`KeyPair` struct definition.
"""
alias Kadena.Types.Cap
@behaviour Kadena.Types.Spec
@type key :: String.t()
@type clist :: list(Cap.t()) | nil
@type arg_type :: atom()
@type arg_value :: key() | clist()
@type arg :: {arg_type(), arg_value()}
@type arg_validation :: {:ok, arg_value()} | {:error, Keyword.t()}
@type validated_keypair :: t() | {:error, Keyword.t()}
@type t :: %__MODULE__{pub_key: key(), secret_key: key(), clist: clist()}
defstruct [:pub_key, :secret_key, :clist]
@impl true
def new(args) when is_list(args) do
pub_key_arg = Keyword.get(args, :pub_key)
secret_key_arg = Keyword.get(args, :secret_key)
clist_arg = Keyword.get(args, :clist)
with {:ok, pub_key} <- validate_key({:pub_key, pub_key_arg}),
{:ok, secret_key} <- validate_key({:secret_key, secret_key_arg}),
{:ok, clist} <- validate_caps_list({:clist, clist_arg}) do
%__MODULE__{pub_key: pub_key, secret_key: secret_key, clist: clist}
end
end
def new(_args), do: {:error, [args: :not_a_list]}
@spec add_caps(keypair :: t(), caps :: clist()) :: validated_keypair()
def add_caps(%__MODULE__{} = keypair, caps) do
case validate_caps_list({:clist, caps}) do
{:ok, _any = caps} -> %{keypair | clist: caps}
{:error, reason} -> {:error, reason}
end
end
@spec validate_key(arg :: arg()) :: arg_validation()
defp validate_key({_arg, key}) when is_binary(key) and byte_size(key) == 64, do: {:ok, key}
defp validate_key({arg, _key}), do: {:error, [{arg, :invalid}]}
@spec validate_caps_list(arg :: arg()) :: arg_validation()
defp validate_caps_list({_arg, nil}), do: {:ok, nil}
defp validate_caps_list({_arg, [%Cap{} | _tail] = clist}), do: {:ok, clist}
defp validate_caps_list({arg, _clist}), do: {:error, [{arg, :invalid}]}
end