API Docs

Overview

This API provides multiple secure connections between a smartphone browser and an IoT device.

Properties:

Goal

Our goal is to provide a easy web-developer friendly way to access data and services on an IoT device, without compromising the user's security

Differences from VPN

Conceptually it can be thought of as a point-to-point VPN, however the connections terminate inside the user's browser so are only available to that page - not to other apps on the same device.

Web API

NOTE: This API is in Beta- the names and functionality may change. Specifically we expect to replace the Ipse name with Pipe before launch

Each service offered by the IoT device is exposed with a websocket-like interface that will be familiar to web-developers. Each service is accessed by name e.g.:
        var camPipe = duct.createDataChannel("camera", {});
Once opened a pipe can be used:
        camPipe.onopen = function() {
            camPipe.send(JSON.stringify({command: "read"}));
        };
The exact semantics of each pipe depend on it's purpose. See "Supported Services" for more details. In general however each pipe looks a lot like a websocket, supporting onopen,onmessage,onclose events and a send() message. Most pipes send and recieve JSON messages, but some do not.

Device Agent

The Device Agent runs on the IoT device. It consists of a multi-threaded networking process with some optional scripts to customize the services.
In our prototype devices it is run in the user's .xsession to ensure it is always present and has access to the screen. Production devices (especially those using BTLE pairing or dedicated screen technologies. We require a Java version later than 8 - 101.

Pairing

When the device is freshly unboxed (or in the factory reset state), it has no local or remote keys.
On startup the Device agent will create a local (selfsigned) Public/Private keypair and put it into a keystore
ipsecert.ks
in the current directory.
It then presents a token (derived from it's public key) for pairing. Currently this is done visually as a QRcode - but it can also be done over a short range radio such as Bluetooth LE.
The new owner (aka Master) uses the
claim.html
page to scan the QRCode and thereby validating their proximity to (hence implied ownership of) the new device.
The |pipe| system facilitates a secure key-exchange between the device and the user's browser. Each side then stores the other's public key and it's fingerprint for future use.
Any subsequent incomming connection requests to the device are ignored unless they use the Master's public key. Connections that pass this test can then access the device's services .

Web Service

The |pipe| system leverages WebRTC functionality in the browsers, this functionality is only available to 'secure' sites, so the claim.html and other pages must be hosted on an https:// site. (or localhost: for testing)
We do not require any dynamic content on the site, so the pages can be hosted by any webservice - including github-pages or even jsfiddle.
When pairing, the Device stores the public key and identity in the keystore, but the webbrowser uses IndexDB. Access to IndexDb is restricted to pages from the 'same origin'. This means that the same site must be used to host both claim.html and any other pages that access the device.

Connecting to a device

The following steps are needed to connect to a device:
  1. Determine (or allocate) your own pipe-id:
            PipeDB.whoAmI(gotId, function(err) {
                console.log("could not create identity " + err);
            });
    
  2. Connect to the Rendevous service
           function gotId(id){
                duct = new PipeDuct(id);
                duct.getWs.onopen = function() {
                  chooseDevice();
                }
           }
    
  3. retreive the known device pipe-ids
          function chooseDevice(){
                PipeDb.dbListPrint(makeDc);
          }      
    
  4. Select a device and connect to a service on it
        function makeDc(friends) {
            duct.setNonce("");
            duct.setTo(friends[friends.length -1].finger);
            camPipe = pipe.createDataChannel("camera", {});
            camPipe.onopen = function() {
                camPipe.send(JSON.stringify({command: "read"}));
            };
            camPipe.onmessage = onDcMessage;
        }
    

Network topologies

The |pipe| system uses ICE (RFC 5245) to provide efficient and secure NAT traversal. Both the device and the browser (smartphone) can be behind different routers and still achive direct communication. In some cases this isn't possible and a |pipe| supplied TURN server will be used. The TURN server has no access to the content of the messages.
These features are a standard part of the Chrome, Firefox and Edge browsers.
In order to facilitate pairing and subsequent connections a |pipe| provided rendevous server is used. Devices and Browsers make websocket connections to this service to exchange setup messages.

Supported Services

The following services are supported in the prototype device agent: NOTE: Licensees can selectively enable features in their binary
featurelabelusageDevice dependenciesJSON?descriptionexampledoc
echoechoch.send("hello");nonenoDevice echos all received messagesEcho
tickticknonenosends a timestamp every secondTick
certcert{id: "1", action: "list"}noneyesCRUD for certsclaim.htmlCert
shellshell{command: "write",text:"ls -l"}noneyesruns "/bin/sh -i" on the device, sending received commands to the shell and returning stdout and stderr responsesshell.html
testtestnoneno
Beaglebone Analog inAIN[0-6]{command: "start"}BeagleBone onlynoSends values(voltages) read from /sys/devices/ocp.*/helper.*/AIN* every 30 secondssolar.html
Artik Analog inin_voltage0_raw{command: "start"}Artik onlyyesReads from /sys/devices/126c0000.adc/ on Artik park.html
DigitalOutGPIO60{command: "write",value:"1"}/sys/class/gpio/GPIO60yesReads and writes to GPIO digital pin
PWM outpwm[1-4]{command: "write",value:"1000000"}/sys/class/pwm/pwmchip0/ (Edison only)yesSends duty cycle value for digital outputtardis.html
CPU Temperaturethermal_zone[0-4]{command: "start"}/sys/class/thermal/thermal_zoneyesReads from /sys/class/thermal/thermal_zone0/temp and sends back values every 5stbone.html
Open Pixel Commandopc:127.0.0.1:7890{ command: "paint", pixels: [0x0,0xffffff]}assumes LedScape is running on localhostyesSend array of pixel RGB values to LedScape neopixel drivermorse.html
Bidirectional realtime audiortpmic{type:"upgrade",time:Date.now()}rtpmic script, softphone, micyes Upgrades peer connection to support realtime bi-directional audio over RTP - uses opus codec. Script starts local 'softphone' with rtp parameters pointing at localhostrtpmic.html
Stills cameracamera{command: "read"}camera.sh script and mjpeg camera pipe to camera on device or local networkyes Runs local script './camera.sh' to capture mjpegs from camera and write them into the named pipe './camera' - most recent frame is base64 encoded and sent on read commandcamera.html
Write to displayscreen{command:"show",tag:b64image}only supported on screens running Xwindowsyes Allows browser to send base64 encoded jpeg to show on device screennone
Database accessredis{command: "zrange", args : [hourS,"0","-1"]}redis running on localhostyes Provides read/search access to stored sensor data on device.
Write to pipefakerfid{command: "write", value:"rfid=1234"};named pipe 'fakerfid'yesWrites to the file './fakerfid' whci may be a named pipe - other processes can read from that filefakerfid.html
Proxy for Node.jstcp/127.0.0.1/9000nonenoOpens a bidirectional socket to port 9000 on the device and proxies data with the channel in the browsercompass.html
Proxy for websocketws://localhost:8181/websocket or ws://localhost:8181/websocket_api or ws://localhost:8181/bin_wsnonenoOpens a bidirectional websocket proxy to a websocket local to the device. Useful for wrapping pre-existing web admin consolesnone
Proxy for httphttp://localhost:8181/ or http://localhost:8080/{command:"index.html",method:"GET"}webservice running on device, bound to localhostyesOpens a http 1.1 connection to a device-local webserver, serves only GET requests returns JSON containing status, headers and a base64 encoded bodynone
Remote terminaltermmypty/ptynoOpens a bidirectional connectio to a unix ptty which spawns a shell as the local user. Useful in combination with terminal.js - disable on prduction devicesterm.html
Temp friendiphonetempfriend{action: "introduce" ,id:"FF..."}noneyesPerforms temp introduction - cert isn't stored. Devices can only support a single temp-friend at a time. Used to support ephermeral users - and early safari versionsishake.html

Factory Reset

Removing the file ipsecert.ks will remove all the pairing information from the device. When restarted it will show a QRcode again. This does not remove the corresponding entries in the user's smartphone, use:
            PipeDb.dbDelPrint(tofinger, dcb);
to do that. (see delete.html)

Device requirements

We currently require at minimum : We have tested on many small linux devices, we reccomend the Raspberry Pi 3 as a good starting point. The Device agent can also be run on a Mac or Windows machine, but many of the Services are not supported.

Smartphone requirements

We currently only support Android 5.X and higher - Chrome on Mac or Windows can also be used for testing, provided a good webcam is available. We have alpha support for safari on ios11 - only for one-time access - permission isn't persistant, yet. see ishake.html