UNPKG

caesarjs

Version:

A microservice framework for node.js implementing client-server mutual certificate authentication

175 lines (140 loc) 4.63 kB
'use strict'; const request = require('request'); const os = require('os'); const patrun = require('patrun'); const encryptor = require('simple-encryptor'); // lodash const isEmpty = require('lodash/isEmpty'); const isObject = require('lodash/isObject'); const has = require('lodash/has'); const isString = require('lodash/isString'); // status const status = require('statuses') // package const pack = require('../../package.json'); class CaesarClient { constructor (domain, port, opts = {}) { this.domain = domain; this.port = port; this.routesInfo = []; this.clientId = this.workOutClientId(opts.clientId); this.isSecure = false; if(isObject(opts) && isEmpty(opts) == false) { this.ca = opts.ca; this.isSecure = (this.ca) ? true : false; } this.encryptor = encryptor(opts.encryptorKey); this.protocol = (this.isSecure) ? 'https' : 'http'; this.baseUrl = `${this.protocol}://${this.domain}:${this.port}`; this.requestOptions = { url: this.baseUrl, agentOptions: { ca: this.ca } }; this.patrun = null; return this; } workOutClientId (clientId) { if(isString(clientId)) { return clientId; } return `${os.hostname()}-${os.type()}-${os.platform()}-${os.release()}`; } getRequestOptions (path, dataObject = {}) { let options = { url: `${this.baseUrl}${path}`, json: true, headers: { 'encryptor-data': this.encryptor.encrypt(dataObject), 'encryptor-client-id': this.encryptor.encrypt(this.clientId) } }; if(this.isSecure) { options = Object.assign( options, { agentOptions: { ca: this.ca } }); } return options; } findService (searchPattern) { return this.patrun.find(searchPattern); } decryptResponse (response) { if( has(response, 'encrypted-by-caesar') ) { response = this.encryptor.decrypt(response['encrypted-by-caesar']); } return response; } setServerRoutes (responseEncryptedBody) { let self = this; let response = self.decryptResponse(responseEncryptedBody); self.patrun = patrun(); self.routesInfo = response.routes; self.routesInfo.forEach( (routeInfo) => { self.patrun.add(routeInfo.patternObject, routeInfo); }); } init () { let self = this; return new Promise((resolve, reject) => { let requestOptions = this.getRequestOptions('/get-user-routes', {version: pack.version}); request.get(requestOptions, (err, resp) => { if(err) { return reject(err); } if(resp.statusCode !== 200) { const errorMessage = resp.body.error; return reject(new Error(`Caesar server has returned an error with code: ${resp.statusCode} - ${errorMessage}`)); } self.setServerRoutes(resp.body); return resolve(self); }); }); } call ( searchPattern, dataObject = {}) { let self = this; let service = self.findService(searchPattern); return new Promise((resolve, reject) => { if(!service || isEmpty(service)) { return reject(new Error('No service found with search pattern provided')); } let requestOptions = this.getRequestOptions(`/user-route/${service.urlId}`, dataObject); request.get(requestOptions, (err, resp) => { if(err) { return reject(err); } if(resp.statusCode !== 200) { let error = new Error(`${status[resp.statusCode]} error with status: ${resp.statusCode}`); error.statusCode = resp.statusCode; if(resp.statusCode === 404) { self.setServerRoutes(resp.body); } return reject(error); } return resolve(self.decryptResponse(resp.body)); }); }); } } module.exports = CaesarClient;