All files / src/domain/did/useCases resolveDidKeyDocument.ts

92.3% Statements 24/26
100% Branches 2/2
100% Functions 3/3
92.3% Lines 24/26

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87        109x 109x 109x                 21x                                   15x 15x 15x 15x 15x         6x 6x 6x 6x 6x 6x     109x             6x 6x             15x 15x                   21x   21x   21x 21x          
import type { IDidDocument } from '../../../models/DidDocument';
import { keyUtils } from '@blockcerts/ecdsa-secp256k1-verification-key-2019';
import { publicKeyMultibaseToBytes } from '../../../helpers/keyUtils';
 
enum SupportedSuite {
  ED25519 = 'ed25519',
  SECP256K1 = 'secp256k1'
}
 
function generateDidDoc ({
  keyId,
  did,
  keyType,
  jwk
}) {
  return {
    '@context': ['https://www.w3.org/ns/did/v1'],
    verificationMethod: [{
      id: keyId,
      type: keyType,
      controller: did,
      publicKeyJwk: jwk
    }],
    id: did,
    authentication: [keyId],
    assertionMethod: [keyId],
    capabilityDelegation: [keyId],
    capabilityInvocation: [keyId],
    keyAgreement: [keyId as any],
  } as any
}
 
async function generateDidDocumentFromDidSecp256k1 (did: string): Promise<IDidDocument> {
  const publicKeyMultibase = did.substring(8);
  const publicKeyBytes = publicKeyMultibaseToBytes(publicKeyMultibase);
  const jwk = keyUtils.publicKeyJWKFrom.publicKeyUint8Array(publicKeyBytes, '');
  const keyId = did + '#' + publicKeyMultibase;
  return generateDidDoc({ keyId, did, jwk, keyType: 'EcdsaVerificationKey2019'})
}
 
async function generateDidDocumentFromDidEd25519 (did: string): Promise<IDidDocument> {
  // @ts-expect-error not a ts package
  const multiKey = await import('@digitalbazaar/ed25519-multikey');
  const publicKeyMultibase = did.substring(8);
  const publicKeyBytes = publicKeyMultibaseToBytes(publicKeyMultibase);
  const jwk = await multiKey.toJwk({ keyPair: { publicKey: publicKeyBytes }});
  const keyId = did + '#' + publicKeyMultibase;
  return generateDidDoc({ keyId, did, jwk, keyType: 'JsonWebKey2020' });
}
 
const supportedSuiteMap: Record<string, SupportedSuite> = {
  'did:key:z6Mk': SupportedSuite.ED25519,
  'did:key:zQ3s': SupportedSuite.SECP256K1
};
 
async function getResolver (suite: SupportedSuite): Promise<{ resolve(did: string): Promise<{ didDocument: IDidDocument }> }> {
  if (suite === SupportedSuite.ED25519) {
    return {
      resolve: async (did:string): Promise<{ didDocument: IDidDocument }> => ({
        didDocument: await generateDidDocumentFromDidEd25519(did) as any
      })
    }
  }
 
  if (suite === SupportedSuite.SECP256K1) {
    return {
      resolve: async (did: string): Promise<{ didDocument: IDidDocument }> => ({
        didDocument: await generateDidDocumentFromDidSecp256k1(did) as any
      })
    };
  }
 
  throw new Error('Error loading did key resolver');
}
 
export default async function resolveDidKeyDocument (didKeyUri: string): Promise<IDidDocument> {
  const keyPrefix = didKeyUri.substring(0, 12);
  if (supportedSuiteMap[keyPrefix]) {
    const resolver = await getResolver(supportedSuiteMap[keyPrefix]);
 
    const { didDocument } = await resolver.resolve(didKeyUri);
    return didDocument;
  }
 
  throw new Error('Unsupported did:key suite');
}