You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
79 lines
2.6 KiB
79 lines
2.6 KiB
4 weeks ago
|
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;
|