Miss any of our Open RFC calls?Watch the recordings here! »

tls-json

3.2.0 • Public • Published

tls-json

A node.js client and server api for bidirectional sending of json over tls after exchanging a password.

When using a reconnectInterval on the client end of the api, clients will reconnect to a server if a connection is lost.

Install

npm install tls-json

Usage

Generate cert

openssl genrsa -out server-key.pem 2048
openssl req -new -key server-key.pem -out server-csr.pem
openssl x509 -req -in server-csr.pem -signkey server-key.pem -out server-cert.pem

Generate localhost cert

# a dev env ~10 year cert, such as the one used in the example code below
openssl req -x509 -newkey rsa:2048 -sha256 -nodes -keyout localhost.key -out localhost.crt -subj "/CN=localhost" -days 3650

General

The api is essentially the following events: authenticated, close, error, message where messages is a JavaScript object (send as JSON). The outgoing sections of the api are the functions send and request. Send will send a message, without any acknowledgement needed. Request sends a message and returns a promise that will resolve to the response -- in other words requests are acknowledged and the sender can be sure that they were received. A simplified request and response pattern is used, where the req contains the data sent, and the res can be used to reply.

Client and server have essentially the same api for communication, with main difference being that the outgoing server calls take a client id as an argument (that's who the message goes to). The client on the other hand invokes send and request without an id because all of its messages can only go to the server.

New to version 3.2+

A keepalive ping/pong have been added (works automatically, no api changes, but configurable if desired).

Server API

const fs = require('fs')
const TLSServer = require('tls-json').Server
 
const port = 8888
 
const server = new TLSServer({
    // this is a tls options object, see https://nodejs.org/api/tls.html
    options: {
        key:  fs.readFileSync('localhost.key'),
        cert: fs.readFileSync('localhost.crt'),
        rejectUnauthorized: true
    },
    requestTimeout: 10000, // milliseconds until a request is considered timedout
    keepAliveInterval: 10000, // milliseconds interval to check if the socket is alive
    keepAliveTimeout: 5000 // milliseconds until a socket is considered dead if it hasn't responded
    password: 'this string is a password, change it'
})
 
// client connected and supplied password correctly
server.on('authenticated', (id, socket) => {
    console.log('authenticated', id, socket.remoteAddress)
})
 
// client closed connection
// gauranteed to fire if a client disconnects, timeouts, etc
server.on('close', id => {
    console.log('connection closed', id)
})
 
// client sent a message
server.on('message', (id, message) => {
    console.log('message', message, 'from', id)
})
 
// client sent a request
server.on('request', (id, req, res) => {
    console.log('request', req, 'from', id)
    // like node, always use res.send when answering a request
    res.send({ anything: 'this is a response to your request'}) 
})
 
// note: close will always fire if there is a problem, so error and
// timeout are merely for information/debugging
server.on('error', (id, err) => {
    console.log('error', err, 'from', id)
})
server.on('timeout', (id) => {
    console.log('timeout', id)
})
 
server.listen(port, () => {
    console.log(`TLSServer listening on port ${port}`)
})
 
/* outgoing examples */
// NOTE: to send anything we just refer to the client by id
server.send(id, { hello: 'world' })
server.request(id, { hello: 'world' })
    .then(data => {} )
    .catch (err => {} )
// or
try {
    const data = await server.request(id, { hello: 'world' })
} catch (err) {
 
}
// and of course responding to requests is outgoing as well

Clients are assigned an id when they connect, and their id is the first arg for all events. This id can be used to send messages and requests to the clients..

Client API

const fs = require('fs')
const TLSClient = require('tls-json').Client
 
const client = new TLSClient({
    // see: https://nodejs.org/api/tls.html for tls options
    options: {      
        ca: [fs.readFileSync('localhost.crt')]  // example allows self-signed certs
    },    
    host: 'localhost',
    port: 8888,
    reconnectInterval: 5000, // milliseocnds required! defaults to 0 which is no reconnecting
    requestTimeout: 10000,
    password: 'this string is a password, change it'
})
 
client.on('authenticated', () => {
    console.log('authenticated')
})
 
client.on('message', message => {
    console.log('Message from server', message)
})
 
client.on('close', () => {
    console.log('TLSClient connection closed')
})
 
client.on('error', err => {
    console.log('TLSClient connection error', err)
})
 
// informational
client.on('reconnectAttempt', () => {
    // invoked once per reconnect attempt, if you don't mind the spam
})
 
client.on('request', (req, res) => {
    res.send({ hello: 'kitty!' })
})
 
/* outgoing */
// NOTE: no id needed, the client only sends to the server
client.send({ any: message })
client.request({ any: message })
    .then(data => {})
    .catch(err => {})
//or
try {
    const data = await client.request({ some: 'thing' })
} catch (err) {
 
}
 
// and of course responding to requests is outgoing as well

Clients with a reconnectInterval > 0 will automatically attempt to reconnect to a server after losing connection. Clients will not automatically send messages that failed to send prior to losing connection (this may be done manually if desired, but be careful about the volume).

Errors

These are errors that can come through the error eventer handler, or through the request promises

  • any socket errors such as ECONNRESET, or ECONNREFUSED, etc
  • 'not connected or not authenticated' - when using send this is emitted if the client or server has not yet authenticated or is not connected, when using request this same error will come through the promise
  • request timeout - when no response comes back within requestTimeout, most likely caused by forgetting to use res.send()
  • connection lost - rare, but can occur if a request is made but the connection is lost before the other service can respond

For spam reasons when a client is in reconnect mode the ECONNREFUSED errors and socket close errors are suppressed. If you'd like to log how often reconnect attempts occur anyways, listen for reconnectAttempt.

Install

npm i tls-json

DownloadsWeekly Downloads

1

Version

3.2.0

License

MIT

Unpacked Size

38 kB

Total Files

13

Last publish

Collaborators

  • avatar