verifyPresentation function

Future<bool> verifyPresentation(
  1. dynamic presentation,
  2. String challenge, {
  3. Erc1056? erc1056,
  4. RevocationRegistry? revocationRegistry,
  5. Signer? signer,
  6. Signer signerSelector(
    1. String typeMatch,
    2. dynamic loadDocumentFunction(
      1. Uri url,
      2. LoadDocumentOptions? options
      )
    ) = _determineSignerForType,
  7. dynamic loadDocumentFunction(
    1. Uri url,
    2. LoadDocumentOptions? options
    ) = loadDocumentStrict,
  8. Future<DidDocument> didResolver(
    1. String
    ) = resolveDidDocument,
  9. Map<String, Map<String, dynamic>>? issuerJwks,
})

Verifies the presentation.

It uses erc1056 to look up the current owner of the dids a proof is given in presentation.

Implementation

Future<bool> verifyPresentation(dynamic presentation, String challenge,
    {Erc1056? erc1056,
    RevocationRegistry? revocationRegistry,
    Signer? signer,
    Signer Function(
            String typeMatch,
            Function(Uri url, LoadDocumentOptions? options)
                loadDocumentFunction)
        signerSelector = _determineSignerForType,
    Function(Uri url, LoadDocumentOptions? options) loadDocumentFunction =
        loadDocumentStrict,
    Future<DidDocument> Function(String) didResolver = resolveDidDocument,
    Map<String, Map<String, dynamic>>? issuerJwks}) async {
  // datatype conversion
  Map<String, dynamic> presentationMap;
  if (presentation is VerifiablePresentation) {
    presentationMap = presentation.toJson();
  } else {
    presentationMap = credentialToMap(presentation);
  }

  // get proof(s) as List
  var proofs = presentationMap['proof'];
  if (proofs is Map<String, dynamic>) {
    proofs = [proofs];
  }
  proofs as List;
  presentationMap.remove('proof');

  List<String> holderDids = [];
  var credentials = [];

  // verify credentials
  if (presentationMap.containsKey('verifiableCredential')) {
    credentials = presentationMap['verifiableCredential'] as List;

    // get potential issuer jwks
    Map<String, Map<String, dynamic>> issuerJwk = {};
    for (var vc in credentials) {
      var asVc = VerifiableCredential.fromJson(vc);
      if (asVc.type.contains('PublicKeyCertificate')) {
        issuerJwk[asVc.credentialSubject['id']] = asVc
            .credentialSubject['publicKey']['publicKeyJwk']
            .cast<String, dynamic>();
      }
    }

    if (issuerJwks != null) {
      issuerJwk.addAll(issuerJwks);
    }
    print(issuerJwk);

    await Future.forEach(credentials, (dynamic element) async {
      bool verified = true;
      if (!VerifiableCredential.fromJson(element)
          .type
          .contains('PublicKeyCertificate')) {
        verified = await verifyCredential(element,
            erc1056: erc1056,
            revocationRegistry: revocationRegistry,
            signerSelector: signerSelector,
            loadDocumentFunction: loadDocumentFunction,
            issuerJwk: issuerJwk[getIssuerDidFromCredential(element)]);
      }
      if (!verified) {
        throw Exception('A credential could not been verified');
      } else {
        var did = getHolderDidFromCredential(element);
        if (erc1056 != null) did = await erc1056.identityOwner(did);
        if (did.isNotEmpty && did.startsWith('did:')) {
          if (!VerifiableCredential.fromJson(element)
              .type
              .contains('PublicKeyCertificate')) {
            holderDids.add(did);
          }
        }
      }
    });
  }

  // check for holder property
  if (presentationMap.containsKey('holder')) {
    var holder = presentationMap['holder'];
    if (holder is String && holder.startsWith('did:')) {
      holderDids.add(holder);
    }
  }

  // verify proofs from presentation
  await Future.forEach(proofs, (dynamic element) async {
    String verifMeth = element['verificationMethod'];
    if (verifMeth.contains('#')) verifMeth = verifMeth.split('#').first;
    if (erc1056 != null) verifMeth = await erc1056.identityOwner(verifMeth);
    var signer = signerSelector.call(element['type'], loadDocumentFunction);
    if (holderDids.contains(verifMeth)) holderDids.remove(verifMeth);
    if (!await signer.verifyProof(element, presentationMap, verifMeth,
        challenge: challenge)) {
      throw Exception('Proof for $verifMeth could not been verified');
    }
  });
  if (holderDids.isNotEmpty) throw Exception('There are dids without a proof');

  presentationMap['proof'] = (proofs.length == 1) ? proofs.first : proofs;

  // compare plaintext credentials (if given)
  if (presentationMap.containsKey('disclosedCredentials')) {
    var disclosedCredentials = presentationMap['disclosedCredentials'] as List;
    Map<String?, Map<String, dynamic>> credsToId = {};
    for (var element in credentials) {
      var did = getHolderDidFromCredential(element);
      credsToId[did] = element;
    }

    for (var element in disclosedCredentials) {
      compareW3cCredentialAndPlaintext(credsToId[element['id']], element);
    }
  }
  return true;
}