/
opt
/
alt
/
alt-nodejs9
/
root
/
lib
/
node_modules
/
npm
/
node_modules.bundled
/
request
/
node_modules
/
hawk
/
lib
/
Upload Filee
HOME
'use strict'; // Load modules const Url = require('url'); const Hoek = require('hoek'); const Cryptiles = require('cryptiles'); const Crypto = require('./crypto'); const Utils = require('./utils'); // Declare internals const 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() / 1000, // A pre-calculated timestamp in seconds 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) { const result = { field: '', artifacts: {} }; // Validate inputs if (!uri || (typeof uri !== 'string' && typeof uri !== 'object') || !method || typeof method !== 'string' || !options || typeof options !== 'object') { result.err = 'Invalid argument type'; return result; } // Application time const timestamp = options.timestamp || Utils.nowSecs(options.localtimeOffsetMsec); // Validate credentials const 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 const artifacts = { ts: timestamp, nonce: options.nonce || Cryptiles.randomString(6), 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); } const mac = Crypto.calculateMac('header', credentials, artifacts); // Construct header const hasExt = artifacts.ext !== null && artifacts.ext !== undefined && artifacts.ext !== ''; // Other falsey values allowed let 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, callback) { artifacts = Hoek.clone(artifacts); options = options || {}; let wwwAttributes = null; let serverAuthAttributes = null; const finalize = function (err) { if (callback) { const headers = { 'www-authenticate': wwwAttributes, 'server-authorization': serverAuthAttributes }; return callback(err, headers); } return !err; }; if (res.headers['www-authenticate']) { // Parse HTTP WWW-Authenticate header wwwAttributes = Utils.parseAuthorizationHeader(res.headers['www-authenticate'], ['ts', 'tsm', 'error']); if (wwwAttributes instanceof Error) { wwwAttributes = null; return finalize(new Error('Invalid WWW-Authenticate header')); } // Validate server timestamp (not used to update clock since it is done via the SNPT client) if (wwwAttributes.ts) { const tsm = Crypto.calculateTsMac(wwwAttributes.ts, credentials); if (tsm !== wwwAttributes.tsm) { return finalize(new Error('Invalid server timestamp hash')); } } } // Parse HTTP Server-Authorization header if (!res.headers['server-authorization'] && !options.required) { return finalize(); } serverAuthAttributes = Utils.parseAuthorizationHeader(res.headers['server-authorization'], ['mac', 'ext', 'hash']); if (serverAuthAttributes instanceof Error) { serverAuthAttributes = null; return finalize(new Error('Invalid Server-Authorization header')); } artifacts.ext = serverAuthAttributes.ext; artifacts.hash = serverAuthAttributes.hash; const mac = Crypto.calculateMac('response', credentials, artifacts); if (mac !== serverAuthAttributes.mac) { return finalize(new Error('Bad response mac')); } if (!options.payload && options.payload !== '') { return finalize(); } if (!serverAuthAttributes.hash) { return finalize(new Error('Missing response hash attribute')); } const calculatedHash = Crypto.calculatePayloadHash(options.payload, credentials.algorithm, res.headers['content-type']); if (calculatedHash !== serverAuthAttributes.hash) { return finalize(new Error('Bad response payload mac')); } return finalize(); }; // 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 !== 'object') || !options || typeof options !== 'object' || !options.ttlSec) { return ''; } options.ext = (options.ext === null || options.ext === undefined ? '' : options.ext); // Zero is valid value // Application time const now = Utils.now(options.localtimeOffsetMsec); // Validate credentials const 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 const exp = Math.floor(now / 1000) + options.ttlSec; const 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 const 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() / 1000, // A pre-calculated timestamp in seconds 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 !== 'object') { return null; } // Application time const timestamp = options.timestamp || Utils.nowSecs(options.localtimeOffsetMsec); // Validate credentials const 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 const artifacts = { ts: timestamp, nonce: options.nonce || Cryptiles.randomString(6), host, port, hash: Crypto.calculatePayloadHash(message, credentials.algorithm) }; // Construct authorization const result = { id: credentials.id, ts: artifacts.ts, nonce: artifacts.nonce, hash: artifacts.hash, mac: Crypto.calculateMac('message', credentials, artifacts) }; return result; };