You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
3.5 KiB
128 lines
3.5 KiB
'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 }; |
|
};
|
|
|