WebSockets

The Hydra-Router supports WebSocket connections. However, it only accepts stringified UMF formatted messages.

let ws = new WebSocket('ws://127.0.0.1:5353');
ws.on('open', () => {
  let msg = {
    'to': 'a-hydra-service:/',
    'version': 'UMF/1.4.3',
    'from': 'tester:/',
    'mid': '4736ef3d-fcbb-46aa-80a0-f4f3493e1d74',
    'timestamp': '2017-01-12T20:16:29.157Z',
    'body': {}
  };
  ws.send(JSON.stringify(msg));
});

WebSocket reconnection and messaging

Hydra-Router supports queuing messages intended for your WebSocket client should your client's WebSocket connection break. Your client only needs to reconnect and issues a reconnection message to begin receiving earlier messages.

Upon an initial connection your WebSocket client will receive a message that looks a bit like this:

{
  "to": "2945p8eigxz@client:/",
  "frm": "c274b25909aee5cbec2857361f425fa7@hydra-router:/",
  "mid": "dffc2949-0e2a-4417-8f28-46addb5fc716",
  "ts": "2017-01-12T19:31:54.831Z",
  "typ": "connection",
  "ver": "UMF/1.4.3",
  "bdy": {
    "id": "2945p8eigxz"
  }
}

Thebdy.idvalue is the WebSocket session ID. If your client dies and needs to reconnect it can issue a reconnection message such as:

{
  "to": "hydra-router:/",
  "frm": "client:/",
  "mid": "e173a0da-2785-4f83-8b39-0dea954dd91b",
  "typ": "reconnection",
  "ver": "UMF/1.4.3",
  "bdy": {
    "id": "2945p8eigxz"
  }
}

There are three things to note above. First the message is sent to thehydra-routerwhich manages the actual WebSocket connections. Secondarily, thebdy.idis the same as the WebSocket session ID that the client had before it crashed or lost its connection. Thirdly, we use a message type (typ) of "reconnection".

Upon receiving a message like that, Hydra-Router will load queued messages (if any) and begin sending them to your newly connected client.

Securing Websocket messages

Hydra-Router supports using cryptographically signed UMF messages. When this feature is enabled only signed messages will be accepted. Non-signed messages will result in the termination of the underlying socket connection.

A signed message only ensures that a message was created by a known client and does not in itself encrypt message content. To encrypt message content consider using other cryptographic methods and converting to BASE64.

To enable signed messages add two fields to your config.json file. Ensure that forceMessageSignture is set to true and that signatureSharedSecret contains a UUID or passphrase

"forceMessageSignature": true, 
"signatureSharedSecret": "d632dd6d-fb75-44cc-bdbf-ee1364f3716c",

HydraRouter uses HMAC SHA-256 to sign messages using the supplied signatureSharedSecret

This is accomplished in HydraRouter using the following NodeJS crypto code.

crypto
  .createHmac('sha256', signatureSharedSecret)
  .update(JSON.stringify(this.message))
  .digest('hex');

Because the Websocket messages are sent from external clients, each client must be capable of signing UMF messages using HMAC SHA-256 using the same shared secret as stored in HydraRouter's config.json file. Due to the difficulty of securing a secret in web browser clients it's not recommended for web client use. Microservices and mobile applications which are compiled and are able to use secure storage are recommended.

As of version 1.4.28, Hydra supports signing UMF messages making it easy to secure messages between microservices. Client applications written for iOS or Android require the use of a cryptographic library.

In Hydra you can use:

'use strict';

const WebSocket = require('ws');
const hydra = require('hydra');
const signatureSharedSecret = 'd632dd6d-fb75-44cc-bdbf-ee1364f3716c';

let ws = new WebSocket('http://localhost:5353');

ws.on('open', () => {
  let umf = hydra.createUMFMessage({
    'to': 'hydra-router:[GET]/v1/router/list/nodes',
    'from': 'client:/',
    'body': {}
  });
  umf.signMessage('sha256', signatureSharedSecret);
  ws.send(JSON.stringify(umf));
});

ws.on('message', (data, flags) => {
  console.log(data);
});

Example program repos

You can see the new reconnection logic by trying the following two examples.

To try this you need to have both Redis and a hydra-router running locally. You then start a copy of themessage-echo-servicewhich will essentially relay messages to a sender. Themessage-sender-servicesends message to the echo service.

You can terminate the sender at some point and then restart it using theidof the first connection response.

$ node message-sender-service 1fh5zi3fglr

That will put the sender app into a reconnection and retrieval mode.

results matching ""

    No results matching ""