-
Notifications
You must be signed in to change notification settings - Fork 0
Textric Routing Protocol
This document attempts to describe how Textric routes messages. It covers from send, through route, to delivery at the endpoint destination.
As detailed elsewhere in this Wiki, the originating device (i.e., the sender) will construct a payload that, at the bare minimum, contains the userID of the intended recipient. This is sent as a POST request to the server, using the fingerprint generated during device enrollment.
Keep in mind; only authenticated devices can send, so we implicitly know the sender's identity.
The server will lookup the user, and then fire off copies to each of the user's devices, assuming they are listening. Ideally, this is done by iterating through active connections...
We'd probably also send push notifications; something like APNs or FCM. So we'll need to keep some other bits of information about the user in this case. Alternatively, at least for APNs, we could even send a background notification...?
Regardless, if an app isn't listening, we'll queue it on the server instead. How long do we keep it? Good question...
In the meantime, the client app has a web socket connected to our server; we pump it down the web socket, and then read it from there and do what we do best!
For now, Textric shall use the standardized WebSocket protocol for communication. After device enrollment, recall that devices (and the server!) now possesses a "fingerprint"; it's a fast pass the device can use to log in.
This protocol makes judicious use of the EncryptedPayload object; it is a JSON payload with the following shape:
{
"iv": "string",
"payload": "string"
}-
iv: The Initialization Vector, used by the cipher and decipher. This is base64-encoded; to retrieve the actual IV, it must be decoded -
payload: The encrypted string. As with the IV, this is base-64 encoded; it must be coded before it can be decrypted.
The key used for all encryption is the device's fingerprint. For more information on how this is created, see the Device Enrollment API. Note that this fingerprint must be decoded from base-64 to be used!
First, the device sets up a WebSocket connection to the server; by default, this is port 8080. Once connected, it sends the following payload:
{
"handle": "string",
"deviceID": "string",
"devNonce": "EncryptedPayload"
}-
handle: The user's handle -
deviceID: The ID of the sending device. -
devNonce: A nonce, generated by the device and encrypted as anEncryptedPayload. This can be any number of any size, but this number MUST BE encoded as a string; for example, the number12345should be sent as"12345".
If this is rejected, an error message - a Message with type ERR - is sent. Note that this is sent regardless of the actual reason (i.e., device does not exist, etc.). At this point, the device should instead attempt re-enrollment.
The server will decrypt the device's nonce and increment it; it will also generate its own nonce, srvNonce. Finally, it will respond with the following payload:
{
"devInc": "EncryptedPayload",
"srvNonce": "EncryptedPayload"
}-
devInc: The device's nonce, incremented by one and encrypted with the shared secret. -
srvNonce: The server's nonce, encrypted with the shared secret.
The device SHOULD ensure that devInc matches what it should match. The device should then decrypt the server's nonce, increment it, and send it back, along with any channel configuration - this configuration is reserved for future use, and is sent in the clear. This payload has the following shape:
{
"srvInc": "EncryptedPayload",
"config": {}
}At this point, the handshake is complete. All future messages should be sent as EncryptedPayloads, where the JSON for the message has been serialized and then encrypted; this is the payload for the EncryptedPayload.
Both the server and client MUST NOT reuse Initialization Vectors.
Upon success, the server will respond with an AACK message. At this point, new messages will be pumped down, and sent messages can be pumped up.