DiodeClient

DiodeClient secure end-to-end encrypted connections between any two machines. Connections are established either through direct peer-to-peer TCP connections or bridged via the Diode network. To learn more about the decentralized Diode network visit https://diode.io/

Example usage with a simple server + client. For this to work open each in individual terminal:

# Server
DiodeClient.interface_add("example_server_interface")
address = DiodeClient.Base16.encode(DiodeClient.address())
{:ok, port} = DiodeClient.port_listen(5000)
spawn_link(fn ->
IO.puts("server #{address} started")
{:ok, ssl} = DiodeClient.port_accept(port)
peer = DiodeClient.Port.peer(ssl)
IO.puts("got a connection from #{Base.encode16(peer)}")
:ssl.controlling_process(ssl, self())
:ssl.setopts(ssl, [packet: :line, active: true])
for x <- 1..10 do
IO.puts("sending message #{x}")
:ssl.send(ssl, "Hello #{Base.encode16(peer)} this is message #{x}\n")
end
receive do
{:ssl_closed, _ssl} -> IO.puts("closed!")
end
end)

And the client. Here insert in the server address the address that has been printed above. For example server_address = "0x389eba94b330140579cdce1feb1a6e905ff876e6"

# Client: Below enter your server address
server_address = "0x389eba94b330140579cdce1feb1a6e905ff876e6"
DiodeClient.interface_add("example_client_interface")
spawn_link(fn ->
{:ok, ssl} = DiodeClient.port_connect(server_address, 5000)
:ssl.controlling_process(ssl, self())
:ssl.setopts(ssl, [packet: :line, active: true])
Enum.reduce_while(1..10, nil, fn _, _ ->
receive do
{:ssl, _ssl, msg} -> {:cont, IO.inspect(msg)}
other -> {:halt, IO.inspect(other)}
end
end)
:ssl.close(ssl)
IO.puts("closed!")
end)

Blockchain Interaction

For limited access to supported blockchain source of truth data :diode_client supports reading from smart contracts and calling contract methods. For each supported blockchain there is a Shell configured, currently supported blockchains are:

Each shell supports call/5 and other methods to read contract data and send transactions.

Example of making a ZTNA contract call on Oasis Sapphire:

alias DiodeClient.{Base16, Shell}
Shell.OasisSapphire.call(
Base16.decode("0xb78700e7254F54b418bdF6DE7109128D1Fe8E8DD"),
"getPropertyValue",
["address", "string"],
[Base16.decode("0x90983fc294577b6f00CBd5D3b26aDf2e85Ca2Cac"), "public"],
result_types: "string"
)

Mix tasks

When using this repo as a dependency, run these from your application root (they start :diode_client and use your configured wallet). Run mix help for the full list or mix help <task> for details.

TaskDescription
mix diode.bnsBNS register, unregister, whoami, version
mix diode.resolveResolve an address or BNS name (drive, members)
mix diode.nodesList or fetch Diode network nodes
mix diode.get_objectPrint a Diode ticket object for an address
mix diode.publishListen on a port and echo traffic
mix diode.udpPublish or consume a Diode UDP port
mix diode.evm_callTrace an eth_call via cast (Oasis Sapphire)
mix diode.evm_transactionSend a test Oasis Sapphire transaction via cast

Examples:

mix diode.bns whoami
mix diode.bns register myname.diode 0x...
mix diode.resolve 0x...
mix diode.nodes get 0x...
mix diode.get_object 0x...
mix diode.publish 5000
mix diode.udp publish 5000
mix diode.udp consume 0x... 5000
mix diode.evm_call request.json
mix diode.evm_transaction

For BNS tasks, set SEED_LIST to reach the network (e.g. export SEED_LIST=us1.prenet.diode.io).

Encryption and Authentication

For encryption standard TLS as builtin into Erlang from OpenSSL is used. For authentication though the Ethereum signature scheme using the elliptic curve secp256k1 is used. The generated public addresses of the form 0x389eba94b330140579cdce1feb1a6e905ff876e6 actually represent hashes of public keys. When opening a port using DiodeClient.port_open("0x389eba94b330140579cdce1feb1a6e905ff876e6", 5000) this first locates the correct peer and then uses cryptographic handshakes to ensure the peer is in fact in possession of the corresponding private key.

To this regard the DiodeClient will by default store private keys in local files. In the example above example_client_interface and example_server_interface. These represent both the address as well as the private key needed to authenticate as such.

Todos

Installation

The package can be installed by adding diode_client to your list of dependencies in mix.exs:

def deps do
[
{:diode_client, "~> 1.1"}
]
end