| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 | /*	MIT License http://www.opensource.org/licenses/mit-license.php	Author Tobias Koppers @sokra*/"use strict";const AbstractMethodError = require("../AbstractMethodError");const BULK_SIZE = 1000;class Hash {	/**	 * Update hash {@link https://nodejs.org/api/crypto.html#crypto_hash_update_data_inputencoding}	 * @param {string|Buffer} data data	 * @param {string=} inputEncoding data encoding	 * @returns {this} updated hash	 */	update(data, inputEncoding) {		throw new AbstractMethodError();	}	/**	 * Calculates the digest {@link https://nodejs.org/api/crypto.html#crypto_hash_digest_encoding}	 * @param {string=} encoding encoding of the return value	 * @returns {string|Buffer} digest	 */	digest(encoding) {		throw new AbstractMethodError();	}}exports.Hash = Hash;/** @typedef {typeof Hash} HashConstructor */class BulkUpdateDecorator extends Hash {	/**	 * @param {Hash} hash hash	 */	constructor(hash) {		super();		this.hash = hash;		this.buffer = "";	}	/**	 * Update hash {@link https://nodejs.org/api/crypto.html#crypto_hash_update_data_inputencoding}	 * @param {string|Buffer} data data	 * @param {string=} inputEncoding data encoding	 * @returns {this} updated hash	 */	update(data, inputEncoding) {		if (			inputEncoding !== undefined ||			typeof data !== "string" ||			data.length > BULK_SIZE		) {			if (this.buffer.length > 0) {				this.hash.update(this.buffer);				this.buffer = "";			}			this.hash.update(data, inputEncoding);		} else {			this.buffer += data;			if (this.buffer.length > BULK_SIZE) {				this.hash.update(this.buffer);				this.buffer = "";			}		}		return this;	}	/**	 * Calculates the digest {@link https://nodejs.org/api/crypto.html#crypto_hash_digest_encoding}	 * @param {string=} encoding encoding of the return value	 * @returns {string|Buffer} digest	 */	digest(encoding) {		if (this.buffer.length > 0) {			this.hash.update(this.buffer);		}		var digestResult = this.hash.digest(encoding);		return typeof digestResult === "string"			? digestResult			: digestResult.toString();	}}/** * istanbul ignore next */class DebugHash extends Hash {	constructor() {		super();		this.string = "";	}	/**	 * Update hash {@link https://nodejs.org/api/crypto.html#crypto_hash_update_data_inputencoding}	 * @param {string|Buffer} data data	 * @param {string=} inputEncoding data encoding	 * @returns {this} updated hash	 */	update(data, inputEncoding) {		if (typeof data !== "string") data = data.toString("utf-8");		this.string += data;		return this;	}	/**	 * Calculates the digest {@link https://nodejs.org/api/crypto.html#crypto_hash_digest_encoding}	 * @param {string=} encoding encoding of the return value	 * @returns {string|Buffer} digest	 */	digest(encoding) {		return this.string.replace(/[^a-z0-9]+/gi, m =>			Buffer.from(m).toString("hex")		);	}}/** * Creates a hash by name or function * @param {string | HashConstructor} algorithm the algorithm name or a constructor creating a hash * @returns {Hash} the hash */module.exports = algorithm => {	if (typeof algorithm === "function") {		return new BulkUpdateDecorator(new algorithm());	}	switch (algorithm) {		// TODO add non-cryptographic algorithm here		case "debug":			return new DebugHash();		default:			return new BulkUpdateDecorator(require("crypto").createHash(algorithm));	}};
 |