Guest User

Untitled

a guest
May 26th, 2018
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.61 KB | None | 0 0
  1. /**
  2. * Provide digestFetch function
  3. */
  4.  
  5. const crypto = require('crypto');
  6. const nodeFetch = require('node-fetch');
  7. const mergeOptions = require('merge-options');
  8.  
  9. const cnonceSize = 32;
  10. const nonceRaw = 'abcdef0123456789';
  11.  
  12. function makeNonce () {
  13. let uid = '';
  14. for (let i = 0; i < cnonceSize; ++i) {
  15. uid += nonceRaw[Math.floor(Math.random() * nonceRaw.length)];
  16. }
  17. return uid;
  18. }
  19.  
  20. function md5(data) {
  21. return crypto.createHash('md5').update(data).digest('hex');
  22. }
  23.  
  24. function ha1Compute(algorithm, user, realm, pass, nonce, cnonce) {
  25. const ha1 = md5(`${user}:${realm}:${pass}`);
  26. if (algorithm && algorithm.toLowerCase() === 'md5-sess') {
  27. return md5(`${ha1}:${nonce}:${cnonce}`);
  28. } else {
  29. return ha1;
  30. }
  31. }
  32.  
  33. function digestFetch(username, password) {
  34. const digest = { nc: 0, algorithm: 'md5' };
  35. let hasAuth = false;
  36.  
  37. function parseAuth (response) {
  38. const authHeader = response.headers.get('www-authenticate');
  39.  
  40. if (authHeader.split(/\s/)[0].toLowerCase() !== 'digest') {
  41. return false;
  42. }
  43.  
  44. const re = /([a-z0-9_-]+)=(?:"([^"]+)"|([a-z0-9_-]+))/gi;
  45. for (;;) {
  46. var match = re.exec(authHeader);
  47. if (!match) {
  48. break;
  49. }
  50. digest[match[1]] = match[2] || match[3];
  51. }
  52.  
  53. digest.nc++;
  54. digest.cnonce = makeNonce();
  55.  
  56. return true;
  57. }
  58.  
  59. function addAuth (url, options) {
  60. if (!hasAuth) {
  61. return options;
  62. }
  63.  
  64. const _url = url.replace('//', '');
  65. const uri = _url.indexOf('/') == -1 ? '/' : _url.slice(_url.indexOf('/'));
  66.  
  67. const method = options.method ? options.method.toUpperCase() : 'GET';
  68.  
  69. const qop = /(^|,)\s*auth\s*($|,)/.test(digest.qop) && 'auth';
  70. const ncString = (`00000000${digest.nc}`).slice(-8);
  71. const cnonce = digest.cnonce;
  72. const ha1 = ha1Compute(digest.algorithm, username, digest.realm, password, digest.nonce, digest.cnonce);
  73. const ha2 = md5(`${method}:${uri}`);
  74.  
  75. const digestResponse = qop
  76. ? md5(`${ha1}:${digest.nonce}:${ncString}:${digest.cnonce}:${qop}:${ha2}`)
  77. : md5(`${ha1}:${digest.nonce}:${ha2}`);
  78.  
  79. const authValues = {
  80. username,
  81. realm: digest.realm,
  82. nonce: digest.nonce,
  83. uri,
  84. qop,
  85. response: digestResponse,
  86. nc: ncString,
  87. cnonce: digest.cnonce,
  88. algorithm: digest.algorithm,
  89. opaque: digest.opaque
  90. };
  91.  
  92. const authHeader = [];
  93. for (var k in authValues) {
  94. if (authValues[k]) {
  95. if (k === 'qop' || k === 'nc' || k === 'algorithm') {
  96. authHeader.push(`${k}=${authValues[k]}`);
  97. } else {
  98. authHeader.push(`${k}="${authValues[k]}"`);
  99. }
  100. }
  101. }
  102.  
  103. return mergeOptions(options, { headers: { Authorization: 'Digest ' + authHeader.join(', ') } });
  104. }
  105.  
  106. return async function fetch (url, options = {}) {
  107. const response = await nodeFetch(url, addAuth(url, options));
  108.  
  109. if (response.status == 401) {
  110. hasAuth = parseAuth(response);
  111.  
  112. if (hasAuth) {
  113. const response2 = await nodeFetch(url, addAuth(url, options));
  114.  
  115. if (response2.status == 401) {
  116. hasAuth = false;
  117. } else {
  118. digest.nc++;
  119. }
  120.  
  121. return response2;
  122. }
  123. } else {
  124. digest.nc++;
  125. }
  126.  
  127. return response;
  128. }
  129. }
  130.  
  131. module.exports = digestFetch;
Add Comment
Please, Sign In to add comment