All files / request/lib oauth.js

16.86% Statements 14/83
0% Branches 0/57
14.28% Functions 1/7
16.86% Lines 14/83

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149    1x 1x 1x 1x 1x 1x 1x     2x 2x     1x                                                                                               1x                         1x                                 1x                                                                                                           1x  
'use strict'
 
var url = require('url')
var qs = require('qs')
var caseless = require('caseless')
var uuid = require('uuid/v4')
var oauth = require('oauth-sign')
var crypto = require('crypto')
var Buffer = require('safe-buffer').Buffer
 
function OAuth (request) {
  this.request = request
  this.params = null
}
 
OAuth.prototype.buildParams = function (_oauth, uri, method, query, form, qsLib) {
  var oa = {}
  for (var i in _oauth) {
    oa['oauth_' + i] = _oauth[i]
  }
  if (!oa.oauth_version) {
    oa.oauth_version = '1.0'
  }
  if (!oa.oauth_timestamp) {
    oa.oauth_timestamp = Math.floor(Date.now() / 1000).toString()
  }
  if (!oa.oauth_nonce) {
    oa.oauth_nonce = uuid().replace(/-/g, '')
  }
  if (!oa.oauth_signature_method) {
    oa.oauth_signature_method = 'HMAC-SHA1'
  }
 
  var consumer_secret_or_private_key = oa.oauth_consumer_secret || oa.oauth_private_key // eslint-disable-line camelcase
  delete oa.oauth_consumer_secret
  delete oa.oauth_private_key
 
  var token_secret = oa.oauth_token_secret // eslint-disable-line camelcase
  delete oa.oauth_token_secret
 
  var realm = oa.oauth_realm
  delete oa.oauth_realm
  delete oa.oauth_transport_method
 
  var baseurl = uri.protocol + '//' + uri.host + uri.pathname
  var params = qsLib.parse([].concat(query, form, qsLib.stringify(oa)).join('&'))
 
  oa.oauth_signature = oauth.sign(
    oa.oauth_signature_method,
    method,
    baseurl,
    params,
    consumer_secret_or_private_key, // eslint-disable-line camelcase
    token_secret // eslint-disable-line camelcase
  )
 
  if (realm) {
    oa.realm = realm
  }
 
  return oa
}
 
OAuth.prototype.buildBodyHash = function (_oauth, body) {
  if (['HMAC-SHA1', 'RSA-SHA1'].indexOf(_oauth.signature_method || 'HMAC-SHA1') < 0) {
    this.request.emit('error', new Error('oauth: ' + _oauth.signature_method +
      ' signature_method not supported with body_hash signing.'))
  }
 
  var shasum = crypto.createHash('sha1')
  shasum.update(body || '')
  var sha1 = shasum.digest('hex')
 
  return Buffer.from(sha1, 'hex').toString('base64')
}
 
OAuth.prototype.concatParams = function (oa, sep, wrap) {
  wrap = wrap || ''
 
  var params = Object.keys(oa).filter(function (i) {
    return i !== 'realm' && i !== 'oauth_signature'
  }).sort()
 
  if (oa.realm) {
    params.splice(0, 0, 'realm')
  }
  params.push('oauth_signature')
 
  return params.map(function (i) {
    return i + '=' + wrap + oauth.rfc3986(oa[i]) + wrap
  }).join(sep)
}
 
OAuth.prototype.onRequest = function (_oauth) {
  var self = this
  self.params = _oauth
 
  var uri = self.request.uri || {}
  var method = self.request.method || ''
  var headers = caseless(self.request.headers)
  var body = self.request.body || ''
  var qsLib = self.request.qsLib || qs
 
  var form
  var query
  var contentType = headers.get('content-type') || ''
  var formContentType = 'application/x-www-form-urlencoded'
  var transport = _oauth.transport_method || 'header'
 
  if (contentType.slice(0, formContentType.length) === formContentType) {
    contentType = formContentType
    form = body
  }
  if (uri.query) {
    query = uri.query
  }
  if (transport === 'body' && (method !== 'POST' || contentType !== formContentType)) {
    self.request.emit('error', new Error('oauth: transport_method of body requires POST ' +
      'and content-type ' + formContentType))
  }
 
  if (!form && typeof _oauth.body_hash === 'boolean') {
    _oauth.body_hash = self.buildBodyHash(_oauth, self.request.body.toString())
  }
 
  var oa = self.buildParams(_oauth, uri, method, query, form, qsLib)
 
  switch (transport) {
    case 'header':
      self.request.setHeader('Authorization', 'OAuth ' + self.concatParams(oa, ',', '"'))
      break
 
    case 'query':
      var href = self.request.uri.href += (query ? '&' : '?') + self.concatParams(oa, '&')
      self.request.uri = url.parse(href)
      self.request.path = self.request.uri.path
      break
 
    case 'body':
      self.request.body = (form ? form + '&' : '') + self.concatParams(oa, '&')
      break
 
    default:
      self.request.emit('error', new Error('oauth: transport_method invalid'))
  }
}
 
exports.OAuth = OAuth