index.js 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. /**!
  2. * digest-header - index.js
  3. *
  4. * Copyright(c) fengmk2 and other contributors.
  5. * MIT Licensed
  6. *
  7. * Authors:
  8. * fengmk2 <fengmk2@gmail.com> (http://fengmk2.github.com)
  9. */
  10. 'use strict';
  11. /**
  12. * Module dependencies.
  13. */
  14. var crypto = require('crypto');
  15. var utility = require('utility');
  16. var AUTH_KEY_VALUE_RE = /(\w+)=["']?([^'"]+)["']?/;
  17. var NC = 0;
  18. var NC_PAD = '00000000';
  19. function digestAuthHeader(method, uri, wwwAuthenticate, userpass) {
  20. var parts = wwwAuthenticate.split(',');
  21. var opts = {};
  22. for (var i = 0; i < parts.length; i++) {
  23. var m = parts[i].match(AUTH_KEY_VALUE_RE);
  24. if (m) {
  25. opts[m[1]] = m[2].replace(/["']/g, '');
  26. }
  27. }
  28. if (!opts.realm || !opts.nonce) {
  29. return '';
  30. }
  31. var qop = opts.qop || '';
  32. // WWW-Authenticate: Digest realm="testrealm@host.com",
  33. // qop="auth,auth-int",
  34. // nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
  35. // opaque="5ccc069c403ebaf9f0171e9517f40e41"
  36. // Authorization: Digest username="Mufasa",
  37. // realm="testrealm@host.com",
  38. // nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
  39. // uri="/dir/index.html",
  40. // qop=auth,
  41. // nc=00000001,
  42. // cnonce="0a4f113b",
  43. // response="6629fae49393a05397450978507c4ef1",
  44. // opaque="5ccc069c403ebaf9f0171e9517f40e41"
  45. // HA1 = MD5( "Mufasa:testrealm@host.com:Circle Of Life" )
  46. // = 939e7578ed9e3c518a452acee763bce9
  47. //
  48. // HA2 = MD5( "GET:/dir/index.html" )
  49. // = 39aff3a2bab6126f332b942af96d3366
  50. //
  51. // Response = MD5( "939e7578ed9e3c518a452acee763bce9:\
  52. // dcd98b7102dd2f0e8b11d0f600bfb0c093:\
  53. // 00000001:0a4f113b:auth:\
  54. // 39aff3a2bab6126f332b942af96d3366" )
  55. // = 6629fae49393a05397450978507c4ef1
  56. userpass = userpass.split(':');
  57. var nc = String(++NC);
  58. nc = NC_PAD.substring(nc.length) + nc;
  59. var cnonce = crypto.randomBytes(8).toString('hex');
  60. var ha1 = utility.md5(userpass[0] + ':' + opts.realm + ':' + userpass[1]);
  61. var ha2 = utility.md5(method.toUpperCase() + ':' + uri);
  62. var s = ha1 + ':' + opts.nonce;
  63. if (qop) {
  64. qop = qop.split(',')[0];
  65. s += ':' + nc + ':' + cnonce + ':' + qop;
  66. }
  67. s += ':' + ha2;
  68. var response = utility.md5(s);
  69. var authstring = 'Digest username="' + userpass[0] + '", realm="' + opts.realm
  70. + '", nonce="' + opts.nonce + '", uri="' + uri
  71. + '", response="' + response + '"';
  72. if (opts.opaque) {
  73. authstring += ', opaque="' + opts.opaque + '"';
  74. }
  75. if (qop) {
  76. authstring +=', qop=' + qop + ', nc=' + nc + ', cnonce="' + cnonce + '"';
  77. }
  78. return authstring;
  79. }
  80. module.exports = digestAuthHeader;