zf

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

restroom.ex (4126B)


      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.Restroom do
     19 @moduledoc """
     20 A module to interact with Restroom instances over (for now) HTTP.
     21 """
     22 
     23 def child_spec(_) do
     24 		Supervisor.child_spec(
     25 			{Zenflows.HTTPC,
     26 				name: __MODULE__,
     27 				scheme: scheme(),
     28 				host: host(),
     29 				port: port(),
     30 			},
     31 			id: __MODULE__)
     32 end
     33 
     34 @doc """
     35 Returns `true` when `left` and `right` are equal, `false` otherwise.
     36 """
     37 @spec byte_equal?(binary(), binary()) :: boolean()
     38 def byte_equal?(left, right) do
     39 	data = %{left: Base.encode64(left), right: Base.encode64(right)}
     40 	case exec("byte_equal", data) do
     41 		{:ok, %{"output" => ["1"]}} -> true
     42 		_ -> false
     43 	end
     44 end
     45 
     46 @doc """
     47 Given the GraphQL `body`, its `signature`, and `pubkey` of the user who
     48 executes the query, verify that everything matches.
     49 """
     50 @spec verify_graphql(binary(), String.t(), String.t()) :: :ok | {:error, String.t()}
     51 def verify_graphql(body, signature, pubkey) do
     52 	data = %{
     53 		"gql" => Base.encode64(body),
     54 		"eddsa_signature" => signature,
     55 		"eddsa_public_key" => pubkey,
     56 	}
     57 	case exec("verify_graphql", data) do
     58 		{:ok, %{"output" => ["1"]}} -> :ok
     59 		{:error, reason} -> {:error, reason}
     60 	end
     61 end
     62 
     63 @doc """
     64 See https://github.com/dyne/keypairoom for details.
     65 """
     66 @spec keypairoom_server(map()) :: {:ok, String.t()} | {:error, term()}
     67 def keypairoom_server(data) do
     68 	data = %{
     69 		"userData" => data,
     70 		"serverSideSalt" => salt(),
     71 	}
     72 	case exec("keypairoomServer-6-7", data) do
     73 		{:ok, %{"seedServerSideShard.HMAC" => hmac}} -> {:ok, hmac}
     74 		{:error, reason} -> {:error, reason}
     75 	end
     76 end
     77 
     78 # Execute a Zencode specified by `name` with JSON data `data`.
     79 @spec exec(String.t(), map()) :: {:ok, map()} | {:error, term()}
     80 def exec(name, post_data) do
     81 	request(&Zenflows.HTTPC.request(__MODULE__, &1, &2, &3, &4),
     82 		name, post_data)
     83 end
     84 
     85 @doc """
     86 Given the request function (wrapper of Zenflows.HTTPC.request), the path
     87 and the data to post, it makes the request and parse the result.
     88 """
     89 @spec request(fun(), String.t(), map()) :: {:ok, map()} | {:error, term()}
     90 def request(request_fn, path, post_data) do
     91 	hdrs = [{"content-type", "application/json"}]
     92 
     93 	with {:ok, post_body} <- Jason.encode(%{data: post_data}),
     94 	   {:ok, %{status: stat, data: body}} when stat == 200 or stat == 500 <-
     95 			request_fn.("POST", "/api/#{path}", hdrs, post_body),
     96 		{:ok, data} <- Jason.decode(body) do
     97 		if stat == 200 do
     98 			{:ok, data}
     99 		else
    100 			{:error, data |> Map.fetch!("zenroom_errors") |> Map.fetch!("logs")}
    101 		end
    102 	else
    103 		{:ok, %{status: stat, data: body}} ->
    104 		  {:error, "the http call result in non-200 status code #{stat}: #{inspect(body)}"}
    105 
    106 		other -> other
    107 	end
    108 end
    109 
    110 # Return the salt from the configs.
    111 @spec salt() :: String.t()
    112 defp salt() do
    113 	Keyword.fetch!(conf(), :room_salt)
    114 end
    115 
    116 # Return the scheme of restroom from the configs.
    117 @spec scheme() :: :http | :https
    118 defp scheme() do
    119 	Keyword.fetch!(conf(), :room_uri).scheme
    120 end
    121 
    122 # Return the hostname of restroom from the configs.
    123 @spec host() :: String.t()
    124 defp host() do
    125 	Keyword.fetch!(conf(), :room_uri).host
    126 end
    127 
    128 # Return the port of restroom from the configs.
    129 @spec port() :: non_neg_integer()
    130 defp port() do
    131 	Keyword.fetch!(conf(), :room_uri).port
    132 end
    133 
    134 # Return the application configurations of this module.
    135 @spec conf() :: Keyword.t()
    136 defp conf() do
    137 	Application.fetch_env!(:zenflows, __MODULE__)
    138 end
    139 end