@zkpassport/sdk 0.2.6 → 0.2.8

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/README.md CHANGED
@@ -4,7 +4,7 @@ Privacy-preserving identity verification using passports and ID cards.
4
4
 
5
5
  _⚠️ Warning ⚠️_
6
6
 
7
- _This version of the SDK is only compatible with the version 0.5 and above of ZKPassport mobile app._
7
+ _This is experimental software that has not been audited yet. Use at your own risk._
8
8
 
9
9
  ## Installation
10
10
 
@@ -128,6 +128,7 @@ export type QueryBuilder = {
128
128
  export declare class ZKPassport {
129
129
  private domain;
130
130
  private topicToConfig;
131
+ private topicToLocalConfig;
131
132
  private topicToKeyPair;
132
133
  private topicToWebSocketClient;
133
134
  private topicToSharedSecret;
@@ -154,14 +155,20 @@ export declare class ZKPassport {
154
155
  private handleEncryptedMessage;
155
156
  private getZkPassportRequest;
156
157
  /**
157
- * @notice Create a new request.
158
+ * @notice Create a new request
159
+ * @param name Your service name
160
+ * @param logo The logo of your service
161
+ * @param purpose To explain what you want to do with the user's data
162
+ * @param scope Scope this request to a specific use case
163
+ * @param validity How many days ago should have the ID been last scanned by the user?
158
164
  * @returns The query builder object.
159
165
  */
160
- request({ name, logo, purpose, scope, topicOverride, keyPairOverride, }: {
166
+ request({ name, logo, purpose, scope, validity, topicOverride, keyPairOverride, }: {
161
167
  name: string;
162
168
  logo: string;
163
169
  purpose: string;
164
170
  scope?: string;
171
+ validity?: number;
165
172
  topicOverride?: string;
166
173
  keyPairOverride?: {
167
174
  privateKey: Uint8Array;
package/dist/cjs/index.js CHANGED
@@ -10,7 +10,7 @@ const websocket_1 = require("./websocket");
10
10
  const json_rpc_1 = require("./json-rpc");
11
11
  const encryption_1 = require("./encryption");
12
12
  const logger_1 = require("./logger");
13
- const node_gzip_1 = require("node-gzip");
13
+ const pako_1 = require("pako");
14
14
  //import initNoirC from '@noir-lang/noirc_abi'
15
15
  //import initACVM from '@noir-lang/acvm_js'
16
16
  const en_json_1 = tslib_1.__importDefault(require("i18n-iso-countries/langs/en.json"));
@@ -18,6 +18,9 @@ const buffer_1 = require("buffer/");
18
18
  // If Buffer is not defined, then we use the Buffer from the buffer package
19
19
  if (typeof globalThis.Buffer === "undefined") {
20
20
  globalThis.Buffer = buffer_1.Buffer;
21
+ if (typeof window !== "undefined") {
22
+ window.Buffer = buffer_1.Buffer;
23
+ }
21
24
  }
22
25
  (0, i18n_iso_countries_1.registerLocale)(en_json_1.default);
23
26
  function hasRequestedAccessToField(credentialsRequest, field) {
@@ -69,6 +72,7 @@ class ZKPassport {
69
72
  //private wasmVerifierInit: boolean = false
70
73
  constructor(_domain) {
71
74
  this.topicToConfig = {};
75
+ this.topicToLocalConfig = {};
72
76
  this.topicToKeyPair = {};
73
77
  this.topicToWebSocketClient = {};
74
78
  this.topicToSharedSecret = {};
@@ -178,7 +182,7 @@ class ZKPassport {
178
182
  logger_1.noLogger.debug(`User generated proof`);
179
183
  // Uncompress the proof and convert it to a hex string
180
184
  const bytesProof = buffer_1.Buffer.from(request.params.proof, "base64");
181
- const uncompressedProof = await (0, node_gzip_1.ungzip)(bytesProof);
185
+ const uncompressedProof = (0, pako_1.inflate)(bytesProof);
182
186
  // The gzip lib in the app compress the proof as ASCII
183
187
  // and since the app passes the proof as a hex string, we can
184
188
  // just decode the bytes as hex characters using the TextDecoder
@@ -302,10 +306,15 @@ class ZKPassport {
302
306
  };
303
307
  }
304
308
  /**
305
- * @notice Create a new request.
309
+ * @notice Create a new request
310
+ * @param name Your service name
311
+ * @param logo The logo of your service
312
+ * @param purpose To explain what you want to do with the user's data
313
+ * @param scope Scope this request to a specific use case
314
+ * @param validity How many days ago should have the ID been last scanned by the user?
306
315
  * @returns The query builder object.
307
316
  */
308
- async request({ name, logo, purpose, scope, topicOverride, keyPairOverride, }) {
317
+ async request({ name, logo, purpose, scope, validity, topicOverride, keyPairOverride, }) {
309
318
  const topic = topicOverride || (0, crypto_1.randomBytes)(16).toString("hex");
310
319
  const keyPair = keyPairOverride || (await (0, encryption_1.generateECDHKeyPair)());
311
320
  this.topicToKeyPair[topic] = {
@@ -316,6 +325,10 @@ class ZKPassport {
316
325
  this.topicToService[topic] = { name, logo, purpose, scope };
317
326
  this.topicToProofs[topic] = [];
318
327
  this.topicToExpectedProofCount[topic] = 0;
328
+ this.topicToLocalConfig[topic] = {
329
+ // Default to 6 months
330
+ validity: validity || 6 * 30,
331
+ };
319
332
  this.onRequestReceivedCallbacks[topic] = [];
320
333
  this.onGeneratingProofCallbacks[topic] = [];
321
334
  this.onBridgeConnectCallbacks[topic] = [];
@@ -372,7 +385,7 @@ class ZKPassport {
372
385
  };
373
386
  return this.getZkPassportRequest(topic);
374
387
  }
375
- async checkPublicInputs(proofs, queryResult) {
388
+ async checkPublicInputs(proofs, queryResult, topic) {
376
389
  let commitmentIn;
377
390
  let commitmentOut;
378
391
  let isCorrect = true;
@@ -430,11 +443,12 @@ class ZKPassport {
430
443
  }
431
444
  commitmentOut = (0, utils_1.getCommitmentOutFromIntegrityProof)(proofData);
432
445
  const currentDate = (0, utils_1.getCurrentDateFromIntegrityProof)(proofData);
433
- // The date should be today or yesterday
434
- // (if the proof request was requested just before midnight and is finalized after)
435
- if (currentDate.getTime() !== today.getTime() &&
436
- currentDate.getTime() !== today.getTime() - 86400000) {
437
- console.warn("Current date used to check the validity of the ID is too old");
446
+ const todayToCurrentDate = today.getTime() - currentDate.getTime();
447
+ const expectedDifference = this.topicToLocalConfig[topic]?.validity * 86400000;
448
+ const actualDifference = today.getTime() - (today.getTime() - expectedDifference);
449
+ // The ID should not expire within the next 6 months (or whatever the custom value is)
450
+ if (todayToCurrentDate >= actualDifference) {
451
+ 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`);
438
452
  isCorrect = false;
439
453
  break;
440
454
  }
@@ -924,7 +938,7 @@ class ZKPassport {
924
938
  let verified = true;
925
939
  let uniqueIdentifier;
926
940
  if (queryResult) {
927
- const { isCorrect, uniqueIdentifier: uniqueIdentifierFromPublicInputs } = await this.checkPublicInputs(proofsToVerify, queryResult);
941
+ const { isCorrect, uniqueIdentifier: uniqueIdentifierFromPublicInputs } = await this.checkPublicInputs(proofsToVerify, queryResult, requestId);
928
942
  uniqueIdentifier = uniqueIdentifierFromPublicInputs;
929
943
  verified = isCorrect;
930
944
  }
@@ -971,6 +985,7 @@ class ZKPassport {
971
985
  delete this.topicToWebSocketClient[requestId];
972
986
  delete this.topicToKeyPair[requestId];
973
987
  delete this.topicToConfig[requestId];
988
+ delete this.topicToLocalConfig[requestId];
974
989
  delete this.topicToSharedSecret[requestId];
975
990
  delete this.topicToProofs[requestId];
976
991
  delete this.topicToExpectedProofCount[requestId];
@@ -128,6 +128,7 @@ export type QueryBuilder = {
128
128
  export declare class ZKPassport {
129
129
  private domain;
130
130
  private topicToConfig;
131
+ private topicToLocalConfig;
131
132
  private topicToKeyPair;
132
133
  private topicToWebSocketClient;
133
134
  private topicToSharedSecret;
@@ -154,14 +155,20 @@ export declare class ZKPassport {
154
155
  private handleEncryptedMessage;
155
156
  private getZkPassportRequest;
156
157
  /**
157
- * @notice Create a new request.
158
+ * @notice Create a new request
159
+ * @param name Your service name
160
+ * @param logo The logo of your service
161
+ * @param purpose To explain what you want to do with the user's data
162
+ * @param scope Scope this request to a specific use case
163
+ * @param validity How many days ago should have the ID been last scanned by the user?
158
164
  * @returns The query builder object.
159
165
  */
160
- request({ name, logo, purpose, scope, topicOverride, keyPairOverride, }: {
166
+ request({ name, logo, purpose, scope, validity, topicOverride, keyPairOverride, }: {
161
167
  name: string;
162
168
  logo: string;
163
169
  purpose: string;
164
170
  scope?: string;
171
+ validity?: number;
165
172
  topicOverride?: string;
166
173
  keyPairOverride?: {
167
174
  privateKey: Uint8Array;
package/dist/esm/index.js CHANGED
@@ -6,7 +6,7 @@ import { getWebSocketClient } from "./websocket";
6
6
  import { createEncryptedJsonRpcRequest } from "./json-rpc";
7
7
  import { decrypt, generateECDHKeyPair, getSharedSecret } from "./encryption";
8
8
  import { noLogger as logger } from "./logger";
9
- import { ungzip } from "node-gzip";
9
+ import { inflate } from "pako";
10
10
  //import initNoirC from '@noir-lang/noirc_abi'
11
11
  //import initACVM from '@noir-lang/acvm_js'
12
12
  import i18en from "i18n-iso-countries/langs/en.json";
@@ -14,6 +14,9 @@ import { Buffer } from "buffer/";
14
14
  // If Buffer is not defined, then we use the Buffer from the buffer package
15
15
  if (typeof globalThis.Buffer === "undefined") {
16
16
  globalThis.Buffer = Buffer;
17
+ if (typeof window !== "undefined") {
18
+ window.Buffer = Buffer;
19
+ }
17
20
  }
18
21
  registerLocale(i18en);
19
22
  function hasRequestedAccessToField(credentialsRequest, field) {
@@ -59,6 +62,7 @@ export class ZKPassport {
59
62
  //private wasmVerifierInit: boolean = false
60
63
  constructor(_domain) {
61
64
  this.topicToConfig = {};
65
+ this.topicToLocalConfig = {};
62
66
  this.topicToKeyPair = {};
63
67
  this.topicToWebSocketClient = {};
64
68
  this.topicToSharedSecret = {};
@@ -168,7 +172,7 @@ export class ZKPassport {
168
172
  logger.debug(`User generated proof`);
169
173
  // Uncompress the proof and convert it to a hex string
170
174
  const bytesProof = Buffer.from(request.params.proof, "base64");
171
- const uncompressedProof = await ungzip(bytesProof);
175
+ const uncompressedProof = inflate(bytesProof);
172
176
  // The gzip lib in the app compress the proof as ASCII
173
177
  // and since the app passes the proof as a hex string, we can
174
178
  // just decode the bytes as hex characters using the TextDecoder
@@ -292,10 +296,15 @@ export class ZKPassport {
292
296
  };
293
297
  }
294
298
  /**
295
- * @notice Create a new request.
299
+ * @notice Create a new request
300
+ * @param name Your service name
301
+ * @param logo The logo of your service
302
+ * @param purpose To explain what you want to do with the user's data
303
+ * @param scope Scope this request to a specific use case
304
+ * @param validity How many days ago should have the ID been last scanned by the user?
296
305
  * @returns The query builder object.
297
306
  */
298
- async request({ name, logo, purpose, scope, topicOverride, keyPairOverride, }) {
307
+ async request({ name, logo, purpose, scope, validity, topicOverride, keyPairOverride, }) {
299
308
  const topic = topicOverride || randomBytes(16).toString("hex");
300
309
  const keyPair = keyPairOverride || (await generateECDHKeyPair());
301
310
  this.topicToKeyPair[topic] = {
@@ -306,6 +315,10 @@ export class ZKPassport {
306
315
  this.topicToService[topic] = { name, logo, purpose, scope };
307
316
  this.topicToProofs[topic] = [];
308
317
  this.topicToExpectedProofCount[topic] = 0;
318
+ this.topicToLocalConfig[topic] = {
319
+ // Default to 6 months
320
+ validity: validity || 6 * 30,
321
+ };
309
322
  this.onRequestReceivedCallbacks[topic] = [];
310
323
  this.onGeneratingProofCallbacks[topic] = [];
311
324
  this.onBridgeConnectCallbacks[topic] = [];
@@ -362,7 +375,7 @@ export class ZKPassport {
362
375
  };
363
376
  return this.getZkPassportRequest(topic);
364
377
  }
365
- async checkPublicInputs(proofs, queryResult) {
378
+ async checkPublicInputs(proofs, queryResult, topic) {
366
379
  let commitmentIn;
367
380
  let commitmentOut;
368
381
  let isCorrect = true;
@@ -420,11 +433,12 @@ export class ZKPassport {
420
433
  }
421
434
  commitmentOut = getCommitmentOutFromIntegrityProof(proofData);
422
435
  const currentDate = getCurrentDateFromIntegrityProof(proofData);
423
- // The date should be today or yesterday
424
- // (if the proof request was requested just before midnight and is finalized after)
425
- if (currentDate.getTime() !== today.getTime() &&
426
- currentDate.getTime() !== today.getTime() - 86400000) {
427
- console.warn("Current date used to check the validity of the ID is too old");
436
+ const todayToCurrentDate = today.getTime() - currentDate.getTime();
437
+ const expectedDifference = this.topicToLocalConfig[topic]?.validity * 86400000;
438
+ const actualDifference = today.getTime() - (today.getTime() - expectedDifference);
439
+ // The ID should not expire within the next 6 months (or whatever the custom value is)
440
+ if (todayToCurrentDate >= actualDifference) {
441
+ 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`);
428
442
  isCorrect = false;
429
443
  break;
430
444
  }
@@ -914,7 +928,7 @@ export class ZKPassport {
914
928
  let verified = true;
915
929
  let uniqueIdentifier;
916
930
  if (queryResult) {
917
- const { isCorrect, uniqueIdentifier: uniqueIdentifierFromPublicInputs } = await this.checkPublicInputs(proofsToVerify, queryResult);
931
+ const { isCorrect, uniqueIdentifier: uniqueIdentifierFromPublicInputs } = await this.checkPublicInputs(proofsToVerify, queryResult, requestId);
918
932
  uniqueIdentifier = uniqueIdentifierFromPublicInputs;
919
933
  verified = isCorrect;
920
934
  }
@@ -961,6 +975,7 @@ export class ZKPassport {
961
975
  delete this.topicToWebSocketClient[requestId];
962
976
  delete this.topicToKeyPair[requestId];
963
977
  delete this.topicToConfig[requestId];
978
+ delete this.topicToLocalConfig[requestId];
964
979
  delete this.topicToSharedSecret[requestId];
965
980
  delete this.topicToProofs[requestId];
966
981
  delete this.topicToExpectedProofCount[requestId];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zkpassport/sdk",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "Privacy-preserving identity verification using passports and ID cards",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "module": "./dist/esm/index.js",
@@ -31,7 +31,7 @@
31
31
  "@jest/globals": "^29.7.0",
32
32
  "@types/jest": "^29.5.14",
33
33
  "@types/node": "^22.10.9",
34
- "@types/node-gzip": "^1.1.3",
34
+ "@types/pako": "^2.0.3",
35
35
  "@types/ws": "^8.5.12",
36
36
  "jest": "^29.7.0",
37
37
  "ts-node": "^10.9.2",
@@ -44,7 +44,7 @@
44
44
  "@zkpassport/utils": "^0.2.16",
45
45
  "buffer": "^6.0.3",
46
46
  "i18n-iso-countries": "^7.12.0",
47
- "node-gzip": "^1.1.2",
47
+ "pako": "^2.1.0",
48
48
  "ws": "^8.18.0"
49
49
  },
50
50
  "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
package/src/index.ts CHANGED
@@ -37,7 +37,7 @@ import { getWebSocketClient, WebSocketClient } from "./websocket"
37
37
  import { createEncryptedJsonRpcRequest } from "./json-rpc"
38
38
  import { decrypt, generateECDHKeyPair, getSharedSecret } from "./encryption"
39
39
  import { noLogger as logger } from "./logger"
40
- import { ungzip } from "node-gzip"
40
+ import { inflate } from "pako"
41
41
  //import initNoirC from '@noir-lang/noirc_abi'
42
42
  //import initACVM from '@noir-lang/acvm_js'
43
43
  import i18en from "i18n-iso-countries/langs/en.json"
@@ -46,6 +46,9 @@ import { Buffer } from "buffer/"
46
46
  // If Buffer is not defined, then we use the Buffer from the buffer package
47
47
  if (typeof globalThis.Buffer === "undefined") {
48
48
  globalThis.Buffer = Buffer as any
49
+ if (typeof window !== "undefined") {
50
+ window.Buffer = Buffer as any
51
+ }
49
52
  }
50
53
 
51
54
  registerLocale(i18en)
@@ -257,6 +260,12 @@ export type QueryBuilder = {
257
260
  export class ZKPassport {
258
261
  private domain: string
259
262
  private topicToConfig: Record<string, Record<string, IDCredentialConfig>> = {}
263
+ private topicToLocalConfig: Record<
264
+ string,
265
+ {
266
+ validity: number
267
+ }
268
+ > = {}
260
269
  private topicToKeyPair: Record<string, { privateKey: Uint8Array; publicKey: Uint8Array }> = {}
261
270
  private topicToWebSocketClient: Record<string, WebSocketClient> = {}
262
271
  private topicToSharedSecret: Record<string, Uint8Array> = {}
@@ -395,7 +404,7 @@ export class ZKPassport {
395
404
  logger.debug(`User generated proof`)
396
405
  // Uncompress the proof and convert it to a hex string
397
406
  const bytesProof = Buffer.from(request.params.proof, "base64")
398
- const uncompressedProof = await ungzip(bytesProof)
407
+ const uncompressedProof = inflate(bytesProof)
399
408
  // The gzip lib in the app compress the proof as ASCII
400
409
  // and since the app passes the proof as a hex string, we can
401
410
  // just decode the bytes as hex characters using the TextDecoder
@@ -543,7 +552,12 @@ export class ZKPassport {
543
552
  }
544
553
 
545
554
  /**
546
- * @notice Create a new request.
555
+ * @notice Create a new request
556
+ * @param name Your service name
557
+ * @param logo The logo of your service
558
+ * @param purpose To explain what you want to do with the user's data
559
+ * @param scope Scope this request to a specific use case
560
+ * @param validity How many days ago should have the ID been last scanned by the user?
547
561
  * @returns The query builder object.
548
562
  */
549
563
  public async request({
@@ -551,6 +565,7 @@ export class ZKPassport {
551
565
  logo,
552
566
  purpose,
553
567
  scope,
568
+ validity,
554
569
  topicOverride,
555
570
  keyPairOverride,
556
571
  }: {
@@ -558,6 +573,7 @@ export class ZKPassport {
558
573
  logo: string
559
574
  purpose: string
560
575
  scope?: string
576
+ validity?: number
561
577
  topicOverride?: string
562
578
  keyPairOverride?: { privateKey: Uint8Array; publicKey: Uint8Array }
563
579
  }): Promise<QueryBuilder> {
@@ -573,6 +589,10 @@ export class ZKPassport {
573
589
  this.topicToService[topic] = { name, logo, purpose, scope }
574
590
  this.topicToProofs[topic] = []
575
591
  this.topicToExpectedProofCount[topic] = 0
592
+ this.topicToLocalConfig[topic] = {
593
+ // Default to 6 months
594
+ validity: validity || 6 * 30,
595
+ }
576
596
 
577
597
  this.onRequestReceivedCallbacks[topic] = []
578
598
  this.onGeneratingProofCallbacks[topic] = []
@@ -647,7 +667,11 @@ export class ZKPassport {
647
667
  return this.getZkPassportRequest(topic)
648
668
  }
649
669
 
650
- private async checkPublicInputs(proofs: Array<ProofResult>, queryResult: QueryResult) {
670
+ private async checkPublicInputs(
671
+ proofs: Array<ProofResult>,
672
+ queryResult: QueryResult,
673
+ topic: string,
674
+ ) {
651
675
  let commitmentIn: bigint | undefined
652
676
  let commitmentOut: bigint | undefined
653
677
  let isCorrect = true
@@ -717,13 +741,14 @@ export class ZKPassport {
717
741
  }
718
742
  commitmentOut = getCommitmentOutFromIntegrityProof(proofData)
719
743
  const currentDate = getCurrentDateFromIntegrityProof(proofData)
720
- // The date should be today or yesterday
721
- // (if the proof request was requested just before midnight and is finalized after)
722
- if (
723
- currentDate.getTime() !== today.getTime() &&
724
- currentDate.getTime() !== today.getTime() - 86400000
725
- ) {
726
- console.warn("Current date used to check the validity of the ID is too old")
744
+ const todayToCurrentDate = today.getTime() - currentDate.getTime()
745
+ const expectedDifference = this.topicToLocalConfig[topic]?.validity * 86400000
746
+ const actualDifference = today.getTime() - (today.getTime() - expectedDifference)
747
+ // The ID should not expire within the next 6 months (or whatever the custom value is)
748
+ if (todayToCurrentDate >= actualDifference) {
749
+ console.warn(
750
+ `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`,
751
+ )
727
752
  isCorrect = false
728
753
  break
729
754
  }
@@ -1306,7 +1331,7 @@ export class ZKPassport {
1306
1331
  let uniqueIdentifier: string | undefined
1307
1332
  if (queryResult) {
1308
1333
  const { isCorrect, uniqueIdentifier: uniqueIdentifierFromPublicInputs } =
1309
- await this.checkPublicInputs(proofsToVerify!, queryResult!)
1334
+ await this.checkPublicInputs(proofsToVerify!, queryResult!, requestId)
1310
1335
  uniqueIdentifier = uniqueIdentifierFromPublicInputs
1311
1336
  verified = isCorrect
1312
1337
  }
@@ -1361,6 +1386,7 @@ export class ZKPassport {
1361
1386
  delete this.topicToWebSocketClient[requestId]
1362
1387
  delete this.topicToKeyPair[requestId]
1363
1388
  delete this.topicToConfig[requestId]
1389
+ delete this.topicToLocalConfig[requestId]
1364
1390
  delete this.topicToSharedSecret[requestId]
1365
1391
  delete this.topicToProofs[requestId]
1366
1392
  delete this.topicToExpectedProofCount[requestId]