mcard-js
Version:
A JavaScript implementation of MCard - A data model for persistently storing content with cryptographic hashing and timestamping
260 lines (231 loc) • 9.06 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "HASH_ALGORITHM_HIERARCHY", {
enumerable: true,
get: function () {
return _config_constants.HASH_ALGORITHM_HIERARCHY;
}
});
Object.defineProperty(exports, "HashAlgorithm", {
enumerable: true,
get: function () {
return _config_constants.HashAlgorithm;
}
});
Object.defineProperty(exports, "VALID_HASH_FUNCTIONS", {
enumerable: true,
get: function () {
return _config_constants.VALID_HASH_FUNCTIONS;
}
});
exports.default = void 0;
var _textEncoderPolyfill = require("../../utils/textEncoderPolyfill.js");
var _bufferPolyfill = require("../../utils/bufferPolyfill.js");
var _cryptoPolyfill = require("../../utils/cryptoPolyfill.js");
var _config_constants = require("../../config/config_constants.js");
// Replace direct crypto import with environment-aware implementation
// Check if we're in a browser environment
const isBrowser = typeof window !== 'undefined';
class HashValidator {
/**
* Constructor for HashValidator
*/
constructor(content, hashAlgorithm = _config_constants.HashAlgorithm.DEFAULT) {
// Convert content to Buffer/Uint8Array if it's a string
this.content = _bufferPolyfill.SafeBuffer.isBuffer(content) ? content : (0, _textEncoderPolyfill.encodeText)(content);
this.hashAlgorithm = this.normalizeHashAlgorithm(hashAlgorithm);
// In browser environments, we can't synchronously compute crypto hashes
if (isBrowser) {
this.hashValue = "computing...";
this._computeHashAsync().then(hash => {
this.hashValue = hash;
});
} else {
this.hashValue = this.computeHash();
}
}
/**
* Async computation of hash for browser environments
* @private
*/
async _computeHashAsync() {
const hash = (0, _cryptoPolyfill.createHash)(this.hashAlgorithm);
hash.update(this.content);
return await hash.digest('hex');
}
/**
* Normalizes the hash algorithm input
* @param {string|Object} hashAlgorithm - The hash algorithm to normalize
* @returns {string} Normalized hash algorithm
*/
normalizeHashAlgorithm(hashAlgorithm) {
// Handle undefined or null input
if (hashAlgorithm === undefined || hashAlgorithm === null) {
return _config_constants.HashAlgorithm.DEFAULT || 'sha256';
}
// If input is an object, try to extract the type
if (typeof hashAlgorithm === 'object') {
hashAlgorithm = hashAlgorithm.type || hashAlgorithm.value || _config_constants.HashAlgorithm.DEFAULT || 'sha256';
}
// Convert to lowercase string and remove dashes for consistency
const normalizedAlgo = String(hashAlgorithm).toLowerCase().replace(/-/g, '');
// Validate the hash algorithm
if (!HashValidator.isValidHashFunction(normalizedAlgo)) {
console.warn(`Invalid hash algorithm: ${normalizedAlgo}, using default instead`);
return _config_constants.HashAlgorithm.DEFAULT || 'sha256';
}
return normalizedAlgo;
}
/**
* Validates a hash function
* @param {string} hashFunction - Hash function to validate
* @returns {boolean} Whether the hash function is valid
*/
static isValidHashFunction(hashFunction) {
if (!hashFunction) return false;
const normalizedFunc = String(hashFunction).toLowerCase().trim();
// Accept both formats: with dashes (Web Crypto format) and without dashes (Node.js format)
const validAlgorithms = [
// Node.js format
'md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512',
// Web Crypto format
'sha-1', 'sha-256', 'sha-384', 'sha-512'];
return validAlgorithms.includes(normalizedFunc) || validAlgorithms.includes(normalizedFunc.replace(/-/g, ''));
}
/**
* Compute hash from content
* @returns {string|Promise<string>} Computed hash or promise to hash
*/
computeHash() {
try {
const hash = (0, _cryptoPolyfill.createHash)(this.hashAlgorithm);
hash.update(this.content);
const result = hash.digest('hex');
// Handle the case where result is a Promise
if (result instanceof Promise) {
return "computing...";
}
return result;
} catch (e) {
console.error('Error computing hash:', e);
return '';
}
}
/**
* Getter for hash value
* @returns {string} Hash value
*/
getHashValue() {
return this.hashValue;
}
/**
* Getter for hash algorithm
* @returns {string} Hash algorithm
*/
getHashAlgorithm() {
return this.hashAlgorithm;
}
/**
* Static method to compute hash
* @param {string|Buffer} content - Content to hash
* @param {string} hashAlgorithm - Algorithm to use
* @returns {string|Promise<string>} Computed hash or Promise of hash in browser
*/
static computeHash(content, hashAlgorithm = _config_constants.HashAlgorithm.DEFAULT) {
const buffer = _bufferPolyfill.SafeBuffer.isBuffer(content) ? content : (0, _textEncoderPolyfill.encodeText)(content);
const hash = (0, _cryptoPolyfill.createHash)(hashAlgorithm);
hash.update(buffer);
return hash.digest('hex');
}
/**
* Validate hash against an expected hash
* @param {string} [expectedHash] - Expected hash value
* @returns {boolean|Promise<boolean>} True if hash matches, false otherwise
*/
validate(expectedHash) {
if (!expectedHash) return false;
if (isBrowser) {
// In browser, we need to handle async validation
return this._computeHashAsync().then(computedHash => {
return computedHash === expectedHash;
});
}
return this.hashValue === expectedHash;
}
/**
* Return string representation
* @returns {string} String representation
*/
toString() {
return `HashValidator(alg=${this.hashAlgorithm}, hash=${this.hashValue})`;
}
/**
* Gets the strength order of hash algorithms
* @returns {string[]} Ordered list of hash algorithms by strength
*/
getHashAlgorithmStrengthOrder() {
return [_config_constants.HashAlgorithm.MD5, _config_constants.HashAlgorithm.SHA1, _config_constants.HashAlgorithm.SHA224, _config_constants.HashAlgorithm.SHA256, _config_constants.HashAlgorithm.SHA384, _config_constants.HashAlgorithm.SHA512];
}
/**
* Gets the strength index of a hash algorithm
* @param {string} algorithm - Hash algorithm
* @returns {number} Strength index
*/
getHashAlgorithmStrength(algorithm) {
return this.getHashAlgorithmStrengthOrder().indexOf(algorithm);
}
/**
* Checks if one hash algorithm is stronger than another
* @param {string} current - Current hash algorithm
* @param {string} upgrade - Potential upgrade hash algorithm
* @returns {boolean} Whether the upgrade is stronger
*/
isStrongerHashAlgorithm(current, upgrade) {
return this.getHashAlgorithmStrength(upgrade) > this.getHashAlgorithmStrength(current);
}
/**
* Determines the next hash algorithm in the upgrade path
* @param {string|Object} currentHashFunction - Current hash function
* @returns {string} Next hash algorithm
*/
nextHashFunction(currentHashFunction) {
const strengthOrder = this.getHashAlgorithmStrengthOrder();
// Handle undefined or null input
if (currentHashFunction === undefined || currentHashFunction === null) {
return _config_constants.HashAlgorithm.MD5;
}
// Extract hash function value if it's an object
const currentHash = typeof currentHashFunction === 'object' ? currentHashFunction.value || currentHashFunction.type : currentHashFunction;
// Normalize to lowercase
const normalizedHash = (currentHash || '').toLowerCase();
// Find current index
const currentIndex = strengthOrder.indexOf(normalizedHash);
// Special case for SHA512 - wrap around to SHA1
if (normalizedHash === _config_constants.HashAlgorithm.SHA512) {
return _config_constants.HashAlgorithm.SHA1;
}
// If not found or last in order, return default (first hash function)
if (currentIndex === -1 || currentIndex === strengthOrder.length - 1) {
return _config_constants.HashAlgorithm[strengthOrder[0].toUpperCase()];
}
// Return the next hash function in the order as an enum
return _config_constants.HashAlgorithm[strengthOrder[currentIndex + 1].toUpperCase()];
}
/**
* Static method to get supported hash algorithms
* @returns {string[]} List of supported hash algorithms
*/
static getSupportedAlgorithms() {
return [_config_constants.HashAlgorithm.MD5, _config_constants.HashAlgorithm.SHA1, _config_constants.HashAlgorithm.SHA256, _config_constants.HashAlgorithm.SHA512];
}
static compute_hash(content, hashAlgorithm = _config_constants.HashAlgorithm.DEFAULT) {
return HashValidator.computeHash(content, hashAlgorithm);
}
static HashAlgorithm = _config_constants.HashAlgorithm;
static HASH_ALGORITHM_HIERARCHY = _config_constants.HASH_ALGORITHM_HIERARCHY;
static VALID_HASH_FUNCTIONS = _config_constants.VALID_HASH_FUNCTIONS;
}
exports.default = HashValidator;
//# sourceMappingURL=validator.js.map