@arcblock/did
Version:
Javascript lib to work with ArcBlock DID
190 lines (188 loc) • 7.03 kB
JavaScript
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;