http-auth-client
Version:
Client side HTTP Authorization header handling
92 lines (74 loc) • 3.02 kB
JavaScript
module.exports = { parseHeaders, pick, create }
const Basic = require('./basic')
const Digest = require('./digest')
const Bearer = require('./bearer')
module.exports.Basic = Basic
module.exports.Digest = Digest
module.exports.Bearer = Bearer
const DefaultTypes = [ Digest, Basic ]
function knownTypeFilter(typeHash) {
return challenge => challenge.name.toString().toLowerCase() in typeHash
}
function typeHash(typeList) {
return (typeList || DefaultTypes).reduce((types, type, index) => {
var name = (type.type || type.prototype.type).toString()
types[name.toLowerCase()] = { type, name, index }
return types
}, {})
}
function cmpChallenge(a, b, typeHash, algHash) {
var ta = typeHash[a.name.toLowerCase()], tb = typeHash[b.name.toLowerCase()]
if(ta.name == tb.name) {
return algHash[(a.params.algorithm||"").toLowerCase()] - algHash[(b.params.algorithm||"").toLowerCase()]
}
return ta.index - tb.index
}
function compare(typeHash, algHash) {
return (a, b) => cmpChallenge(a, b, typeHash, algHash)
}
function parseHeaders() {
var headers = Array.prototype.slice.call(arguments)
if(headers.length == 1 && headers[0].toString().toLowerCase().includes("www-authenticate:")) {
// All headers are in one string
headers = headers[0].split("\r\n")
.filter(line => line.toLowerCase().includes("www-authenticate"))
.map(line => line.replace(/^\s*www-authenticate\s*:\s*/i, ""))
}
var challenge_r = /\s*(\w+)\s+((?:\w+\s*=\s*(?:\w+|"[^"]+"))(?:\s*,\s*(?:\w+\s*=\s*(?:[\w-]+|"[^"]+")))*|[\w-.~+\/]+=*)\s*(?:,|$)/g
var challenges = []
for(var header of headers) {
var match
while(match = challenge_r.exec(header)) {
var [, name, params] = match
if(/=./.test(params)) {
var list = params.split(',')
params = list.reduce((params, line) => {
var match = /(\w+)\s*=\s*([\w-]+|"([^"]+)")/.exec(line)
params[match[1].toLowerCase()] = match[3] || match[2]
return params
}, {})
}
challenges.push({ name, params })
}
}
return challenges
}
function create(challenge, typeList) {
var types = typeHash(typeList)
if(typeof challenge == 'string') challenge = parseHeaders(challenge)
if(challenge instanceof Array) challenge = pick(challenge, typeList)[0]
if(!challenge || !challenge.name || !challenge.params) throw new Error("Invalid challenge")
var name = challenge.name.toString().toLowerCase()
if(name in types) return new types[name].type(challenge.params)
throw new TypeError("Unknown challenge type: " + challenge.name)
}
function pick(challenges, typeList, algList) {
if(typeof(challenges) == 'string') challenges = parseHeaders(challenges)
var types = typeHash(typeList)
var algs = (algList || Digest.Algorithms).reduce((algs, a, i) => {
var name = a.toString().toLowerCase()
algs[name] = name in algs ? (algs[name] < i ? algs[name] : i) : i
return algs
}, {})
return challenges.filter(knownTypeFilter(types)).sort(compare(types, algs))
}