UNPKG

@adorsys-gis/did-resolver-lib

Version:

A library or tool that allows applications to resolve Decentralized Identifiers (DIDs) into their corresponding DID Documents.

140 lines (122 loc) 3.74 kB
import { DIDDoc, DIDResolver, Service, VerificationMethod } from 'didcomm'; import base64url from 'base64url'; import { Buffer } from 'buffer'; // Polyfill Buffer for environments like the browser if (!globalThis.Buffer) { globalThis.Buffer = Buffer; } type Purpose = | 'Assertion' | 'Encryption' | 'Verification' | 'CapabilityDelegation' | 'CapabilityInvocation' | 'Service'; export default class PeerDIDResolver implements DIDResolver { async resolve(did: string): Promise<DIDDoc | null> { try { // Validate if the DID starts with the "did:peer:" prefix if (!did.startsWith('did:peer:')) { throw new Error('Unsupported DID method'); } else if (!did.startsWith('did:peer:2')) { Error('Unsupported DID peer Version'); } // Dissect the DID address const chain = did .replace(/^did:peer:2\./, '') .split('.') .map((e) => { const purposeCode = e.charAt(0); const purpose = mapPurposeFromCode(purposeCode); const multikey = e.slice(1); return { purpose, multikey }; }); const authentication: string[] = []; const keyAgreement: string[] = []; const assertionMethod: string[] = []; const verificationMethods: VerificationMethod[] = []; chain .filter(({ purpose }) => purpose !== 'Service') .forEach((item, index) => { const id = `${did}#key-${index + 1}`; const { purpose, multikey } = item; let type: string; switch (purpose) { case 'Assertion': type = 'Multikey'; assertionMethod.push(id); break; case 'Verification': type = 'Ed25519VerificationKey2020'; authentication.push(id); break; case 'Encryption': type = 'X25519KeyAgreementKey2020'; keyAgreement.push(id); break; default: type = 'Multikey'; } const method: VerificationMethod = { id, type, controller: did, publicKeyMultibase: `${multikey}`, }; verificationMethods.push(method); }); // Resolve services const services: Service[] = []; let serviceNextId = 0; chain .filter(({ purpose }) => purpose === 'Service') .forEach(({ multikey }) => { const decodedService = base64url.decode(multikey); const service = reverseAbbreviateService(decodedService); if (!service.id) { service.id = serviceNextId === 0 ? '#service' : `#service-${serviceNextId}`; serviceNextId++; } services.push(service); }); const diddoc: DIDDoc = { id: did, keyAgreement, authentication, verificationMethod: verificationMethods, service: services, }; return diddoc; } catch (error: string | unknown) { Error(error as string); return null; } } } function reverseAbbreviateService(decodedService: string): Service { const parsed = JSON.parse(decodedService); return { id: parsed.id || '', type: 'DIDCommMessaging', serviceEndpoint: parsed.s, }; } function mapPurposeFromCode(code: string): Purpose { switch (code) { case 'A': return 'Assertion'; case 'E': return 'Encryption'; case 'V': return 'Verification'; case 'D': return 'CapabilityDelegation'; case 'I': return 'CapabilityInvocation'; case 'S': return 'Service'; default: throw new Error('Invalid purpose prefix'); } }