twitst4tz

twitter statistics web application
Log | Files | Refs | README | LICENSE

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 }