UNPKG

@arcblock/did

Version:

Javascript lib to work with ArcBlock DID

190 lines (188 loc) 7.03 kB
const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs'); const require_util = require('./util.cjs'); let _ocap_mcrypto = require("@ocap/mcrypto"); let _ocap_util = require("@ocap/util"); let lodash_isEqual = require("lodash/isEqual"); lodash_isEqual = require_rolldown_runtime.__toESM(lodash_isEqual); let lodash_pick = require("lodash/pick"); lodash_pick = require_rolldown_runtime.__toESM(lodash_pick); let lodash_upperFirst = require("lodash/upperFirst"); lodash_upperFirst = require_rolldown_runtime.__toESM(lodash_upperFirst); //#region src/type.ts const mapping = { pk: "key", address: "encoding" }; const DID_TYPE_ARCBLOCK = { role: _ocap_mcrypto.types.RoleType.ROLE_ACCOUNT, pk: _ocap_mcrypto.types.KeyType.ED25519, hash: _ocap_mcrypto.types.HashType.SHA3, address: _ocap_mcrypto.types.EncodingType.BASE58 }; const DID_TYPE_PASSKEY = { role: _ocap_mcrypto.types.RoleType.ROLE_PASSKEY, pk: _ocap_mcrypto.types.KeyType.PASSKEY, hash: _ocap_mcrypto.types.HashType.SHA2, address: _ocap_mcrypto.types.EncodingType.BASE58 }; const DID_TYPE_ETHEREUM = { role: _ocap_mcrypto.types.RoleType.ROLE_ACCOUNT, pk: _ocap_mcrypto.types.KeyType.ETHEREUM, hash: _ocap_mcrypto.types.HashType.KECCAK, address: _ocap_mcrypto.types.EncodingType.BASE16 }; const isEthereumType = (type) => { const props = [ "pk", "hash", "address" ]; return (0, lodash_isEqual.default)((0, lodash_pick.default)(type, props), (0, lodash_pick.default)(DID_TYPE_ETHEREUM, props)); }; /** * Checks if the given string is an address * * @method isEthereumDid * @param {String} address the given HEX address * @return {Boolean} */ const isEthereumDid = (did) => { const address = (0, _ocap_util.toAddress)(did); if (!/^(0x)?[0-9a-f]{40}$/i.test(address)) return false; if (/^(0x|0X)?[0-9a-f]{40}$/.test(address) || /^(0x|0X)?[0-9A-F]{40}$/.test(address)) return true; return checkAddressChecksum(address); }; /** * Checks if the given string is a checksummed address * * @method checkAddressChecksum * @param {String} address the given HEX address * @return {Boolean} */ const checkAddressChecksum = (address) => { const origin = address.replace(/^0x/i, ""); const addressHash = _ocap_mcrypto.Hasher.Keccak.hash256(origin.toLowerCase()).replace(/^0x/i, ""); for (let i = 0; i < 40; i++) if (Number.parseInt(addressHash[i], 16) > 7 && origin[i].toUpperCase() !== origin[i] || Number.parseInt(addressHash[i], 16) <= 7 && origin[i].toLowerCase() !== origin[i]) return false; return true; }; /** * Converts to a checksum address * * @method toChecksumAddress * @param {String} address the given HEX address * @return {String} */ const toChecksumAddress = (address) => { if (typeof address === "undefined") return ""; if (!/^(0x)?[0-9a-f]{40}$/i.test(address)) throw new Error(`Given address "${address}" is not a valid Ethereum address.`); const lower = address.toLowerCase().replace(/^0x/i, ""); const addressHash = _ocap_mcrypto.Hasher.Keccak.hash256(lower).replace(/^0x/i, ""); let checksumAddress = "0x"; for (let i = 0; i < lower.length; i++) if (Number.parseInt(addressHash[i], 16) > 7) checksumAddress += lower[i].toUpperCase(); else checksumAddress += lower[i]; return checksumAddress; }; /** * Create an wallet type object that be used as param to create a new wallet */ function DidType(type = {}) { let input = {}; if (["default", "arcblock"].includes(type)) input = DID_TYPE_ARCBLOCK; else if (["eth", "ethereum"].includes(type)) input = DID_TYPE_ETHEREUM; else if (["passkey"].includes(type)) input = DID_TYPE_PASSKEY; else input = { ...DID_TYPE_ARCBLOCK, ...type }; const { role, pk, hash, address } = input; Object.keys(input).forEach((x) => { const key = (0, lodash_upperFirst.default)(`${mapping[x] || x}Type`); if (Object.values(_ocap_mcrypto.types[key]).includes(input[x]) === false) throw new Error(`Unsupported ${x} type: ${input[x]}`); }); const output = { role, pk, hash, address }; if (isEthereumType(output) === false) { if ([ _ocap_mcrypto.types.RoleType.ROLE_NODE, _ocap_mcrypto.types.RoleType.ROLE_VALIDATOR, _ocap_mcrypto.types.RoleType.ROLE_TETHER, _ocap_mcrypto.types.RoleType.ROLE_SWAP ].includes(output.role)) output.hash = _ocap_mcrypto.types.HashType.SHA2; } return output; } DidType.toJSON = (type) => Object.keys(type).reduce((acc, x) => { const key = (0, lodash_upperFirst.default)(`${mapping[x] || x}Type`); acc[x] = Object.keys(_ocap_mcrypto.types[key])[Object.values(_ocap_mcrypto.types[key]).indexOf(type[x])]; return acc; }, {}); DidType.fromJSON = (json) => Object.keys(json).reduce((acc, x) => { const key = (0, lodash_upperFirst.default)(`${mapping[x] || x}Type`); const typeStr = Object.keys(_ocap_mcrypto.types[key]); acc[x] = Object.values(_ocap_mcrypto.types[key])[typeStr.indexOf(json[x])]; return acc; }, {}); /** * Convert type info object to hex string * * @public * @static * @param {object} type - wallet type, {@see @arcblock/did#DidType} * @returns string */ const fromTypeInfo = (type) => { const info = DidType(type); const infoBits = `${require_util.toBits(info.role, 6)}${require_util.toBits(info.pk, 5)}${require_util.toBits(info.hash, 5)}`; return require_util.toStrictHex((0, _ocap_util.stripHexPrefix)((0, _ocap_util.numberToHex)(Number.parseInt(infoBits, 2))), 4); }; /** * Get type info from did */ const toTypeInfo = (did) => { let type = {}; try { if (isEthereumDid(did)) type = DID_TYPE_ETHEREUM; else { const typeBytes = require_util.toBytes(did).slice(0, 2); const typeBits = require_util.toBits(new _ocap_util.BN(require_util.toStrictHex(Buffer.from(Uint8Array.from(typeBytes)).toString("hex")), 16), 16); const roleBits = typeBits.slice(0, 6); const keyBits = typeBits.slice(6, 11); const hashBits = typeBits.slice(11, 16); type = { role: Number.parseInt(roleBits, 2), pk: Number.parseInt(keyBits, 2), hash: Number.parseInt(hashBits, 2), address: (0, _ocap_util.isHex)((0, _ocap_util.toAddress)(did)) ? _ocap_mcrypto.types.EncodingType.BASE16 : _ocap_mcrypto.types.EncodingType.BASE58 }; } Object.keys(type).forEach((x) => { if (Object.values(_ocap_mcrypto.types[`${(0, lodash_upperFirst.default)(mapping[x] || x)}Type`]).includes(type[x]) === false) delete type[x]; }); return type; } catch { return type; } }; const toTypeInfoStr = (did) => { const type = toTypeInfo(did); return Object.keys(type).reduce((acc, x) => { const enums = _ocap_mcrypto.types[`${(0, lodash_upperFirst.default)(mapping[x] || x)}Type`]; acc[x] = Object.keys(enums).find((d) => enums[d] === type[x]); return acc; }, {}); }; //#endregion exports.DID_TYPE_ARCBLOCK = DID_TYPE_ARCBLOCK; exports.DID_TYPE_ETHEREUM = DID_TYPE_ETHEREUM; exports.DID_TYPE_PASSKEY = DID_TYPE_PASSKEY; exports.DidType = DidType; exports.fromTypeInfo = fromTypeInfo; exports.isEthereumDid = isEthereumDid; exports.isEthereumType = isEthereumType; exports.toChecksumAddress = toChecksumAddress; exports.toTypeInfo = toTypeInfo; exports.toTypeInfoStr = toTypeInfoStr;