UNPKG

serialport-v5

Version:

fork with electron support of Node.js package to access serial ports. Linux, OSX and Windows. Welcome your robotic JavaScript overlords. Better yet, program them!

344 lines (242 loc) 10.6 kB
'use strict' // Load modules ; var _typeof = function (obj) { return obj && typeof Symbol !== 'undefined' && obj.constructor === Symbol ? 'symbol' : typeof obj; }; var Url = require('url'); var Hoek = require('hoek'); var Cryptiles = require('cryptiles'); var Crypto = require('./crypto'); var Utils = require('./utils'); // Declare internals var internals = {}; // Generate an Authorization header for a given request /* uri: 'http://example.com/resource?a=b' or object from Url.parse() method: HTTP verb (e.g. 'GET', 'POST') options: { // Required credentials: { id: 'dh37fgj492je', key: 'aoijedoaijsdlaksjdl', algorithm: 'sha256' // 'sha1', 'sha256' }, // Optional ext: 'application-specific', // Application specific data sent via the ext attribute timestamp: Date.now(), // A pre-calculated timestamp nonce: '2334f34f', // A pre-generated nonce localtimeOffsetMsec: 400, // Time offset to sync with server time (ignored if timestamp provided) payload: '{"some":"payload"}', // UTF-8 encoded string for body hash generation (ignored if hash provided) contentType: 'application/json', // Payload content-type (ignored if hash provided) hash: 'U4MKKSmiVxk37JCCrAVIjV=', // Pre-calculated payload hash app: '24s23423f34dx', // Oz application id dlg: '234sz34tww3sd' // Oz delegated-by application id } */ exports.header = function (uri, method, options) { var result = { field: '', artifacts: {} }; // Validate inputs if (!uri || typeof uri !== 'string' && (typeof uri === 'undefined' ? 'undefined' : _typeof(uri)) !== 'object' || !method || typeof method !== 'string' || !options || (typeof options === 'undefined' ? 'undefined' : _typeof(options)) !== 'object') { result.err = 'Invalid argument type'; return result; } // Application time var timestamp = options.timestamp || Utils.nowSecs(options.localtimeOffsetMsec); // Validate credentials var credentials = options.credentials; if (!credentials || !credentials.id || !credentials.key || !credentials.algorithm) { result.err = 'Invalid credential object'; return result; } if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) { result.err = 'Unknown algorithm'; return result; } // Parse URI if (typeof uri === 'string') { uri = Url.parse(uri); } // Calculate signature var artifacts = { ts: timestamp, nonce: options.nonce || Cryptiles.randomString(6), method: method, resource: uri.pathname + (uri.search || ''), // Maintain trailing '?' host: uri.hostname, port: uri.port || (uri.protocol === 'http:' ? 80 : 443), hash: options.hash, ext: options.ext, app: options.app, dlg: options.dlg }; result.artifacts = artifacts; // Calculate payload hash if (!artifacts.hash && (options.payload || options.payload === '')) { artifacts.hash = Crypto.calculatePayloadHash(options.payload, credentials.algorithm, options.contentType); } var mac = Crypto.calculateMac('header', credentials, artifacts); // Construct header var hasExt = artifacts.ext !== null && artifacts.ext !== undefined && artifacts.ext !== ''; // Other falsey values allowed var header = 'Hawk id="' + credentials.id + '", ts="' + artifacts.ts + '", nonce="' + artifacts.nonce + (artifacts.hash ? '", hash="' + artifacts.hash : '') + (hasExt ? '", ext="' + Hoek.escapeHeaderAttribute(artifacts.ext) : '') + '", mac="' + mac + '"'; if (artifacts.app) { header = header + ', app="' + artifacts.app + (artifacts.dlg ? '", dlg="' + artifacts.dlg : '') + '"'; } result.field = header; return result; }; // Validate server response /* res: node's response object artifacts: object received from header().artifacts options: { payload: optional payload received required: specifies if a Server-Authorization header is required. Defaults to 'false' } */ exports.authenticate = function (res, credentials, artifacts, options) { artifacts = Hoek.clone(artifacts); options = options || {}; if (res.headers['www-authenticate']) { // Parse HTTP WWW-Authenticate header var wwwAttributes = Utils.parseAuthorizationHeader(res.headers['www-authenticate'], ['ts', 'tsm', 'error']); if (wwwAttributes instanceof Error) { return false; } // Validate server timestamp (not used to update clock since it is done via the SNPT client) if (wwwAttributes.ts) { var tsm = Crypto.calculateTsMac(wwwAttributes.ts, credentials); if (tsm !== wwwAttributes.tsm) { return false; } } } // Parse HTTP Server-Authorization header if (!res.headers['server-authorization'] && !options.required) { return true; } var attributes = Utils.parseAuthorizationHeader(res.headers['server-authorization'], ['mac', 'ext', 'hash']); if (attributes instanceof Error) { return false; } artifacts.ext = attributes.ext; artifacts.hash = attributes.hash; var mac = Crypto.calculateMac('response', credentials, artifacts); if (mac !== attributes.mac) { return false; } if (!options.payload && options.payload !== '') { return true; } if (!attributes.hash) { return false; } var calculatedHash = Crypto.calculatePayloadHash(options.payload, credentials.algorithm, res.headers['content-type']); return calculatedHash === attributes.hash; }; // Generate a bewit value for a given URI /* uri: 'http://example.com/resource?a=b' or object from Url.parse() options: { // Required credentials: { id: 'dh37fgj492je', key: 'aoijedoaijsdlaksjdl', algorithm: 'sha256' // 'sha1', 'sha256' }, ttlSec: 60 * 60, // TTL in seconds // Optional ext: 'application-specific', // Application specific data sent via the ext attribute localtimeOffsetMsec: 400 // Time offset to sync with server time }; */ exports.getBewit = function (uri, options) { // Validate inputs if (!uri || typeof uri !== 'string' && (typeof uri === 'undefined' ? 'undefined' : _typeof(uri)) !== 'object' || !options || (typeof options === 'undefined' ? 'undefined' : _typeof(options)) !== 'object' || !options.ttlSec) { return ''; } options.ext = options.ext === null || options.ext === undefined ? '' : options.ext; // Zero is valid value // Application time var now = Utils.now(options.localtimeOffsetMsec); // Validate credentials var credentials = options.credentials; if (!credentials || !credentials.id || !credentials.key || !credentials.algorithm) { return ''; } if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) { return ''; } // Parse URI if (typeof uri === 'string') { uri = Url.parse(uri); } // Calculate signature var exp = Math.floor(now / 1000) + options.ttlSec; var mac = Crypto.calculateMac('bewit', credentials, { ts: exp, nonce: '', method: 'GET', resource: uri.pathname + (uri.search || ''), // Maintain trailing '?' host: uri.hostname, port: uri.port || (uri.protocol === 'http:' ? 80 : 443), ext: options.ext }); // Construct bewit: id\exp\mac\ext var bewit = credentials.id + '\\' + exp + '\\' + mac + '\\' + options.ext; return Hoek.base64urlEncode(bewit); }; // Generate an authorization string for a message /* host: 'example.com', port: 8000, message: '{"some":"payload"}', // UTF-8 encoded string for body hash generation options: { // Required credentials: { id: 'dh37fgj492je', key: 'aoijedoaijsdlaksjdl', algorithm: 'sha256' // 'sha1', 'sha256' }, // Optional timestamp: Date.now(), // A pre-calculated timestamp nonce: '2334f34f', // A pre-generated nonce localtimeOffsetMsec: 400, // Time offset to sync with server time (ignored if timestamp provided) } */ exports.message = function (host, port, message, options) { // Validate inputs if (!host || typeof host !== 'string' || !port || typeof port !== 'number' || message === null || message === undefined || typeof message !== 'string' || !options || (typeof options === 'undefined' ? 'undefined' : _typeof(options)) !== 'object') { return null; } // Application time var timestamp = options.timestamp || Utils.nowSecs(options.localtimeOffsetMsec); // Validate credentials var credentials = options.credentials; if (!credentials || !credentials.id || !credentials.key || !credentials.algorithm) { // Invalid credential object return null; } if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) { return null; } // Calculate signature var artifacts = { ts: timestamp, nonce: options.nonce || Cryptiles.randomString(6), host: host, port: port, hash: Crypto.calculatePayloadHash(message, credentials.algorithm) }; // Construct authorization var result = { id: credentials.id, ts: artifacts.ts, nonce: artifacts.nonce, hash: artifacts.hash, mac: Crypto.calculateMac('message', credentials, artifacts) }; return result; };