/**
|
* Node.js constant object hash module.
|
* @exports node-object-hash
|
* @type {Function}
|
*/
|
|
'use strict';
|
const crypto = require('crypto');
|
|
/**
|
* Sorts object fields
|
* @param {Object|Array|string|function} obj Initial object
|
* @param {Object} options Options
|
* @param {boolean} [options.coerce=true] Perform coercion
|
* @param {boolean} [options.sort=true] Perform Array, Set, Object sorting
|
* @returns {string}
|
*/
|
exports.sortedObjectString = (obj, options) => {
|
const coerce = typeof options.coerce == 'undefined' ? true : options.coerce;
|
const sort = typeof options.sort == 'undefined' ? true : options.sort;
|
if (typeof obj == 'object') {
|
if (Array.isArray(obj)) {
|
let tmp = [...obj];
|
tmp.forEach((it, idx) => {
|
tmp[idx] = exports.sortedObjectString(it, {coerce, sort})
|
});
|
return sort ? `[${tmp.sort().toString()}]` : `[${tmp.toString()}]`;
|
}
|
if (obj === null) {
|
return `null`;
|
}
|
if (obj instanceof Map) {
|
return `Map[${[...obj].toString()}]`;
|
}
|
if (obj instanceof Set) {
|
return sort ? `Set[${[...obj].sort().toString()}]` : `Set[${[...obj].toString()}]`;
|
}
|
const sortedObj = new Map();
|
const keys = sort ? Object.keys(obj).sort() : Object.keys(obj);
|
keys.forEach((key) => {
|
sortedObj.set(key, exports.sortedObjectString(obj[key], {coerce, sort}));
|
});
|
return `{${[...sortedObj].toString()}}`;
|
}
|
if (typeof obj == 'function') {
|
return `${obj.name}=>${obj.toString()}`;
|
}
|
if (coerce) {
|
if (typeof obj == 'boolean') {
|
return `${Number(obj)}`;
|
}
|
} else {
|
if (typeof obj == 'string') {
|
return `"${obj}"`
|
}
|
}
|
if (coerce && typeof obj == 'boolean') {
|
return `${Number(obj)}`;
|
}
|
return obj;
|
};
|
|
/**
|
* Calculates object hash
|
* @param {Object} obj Object to hash
|
* @param {Object} [options] Options
|
* @param {string} [options.alg="sha256"] Crypto algorithm to use
|
* @param {string} [options.enc="hex"] Hash string encoding
|
* @param {boolean} [options.coerce=true] Perform coercion
|
* @param {boolean} [options.sort=true] Perform Array, Set, Object sorting
|
* @returns {string} Hash string
|
*/
|
exports.hash = (obj, options) => {
|
options = options || {};
|
const alg = options.alg || 'sha256';
|
const enc = options.enc || 'hex';
|
const coerce = typeof options.coerce == 'undefined' ? true : options.coerce;
|
const sort = typeof options.sort == 'undefined' ? true : options.sort;
|
|
if (~crypto.getHashes().indexOf(alg)) {
|
const sorted = exports.sortedObjectString(obj, {coerce, sort});
|
return crypto.createHash(alg)
|
.update(sorted)
|
.digest(enc);
|
} else {
|
throw new Error(`Algorithm ${alg} not supported by "ctypto" module`);
|
}
|
};
|