buildPresentation function

Future<String> buildPresentation(
  1. List? credentials,
  2. WalletStore wallet,
  3. String challenge, {
  4. String? holder,
  5. String? domain,
  6. List<String>? additionalDids,
  7. List? disclosedCredentials,
  8. dynamic loadDocumentFunction(
    1. Uri url,
    2. LoadDocumentOptions? options
    ) = loadDocumentStrict,
})

Builds a presentation for credentials.

If not only the ownership of the dids in the credentials should be proofed a List of additionalDids could be given and a proof section for each did is added.

Implementation

Future<String> buildPresentation(
    List<dynamic>? credentials, WalletStore wallet, String challenge,
    {String? holder,
    String? domain,
    List<String>? additionalDids,
    List<dynamic>? disclosedCredentials,
    Function(Uri url, LoadDocumentOptions? options) loadDocumentFunction =
        loadDocumentStrict}) async {
  List<Map<String, dynamic>?> credMapList = [];
  List<String?> holderDids = [];
  Set<String> signatureContext = {};

  PresentationSubmission? submission;
  if (credentials != null) {
    for (var element in credentials) {
      if (element is FilterResult) {
        List<InputDescriptorMappingObject> mapping = [];
        if (submission != null) {
          mapping = submission.descriptorMap;
        }
        for (var cred in element.credentials) {
          var credEntry = cred.toJson();
          credMapList.add(credEntry);
          var tmp = getHolderDidFromCredential(credEntry);
          holderDids.add(tmp);
          signatureContext.add(_findContext(tmp));
          for (var descriptor in element.matchingDescriptorIds) {
            var map = InputDescriptorMappingObject(
                id: descriptor,
                format: 'ldp_vc',
                path: JsonPath(
                    '\$.verifiableCredential[${credMapList.length - 1}]'));
            mapping.add(map);
          }
        }
        submission = PresentationSubmission(
            presentationDefinitionId: element.presentationDefinitionId,
            descriptorMap: mapping);
      } else {
        Map<String, dynamic> credMap;
        if (element is VerifiableCredential) {
          credMap = element.toJson();
        } else {
          credMap = credentialToMap(element);
        }
        credMapList.add(credMap);
        if (!VerifiableCredential.fromJson(credMap)
            .type
            .contains('PublicKeyCertificate')) {
          var tmp = getHolderDidFromCredential(credMap);
          holderDids.add(tmp);
          signatureContext.add(_findContext(tmp));
        }
      }
    }
  }

  if (holder != null) {
    holderDids.add(holder);
  }

  if (holderDids.isEmpty) {
    throw Exception('No holder did given. Can\'t generate Presentation');
  }

  //TODO dynamically build context based on proof methods
  List<String> context = [
    'https://www.w3.org/2018/credentials/v1',
  ];
  context.addAll(signatureContext);
  List<String> type = ['VerifiablePresentation'];
  if (submission != null) {
    context.add(
        'https://identity.foundation/presentation-exchange/submission/v1/');
    type.add('PresentationSubmission');
  }

  Map<String, dynamic> presentation = {'@context': context, 'type': type};

  if (credMapList.isNotEmpty) {
    presentation['verifiableCredential'] = credMapList;
  }

  if (holder != null) {
    presentation['holder'] = holder;
  }

  if (submission != null) {
    presentation['presentation_submission'] = submission.toJson();
  }

  if (disclosedCredentials != null) {
    List<Map<String, dynamic>?> disclosedCreds = [];
    for (var element in disclosedCredentials) {
      var credMap = credentialToMap(element);
      disclosedCreds.add(credMap);
    }
    presentation['disclosedCredentials'] = disclosedCreds;
    var type = presentation['type'] as List<String?>;
    type.add('DisclosedCredentialPresentation');
    presentation['type'] = type;
  }

  // build signatures
  List<Map<String, dynamic>> proofList = [];
  Set<Type> signerTypes = {};
  for (var element in holderDids) {
    print(element);
    var signer = _determineSignerForDid(element!, loadDocumentFunction);
    signerTypes.add(signer.runtimeType);
    proofList.add(await signer.buildProof(presentation, wallet, element,
        challenge: challenge, proofPurpose: 'authentication', domain: domain));
  }

  if (additionalDids != null) {
    for (var element in additionalDids) {
      var signer = _determineSignerForDid(element, loadDocumentFunction);
      var t = signer.runtimeType;
      if (t == EcdsaRecoverySignature &&
          !context.contains(ecdsaRecoveryContextIri)) {
        context.add(ecdsaRecoveryContextIri);
      } else if (t == EdDsaSigner && !context.contains(ed25519ContextIri)) {
        context.add(ed25519ContextIri);
      }
      proofList.add(await signer.buildProof(presentation, wallet, element,
          challenge: challenge,
          proofPurpose: 'authentication',
          domain: domain));
    }
  }

  presentation['proof'] = proofList;

  return jsonEncode(presentation);
}