@zkpassport/sdk 0.1.2 → 0.2.1
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 +80 -25
- package/dist/{encryption.d.ts → cjs/encryption.d.ts} +4 -4
- package/dist/cjs/encryption.js +79 -0
- package/dist/cjs/index.d.ts +191 -0
- package/dist/cjs/index.js +857 -0
- package/dist/{json-rpc.d.ts → cjs/json-rpc.d.ts} +1 -1
- package/dist/cjs/json-rpc.js +48 -0
- package/dist/{logger.js → cjs/logger.js} +5 -38
- package/dist/cjs/mobile.js +131 -0
- package/dist/{websocket.js → cjs/websocket.js} +2 -2
- package/dist/esm/encryption.d.ts +7 -0
- package/dist/esm/encryption.js +40 -0
- package/dist/esm/index.d.ts +191 -0
- package/dist/esm/index.js +846 -0
- package/dist/esm/json-rpc.d.ts +6 -0
- package/dist/esm/json-rpc.js +41 -0
- package/dist/esm/logger.d.ts +7 -0
- package/dist/esm/logger.js +37 -0
- package/dist/esm/mobile.d.ts +39 -0
- package/dist/esm/mobile.js +126 -0
- package/dist/esm/websocket.d.ts +2 -0
- package/dist/esm/websocket.js +15 -0
- package/package.json +16 -8
- package/src/index.ts +974 -63
- package/src/json-rpc.ts +6 -2
- package/src/mobile.ts +14 -5
- package/tsconfig.json +14 -9
- package/dist/constants/index.d.ts +0 -13
- package/dist/constants/index.js +0 -52
- package/dist/encryption.js +0 -126
- package/dist/index.d.ts +0 -79
- package/dist/index.js +0 -384
- package/dist/json-rpc.js +0 -105
- package/dist/mobile.js +0 -253
- package/dist/types/countries.d.ts +0 -1
- package/dist/types/countries.js +0 -2
- package/dist/types/credentials.d.ts +0 -17
- package/dist/types/credentials.js +0 -2
- package/dist/types/index.d.ts +0 -4
- package/dist/types/index.js +0 -2
- package/dist/types/json-rpc.d.ts +0 -12
- package/dist/types/json-rpc.js +0 -2
- package/dist/types/query-result.d.ts +0 -46
- package/dist/types/query-result.js +0 -2
- package/src/circuits/proof_age.json +0 -1
- package/src/constants/index.ts +0 -54
- package/src/types/countries.ts +0 -278
- package/src/types/credentials.ts +0 -40
- package/src/types/index.ts +0 -13
- package/src/types/json-rpc.ts +0 -13
- package/src/types/query-result.ts +0 -49
- /package/dist/{logger.d.ts → cjs/logger.d.ts} +0 -0
- /package/dist/{mobile.d.ts → cjs/mobile.d.ts} +0 -0
- /package/dist/{websocket.d.ts → cjs/websocket.d.ts} +0 -0
|
@@ -0,0 +1,857 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ZKPassport = exports.MERCOSUR_COUNTRIES = exports.ASEAN_COUNTRIES = exports.SCHENGEN_COUNTRIES = exports.EEA_COUNTRIES = exports.EU_COUNTRIES = exports.SANCTIONED_COUNTRIES = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const crypto_1 = require("crypto");
|
|
6
|
+
const i18n_iso_countries_1 = require("i18n-iso-countries");
|
|
7
|
+
const utils_1 = require("@zkpassport/utils");
|
|
8
|
+
const utils_2 = require("@noble/ciphers/utils");
|
|
9
|
+
const websocket_1 = require("./websocket");
|
|
10
|
+
const json_rpc_1 = require("./json-rpc");
|
|
11
|
+
const encryption_1 = require("./encryption");
|
|
12
|
+
const logger_1 = tslib_1.__importDefault(require("./logger"));
|
|
13
|
+
const node_gzip_1 = require("node-gzip");
|
|
14
|
+
//import initNoirC from '@noir-lang/noirc_abi'
|
|
15
|
+
//import initACVM from '@noir-lang/acvm_js'
|
|
16
|
+
(0, i18n_iso_countries_1.registerLocale)(require('i18n-iso-countries/langs/en.json'));
|
|
17
|
+
function normalizeCountry(country) {
|
|
18
|
+
let normalizedCountry;
|
|
19
|
+
const alpha3 = (0, i18n_iso_countries_1.getAlpha3Code)(country, 'en');
|
|
20
|
+
normalizedCountry = alpha3 || country;
|
|
21
|
+
return normalizedCountry;
|
|
22
|
+
}
|
|
23
|
+
function numericalCompare(fnName, key, value, requestId, requestIdToConfig) {
|
|
24
|
+
requestIdToConfig[requestId][key] = {
|
|
25
|
+
...requestIdToConfig[requestId][key],
|
|
26
|
+
[fnName]: value,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function rangeCompare(key, value, requestId, requestIdToConfig) {
|
|
30
|
+
requestIdToConfig[requestId][key] = {
|
|
31
|
+
...requestIdToConfig[requestId][key],
|
|
32
|
+
range: value,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function generalCompare(fnName, key, value, requestId, requestIdToConfig) {
|
|
36
|
+
requestIdToConfig[requestId][key] = {
|
|
37
|
+
...requestIdToConfig[requestId][key],
|
|
38
|
+
[fnName]: value,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
var utils_3 = require("@zkpassport/utils");
|
|
42
|
+
Object.defineProperty(exports, "SANCTIONED_COUNTRIES", { enumerable: true, get: function () { return utils_3.SANCTIONED_COUNTRIES; } });
|
|
43
|
+
Object.defineProperty(exports, "EU_COUNTRIES", { enumerable: true, get: function () { return utils_3.EU_COUNTRIES; } });
|
|
44
|
+
Object.defineProperty(exports, "EEA_COUNTRIES", { enumerable: true, get: function () { return utils_3.EEA_COUNTRIES; } });
|
|
45
|
+
Object.defineProperty(exports, "SCHENGEN_COUNTRIES", { enumerable: true, get: function () { return utils_3.SCHENGEN_COUNTRIES; } });
|
|
46
|
+
Object.defineProperty(exports, "ASEAN_COUNTRIES", { enumerable: true, get: function () { return utils_3.ASEAN_COUNTRIES; } });
|
|
47
|
+
Object.defineProperty(exports, "MERCOSUR_COUNTRIES", { enumerable: true, get: function () { return utils_3.MERCOSUR_COUNTRIES; } });
|
|
48
|
+
class ZKPassport {
|
|
49
|
+
//private wasmVerifierInit: boolean = false
|
|
50
|
+
constructor(_domain) {
|
|
51
|
+
this.topicToConfig = {};
|
|
52
|
+
this.topicToKeyPair = {};
|
|
53
|
+
this.topicToWebSocketClient = {};
|
|
54
|
+
this.topicToSharedSecret = {};
|
|
55
|
+
this.topicToRequestReceived = {};
|
|
56
|
+
this.topicToService = {};
|
|
57
|
+
this.topicToProofs = {};
|
|
58
|
+
this.onRequestReceivedCallbacks = {};
|
|
59
|
+
this.onGeneratingProofCallbacks = {};
|
|
60
|
+
this.onBridgeConnectCallbacks = {};
|
|
61
|
+
this.onProofGeneratedCallbacks = {};
|
|
62
|
+
this.onResultCallbacks = {};
|
|
63
|
+
this.onRejectCallbacks = {};
|
|
64
|
+
this.onErrorCallbacks = {};
|
|
65
|
+
if (!_domain && typeof window === 'undefined') {
|
|
66
|
+
throw new Error('Domain argument is required in Node.js environment');
|
|
67
|
+
}
|
|
68
|
+
this.domain = _domain || window.location.hostname;
|
|
69
|
+
}
|
|
70
|
+
/*private async initWasmVerifier() {
|
|
71
|
+
const acvm = await import('@noir-lang/acvm_js/web/acvm_js_bg.wasm')
|
|
72
|
+
const noirc = await import('@noir-lang/noirc_abi/web/noirc_abi_wasm_bg.wasm')
|
|
73
|
+
await Promise.all([initACVM(acvm), initNoirC(noirc)])
|
|
74
|
+
this.wasmVerifierInit = true
|
|
75
|
+
}*/
|
|
76
|
+
/**
|
|
77
|
+
* @notice Handle an encrypted message.
|
|
78
|
+
* @param request The request.
|
|
79
|
+
* @param outerRequest The outer request.
|
|
80
|
+
*/
|
|
81
|
+
async handleEncryptedMessage(topic, request, outerRequest) {
|
|
82
|
+
logger_1.default.debug('Received encrypted message:', request);
|
|
83
|
+
if (request.method === 'accept') {
|
|
84
|
+
logger_1.default.debug(`User accepted the request and is generating a proof`);
|
|
85
|
+
await Promise.all(this.onGeneratingProofCallbacks[topic].map((callback) => callback(topic)));
|
|
86
|
+
}
|
|
87
|
+
else if (request.method === 'reject') {
|
|
88
|
+
logger_1.default.debug(`User rejected the request`);
|
|
89
|
+
await Promise.all(this.onRejectCallbacks[topic].map((callback) => callback()));
|
|
90
|
+
}
|
|
91
|
+
else if (request.method === 'proof') {
|
|
92
|
+
logger_1.default.debug(`User generated proof`);
|
|
93
|
+
// Uncompress the proof and convert it to a hex string
|
|
94
|
+
const bytesProof = Buffer.from(request.params.proof, 'base64');
|
|
95
|
+
const uncompressedProof = await (0, node_gzip_1.ungzip)(bytesProof);
|
|
96
|
+
// The gzip lib in the app compress the proof as ASCII
|
|
97
|
+
// and since the app passes the proof as a hex string, we can
|
|
98
|
+
// just decode the bytes as hex characters using the TextDecoder
|
|
99
|
+
const hexProof = new TextDecoder().decode(uncompressedProof);
|
|
100
|
+
const processedProof = {
|
|
101
|
+
proof: hexProof,
|
|
102
|
+
vkeyHash: request.params.vkeyHash,
|
|
103
|
+
name: request.params.name,
|
|
104
|
+
version: request.params.version,
|
|
105
|
+
};
|
|
106
|
+
this.topicToProofs[topic].push(processedProof);
|
|
107
|
+
await Promise.all(this.onProofGeneratedCallbacks[topic].map((callback) => callback(processedProof)));
|
|
108
|
+
}
|
|
109
|
+
else if (request.method === 'done') {
|
|
110
|
+
logger_1.default.debug(`User sent the query result`);
|
|
111
|
+
// Verify the proofs and extract the unique identifier (aka nullifier) and the verification result
|
|
112
|
+
const { uniqueIdentifier, verified } = await this.verify(topic, this.topicToProofs[topic], request.params);
|
|
113
|
+
await Promise.all(this.onResultCallbacks[topic].map((callback) => callback({
|
|
114
|
+
uniqueIdentifier,
|
|
115
|
+
verified,
|
|
116
|
+
result: request.params,
|
|
117
|
+
})));
|
|
118
|
+
}
|
|
119
|
+
else if (request.method === 'error') {
|
|
120
|
+
await Promise.all(this.onErrorCallbacks[topic].map((callback) => callback(request.params.error)));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
getZkPassportRequest(topic) {
|
|
124
|
+
return {
|
|
125
|
+
eq: (key, value) => {
|
|
126
|
+
if (key === 'issuing_country' || key === 'nationality') {
|
|
127
|
+
value = normalizeCountry(value);
|
|
128
|
+
}
|
|
129
|
+
generalCompare('eq', key, value, topic, this.topicToConfig);
|
|
130
|
+
return this.getZkPassportRequest(topic);
|
|
131
|
+
},
|
|
132
|
+
gte: (key, value) => {
|
|
133
|
+
numericalCompare('gte', key, value, topic, this.topicToConfig);
|
|
134
|
+
return this.getZkPassportRequest(topic);
|
|
135
|
+
},
|
|
136
|
+
/*gt: <T extends NumericalIDCredential>(key: T, value: IDCredentialValue<T>) => {
|
|
137
|
+
numericalCompare('gt', key, value, topic, this.topicToConfig)
|
|
138
|
+
return this.getZkPassportRequest(topic)
|
|
139
|
+
},*/
|
|
140
|
+
lte: (key, value) => {
|
|
141
|
+
numericalCompare('lte', key, value, topic, this.topicToConfig);
|
|
142
|
+
return this.getZkPassportRequest(topic);
|
|
143
|
+
},
|
|
144
|
+
lt: (key, value) => {
|
|
145
|
+
numericalCompare('lt', key, value, topic, this.topicToConfig);
|
|
146
|
+
return this.getZkPassportRequest(topic);
|
|
147
|
+
},
|
|
148
|
+
range: (key, start, end) => {
|
|
149
|
+
rangeCompare(key, [start, end], topic, this.topicToConfig);
|
|
150
|
+
return this.getZkPassportRequest(topic);
|
|
151
|
+
},
|
|
152
|
+
in: (key, value) => {
|
|
153
|
+
value = value.map((v) => normalizeCountry(v));
|
|
154
|
+
generalCompare('in', key, value, topic, this.topicToConfig);
|
|
155
|
+
return this.getZkPassportRequest(topic);
|
|
156
|
+
},
|
|
157
|
+
out: (key, value) => {
|
|
158
|
+
value = value.map((v) => normalizeCountry(v));
|
|
159
|
+
generalCompare('out', key, value, topic, this.topicToConfig);
|
|
160
|
+
return this.getZkPassportRequest(topic);
|
|
161
|
+
},
|
|
162
|
+
disclose: (key) => {
|
|
163
|
+
this.topicToConfig[topic][key] = {
|
|
164
|
+
...this.topicToConfig[topic][key],
|
|
165
|
+
disclose: true,
|
|
166
|
+
};
|
|
167
|
+
return this.getZkPassportRequest(topic);
|
|
168
|
+
},
|
|
169
|
+
/*checkAML: (country?: CountryName | Alpha2Code | Alpha3Code) => {
|
|
170
|
+
return this.getZkPassportRequest(topic)
|
|
171
|
+
},*/
|
|
172
|
+
done: () => {
|
|
173
|
+
const base64Config = Buffer.from(JSON.stringify(this.topicToConfig[topic])).toString('base64');
|
|
174
|
+
const base64Service = Buffer.from(JSON.stringify(this.topicToService[topic])).toString('base64');
|
|
175
|
+
const pubkey = (0, utils_2.bytesToHex)(this.topicToKeyPair[topic].publicKey);
|
|
176
|
+
return {
|
|
177
|
+
url: `https://zkpassport.id/r?d=${this.domain}&t=${topic}&c=${base64Config}&s=${base64Service}&p=${pubkey}`,
|
|
178
|
+
requestId: topic,
|
|
179
|
+
onRequestReceived: (callback) => this.onRequestReceivedCallbacks[topic].push(callback),
|
|
180
|
+
onGeneratingProof: (callback) => this.onGeneratingProofCallbacks[topic].push(callback),
|
|
181
|
+
onBridgeConnect: (callback) => this.onBridgeConnectCallbacks[topic].push(callback),
|
|
182
|
+
onProofGenerated: (callback) => this.onProofGeneratedCallbacks[topic].push(callback),
|
|
183
|
+
onResult: (callback) => this.onResultCallbacks[topic].push(callback),
|
|
184
|
+
onReject: (callback) => this.onRejectCallbacks[topic].push(callback),
|
|
185
|
+
onError: (callback) => this.onErrorCallbacks[topic].push(callback),
|
|
186
|
+
isBridgeConnected: () => this.topicToWebSocketClient[topic].readyState === WebSocket.OPEN,
|
|
187
|
+
requestReceived: () => this.topicToRequestReceived[topic] === true,
|
|
188
|
+
};
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* @notice Create a new request.
|
|
194
|
+
* @returns The query builder object.
|
|
195
|
+
*/
|
|
196
|
+
async request({ name, logo, purpose, scope, topicOverride, keyPairOverride, }) {
|
|
197
|
+
const topic = topicOverride || (0, crypto_1.randomBytes)(16).toString('hex');
|
|
198
|
+
const keyPair = keyPairOverride || (await (0, encryption_1.generateECDHKeyPair)());
|
|
199
|
+
this.topicToKeyPair[topic] = {
|
|
200
|
+
privateKey: keyPair.privateKey,
|
|
201
|
+
publicKey: keyPair.publicKey,
|
|
202
|
+
};
|
|
203
|
+
this.topicToConfig[topic] = {};
|
|
204
|
+
this.topicToService[topic] = { name, logo, purpose, scope };
|
|
205
|
+
this.topicToProofs[topic] = [];
|
|
206
|
+
this.onRequestReceivedCallbacks[topic] = [];
|
|
207
|
+
this.onGeneratingProofCallbacks[topic] = [];
|
|
208
|
+
this.onBridgeConnectCallbacks[topic] = [];
|
|
209
|
+
this.onProofGeneratedCallbacks[topic] = [];
|
|
210
|
+
this.onResultCallbacks[topic] = [];
|
|
211
|
+
this.onRejectCallbacks[topic] = [];
|
|
212
|
+
this.onErrorCallbacks[topic] = [];
|
|
213
|
+
const wsClient = (0, websocket_1.getWebSocketClient)(`wss://bridge.zkpassport.id?topic=${topic}`, this.domain);
|
|
214
|
+
this.topicToWebSocketClient[topic] = wsClient;
|
|
215
|
+
wsClient.onopen = async () => {
|
|
216
|
+
logger_1.default.info('[frontend] WebSocket connection established');
|
|
217
|
+
await Promise.all(this.onBridgeConnectCallbacks[topic].map((callback) => callback()));
|
|
218
|
+
};
|
|
219
|
+
wsClient.addEventListener('message', async (event) => {
|
|
220
|
+
logger_1.default.debug('[frontend] Received message:', event.data);
|
|
221
|
+
try {
|
|
222
|
+
const data = JSON.parse(event.data);
|
|
223
|
+
// Handshake happens when the mobile app scans the QR code and connects to the bridge
|
|
224
|
+
if (data.method === 'handshake') {
|
|
225
|
+
logger_1.default.debug('[frontend] Received handshake:', event.data);
|
|
226
|
+
this.topicToRequestReceived[topic] = true;
|
|
227
|
+
this.topicToSharedSecret[topic] = await (0, encryption_1.getSharedSecret)((0, utils_2.bytesToHex)(keyPair.privateKey), data.params.pubkey);
|
|
228
|
+
logger_1.default.debug('[frontend] Shared secret:', Buffer.from(this.topicToSharedSecret[topic]).toString('hex'));
|
|
229
|
+
const encryptedMessage = await (0, json_rpc_1.createEncryptedJsonRpcRequest)('hello', null, this.topicToSharedSecret[topic], topic);
|
|
230
|
+
logger_1.default.debug('[frontend] Sending encrypted message:', encryptedMessage);
|
|
231
|
+
wsClient.send(JSON.stringify(encryptedMessage));
|
|
232
|
+
await Promise.all(this.onRequestReceivedCallbacks[topic].map((callback) => callback()));
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
// Handle encrypted messages
|
|
236
|
+
if (data.method === 'encryptedMessage') {
|
|
237
|
+
// Decode the payload from base64 to Uint8Array
|
|
238
|
+
const payload = new Uint8Array(atob(data.params.payload)
|
|
239
|
+
.split('')
|
|
240
|
+
.map((c) => c.charCodeAt(0)));
|
|
241
|
+
try {
|
|
242
|
+
// Decrypt the payload using the shared secret
|
|
243
|
+
const decrypted = await (0, encryption_1.decrypt)(payload, this.topicToSharedSecret[topic], topic);
|
|
244
|
+
const decryptedJson = JSON.parse(decrypted);
|
|
245
|
+
this.handleEncryptedMessage(topic, decryptedJson, data);
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
logger_1.default.error('[frontend] Error decrypting message:', error);
|
|
249
|
+
}
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
logger_1.default.error('[frontend] Error:', error);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
wsClient.onerror = (error) => {
|
|
258
|
+
logger_1.default.error('[frontend] WebSocket error:', error);
|
|
259
|
+
};
|
|
260
|
+
return this.getZkPassportRequest(topic);
|
|
261
|
+
}
|
|
262
|
+
async checkPublicInputs(proofs, queryResult) {
|
|
263
|
+
let commitmentIn;
|
|
264
|
+
let commitmentOut;
|
|
265
|
+
let isCorrect = true;
|
|
266
|
+
let uniqueIdentifier;
|
|
267
|
+
const expectedMerkleRoot = BigInt('21301853597069384763054217328384418971999152625381818922211526730996340553696');
|
|
268
|
+
const defaultDateValue = new Date(1111, 10, 11);
|
|
269
|
+
const currentTime = new Date();
|
|
270
|
+
const today = new Date(currentTime.getFullYear(), currentTime.getMonth(), currentTime.getDate(), 0, 0, 0, 0);
|
|
271
|
+
// Since the order is important for the commitments, we need to sort the proofs
|
|
272
|
+
// by their expected order: root signature check -> ID signature check -> integrity check -> disclosure
|
|
273
|
+
const sortedProofs = proofs.sort((a, b) => {
|
|
274
|
+
const proofOrder = [
|
|
275
|
+
'sig_check_dsc',
|
|
276
|
+
'sig_check_id_data',
|
|
277
|
+
'data_check_integrity',
|
|
278
|
+
'disclose_bytes',
|
|
279
|
+
'compare_age',
|
|
280
|
+
'compare_birthdate',
|
|
281
|
+
'compare_expiry',
|
|
282
|
+
'exclusion_check_country',
|
|
283
|
+
'inclusion_check_country',
|
|
284
|
+
];
|
|
285
|
+
const getIndex = (proof) => {
|
|
286
|
+
const name = proof.name || '';
|
|
287
|
+
return proofOrder.findIndex((p) => name.startsWith(p));
|
|
288
|
+
};
|
|
289
|
+
return getIndex(a) - getIndex(b);
|
|
290
|
+
});
|
|
291
|
+
for (const proof of sortedProofs) {
|
|
292
|
+
const proofData = (0, utils_1.getProofData)(proof.proof, true);
|
|
293
|
+
if (proof.name?.startsWith('sig_check_dsc')) {
|
|
294
|
+
commitmentOut = (0, utils_1.getCommitmentFromDSCProof)(proofData);
|
|
295
|
+
const merkleRoot = (0, utils_1.getMerkleRootFromDSCProof)(proofData);
|
|
296
|
+
if (merkleRoot !== expectedMerkleRoot) {
|
|
297
|
+
console.warn('The ID was signed by an unrecognized root certificate');
|
|
298
|
+
isCorrect = false;
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
else if (proof.name?.startsWith('sig_check_id_data')) {
|
|
303
|
+
commitmentIn = (0, utils_1.getCommitmentInFromIDDataProof)(proofData);
|
|
304
|
+
if (commitmentIn !== commitmentOut) {
|
|
305
|
+
console.warn('Failed to check the link between the certificate signature and ID signature');
|
|
306
|
+
isCorrect = false;
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
commitmentOut = (0, utils_1.getCommitmentOutFromIDDataProof)(proofData);
|
|
310
|
+
}
|
|
311
|
+
else if (proof.name?.startsWith('data_check_integrity')) {
|
|
312
|
+
commitmentIn = (0, utils_1.getCommitmentInFromIntegrityProof)(proofData);
|
|
313
|
+
if (commitmentIn !== commitmentOut) {
|
|
314
|
+
console.warn('Failed to check the link between the ID signature and the data signed');
|
|
315
|
+
isCorrect = false;
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
commitmentOut = (0, utils_1.getCommitmentOutFromIntegrityProof)(proofData);
|
|
319
|
+
const currentDate = (0, utils_1.getCurrentDateFromIntegrityProof)(proofData);
|
|
320
|
+
// The date should be today or yesterday
|
|
321
|
+
// (if the proof request was requested just before midnight and is finalized after)
|
|
322
|
+
if (currentDate.getTime() !== today.getTime() &&
|
|
323
|
+
currentDate.getTime() !== today.getTime() - 86400000) {
|
|
324
|
+
console.warn('Current date used to check the validity of the ID is too old');
|
|
325
|
+
isCorrect = false;
|
|
326
|
+
break;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
else if (proof.name === 'disclose_bytes') {
|
|
330
|
+
commitmentIn = (0, utils_1.getCommitmentInFromDisclosureProof)(proofData);
|
|
331
|
+
if (commitmentIn !== commitmentOut) {
|
|
332
|
+
console.warn('Failed to check the link between the validity of the ID and the data to disclose');
|
|
333
|
+
isCorrect = false;
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
// We can't be certain that the disclosed data is for a passport or an ID card
|
|
337
|
+
// so we need to check both (unless the document type is revealed)
|
|
338
|
+
const disclosedDataPassport = utils_1.DisclosedData.fromBytesProof(proofData, 'passport');
|
|
339
|
+
const disclosedDataIDCard = utils_1.DisclosedData.fromBytesProof(proofData, 'id_card');
|
|
340
|
+
if (queryResult.document_type) {
|
|
341
|
+
// Document type is always at the same index in the disclosed data
|
|
342
|
+
if (queryResult.document_type.eq &&
|
|
343
|
+
queryResult.document_type.eq.result &&
|
|
344
|
+
queryResult.document_type.eq.expected !== disclosedDataPassport.documentType) {
|
|
345
|
+
console.warn('Document type does not match the expected document type');
|
|
346
|
+
isCorrect = false;
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
if (queryResult.document_type.disclose?.result !== disclosedDataIDCard.documentType) {
|
|
350
|
+
console.warn('Document type does not match the disclosed document type in query result');
|
|
351
|
+
isCorrect = false;
|
|
352
|
+
break;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
if (queryResult.birthdate) {
|
|
356
|
+
const birthdatePassport = disclosedDataPassport.dateOfBirth;
|
|
357
|
+
const birthdateIDCard = disclosedDataIDCard.dateOfBirth;
|
|
358
|
+
if (queryResult.birthdate.eq &&
|
|
359
|
+
queryResult.birthdate.eq.result &&
|
|
360
|
+
queryResult.birthdate.eq.expected.getTime() !== birthdatePassport.getTime() &&
|
|
361
|
+
queryResult.birthdate.eq.expected.getTime() !== birthdateIDCard.getTime()) {
|
|
362
|
+
console.warn('Birthdate does not match the expected birthdate');
|
|
363
|
+
isCorrect = false;
|
|
364
|
+
break;
|
|
365
|
+
}
|
|
366
|
+
if (queryResult.birthdate.disclose &&
|
|
367
|
+
queryResult.birthdate.disclose.result.getTime() !== birthdatePassport.getTime() &&
|
|
368
|
+
queryResult.birthdate.disclose.result.getTime() !== birthdateIDCard.getTime()) {
|
|
369
|
+
console.warn('Birthdate does not match the disclosed birthdate in query result');
|
|
370
|
+
isCorrect = false;
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
if (queryResult.expiry_date) {
|
|
375
|
+
const expiryDatePassport = disclosedDataPassport.dateOfExpiry;
|
|
376
|
+
const expiryDateIDCard = disclosedDataIDCard.dateOfExpiry;
|
|
377
|
+
if (queryResult.expiry_date.eq &&
|
|
378
|
+
queryResult.expiry_date.eq.result &&
|
|
379
|
+
queryResult.expiry_date.eq.expected.getTime() !== expiryDatePassport.getTime() &&
|
|
380
|
+
queryResult.expiry_date.eq.expected.getTime() !== expiryDateIDCard.getTime()) {
|
|
381
|
+
console.warn('Expiry date does not match the expected expiry date');
|
|
382
|
+
isCorrect = false;
|
|
383
|
+
break;
|
|
384
|
+
}
|
|
385
|
+
if (queryResult.expiry_date.disclose &&
|
|
386
|
+
queryResult.expiry_date.disclose.result.getTime() !== expiryDatePassport.getTime() &&
|
|
387
|
+
queryResult.expiry_date.disclose.result.getTime() !== expiryDateIDCard.getTime()) {
|
|
388
|
+
console.warn('Expiry date does not match the disclosed expiry date in query result');
|
|
389
|
+
isCorrect = false;
|
|
390
|
+
break;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
if (queryResult.nationality) {
|
|
394
|
+
const nationalityPassport = disclosedDataPassport.nationality;
|
|
395
|
+
const nationalityIDCard = disclosedDataIDCard.nationality;
|
|
396
|
+
if (queryResult.nationality.eq &&
|
|
397
|
+
queryResult.nationality.eq.result &&
|
|
398
|
+
queryResult.nationality.eq.expected !== nationalityPassport &&
|
|
399
|
+
queryResult.nationality.eq.expected !== nationalityIDCard) {
|
|
400
|
+
console.warn('Nationality does not match the expected nationality');
|
|
401
|
+
isCorrect = false;
|
|
402
|
+
break;
|
|
403
|
+
}
|
|
404
|
+
if (queryResult.nationality.disclose &&
|
|
405
|
+
queryResult.nationality.disclose.result !== nationalityPassport &&
|
|
406
|
+
queryResult.nationality.disclose.result !== nationalityIDCard) {
|
|
407
|
+
console.warn('Nationality does not match the disclosed nationality in query result');
|
|
408
|
+
isCorrect = false;
|
|
409
|
+
break;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
if (queryResult.document_number) {
|
|
413
|
+
const documentNumberPassport = disclosedDataPassport.documentNumber;
|
|
414
|
+
const documentNumberIDCard = disclosedDataIDCard.documentNumber;
|
|
415
|
+
if (queryResult.document_number.eq &&
|
|
416
|
+
queryResult.document_number.eq.result &&
|
|
417
|
+
queryResult.document_number.eq.expected !== documentNumberPassport &&
|
|
418
|
+
queryResult.document_number.eq.expected !== documentNumberIDCard) {
|
|
419
|
+
console.warn('Document number does not match the expected document number');
|
|
420
|
+
isCorrect = false;
|
|
421
|
+
break;
|
|
422
|
+
}
|
|
423
|
+
if (queryResult.document_number.disclose &&
|
|
424
|
+
queryResult.document_number.disclose.result !== documentNumberPassport &&
|
|
425
|
+
queryResult.document_number.disclose.result !== documentNumberIDCard) {
|
|
426
|
+
console.warn('Document number does not match the disclosed document number in query result');
|
|
427
|
+
isCorrect = false;
|
|
428
|
+
break;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
if (queryResult.gender) {
|
|
432
|
+
const genderPassport = disclosedDataPassport.gender;
|
|
433
|
+
const genderIDCard = disclosedDataIDCard.gender;
|
|
434
|
+
if (queryResult.gender.eq &&
|
|
435
|
+
queryResult.gender.eq.result &&
|
|
436
|
+
queryResult.gender.eq.expected !== genderPassport &&
|
|
437
|
+
queryResult.gender.eq.expected !== genderIDCard) {
|
|
438
|
+
console.warn('Gender does not match the expected gender');
|
|
439
|
+
isCorrect = false;
|
|
440
|
+
break;
|
|
441
|
+
}
|
|
442
|
+
if (queryResult.gender.disclose &&
|
|
443
|
+
queryResult.gender.disclose.result !== genderPassport &&
|
|
444
|
+
queryResult.gender.disclose.result !== genderIDCard) {
|
|
445
|
+
console.warn('Gender does not match the disclosed gender in query result');
|
|
446
|
+
isCorrect = false;
|
|
447
|
+
break;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
if (queryResult.issuing_country) {
|
|
451
|
+
const issuingCountryPassport = disclosedDataPassport.issuingCountry;
|
|
452
|
+
const issuingCountryIDCard = disclosedDataIDCard.issuingCountry;
|
|
453
|
+
if (queryResult.issuing_country.eq &&
|
|
454
|
+
queryResult.issuing_country.eq.result &&
|
|
455
|
+
queryResult.issuing_country.eq.expected !== issuingCountryPassport &&
|
|
456
|
+
queryResult.issuing_country.eq.expected !== issuingCountryIDCard) {
|
|
457
|
+
console.warn('Issuing country does not match the expected issuing country');
|
|
458
|
+
isCorrect = false;
|
|
459
|
+
break;
|
|
460
|
+
}
|
|
461
|
+
if (queryResult.issuing_country.disclose &&
|
|
462
|
+
queryResult.issuing_country.disclose.result !== issuingCountryPassport &&
|
|
463
|
+
queryResult.issuing_country.disclose.result !== issuingCountryIDCard) {
|
|
464
|
+
console.warn('Issuing country does not match the disclosed issuing country in query result');
|
|
465
|
+
isCorrect = false;
|
|
466
|
+
break;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
if (queryResult.fullname) {
|
|
470
|
+
const fullnamePassport = disclosedDataPassport.name;
|
|
471
|
+
const fullnameIDCard = disclosedDataIDCard.name;
|
|
472
|
+
if (queryResult.fullname.eq &&
|
|
473
|
+
queryResult.fullname.eq.result &&
|
|
474
|
+
(0, utils_1.formatName)(queryResult.fullname.eq.expected).toLowerCase() !==
|
|
475
|
+
fullnamePassport.toLowerCase() &&
|
|
476
|
+
(0, utils_1.formatName)(queryResult.fullname.eq.expected).toLowerCase() !==
|
|
477
|
+
fullnameIDCard.toLowerCase()) {
|
|
478
|
+
console.warn('Fullname does not match the expected fullname');
|
|
479
|
+
isCorrect = false;
|
|
480
|
+
break;
|
|
481
|
+
}
|
|
482
|
+
if (queryResult.fullname.disclose &&
|
|
483
|
+
(0, utils_1.formatName)(queryResult.fullname.disclose.result).toLowerCase() !==
|
|
484
|
+
fullnamePassport.toLowerCase() &&
|
|
485
|
+
(0, utils_1.formatName)(queryResult.fullname.disclose.result).toLowerCase() !==
|
|
486
|
+
fullnameIDCard.toLowerCase()) {
|
|
487
|
+
console.warn('Fullname does not match the disclosed fullname in query result');
|
|
488
|
+
isCorrect = false;
|
|
489
|
+
break;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
if (queryResult.firstname) {
|
|
493
|
+
// If fullname was not revealed, then the name could be either the first name or last name
|
|
494
|
+
const firstnamePassport = disclosedDataPassport.firstName && disclosedDataPassport.firstName.length > 0
|
|
495
|
+
? disclosedDataPassport.firstName
|
|
496
|
+
: disclosedDataPassport.name;
|
|
497
|
+
const firstnameIDCard = disclosedDataIDCard.firstName && disclosedDataIDCard.firstName.length > 0
|
|
498
|
+
? disclosedDataIDCard.firstName
|
|
499
|
+
: disclosedDataIDCard.name;
|
|
500
|
+
if (queryResult.firstname.eq &&
|
|
501
|
+
queryResult.firstname.eq.result &&
|
|
502
|
+
(0, utils_1.formatName)(queryResult.firstname.eq.expected).toLowerCase() !==
|
|
503
|
+
firstnamePassport.toLowerCase() &&
|
|
504
|
+
(0, utils_1.formatName)(queryResult.firstname.eq.expected).toLowerCase() !==
|
|
505
|
+
firstnameIDCard.toLowerCase()) {
|
|
506
|
+
console.warn('Firstname does not match the expected firstname');
|
|
507
|
+
isCorrect = false;
|
|
508
|
+
break;
|
|
509
|
+
}
|
|
510
|
+
if (queryResult.firstname.disclose &&
|
|
511
|
+
(0, utils_1.formatName)(queryResult.firstname.disclose.result).toLowerCase() !==
|
|
512
|
+
firstnamePassport.toLowerCase() &&
|
|
513
|
+
(0, utils_1.formatName)(queryResult.firstname.disclose.result).toLowerCase() !==
|
|
514
|
+
firstnameIDCard.toLowerCase()) {
|
|
515
|
+
console.warn('Firstname does not match the disclosed firstname in query result');
|
|
516
|
+
isCorrect = false;
|
|
517
|
+
break;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
if (queryResult.lastname) {
|
|
521
|
+
// If fullname was not revealed, then the name could be either the first name or last name
|
|
522
|
+
const lastnamePassport = disclosedDataPassport.lastName && disclosedDataPassport.lastName.length > 0
|
|
523
|
+
? disclosedDataPassport.lastName
|
|
524
|
+
: disclosedDataPassport.name;
|
|
525
|
+
const lastnameIDCard = disclosedDataIDCard.lastName && disclosedDataIDCard.lastName.length > 0
|
|
526
|
+
? disclosedDataIDCard.lastName
|
|
527
|
+
: disclosedDataIDCard.name;
|
|
528
|
+
if (queryResult.lastname.eq &&
|
|
529
|
+
queryResult.lastname.eq.result &&
|
|
530
|
+
(0, utils_1.formatName)(queryResult.lastname.eq.expected).toLowerCase() !==
|
|
531
|
+
lastnamePassport.toLowerCase() &&
|
|
532
|
+
(0, utils_1.formatName)(queryResult.lastname.eq.expected).toLowerCase() !==
|
|
533
|
+
lastnameIDCard.toLowerCase()) {
|
|
534
|
+
console.warn('Lastname does not match the expected lastname');
|
|
535
|
+
isCorrect = false;
|
|
536
|
+
break;
|
|
537
|
+
}
|
|
538
|
+
if (queryResult.lastname.disclose &&
|
|
539
|
+
(0, utils_1.formatName)(queryResult.lastname.disclose.result).toLowerCase() !==
|
|
540
|
+
lastnamePassport.toLowerCase() &&
|
|
541
|
+
(0, utils_1.formatName)(queryResult.lastname.disclose.result).toLowerCase() !==
|
|
542
|
+
lastnameIDCard.toLowerCase()) {
|
|
543
|
+
console.warn('Lastname does not match the disclosed lastname in query result');
|
|
544
|
+
isCorrect = false;
|
|
545
|
+
break;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
|
|
549
|
+
}
|
|
550
|
+
else if (proof.name === 'compare_age') {
|
|
551
|
+
commitmentIn = (0, utils_1.getCommitmentInFromDisclosureProof)(proofData);
|
|
552
|
+
if (commitmentIn !== commitmentOut) {
|
|
553
|
+
console.warn('Failed to check the link between the validity of the ID and the age derived from it');
|
|
554
|
+
isCorrect = false;
|
|
555
|
+
break;
|
|
556
|
+
}
|
|
557
|
+
const minAge = (0, utils_1.getMinAgeFromProof)(proofData);
|
|
558
|
+
const maxAge = (0, utils_1.getMaxAgeFromProof)(proofData);
|
|
559
|
+
if (queryResult.age) {
|
|
560
|
+
if (queryResult.age.gte &&
|
|
561
|
+
queryResult.age.gte.result &&
|
|
562
|
+
minAge < queryResult.age.gte.expected) {
|
|
563
|
+
console.warn('Age is not greater than or equal to the expected age');
|
|
564
|
+
isCorrect = false;
|
|
565
|
+
break;
|
|
566
|
+
}
|
|
567
|
+
if (queryResult.age.lt &&
|
|
568
|
+
queryResult.age.lt.result &&
|
|
569
|
+
maxAge >= queryResult.age.lt.expected) {
|
|
570
|
+
console.warn('Age is not less than the expected age');
|
|
571
|
+
isCorrect = false;
|
|
572
|
+
break;
|
|
573
|
+
}
|
|
574
|
+
if (queryResult.age.range) {
|
|
575
|
+
if (queryResult.age.range.result &&
|
|
576
|
+
(minAge < queryResult.age.range.expected[0] ||
|
|
577
|
+
maxAge >= queryResult.age.range.expected[1])) {
|
|
578
|
+
console.warn('Age is not in the expected range');
|
|
579
|
+
isCorrect = false;
|
|
580
|
+
break;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
if (!queryResult.age.lt && !queryResult.age.range && maxAge != 0) {
|
|
584
|
+
console.warn('Maximum age should be equal to 0');
|
|
585
|
+
isCorrect = false;
|
|
586
|
+
break;
|
|
587
|
+
}
|
|
588
|
+
if (!queryResult.age.gte && !queryResult.age.range && minAge != 0) {
|
|
589
|
+
console.warn('Minimum age should be equal to 0');
|
|
590
|
+
isCorrect = false;
|
|
591
|
+
break;
|
|
592
|
+
}
|
|
593
|
+
if (queryResult.age.disclose &&
|
|
594
|
+
(queryResult.age.disclose.result !== minAge ||
|
|
595
|
+
queryResult.age.disclose.result !== maxAge)) {
|
|
596
|
+
console.warn('Age does not match the disclosed age in query result');
|
|
597
|
+
isCorrect = false;
|
|
598
|
+
break;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
else {
|
|
602
|
+
console.warn('Age is not set in the query result');
|
|
603
|
+
isCorrect = false;
|
|
604
|
+
break;
|
|
605
|
+
}
|
|
606
|
+
const currentDate = (0, utils_1.getCurrentDateFromAgeProof)(proofData);
|
|
607
|
+
if (currentDate.getTime() !== today.getTime() &&
|
|
608
|
+
currentDate.getTime() !== today.getTime() - 86400000) {
|
|
609
|
+
console.warn('Current date in the proof is too old');
|
|
610
|
+
isCorrect = false;
|
|
611
|
+
break;
|
|
612
|
+
}
|
|
613
|
+
uniqueIdentifier = (0, utils_1.getCommitmentInFromDisclosureProof)(proofData).toString(10);
|
|
614
|
+
}
|
|
615
|
+
else if (proof.name === 'compare_birthdate') {
|
|
616
|
+
commitmentIn = (0, utils_1.getCommitmentInFromDisclosureProof)(proofData);
|
|
617
|
+
if (commitmentIn !== commitmentOut) {
|
|
618
|
+
console.warn('Failed to check the link between the validity of the ID and the birthdate derived from it');
|
|
619
|
+
isCorrect = false;
|
|
620
|
+
break;
|
|
621
|
+
}
|
|
622
|
+
const minDate = (0, utils_1.getMinDateFromProof)(proofData);
|
|
623
|
+
const maxDate = (0, utils_1.getMaxDateFromProof)(proofData);
|
|
624
|
+
if (queryResult.birthdate) {
|
|
625
|
+
if (queryResult.birthdate.gte &&
|
|
626
|
+
queryResult.birthdate.gte.result &&
|
|
627
|
+
minDate < queryResult.birthdate.gte.expected) {
|
|
628
|
+
console.warn('Birthdate is not greater than or equal to the expected birthdate');
|
|
629
|
+
isCorrect = false;
|
|
630
|
+
break;
|
|
631
|
+
}
|
|
632
|
+
if (queryResult.birthdate.lte &&
|
|
633
|
+
queryResult.birthdate.lte.result &&
|
|
634
|
+
maxDate > queryResult.birthdate.lte.expected) {
|
|
635
|
+
console.warn('Birthdate is not less than the expected birthdate');
|
|
636
|
+
isCorrect = false;
|
|
637
|
+
break;
|
|
638
|
+
}
|
|
639
|
+
if (queryResult.birthdate.range) {
|
|
640
|
+
if (queryResult.birthdate.range.result &&
|
|
641
|
+
(minDate < queryResult.birthdate.range.expected[0] ||
|
|
642
|
+
maxDate > queryResult.birthdate.range.expected[1])) {
|
|
643
|
+
console.warn('Birthdate is not in the expected range');
|
|
644
|
+
isCorrect = false;
|
|
645
|
+
break;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
if (!queryResult.birthdate.lte &&
|
|
649
|
+
!queryResult.birthdate.range &&
|
|
650
|
+
maxDate.getTime() != defaultDateValue.getTime()) {
|
|
651
|
+
console.warn('Maximum birthdate should be equal to default date value');
|
|
652
|
+
isCorrect = false;
|
|
653
|
+
break;
|
|
654
|
+
}
|
|
655
|
+
if (!queryResult.birthdate.gte &&
|
|
656
|
+
!queryResult.birthdate.range &&
|
|
657
|
+
minDate.getTime() != defaultDateValue.getTime()) {
|
|
658
|
+
console.warn('Minimum birthdate should be equal to default date value');
|
|
659
|
+
isCorrect = false;
|
|
660
|
+
break;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
else {
|
|
664
|
+
console.warn('Birthdate is not set in the query result');
|
|
665
|
+
isCorrect = false;
|
|
666
|
+
break;
|
|
667
|
+
}
|
|
668
|
+
uniqueIdentifier = (0, utils_1.getCommitmentInFromDisclosureProof)(proofData).toString(10);
|
|
669
|
+
}
|
|
670
|
+
else if (proof.name === 'compare_expiry') {
|
|
671
|
+
commitmentIn = (0, utils_1.getCommitmentInFromDisclosureProof)(proofData);
|
|
672
|
+
if (commitmentIn !== commitmentOut) {
|
|
673
|
+
console.warn('Failed to check the link between the validity of the ID and its expiry date');
|
|
674
|
+
isCorrect = false;
|
|
675
|
+
break;
|
|
676
|
+
}
|
|
677
|
+
const minDate = (0, utils_1.getMinDateFromProof)(proofData);
|
|
678
|
+
const maxDate = (0, utils_1.getMaxDateFromProof)(proofData);
|
|
679
|
+
if (queryResult.expiry_date) {
|
|
680
|
+
if (queryResult.expiry_date.gte &&
|
|
681
|
+
queryResult.expiry_date.gte.result &&
|
|
682
|
+
minDate < queryResult.expiry_date.gte.expected) {
|
|
683
|
+
console.warn('Expiry date is not greater than or equal to the expected expiry date');
|
|
684
|
+
isCorrect = false;
|
|
685
|
+
break;
|
|
686
|
+
}
|
|
687
|
+
if (queryResult.expiry_date.lte &&
|
|
688
|
+
queryResult.expiry_date.lte.result &&
|
|
689
|
+
maxDate > queryResult.expiry_date.lte.expected) {
|
|
690
|
+
console.warn('Expiry date is not less than the expected expiry date');
|
|
691
|
+
isCorrect = false;
|
|
692
|
+
break;
|
|
693
|
+
}
|
|
694
|
+
if (queryResult.expiry_date.range) {
|
|
695
|
+
if (queryResult.expiry_date.range.result &&
|
|
696
|
+
(minDate < queryResult.expiry_date.range.expected[0] ||
|
|
697
|
+
maxDate > queryResult.expiry_date.range.expected[1])) {
|
|
698
|
+
console.warn('Expiry date is not in the expected range');
|
|
699
|
+
isCorrect = false;
|
|
700
|
+
break;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
if (!queryResult.expiry_date.lte &&
|
|
704
|
+
!queryResult.expiry_date.range &&
|
|
705
|
+
maxDate.getTime() != defaultDateValue.getTime()) {
|
|
706
|
+
console.warn('Maximum expiry date should be equal to default date value');
|
|
707
|
+
isCorrect = false;
|
|
708
|
+
break;
|
|
709
|
+
}
|
|
710
|
+
if (!queryResult.expiry_date.gte &&
|
|
711
|
+
!queryResult.expiry_date.range &&
|
|
712
|
+
minDate.getTime() != defaultDateValue.getTime()) {
|
|
713
|
+
console.warn('Minimum expiry date should be equal to default date value');
|
|
714
|
+
isCorrect = false;
|
|
715
|
+
break;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
else {
|
|
719
|
+
console.warn('Expiry date is not set in the query result');
|
|
720
|
+
isCorrect = false;
|
|
721
|
+
break;
|
|
722
|
+
}
|
|
723
|
+
uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
|
|
724
|
+
}
|
|
725
|
+
else if (proof.name === 'exclusion_check_country') {
|
|
726
|
+
commitmentIn = (0, utils_1.getCommitmentInFromDisclosureProof)(proofData);
|
|
727
|
+
if (commitmentIn !== commitmentOut) {
|
|
728
|
+
console.warn('Failed to check the link between the validity of the ID and the country exclusion check');
|
|
729
|
+
isCorrect = false;
|
|
730
|
+
break;
|
|
731
|
+
}
|
|
732
|
+
const countryList = (0, utils_1.getCountryListFromExclusionProof)(proofData);
|
|
733
|
+
if (queryResult.nationality &&
|
|
734
|
+
queryResult.nationality.out &&
|
|
735
|
+
queryResult.nationality.out.result) {
|
|
736
|
+
if (!queryResult.nationality.out.expected?.every((country) => countryList.includes(country))) {
|
|
737
|
+
console.warn('Country exclusion list does not match the one from the query results');
|
|
738
|
+
isCorrect = false;
|
|
739
|
+
break;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
else if (!queryResult.nationality || !queryResult.nationality.out) {
|
|
743
|
+
console.warn('Nationality exclusion is not set in the query result');
|
|
744
|
+
isCorrect = false;
|
|
745
|
+
break;
|
|
746
|
+
}
|
|
747
|
+
uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
|
|
748
|
+
}
|
|
749
|
+
else if (proof.name === 'inclusion_check_country') {
|
|
750
|
+
commitmentIn = (0, utils_1.getCommitmentInFromDisclosureProof)(proofData);
|
|
751
|
+
if (commitmentIn !== commitmentOut) {
|
|
752
|
+
console.warn('Failed to check the link between the validity of the ID and the country inclusion check');
|
|
753
|
+
isCorrect = false;
|
|
754
|
+
break;
|
|
755
|
+
}
|
|
756
|
+
const countryList = (0, utils_1.getCountryListFromInclusionProof)(proofData);
|
|
757
|
+
if (queryResult.nationality &&
|
|
758
|
+
queryResult.nationality.in &&
|
|
759
|
+
queryResult.nationality.in.result) {
|
|
760
|
+
if (!queryResult.nationality.in.expected?.every((country) => countryList.includes(country))) {
|
|
761
|
+
console.warn('Country inclusion list does not match the one from the query results');
|
|
762
|
+
isCorrect = false;
|
|
763
|
+
break;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
else if (!queryResult.nationality || !queryResult.nationality.in) {
|
|
767
|
+
console.warn('Nationality inclusion is not set in the query result');
|
|
768
|
+
isCorrect = false;
|
|
769
|
+
break;
|
|
770
|
+
}
|
|
771
|
+
uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
return { isCorrect, uniqueIdentifier };
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* @notice Verify the proofs received from the mobile app.
|
|
778
|
+
* @param requestId The request ID.
|
|
779
|
+
* @param proofs The proofs to verify.
|
|
780
|
+
* @param queryResult The query result to verify against
|
|
781
|
+
* @returns An object containing the unique identifier associated to the user
|
|
782
|
+
* and a boolean indicating whether the proofs were successfully verified.
|
|
783
|
+
*/
|
|
784
|
+
async verify(requestId, proofs, queryResult) {
|
|
785
|
+
let proofsToVerify = proofs;
|
|
786
|
+
if (!proofs) {
|
|
787
|
+
proofsToVerify = this.topicToProofs[requestId];
|
|
788
|
+
if (!proofsToVerify || proofsToVerify.length === 0) {
|
|
789
|
+
throw new Error('No proofs to verify');
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
const { BarretenbergVerifier } = await Promise.resolve().then(() => tslib_1.__importStar(require('@aztec/bb.js')));
|
|
793
|
+
const verifier = new BarretenbergVerifier();
|
|
794
|
+
/*if (!this.wasmVerifierInit) {
|
|
795
|
+
await this.initWasmVerifier()
|
|
796
|
+
}*/
|
|
797
|
+
let verified = true;
|
|
798
|
+
let uniqueIdentifier;
|
|
799
|
+
if (queryResult) {
|
|
800
|
+
const { isCorrect, uniqueIdentifier: uniqueIdentifierFromPublicInputs } = await this.checkPublicInputs(proofsToVerify, queryResult);
|
|
801
|
+
uniqueIdentifier = uniqueIdentifierFromPublicInputs;
|
|
802
|
+
verified = isCorrect;
|
|
803
|
+
}
|
|
804
|
+
// Only proceed with the proof verification if the public inputs are correct
|
|
805
|
+
if (verified) {
|
|
806
|
+
for (const proof of proofsToVerify) {
|
|
807
|
+
const proofData = (0, utils_1.getProofData)(proof.proof, true);
|
|
808
|
+
const hostedPackagedCircuit = await (0, utils_1.getHostedPackagedCircuitByName)(proof.version, proof.name);
|
|
809
|
+
const vkeyBytes = Buffer.from(hostedPackagedCircuit.vkey, 'base64');
|
|
810
|
+
try {
|
|
811
|
+
verified = await verifier.verifyUltraHonkProof(proofData, new Uint8Array(vkeyBytes));
|
|
812
|
+
}
|
|
813
|
+
catch (e) {
|
|
814
|
+
console.warn('Error verifying proof', e);
|
|
815
|
+
verified = false;
|
|
816
|
+
}
|
|
817
|
+
if (!verified) {
|
|
818
|
+
// Break the loop if the proof is not valid
|
|
819
|
+
// and don't bother checking the other proofs
|
|
820
|
+
break;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
this.topicToProofs[requestId] = [];
|
|
825
|
+
return { uniqueIdentifier, verified };
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* @notice Returns the URL of the request.
|
|
829
|
+
* @param requestId The request ID.
|
|
830
|
+
* @returns The URL of the request.
|
|
831
|
+
*/
|
|
832
|
+
getUrl(requestId) {
|
|
833
|
+
const pubkey = (0, utils_2.bytesToHex)(this.topicToKeyPair[requestId].publicKey);
|
|
834
|
+
const base64Config = Buffer.from(JSON.stringify(this.topicToConfig[requestId])).toString('base64');
|
|
835
|
+
const base64Service = Buffer.from(JSON.stringify(this.topicToService[requestId])).toString('base64');
|
|
836
|
+
return `https://zkpassport.id/r?d=${this.domain}&t=${requestId}&c=${base64Config}&s=${base64Service}&p=${pubkey}`;
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* @notice Cancels a request by closing the WebSocket connection and deleting the associated data.
|
|
840
|
+
* @param requestId The request ID.
|
|
841
|
+
*/
|
|
842
|
+
cancelRequest(requestId) {
|
|
843
|
+
this.topicToWebSocketClient[requestId].close();
|
|
844
|
+
delete this.topicToWebSocketClient[requestId];
|
|
845
|
+
delete this.topicToKeyPair[requestId];
|
|
846
|
+
delete this.topicToConfig[requestId];
|
|
847
|
+
delete this.topicToSharedSecret[requestId];
|
|
848
|
+
delete this.topicToProofs[requestId];
|
|
849
|
+
this.onRequestReceivedCallbacks[requestId] = [];
|
|
850
|
+
this.onGeneratingProofCallbacks[requestId] = [];
|
|
851
|
+
this.onBridgeConnectCallbacks[requestId] = [];
|
|
852
|
+
this.onProofGeneratedCallbacks[requestId] = [];
|
|
853
|
+
this.onRejectCallbacks[requestId] = [];
|
|
854
|
+
this.onErrorCallbacks[requestId] = [];
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
exports.ZKPassport = ZKPassport;
|