UNPKG

ens-did-resolver

Version:
371 lines (315 loc) 13.8 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@ethersproject/bignumber'), require('@ethersproject/providers')) : typeof define === 'function' && define.amd ? define(['exports', '@ethersproject/bignumber', '@ethersproject/providers'], factory) : (global = global || self, factory(global.ensDidResolver = {}, global.bignumber, global.providers)); }(this, (function (exports, bignumber, providers) { const identifierMatcher = /^(.*:)?(.*\.eth)$/; const knownInfuraNetworks = { mainnet: '0x1', goerli: '0x5' }; const knownNetworks = { ...knownInfuraNetworks, rsk: '0x1e', 'rsk:testnet': '0x1f', artis_t1: '0x03c401', artis_s1: '0x03c301', matic: '0x89', maticmum: '0x13881' }; var Errors; (function (Errors) { /** * The resolver has failed to construct the DID document. * This can be caused by a network issue, a wrong registry address or malformed logs while parsing the registry * history. Please inspect the `DIDResolutionMetadata.message` to debug further. */ Errors["notFound"] = "notFound"; /** * The resolver does not know how to resolve the given DID. Most likely it is not a `did:ens`. */ Errors["invalidDid"] = "invalidDid"; /** * The resolver is misconfigured or is being asked to resolve a DID anchored on an unknown network */ Errors["unknownNetwork"] = "unknownNetwork"; /** * The resolver is being asked to resolve a DID anchored on a network without a known ENS resolver. */ Errors["unknownEnsResolver"] = "unknownEnsResolver"; })(Errors || (Errors = {})); function isDefined(arg) { return arg && typeof arg !== 'undefined'; } function configureNetworksWithInfura(projectId) { if (!projectId) { return {}; } const networks = [{ name: 'mainnet', chainId: '0x1', provider: new providers.InfuraProvider('homestead', projectId) }, { name: 'goerli', chainId: '0x5', provider: new providers.InfuraProvider('goerli', projectId) }]; return configureNetworks({ networks }); } function getProviderForNetwork(conf) { var _conf$web; let provider = conf.provider || ((_conf$web = conf.web3) == null ? void 0 : _conf$web.currentProvider); if (!provider) { if (conf.rpcUrl) { var _conf$name; const chainIdRaw = conf.chainId ? conf.chainId : knownNetworks[conf.name || '']; const chainId = chainIdRaw ? bignumber.BigNumber.from(chainIdRaw).toNumber() : chainIdRaw; const networkName = knownInfuraNetworks[conf.name || ''] ? (_conf$name = conf.name) == null ? void 0 : _conf$name.replace('mainnet', 'homestead') : 'any'; provider = new providers.JsonRpcProvider(conf.rpcUrl, chainId || networkName); } else { throw new Error(`invalid_config: No web3 provider could be determined for network ${conf.name || conf.chainId}`); } } return provider; } function configureNetwork(net) { const networks = {}; const chainId = net.chainId || knownNetworks[net.name || '']; if (chainId) { if (net.name) { networks[net.name] = getProviderForNetwork(net); } const id = typeof chainId === 'number' ? `0x${chainId.toString(16)}` : chainId; networks[id] = getProviderForNetwork(net); } else if (net.provider || net.web3 || net.rpcUrl) { networks[net.name || ''] = getProviderForNetwork(net); } return networks; } function configureNetworks(conf) { var _conf$networks; return { ...configureNetwork(conf), ...((_conf$networks = conf.networks) == null ? void 0 : _conf$networks.reduce((networks, net) => { return { ...networks, ...configureNetwork(net) }; }, {})) }; } /** * Generates a configuration that maps ethereum network names and chainIDs to the respective web3 providers. * @returns a record of providers * @param conf configuration options for the resolver. An array of network details. * Each network entry should contain at least one of `name` or `chainId` AND one of `provider`, `web3`, or `rpcUrl` * For convenience, you can also specify an `infuraProjectId` which will create a mapping for all the networks * supported by https://infura.io. * @example ```js * [ * { name: 'development', rpcUrl: 'http://127.0.0.1:8545/' }, * { name: 'goerli', chainId: 5, provider: new InfuraProvider('goerli') }, * { name: 'rinkeby', provider: new AlchemyProvider('rinkeby') }, * { name: 'rsk:testnet', chainId: '0x1f', rpcUrl: 'https://public-node.testnet.rsk.co' }, * ] * ``` */ function configureResolverWithNetworks(conf = {}) { const networks = { ...configureNetworksWithInfura(conf.infuraProjectId), ...configureNetworks(conf) }; if (Object.keys(networks).length === 0) { throw new Error('invalid_config: Please make sure to have at least one network'); } return networks; } function _catch(body, recover) { try { var result = body(); } catch (e) { return recover(e); } if (result && result.then) { return result.then(void 0, recover); } return result; } function getResolver(config) { const resolve = function (did, parsed) { try { const networks = configureResolverWithNetworks(config); // check if identifier(parsed.id) contains a network code const fullId = parsed.id.match(identifierMatcher); if (!fullId) { return Promise.resolve({ didResolutionMetadata: { error: Errors.invalidDid, message: `Not a valid did:ens: ${parsed.id}` }, didDocumentMetadata: {}, didDocument: null }); } const ensName = fullId[2]; const networkCode = typeof fullId[1] === 'string' ? fullId[1].slice(0, -1) : ''; // get provider for that network or the mainnet provider if none other is given const provider = networks[networkCode]; if (!provider || typeof provider === 'undefined') { return Promise.resolve({ didResolutionMetadata: { error: Errors.unknownNetwork, message: `This resolver is not configured for the ${networkCode} network required by ${parsed.id}. Networks: ${JSON.stringify(Object.keys(networks))}` }, didDocumentMetadata: {}, didDocument: null }); } return Promise.resolve(provider.getResolver(ensName)).then(function (ensResolver) { function _temp4() { function _temp2() { const getEnsRecord = function (ensResolver, name) { try { let parsedEntry = null; return Promise.resolve(ensResolver.getText(name)).then(function (entry) { if (entry) { try { parsedEntry = JSON.parse(unescape(entry)); } catch (e) { return null; } } return parsedEntry; }); } catch (e) { return Promise.reject(e); } }; const filterValidVerificationMethods = (did, current, all) => { const methodLinks = current.filter(entry => typeof entry === 'string').map(entry => entry.startsWith('#') ? `${did}${entry}` : entry).filter(entry => all == null ? void 0 : all.some(b => b.id === entry)); const fullMethods = current.filter(entry => entry != null && typeof entry === 'object' && Object.keys(entry).includes('id') && Object.keys(entry).includes('type') && Object.keys(entry).some(k => k.startsWith('publicKey'))).map(entry => { entry.controller = entry.controller || did; if (entry.id.startsWith('#')) { entry.id = `${did}${entry}`; } return entry; }); return [...methodLinks, ...fullMethods]; }; return Promise.resolve(getEnsRecord(ensResolver, 'org.w3c.did.service')).then(function (services) { if (services) { if (didDocument) { didDocument.service = [...(didDocument.service || []), ...services].filter(isDefined); } } return Promise.resolve(getEnsRecord(ensResolver, 'org.w3c.did.verificationMethod')).then(function (verificationMethods) { if (verificationMethods) { verificationMethods.map(method => { if (method.id.startsWith('#')) { method.id = `${did}${method.id}`; } method.controller = method.controller || did; return method; }); if (didDocument) { didDocument.verificationMethod = [...(didDocument.verificationMethod || []), ...verificationMethods].filter(isDefined); } } const relationships = ['keyAgreement', 'assertionMethod', 'authentication', 'capabilityInvocation', 'capabilityDelegation']; return Promise.resolve(relationships.reduce(function (memo, relationship) { return Promise.resolve(memo).then(function () { const _temp5 = _catch(function () { return Promise.resolve(getEnsRecord(ensResolver, `org.w3c.did.${relationship}`)).then(function (verificationMethod) { if (verificationMethod) { if (didDocument) { didDocument[relationship] = [...(didDocument[relationship] || []), ...filterValidVerificationMethods(did, verificationMethod, verificationMethods)]; } } }); }, function () {}); if (_temp5 && _temp5.then) return _temp5.then(function () {}); }); }, Promise.resolve())).then(function () { var _didDocument; const contentType = typeof ((_didDocument = didDocument) == null ? void 0 : _didDocument['@context']) !== 'undefined' ? 'application/did+ld+json' : 'application/did+json'; if (err) { return { didDocument, didDocumentMetadata, didResolutionMetadata: { error: Errors.notFound, message: err } }; } else { return { didDocument, didDocumentMetadata, didResolutionMetadata: { contentType } }; } }); }); }); } const didDocumentMetadata = {}; let didDocument = null; const _temp = function () { if (address) { return Promise.resolve(provider.getNetwork()).then(function (_provider$getNetwork) { const chainId = _provider$getNetwork.chainId; const blockchainAccountId = `${address}@eip155:${chainId}`; const postfix = address; // setup default did doc didDocument = { id: did, service: [{ id: `${did}#Web3PublicProfile-${postfix}`, type: 'Web3PublicProfile', serviceEndpoint: ensName }], verificationMethod: [{ id: `${did}#${postfix}`, type: 'EcdsaSecp256k1RecoveryMethod2020', controller: did, blockchainAccountId }], authentication: [`${did}#${postfix}`], capabilityDelegation: [`${did}#${postfix}`], capabilityInvocation: [`${did}#${postfix}`], assertionMethod: [`${did}#${postfix}`] }; }); } }(); return _temp && _temp.then ? _temp.then(_temp2) : _temp2(_temp); } if (!ensResolver) { return { didResolutionMetadata: { error: Errors.unknownEnsResolver, message: `This network (${networkCode}), required by ${parsed.id}, does not have a known ENS resolver` }, didDocumentMetadata: {}, didDocument: null }; } let err = null; let address = null; const _temp3 = _catch(function () { return Promise.resolve(ensResolver.getAddress()).then(function (_ensResolver$getAddre) { address = _ensResolver$getAddre; }); }, function (error) { err = `resolver_error: Cannot resolve ENS name: ${error}`; }); return _temp3 && _temp3.then ? _temp3.then(_temp4) : _temp4(_temp3); }); } catch (e) { return Promise.reject(e); } }; return { ens: resolve }; } exports.getResolver = getResolver; }))); //# sourceMappingURL=index.umd.js.map