Skip to content
This repository has been archived by the owner on Oct 30, 2023. It is now read-only.

Commit

Permalink
feat: added ucan token validate function
Browse files Browse the repository at this point in the history
  • Loading branch information
madclaws committed Oct 29, 2023
1 parent c716463 commit 830a17d
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 6 deletions.
5 changes: 5 additions & 0 deletions lib/ex_ucan.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@ defmodule ExUcan do
@moduledoc """
Documentation for `ExUcan`.
"""
alias ExUcan.Plugins.Ed25519
alias ExUcan.Core.Token
alias ExUcan.Core.Structs.Ucan

def create_keypair() do
Ed25519.Keypair.create()
end

@spec build(struct(), map()) :: {:ok, Ucan.t()} | {:error, String.t()}
def build(keypair, _params) do
Token.build(%{
Expand Down
10 changes: 10 additions & 0 deletions lib/ex_ucan/core/plugins.ex
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
defmodule ExUcan.Core.Plugins do

Check warning on line 1 in lib/ex_ucan/core/plugins.ex

View workflow job for this annotation

GitHub Actions / Build and test (1.15.7, 26.0.2)

Modules should have a @moduledoc tag.
alias ExUcan.Plugins.Ed25519.Crypto
# TODO: docs

@spec verify_issuer_alg(String.t(), String.t()) :: boolean()
def verify_issuer_alg(did, jwt_alg) do
end

@spec verify_signature(String.t(), String.t(), String.t()) :: boolean()
def verify_signature(did, data, signature) do
{:ok, public_key} = Crypto.did_to_publickey(did)
IO.inspect(public_key)

Check warning on line 12 in lib/ex_ucan/core/plugins.ex

View workflow job for this annotation

GitHub Actions / Build and test (1.15.7, 26.0.2)

There should be no calls to IO.inspect/1.
IO.inspect(data)

Check warning on line 13 in lib/ex_ucan/core/plugins.ex

View workflow job for this annotation

GitHub Actions / Build and test (1.15.7, 26.0.2)

There should be no calls to IO.inspect/1.
IO.inspect(signature)

Check warning on line 14 in lib/ex_ucan/core/plugins.ex

View workflow job for this annotation

GitHub Actions / Build and test (1.15.7, 26.0.2)

There should be no calls to IO.inspect/1.
:public_key.verify(data, :ignored, signature, {:ed_pub, :ed25519, public_key})
end

@spec parseDidMethod(String.t()) :: String.t()
defp parseDidMethod(did) do

Check warning on line 19 in lib/ex_ucan/core/plugins.ex

View workflow job for this annotation

GitHub Actions / Build and test (1.15.7, 26.0.2)

Function/macro/guard names should be written in snake_case.
parts = String.split(did, ":")
Expand Down
1 change: 0 additions & 1 deletion lib/ex_ucan/core/structs.ex
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,5 @@ defmodule ExUcan.Core.Structs.Ucan do
signature: String.t()
}

@derive Jason.Encoder
defstruct [:header, :payload, :signed_data, :signature]
end
28 changes: 23 additions & 5 deletions lib/ex_ucan/core/token.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ defmodule ExUcan.Core.Token do
@moduledoc """
Creates and manages UCAN tokens
"""
alias ExUcan.Core.Plugins
alias ExUnit.DuplicateDescribeError
alias ExUcan.Core.Structs.UcanHeader
alias ExUcan.Core.Keymaterial
alias ExUcan.Core.Structs.Ucan
Expand Down Expand Up @@ -76,8 +78,17 @@ defmodule ExUcan.Core.Token do
"#{ucan.signed_data}.#{ucan.signature}"
end

# TODO: Refactor thiess
@spec validate(String.t()) :: {:ok, Ucan.t()} | {:error, String.t()}
def validate(encoded_ucan) do
with {:ok, {header, payload}} <- parse_encoded_ucan(encoded_ucan),
false <- is_expired?(payload),
false <- is_too_early?(payload) do
[encoded_header, encoded_payload, encoded_sign] = String.split(encoded_ucan, ".")
{:ok, signature} = Base.url_decode64(encoded_sign, padding: false)
data = "#{encoded_header}.#{encoded_payload}"
Plugins.verify_signature(payload.iss, data, signature)
end
end

defp add_nonce(true), do: Utils.generate_nonce()
Expand All @@ -92,6 +103,7 @@ defmodule ExUcan.Core.Token do

signed_data = "#{encoded_header}.#{encoded_payload}"
signature = Keymaterial.sign(keypair, signed_data)
IO.inspect(signature)

Check warning on line 106 in lib/ex_ucan/core/token.ex

View workflow job for this annotation

GitHub Actions / Build and test (1.15.7, 26.0.2)

There should be no calls to IO.inspect/1.

%Ucan{
header: header,
Expand All @@ -108,8 +120,14 @@ defmodule ExUcan.Core.Token do
|> Base.url_encode64(padding: false)
end

@spec is_expired?() :: boolean()
defp is_expired?() do
@spec is_expired?(UcanPayload.t()) :: boolean()
defp is_expired?(%UcanPayload{} = ucan_payload) do
ucan_payload.exp < DateTime.utc_now() |> DateTime.to_unix()
end

@spec is_too_early?(UcanPayload.t()) :: boolean()
defp is_too_early?(%UcanPayload{nbf: nbf}) do
nbf > DateTime.utc_now() |> DateTime.to_unix()
end

@spec parse_encoded_ucan(String.t()) ::
Expand All @@ -118,11 +136,11 @@ defmodule ExUcan.Core.Token do
opts = [padding: false]

with {:ok, {header, payload, sign}} <- tear_into_parts(encoded_ucan),
{:ok, decoded_header} <- Base.url_decode64(header, opts) |> IO.inspect(),
{:ok, header} <- Jason.decode(decoded_header, keys: :atoms) |> IO.inspect(),
{:ok, decoded_header} <- Base.url_decode64(header, opts),
{:ok, header} <- Jason.decode(decoded_header, keys: :atoms),
{:ok, decoded_payload} <- Base.url_decode64(payload, opts),
{:ok, payload} <- Jason.decode(decoded_payload, keys: :atoms) do
{:ok, struct(UcanHeader, header), struct(UcanPayload, payload)}
{:ok, {struct(UcanHeader, header), struct(UcanPayload, payload)}}
end
end

Expand Down

0 comments on commit 830a17d

Please sign in to comment.