<commit_before>'use strict'

var crypto = require('crypto')
  , uuid = require('node-uuid')


function auth (req, options, res) {
  var auth = options.auth || {}
    , header

  // request
  if (!res) {
    if (auth.user) {
      header = basic(auth)
    }
    else if (auth.bearer) {
      header = bearer(auth)
    }
    else if (options.hawk) {
      header = hawk(options)
    }
    else if (options.httpSignature) {
      header = httpSignature(options)
    }
    else if (options.aws) {
      header = aws(options)
    }
  }
  // response
  else {
    if (auth.sendImmediately) return

    var authHeader = res.headers.get('www-authenticate')
      , authVerb = authHeader && authHeader.split(' ')[0].toLowerCase()

    auth.sendImmediately = true

    if (authVerb === 'basic') {
      header = basic(auth)
    }
    else if (authVerb === 'bearer') {
      header = bearer(auth)
    }
    else if (authVerb === 'digest') {
      header = digest(auth.user, auth.pass, options.method, options.path, authHeader)
    }
  }

  if (header) {
    options.headers.set('authorization', header)
  }
}

function basic (auth) {
  if (auth.sendImmediately || auth.sendImmediately === undefined) {
    auth.sendImmediately = true
    var header = 'Basic ' + toBase64(auth.user + ':' + (auth.pass || ''))
    return header
  }
}

function bearer (auth) {
  if (auth.sendImmediately || auth.sendImmediately === undefined) {
    auth.sendImmediately = true
    var header = 'Bearer ' + (auth.bearer || '')
    return header
  }
}

function digest (user, pass, method, path, authHeader) {
  // TODO: More complete implementation of RFC 2617.
  //   - check challenge.algorithm
  //   - support algorithm="MD5-sess"
  //   - handle challenge.domain
  //   - support qop="auth-int" only
  //   - handle Authentication-Info (not necessarily?)
  //   - check challenge.stale (not necessarily?)
  //   - increase nc (not necessarily?)
  // For reference:
  // http://tools.ietf.org/html/rfc2617#section-3
  // https://github.com/bagder/curl/blob/master/lib/http_digest.c

  var challenge = {}
  var re = /([a-z0-9_-]+)=(?:"([^"]+)"|([a-z0-9_-]+))/gi
  for (;;) {
    var match = re.exec(authHeader)
    if (!match) {
      break
    }
    challenge[match[1]] = match[2] || match[3]
  }

  var ha1 = md5(user + ':' + challenge.realm + ':' + pass)
  var ha2 = md5(method + ':' + path)
  var qop = /(^|,)\s*auth\s*($|,)/.test(challenge.qop) && 'auth'
  var nc = qop && '00000001'
  var cnonce = qop && uuid().replace(/-/g, '')
  var digestResponse = qop
    ? md5(ha1 + ':' + challenge.nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + ha2)
    : md5(ha1 + ':' + challenge.nonce + ':' + ha2)
  var authValues = {
    username: user,
    realm: challenge.realm,
    nonce: challenge.nonce,
    uri: path,
    qop: qop,
    response: digestResponse,
    nc: nc,
    cnonce: cnonce,
    algorithm: challenge.algorithm,
    opaque: challenge.opaque
  }

  authHeader = []
  for (var k in authValues) {
    if (authValues[k]) {
      if (k === 'qop' || k === 'nc' || k === 'algorithm') {
        authHeader.push(k + '=' + authValues[k])
      } else {
        authHeader.push(k + '="' + authValues[k] + '"')
      }
    }
  }
  var header = 'Digest ' + authHeader.join(', ')
  return header
}

function toBase64 (str) {
  return (new Buffer(str || '', 'utf8')).toString('base64')
}

function md5 (str) {
  return crypto.createHash('md5').update(str).digest('hex')
}

//

function hawk (options) {<commit_msg>Move digest logic into separate module<commit_after>'use strict'

var _digest = require('request-digest')


function auth (req, options, res) {
  var auth = options.auth || {}
    , header

  // request
  if (!res) {
    if (auth.user) {
      header = basic(auth)
    }
    else if (auth.bearer) {
      header = bearer(auth)
    }
    else if (options.hawk) {
      header = hawk(options)
    }
    else if (options.httpSignature) {
      header = httpSignature(options)
    }
    else if (options.aws) {
      header = aws(options)
    }
  }
  // response
  else {
    if (auth.sendImmediately) return

    var authHeader = res.headers.get('www-authenticate')
      , authVerb = authHeader && authHeader.split(' ')[0].toLowerCase()

    auth.sendImmediately = true

    if (authVerb === 'basic') {
      header = basic(auth)
    }
    else if (authVerb === 'bearer') {
      header = bearer(auth)
    }
    else if (authVerb === 'digest') {
      header = digest(auth.user, auth.pass, options.method, options.path, authHeader)
    }
  }

  if (header) {
    options.headers.set('authorization', header)
  }
}

function basic (auth) {
  function toBase64 (str) {
    return (new Buffer(str || '', 'utf8')).toString('base64')
  }

  if (auth.sendImmediately || auth.sendImmediately === undefined) {
    auth.sendImmediately = true
    var header = 'Basic ' + toBase64(auth.user + ':' + (auth.pass || ''))
    return header
  }
}

function bearer (auth) {
  if (auth.sendImmediately || auth.sendImmediately === undefined) {
    auth.sendImmediately = true
    var header = 'Bearer ' + (auth.bearer || '')
    return header
  }
}

function digest (user, pass, method, path, authHeader) {
  var header = 'Digest ' + _digest(user, pass, method, path, authHeader)
  return header
}

function hawk (options) {
{'fraction_non_alphanumeric': 0.1671077504725898, 'fraction_numerical': 0.01001890359168242, 'mean_word_length': 2.679415855354659, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 1, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4399454', 'n_tokens_mistral': 1882, 'n_tokens_neox': 1823, 'n_words': 406}