UNPKG

did-sdk-js

Version:

js sdk for did and vc according to mcps did spec

448 lines (447 loc) 14.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Utils = void 0; const hexEncoding = require("crypto-js/enc-hex"); const SHA3 = require("crypto-js/sha3"); const SHA256 = require("crypto-js/sha256"); const RIPEMD160 = require("crypto-js/ripemd160"); const is = require("is_js"); const errors_1 = require("../errors"); const csprng = require("secure-random"); const uuid = require("uuid"); const cryp = require("crypto-browserify"); const _ = require("underscore"); const crypto = require("crypto"); /** * IRITA SDK JS Utils * @hidden */ class Utils { /** * String to ArrayBuffer * @param str ASCII string * @returns Uint8Array */ static str2ab(str) { if (typeof str !== 'string') { throw new errors_1.SdkError('str2ab expects a string'); } const result = new Uint8Array(str.length); for (let i = 0, strLen = str.length; i < strLen; i++) { result[i] = str.charCodeAt(i); } return result; } /** * String to Byte Array * @param str ASCII string * @returns Uint8Array */ static str2ba(str) { if (typeof str !== 'string') { throw new errors_1.SdkError('str2ba expects a string'); } const result = []; for (let i = 0, strLen = str.length; i < strLen; i++) { result[i] = str.charCodeAt(i); } return result; } /** * ArrayBuffer to String * @param arr Uint8Array * @returns HEX string */ static ab2hexstring(arr) { if (typeof arr !== 'object') { throw new errors_1.SdkError('ab2hexstring expects an array'); } let result = ''; for (let i = 0; i < arr.length; i++) { let str = arr[i].toString(16); str = str.length === 0 ? '00' : str.length === 1 ? '0' + str : str; result += str; } return result; } /** * String to Hex String * @param str ASCII string * @returns HEX string */ static str2hexstring(str) { return Utils.ab2hexstring(Utils.str2ab(str)); } /** * Object to Hex String * @param obj Json Object * @returns HEX string */ static obj2hexstring(obj) { return Utils.str2hexstring(JSON.stringify(obj)); } /** * Convert an integer to big endian hex and add leading zeros * @param num The number to be converted * @returns HEX string */ static int2hex(num) { if (typeof num !== 'number') { throw new errors_1.SdkError('int2hex expects a number'); } const h = num.toString(16); return h.length % 2 ? '0' + h : h; } /** * Converts a number to a big endian hexstring of a suitable size, optionally little endian * @param num Number to convert * @param size The required size in bytes, eg 1 for Uint8, 2 for Uint16. Defaults to 1. * @param littleEndian Encode the hex in little endian form * @returns HEX string */ static num2hexstring(num, size = 1, littleEndian = false) { if (typeof num !== 'number') throw new errors_1.SdkError('num must be numeric'); if (num < 0) throw new RangeError('num is unsigned (>= 0)'); if (size % 1 !== 0) throw new errors_1.SdkError('size must be a whole integer'); if (!Number.isSafeInteger(num)) { throw new RangeError(`num (${num}) must be a safe integer`); } size = size * 2; let hexstring = num.toString(16); hexstring = hexstring.length % size === 0 ? hexstring : ('0'.repeat(size) + hexstring).substring(hexstring.length); if (littleEndian) hexstring = Utils.reverseHex(hexstring); return hexstring; } /** * Converts a number to a variable length Int. Used for array length header * @param num Number to convert * @returns HEX string of the variable Int. */ static num2VarInt(num) { if (num < 0xfd) { return Utils.num2hexstring(num); } else if (num <= 0xffff) { // uint16 return 'fd' + Utils.num2hexstring(num, 2, true); } else if (num <= 0xffffffff) { // uint32 return 'fe' + Utils.num2hexstring(num, 4, true); } else { // uint64 return 'ff' + Utils.num2hexstring(num, 8, true); } } /** * Reverses an array. Accepts arrayBuffer. * @param arr Array to reverse * @returns Reversed array */ static reverseArray(arr) { if (typeof arr !== 'object' || !arr.length) { throw new errors_1.SdkError('reverseArray expects an array'); } const result = new Uint8Array(arr.length); for (let i = 0; i < arr.length; i++) { result[i] = arr[arr.length - 1 - i]; } return result; } /** * Reverses a HEX string, treating 2 chars as a byte. * @example * reverseHex('abcdef') = 'efcdab' * @param hex HEX string * @returns HEX string reversed in 2s. */ static reverseHex(hex) { Utils.ensureHex(hex); let out = ''; for (let i = hex.length - 2; i >= 0; i -= 2) { out += hex.substr(i, 2); } return out; } /** * Checks if input is a hexstring. Empty string is considered a hexstring. * @example * isHex('0101') = true * isHex('') = true * isHex('0x01') = false * @param str * @returns {boolean} */ static isHex(str) { try { const hexRegex = /^([0-9A-Fa-f]{2})*$/; return hexRegex.test(str); } catch (err) { return false; } } /** * Throws an error if input is not hexstring. * @param str */ static ensureHex(str) { if (!Utils.isHex(str)) { throw new errors_1.SdkError(`Expected a hexstring but got ${str}`); } } /** * Computes a SHA256 followed by a RIPEMD160. * @param hex Message to hash * @returns Hash output */ static sha256ripemd160(hex) { if (typeof hex !== 'string') { throw new errors_1.SdkError('sha256ripemd160 expects a string'); } if (hex.length % 2 !== 0) { throw new errors_1.SdkError(`invalid hex string length: ${hex}`); } const hexEncoded = hexEncoding.parse(hex); const programSha256 = SHA256(hexEncoded); return RIPEMD160(programSha256).toString(); } /** * Computes a single SHA256 digest. * @param hex Message to hash * @returns Hash output */ // static sha256(hex: string): string { // if (typeof hex !== 'string') { // throw new SdkError('sha256 expects a hex string'); // } // if (hex.length % 2 !== 0) { // throw new SdkError(`invalid hex string length: ${hex}`); // } // const hexEncoded = hexEncoding.parse(hex); // return SHA256(hexEncoded).toString(); // } static sha256(signMsg) { if (typeof signMsg !== 'string') { throw new errors_1.SdkError('sha256 expects a string'); } return crypto.createHash("sha256").update(signMsg).digest(); } /** * Computes a single SHA3 (Keccak) digest. * @param hex Message to hash * @returns Hash output */ static sha3(hex) { if (typeof hex !== 'string') { throw new errors_1.SdkError('sha3 expects a hex string'); } if (hex.length % 2 !== 0) { throw new errors_1.SdkError(`invalid hex string length: ${hex}`); } const hexEncoded = hexEncoding.parse(hex); return SHA3(hexEncoded).toString(); } static sortObject(obj) { if (obj === null) return null; if (is.not.object(obj)) return obj; if (is.array(obj)) return obj.map(Utils.sortObject); const sortedKeys = Object.keys(obj).sort(); const result = {}; sortedKeys.forEach(key => { result[key] = Utils.sortObject(obj[key]); }); return result; } static base64ToString(b64) { return Buffer.from(b64, 'base64').toString(); } static bytesToBase64(bytes) { return Buffer.from(bytes).toString('base64'); } /** * get amino prefix from public key encode type. * @param public key encode type * @returns UintArray */ static getAminoPrefix(prefix) { let b = Array.from(Buffer.from(SHA256(prefix).toString(), 'hex')); while (b[0] === 0) { b = b.slice(1); } b = b.slice(3); while (b[0] === 0) { b = b.slice(1); } b = b.slice(0, 4); return b; } static getRandomBytes(len) { return Buffer.from(csprng(len)); } static getRandomString(len) { let randB = Utils.getRandomBytes(len / 2); return randB.toString('hex'); } static genUUID() { return uuid.v4({ random: cryp.randomBytes(16), }); } static isJson(obj) { return typeof (obj) == "object" && Object.prototype.toString.call(obj).toLowerCase() == "[object object]" && !obj.length; } static isArray(obj) { return typeof (obj) == "object" && Object.prototype.toString.call(obj).toLowerCase() == "[object array]"; } static isObject(obj) { return typeof (obj) == "object"; } static isNull(arg) { let isNull = arg === 0 || arg === "" || arg === undefined || arg === null || !arg || _.isEqual(arg, {}) || _.isEqual(arg, []); // return isNull if (isNull) { return true; } // 递归判断子字段是否为空;这里进判断json对象;数组等其它对象不处理 if (Utils.isJson(arg)) { //(typeof arg === "object") { let sr = JSON.stringify(arg, Utils.replacerTrimEmpty); return sr == "{}" || sr == "[]"; } else { return false; } } /* * * json序列化时,如果指定replacer,遇到外层为数组值或json值的字段,会自动递归处理内部元素 * { "id": "xxxxsdfs", "name": "name", "address": "", "given": [], "givensss": ["", "", {}], // [null, null, null] "hh": {}, "ee": 0, "yeyeye": { "hhaha": "", "yyy": ["", ""] // [null, null, null]; 后续优化为不处理数组内部元素为null的情况,但是内部为json对象还需要递归处理 } } * */ static replacerTrimEmpty(key, value) { if (key !== "" && Utils.isNull(value)) { return undefined; } return value; } static dateToStr(d) { // 2021-06-18T02:52:28.457Z 去掉毫秒数=》 2021-06-18T02:52:28Z let str = d.toISOString(); return str.substr(0, 19) + "Z"; } static getCurTimeStr() { return Utils.dateToStr(new Date()); } static strToDate(str) { // 2021-06-18T02:52:28Z return new Date(str); } static checkTimeFormat(time) { if (time === "") { return new errors_1.SdkError("time is null"); } // 2021-06-18T02:52:28Z if (time.length != 20) { return new errors_1.SdkError("time length error"); } try { if (time === Utils.dateToStr(Utils.strToDate(time))) { return null; } } catch (e) { return new errors_1.SdkError(e.toString()); } return null; } static sortObj(obj) { if (!Utils.isObject(obj)) { return obj; } return Object.keys(obj).sort().reduce(function (result, key) { // 递归处理json 值、及array数组元素 // @ts-ignore let obValue = obj[key]; if (Utils.isJson(obValue)) { obValue = Utils.sortObj(obValue); } else if (Utils.isArray(obValue)) { for (let i = 0; i < obValue.length; i++) { obValue[i] = Utils.sortObj(obValue[i]); } } // @ts-ignore result[key] = obValue; return result; }, {}); } static isUndefined(obj) { return (typeof obj == "undefined"); } static clone(obj) { if (obj === null) return null; if (typeof obj !== 'object') return obj; if (obj.constructor === Date) return new Date(obj); if (obj.constructor === RegExp) return new RegExp(obj); let newObj = Array.isArray(obj) ? [] : new obj.constructor(); // let newObj = new obj.constructor(); //保持继承的原型 for (let key in obj) { newObj[key] = Utils.clone(obj[key]); // if(obj.hasOwnProperty(key)){ // let val = obj[key]; // newObj[key] = typeof val === 'object' ? Utils.clone(val):val; // // 数组深度拷贝 // if (val instanceof Array) { // // newObj[key] = Array.from(val); // for (let i = 0; i < val.length; i++) { // newObj[key][i] = Utils.clone(val[i]) // } // // } // } } return newObj; } static isInArray(arr, value) { for (let i = 0; i < arr.length; i++) { if (value === arr[i]) { return true; } } return false; } } exports.Utils = Utils; //# sourceMappingURL=utils.js.map