@0xpolygonid/js-sdk 1.21.1 → 1.23.0

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.
Files changed (82) hide show
  1. package/dist/browser/esm/index.js +1394 -278
  2. package/dist/browser/esm/index.js.map +1 -1
  3. package/dist/browser/umd/index.js +1399 -278
  4. package/dist/browser/umd/index.js.map +1 -1
  5. package/dist/node/cjs/iden3comm/constants.js +25 -1
  6. package/dist/node/cjs/iden3comm/handlers/auth.js +52 -8
  7. package/dist/node/cjs/iden3comm/handlers/common.js +13 -1
  8. package/dist/node/cjs/iden3comm/handlers/contract-request.js +5 -1
  9. package/dist/node/cjs/iden3comm/handlers/credential-proposal.js +14 -3
  10. package/dist/node/cjs/iden3comm/handlers/fetch.js +12 -2
  11. package/dist/node/cjs/iden3comm/handlers/message-handler.js +4 -0
  12. package/dist/node/cjs/iden3comm/handlers/payment.js +240 -28
  13. package/dist/node/cjs/iden3comm/handlers/revocation-status.js +4 -0
  14. package/dist/node/cjs/iden3comm/index.js +1 -0
  15. package/dist/node/cjs/iden3comm/packageManager.js +12 -0
  16. package/dist/node/cjs/iden3comm/packers/jws.js +21 -0
  17. package/dist/node/cjs/iden3comm/packers/plain.js +19 -0
  18. package/dist/node/cjs/iden3comm/packers/zkp.js +25 -0
  19. package/dist/node/cjs/iden3comm/types/index.js +1 -0
  20. package/dist/node/cjs/iden3comm/types/protocol/accept-profile.js +2 -0
  21. package/dist/node/cjs/iden3comm/utils/accept-profile.js +107 -0
  22. package/dist/node/cjs/iden3comm/utils/index.js +1 -0
  23. package/dist/node/cjs/proof/provers/inputs-generator.js +2 -1
  24. package/dist/node/cjs/storage/blockchain/abi/ERC20Permit.json +1 -0
  25. package/dist/node/cjs/storage/blockchain/erc20-permit-sig.js +46 -0
  26. package/dist/node/cjs/storage/blockchain/index.js +1 -0
  27. package/dist/node/cjs/storage/filters/jsonQuery.js +5 -3
  28. package/dist/node/cjs/verifiable/constants.js +28 -11
  29. package/dist/node/esm/iden3comm/constants.js +24 -0
  30. package/dist/node/esm/iden3comm/handlers/auth.js +55 -11
  31. package/dist/node/esm/iden3comm/handlers/common.js +11 -0
  32. package/dist/node/esm/iden3comm/handlers/contract-request.js +7 -3
  33. package/dist/node/esm/iden3comm/handlers/credential-proposal.js +15 -4
  34. package/dist/node/esm/iden3comm/handlers/fetch.js +12 -2
  35. package/dist/node/esm/iden3comm/handlers/message-handler.js +4 -0
  36. package/dist/node/esm/iden3comm/handlers/payment.js +240 -29
  37. package/dist/node/esm/iden3comm/handlers/revocation-status.js +4 -0
  38. package/dist/node/esm/iden3comm/index.js +1 -0
  39. package/dist/node/esm/iden3comm/packageManager.js +12 -0
  40. package/dist/node/esm/iden3comm/packers/jws.js +22 -1
  41. package/dist/node/esm/iden3comm/packers/plain.js +19 -0
  42. package/dist/node/esm/iden3comm/packers/zkp.js +26 -1
  43. package/dist/node/esm/iden3comm/types/index.js +1 -0
  44. package/dist/node/esm/iden3comm/types/protocol/accept-profile.js +1 -0
  45. package/dist/node/esm/iden3comm/utils/accept-profile.js +102 -0
  46. package/dist/node/esm/iden3comm/utils/index.js +1 -0
  47. package/dist/node/esm/proof/provers/inputs-generator.js +2 -1
  48. package/dist/node/esm/storage/blockchain/abi/ERC20Permit.json +1 -0
  49. package/dist/node/esm/storage/blockchain/erc20-permit-sig.js +39 -0
  50. package/dist/node/esm/storage/blockchain/index.js +1 -0
  51. package/dist/node/esm/storage/filters/jsonQuery.js +5 -3
  52. package/dist/node/esm/verifiable/constants.js +27 -10
  53. package/dist/types/iden3comm/constants.d.ts +16 -0
  54. package/dist/types/iden3comm/handlers/auth.d.ts +19 -7
  55. package/dist/types/iden3comm/handlers/common.d.ts +7 -1
  56. package/dist/types/iden3comm/handlers/contract-request.d.ts +2 -2
  57. package/dist/types/iden3comm/handlers/credential-proposal.d.ts +9 -4
  58. package/dist/types/iden3comm/handlers/fetch.d.ts +22 -6
  59. package/dist/types/iden3comm/handlers/message-handler.d.ts +6 -0
  60. package/dist/types/iden3comm/handlers/payment.d.ts +70 -10
  61. package/dist/types/iden3comm/handlers/revocation-status.d.ts +2 -2
  62. package/dist/types/iden3comm/index.d.ts +1 -0
  63. package/dist/types/iden3comm/packageManager.d.ts +4 -0
  64. package/dist/types/iden3comm/packers/jws.d.ts +5 -0
  65. package/dist/types/iden3comm/packers/plain.d.ts +4 -0
  66. package/dist/types/iden3comm/packers/zkp.d.ts +6 -0
  67. package/dist/types/iden3comm/types/index.d.ts +1 -0
  68. package/dist/types/iden3comm/types/packageManager.d.ts +14 -0
  69. package/dist/types/iden3comm/types/packer.d.ts +25 -0
  70. package/dist/types/iden3comm/types/protocol/accept-profile.d.ts +7 -0
  71. package/dist/types/iden3comm/types/protocol/auth.d.ts +1 -0
  72. package/dist/types/iden3comm/types/protocol/credentials.d.ts +6 -6
  73. package/dist/types/iden3comm/types/protocol/messages.d.ts +2 -2
  74. package/dist/types/iden3comm/types/protocol/payment.d.ts +87 -13
  75. package/dist/types/iden3comm/types/protocol/proof.d.ts +3 -3
  76. package/dist/types/iden3comm/types/protocol/revocation.d.ts +2 -2
  77. package/dist/types/iden3comm/utils/accept-profile.d.ts +3 -0
  78. package/dist/types/iden3comm/utils/index.d.ts +1 -0
  79. package/dist/types/storage/blockchain/erc20-permit-sig.d.ts +12 -0
  80. package/dist/types/storage/blockchain/index.d.ts +1 -0
  81. package/dist/types/verifiable/constants.d.ts +27 -11
  82. package/package.json +2 -2
@@ -1,11 +1,13 @@
1
1
  import { PROTOCOL_MESSAGE_TYPE } from '../constants';
2
2
  import { MediaType } from '../constants';
3
- import { DID } from '@iden3/js-iden3-core';
3
+ import { DID, getUnixTimestamp } from '@iden3/js-iden3-core';
4
4
  import * as uuid from 'uuid';
5
5
  import { proving } from '@iden3/js-jwz';
6
6
  import { byteEncoder } from '../../utils';
7
7
  import { AbstractMessageHandler } from './message-handler';
8
- import { PaymentRequestDataType, PaymentRequestType, PaymentType } from '../../verifiable';
8
+ import { PaymentFeatures, PaymentRequestDataType, PaymentType, SupportedPaymentProofType } from '../../verifiable';
9
+ import { ethers } from 'ethers';
10
+ import { verifyExpiresTime } from './common';
9
11
  /**
10
12
  * @beta
11
13
  * createPaymentRequest is a function to create protocol payment-request message
@@ -15,7 +17,7 @@ import { PaymentRequestDataType, PaymentRequestType, PaymentType } from '../../v
15
17
  * @param {PaymentRequestInfo[]} payments - payments
16
18
  * @returns `PaymentRequestMessage`
17
19
  */
18
- export function createPaymentRequest(sender, receiver, agent, payments) {
20
+ export function createPaymentRequest(sender, receiver, agent, payments, opts) {
19
21
  const uuidv4 = uuid.v4();
20
22
  const request = {
21
23
  id: uuidv4,
@@ -27,19 +29,57 @@ export function createPaymentRequest(sender, receiver, agent, payments) {
27
29
  body: {
28
30
  agent,
29
31
  payments
30
- }
32
+ },
33
+ created_time: getUnixTimestamp(new Date()),
34
+ expires_time: opts?.expires_time ? getUnixTimestamp(opts.expires_time) : undefined
31
35
  };
32
36
  return request;
33
37
  }
38
+ export async function verifyEIP712TypedData(data, resolver) {
39
+ const paymentData = data.type === PaymentRequestDataType.Iden3PaymentRailsRequestV1
40
+ ? {
41
+ recipient: data.recipient,
42
+ amount: data.amount,
43
+ expirationDate: new Date(data.expirationDate).getTime(),
44
+ nonce: data.nonce,
45
+ metadata: '0x'
46
+ }
47
+ : {
48
+ tokenAddress: data.tokenAddress,
49
+ recipient: data.recipient,
50
+ amount: data.amount,
51
+ expirationDate: new Date(data.expirationDate).getTime(),
52
+ nonce: data.nonce,
53
+ metadata: '0x'
54
+ };
55
+ const proof = Array.isArray(data.proof) ? data.proof[0] : data.proof;
56
+ const typesFetchResult = await fetch(proof.eip712.types);
57
+ const types = await typesFetchResult.json();
58
+ delete types.EIP712Domain;
59
+ const recovered = ethers.verifyTypedData(proof.eip712.domain, types, paymentData, proof.proofValue);
60
+ const { didDocument } = await resolver.resolve(proof.verificationMethod);
61
+ if (didDocument?.verificationMethod) {
62
+ for (const verificationMethod of didDocument.verificationMethod) {
63
+ if (verificationMethod.blockchainAccountId?.split(':').slice(-1)[0].toLowerCase() ===
64
+ recovered.toLowerCase()) {
65
+ return recovered;
66
+ }
67
+ }
68
+ }
69
+ else {
70
+ throw new Error('failed request. issuer DIDDocument does not contain any verificationMethods');
71
+ }
72
+ throw new Error(`failed request. no matching verificationMethod`);
73
+ }
34
74
  /**
35
75
  * @beta
36
76
  * createPayment is a function to create protocol payment message
37
77
  * @param {DID} sender - sender did
38
78
  * @param {DID} receiver - receiver did
39
- * @param {PaymentInfo[]} payments - payments
79
+ * @param {PaymentMessageBody} body - payments
40
80
  * @returns `PaymentMessage`
41
81
  */
42
- export function createPayment(sender, receiver, payments) {
82
+ export function createPayment(sender, receiver, payments, opts) {
43
83
  const uuidv4 = uuid.v4();
44
84
  const request = {
45
85
  id: uuidv4,
@@ -50,7 +90,9 @@ export function createPayment(sender, receiver, payments) {
50
90
  type: PROTOCOL_MESSAGE_TYPE.PAYMENT_MESSAGE_TYPE,
51
91
  body: {
52
92
  payments
53
- }
93
+ },
94
+ created_time: getUnixTimestamp(new Date()),
95
+ expires_time: opts?.expires_time ? getUnixTimestamp(opts.expires_time) : undefined
54
96
  };
55
97
  return request;
56
98
  }
@@ -112,21 +154,28 @@ export class PaymentHandler extends AbstractMessageHandler {
112
154
  const receiverDID = DID.parse(paymentRequest.from);
113
155
  const payments = [];
114
156
  for (let i = 0; i < paymentRequest.body.payments.length; i++) {
115
- const paymentReq = paymentRequest.body.payments[i];
116
- if (paymentReq.type !== PaymentRequestType.PaymentRequest) {
117
- throw new Error(`failed request. not supported '${paymentReq.type}' payment type `);
157
+ const { data } = paymentRequest.body.payments[i];
158
+ const selectedPayment = Array.isArray(data)
159
+ ? data.find((p) => {
160
+ return p.type === PaymentRequestDataType.Iden3PaymentRequestCryptoV1
161
+ ? p.id === ctx.nonce
162
+ : p.nonce === ctx.nonce;
163
+ })
164
+ : data;
165
+ if (!selectedPayment) {
166
+ throw new Error(`failed request. no payment in request for nonce ${ctx.nonce}`);
118
167
  }
119
- if (paymentReq.data.type !== PaymentRequestDataType.Iden3PaymentRequestCryptoV1) {
120
- throw new Error(`failed request. not supported '${paymentReq.data.type}' payment type `);
168
+ switch (selectedPayment.type) {
169
+ case PaymentRequestDataType.Iden3PaymentRequestCryptoV1:
170
+ payments.push(await this.handleIden3PaymentRequestCryptoV1(selectedPayment, ctx.paymentHandler));
171
+ break;
172
+ case PaymentRequestDataType.Iden3PaymentRailsRequestV1:
173
+ payments.push(await this.handleIden3PaymentRailsRequestV1(selectedPayment, ctx.paymentHandler));
174
+ break;
175
+ case PaymentRequestDataType.Iden3PaymentRailsERC20RequestV1:
176
+ payments.push(await this.handleIden3PaymentRailsERC20RequestV1(selectedPayment, ctx.paymentHandler, ctx.erc20TokenApproveHandler));
177
+ break;
121
178
  }
122
- const txId = await ctx.paymentHandler(paymentReq.data);
123
- payments.push({
124
- id: paymentReq.data.id,
125
- type: PaymentType.Iden3PaymentCryptoV1,
126
- paymentData: {
127
- txId
128
- }
129
- });
130
179
  }
131
180
  const paymentMessage = createPayment(senderDID, receiverDID, payments);
132
181
  const response = await this.packMessage(paymentMessage, senderDID);
@@ -159,6 +208,9 @@ export class PaymentHandler extends AbstractMessageHandler {
159
208
  if (!paymentRequest.to) {
160
209
  throw new Error(`failed request. empty 'to' field`);
161
210
  }
211
+ if (!opts?.allowExpiredMessages) {
212
+ verifyExpiresTime(paymentRequest);
213
+ }
162
214
  const agentMessage = await this.handlePaymentRequestMessage(paymentRequest, opts);
163
215
  if (!agentMessage) {
164
216
  return null;
@@ -169,24 +221,122 @@ export class PaymentHandler extends AbstractMessageHandler {
169
221
  /**
170
222
  * @inheritdoc IPaymentHandler#handlePayment
171
223
  */
172
- async handlePayment(payment, opts) {
173
- if (opts.paymentRequest.from !== payment.to) {
174
- throw new Error(`sender of the request is not a target of response - expected ${opts.paymentRequest.from}, given ${payment.to}`);
224
+ async handlePayment(payment, params) {
225
+ if (!params?.allowExpiredMessages) {
226
+ verifyExpiresTime(payment);
227
+ }
228
+ if (params.paymentRequest.from !== payment.to) {
229
+ throw new Error(`sender of the request is not a target of response - expected ${params.paymentRequest.from}, given ${payment.to}`);
175
230
  }
176
231
  if (!payment.body.payments.length) {
177
232
  throw new Error(`failed request. empty 'payments' field in body`);
178
233
  }
234
+ if (!params.paymentValidationHandler) {
235
+ throw new Error(`please provide payment validation handler in options`);
236
+ }
179
237
  for (let i = 0; i < payment.body.payments.length; i++) {
180
238
  const p = payment.body.payments[i];
181
- const paymentRequestData = opts.paymentRequest.body.payments.find((r) => r.data.id === p.id);
182
- if (!paymentRequestData) {
183
- throw new Error(`can't find payment request for payment id ${p.id}`);
239
+ const nonce = p.type === PaymentType.Iden3PaymentCryptoV1 ? p.id : p.nonce;
240
+ const requestDataArr = params.paymentRequest.body.payments
241
+ .map((r) => (Array.isArray(r.data) ? r.data : [r.data]))
242
+ .flat();
243
+ const requestData = requestDataArr.find((r) => r.type === PaymentRequestDataType.Iden3PaymentRequestCryptoV1
244
+ ? r.id === nonce
245
+ : r.nonce === nonce);
246
+ if (!requestData) {
247
+ throw new Error(`can't find payment request for payment ${p.type === PaymentType.Iden3PaymentCryptoV1 ? 'id' : 'nonce'} ${nonce}`);
184
248
  }
185
- if (!opts.paymentValidationHandler) {
186
- throw new Error(`please provide payment validation handler in options`);
249
+ await params.paymentValidationHandler(p.paymentData.txId, requestData);
250
+ }
251
+ }
252
+ /**
253
+ * @inheritdoc IPaymentHandler#createPaymentRailsV1
254
+ */
255
+ async createPaymentRailsV1(sender, receiver, agent, signer, payments) {
256
+ const paymentRequestInfo = [];
257
+ for (let i = 0; i < payments.length; i++) {
258
+ const { credentials, description } = payments[i];
259
+ const dataArr = [];
260
+ for (let j = 0; j < payments[i].chains.length; j++) {
261
+ const { features, nonce, amount, currency, chainId, expirationDate, type } = payments[i].chains[j];
262
+ const multiChainConfig = this._params.multiChainPaymentConfig?.find((c) => c.chainId === chainId);
263
+ if (!multiChainConfig) {
264
+ throw new Error(`failed request. no config for chain ${chainId}`);
265
+ }
266
+ const { recipient, paymentContract, erc20TokenAddressArr } = multiChainConfig;
267
+ const tokenAddress = erc20TokenAddressArr.find((t) => t.symbol === currency)?.address;
268
+ if (type === PaymentRequestDataType.Iden3PaymentRailsERC20RequestV1 && !tokenAddress) {
269
+ throw new Error(`failed request. no token address for currency ${currency}`);
270
+ }
271
+ const expirationTime = expirationDate
272
+ ? new Date(expirationDate).getTime()
273
+ : new Date(new Date().setHours(new Date().getHours() + 1)).getTime();
274
+ const typeUrl = `https://schema.iden3.io/core/json/${type}.json`;
275
+ const typesFetchResult = await fetch(typeUrl);
276
+ const types = await typesFetchResult.json();
277
+ delete types.EIP712Domain;
278
+ const paymentData = type === PaymentRequestDataType.Iden3PaymentRailsRequestV1
279
+ ? {
280
+ recipient,
281
+ amount,
282
+ expirationDate: expirationTime,
283
+ nonce,
284
+ metadata: '0x'
285
+ }
286
+ : {
287
+ tokenAddress,
288
+ recipient,
289
+ amount,
290
+ expirationDate: expirationTime,
291
+ nonce,
292
+ metadata: '0x'
293
+ };
294
+ const domain = {
295
+ name: 'MCPayment',
296
+ version: '1.0.0',
297
+ chainId,
298
+ verifyingContract: paymentContract
299
+ };
300
+ const signature = await signer.signTypedData(domain, types, paymentData);
301
+ const proof = [
302
+ {
303
+ type: SupportedPaymentProofType.EthereumEip712Signature2021,
304
+ proofPurpose: 'assertionMethod',
305
+ proofValue: signature,
306
+ verificationMethod: `did:pkh:eip155:${chainId}:${await signer.getAddress()}`,
307
+ created: new Date().toISOString(),
308
+ eip712: {
309
+ types: typeUrl,
310
+ primaryType: 'Iden3PaymentRailsRequestV1',
311
+ domain
312
+ }
313
+ }
314
+ ];
315
+ const d = {
316
+ type: PaymentRequestDataType.Iden3PaymentRailsRequestV1,
317
+ '@context': [
318
+ `https://schema.iden3.io/core/jsonld/payment.jsonld#${type}`,
319
+ 'https://w3id.org/security/suites/eip712sig-2021/v1'
320
+ ],
321
+ recipient,
322
+ amount: amount.toString(),
323
+ currency,
324
+ expirationDate: new Date(expirationTime).toISOString(),
325
+ nonce: nonce.toString(),
326
+ metadata: '0x',
327
+ proof
328
+ };
329
+ dataArr.push(type === PaymentRequestDataType.Iden3PaymentRailsRequestV1
330
+ ? d
331
+ : { ...d, type, tokenAddress: tokenAddress || '', features: features || [] });
187
332
  }
188
- await opts.paymentValidationHandler(p.paymentData.txId, paymentRequestData.data);
333
+ paymentRequestInfo.push({
334
+ data: dataArr,
335
+ credentials,
336
+ description
337
+ });
189
338
  }
339
+ return createPaymentRequest(sender, receiver, agent, paymentRequestInfo);
190
340
  }
191
341
  async packMessage(message, senderDID) {
192
342
  const responseEncoded = byteEncoder.encode(JSON.stringify(message));
@@ -200,4 +350,65 @@ export class PaymentHandler extends AbstractMessageHandler {
200
350
  ...packerOpts
201
351
  });
202
352
  }
353
+ async handleIden3PaymentRequestCryptoV1(data, paymentHandler) {
354
+ if (data.expiration && new Date(data.expiration) < new Date()) {
355
+ throw new Error(`failed request. expired request`);
356
+ }
357
+ const txId = await paymentHandler(data);
358
+ return {
359
+ id: data.id,
360
+ '@context': 'https://schema.iden3.io/core/jsonld/payment.jsonld#Iden3PaymentCryptoV1',
361
+ type: PaymentType.Iden3PaymentCryptoV1,
362
+ paymentData: {
363
+ txId
364
+ }
365
+ };
366
+ }
367
+ async handleIden3PaymentRailsRequestV1(data, paymentHandler) {
368
+ if (data.expirationDate && new Date(data.expirationDate) < new Date()) {
369
+ throw new Error(`failed request. expired request`);
370
+ }
371
+ const signer = await verifyEIP712TypedData(data, this._params.documentResolver);
372
+ if (this._params.allowedSigners && !this._params.allowedSigners.includes(signer)) {
373
+ throw new Error(`failed request. signer is not in the allowed signers list`);
374
+ }
375
+ const txId = await paymentHandler(data);
376
+ const proof = Array.isArray(data.proof) ? data.proof[0] : data.proof;
377
+ return {
378
+ nonce: data.nonce,
379
+ type: PaymentType.Iden3PaymentRailsV1,
380
+ '@context': 'https://schema.iden3.io/core/jsonld/payment.jsonld#Iden3PaymentRailsV1',
381
+ paymentData: {
382
+ txId,
383
+ chainId: proof.eip712.domain.chainId
384
+ }
385
+ };
386
+ }
387
+ async handleIden3PaymentRailsERC20RequestV1(data, paymentHandler, approveHandler) {
388
+ if (data.expirationDate && new Date(data.expirationDate) < new Date()) {
389
+ throw new Error(`failed request. expired request`);
390
+ }
391
+ const signer = await verifyEIP712TypedData(data, this._params.documentResolver);
392
+ if (this._params.allowedSigners && !this._params.allowedSigners.includes(signer)) {
393
+ throw new Error(`failed request. signer is not in the allowed signers list`);
394
+ }
395
+ if (!data.features?.includes(PaymentFeatures.EIP_2612) && !approveHandler) {
396
+ throw new Error(`please provide erc20TokenApproveHandler in context for ERC-20 payment type`);
397
+ }
398
+ if (approveHandler) {
399
+ await approveHandler(data);
400
+ }
401
+ const txId = await paymentHandler(data);
402
+ const proof = Array.isArray(data.proof) ? data.proof[0] : data.proof;
403
+ return {
404
+ nonce: data.nonce,
405
+ type: PaymentType.Iden3PaymentRailsERC20V1,
406
+ '@context': 'https://schema.iden3.io/core/jsonld/payment.jsonld#Iden3PaymentRailsERC20V1',
407
+ paymentData: {
408
+ txId,
409
+ chainId: proof.eip712.domain.chainId,
410
+ tokenAddress: data.tokenAddress
411
+ }
412
+ };
413
+ }
203
414
  }
@@ -5,6 +5,7 @@ import * as uuid from 'uuid';
5
5
  import { byteEncoder } from '../../utils';
6
6
  import { proving } from '@iden3/js-jwz';
7
7
  import { AbstractMessageHandler } from './message-handler';
8
+ import { verifyExpiresTime } from './common';
8
9
  /**
9
10
  *
10
11
  * Allows to process RevocationStatusRequest protocol message
@@ -97,6 +98,9 @@ export class RevocationStatusHandler extends AbstractMessageHandler {
97
98
  throw new Error(`jws packer options are required for ${MediaType.SignedMessage}`);
98
99
  }
99
100
  const rsRequest = await this.parseRevocationStatusRequest(request);
101
+ if (!opts.allowExpiredMessages) {
102
+ verifyExpiresTime(rsRequest);
103
+ }
100
104
  const response = await this.handleRevocationStatusRequestMessage(rsRequest, {
101
105
  senderDid: did,
102
106
  mediaType: opts.mediaType,
@@ -3,5 +3,6 @@ export * from './packers';
3
3
  export * from './types';
4
4
  export * from './handlers';
5
5
  export * from './utils/did';
6
+ export * from './utils/accept-profile';
6
7
  import * as PROTOCOL_CONSTANTS from './constants';
7
8
  export { PROTOCOL_CONSTANTS };
@@ -15,6 +15,18 @@ export class PackageManager {
15
15
  constructor() {
16
16
  this.packers = new Map();
17
17
  }
18
+ /** {@inheritDoc IPackageManager.isProfileSupported} */
19
+ isProfileSupported(mediaType, profile) {
20
+ const p = this.packers.get(mediaType);
21
+ if (!p) {
22
+ return false;
23
+ }
24
+ return p.isProfileSupported(profile);
25
+ }
26
+ /** {@inheritDoc IPackageManager.getSupportedMediaTypes} */
27
+ getSupportedMediaTypes() {
28
+ return [...this.packers.keys()];
29
+ }
18
30
  /** {@inheritDoc IPackageManager.registerPackers} */
19
31
  registerPackers(packers) {
20
32
  packers.forEach((p) => {
@@ -1,10 +1,11 @@
1
- import { MediaType, SUPPORTED_PUBLIC_KEY_TYPES } from '../constants';
1
+ import { AcceptJwsAlgorithms, MediaType, SUPPORTED_PUBLIC_KEY_TYPES } from '../constants';
2
2
  import { extractPublicKeyBytes, resolveVerificationMethods } from '../utils/did';
3
3
  import { keyPath } from '../../kms/';
4
4
  import { verifyJWS } from 'did-jwt';
5
5
  import { parse } from 'did-resolver';
6
6
  import { bytesToBase64url } from '../../utils/encoding';
7
7
  import { byteDecoder, byteEncoder, bytesToHex, decodeBase64url, encodeBase64url } from '../../utils';
8
+ import { parseAcceptProfile } from '../utils';
8
9
  /**
9
10
  * Packer that can pack message to JWZ token,
10
11
  * and unpack and validate JWZ envelope
@@ -83,6 +84,26 @@ export class JWSPacker {
83
84
  mediaType() {
84
85
  return MediaType.SignedMessage;
85
86
  }
87
+ /** {@inheritDoc IPacker.getSupportedProfiles} */
88
+ getSupportedProfiles() {
89
+ return [`env=${this.mediaType()}&alg=${this.getSupportedAlgorithms().join(',')}`];
90
+ }
91
+ /** {@inheritDoc IPacker.isProfileSupported} */
92
+ isProfileSupported(profile) {
93
+ const { env, circuits, alg } = parseAcceptProfile(profile);
94
+ if (env !== this.mediaType()) {
95
+ return false;
96
+ }
97
+ if (circuits) {
98
+ throw new Error(`Circuits are not supported for ${env} media type`);
99
+ }
100
+ const supportedAlgArr = this.getSupportedAlgorithms();
101
+ const algSupported = !alg?.length || alg.some((a) => supportedAlgArr.includes(a));
102
+ return algSupported;
103
+ }
104
+ getSupportedAlgorithms() {
105
+ return [AcceptJwsAlgorithms.ES256K, AcceptJwsAlgorithms.ES256KR];
106
+ }
86
107
  async resolveDidDoc(from) {
87
108
  let didDocument;
88
109
  try {
@@ -1,5 +1,6 @@
1
1
  import { MediaType } from '../constants';
2
2
  import { byteDecoder, byteEncoder } from '../../utils';
3
+ import { parseAcceptProfile } from '../utils';
3
4
  /**
4
5
  * Plain packer just serializes bytes to JSON and adds media type
5
6
  *
@@ -49,4 +50,22 @@ export class PlainPacker {
49
50
  mediaType() {
50
51
  return MediaType.PlainMessage;
51
52
  }
53
+ /** {@inheritDoc IPacker.getSupportedProfiles} */
54
+ getSupportedProfiles() {
55
+ return [`env=${this.mediaType()}`];
56
+ }
57
+ /** {@inheritDoc IPacker.isProfileSupported} */
58
+ isProfileSupported(profile) {
59
+ const { env, circuits, alg } = parseAcceptProfile(profile);
60
+ if (env !== this.mediaType()) {
61
+ return false;
62
+ }
63
+ if (circuits) {
64
+ throw new Error(`Circuits are not supported for ${env} media type`);
65
+ }
66
+ if (alg) {
67
+ throw new Error(`Algorithms are not supported for ${env} media type`);
68
+ }
69
+ return true;
70
+ }
52
71
  }
@@ -3,9 +3,10 @@ import { AuthV2PubSignals, CircuitId } from '../../circuits/index';
3
3
  import { BytesHelper, DID } from '@iden3/js-iden3-core';
4
4
  import { bytesToProtocolMessage } from '../utils/envelope';
5
5
  import { ErrNoProvingMethodAlg, ErrPackedWithUnsupportedCircuit, ErrProofIsInvalid, ErrSenderNotUsedTokenCreation, ErrStateVerificationFailed, ErrUnknownCircuitID } from '../errors';
6
- import { MediaType } from '../constants';
6
+ import { AcceptAuthCircuits, AcceptJwzAlgorithms, MediaType } from '../constants';
7
7
  import { byteDecoder, byteEncoder } from '../../utils';
8
8
  import { DEFAULT_AUTH_VERIFY_DELAY } from '../constants';
9
+ import { parseAcceptProfile } from '../utils';
9
10
  const { getProvingMethod } = proving;
10
11
  /**
11
12
  * Handler to
@@ -136,6 +137,30 @@ export class ZKPPacker {
136
137
  mediaType() {
137
138
  return MediaType.ZKPMessage;
138
139
  }
140
+ /** {@inheritDoc IPacker.getSupportedProfiles} */
141
+ getSupportedProfiles() {
142
+ return [
143
+ `env=${this.mediaType()}&alg=${this.getSupportedAlgorithms().join(',')}&circuitIds=${this.getSupportedCircuitIds().join(',')}`
144
+ ];
145
+ }
146
+ /** {@inheritDoc IPacker.isProfileSupported} */
147
+ isProfileSupported(profile) {
148
+ const { env, circuits, alg } = parseAcceptProfile(profile);
149
+ if (env !== this.mediaType()) {
150
+ return false;
151
+ }
152
+ const supportedCircuitIds = this.getSupportedCircuitIds();
153
+ const circuitIdSupported = !circuits?.length || circuits.some((c) => supportedCircuitIds.includes(c));
154
+ const supportedAlgArr = this.getSupportedAlgorithms();
155
+ const algSupported = !alg?.length || alg.some((a) => supportedAlgArr.includes(a));
156
+ return algSupported && circuitIdSupported;
157
+ }
158
+ getSupportedAlgorithms() {
159
+ return [AcceptJwzAlgorithms.Groth16];
160
+ }
161
+ getSupportedCircuitIds() {
162
+ return [AcceptAuthCircuits.AuthV2];
163
+ }
139
164
  }
140
165
  const verifySender = async (token, msg) => {
141
166
  switch (token.circuitId) {
@@ -6,6 +6,7 @@ export * from './protocol/revocation';
6
6
  export * from './protocol/contract-request';
7
7
  export * from './protocol/proposal-request';
8
8
  export * from './protocol/payment';
9
+ export * from './protocol/accept-profile';
9
10
  export * from './packer';
10
11
  export * from './models';
11
12
  export * from './packageManager';
@@ -0,0 +1,102 @@
1
+ import { MediaType, ProtocolVersion, AcceptAuthCircuits, AcceptJwzAlgorithms, AcceptJwsAlgorithms } from '../constants';
2
+ function isProtocolVersion(value) {
3
+ return Object.values(ProtocolVersion).includes(value);
4
+ }
5
+ function isMediaType(value) {
6
+ return Object.values(MediaType).includes(value);
7
+ }
8
+ function isAcceptAuthCircuits(value) {
9
+ return Object.values(AcceptAuthCircuits).includes(value);
10
+ }
11
+ function isAcceptJwsAlgorithms(value) {
12
+ return Object.values(AcceptJwsAlgorithms).includes(value);
13
+ }
14
+ function isAcceptJwzAlgorithms(value) {
15
+ return Object.values(AcceptJwzAlgorithms).includes(value);
16
+ }
17
+ export const buildAccept = (profiles) => {
18
+ const result = [];
19
+ for (const profile of profiles) {
20
+ let accept = `${profile.protocolVersion};env=${profile.env}`;
21
+ if (profile.circuits?.length) {
22
+ accept += `;circuitId=${profile.circuits.join(',')}`;
23
+ }
24
+ if (profile.alg?.length) {
25
+ accept += `;alg=${profile.alg.join(',')}`;
26
+ }
27
+ result.push(accept);
28
+ }
29
+ return result;
30
+ };
31
+ export const parseAcceptProfile = (profile) => {
32
+ const params = profile.split(';');
33
+ if (params.length < 2) {
34
+ throw new Error('Invalid accept profile');
35
+ }
36
+ const protocolVersion = params[0].trim();
37
+ if (!isProtocolVersion(protocolVersion)) {
38
+ throw new Error(`Protocol version '${protocolVersion}' not supported`);
39
+ }
40
+ const envParam = params[1].split('=');
41
+ if (envParam.length !== 2) {
42
+ throw new Error(`Invalid accept profile 'env' parameter`);
43
+ }
44
+ const env = params[1].split('=')[1].trim();
45
+ if (!isMediaType(env)) {
46
+ throw new Error(`Envelop '${env}' not supported`);
47
+ }
48
+ const circuitsIndex = params.findIndex((i) => i.includes('circuitId='));
49
+ if (env !== MediaType.ZKPMessage && circuitsIndex > 0) {
50
+ throw new Error(`Circuits not supported for env '${env}'`);
51
+ }
52
+ let circuits = undefined;
53
+ if (circuitsIndex > 0) {
54
+ circuits = params[circuitsIndex]
55
+ .split('=')[1]
56
+ .split(',')
57
+ .map((i) => i.trim())
58
+ .map((i) => {
59
+ if (!isAcceptAuthCircuits(i)) {
60
+ throw new Error(`Circuit '${i}' not supported`);
61
+ }
62
+ return i;
63
+ });
64
+ }
65
+ const algIndex = params.findIndex((i) => i.includes('alg='));
66
+ let alg = undefined;
67
+ if (algIndex > 0) {
68
+ if (env === MediaType.ZKPMessage) {
69
+ alg = params[algIndex]
70
+ .split('=')[1]
71
+ .split(',')
72
+ .map((i) => {
73
+ i = i.trim();
74
+ if (!isAcceptJwzAlgorithms(i)) {
75
+ throw new Error(`Algorithm '${i}' not supported for '${env}'`);
76
+ }
77
+ return i;
78
+ });
79
+ }
80
+ else if (env === MediaType.SignedMessage) {
81
+ alg = params[algIndex]
82
+ .split('=')[1]
83
+ .split(',')
84
+ .map((i) => {
85
+ i = i.trim();
86
+ if (!isAcceptJwsAlgorithms(i)) {
87
+ throw new Error(`Algorithm '${i}' not supported for '${env}'`);
88
+ }
89
+ return i;
90
+ });
91
+ }
92
+ else {
93
+ throw new Error(`Algorithm not supported for '${env}'`);
94
+ }
95
+ }
96
+ return {
97
+ protocolVersion,
98
+ env,
99
+ circuits,
100
+ alg
101
+ };
102
+ };
@@ -1,3 +1,4 @@
1
1
  export * from './envelope';
2
2
  export * from './message';
3
3
  export * from './did';
4
+ export * from './accept-profile';
@@ -12,7 +12,8 @@ const v2Operations = [
12
12
  Operators.GT,
13
13
  Operators.IN,
14
14
  Operators.NIN,
15
- Operators.NE
15
+ Operators.NE,
16
+ Operators.SD
16
17
  ];
17
18
  const v2OnChainOperations = [
18
19
  Operators.EQ,
@@ -0,0 +1 @@
1
+ [{ "inputs": [], "name": "ECDSAInvalidSignature", "type": "error" }, { "inputs": [{ "internalType": "uint256", "name": "length", "type": "uint256" }], "name": "ECDSAInvalidSignatureLength", "type": "error" }, { "inputs": [{ "internalType": "bytes32", "name": "s", "type": "bytes32" }], "name": "ECDSAInvalidSignatureS", "type": "error" }, { "inputs": [{ "internalType": "address", "name": "spender", "type": "address" }, { "internalType": "uint256", "name": "allowance", "type": "uint256" }, { "internalType": "uint256", "name": "needed", "type": "uint256" }], "name": "ERC20InsufficientAllowance", "type": "error" }, { "inputs": [{ "internalType": "address", "name": "sender", "type": "address" }, { "internalType": "uint256", "name": "balance", "type": "uint256" }, { "internalType": "uint256", "name": "needed", "type": "uint256" }], "name": "ERC20InsufficientBalance", "type": "error" }, { "inputs": [{ "internalType": "address", "name": "approver", "type": "address" }], "name": "ERC20InvalidApprover", "type": "error" }, { "inputs": [{ "internalType": "address", "name": "receiver", "type": "address" }], "name": "ERC20InvalidReceiver", "type": "error" }, { "inputs": [{ "internalType": "address", "name": "sender", "type": "address" }], "name": "ERC20InvalidSender", "type": "error" }, { "inputs": [{ "internalType": "address", "name": "spender", "type": "address" }], "name": "ERC20InvalidSpender", "type": "error" }, { "inputs": [{ "internalType": "uint256", "name": "deadline", "type": "uint256" }], "name": "ERC2612ExpiredSignature", "type": "error" }, { "inputs": [{ "internalType": "address", "name": "signer", "type": "address" }, { "internalType": "address", "name": "owner", "type": "address" }], "name": "ERC2612InvalidSigner", "type": "error" }, { "inputs": [{ "internalType": "address", "name": "account", "type": "address" }, { "internalType": "uint256", "name": "currentNonce", "type": "uint256" }], "name": "InvalidAccountNonce", "type": "error" }, { "inputs": [], "name": "InvalidShortString", "type": "error" }, { "inputs": [{ "internalType": "string", "name": "str", "type": "string" }], "name": "StringTooLong", "type": "error" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, { "indexed": true, "internalType": "address", "name": "spender", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" }], "name": "Approval", "type": "event" }, { "anonymous": false, "inputs": [], "name": "EIP712DomainChanged", "type": "event" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "from", "type": "address" }, { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" }], "name": "Transfer", "type": "event" }, { "inputs": [], "name": "DOMAIN_SEPARATOR", "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }, { "internalType": "address", "name": "spender", "type": "address" }], "name": "allowance", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "spender", "type": "address" }, { "internalType": "uint256", "name": "value", "type": "uint256" }], "name": "approve", "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], "name": "balanceOf", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "decimals", "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "eip712Domain", "outputs": [{ "internalType": "bytes1", "name": "fields", "type": "bytes1" }, { "internalType": "string", "name": "name", "type": "string" }, { "internalType": "string", "name": "version", "type": "string" }, { "internalType": "uint256", "name": "chainId", "type": "uint256" }, { "internalType": "address", "name": "verifyingContract", "type": "address" }, { "internalType": "bytes32", "name": "salt", "type": "bytes32" }, { "internalType": "uint256[]", "name": "extensions", "type": "uint256[]" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "name", "outputs": [{ "internalType": "string", "name": "", "type": "string" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }], "name": "nonces", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }, { "internalType": "address", "name": "spender", "type": "address" }, { "internalType": "uint256", "name": "value", "type": "uint256" }, { "internalType": "uint256", "name": "deadline", "type": "uint256" }, { "internalType": "uint8", "name": "v", "type": "uint8" }, { "internalType": "bytes32", "name": "r", "type": "bytes32" }, { "internalType": "bytes32", "name": "s", "type": "bytes32" }], "name": "permit", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "symbol", "outputs": [{ "internalType": "string", "name": "", "type": "string" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "totalSupply", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "to", "type": "address" }, { "internalType": "uint256", "name": "value", "type": "uint256" }], "name": "transfer", "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "from", "type": "address" }, { "internalType": "address", "name": "to", "type": "address" }, { "internalType": "uint256", "name": "value", "type": "uint256" }], "name": "transferFrom", "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "nonpayable", "type": "function" }]