UNPKG

http-auth-client

Version:

Client side HTTP Authorization header handling

92 lines (74 loc) 3.02 kB
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)) }