"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/npm/node_modules/request/lib/auth.js" (7 Feb 2017, 4777 Bytes) of archive /windows/misc/atom-windows.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Javascript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 'use strict'
    2 
    3 var caseless = require('caseless')
    4   , uuid = require('node-uuid')
    5   , helpers = require('./helpers')
    6 
    7 var md5 = helpers.md5
    8   , toBase64 = helpers.toBase64
    9 
   10 
   11 function Auth (request) {
   12   // define all public properties here
   13   this.request = request
   14   this.hasAuth = false
   15   this.sentAuth = false
   16   this.bearerToken = null
   17   this.user = null
   18   this.pass = null
   19 }
   20 
   21 Auth.prototype.basic = function (user, pass, sendImmediately) {
   22   var self = this
   23   if (typeof user !== 'string' || (pass !== undefined && typeof pass !== 'string')) {
   24     self.request.emit('error', new Error('auth() received invalid user or password'))
   25   }
   26   self.user = user
   27   self.pass = pass
   28   self.hasAuth = true
   29   var header = user + ':' + (pass || '')
   30   if (sendImmediately || typeof sendImmediately === 'undefined') {
   31     var authHeader = 'Basic ' + toBase64(header)
   32     self.sentAuth = true
   33     return authHeader
   34   }
   35 }
   36 
   37 Auth.prototype.bearer = function (bearer, sendImmediately) {
   38   var self = this
   39   self.bearerToken = bearer
   40   self.hasAuth = true
   41   if (sendImmediately || typeof sendImmediately === 'undefined') {
   42     if (typeof bearer === 'function') {
   43       bearer = bearer()
   44     }
   45     var authHeader = 'Bearer ' + (bearer || '')
   46     self.sentAuth = true
   47     return authHeader
   48   }
   49 }
   50 
   51 Auth.prototype.digest = function (method, path, authHeader) {
   52   // TODO: More complete implementation of RFC 2617.
   53   //   - handle challenge.domain
   54   //   - support qop="auth-int" only
   55   //   - handle Authentication-Info (not necessarily?)
   56   //   - check challenge.stale (not necessarily?)
   57   //   - increase nc (not necessarily?)
   58   // For reference:
   59   // http://tools.ietf.org/html/rfc2617#section-3
   60   // https://github.com/bagder/curl/blob/master/lib/http_digest.c
   61 
   62   var self = this
   63 
   64   var challenge = {}
   65   var re = /([a-z0-9_-]+)=(?:"([^"]+)"|([a-z0-9_-]+))/gi
   66   for (;;) {
   67     var match = re.exec(authHeader)
   68     if (!match) {
   69       break
   70     }
   71     challenge[match[1]] = match[2] || match[3]
   72   }
   73 
   74   /**
   75    * RFC 2617: handle both MD5 and MD5-sess algorithms.
   76    *
   77    * If the algorithm directive's value is "MD5" or unspecified, then HA1 is
   78    *   HA1=MD5(username:realm:password)
   79    * If the algorithm directive's value is "MD5-sess", then HA1 is
   80    *   HA1=MD5(MD5(username:realm:password):nonce:cnonce)
   81    */
   82   var ha1Compute = function (algorithm, user, realm, pass, nonce, cnonce) {
   83     var ha1 = md5(user + ':' + realm + ':' + pass)
   84     if (algorithm && algorithm.toLowerCase() === 'md5-sess') {
   85       return md5(ha1 + ':' + nonce + ':' + cnonce)
   86     } else {
   87       return ha1
   88     }
   89   }
   90 
   91   var qop = /(^|,)\s*auth\s*($|,)/.test(challenge.qop) && 'auth'
   92   var nc = qop && '00000001'
   93   var cnonce = qop && uuid().replace(/-/g, '')
   94   var ha1 = ha1Compute(challenge.algorithm, self.user, challenge.realm, self.pass, challenge.nonce, cnonce)
   95   var ha2 = md5(method + ':' + path)
   96   var digestResponse = qop
   97     ? md5(ha1 + ':' + challenge.nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + ha2)
   98     : md5(ha1 + ':' + challenge.nonce + ':' + ha2)
   99   var authValues = {
  100     username: self.user,
  101     realm: challenge.realm,
  102     nonce: challenge.nonce,
  103     uri: path,
  104     qop: qop,
  105     response: digestResponse,
  106     nc: nc,
  107     cnonce: cnonce,
  108     algorithm: challenge.algorithm,
  109     opaque: challenge.opaque
  110   }
  111 
  112   authHeader = []
  113   for (var k in authValues) {
  114     if (authValues[k]) {
  115       if (k === 'qop' || k === 'nc' || k === 'algorithm') {
  116         authHeader.push(k + '=' + authValues[k])
  117       } else {
  118         authHeader.push(k + '="' + authValues[k] + '"')
  119       }
  120     }
  121   }
  122   authHeader = 'Digest ' + authHeader.join(', ')
  123   self.sentAuth = true
  124   return authHeader
  125 }
  126 
  127 Auth.prototype.onRequest = function (user, pass, sendImmediately, bearer) {
  128   var self = this
  129     , request = self.request
  130 
  131   var authHeader
  132   if (bearer === undefined && user === undefined) {
  133     self.request.emit('error', new Error('no auth mechanism defined'))
  134   } else if (bearer !== undefined) {
  135     authHeader = self.bearer(bearer, sendImmediately)
  136   } else {
  137     authHeader = self.basic(user, pass, sendImmediately)
  138   }
  139   if (authHeader) {
  140     request.setHeader('authorization', authHeader)
  141   }
  142 }
  143 
  144 Auth.prototype.onResponse = function (response) {
  145   var self = this
  146     , request = self.request
  147 
  148   if (!self.hasAuth || self.sentAuth) { return null }
  149 
  150   var c = caseless(response.headers)
  151 
  152   var authHeader = c.get('www-authenticate')
  153   var authVerb = authHeader && authHeader.split(' ')[0].toLowerCase()
  154   request.debug('reauth', authVerb)
  155 
  156   switch (authVerb) {
  157     case 'basic':
  158       return self.basic(self.user, self.pass, true)
  159 
  160     case 'bearer':
  161       return self.bearer(self.bearerToken, true)
  162 
  163     case 'digest':
  164       return self.digest(request.method, request.path, authHeader)
  165   }
  166 }
  167 
  168 exports.Auth = Auth