index.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. const crypto = require('crypto');
  2. const AUTH_KEY_VALUE_RE = /(\w+)=["']?([^'"]{1,10000})["']?/;
  3. let NC = 0;
  4. const NC_PAD = '00000000';
  5. function md5(text) {
  6. return crypto.createHash('md5').update(text).digest('hex');
  7. }
  8. function digestAuthHeader(method, uri, wwwAuthenticate, userpass) {
  9. const parts = wwwAuthenticate.split(',');
  10. const opts = {};
  11. for (let i = 0; i < parts.length; i++) {
  12. const m = AUTH_KEY_VALUE_RE.exec(parts[i]);
  13. if (m) {
  14. opts[m[1]] = m[2].replace(/["']/g, '');
  15. }
  16. }
  17. if (!opts.realm || !opts.nonce) {
  18. return '';
  19. }
  20. let qop = opts.qop || '';
  21. // WWW-Authenticate: Digest realm="testrealm@host.com",
  22. // qop="auth,auth-int",
  23. // nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
  24. // opaque="5ccc069c403ebaf9f0171e9517f40e41"
  25. // Authorization: Digest username="Mufasa",
  26. // realm="testrealm@host.com",
  27. // nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
  28. // uri="/dir/index.html",
  29. // qop=auth,
  30. // nc=00000001,
  31. // cnonce="0a4f113b",
  32. // response="6629fae49393a05397450978507c4ef1",
  33. // opaque="5ccc069c403ebaf9f0171e9517f40e41"
  34. // HA1 = MD5( "Mufasa:testrealm@host.com:Circle Of Life" )
  35. // = 939e7578ed9e3c518a452acee763bce9
  36. //
  37. // HA2 = MD5( "GET:/dir/index.html" )
  38. // = 39aff3a2bab6126f332b942af96d3366
  39. //
  40. // Response = MD5( "939e7578ed9e3c518a452acee763bce9:\
  41. // dcd98b7102dd2f0e8b11d0f600bfb0c093:\
  42. // 00000001:0a4f113b:auth:\
  43. // 39aff3a2bab6126f332b942af96d3366" )
  44. // = 6629fae49393a05397450978507c4ef1
  45. userpass = userpass.split(':');
  46. let nc = String(++NC);
  47. nc = NC_PAD.substring(nc.length) + nc;
  48. const cnonce = crypto.randomBytes(8).toString('hex');
  49. const ha1 = md5(userpass[0] + ':' + opts.realm + ':' + userpass[1]);
  50. const ha2 = md5(method.toUpperCase() + ':' + uri);
  51. let s = ha1 + ':' + opts.nonce;
  52. if (qop) {
  53. qop = qop.split(',')[0];
  54. s += ':' + nc + ':' + cnonce + ':' + qop;
  55. }
  56. s += ':' + ha2;
  57. const response = md5(s);
  58. let authstring = 'Digest username="' + userpass[0] + '", realm="' + opts.realm
  59. + '", nonce="' + opts.nonce + '", uri="' + uri
  60. + '", response="' + response + '"';
  61. if (opts.opaque) {
  62. authstring += ', opaque="' + opts.opaque + '"';
  63. }
  64. if (qop) {
  65. authstring +=', qop=' + qop + ', nc=' + nc + ', cnonce="' + cnonce + '"';
  66. }
  67. return authstring;
  68. }
  69. module.exports = digestAuthHeader;