Skip to content
Snippets Groups Projects
Commit b9f25b33 authored by Richard T. Carback III's avatar Richard T. Carback III
Browse files

Merge branch 'jemimah/xxdk-documentation' into 'release'

Update README instructions for using client

See merge request !180
parents afd13499 bd88e797
No related branches found
No related tags found
3 merge requests!231Revert "Update store to print changes to the partners list",!187Xx 3829/triggers,!180Update README instructions for using client
...@@ -3,28 +3,30 @@ ...@@ -3,28 +3,30 @@
[![pipeline status](https://gitlab.com/elixxir/client/badges/master/pipeline.svg)](https://gitlab.com/elixxir/client/commits/master) [![pipeline status](https://gitlab.com/elixxir/client/badges/master/pipeline.svg)](https://gitlab.com/elixxir/client/commits/master)
[![coverage report](https://gitlab.com/elixxir/client/badges/master/coverage.svg)](https://gitlab.com/elixxir/client/commits/master) [![coverage report](https://gitlab.com/elixxir/client/badges/master/coverage.svg)](https://gitlab.com/elixxir/client/commits/master)
The xx network client is a library and related command line tool
that facilitate making full-featured xx clients for all platforms. The The client is a library and related command-line tool
command line tool can be built for any platform supported by that facilitates making full-featured xx clients for all platforms. It interfaces with the cMix system, enabling access
golang. The libraries are built for iOS and Android using to all xx network messaging features, including end-to-end encryption and metadata protection.
[gomobile](https://godoc.org/golang.org/x/mobile/cmd/gomobile).
This repository contains everything necessary to implement all of the This repository contains everything necessary to implement all of the
xx network messaging features. These include the end-to-end encryption xx network messaging features. It also contains features to extend the base
and metadata protection. It also contains features to extend the base
messaging protocols. messaging protocols.
The command-line tool accompanying the client library can be built for any platform supported by
golang. The libraries are built for iOS and Android using
[gomobile](https://godoc.org/golang.org/x/mobile/cmd/gomobile).
For library writers, the client requires a writable folder to store For library writers, the client requires a writable folder to store
data, functions for receiving and approving requests for creating data, functions for receiving and approving requests for creating
secure end-to-end messaging channels, for discovering users, and for secure end-to-end messaging channels, for discovering users, and for
receiving different types of messages. Details for implementing these receiving different types of messages. Details for implementing these
features are in the Library Overview section below. features are in the [Library Overview section](#library-overview) below.
The client is open source software released under the simplified BSD License. The client is open-source software released under the simplified BSD License.
## Command Line Usage ## Command Line Usage
The command line tool is intended for testing xx network functionality and not The command-line tool is intended for testing xx network functionality and not
for regular user use. for regular user use.
These instructions assume that you have [Go 1.17.X installed](https://go.dev/doc/install), and GCC installed for Cgo (such as `build-essential` on Debian or Ubuntu). These instructions assume that you have [Go 1.17.X installed](https://go.dev/doc/install), and GCC installed for Cgo (such as `build-essential` on Debian or Ubuntu).
...@@ -47,31 +49,27 @@ GOOS=windows GOARCH=386 CGO_ENABLED=0 go build -ldflags '-w -s' -o release/clien ...@@ -47,31 +49,27 @@ GOOS=windows GOARCH=386 CGO_ENABLED=0 go build -ldflags '-w -s' -o release/clien
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '-w -s' -o release/client.darwin64 main.go GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '-w -s' -o release/client.darwin64 main.go
``` ```
To get an NDF from a network gateway and the permissioning server, use the `getndf` subcommand. The `getndf` subcommand allows command line users to poll the NDF from both a gateway and the permissioning server without any pre-established client connection. It requires an IP address, port, and ssl certificate. You can download an ssl cert with: #### Fetching an NDF
```
openssl s_client -showcerts -connect permissioning.prod.cmix.rip:11420 < /dev/null 2>&1 | openssl x509 -outform PEM > certfile.pem
```
Example usage for Gateways: All actions performed with the client require a current [NDF](https://xxdk-dev.xx.network/technical-glossary#network-definition-file-ndf). The NDF is downloadable from the command line or [via an access point](https://xxdk-dev.xx.network/quick-reference#func-downloadandverifysignedndfwithurl) in the Client API.
Use the `getndf` command to fetch the NDF via the command line. `getndf` enables command-line users to poll the NDF from a network gateway without any pre-established client connection:
``` ```
$ go run main.go getndf --gwhost localhost:8440 --cert ~/integration/keys/cmix.rip.crt | jq . | head // Fetch NDF (example usage for Gateways, assumes you are running a gateway locally)
{ $ go run main.go getndf --gwhost localhost:8440 --cert certfile.pem | jq . >ndf.json
"Timestamp": "2021-01-29T01:19:49.227246827Z",
"Gateways": [
{
"Id": "BRM+Iotl6ujIGhjRddZMBdauapS7Z6jL0FJGq7IkUdYB",
"Address": ":8440",
"Tls_certificate": "-----BEGIN CERTIFICATE-----\nMIIDbDCCAlSgAwIBAgIJAOUNtZneIYECMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNV\nBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQx\nGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJp\ncDAeFw0xOTAzMDUxODM1NDNaFw0yOTAzMDIxODM1NDNaMGgxCzAJBgNVBAYTAlVT\nMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNV\nBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDCCASIw\nDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPP0WyVkfZA/CEd2DgKpcudn0oDh\nDwsjmx8LBDWsUgQzyLrFiVigfUmUefknUH3dTJjmiJtGqLsayCnWdqWLHPJYvFfs\nWYW0IGF93UG/4N5UAWO4okC3CYgKSi4ekpfw2zgZq0gmbzTnXcHF9gfmQ7jJUKSE\ntJPSNzXq+PZeJTC9zJAb4Lj8QzH18rDM8DaL2y1ns0Y2Hu0edBFn/OqavBJKb/uA\nm3AEjqeOhC7EQUjVamWlTBPt40+B/6aFJX5BYm2JFkRsGBIyBVL46MvC02MgzTT9\nbJIJfwqmBaTruwemNgzGu7Jk03hqqS1TUEvSI6/x8bVoba3orcKkf9HsDjECAwEA\nAaMZMBcwFQYDVR0RBA4wDIIKKi5jbWl4LnJpcDANBgkqhkiG9w0BAQUFAAOCAQEA\nneUocN4AbcQAC1+b3To8u5UGdaGxhcGyZBlAoenRVdjXK3lTjsMdMWb4QctgNfIf\nU/zuUn2mxTmF/ekP0gCCgtleZr9+DYKU5hlXk8K10uKxGD6EvoiXZzlfeUuotgp2\nqvI3ysOm/hvCfyEkqhfHtbxjV7j7v7eQFPbvNaXbLa0yr4C4vMK/Z09Ui9JrZ/Z4\ncyIkxfC6/rOqAirSdIp09EGiw7GM8guHyggE4IiZrDslT8V3xIl985cbCxSxeW1R\ntgH4rdEXuVe9+31oJhmXOE9ux2jCop9tEJMgWg7HStrJ5plPbb+HmjoX3nBO04E5\n6m52PyzMNV+2N21IPppKwA==\n-----END CERTIFICATE-----\n"
},
{
"Id": "JCBd9mAQb2BW8hc8H9avy1ubcjUAa7MHrPp0dBU/VqQB",
``` ```
Example usage for the Permissioning server: You can also download an NDF directly for different environments by using the `--env` flag:
```go
$ go run main.go getndf --env mainnet | jq . >ndf.json
// Or, run via the binary (assuming 64-bit Windows):
$ ./client.win64 getndf --env mainnet | jq . >ndf.json
```
Sample content of `ndf.json`:
``` ```
$ go run main.go getndf --permhost localhost:18000 --cert ~/integration/keys/cmix.rip.crt | jq . | head
{ {
"Timestamp": "2021-01-29T01:19:49.227246827Z", "Timestamp": "2021-01-29T01:19:49.227246827Z",
"Gateways": [ "Gateways": [
...@@ -82,61 +80,76 @@ $ go run main.go getndf --permhost localhost:18000 --cert ~/integration/keys/cmi ...@@ -82,61 +80,76 @@ $ go run main.go getndf --permhost localhost:18000 --cert ~/integration/keys/cmi
}, },
{ {
"Id": "JCBd9mAQb2BW8hc8H9avy1ubcjUAa7MHrPp0dBU/VqQB", "Id": "JCBd9mAQb2BW8hc8H9avy1ubcjUAa7MHrPp0dBU/VqQB",
.....
``` ```
Basic command line usage, sending unsafe, unencrypted messages to yourself: #### Sending safe messages between 2 users
```
client --password user-password --ndf ndf.json -l client.log -s session-directory --writeContact user-contact.json --unsafe -m \"Hello World, without E2E Encryption\"
```
* `--password` is the password used to encrypt and load the session. To send messages with end-to-end encryption, you must first establish a connection
* `--ndf` is the network definition file, downloadable from the xx network or [authenticated channel](https://xxdk-dev.xx.network/technical-glossary#authenticated-channel) with the other user:
website when available.
* `-l` the file to write logs (user messages are still printed to stdout)
* `--writeContact` Output the user's contact information to this file.
* `--unsafe` Send message without encryption (necessary whenever you have not
already established an e2e channel)
* `-m` The message to send
The client defaults to sending to itself when not supplied. ```
# Get user contact jsons for each client
$ client --password user1-password --ndf ndf.json -l client1.log -s user1session --writeContact user1-contact.json --unsafe -m "Hi to me, without E2E Encryption"
$ client --password user2-password --ndf ndf.json -l client2.log -s user2session --writeContact user2-contact.json --unsafe -m "Hi to me, without E2E Encryption"
Sending unsafe messages between 2 users: # Request authenticated channel from another client. Note that the receiving client
# is expected to confirm the request before any specified timeout (default 120s)
$ client --password password --ndf ndf.json -l client.log -s session-directory --destfile user2-contact.json --waitTimeout 360 --unsafe-channel-creation --send-auth-request
WARNING: unsafe channel creation enabled
Adding authenticated channel for: Qm40C5hRUm7uhp5aATVWhSL6Mt+Z4JVBQrsEDvMORh4D
Message received:
Sending to Qm40C5hRUm7uhp5aATVWhSL6Mt+Z4JVBQrsEDvMORh4D:
Received 1
``` # Alternatively, to accept an authenticated channel request implicitly
# Get user contact jsons # (should be within the timeout window of requesting client, or the request will need to be resent):
client --password user1-password --ndf ndf.json -l client1.log -s user1session --writeContact user1-contact.json --unsafe -m "Hi" $ client --password "password" --ndf ndf.json -l client.log -s session-directory --destfile user2-contact.json" --unsafe-channel-creation --waitTimeout 200
client --password user2-password --ndf ndf.json -l client2.log -s user2session --writeContact user2-contact.json --unsafe -m "Hi" Authentication channel request from: o+QpswTmnsuZve/QRz0j0RYNWqjgx4R5pACfO00Pe0cD
Sending to o+QpswTmnsuZve/QRz0j0RYNWqjgx4R5pACfO00Pe0cD:
# Send messages to each other, run them in the background so they both receive Message received:
# each other's messages Received 1
client --password user1-password --ndf ndf.json -l client1.log -s user1session --destfile user2-contact.json --unsafe -m "Hi User 2, from User 1 without E2E Encryption" &
client --password user2-password --ndf ndf.json -l client2.log -s user2session --destfile user1-contact.json --unsafe -m "Hi User 1, from User 2 without E2E Encryption" &
```
# Send E2E Messages
$ client --password user1-password --ndf ndf.json -l client1.log -s user1session --destfile user2-contact.json -m "Hi User 2, from User 1 with E2E Encryption"
Sending to Qm40C5hRUm7uhp5aATVWhSL6Mt+Z4JVBQrsEDvMORh4D: Hi User 2, from User 1 with E2E Encryption
Timed out!
Received 0
$ client --password user2-password --ndf ndf.json -l client1.log -s user2session --destfile user1-contact.json -m "Hi User 1, from User 2 with E2E Encryption"
Sending to o+QpswTmnsuZve/QRz0j0RYNWqjgx4R5pACfO00Pe0cD: Hi User 1, from User 2 with E2E Encryption
Timed out!
Received 0
```
* `--password`: The password used to encrypt and load the session.
* `--ndf`: The network definition file.
* `-l`: The file to write logs (user messages are still printed to stdout).
* `-s`: The storage directory for client session data.
* `--writeContact`: Output the user's contact information to this file.
* `--destfile` is used to specify the recipient. You can also use * `--destfile` is used to specify the recipient. You can also use
`--destid b64:...` using the user's base64 id which is printed in the logs. `--destid b64:...` using the user's base64 id which is printed in the logs.
* `--unsafe`: Send message without encryption (necessary whenever you have not
already established an e2e channel).
* `--unsafe-channel-creation` Auto-create and auto-accept channel requests.
* `-m`: The message to send.
To send with end to end encryption, you must first establish a connection Note that the client defaults to sending to itself when a destination is not supplied.
with the other user: This is why we've used the `--unsafe` flag when creating the user contact jsons.
However, when sending between users it is dropped in exchange for `--unsafe-channel-creation`.
``` For the authenticated channel creation to be considered "safe" the user should be prompted. You can do this
# Get user contact jsons on the command line by explicitly accepting the channel creation
client --password user1-password --ndf ndf.json -l client1.log -s user1session --writeContact user1-contact.json --unsafe -m "Hi" when sending a request with `--send-auth-request` and/or explicitly accepting a request with
client --password user2-password --ndf ndf.json -l client2.log -s user2session --writeContact user2-contact.json --unsafe -m "Hi" `--accept-channel`:
# Send E2E Messages
client --password user1-password --ndf ndf.json -l client1.log -s user1session --destfile user1-contact.json --unsafe-channel-creation -m "Hi User 2, from User 1 with E2E Encryption" &
client --password user2-password --ndf ndf.json -l client2.log -s user2session --destfile user1-contact.json --unsafe-channel-creation -m "Hi User 1, from User 2 with E2E Encryption" &
``` ```
$ client --password user-password --ndf ndf.json -l client.log -s session-directory --destfile user-contact.json --accept-channel
Note that we have dropped the `--unsafe` in exchange for: Authentication channel request from: yYAztmoCoAH2VIr00zPxnj/ZRvdiDdURjdDWys0KYI4D
* `--unsafe-channel-creation` Auto-create and auto-accept channel requests. Sending to yYAztmoCoAH2VIr00zPxnj/ZRvdiDdURjdDWys0KYI4D:
Message received:
To be considered "safe" the user should be prompted. You can do this Received 1
with the command line by explicitly accepting the channel creation ```
when sending and/or explicitly accepting a request with
`--accept-channel`.
Full usage of client can be found with `client --help`: Full usage of client can be found with `client --help`:
...@@ -204,7 +217,7 @@ Flags: ...@@ -204,7 +217,7 @@ Flags:
Use "client [command] --help" for more information about a command. Use "client [command] --help" for more information about a command.
``` ```
Note that the client cannot be used on the betanet with precanned user ids. **Note:** The client cannot be used on the betanet with precanned user ids.
## Library Overview ## Library Overview
...@@ -219,175 +232,13 @@ platforms. ...@@ -219,175 +232,13 @@ platforms.
Clients need to perform the same actions *in the same order* as shown in Clients need to perform the same actions *in the same order* as shown in
`cmd/root.go`. Specifically, certain handlers need to be registered and `cmd/root.go`. Specifically, certain handlers need to be registered and
set up before starting network threads (i.e., before StartNetworkFollowers set up before starting network threads. Additionally, you cannot perform certain actions until the network connection reaches a "healthy" state.
-- #2 below) and you cannot perform certain actions until the network
connection reaches the "healthy" state. Below are relevant code listings for
how to do these actions.
the ndf is the network definition file, downloadable from the xx network
website when available.
1. Creating and/or Loading a client:
```
//create a new client if none exist
if _, err := os.Stat(storeDir); os.IsNotExist(err) {
// Load NDF
ndfPath := viper.GetString("ndf")
ndfJSON, err := ioutil.ReadFile(ndfPath)
if err != nil {
jww.FATAL.Panicf(err.Error())
}
err = api.NewClient(string(ndfJSON), storeDir,
[]byte(pass), regCode)
}
if err != nil {
jww.FATAL.Panicf("%+v", err)
}
}
//load the client See [main.go](https://git.xx.network/elixxir/xxdk-examples/-/blob/sample-messaging-app/sample-messaging-app/main.go) for relevant code listings on when and how to perform these actions.
client, err := api.Login(storeDir, []byte(pass)) The [Getting Started](https://xxdk-dev.xx.network/getting-started) guide provides further detail.
if err != nil {
jww.FATAL.Panicf("%+v", err)
}
```
2. Set up registration, authorization request handlers
```
user := client.GetUser()
// Set up reception handler
swboard := client.GetSwitchboard()
recvCh := make(chan message.Receive, 10000) // Needs to be large
// Note the name below is arbitrary
listenerID := swboard.RegisterChannel("DefaultCLIReceiver",
switchboard.AnyUser(), message.Text, recvCh)
jww.INFO.Printf("Message ListenerID: %v", listenerID)
// Set up auth request handler, which simply prints the
// user id of the requestor.
authMgr := client.GetAuthRegistrar()
authMgr.AddGeneralRequestCallback(printChanRequest)
...
func printChanRequest(requestor contact.Contact, message string) {
msg := fmt.Sprintf("Authentication channel request from: %s\n",
requestor.ID)
jww.INFO.Printf(msg)
fmt.Printf(msg)
msg = fmt.Sprintf("Authentication channel request message: %s\n", message)
jww.INFO.Printf(msg)
fmt.Printf(msg)
// Or you can auto confirm with:
// err := client.ConfirmAuthenticatedChannel(
// requestor)
} You can also visit the [API Quick Reference](https://xxdk-dev.xx.network/quick-reference)
``` for information on the types and functions exposed by the Client API.
3. Start network threads and wait until network is healthy:
```
err = client.StartNetworkFollower()
if err != nil {
jww.FATAL.Panicf("%+v", err)
}
// Wait until connected or crash on timeout
connected := make(chan bool, 10)
client.GetHealth().AddChannel(connected)
waitUntilConnected(connected)
...
func waitUntilConnected(connected chan bool) {
waitTimeout := time.Duration(viper.GetUint("waitTimeout"))
timeoutTimer := time.NewTimer(waitTimeout * time.Second)
isConnected := false
//Wait until we connect or panic if we can't by a timeout
for !isConnected {
select {
case isConnected = <-connected:
jww.INFO.Printf("Network Status: %v\n",
isConnected)
break
case <-timeoutTimer.C:
jww.FATAL.Panic("timeout on connection")
}
}
}
```
4. Adding authenticated channels (if we haven't done it yet)
```
if client.HasAuthenticatedChannel(recipientID) {
jww.INFO.Printf("Authenticated channel already in place for %s",
recipientID)
return
}
// Check if a channel exists for this recipientID
recipientContact, err := client.GetAuthenticatedChannelRequest(
recipientID)
if err == nil {
jww.INFO.Printf("Accepting existing channel request for %s",
recipientID)
err := client.ConfirmAuthenticatedChannel(recipientContact)
if err != nil {
jww.FATAL.Panicf("%+v", err)
}
return
} else {
recipientContact = recipient
}
me := client.GetUser().GetContact()
jww.INFO.Printf("Requesting auth channel from: %s",
recipientID)
err := client.RequestAuthenticatedChannel(recipientContact,
me, msg)
if err != nil {
jww.FATAL.Panicf("%+v", err)
}
```
5. Sending E2E and Unsafe Messages
```
msg := message.Send{
Recipient: recipientID,
Payload: []byte(msgBody),
MessageType: message.Text,
}
paramsE2E := params.GetDefaultE2E()
paramsUnsafe := params.GetDefaultUnsafe()
fmt.Printf("Sending to %s: %s\n", recipientID, msgBody)
var roundIDs []id.Round
if unsafe {
roundIDs, err = client.SendUnsafe(msg,
paramsUnsafe)
} else {
roundIDs, _, err = client.SendE2E(msg,
paramsE2E)
}
if err != nil {
jww.FATAL.Panicf("%+v", err)
}
jww.INFO.Printf("RoundIDs: %+v\n", roundIDs)
```
The "RoundIDs" are the rounds in which your message parts were sent. After those
rounds have completed on the network, you can assume that the message has "sent"
successfully. See the client interface section for info on how to access round
state changes.
6. Receiving Messages (assuming you set the receiver above in step 2)
```
timeoutTimer := time.NewTimer(waitTimeout * time.Second)
select {
case <-timeoutTimer.C:
fmt.Println("Timed out!")
break
case m := <-recvCh:
fmt.Printf("Message received: %s\n", string(
m.Payload))
break
}
```
The main entry point for developing with the client is `api/client` (or The main entry point for developing with the client is `api/client` (or
`bindings/client`). We recommend using go doc to explore: `bindings/client`). We recommend using go doc to explore:
...@@ -492,4 +343,4 @@ parts of the roadmap that are intended for the client: ...@@ -492,4 +343,4 @@ parts of the roadmap that are intended for the client:
* Efficiency improvements - mechanisms for message pickup and network tracking * Efficiency improvements - mechanisms for message pickup and network tracking
* will evolve to allow tradeoffs and options for use * will evolve to allow tradeoffs and options for use
We also are always looking at how to simplify and improve the library interface. We are also always looking at simplifying and improving the library interface.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment