⚠️ This has been deprecated. Please use: lattice-connect-v2. ⚠️
By default, communication with a Lattice1 is routed through GridPlus' centralized cloud infrastructure. Although there is great care that goes into encrypting and securing these communication channels, we at GridPlus want your Lattice1 to be 100% yours, so we want to offer lattice-connect
as an alternative to centralized message routing.
If you are an advanced user, you can deploy this module yourself and change your Lattice's config to hook into your own deployed instance.
▶️ Installing & Runninglattice-connect
; and,- ☁️ (OPTIONAL) Deploying to the Cloud; and,
- 🔌 Configuring your Lattice1 to connect; and,
- 🥽 Testing the connection
This section describes installing the lattice-connector
, which is a small HTTP server + MQTT broker designed to communicate with Lattice1 hardware wallets over the web.
It's possible to run the server:
- as a process directly on a host system (using
node v12
); or, - through a Docker container.
You can start server with the following steps:
- Clone the repo via
git clone
; - install dependencies via
npm ci
; - start the daemon with
npm run start
.
Starting the server creates a pm2 process which will watch for crashes. For more information on pm2, see the pm2 docs.
# Clone the repo
$ git clone https://github.com/GridPlus/lattice-connect.git
$ cd lattice-connect
# Assumes 'node 12'
$ npm ci && npm run start
> lattice-connect@0.1.1 start
> npx pm2 start dist/index.js --name lattice-connect --watch
[PM2] Applying action restartProcessId on app [lattice-connect](ids: [ 0 ])
[PM2] [lattice-connect](0) ✓
[PM2] Process successfully started
⇆ PM2+ activated | Instance Name: laptop.local-5d42
┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐
│ id │ name │ mode │ ↺ │ status │ cpu │ memory │
├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤
│ 0 │ lattice-connect │ fork │ 9 │ online │ 0% │ 17.7mb │
└────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘
$ npm run stop
$ npm run rm
$ npm run logs
NOTE: this won't be useful when debugging MQTT connections or other issues internal to the application itself. For that, inspect the logs written to
LOG_DEST
(in./config.js
). You may also changeLOG_LEVEL
to a lower level for debugging (trace
will produce the most logs).
To watch logs in real time, start your pm2
process and run
tail -f <LOG_DEST>
- Clone the repo via
git clone
; - build the container via
npm run docker-build
; - start the container with
npm run docker-run
.
# Clone the repo
$ git clone https://github.com/GridPlus/lattice-connect.git
$ cd lattice-connect
# Build the container and start it
$ npm run docker-build && npm run docker-run
> lattice-connect@0.1.1 docker-run
> docker run -d --name lattice-connect -p 3000:3000 -p 1883:1883 lattice-connect:1.0
94915b49dd5cd38242bc0cf8d086b2be4c772687bd707a9b331deca18112854f
$ docker stop lattice-connect
$ docker stop lattice-connect && \
docker rm lattice-connect && \
npm run docker-build
$ docker logs -f lattice-container
The config parameters set in config.js
are referenced when starting the application. These come with defaults and
also look at a local file .config.json
(if it exists). This local .config.json
is not tracked in git and it is
where you can define params that are inspected in config.js
. Any param defined in both config.js
and .config.json
will be cast to the valuein .config.json
.
{
"LOG_DEST": "./lattice.log",
"MQTT_PASSWORD": "superdupersecretpassword"
}
Either install method described in Installing & Running should work on most cloud hosting providers. Important: do be sure to check that your provider allows opening the following ports:
- HTTP :80 (or, HTTPS :443);
- MQTT :1883 (or, MQTTS :8883).
On AWS, do the following to prepare your AWS instance:
- install node.js and npm: on Ubuntu, you can do this with
sudo apt-get update && sudo apt-get install node.js npm
; - update security group firewall settings: Do this by going to the
Security
tab when you have your EC2 instance selected on the AWS console. Make sure the ports listed inconfig.js
are open to0.0.0.0/0
(by default, these are 3000 for the web server and 1883 for the MQTT broker). They are bothTCP
connections; - go to the Start the server with: NPM & PM2.
This section describes how to modify settings on your Lattice1 so it's able to communicate with your lattice-connect
deployed instance.
- SSH into your Lattice1; and,
a. stopgpd
&mosquitto
viaservice <SERVICE> stop
; and,
b. reviewgpd
settings viauci show gridplus
; and, - modify settings for the
gpd
&mosquitto
services:
a. change the MQTT endpoint used ingpd
; and,
b. (OPTIONAL) disable SSL checks inmosquitto
(MQTT); and. - restart
gpd
andmosquitto
services to apply changes.
In order to point your Lattice1 at your own deployed instance of this module, you'll need to SSH into the device and change its configurations manually.
Your Lattice1's UI displays the necessary SSH Host
and SSH Password
parameters. Navigate to them by tapping Settings -> Advanced -> Device Info
.
From a remote terminal session, proceed by:
- SSH'ing using
ssh root@<SSH Host>.local
; - entering the
SSH Password
displayed on the Lattice1 when prompted.
# SSH command
$ root@<SSH Host>.local
# Input SSH password
root@<SSH Host>.local's password:
BusyBox v1.28.3 () built-in shell (ash)
__ __ __ _ ___
/ / ____ _/ /_/ /_(_)_______ < /
/ / / __ `/ __/ __/ / ___/ _ \/ /
/ /___/ /_/ / /_/ /_/ / /__/ __/ /
/_____/\__,_/\__/\__/_/\___/\___/_/
-----------------------------------------------------
Ω-ware: 0.3.2 b228
Gridplus GCE Version: 0.48.12
-----------------------------------------------------
root@<SSH Host>:~#
Stop these two services in preparation to make your changes:
# Stop `gdp`
$ root@<SSH Host>: service gpd stop
# Stop `mosquitto`
$ root@<SSH Host>: service mosquitto stop
The gpd
stands for GridPlus Daemon and it has several important functions, among them is connecting to the MQTT pub/sub.
To view the default settings, run uci show gridplus
:
$ root@<SSH Host>: uci show gridplus
NOTE: Consider writing down the original values if you want to reset back to GridPlus' default infrastructure.
# Show default 'gpd' configuration
$ root@<SSH Host>: uci show gridplus
# List of settings
gridplus.env=production
gridplus.gpdLogFile=/gpd/gpd.log
gridplus.gceVersion=0.48.12
gridplus.remote_mqtt_address=rabbitmq.gridpl.us:8883
gridplus.releaseCatalogURL=https://release-catalog-api.gridpl.us/update
gridplus.releaseCatalogUser=lattice1
gridplus.releaseCatalogPass=<REDACTED>
gridplus.ftla=false
gridplus.personalizationEnabled=true
gridplus.gpdLogLevel=FATAL
gridplus.provisionLatticeAPIURL=https://provision-lattice-api.gridpl.us/provision
gridplus.personalized=true
gridplus.rootPass=<REDACTED>
gridplus.deviceID=<REDACTED>
gridplus.rabbitmq_password=<REDACTED>
You should see a line like the following:
gridplus.remote_mqtt_address=rabbitmq.gridpl.us:8883
To change this value, use:
uci set gridplus.remote_mqtt_address=[host]:[BROKER_PORT]
uci commit
.
# Stop 'gpd' & 'mosquitto'
$ root@<SSH Host>: service gpd stop
$ root@<SSH Host>: service mosquitto stop
# Point the MQTT connection to the relevant address ('1883' for non-SSL; see next section)
$ root@<SSH Host>: uci set gridplus.remote_mqtt_address=10.0.0.1:1883
# Apply the change
$ root@<SSH Host>: uci commit
If you want to use an insecure connection (i.e. connect to a local IP address, or the default AWS instance host rather than your own secure domain), then:
- connect to MQTT over port
1883
; and, - add
bridge_insecure
to the/etc/init.d/mosquitto
; and,
See the man
page for mosquitto
to review the full list of configuration options.
Open the configuration file using vim
:
# Open file
$ root@<SSH Host>: vim /etc/init.d/mosquitto
Once in vim
:
- Navigate the cursor LINE 31;
- enter
INSERT
mode by pressing thei
key; - insert a
#
to comment outbridge_capath /etc/ssl/certs
; - insert
bridge_insecure true
on the next line.
// BEFORE
28 ...
29 connection ${DEVICE_ID}
30 address ${REMOTE_MQTT_ADDRESS}
31 bridge_capath /etc/ssl/certs/
32 remote_username ${DEVICE_ID}
33 ...
// AFTER
28 ...
29 address ${REMOTE_MQTT_ADDRESS}
30 # bridge_capath /etc/ssl/certs/
31 bridge_insecure true
32 remote_username ${DEVICE_ID}
33 ...
// Vim command to write file & quit:
// ESC + :x
After writing the file and closing vim
:
- restart service via
service mosquitto start
; and, - restart service via
service gpd start
.
# After quitting 'vim'
$ root@<SSH Host>: service mosquitto start
$ root@<SSH Host>: service gpd start
This section descbribes how you can test the connection between your Lattice1 and the lattice-connect
module.
It's possible to test the connection in multiple ways:
- send a
POST
usingwget
from the Lattice1 to the server; or, - log into the cloud-hosted version of the Lattice Manager; or,
- connect (or re-connect) your Lattice1 to MetaMask.
While connected to a remote SSH terminal session:
- get the
deviceID
; and, - use
wget
to send a HTTPPOST
request to the server; and, - if you had accounts connected to MetaMask, you may need to re-pair your device.
# Read the 'deviceID';
# Your Lattice1 also displays 'Device ID' under 'Settings'
$ root@<SSH Host>: uci show gridplus.deviceID
gridplus.deviceID=abc123
# Send the HTTP 'POST' request
$ root@<SSH Host>: wget -O- --post-data='[1,2,3]' \
--header='Content-Type:application/json' \
'http://10.0.0.1:3000/abc123'
Connecting to 10.0.0.1:3000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 151 [application/json]
Saving to: 'STDOUT'
...
2022-01-01 00:00:00 (1.96 MB/s) - written to stdout [151/151]
You can replace a known deviceID
with a fake one and it will still work for testing purposes, so long as the requst hangs (i. e., you should not immediately get a Connection refused
error). If you do get Connection refused
it means your process isn't running on the expected port.
This article can guide you through disabling insecure content checks on most browsers. Proceed cautiously
From an Internet browser, navigate to the Lattice Manager:
- go to https://lattice.gridplus.io; and,
- at the bottom of the page, click Settings; and,
- in the section titled: Connection Endpoint:
- for HTTPS;
https://[host | ip_address]:[HTTP_PORT]
; or, - for HTTP;
http://[host | ip_address]:[HTTP_PORT]
;
- for HTTPS;
- click Update and Reload,
# Connection Endpoint:
http://10.0.0.1:3000
You are now ready to log in:
- enter your
deviceID
; and, - enter your
password
.
You may be asked to pair (aka, give permssions) to your Lattice1 before completing the login process.
If your device was previously paired with the Lattice Manager, and you with to re-pair it, then unlock your Lattice1 and tap Permissions -> Lattice Manager -> Delete
.
Log out of the Lattice Manager (if necessary), and then follow the steps above to log back in. You will be prompted to re-pair your device during the login process.
Similarly to the Lattice Manager, you may be required to re-pair your device with MetaMask. Re-connecting your Lattice1 using "Connect Hardware Wallet" within MetaMask should be your first step.
It may be that deleting MetaMask from Permissions
(on your device) is required. Fixing pairing issues is simple, and is how messages get routed from clients to devices.
For the most comprehensive guide to connecting to the MetaMask extension, review the Knowledge Base article.
- Troubleshooting
- Integration Tests
- Web API
- Background
Testing may reveal things simply aren't working; please re-read the above documentation be certain you've done everything as described for your situation.
If you're sure everything was setup properly, consider if:
- the module's ports (see
config.js
) are set correctly wherever they are changed; or, - rebuilding the Docker container is needed to sync any source file changes; or,
- your Lattice1 is connected to the Internet, and update WiFi, if need be.
If you want to get more information about what's going on with your app, update config.js
to use LOG_LEVEL: 'trace'
and run:
npm run stop && npm run start && tail -f <LOG_DEST>
(Where LOG_DEST
is defined in config.js
).
If you are trying to get a connection, you will see something like this after running service mosquitto start && service gpd start
:
{"level":10,"time":1612201604724,"pid":45728,"hostname":"ip-172-31-26-163","msg":"BROKER: Client ([object Object]) published message: {\"retain\":true,\"qos\":1,\"topic\":\"$SYS/broker/connection/XXXXXX/state\",\"payload\":{\"type\":\"Buffer\",\"data\":[48]},\"brokerId\":\"20dc7c87-e5a1-4a33-a450-5c50dc5fb5ee\",\"clientId\":\"XXXXXX\"}"}
(Where I have replaced my device ID with XXXXXX
.)
If you are in a bad state and can't get out, you can always go to your Lattice1 UI and navigate to Settings -> Advanced -> Reeset Router
. This will restore factory settings for the Linux kernel you have been SSH'ing into. This reset will not delete your wallet, keys, or any secure data.
This repo includes an integration test script that you can run to ensure your communication endpoint is functioning as expected.
Step 1: Deploy locally
The test should be run against a local instance. Deploy locally with one of the methods above (npm start
or using Docker).
Step 2: Point your Lattice your local broker
Follow the instructions in the previous section to SSH into your Lattice and update gridplus.remote_mqtt_address
.
Step 3: Run test script
Once your Lattice is pointed to the desired MQTT broker, it will listen to the correct topics and is ready for testing. You can run the tests with:
npm run test
This will kick off a few integration tests to validate that we are able to connect to the Lattice and get addresses. If these pass, it means the communication pathway is working as expected.
The HTTP webserver hosted from this module only contains one route:
POST /:deviceID
Contact a Lattice (given its deviceID
) with a payload. The payload must be a UInt8Array
or Buffer
type. On a successful message, a hex string is returned. gridplus-sdk
will parse this data into an appropriate response, so using it is highly recommended.
Request data:
{
data: <UInt8Array or Buffer>
}
Response:
{
status: <Number> // 200 for success, 500 for internal error
message: <String> // Hex string containing response payload (status=200) or error string (status=500)
}
The Lattice1 is a next generation, always-online hardware wallet designed to sit behind a user's home WiFi network router. Because we aren't expecting most users to reconfigure their home router in the event a default firewall might block incoming requests, the Lattice1 is not designed to communicate over HTTP.
The implemented pub/sub model subscribes to specific topics available on a cloud-hosted MQTT broker GridPlus provides by default. Requests from third-party applications are transformed into MQTT messages and sent to this broker, and are then forwarded to a Lattice1 with a matching device ID.
As previously mentioned, having the choice to deploy the lattice-connect
server on infrastructure our customers directly control is a priority for us, and a decision GridPlus supports.