@zkpassport/sdk 0.2.7 → 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js CHANGED
@@ -72,6 +72,7 @@ class ZKPassport {
72
72
  //private wasmVerifierInit: boolean = false
73
73
  constructor(_domain) {
74
74
  this.topicToConfig = {};
75
+ this.topicToLocalConfig = {};
75
76
  this.topicToKeyPair = {};
76
77
  this.topicToWebSocketClient = {};
77
78
  this.topicToSharedSecret = {};
@@ -79,6 +80,7 @@ class ZKPassport {
79
80
  this.topicToService = {};
80
81
  this.topicToProofs = {};
81
82
  this.topicToExpectedProofCount = {};
83
+ this.topicToFailedProofCount = {};
82
84
  this.topicToResults = {};
83
85
  this.onRequestReceivedCallbacks = {};
84
86
  this.onGeneratingProofCallbacks = {};
@@ -103,14 +105,19 @@ class ZKPassport {
103
105
  // Clear the results straight away to avoid concurrency issues
104
106
  delete this.topicToResults[topic];
105
107
  // Verify the proofs and extract the unique identifier (aka nullifier) and the verification result
106
- const { uniqueIdentifier, verified } = await this.verify(topic, this.topicToProofs[topic], result);
108
+ const { uniqueIdentifier, verified, queryResultErrors } = await this.verify(topic, this.topicToProofs[topic], result);
109
+ const hasFailedProofs = this.topicToFailedProofCount[topic] > 0;
107
110
  await Promise.all(this.onResultCallbacks[topic].map((callback) => callback({
108
- uniqueIdentifier,
109
- verified,
111
+ // If there are failed proofs, we don't return the unique identifier
112
+ // and we set the verified result to false
113
+ uniqueIdentifier: hasFailedProofs ? undefined : uniqueIdentifier,
114
+ verified: hasFailedProofs ? false : verified,
110
115
  result,
116
+ queryResultErrors,
111
117
  })));
112
- // Clear the expected proof count
118
+ // Clear the expected proof count and failed proof count
113
119
  delete this.topicToExpectedProofCount[topic];
120
+ delete this.topicToFailedProofCount[topic];
114
121
  }
115
122
  setExpectedProofCount(topic) {
116
123
  const fields = Object.keys(this.topicToConfig[topic]).filter((key) => hasRequestedAccessToField(this.topicToConfig[topic], key));
@@ -161,6 +168,7 @@ class ZKPassport {
161
168
  // Each separate needed circuit adds 1 disclosure proof
162
169
  this.topicToExpectedProofCount[topic] =
163
170
  neededCircuits.length === 0 ? 4 : 3 + neededCircuits.length;
171
+ this.topicToFailedProofCount[topic] = 0;
164
172
  }
165
173
  /**
166
174
  * @notice Handle an encrypted message.
@@ -216,6 +224,7 @@ class ZKPassport {
216
224
  // This means the user has an ID that is not supported yet
217
225
  // So we won't receive any proofs and we can handle the result now
218
226
  this.topicToExpectedProofCount[topic] = 0;
227
+ this.topicToFailedProofCount[topic] += this.topicToExpectedProofCount[topic];
219
228
  if (this.topicToResults[topic]) {
220
229
  await this.handleResult(topic);
221
230
  }
@@ -224,6 +233,7 @@ class ZKPassport {
224
233
  // This means one of the disclosure proofs failed to be generated
225
234
  // So we need to remove one from the expected proof count
226
235
  this.topicToExpectedProofCount[topic] -= 1;
236
+ this.topicToFailedProofCount[topic] += 1;
227
237
  // If the expected proof count is now equal to the number of proofs received
228
238
  // and the results were received, we can handle the result now
229
239
  if (this.topicToResults[topic] &&
@@ -280,9 +290,6 @@ class ZKPassport {
280
290
  };
281
291
  return this.getZkPassportRequest(topic);
282
292
  },
283
- /*checkAML: (country?: CountryName | Alpha2Code | Alpha3Code) => {
284
- return this.getZkPassportRequest(topic)
285
- },*/
286
293
  done: () => {
287
294
  const base64Config = buffer_1.Buffer.from(JSON.stringify(this.topicToConfig[topic])).toString("base64");
288
295
  const base64Service = buffer_1.Buffer.from(JSON.stringify(this.topicToService[topic])).toString("base64");
@@ -305,10 +312,15 @@ class ZKPassport {
305
312
  };
306
313
  }
307
314
  /**
308
- * @notice Create a new request.
315
+ * @notice Create a new request
316
+ * @param name Your service name
317
+ * @param logo The logo of your service
318
+ * @param purpose To explain what you want to do with the user's data
319
+ * @param scope Scope this request to a specific use case
320
+ * @param validity How many days ago should have the ID been last scanned by the user?
309
321
  * @returns The query builder object.
310
322
  */
311
- async request({ name, logo, purpose, scope, topicOverride, keyPairOverride, }) {
323
+ async request({ name, logo, purpose, scope, validity, topicOverride, keyPairOverride, }) {
312
324
  const topic = topicOverride || (0, crypto_1.randomBytes)(16).toString("hex");
313
325
  const keyPair = keyPairOverride || (await (0, encryption_1.generateECDHKeyPair)());
314
326
  this.topicToKeyPair[topic] = {
@@ -319,6 +331,10 @@ class ZKPassport {
319
331
  this.topicToService[topic] = { name, logo, purpose, scope };
320
332
  this.topicToProofs[topic] = [];
321
333
  this.topicToExpectedProofCount[topic] = 0;
334
+ this.topicToLocalConfig[topic] = {
335
+ // Default to 6 months
336
+ validity: validity || 6 * 30,
337
+ };
322
338
  this.onRequestReceivedCallbacks[topic] = [];
323
339
  this.onGeneratingProofCallbacks[topic] = [];
324
340
  this.onBridgeConnectCallbacks[topic] = [];
@@ -375,7 +391,7 @@ class ZKPassport {
375
391
  };
376
392
  return this.getZkPassportRequest(topic);
377
393
  }
378
- async checkPublicInputs(proofs, queryResult) {
394
+ async checkPublicInputs(proofs, queryResult, topic) {
379
395
  let commitmentIn;
380
396
  let commitmentOut;
381
397
  let isCorrect = true;
@@ -384,6 +400,23 @@ class ZKPassport {
384
400
  const defaultDateValue = new Date(1111, 10, 11);
385
401
  const currentTime = new Date();
386
402
  const today = new Date(currentTime.getFullYear(), currentTime.getMonth(), currentTime.getDate(), 0, 0, 0, 0);
403
+ const queryResultErrors = {
404
+ sig_check_dsc: {},
405
+ sig_check_id_data: {},
406
+ data_check_integrity: {},
407
+ disclose: {},
408
+ age: {},
409
+ birthdate: {},
410
+ expiry_date: {},
411
+ document_type: {},
412
+ issuing_country: {},
413
+ gender: {},
414
+ nationality: {},
415
+ firstname: {},
416
+ lastname: {},
417
+ fullname: {},
418
+ document_number: {},
419
+ };
387
420
  // Since the order is important for the commitments, we need to sort the proofs
388
421
  // by their expected order: root signature check -> ID signature check -> integrity check -> disclosure
389
422
  const sortedProofs = proofs.sort((a, b) => {
@@ -412,7 +445,11 @@ class ZKPassport {
412
445
  if (merkleRoot !== expectedMerkleRoot) {
413
446
  console.warn("The ID was signed by an unrecognized root certificate");
414
447
  isCorrect = false;
415
- break;
448
+ queryResultErrors.sig_check_dsc.certificate = {
449
+ expected: `Certificate registry root: ${expectedMerkleRoot.toString()}`,
450
+ received: `Certificate registry root: ${merkleRoot.toString()}`,
451
+ message: "The ID was signed by an unrecognized root certificate",
452
+ };
416
453
  }
417
454
  }
418
455
  else if (proof.name?.startsWith("sig_check_id_data")) {
@@ -420,7 +457,11 @@ class ZKPassport {
420
457
  if (commitmentIn !== commitmentOut) {
421
458
  console.warn("Failed to check the link between the certificate signature and ID signature");
422
459
  isCorrect = false;
423
- break;
460
+ queryResultErrors.sig_check_id_data.commitment = {
461
+ expected: `Commitment: ${commitmentOut?.toString() || "undefined"}`,
462
+ received: `Commitment: ${commitmentIn?.toString() || "undefined"}`,
463
+ message: "Failed to check the link between the certificate signature and ID signature",
464
+ };
424
465
  }
425
466
  commitmentOut = (0, utils_1.getCommitmentOutFromIDDataProof)(proofData);
426
467
  }
@@ -429,17 +470,26 @@ class ZKPassport {
429
470
  if (commitmentIn !== commitmentOut) {
430
471
  console.warn("Failed to check the link between the ID signature and the data signed");
431
472
  isCorrect = false;
432
- break;
473
+ queryResultErrors.data_check_integrity.commitment = {
474
+ expected: `Commitment: ${commitmentOut?.toString() || "undefined"}`,
475
+ received: `Commitment: ${commitmentIn?.toString() || "undefined"}`,
476
+ message: "Failed to check the link between the ID signature and the data signed",
477
+ };
433
478
  }
434
479
  commitmentOut = (0, utils_1.getCommitmentOutFromIntegrityProof)(proofData);
435
480
  const currentDate = (0, utils_1.getCurrentDateFromIntegrityProof)(proofData);
436
- // The date should be today or yesterday
437
- // (if the proof request was requested just before midnight and is finalized after)
438
- if (currentDate.getTime() !== today.getTime() &&
439
- currentDate.getTime() !== today.getTime() - 86400000) {
440
- console.warn("Current date used to check the validity of the ID is too old");
481
+ const todayToCurrentDate = today.getTime() - currentDate.getTime();
482
+ const expectedDifference = this.topicToLocalConfig[topic]?.validity * 86400000;
483
+ const actualDifference = today.getTime() - (today.getTime() - expectedDifference);
484
+ // The ID should not expire within the next 6 months (or whatever the custom value is)
485
+ if (todayToCurrentDate >= actualDifference) {
486
+ console.warn(`The date used to check the validity of the ID is older than ${this.topicToLocalConfig[topic]?.validity} days. You can ask the user to rescan their ID or ask them to disclose their expiry date`);
441
487
  isCorrect = false;
442
- break;
488
+ queryResultErrors.data_check_integrity.date = {
489
+ expected: `Difference: ${this.topicToLocalConfig[topic]?.validity} days`,
490
+ received: `Difference: ${Math.round(todayToCurrentDate / 86400000)} days`,
491
+ message: "The date used to check the validity of the ID is older than the validity period",
492
+ };
443
493
  }
444
494
  }
445
495
  else if (proof.name === "disclose_bytes") {
@@ -447,7 +497,11 @@ class ZKPassport {
447
497
  if (commitmentIn !== commitmentOut) {
448
498
  console.warn("Failed to check the link between the validity of the ID and the data to disclose");
449
499
  isCorrect = false;
450
- break;
500
+ queryResultErrors.disclose.commitment = {
501
+ expected: `Commitment: ${commitmentOut?.toString() || "undefined"}`,
502
+ received: `Commitment: ${commitmentIn?.toString() || "undefined"}`,
503
+ message: "Failed to check the link between the validity of the ID and the data to disclose",
504
+ };
451
505
  }
452
506
  // We can't be certain that the disclosed data is for a passport or an ID card
453
507
  // so we need to check both (unless the document type is revealed)
@@ -460,12 +514,20 @@ class ZKPassport {
460
514
  queryResult.document_type.eq.expected !== disclosedDataPassport.documentType) {
461
515
  console.warn("Document type does not match the expected document type");
462
516
  isCorrect = false;
463
- break;
517
+ queryResultErrors.document_type.eq = {
518
+ expected: `${queryResult.document_type.eq.expected}`,
519
+ received: `${disclosedDataPassport.documentType}`,
520
+ message: "Document type does not match the expected document type",
521
+ };
464
522
  }
465
523
  if (queryResult.document_type.disclose?.result !== disclosedDataIDCard.documentType) {
466
524
  console.warn("Document type does not match the disclosed document type in query result");
467
525
  isCorrect = false;
468
- break;
526
+ queryResultErrors.document_type.disclose = {
527
+ expected: `${queryResult.document_type.disclose?.result}`,
528
+ received: `${disclosedDataIDCard.documentType}`,
529
+ message: "Document type does not match the disclosed document type in query result",
530
+ };
469
531
  }
470
532
  }
471
533
  if (queryResult.birthdate) {
@@ -477,14 +539,22 @@ class ZKPassport {
477
539
  queryResult.birthdate.eq.expected.getTime() !== birthdateIDCard.getTime()) {
478
540
  console.warn("Birthdate does not match the expected birthdate");
479
541
  isCorrect = false;
480
- break;
542
+ queryResultErrors.birthdate.eq = {
543
+ expected: `${queryResult.birthdate.eq.expected.toISOString()}`,
544
+ received: `${birthdatePassport.toISOString()}`,
545
+ message: "Birthdate does not match the expected birthdate",
546
+ };
481
547
  }
482
548
  if (queryResult.birthdate.disclose &&
483
549
  queryResult.birthdate.disclose.result.getTime() !== birthdatePassport.getTime() &&
484
550
  queryResult.birthdate.disclose.result.getTime() !== birthdateIDCard.getTime()) {
485
551
  console.warn("Birthdate does not match the disclosed birthdate in query result");
486
552
  isCorrect = false;
487
- break;
553
+ queryResultErrors.birthdate.disclose = {
554
+ expected: `${queryResult.birthdate.disclose.result.toISOString()}`,
555
+ received: `${birthdatePassport.toISOString()}`,
556
+ message: "Birthdate does not match the disclosed birthdate in query result",
557
+ };
488
558
  }
489
559
  }
490
560
  if (queryResult.expiry_date) {
@@ -496,14 +566,22 @@ class ZKPassport {
496
566
  queryResult.expiry_date.eq.expected.getTime() !== expiryDateIDCard.getTime()) {
497
567
  console.warn("Expiry date does not match the expected expiry date");
498
568
  isCorrect = false;
499
- break;
569
+ queryResultErrors.expiry_date.eq = {
570
+ expected: `${queryResult.expiry_date.eq.expected.toISOString()}`,
571
+ received: `${expiryDatePassport.toISOString()}`,
572
+ message: "Expiry date does not match the expected expiry date",
573
+ };
500
574
  }
501
575
  if (queryResult.expiry_date.disclose &&
502
576
  queryResult.expiry_date.disclose.result.getTime() !== expiryDatePassport.getTime() &&
503
577
  queryResult.expiry_date.disclose.result.getTime() !== expiryDateIDCard.getTime()) {
504
578
  console.warn("Expiry date does not match the disclosed expiry date in query result");
505
579
  isCorrect = false;
506
- break;
580
+ queryResultErrors.expiry_date.disclose = {
581
+ expected: `${queryResult.expiry_date.disclose.result.toISOString()}`,
582
+ received: `${expiryDatePassport.toISOString()}`,
583
+ message: "Expiry date does not match the disclosed expiry date in query result",
584
+ };
507
585
  }
508
586
  }
509
587
  if (queryResult.nationality) {
@@ -515,14 +593,22 @@ class ZKPassport {
515
593
  queryResult.nationality.eq.expected !== nationalityIDCard) {
516
594
  console.warn("Nationality does not match the expected nationality");
517
595
  isCorrect = false;
518
- break;
596
+ queryResultErrors.nationality.eq = {
597
+ expected: `${queryResult.nationality.eq.expected}`,
598
+ received: `${nationalityPassport}`,
599
+ message: "Nationality does not match the expected nationality",
600
+ };
519
601
  }
520
602
  if (queryResult.nationality.disclose &&
521
603
  queryResult.nationality.disclose.result !== nationalityPassport &&
522
604
  queryResult.nationality.disclose.result !== nationalityIDCard) {
523
605
  console.warn("Nationality does not match the disclosed nationality in query result");
524
606
  isCorrect = false;
525
- break;
607
+ queryResultErrors.nationality.disclose = {
608
+ expected: `${queryResult.nationality.disclose.result}`,
609
+ received: `${nationalityPassport}`,
610
+ message: "Nationality does not match the disclosed nationality in query result",
611
+ };
526
612
  }
527
613
  }
528
614
  if (queryResult.document_number) {
@@ -534,14 +620,22 @@ class ZKPassport {
534
620
  queryResult.document_number.eq.expected !== documentNumberIDCard) {
535
621
  console.warn("Document number does not match the expected document number");
536
622
  isCorrect = false;
537
- break;
623
+ queryResultErrors.document_number.eq = {
624
+ expected: `${queryResult.document_number.eq.expected}`,
625
+ received: `${documentNumberPassport}`,
626
+ message: "Document number does not match the expected document number",
627
+ };
538
628
  }
539
629
  if (queryResult.document_number.disclose &&
540
630
  queryResult.document_number.disclose.result !== documentNumberPassport &&
541
631
  queryResult.document_number.disclose.result !== documentNumberIDCard) {
542
632
  console.warn("Document number does not match the disclosed document number in query result");
543
633
  isCorrect = false;
544
- break;
634
+ queryResultErrors.document_number.disclose = {
635
+ expected: `${queryResult.document_number.disclose.result}`,
636
+ received: `${documentNumberPassport}`,
637
+ message: "Document number does not match the disclosed document number in query result",
638
+ };
545
639
  }
546
640
  }
547
641
  if (queryResult.gender) {
@@ -553,14 +647,22 @@ class ZKPassport {
553
647
  queryResult.gender.eq.expected !== genderIDCard) {
554
648
  console.warn("Gender does not match the expected gender");
555
649
  isCorrect = false;
556
- break;
650
+ queryResultErrors.gender.eq = {
651
+ expected: `${queryResult.gender.eq.expected}`,
652
+ received: `${genderPassport}`,
653
+ message: "Gender does not match the expected gender",
654
+ };
557
655
  }
558
656
  if (queryResult.gender.disclose &&
559
657
  queryResult.gender.disclose.result !== genderPassport &&
560
658
  queryResult.gender.disclose.result !== genderIDCard) {
561
659
  console.warn("Gender does not match the disclosed gender in query result");
562
660
  isCorrect = false;
563
- break;
661
+ queryResultErrors.gender.disclose = {
662
+ expected: `${queryResult.gender.disclose.result}`,
663
+ received: `${genderPassport}`,
664
+ message: "Gender does not match the disclosed gender in query result",
665
+ };
564
666
  }
565
667
  }
566
668
  if (queryResult.issuing_country) {
@@ -572,14 +674,22 @@ class ZKPassport {
572
674
  queryResult.issuing_country.eq.expected !== issuingCountryIDCard) {
573
675
  console.warn("Issuing country does not match the expected issuing country");
574
676
  isCorrect = false;
575
- break;
677
+ queryResultErrors.issuing_country.eq = {
678
+ expected: `${queryResult.issuing_country.eq.expected}`,
679
+ received: `${issuingCountryPassport}`,
680
+ message: "Issuing country does not match the expected issuing country",
681
+ };
576
682
  }
577
683
  if (queryResult.issuing_country.disclose &&
578
684
  queryResult.issuing_country.disclose.result !== issuingCountryPassport &&
579
685
  queryResult.issuing_country.disclose.result !== issuingCountryIDCard) {
580
686
  console.warn("Issuing country does not match the disclosed issuing country in query result");
581
687
  isCorrect = false;
582
- break;
688
+ queryResultErrors.issuing_country.disclose = {
689
+ expected: `${queryResult.issuing_country.disclose.result}`,
690
+ received: `${issuingCountryPassport}`,
691
+ message: "Issuing country does not match the disclosed issuing country in query result",
692
+ };
583
693
  }
584
694
  }
585
695
  if (queryResult.fullname) {
@@ -593,7 +703,11 @@ class ZKPassport {
593
703
  fullnameIDCard.toLowerCase()) {
594
704
  console.warn("Fullname does not match the expected fullname");
595
705
  isCorrect = false;
596
- break;
706
+ queryResultErrors.fullname.eq = {
707
+ expected: `${queryResult.fullname.eq.expected}`,
708
+ received: `${fullnamePassport}`,
709
+ message: "Fullname does not match the expected fullname",
710
+ };
597
711
  }
598
712
  if (queryResult.fullname.disclose &&
599
713
  (0, utils_1.formatName)(queryResult.fullname.disclose.result).toLowerCase() !==
@@ -602,7 +716,11 @@ class ZKPassport {
602
716
  fullnameIDCard.toLowerCase()) {
603
717
  console.warn("Fullname does not match the disclosed fullname in query result");
604
718
  isCorrect = false;
605
- break;
719
+ queryResultErrors.fullname.disclose = {
720
+ expected: `${queryResult.fullname.disclose.result}`,
721
+ received: `${fullnamePassport}`,
722
+ message: "Fullname does not match the disclosed fullname in query result",
723
+ };
606
724
  }
607
725
  }
608
726
  if (queryResult.firstname) {
@@ -621,7 +739,11 @@ class ZKPassport {
621
739
  firstnameIDCard.toLowerCase()) {
622
740
  console.warn("Firstname does not match the expected firstname");
623
741
  isCorrect = false;
624
- break;
742
+ queryResultErrors.firstname.eq = {
743
+ expected: `${queryResult.firstname.eq.expected}`,
744
+ received: `${firstnamePassport}`,
745
+ message: "Firstname does not match the expected firstname",
746
+ };
625
747
  }
626
748
  if (queryResult.firstname.disclose &&
627
749
  (0, utils_1.formatName)(queryResult.firstname.disclose.result).toLowerCase() !==
@@ -630,7 +752,11 @@ class ZKPassport {
630
752
  firstnameIDCard.toLowerCase()) {
631
753
  console.warn("Firstname does not match the disclosed firstname in query result");
632
754
  isCorrect = false;
633
- break;
755
+ queryResultErrors.firstname.disclose = {
756
+ expected: `${queryResult.firstname.disclose.result}`,
757
+ received: `${firstnamePassport}`,
758
+ message: "Firstname does not match the disclosed firstname in query result",
759
+ };
634
760
  }
635
761
  }
636
762
  if (queryResult.lastname) {
@@ -649,7 +775,11 @@ class ZKPassport {
649
775
  lastnameIDCard.toLowerCase()) {
650
776
  console.warn("Lastname does not match the expected lastname");
651
777
  isCorrect = false;
652
- break;
778
+ queryResultErrors.lastname.eq = {
779
+ expected: `${queryResult.lastname.eq.expected}`,
780
+ received: `${lastnamePassport}`,
781
+ message: "Lastname does not match the expected lastname",
782
+ };
653
783
  }
654
784
  if (queryResult.lastname.disclose &&
655
785
  (0, utils_1.formatName)(queryResult.lastname.disclose.result).toLowerCase() !==
@@ -658,7 +788,11 @@ class ZKPassport {
658
788
  lastnameIDCard.toLowerCase()) {
659
789
  console.warn("Lastname does not match the disclosed lastname in query result");
660
790
  isCorrect = false;
661
- break;
791
+ queryResultErrors.lastname.disclose = {
792
+ expected: `${queryResult.lastname.disclose.result}`,
793
+ received: `${lastnamePassport}`,
794
+ message: "Lastname does not match the disclosed lastname in query result",
795
+ };
662
796
  }
663
797
  }
664
798
  uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
@@ -668,7 +802,11 @@ class ZKPassport {
668
802
  if (commitmentIn !== commitmentOut) {
669
803
  console.warn("Failed to check the link between the validity of the ID and the age derived from it");
670
804
  isCorrect = false;
671
- break;
805
+ queryResultErrors.age.commitment = {
806
+ expected: `Commitment: ${commitmentOut}`,
807
+ received: `Commitment: ${commitmentIn}`,
808
+ message: "Failed to check the link between the validity of the ID and the age derived from it",
809
+ };
672
810
  }
673
811
  const minAge = (0, utils_1.getMinAgeFromProof)(proofData);
674
812
  const maxAge = (0, utils_1.getMaxAgeFromProof)(proofData);
@@ -678,14 +816,22 @@ class ZKPassport {
678
816
  minAge < queryResult.age.gte.expected) {
679
817
  console.warn("Age is not greater than or equal to the expected age");
680
818
  isCorrect = false;
681
- break;
819
+ queryResultErrors.age.gte = {
820
+ expected: queryResult.age.gte.expected,
821
+ received: minAge,
822
+ message: "Age is not greater than or equal to the expected age",
823
+ };
682
824
  }
683
825
  if (queryResult.age.lt &&
684
826
  queryResult.age.lt.result &&
685
827
  maxAge >= queryResult.age.lt.expected) {
686
828
  console.warn("Age is not less than the expected age");
687
829
  isCorrect = false;
688
- break;
830
+ queryResultErrors.age.lt = {
831
+ expected: queryResult.age.lt.expected,
832
+ received: maxAge,
833
+ message: "Age is not less than the expected age",
834
+ };
689
835
  }
690
836
  if (queryResult.age.range) {
691
837
  if (queryResult.age.range.result &&
@@ -693,38 +839,60 @@ class ZKPassport {
693
839
  maxAge >= queryResult.age.range.expected[1])) {
694
840
  console.warn("Age is not in the expected range");
695
841
  isCorrect = false;
696
- break;
842
+ queryResultErrors.age.range = {
843
+ expected: queryResult.age.range.expected,
844
+ received: [minAge, maxAge],
845
+ message: "Age is not in the expected range",
846
+ };
697
847
  }
698
848
  }
699
849
  if (!queryResult.age.lt && !queryResult.age.range && maxAge != 0) {
700
850
  console.warn("Maximum age should be equal to 0");
701
851
  isCorrect = false;
702
- break;
852
+ queryResultErrors.age.disclose = {
853
+ expected: 0,
854
+ received: maxAge,
855
+ message: "Maximum age should be equal to 0",
856
+ };
703
857
  }
704
858
  if (!queryResult.age.gte && !queryResult.age.range && minAge != 0) {
705
859
  console.warn("Minimum age should be equal to 0");
706
860
  isCorrect = false;
707
- break;
861
+ queryResultErrors.age.disclose = {
862
+ expected: 0,
863
+ received: minAge,
864
+ message: "Minimum age should be equal to 0",
865
+ };
708
866
  }
709
867
  if (queryResult.age.disclose &&
710
868
  (queryResult.age.disclose.result !== minAge ||
711
869
  queryResult.age.disclose.result !== maxAge)) {
712
870
  console.warn("Age does not match the disclosed age in query result");
713
871
  isCorrect = false;
714
- break;
872
+ queryResultErrors.age.disclose = {
873
+ expected: `${minAge}`,
874
+ received: `${queryResult.age.disclose.result}`,
875
+ message: "Age does not match the disclosed age in query result",
876
+ };
715
877
  }
716
878
  }
717
879
  else {
718
880
  console.warn("Age is not set in the query result");
719
881
  isCorrect = false;
720
- break;
882
+ queryResultErrors.age.disclose = {
883
+ message: "Age is not set in the query result",
884
+ };
721
885
  }
722
886
  const currentDate = (0, utils_1.getCurrentDateFromAgeProof)(proofData);
723
887
  if (currentDate.getTime() !== today.getTime() &&
724
888
  currentDate.getTime() !== today.getTime() - 86400000) {
725
889
  console.warn("Current date in the proof is too old");
726
890
  isCorrect = false;
727
- break;
891
+ queryResultErrors.age.disclose = {
892
+ expected: `${today.toISOString()}`,
893
+ received: `${currentDate.toISOString()}`,
894
+ message: "Current date in the proof is too old",
895
+ };
728
896
  }
729
897
  uniqueIdentifier = (0, utils_1.getCommitmentInFromDisclosureProof)(proofData).toString(10);
730
898
  }
@@ -733,7 +901,11 @@ class ZKPassport {
733
901
  if (commitmentIn !== commitmentOut) {
734
902
  console.warn("Failed to check the link between the validity of the ID and the birthdate derived from it");
735
903
  isCorrect = false;
736
- break;
904
+ queryResultErrors.birthdate.commitment = {
905
+ expected: `Commitment: ${commitmentOut}`,
906
+ received: `Commitment: ${commitmentIn}`,
907
+ message: "Failed to check the link between the validity of the ID and the birthdate derived from it",
908
+ };
737
909
  }
738
910
  const minDate = (0, utils_1.getMinDateFromProof)(proofData);
739
911
  const maxDate = (0, utils_1.getMaxDateFromProof)(proofData);
@@ -743,14 +915,22 @@ class ZKPassport {
743
915
  minDate < queryResult.birthdate.gte.expected) {
744
916
  console.warn("Birthdate is not greater than or equal to the expected birthdate");
745
917
  isCorrect = false;
746
- break;
918
+ queryResultErrors.birthdate.gte = {
919
+ expected: queryResult.birthdate.gte.expected,
920
+ received: minDate,
921
+ message: "Birthdate is not greater than or equal to the expected birthdate",
922
+ };
747
923
  }
748
924
  if (queryResult.birthdate.lte &&
749
925
  queryResult.birthdate.lte.result &&
750
926
  maxDate > queryResult.birthdate.lte.expected) {
751
927
  console.warn("Birthdate is not less than the expected birthdate");
752
928
  isCorrect = false;
753
- break;
929
+ queryResultErrors.birthdate.lte = {
930
+ expected: queryResult.birthdate.lte.expected,
931
+ received: maxDate,
932
+ message: "Birthdate is not less than the expected birthdate",
933
+ };
754
934
  }
755
935
  if (queryResult.birthdate.range) {
756
936
  if (queryResult.birthdate.range.result &&
@@ -758,7 +938,11 @@ class ZKPassport {
758
938
  maxDate > queryResult.birthdate.range.expected[1])) {
759
939
  console.warn("Birthdate is not in the expected range");
760
940
  isCorrect = false;
761
- break;
941
+ queryResultErrors.birthdate.range = {
942
+ expected: queryResult.birthdate.range.expected,
943
+ received: [minDate, maxDate],
944
+ message: "Birthdate is not in the expected range",
945
+ };
762
946
  }
763
947
  }
764
948
  if (!queryResult.birthdate.lte &&
@@ -766,20 +950,30 @@ class ZKPassport {
766
950
  maxDate.getTime() != defaultDateValue.getTime()) {
767
951
  console.warn("Maximum birthdate should be equal to default date value");
768
952
  isCorrect = false;
769
- break;
953
+ queryResultErrors.birthdate.disclose = {
954
+ expected: `${defaultDateValue.toISOString()}`,
955
+ received: `${maxDate.toISOString()}`,
956
+ message: "Maximum birthdate should be equal to default date value",
957
+ };
770
958
  }
771
959
  if (!queryResult.birthdate.gte &&
772
960
  !queryResult.birthdate.range &&
773
961
  minDate.getTime() != defaultDateValue.getTime()) {
774
962
  console.warn("Minimum birthdate should be equal to default date value");
775
963
  isCorrect = false;
776
- break;
964
+ queryResultErrors.birthdate.disclose = {
965
+ expected: `${defaultDateValue.toISOString()}`,
966
+ received: `${minDate.toISOString()}`,
967
+ message: "Minimum birthdate should be equal to default date value",
968
+ };
777
969
  }
778
970
  }
779
971
  else {
780
972
  console.warn("Birthdate is not set in the query result");
781
973
  isCorrect = false;
782
- break;
974
+ queryResultErrors.birthdate.disclose = {
975
+ message: "Birthdate is not set in the query result",
976
+ };
783
977
  }
784
978
  uniqueIdentifier = (0, utils_1.getCommitmentInFromDisclosureProof)(proofData).toString(10);
785
979
  }
@@ -788,7 +982,11 @@ class ZKPassport {
788
982
  if (commitmentIn !== commitmentOut) {
789
983
  console.warn("Failed to check the link between the validity of the ID and its expiry date");
790
984
  isCorrect = false;
791
- break;
985
+ queryResultErrors.expiry_date.commitment = {
986
+ expected: `Commitment: ${commitmentOut}`,
987
+ received: `Commitment: ${commitmentIn}`,
988
+ message: "Failed to check the link between the validity of the ID and its expiry date",
989
+ };
792
990
  }
793
991
  const minDate = (0, utils_1.getMinDateFromProof)(proofData);
794
992
  const maxDate = (0, utils_1.getMaxDateFromProof)(proofData);
@@ -798,14 +996,22 @@ class ZKPassport {
798
996
  minDate < queryResult.expiry_date.gte.expected) {
799
997
  console.warn("Expiry date is not greater than or equal to the expected expiry date");
800
998
  isCorrect = false;
801
- break;
999
+ queryResultErrors.expiry_date.gte = {
1000
+ expected: queryResult.expiry_date.gte.expected,
1001
+ received: minDate,
1002
+ message: "Expiry date is not greater than or equal to the expected expiry date",
1003
+ };
802
1004
  }
803
1005
  if (queryResult.expiry_date.lte &&
804
1006
  queryResult.expiry_date.lte.result &&
805
1007
  maxDate > queryResult.expiry_date.lte.expected) {
806
1008
  console.warn("Expiry date is not less than the expected expiry date");
807
1009
  isCorrect = false;
808
- break;
1010
+ queryResultErrors.expiry_date.lte = {
1011
+ expected: queryResult.expiry_date.lte.expected,
1012
+ received: maxDate,
1013
+ message: "Expiry date is not less than the expected expiry date",
1014
+ };
809
1015
  }
810
1016
  if (queryResult.expiry_date.range) {
811
1017
  if (queryResult.expiry_date.range.result &&
@@ -813,7 +1019,11 @@ class ZKPassport {
813
1019
  maxDate > queryResult.expiry_date.range.expected[1])) {
814
1020
  console.warn("Expiry date is not in the expected range");
815
1021
  isCorrect = false;
816
- break;
1022
+ queryResultErrors.expiry_date.range = {
1023
+ expected: queryResult.expiry_date.range.expected,
1024
+ received: [minDate, maxDate],
1025
+ message: "Expiry date is not in the expected range",
1026
+ };
817
1027
  }
818
1028
  }
819
1029
  if (!queryResult.expiry_date.lte &&
@@ -821,20 +1031,30 @@ class ZKPassport {
821
1031
  maxDate.getTime() != defaultDateValue.getTime()) {
822
1032
  console.warn("Maximum expiry date should be equal to default date value");
823
1033
  isCorrect = false;
824
- break;
1034
+ queryResultErrors.expiry_date.disclose = {
1035
+ expected: `${defaultDateValue.toISOString()}`,
1036
+ received: `${maxDate.toISOString()}`,
1037
+ message: "Maximum expiry date should be equal to default date value",
1038
+ };
825
1039
  }
826
1040
  if (!queryResult.expiry_date.gte &&
827
1041
  !queryResult.expiry_date.range &&
828
1042
  minDate.getTime() != defaultDateValue.getTime()) {
829
1043
  console.warn("Minimum expiry date should be equal to default date value");
830
1044
  isCorrect = false;
831
- break;
1045
+ queryResultErrors.expiry_date.disclose = {
1046
+ expected: `${defaultDateValue.toISOString()}`,
1047
+ received: `${minDate.toISOString()}`,
1048
+ message: "Minimum expiry date should be equal to default date value",
1049
+ };
832
1050
  }
833
1051
  }
834
1052
  else {
835
1053
  console.warn("Expiry date is not set in the query result");
836
1054
  isCorrect = false;
837
- break;
1055
+ queryResultErrors.expiry_date.disclose = {
1056
+ message: "Expiry date is not set in the query result",
1057
+ };
838
1058
  }
839
1059
  uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
840
1060
  }
@@ -843,7 +1063,11 @@ class ZKPassport {
843
1063
  if (commitmentIn !== commitmentOut) {
844
1064
  console.warn("Failed to check the link between the validity of the ID and the country exclusion check");
845
1065
  isCorrect = false;
846
- break;
1066
+ queryResultErrors.nationality.commitment = {
1067
+ expected: `Commitment: ${commitmentOut}`,
1068
+ received: `Commitment: ${commitmentIn}`,
1069
+ message: "Failed to check the link between the validity of the ID and the country exclusion check",
1070
+ };
847
1071
  }
848
1072
  const countryList = (0, utils_1.getCountryListFromExclusionProof)(proofData);
849
1073
  if (queryResult.nationality &&
@@ -852,13 +1076,19 @@ class ZKPassport {
852
1076
  if (!queryResult.nationality.out.expected?.every((country) => countryList.includes(country))) {
853
1077
  console.warn("Country exclusion list does not match the one from the query results");
854
1078
  isCorrect = false;
855
- break;
1079
+ queryResultErrors.nationality.out = {
1080
+ expected: queryResult.nationality.out.expected,
1081
+ received: countryList,
1082
+ message: "Country exclusion list does not match the one from the query results",
1083
+ };
856
1084
  }
857
1085
  }
858
1086
  else if (!queryResult.nationality || !queryResult.nationality.out) {
859
1087
  console.warn("Nationality exclusion is not set in the query result");
860
1088
  isCorrect = false;
861
- break;
1089
+ queryResultErrors.nationality.out = {
1090
+ message: "Nationality exclusion is not set in the query result",
1091
+ };
862
1092
  }
863
1093
  // Check the countryList is in ascending order
864
1094
  // If the prover doesn't use a sorted list then the proof cannot be trusted
@@ -867,7 +1097,9 @@ class ZKPassport {
867
1097
  if (countryList[i] < countryList[i - 1]) {
868
1098
  console.warn("The nationality exclusion list has not been sorted, and thus the proof cannot be trusted");
869
1099
  isCorrect = false;
870
- break;
1100
+ queryResultErrors.nationality.out = {
1101
+ message: "The nationality exclusion list has not been sorted, and thus the proof cannot be trusted",
1102
+ };
871
1103
  }
872
1104
  }
873
1105
  uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
@@ -877,7 +1109,11 @@ class ZKPassport {
877
1109
  if (commitmentIn !== commitmentOut) {
878
1110
  console.warn("Failed to check the link between the validity of the ID and the country inclusion check");
879
1111
  isCorrect = false;
880
- break;
1112
+ queryResultErrors.nationality.commitment = {
1113
+ expected: `Commitment: ${commitmentOut}`,
1114
+ received: `Commitment: ${commitmentIn}`,
1115
+ message: "Failed to check the link between the validity of the ID and the country inclusion check",
1116
+ };
881
1117
  }
882
1118
  const countryList = (0, utils_1.getCountryListFromInclusionProof)(proofData);
883
1119
  if (queryResult.nationality &&
@@ -886,18 +1122,24 @@ class ZKPassport {
886
1122
  if (!queryResult.nationality.in.expected?.every((country) => countryList.includes(country))) {
887
1123
  console.warn("Country inclusion list does not match the one from the query results");
888
1124
  isCorrect = false;
889
- break;
1125
+ queryResultErrors.nationality.in = {
1126
+ expected: queryResult.nationality.in.expected,
1127
+ received: countryList,
1128
+ message: "Country inclusion list does not match the one from the query results",
1129
+ };
890
1130
  }
891
1131
  }
892
1132
  else if (!queryResult.nationality || !queryResult.nationality.in) {
893
1133
  console.warn("Nationality inclusion is not set in the query result");
894
1134
  isCorrect = false;
895
- break;
1135
+ queryResultErrors.nationality.in = {
1136
+ message: "Nationality inclusion is not set in the query result",
1137
+ };
896
1138
  }
897
1139
  uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
898
1140
  }
899
1141
  }
900
- return { isCorrect, uniqueIdentifier };
1142
+ return { isCorrect, uniqueIdentifier, queryResultErrors };
901
1143
  }
902
1144
  /**
903
1145
  * @notice Verify the proofs received from the mobile app.
@@ -912,12 +1154,6 @@ class ZKPassport {
912
1154
  // There is a minimum of 4 subproofs to make a complete proof
913
1155
  if (!proofs || proofs.length < 4) {
914
1156
  proofsToVerify = this.topicToProofs[requestId];
915
- if (!proofsToVerify || proofsToVerify.length < 4) {
916
- // It may happen that a request returns a result without proofs
917
- // Meaning the ID is not supported yet by ZKPassport circuits,
918
- // so the results has to be trusted and cannot be independently verified
919
- return { uniqueIdentifier: undefined, verified: false };
920
- }
921
1157
  }
922
1158
  const { BarretenbergVerifier } = await Promise.resolve().then(() => tslib_1.__importStar(require("@aztec/bb.js")));
923
1159
  const verifier = new BarretenbergVerifier();
@@ -926,13 +1162,15 @@ class ZKPassport {
926
1162
  }*/
927
1163
  let verified = true;
928
1164
  let uniqueIdentifier;
1165
+ let queryResultErrors;
929
1166
  if (queryResult) {
930
- const { isCorrect, uniqueIdentifier: uniqueIdentifierFromPublicInputs } = await this.checkPublicInputs(proofsToVerify, queryResult);
1167
+ const { isCorrect, uniqueIdentifier: uniqueIdentifierFromPublicInputs, queryResultErrors: queryResultErrorsFromPublicInputs, } = await this.checkPublicInputs(proofsToVerify, queryResult, requestId);
931
1168
  uniqueIdentifier = uniqueIdentifierFromPublicInputs;
932
1169
  verified = isCorrect;
1170
+ queryResultErrors = isCorrect ? undefined : queryResultErrorsFromPublicInputs;
933
1171
  }
934
1172
  // Only proceed with the proof verification if the public inputs are correct
935
- if (verified) {
1173
+ if (verified && queryResult) {
936
1174
  for (const proof of proofsToVerify) {
937
1175
  const proofData = (0, utils_1.getProofData)(proof.proof, true);
938
1176
  const hostedPackagedCircuit = await (0, utils_1.getHostedPackagedCircuitByName)(proof.version, proof.name);
@@ -952,7 +1190,7 @@ class ZKPassport {
952
1190
  }
953
1191
  }
954
1192
  this.topicToProofs[requestId] = [];
955
- return { uniqueIdentifier, verified };
1193
+ return { uniqueIdentifier, verified, queryResultErrors };
956
1194
  }
957
1195
  /**
958
1196
  * @notice Returns the URL of the request.
@@ -970,13 +1208,17 @@ class ZKPassport {
970
1208
  * @param requestId The request ID.
971
1209
  */
972
1210
  cancelRequest(requestId) {
973
- this.topicToWebSocketClient[requestId].close();
974
- delete this.topicToWebSocketClient[requestId];
1211
+ if (this.topicToWebSocketClient[requestId]) {
1212
+ this.topicToWebSocketClient[requestId].close();
1213
+ delete this.topicToWebSocketClient[requestId];
1214
+ }
975
1215
  delete this.topicToKeyPair[requestId];
976
1216
  delete this.topicToConfig[requestId];
1217
+ delete this.topicToLocalConfig[requestId];
977
1218
  delete this.topicToSharedSecret[requestId];
978
1219
  delete this.topicToProofs[requestId];
979
1220
  delete this.topicToExpectedProofCount[requestId];
1221
+ delete this.topicToFailedProofCount[requestId];
980
1222
  delete this.topicToResults[requestId];
981
1223
  this.onRequestReceivedCallbacks[requestId] = [];
982
1224
  this.onGeneratingProofCallbacks[requestId] = [];
@@ -985,5 +1227,13 @@ class ZKPassport {
985
1227
  this.onRejectCallbacks[requestId] = [];
986
1228
  this.onErrorCallbacks[requestId] = [];
987
1229
  }
1230
+ /**
1231
+ * @notice Clears all requests.
1232
+ */
1233
+ clearAllRequests() {
1234
+ for (const requestId in this.topicToWebSocketClient) {
1235
+ this.cancelRequest(requestId);
1236
+ }
1237
+ }
988
1238
  }
989
1239
  exports.ZKPassport = ZKPassport;