hawk.js (2750B)
1 'use strict' 2 3 var crypto = require('crypto') 4 5 function randomString (size) { 6 var bits = (size + 1) * 6 7 var buffer = crypto.randomBytes(Math.ceil(bits / 8)) 8 var string = buffer.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '') 9 return string.slice(0, size) 10 } 11 12 function calculatePayloadHash (payload, algorithm, contentType) { 13 var hash = crypto.createHash(algorithm) 14 hash.update('hawk.1.payload\n') 15 hash.update((contentType ? contentType.split(';')[0].trim().toLowerCase() : '') + '\n') 16 hash.update(payload || '') 17 hash.update('\n') 18 return hash.digest('base64') 19 } 20 21 exports.calculateMac = function (credentials, opts) { 22 var normalized = 'hawk.1.header\n' + 23 opts.ts + '\n' + 24 opts.nonce + '\n' + 25 (opts.method || '').toUpperCase() + '\n' + 26 opts.resource + '\n' + 27 opts.host.toLowerCase() + '\n' + 28 opts.port + '\n' + 29 (opts.hash || '') + '\n' 30 31 if (opts.ext) { 32 normalized = normalized + opts.ext.replace('\\', '\\\\').replace('\n', '\\n') 33 } 34 35 normalized = normalized + '\n' 36 37 if (opts.app) { 38 normalized = normalized + opts.app + '\n' + (opts.dlg || '') + '\n' 39 } 40 41 var hmac = crypto.createHmac(credentials.algorithm, credentials.key).update(normalized) 42 var digest = hmac.digest('base64') 43 return digest 44 } 45 46 exports.header = function (uri, method, opts) { 47 var timestamp = opts.timestamp || Math.floor((Date.now() + (opts.localtimeOffsetMsec || 0)) / 1000) 48 var credentials = opts.credentials 49 if (!credentials || !credentials.id || !credentials.key || !credentials.algorithm) { 50 return '' 51 } 52 53 if (['sha1', 'sha256'].indexOf(credentials.algorithm) === -1) { 54 return '' 55 } 56 57 var artifacts = { 58 ts: timestamp, 59 nonce: opts.nonce || randomString(6), 60 method: method, 61 resource: uri.pathname + (uri.search || ''), 62 host: uri.hostname, 63 port: uri.port || (uri.protocol === 'http:' ? 80 : 443), 64 hash: opts.hash, 65 ext: opts.ext, 66 app: opts.app, 67 dlg: opts.dlg 68 } 69 70 if (!artifacts.hash && (opts.payload || opts.payload === '')) { 71 artifacts.hash = calculatePayloadHash(opts.payload, credentials.algorithm, opts.contentType) 72 } 73 74 var mac = exports.calculateMac(credentials, artifacts) 75 76 var hasExt = artifacts.ext !== null && artifacts.ext !== undefined && artifacts.ext !== '' 77 var header = 'Hawk id="' + credentials.id + 78 '", ts="' + artifacts.ts + 79 '", nonce="' + artifacts.nonce + 80 (artifacts.hash ? '", hash="' + artifacts.hash : '') + 81 (hasExt ? '", ext="' + artifacts.ext.replace(/\\/g, '\\\\').replace(/"/g, '\\"') : '') + 82 '", mac="' + mac + '"' 83 84 if (artifacts.app) { 85 header = header + ', app="' + artifacts.app + (artifacts.dlg ? '", dlg="' + artifacts.dlg : '') + '"' 86 } 87 88 return header 89 }