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.

createHash.js 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const AbstractMethodError = require("../AbstractMethodError");
  7. const BULK_SIZE = 1000;
  8. class Hash {
  9. /**
  10. * Update hash {@link https://nodejs.org/api/crypto.html#crypto_hash_update_data_inputencoding}
  11. * @param {string|Buffer} data data
  12. * @param {string=} inputEncoding data encoding
  13. * @returns {this} updated hash
  14. */
  15. update(data, inputEncoding) {
  16. throw new AbstractMethodError();
  17. }
  18. /**
  19. * Calculates the digest {@link https://nodejs.org/api/crypto.html#crypto_hash_digest_encoding}
  20. * @param {string=} encoding encoding of the return value
  21. * @returns {string|Buffer} digest
  22. */
  23. digest(encoding) {
  24. throw new AbstractMethodError();
  25. }
  26. }
  27. exports.Hash = Hash;
  28. /** @typedef {typeof Hash} HashConstructor */
  29. class BulkUpdateDecorator extends Hash {
  30. /**
  31. * @param {Hash} hash hash
  32. */
  33. constructor(hash) {
  34. super();
  35. this.hash = hash;
  36. this.buffer = "";
  37. }
  38. /**
  39. * Update hash {@link https://nodejs.org/api/crypto.html#crypto_hash_update_data_inputencoding}
  40. * @param {string|Buffer} data data
  41. * @param {string=} inputEncoding data encoding
  42. * @returns {this} updated hash
  43. */
  44. update(data, inputEncoding) {
  45. if (
  46. inputEncoding !== undefined ||
  47. typeof data !== "string" ||
  48. data.length > BULK_SIZE
  49. ) {
  50. if (this.buffer.length > 0) {
  51. this.hash.update(this.buffer);
  52. this.buffer = "";
  53. }
  54. this.hash.update(data, inputEncoding);
  55. } else {
  56. this.buffer += data;
  57. if (this.buffer.length > BULK_SIZE) {
  58. this.hash.update(this.buffer);
  59. this.buffer = "";
  60. }
  61. }
  62. return this;
  63. }
  64. /**
  65. * Calculates the digest {@link https://nodejs.org/api/crypto.html#crypto_hash_digest_encoding}
  66. * @param {string=} encoding encoding of the return value
  67. * @returns {string|Buffer} digest
  68. */
  69. digest(encoding) {
  70. if (this.buffer.length > 0) {
  71. this.hash.update(this.buffer);
  72. }
  73. var digestResult = this.hash.digest(encoding);
  74. return typeof digestResult === "string"
  75. ? digestResult
  76. : digestResult.toString();
  77. }
  78. }
  79. /**
  80. * istanbul ignore next
  81. */
  82. class DebugHash extends Hash {
  83. constructor() {
  84. super();
  85. this.string = "";
  86. }
  87. /**
  88. * Update hash {@link https://nodejs.org/api/crypto.html#crypto_hash_update_data_inputencoding}
  89. * @param {string|Buffer} data data
  90. * @param {string=} inputEncoding data encoding
  91. * @returns {this} updated hash
  92. */
  93. update(data, inputEncoding) {
  94. if (typeof data !== "string") data = data.toString("utf-8");
  95. this.string += data;
  96. return this;
  97. }
  98. /**
  99. * Calculates the digest {@link https://nodejs.org/api/crypto.html#crypto_hash_digest_encoding}
  100. * @param {string=} encoding encoding of the return value
  101. * @returns {string|Buffer} digest
  102. */
  103. digest(encoding) {
  104. return this.string.replace(/[^a-z0-9]+/gi, m =>
  105. Buffer.from(m).toString("hex")
  106. );
  107. }
  108. }
  109. /**
  110. * Creates a hash by name or function
  111. * @param {string | HashConstructor} algorithm the algorithm name or a constructor creating a hash
  112. * @returns {Hash} the hash
  113. */
  114. module.exports = algorithm => {
  115. if (typeof algorithm === "function") {
  116. return new BulkUpdateDecorator(new algorithm());
  117. }
  118. switch (algorithm) {
  119. // TODO add non-cryptographic algorithm here
  120. case "debug":
  121. return new DebugHash();
  122. default:
  123. return new BulkUpdateDecorator(require("crypto").createHash(algorithm));
  124. }
  125. };