const crypto = require('crypto'); const AUTH_KEY_VALUE_RE = /(\w+)=["']?([^'"]{1,10000})["']?/; let NC = 0; const NC_PAD = '00000000'; function md5(text) { return crypto.createHash('md5').update(text).digest('hex'); } function digestAuthHeader(method, uri, wwwAuthenticate, userpass) { const parts = wwwAuthenticate.split(','); const opts = {}; for (let i = 0; i < parts.length; i++) { const m = AUTH_KEY_VALUE_RE.exec(parts[i]); if (m) { opts[m[1]] = m[2].replace(/["']/g, ''); } } if (!opts.realm || !opts.nonce) { return ''; } let qop = opts.qop || ''; // WWW-Authenticate: Digest realm="testrealm@host.com", // qop="auth,auth-int", // nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", // opaque="5ccc069c403ebaf9f0171e9517f40e41" // Authorization: Digest username="Mufasa", // realm="testrealm@host.com", // nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", // uri="/dir/index.html", // qop=auth, // nc=00000001, // cnonce="0a4f113b", // response="6629fae49393a05397450978507c4ef1", // opaque="5ccc069c403ebaf9f0171e9517f40e41" // HA1 = MD5( "Mufasa:testrealm@host.com:Circle Of Life" ) // = 939e7578ed9e3c518a452acee763bce9 // // HA2 = MD5( "GET:/dir/index.html" ) // = 39aff3a2bab6126f332b942af96d3366 // // Response = MD5( "939e7578ed9e3c518a452acee763bce9:\ // dcd98b7102dd2f0e8b11d0f600bfb0c093:\ // 00000001:0a4f113b:auth:\ // 39aff3a2bab6126f332b942af96d3366" ) // = 6629fae49393a05397450978507c4ef1 userpass = userpass.split(':'); let nc = String(++NC); nc = NC_PAD.substring(nc.length) + nc; const cnonce = crypto.randomBytes(8).toString('hex'); const ha1 = md5(userpass[0] + ':' + opts.realm + ':' + userpass[1]); const ha2 = md5(method.toUpperCase() + ':' + uri); let s = ha1 + ':' + opts.nonce; if (qop) { qop = qop.split(',')[0]; s += ':' + nc + ':' + cnonce + ':' + qop; } s += ':' + ha2; const response = md5(s); let authstring = 'Digest username="' + userpass[0] + '", realm="' + opts.realm + '", nonce="' + opts.nonce + '", uri="' + uri + '", response="' + response + '"'; if (opts.opaque) { authstring += ', opaque="' + opts.opaque + '"'; } if (qop) { authstring +=', qop=' + qop + ', nc=' + nc + ', cnonce="' + cnonce + '"'; } return authstring; } module.exports = digestAuthHeader;