| 'use strict'; |
| |
| // Load modules |
| |
| const Crypto = require('crypto'); |
| const Url = require('url'); |
| const Utils = require('./utils'); |
| |
| |
| // Declare internals |
| |
| const internals = {}; |
| |
| |
| // MAC normalization format version |
| |
| exports.headerVersion = '1'; // Prevent comparison of mac values generated with different normalized string formats |
| |
| |
| // Supported HMAC algorithms |
| |
| exports.algorithms = ['sha1', 'sha256']; |
| |
| |
| // Calculate the request MAC |
| |
| /* |
| type: 'header', // 'header', 'bewit', 'response' |
| credentials: { |
| key: 'aoijedoaijsdlaksjdl', |
| algorithm: 'sha256' // 'sha1', 'sha256' |
| }, |
| options: { |
| method: 'GET', |
| resource: '/resource?a=1&b=2', |
| host: 'example.com', |
| port: 8080, |
| ts: 1357718381034, |
| nonce: 'd3d345f', |
| hash: 'U4MKKSmiVxk37JCCrAVIjV/OhB3y+NdwoCr6RShbVkE=', |
| ext: 'app-specific-data', |
| app: 'hf48hd83qwkj', // Application id (Oz) |
| dlg: 'd8djwekds9cj' // Delegated by application id (Oz), requires options.app |
| } |
| */ |
| |
| exports.calculateMac = function (type, credentials, options) { |
| |
| const normalized = exports.generateNormalizedString(type, options); |
| |
| const hmac = Crypto.createHmac(credentials.algorithm, credentials.key).update(normalized); |
| const digest = hmac.digest('base64'); |
| return digest; |
| }; |
| |
| |
| exports.generateNormalizedString = function (type, options) { |
| |
| let resource = options.resource || ''; |
| if (resource && |
| resource[0] !== '/') { |
| |
| const url = Url.parse(resource, false); |
| resource = url.path; // Includes query |
| } |
| |
| let normalized = 'hawk.' + exports.headerVersion + '.' + type + '\n' + |
| options.ts + '\n' + |
| options.nonce + '\n' + |
| (options.method || '').toUpperCase() + '\n' + |
| resource + '\n' + |
| options.host.toLowerCase() + '\n' + |
| options.port + '\n' + |
| (options.hash || '') + '\n'; |
| |
| if (options.ext) { |
| normalized = normalized + options.ext.replace('\\', '\\\\').replace('\n', '\\n'); |
| } |
| |
| normalized = normalized + '\n'; |
| |
| if (options.app) { |
| normalized = normalized + options.app + '\n' + |
| (options.dlg || '') + '\n'; |
| } |
| |
| return normalized; |
| }; |
| |
| |
| exports.calculatePayloadHash = function (payload, algorithm, contentType) { |
| |
| const hash = exports.initializePayloadHash(algorithm, contentType); |
| hash.update(payload || ''); |
| return exports.finalizePayloadHash(hash); |
| }; |
| |
| |
| exports.initializePayloadHash = function (algorithm, contentType) { |
| |
| const hash = Crypto.createHash(algorithm); |
| hash.update('hawk.' + exports.headerVersion + '.payload\n'); |
| hash.update(Utils.parseContentType(contentType) + '\n'); |
| return hash; |
| }; |
| |
| |
| exports.finalizePayloadHash = function (hash) { |
| |
| hash.update('\n'); |
| return hash.digest('base64'); |
| }; |
| |
| |
| exports.calculateTsMac = function (ts, credentials) { |
| |
| const hmac = Crypto.createHmac(credentials.algorithm, credentials.key); |
| hmac.update('hawk.' + exports.headerVersion + '.ts\n' + ts + '\n'); |
| return hmac.digest('base64'); |
| }; |
| |
| |
| exports.timestampMessage = function (credentials, localtimeOffsetMsec) { |
| |
| const now = Utils.nowSecs(localtimeOffsetMsec); |
| const tsm = exports.calculateTsMac(now, credentials); |
| return { ts: now, tsm }; |
| }; |