zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

did.ex (4318B)


      1 # Zenflows is designed to implement the Valueflows vocabulary,
      2 # written and maintained by srfsh <info@dyne.org>.
      3 # Copyright (C) 2021-2023 Dyne.org foundation <foundation@dyne.org>.
      4 #
      5 # This program is free software: you can redistribute it and/or modify
      6 # it under the terms of the GNU Affero General Public License as published by
      7 # the Free Software Foundation, either version 3 of the License, or
      8 # (at your option) any later version.
      9 #
     10 # This program is distributed in the hope that it will be useful,
     11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 # GNU Affero General Public License for more details.
     14 #
     15 # You should have received a copy of the GNU Affero General Public License
     16 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
     17 
     18 defmodule Zenflows.DID do
     19 @moduledoc """
     20 A module to interact with the did controller instances over HTTPS.
     21 """
     22 
     23 alias Zenflows.VF.Person
     24 
     25 def child_spec(_) do
     26 		Supervisor.child_spec(
     27 			{Zenflows.HTTPC,
     28 				name: __MODULE__,
     29 				scheme: scheme(),
     30 				host: host(),
     31 				port: port(),
     32 			},
     33 			id: __MODULE__)
     34 end
     35 
     36 # Execute a Zencode specified by `name` with JSON data `data`.
     37 @spec exec(String.t(), map()) :: {:ok, map()} | {:error, term()}
     38 defp exec(name, post_data) do
     39 	Zenflows.Restroom.request(&Zenflows.HTTPC.request(__MODULE__, &1, &2, &3, &4),
     40 		"/v1/sandbox/#{name}", post_data)
     41 end
     42 
     43 @spec did_id(Person.t()) :: String.t()
     44 defp did_id(person) do
     45 	"did:dyne:ifacer:#{person.eddsa_public_key}"
     46 end
     47 
     48 @spec get_did(Person.t()) :: {:ok, map()} | {:error, term()}
     49 def get_did(person) do
     50 	with {:ok, %{status: stat, data: body}} when stat == 200 <-
     51 			Zenflows.HTTPC.request(__MODULE__, "GET",
     52 				"/dids/#{did_id(person)}") do
     53 		case Jason.decode(body) do
     54 			{:ok, data} -> {:ok, %{"created" => false, "did" => data}}
     55 			{:error, err} -> {:error, err}
     56 		end
     57 	else
     58 		_err -> {:error, "DID not found"}
     59 	end
     60 end
     61 
     62 @spec request_new_did(Person.t()) :: {:ok, map()} | {:error, term()}
     63 def request_new_did(person) do
     64 	did_request = %{
     65 		"proof" => %{
     66 			"type" => "EcdsaSecp256k1Signature2019",
     67 			"proofPurpose" => "assertionMethod"
     68 		},
     69 		"@context" => [
     70 			"https://www.w3.org/ns/did/v1",
     71 			"https://w3id.org/security/suites/ed25519-2018/v1",
     72 			"https://w3id.org/security/suites/secp256k1-2019/v1",
     73 			"https://w3id.org/security/suites/secp256k1-2020/v1",
     74 			"https://dyne.github.io/W3C-DID/specs/ReflowBLS12381.json",
     75 			%{
     76 				"description" => "https://schema.org/description",
     77 				"identifier" => "https://schema.org/identifier"
     78 			}
     79 		],
     80 		"did_spec" => "ifacer",
     81 		"signer_did_spec" => "ifacer.A",
     82 		"identity" => "Ifacer user test",
     83 		"ifacer_id" => %{"identifier" => person.id},
     84 		"bitcoin_public_key" => person.bitcoin_public_key,
     85 		"ecdh_public_key" => person.ecdh_public_key,
     86 		"eddsa_public_key" => person.eddsa_public_key,
     87 		"ethereum_address" => person.ethereum_address,
     88 		"reflow_public_key" => person.reflow_public_key,
     89 		"timestamp" =>
     90 			DateTime.utc_now() |> DateTime.to_unix(:millisecond) |> to_string
     91 	}
     92 
     93 	with {:ok, did} <-
     94 		Zenflows.Restroom.exec("pubkeys-request-signed",
     95 			Map.merge(did_request, keyring())),
     96 		{:ok, did_signed} <- exec("pubkeys-accept.chain", did)
     97 	do
     98 		{:ok, %{"created" => true, "did" => did_signed}}
     99 	end
    100 end
    101 
    102 @spec claim(Ecto.Repo.t(), %{person: Person.t()}) :: {:ok, map()} | {:error, term()}
    103 def claim(_repo, %{person: person}) do
    104 	if keyring() == nil do
    105 		{:error, "DID Controller not configured"}
    106 	else
    107 		case get_did(person) do
    108 			{:ok, did} -> {:ok, did}
    109 			_ -> request_new_did(person)
    110 		end
    111 	end
    112 end
    113 
    114 # Return the scheme of did from the configs.
    115 @spec scheme() :: :http | :https
    116 defp scheme() do
    117 	Keyword.fetch!(conf(), :did_uri).scheme
    118 end
    119 
    120 # Return the hostname of did from the configs.
    121 @spec host() :: String.t()
    122 defp host() do
    123 	Keyword.fetch!(conf(), :did_uri).host
    124 end
    125 
    126 # Return the port of did from the configs.
    127 @spec port() :: non_neg_integer()
    128 defp port() do
    129 	Keyword.fetch!(conf(), :did_uri).port
    130 end
    131 
    132 # Return the private keyring of the server from the configs.
    133 @spec keyring() :: nil | map()
    134 defp keyring() do
    135 	Keyword.fetch!(conf(), :did_keyring)
    136 end
    137 
    138 # Return the application configurations of this module.
    139 @spec conf() :: Keyword.t()
    140 defp conf() do
    141 	Application.fetch_env!(:zenflows, __MODULE__)
    142 end
    143 end