alias Wampex.Crypto
alias Wampex.Roles.Peer.Challenge
- @enforce_keys [:authid, :authmethods, :secret]
- defstruct [:authid, :authmethods, :secret]
-
- @callback handle(challenge :: Challenge.t(), auth :: __MODULE__.t()) :: {binary(), map()}
+ @enforce_keys [:authid, :authmethods]
+ defstruct [:authid, :authmethods, :secret, authextra: %{}]
@type t :: %__MODULE__{
authid: binary(),
authmethods: [binary()],
- secret: binary()
+ secret: binary(),
+ authextra: map()
}
- def handle(
- %Challenge{
- auth_method: "wampcra",
- extra: %{"challenge" => ch, "salt" => salt, "iterations" => it, "keylen" => len}
- },
- auth
- ) do
- {auth
- |> Map.get(:secret)
- |> Crypto.pbkdf2(salt, it, len)
- |> Crypto.hash_challenge(ch), %{}}
+ @callback handle(challenge :: Challenge.t(), auth :: t()) :: {binary(), map()}
+
+ @spec cryptosign(binary(), binary()) :: t()
+ def cryptosign(authid, privkey) do
+ privkey = privkey |> String.upcase() |> Base.decode16!()
+ pubkey = :eddsa |> :crypto.generate_key(:ed25519, privkey) |> elem(0) |> Base.encode16()
+
+ %__MODULE__{authmethods: ~w[cryptosign], authextra: %{pubkey: pubkey}, authid: authid, secret: privkey}
end
- def handle(%Challenge{auth_method: "wampcra", extra: %{"challenge" => ch}}, auth) do
- {auth
- |> Map.get(:secret)
- |> Crypto.hash_challenge(ch), %{}}
+ @spec wampcra(binary(), binary()) :: t()
+ def wampcra(authid, secret), do: %__MODULE__{authmethods: ~w[wampcra], authid: authid, secret: secret}
+
+ @spec password(binary(), binary()) :: t()
+ def password(authid, password), do: %__MODULE__{authid: authid, secret: password, authmethods: ~w[password]}
+
+ def handle(%Challenge{auth_method: "wampcra", extra: %{"challenge" => ch} = xtra}, auth) do
+ xtra
+ |> case do
+ %{"salt" => salt, "iterations" => it, "keylen" => len} ->
+ :sha256 |> :crypto.pbkdf2_hmac(auth.secret, salt, it, len) |> Base.encode64()
+
+ _ ->
+ auth.secret
+ end
+ |> Crypto.hash_challenge(ch)
+ |> then(&{&1, %{}})
+ end
+
+ def handle(%Challenge{auth_method: "password"}, auth) do
+ {auth.secret, %{}}
+ end
+
+ def handle(%Challenge{auth_method: "cryptosign", extra: %{"challenge" => ch}}, auth) do
+ ch_bytes = ch |> String.upcase() |> Base.decode16!()
+ prefix = :eddsa |> :crypto.sign(:none, ch_bytes, [auth.secret, :ed25519]) |> Base.encode16() |> String.downcase()
+
+ {"#{prefix}#{ch}", %{}}
end
end