@keetanetwork/anchor 0.0.45 → 0.0.48
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/LICENSE +163 -34
- package/lib/asset.d.ts +30 -0
- package/lib/asset.d.ts.map +1 -0
- package/lib/asset.js +78 -0
- package/lib/asset.js.map +1 -0
- package/lib/certificates.d.ts +11 -38
- package/lib/certificates.d.ts.map +1 -1
- package/lib/certificates.js +33 -336
- package/lib/certificates.js.map +1 -1
- package/lib/resolver.d.ts +9 -2
- package/lib/resolver.d.ts.map +1 -1
- package/lib/resolver.js +195 -159
- package/lib/resolver.js.map +1 -1
- package/lib/sensitive-attribute.d.ts +87 -0
- package/lib/sensitive-attribute.d.ts.map +1 -0
- package/lib/sensitive-attribute.js +419 -0
- package/lib/sensitive-attribute.js.map +1 -0
- package/lib/token-metadata.d.ts +21 -0
- package/lib/token-metadata.d.ts.map +1 -0
- package/lib/token-metadata.generated.d.ts +5 -0
- package/lib/token-metadata.generated.d.ts.map +1 -0
- package/lib/token-metadata.generated.js +70 -0
- package/lib/token-metadata.generated.js.map +1 -0
- package/lib/token-metadata.js +57 -0
- package/lib/token-metadata.js.map +1 -0
- package/lib/utils/pii.d.ts +128 -0
- package/lib/utils/pii.d.ts.map +1 -0
- package/lib/utils/pii.js +198 -0
- package/lib/utils/pii.js.map +1 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/services/asset-movement/common.d.ts +7 -29
- package/services/asset-movement/common.d.ts.map +1 -1
- package/services/asset-movement/common.js +5223 -2660
- package/services/asset-movement/common.js.map +1 -1
- package/services/asset-movement/lib/data/addresses/bank-account/iban-swift.d.ts.map +1 -1
- package/services/asset-movement/lib/data/addresses/bank-account/iban-swift.js +22 -1
- package/services/asset-movement/lib/data/addresses/bank-account/iban-swift.js.map +1 -1
- package/services/asset-movement/lib/data/addresses/bank-account/interac.d.ts +1 -1
- package/services/asset-movement/lib/data/addresses/bank-account/interac.d.ts.map +1 -1
- package/services/asset-movement/lib/data/addresses/bank-account/interac.js +13 -3
- package/services/asset-movement/lib/data/addresses/bank-account/interac.js.map +1 -1
- package/services/asset-movement/lib/data/addresses/bank-account/pix.d.ts +1 -1
- package/services/asset-movement/lib/data/addresses/bank-account/pix.d.ts.map +1 -1
- package/services/asset-movement/lib/data/addresses/bank-account/pix.js +11 -1
- package/services/asset-movement/lib/data/addresses/bank-account/pix.js.map +1 -1
- package/services/asset-movement/lib/data/addresses/types.generated.d.ts +116 -33
- package/services/asset-movement/lib/data/addresses/types.generated.d.ts.map +1 -1
- package/services/asset-movement/lib/data/addresses/types.generated.js +102 -26
- package/services/asset-movement/lib/data/addresses/types.generated.js.map +1 -1
- package/services/asset-movement/lib/data/types.d.ts.map +1 -1
- package/services/asset-movement/lib/data/types.js +15 -10
- package/services/asset-movement/lib/data/types.js.map +1 -1
- package/services/fx/client.d.ts.map +1 -1
- package/services/fx/client.js +6 -2
- package/services/fx/client.js.map +1 -1
- package/services/fx/common.d.ts +14 -6
- package/services/fx/common.d.ts.map +1 -1
- package/services/fx/common.js +34 -8
- package/services/fx/common.js.map +1 -1
- package/services/fx/server.d.ts +6 -0
- package/services/fx/server.d.ts.map +1 -1
- package/services/fx/server.js +52 -10
- package/services/fx/server.js.map +1 -1
- package/services/kyc/common.d.ts +7 -0
- package/services/kyc/common.d.ts.map +1 -1
- package/services/kyc/common.generated.js +6 -1
- package/services/kyc/common.generated.js.map +1 -1
- package/services/kyc/common.js.map +1 -1
- package/services/notification/client.d.ts +1 -1
- package/services/notification/client.d.ts.map +1 -1
- package/services/notification/client.js +65 -2
- package/services/notification/client.js.map +1 -1
- package/services/notification/common.d.ts +1 -0
- package/services/notification/common.d.ts.map +1 -1
- package/services/notification/common.js.map +1 -1
- package/services/storage/clients/contacts.generated.js +506 -233
- package/services/storage/clients/contacts.generated.js.map +1 -1
- package/services/storage/server.d.ts +8 -1
- package/services/storage/server.d.ts.map +1 -1
- package/services/storage/server.js +9 -1
- package/services/storage/server.js.map +1 -1
package/lib/certificates.js
CHANGED
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
import * as KeetaNetClient from '@keetanetwork/keetanet-client';
|
|
2
2
|
import * as oids from '../services/kyc/oids.generated.js';
|
|
3
3
|
import * as ASN1 from './utils/asn1.js';
|
|
4
|
-
import {
|
|
5
|
-
import crypto from './utils/crypto.js';
|
|
4
|
+
import { arrayBufferToBuffer, Buffer, bufferToArrayBuffer } from './utils/buffer.js';
|
|
6
5
|
import { assertNever } from './utils/never.js';
|
|
7
6
|
import { CertificateAttributeOIDDB, CertificateAttributeSchema } from '../services/kyc/iso20022.generated.js';
|
|
8
|
-
import {
|
|
9
|
-
import { toJSONSerializable } from './utils/json.js';
|
|
7
|
+
import { lookupByOID } from './utils/oid.js';
|
|
10
8
|
import { EncryptedContainer } from './encrypted-container.js';
|
|
11
9
|
import { assertSharableCertificateAttributesContentsSchema } from './certificates.generated.js';
|
|
12
10
|
import { checkHashWithOID } from './utils/external.js';
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
*/
|
|
16
|
-
const DPO = KeetaNetClient.lib.Utils.Helper.debugPrintableObject.bind(KeetaNetClient.lib.Utils.Helper);
|
|
11
|
+
import { SensitiveAttribute, encodeForSensitive, encodeAttribute } from './sensitive-attribute.js';
|
|
12
|
+
export { SensitiveAttribute } from './sensitive-attribute.js';
|
|
17
13
|
/**
|
|
18
14
|
* Short alias for the KeetaNetAccount type
|
|
19
15
|
*/
|
|
@@ -180,9 +176,6 @@ async function walkObject(input, keyTransformer) {
|
|
|
180
176
|
}
|
|
181
177
|
return (newObj);
|
|
182
178
|
}
|
|
183
|
-
function toJSON(data) {
|
|
184
|
-
return (toJSONSerializable(data));
|
|
185
|
-
}
|
|
186
179
|
// Generic type guard to align decoded values with generated attribute types
|
|
187
180
|
function isAttributeValue(_name, _v) {
|
|
188
181
|
// Runtime schema validation is already performed by BufferStorageASN1; this guard
|
|
@@ -196,57 +189,6 @@ function asAttributeValue(name, v) {
|
|
|
196
189
|
}
|
|
197
190
|
return (v);
|
|
198
191
|
}
|
|
199
|
-
/**
|
|
200
|
-
* Sensitive Attribute Schema
|
|
201
|
-
*
|
|
202
|
-
* ASN.1 Schema:
|
|
203
|
-
* SensitiveAttributes DEFINITIONS ::= BEGIN
|
|
204
|
-
* SensitiveAttribute ::= SEQUENCE {
|
|
205
|
-
* version INTEGER { v1(0) },
|
|
206
|
-
* cipher SEQUENCE {
|
|
207
|
-
* algorithm OBJECT IDENTIFIER,
|
|
208
|
-
* ivOrNonce OCTET STRING,
|
|
209
|
-
* key OCTET STRING
|
|
210
|
-
* },
|
|
211
|
-
* hashedValue SEQUENCE {
|
|
212
|
-
* encryptedSalt OCTET STRING,
|
|
213
|
-
* algorithm OBJECT IDENTIFIER,
|
|
214
|
-
* value OCTET STRING
|
|
215
|
-
* },
|
|
216
|
-
* encryptedValue OCTET STRING
|
|
217
|
-
* }
|
|
218
|
-
* END
|
|
219
|
-
*
|
|
220
|
-
* https://keeta.notion.site/Keeta-KYC-Certificate-Extensions-13e5da848e588042bdcef81fc40458b7
|
|
221
|
-
*
|
|
222
|
-
* @internal
|
|
223
|
-
*/
|
|
224
|
-
const SensitiveAttributeSchemaInternal = [
|
|
225
|
-
0n,
|
|
226
|
-
[
|
|
227
|
-
ASN1.ValidateASN1.IsOID,
|
|
228
|
-
ASN1.ValidateASN1.IsOctetString,
|
|
229
|
-
ASN1.ValidateASN1.IsOctetString
|
|
230
|
-
],
|
|
231
|
-
[
|
|
232
|
-
ASN1.ValidateASN1.IsOctetString,
|
|
233
|
-
ASN1.ValidateASN1.IsOID,
|
|
234
|
-
ASN1.ValidateASN1.IsOctetString
|
|
235
|
-
],
|
|
236
|
-
ASN1.ValidateASN1.IsOctetString
|
|
237
|
-
];
|
|
238
|
-
/*
|
|
239
|
-
* Database of permitted algorithms and their OIDs
|
|
240
|
-
*/
|
|
241
|
-
const sensitiveAttributeOIDDB = {
|
|
242
|
-
'aes-256-gcm': oids.AES_256_GCM,
|
|
243
|
-
'aes-256-cbc': oids.AES_256_CBC,
|
|
244
|
-
'sha2-256': oids.SHA2_256,
|
|
245
|
-
'sha3-256': oids.SHA3_256,
|
|
246
|
-
'sha256': oids.SHA2_256,
|
|
247
|
-
'aes256-gcm': oids.AES_256_GCM,
|
|
248
|
-
'aes256-cbc': oids.AES_256_CBC
|
|
249
|
-
};
|
|
250
192
|
function assertCertificateAttributeNames(name) {
|
|
251
193
|
if (!(name in CertificateAttributeOIDDB)) {
|
|
252
194
|
throw (new Error(`Unknown attribute name: ${name}`));
|
|
@@ -256,50 +198,6 @@ function asCertificateAttributeNames(name) {
|
|
|
256
198
|
assertCertificateAttributeNames(name);
|
|
257
199
|
return (name);
|
|
258
200
|
}
|
|
259
|
-
function encodeAttribute(name, value) {
|
|
260
|
-
const schema = CertificateAttributeSchema[name];
|
|
261
|
-
let encodedJS;
|
|
262
|
-
try {
|
|
263
|
-
encodedJS = new ASN1.ValidateASN1(schema).fromJavaScriptObject(value);
|
|
264
|
-
}
|
|
265
|
-
catch (err) {
|
|
266
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
267
|
-
throw (new Error(`Attribute ${name}: ${message} (value: ${JSON.stringify(DPO(value))})`));
|
|
268
|
-
}
|
|
269
|
-
if (encodedJS === undefined) {
|
|
270
|
-
throw (new Error(`Unsupported attribute value for encoding: ${JSON.stringify(DPO(value))}`));
|
|
271
|
-
}
|
|
272
|
-
const asn1Object = ASN1.JStoASN1(encodedJS);
|
|
273
|
-
if (!asn1Object) {
|
|
274
|
-
throw (new Error(`Failed to encode value for attribute ${name}`));
|
|
275
|
-
}
|
|
276
|
-
return (asn1Object.toBER(false));
|
|
277
|
-
}
|
|
278
|
-
// Prepare a value for inclusion in a SensitiveAttribute: pre-encode complex and date types
|
|
279
|
-
function encodeForSensitive(name, value) {
|
|
280
|
-
if (Buffer.isBuffer(value)) {
|
|
281
|
-
return (value);
|
|
282
|
-
}
|
|
283
|
-
if (value instanceof ArrayBuffer) {
|
|
284
|
-
return (arrayBufferToBuffer(value));
|
|
285
|
-
}
|
|
286
|
-
if (typeof value === 'string') {
|
|
287
|
-
const asn1 = ASN1.JStoASN1({ type: 'string', kind: 'utf8', value });
|
|
288
|
-
return (arrayBufferToBuffer(asn1.toBER(false)));
|
|
289
|
-
}
|
|
290
|
-
if (value instanceof Date) {
|
|
291
|
-
const asn1 = ASN1.JStoASN1(value);
|
|
292
|
-
return (arrayBufferToBuffer(asn1.toBER(false)));
|
|
293
|
-
}
|
|
294
|
-
if (typeof value === 'object' && value !== null) {
|
|
295
|
-
if (!name) {
|
|
296
|
-
throw (new Error('attributeName required for complex types'));
|
|
297
|
-
}
|
|
298
|
-
const encoded = encodeAttribute(name, value);
|
|
299
|
-
return (arrayBufferToBuffer(encoded));
|
|
300
|
-
}
|
|
301
|
-
return (Buffer.from(String(value), 'utf-8'));
|
|
302
|
-
}
|
|
303
201
|
function unwrapSingleLayer(schema) {
|
|
304
202
|
if (typeof schema === 'object' && schema !== null && 'type' in schema && schema.type === 'context') {
|
|
305
203
|
return (schema.contains);
|
|
@@ -438,216 +336,6 @@ async function decodeAttribute(name, value, principals) {
|
|
|
438
336
|
const candidate = normalizeDecodedASN1(plainObject, principals);
|
|
439
337
|
return (asAttributeValue(name, candidate));
|
|
440
338
|
}
|
|
441
|
-
class SensitiveAttributeBuilder {
|
|
442
|
-
#account;
|
|
443
|
-
#value;
|
|
444
|
-
constructor(account) {
|
|
445
|
-
this.#account = account;
|
|
446
|
-
}
|
|
447
|
-
set(value) {
|
|
448
|
-
this.#value = Buffer.isBuffer(value) ? value : arrayBufferLikeToBuffer(value);
|
|
449
|
-
return (this);
|
|
450
|
-
}
|
|
451
|
-
async build() {
|
|
452
|
-
if (this.#value === undefined) {
|
|
453
|
-
throw (new Error('Value not set'));
|
|
454
|
-
}
|
|
455
|
-
const salt = crypto.randomBytes(32);
|
|
456
|
-
const hashingAlgorithm = KeetaNetClient.lib.Utils.Hash.HashFunctionName;
|
|
457
|
-
const publicKey = Buffer.from(this.#account.publicKey.get());
|
|
458
|
-
const cipher = 'aes-256-gcm';
|
|
459
|
-
const key = crypto.randomBytes(32);
|
|
460
|
-
const nonce = crypto.randomBytes(12);
|
|
461
|
-
const encryptedKey = await this.#account.encrypt(bufferToArrayBuffer(key));
|
|
462
|
-
function encrypt(value) {
|
|
463
|
-
const cipherObject = crypto.createCipheriv(cipher, key, nonce);
|
|
464
|
-
let retval = cipherObject.update(value);
|
|
465
|
-
retval = Buffer.concat([retval, cipherObject.final()]);
|
|
466
|
-
/*
|
|
467
|
-
* For AES-GCM, the last 16 bytes are the authentication tag
|
|
468
|
-
*/
|
|
469
|
-
if (cipher === 'aes-256-gcm') {
|
|
470
|
-
const getAuthTagFn = Reflect.get(cipherObject, 'getAuthTag');
|
|
471
|
-
if (typeof getAuthTagFn === 'function') {
|
|
472
|
-
const tag = getAuthTagFn.call(cipherObject);
|
|
473
|
-
if (!Buffer.isBuffer(tag)) {
|
|
474
|
-
throw (new Error('getAuthTag did not return a Buffer'));
|
|
475
|
-
}
|
|
476
|
-
retval = Buffer.concat([retval, tag]);
|
|
477
|
-
}
|
|
478
|
-
else {
|
|
479
|
-
throw (new Error('getAuthTag is not available on cipherObject'));
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
return (retval);
|
|
483
|
-
}
|
|
484
|
-
const encryptedValue = encrypt(this.#value);
|
|
485
|
-
const encryptedSalt = encrypt(arrayBufferLikeToBuffer(salt));
|
|
486
|
-
const saltedValue = Buffer.concat([salt, publicKey, encryptedValue, this.#value]);
|
|
487
|
-
const hashedAndSaltedValue = KeetaNetClient.lib.Utils.Hash.Hash(saltedValue);
|
|
488
|
-
const attributeStructure = [
|
|
489
|
-
/* Version */
|
|
490
|
-
0n,
|
|
491
|
-
/* Cipher Details */
|
|
492
|
-
[
|
|
493
|
-
/* Algorithm */
|
|
494
|
-
{ type: 'oid', oid: getOID(cipher, sensitiveAttributeOIDDB) },
|
|
495
|
-
/* IV or Nonce */
|
|
496
|
-
nonce,
|
|
497
|
-
/* Symmetric key, encrypted with the public key of the account */
|
|
498
|
-
Buffer.from(encryptedKey)
|
|
499
|
-
],
|
|
500
|
-
/* Hashed Value */
|
|
501
|
-
[
|
|
502
|
-
/* Encrypted Salt */
|
|
503
|
-
Buffer.from(encryptedSalt),
|
|
504
|
-
/* Hashing Algorithm */
|
|
505
|
-
{ type: 'oid', oid: getOID(hashingAlgorithm, sensitiveAttributeOIDDB) },
|
|
506
|
-
/* Hash of <Encrypted Salt> || <Public Key> || <Value> */
|
|
507
|
-
Buffer.from(hashedAndSaltedValue)
|
|
508
|
-
],
|
|
509
|
-
/* Encrypted Value, encrypted with the Cipher above */
|
|
510
|
-
encryptedValue
|
|
511
|
-
];
|
|
512
|
-
const encodedAttributeObject = ASN1.JStoASN1(attributeStructure);
|
|
513
|
-
// Produce canonical DER as ArrayBuffer
|
|
514
|
-
const retval = encodedAttributeObject.toBER(false);
|
|
515
|
-
return (retval);
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
class SensitiveAttribute {
|
|
519
|
-
#account;
|
|
520
|
-
#info;
|
|
521
|
-
#decoder;
|
|
522
|
-
constructor(account, data, decoder) {
|
|
523
|
-
this.#account = account;
|
|
524
|
-
this.#info = this.decode(data);
|
|
525
|
-
if (decoder) {
|
|
526
|
-
this.#decoder = decoder;
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
decode(data) {
|
|
530
|
-
if (Buffer.isBuffer(data)) {
|
|
531
|
-
data = bufferToArrayBuffer(data);
|
|
532
|
-
}
|
|
533
|
-
let decodedAttribute;
|
|
534
|
-
try {
|
|
535
|
-
const dataObject = new ASN1.BufferStorageASN1(data, SensitiveAttributeSchemaInternal);
|
|
536
|
-
decodedAttribute = dataObject.getASN1();
|
|
537
|
-
}
|
|
538
|
-
catch {
|
|
539
|
-
const js = ASN1.ASN1toJS(data);
|
|
540
|
-
throw (new Error(`SensitiveAttribute.decode: unexpected DER shape ${JSON.stringify(DPO(js))}`));
|
|
541
|
-
}
|
|
542
|
-
const decodedVersion = decodedAttribute[0] + 1n;
|
|
543
|
-
if (decodedVersion !== 1n) {
|
|
544
|
-
throw (new Error(`Unsupported Sensitive Attribute version (${decodedVersion})`));
|
|
545
|
-
}
|
|
546
|
-
return ({
|
|
547
|
-
version: decodedVersion,
|
|
548
|
-
publicKey: this.#account.publicKeyString.get(),
|
|
549
|
-
cipher: {
|
|
550
|
-
algorithm: lookupByOID(decodedAttribute[1][0].oid, sensitiveAttributeOIDDB),
|
|
551
|
-
iv: decodedAttribute[1][1],
|
|
552
|
-
key: decodedAttribute[1][2]
|
|
553
|
-
},
|
|
554
|
-
hashedValue: {
|
|
555
|
-
encryptedSalt: decodedAttribute[2][0],
|
|
556
|
-
algorithm: lookupByOID(decodedAttribute[2][1].oid, sensitiveAttributeOIDDB),
|
|
557
|
-
value: decodedAttribute[2][2]
|
|
558
|
-
},
|
|
559
|
-
encryptedValue: decodedAttribute[3]
|
|
560
|
-
});
|
|
561
|
-
}
|
|
562
|
-
async #decryptValue(value) {
|
|
563
|
-
const decryptedKey = await this.#account.decrypt(bufferToArrayBuffer(this.#info.cipher.key));
|
|
564
|
-
const algorithm = this.#info.cipher.algorithm;
|
|
565
|
-
const iv = this.#info.cipher.iv;
|
|
566
|
-
const cipher = crypto.createDecipheriv(algorithm, Buffer.from(decryptedKey), iv);
|
|
567
|
-
// For AES-GCM, the last 16 bytes are the authentication tag
|
|
568
|
-
if (algorithm === 'aes-256-gcm') {
|
|
569
|
-
const authTag = value.subarray(value.length - 16);
|
|
570
|
-
const ciphertext = value.subarray(0, value.length - 16);
|
|
571
|
-
// XXX:TODO Fix typescript unsafe calls
|
|
572
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
573
|
-
const setAuthTagFn = Reflect.get(cipher, 'setAuthTag');
|
|
574
|
-
if (typeof setAuthTagFn === 'function') {
|
|
575
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
576
|
-
setAuthTagFn.call(cipher, authTag);
|
|
577
|
-
}
|
|
578
|
-
else {
|
|
579
|
-
throw (new Error('setAuthTag is not available on cipher'));
|
|
580
|
-
}
|
|
581
|
-
const decrypted = cipher.update(ciphertext);
|
|
582
|
-
cipher.final(); // Verify auth tag
|
|
583
|
-
return (decrypted);
|
|
584
|
-
}
|
|
585
|
-
// For other algorithms (like CBC), just decrypt normally
|
|
586
|
-
const decryptedValue = cipher.update(value);
|
|
587
|
-
cipher.final();
|
|
588
|
-
return (decryptedValue);
|
|
589
|
-
}
|
|
590
|
-
/**
|
|
591
|
-
* Get the value of the sensitive attribute
|
|
592
|
-
*
|
|
593
|
-
* This will decrypt the value using the account's private key
|
|
594
|
-
* and return the value as an ArrayBuffer
|
|
595
|
-
*
|
|
596
|
-
* Since sensitive attributes are binary blobs, this returns an
|
|
597
|
-
* ArrayBuffer
|
|
598
|
-
*/
|
|
599
|
-
async get() {
|
|
600
|
-
const decryptedValue = await this.#decryptValue(arrayBufferLikeToBuffer(this.#info.encryptedValue));
|
|
601
|
-
return (bufferToArrayBuffer(decryptedValue));
|
|
602
|
-
}
|
|
603
|
-
async getValue() {
|
|
604
|
-
const value = await this.get();
|
|
605
|
-
if (!this.#decoder) {
|
|
606
|
-
/**
|
|
607
|
-
* TypeScript complains that T may not be the correct
|
|
608
|
-
* type here, but gives us no tools to enforce that it
|
|
609
|
-
* is -- it should always be ArrayBuffer if no decoder
|
|
610
|
-
* is provided, but someone could always specify a
|
|
611
|
-
* type parameter in that case and we cannot check
|
|
612
|
-
* that at runtime since T is only a compile-time type.
|
|
613
|
-
*/
|
|
614
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
615
|
-
return value;
|
|
616
|
-
}
|
|
617
|
-
return (this.#decoder(value));
|
|
618
|
-
}
|
|
619
|
-
/**
|
|
620
|
-
* Generate a proof that a sensitive attribute is a given value,
|
|
621
|
-
* which can be validated by a third party using the certificate
|
|
622
|
-
* and the `validateProof` method
|
|
623
|
-
*/
|
|
624
|
-
async getProof() {
|
|
625
|
-
const value = await this.get();
|
|
626
|
-
const salt = await this.#decryptValue(arrayBufferLikeToBuffer(this.#info.hashedValue.encryptedSalt));
|
|
627
|
-
return ({
|
|
628
|
-
value: Buffer.from(value).toString('base64'),
|
|
629
|
-
hash: {
|
|
630
|
-
salt: salt.toString('base64')
|
|
631
|
-
}
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
|
-
/**
|
|
635
|
-
* Validate the proof that a sensitive attribute is a given value
|
|
636
|
-
*/
|
|
637
|
-
async validateProof(proof) {
|
|
638
|
-
const plaintextValue = Buffer.from(proof.value, 'base64');
|
|
639
|
-
const proofSaltBuffer = Buffer.from(proof.hash.salt, 'base64');
|
|
640
|
-
const publicKeyBuffer = Buffer.from(this.#account.publicKey.get());
|
|
641
|
-
const encryptedValue = this.#info.encryptedValue;
|
|
642
|
-
const hashInput = Buffer.concat([proofSaltBuffer, publicKeyBuffer, encryptedValue, plaintextValue]);
|
|
643
|
-
const hashedAndSaltedValue = KeetaNetClient.lib.Utils.Hash.Hash(hashInput);
|
|
644
|
-
const hashedAndSaltedValueBuffer = Buffer.from(hashedAndSaltedValue);
|
|
645
|
-
return (this.#info.hashedValue.value.equals(hashedAndSaltedValueBuffer));
|
|
646
|
-
}
|
|
647
|
-
toJSON() {
|
|
648
|
-
return (toJSON(this.#info));
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
339
|
/**
|
|
652
340
|
* ASN.1 Schema for Certificate KYC Attributes Extension
|
|
653
341
|
*
|
|
@@ -679,6 +367,7 @@ const CertificateKYCAttributeSchemaValidation = {
|
|
|
679
367
|
};
|
|
680
368
|
export class CertificateBuilder extends BaseCertificateBuilder {
|
|
681
369
|
#attributes = {};
|
|
370
|
+
#subjectPublicKeyString;
|
|
682
371
|
/**
|
|
683
372
|
* Map the parameters from the public interface to the internal
|
|
684
373
|
* (Certificate library) interface
|
|
@@ -698,6 +387,9 @@ export class CertificateBuilder extends BaseCertificateBuilder {
|
|
|
698
387
|
}
|
|
699
388
|
constructor(params) {
|
|
700
389
|
super(CertificateBuilder.mapParams(params));
|
|
390
|
+
if (params?.subject) {
|
|
391
|
+
this.#subjectPublicKeyString = params.subject.publicKeyString.get();
|
|
392
|
+
}
|
|
701
393
|
}
|
|
702
394
|
/**
|
|
703
395
|
* Set a KYC Attribute to a given value.
|
|
@@ -708,14 +400,12 @@ export class CertificateBuilder extends BaseCertificateBuilder {
|
|
|
708
400
|
* value can be proven later without revealing it.
|
|
709
401
|
*/
|
|
710
402
|
setAttribute(name, sensitive, value) {
|
|
711
|
-
// Non-sensitive path: only primitive schema (string/date) allowed
|
|
712
403
|
const schemaValidator = CertificateAttributeSchema[name];
|
|
713
404
|
let encoded;
|
|
714
405
|
if (value instanceof ArrayBuffer) {
|
|
715
406
|
encoded = value;
|
|
716
407
|
}
|
|
717
408
|
else if (name in CertificateAttributeSchema) {
|
|
718
|
-
/* XXX: Why do we have two encoding methods ? */
|
|
719
409
|
encoded = bufferToArrayBuffer(encodeForSensitive(name, value));
|
|
720
410
|
}
|
|
721
411
|
else if (schemaValidator === ASN1.ValidateASN1.IsDate) {
|
|
@@ -728,42 +418,50 @@ export class CertificateBuilder extends BaseCertificateBuilder {
|
|
|
728
418
|
encoded = encodeAttribute(name, value);
|
|
729
419
|
}
|
|
730
420
|
else {
|
|
731
|
-
throw (new Error('Unsupported
|
|
421
|
+
throw (new Error('Unsupported attribute value type'));
|
|
732
422
|
}
|
|
733
423
|
this.#attributes[name] = {
|
|
734
424
|
sensitive: sensitive,
|
|
735
425
|
value: encoded
|
|
736
426
|
};
|
|
737
427
|
}
|
|
428
|
+
/**
|
|
429
|
+
* Set a pre-built SensitiveAttribute for a given attribute name.
|
|
430
|
+
*
|
|
431
|
+
* The attribute must have been encrypted for this certificate's subject.
|
|
432
|
+
*
|
|
433
|
+
* @throws Error if the attribute was encrypted for a different subject
|
|
434
|
+
*/
|
|
435
|
+
setSensitiveAttribute(name, attribute) {
|
|
436
|
+
if (this.#subjectPublicKeyString && attribute.publicKey !== this.#subjectPublicKeyString) {
|
|
437
|
+
throw (new Error('SensitiveAttribute was encrypted for a different subject'));
|
|
438
|
+
}
|
|
439
|
+
this.#attributes[name] = {
|
|
440
|
+
sensitive: true,
|
|
441
|
+
attribute
|
|
442
|
+
};
|
|
443
|
+
}
|
|
738
444
|
async addExtensions(...args) {
|
|
739
445
|
const retval = await super.addExtensions(...args);
|
|
740
|
-
const subject = args[0].subjectPublicKey;
|
|
741
446
|
/* Encode the attributes */
|
|
742
447
|
const certAttributes = [];
|
|
743
448
|
for (const [name, attribute] of Object.entries(this.#attributes)) {
|
|
744
449
|
if (!(name in CertificateAttributeOIDDB)) {
|
|
745
450
|
throw (new Error(`Unknown attribute: ${name}`));
|
|
746
451
|
}
|
|
747
|
-
/*
|
|
748
|
-
* Since we are iteratively building the certificate, we
|
|
749
|
-
* can assume that the attribute is always present in
|
|
750
|
-
* the object
|
|
751
|
-
*/
|
|
752
452
|
assertCertificateAttributeNames(name);
|
|
753
453
|
const nameOID = CertificateAttributeOIDDB[name];
|
|
754
454
|
let value;
|
|
755
|
-
if (attribute
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
455
|
+
if ('attribute' in attribute) {
|
|
456
|
+
value = arrayBufferToBuffer(attribute.attribute.toDER());
|
|
457
|
+
}
|
|
458
|
+
else if (attribute.sensitive) {
|
|
459
|
+
const subject = args[0].subjectPublicKey;
|
|
460
|
+
const sensitiveAttr = await SensitiveAttribute.create(subject, name, attribute.value);
|
|
461
|
+
value = arrayBufferToBuffer(sensitiveAttr.toDER());
|
|
759
462
|
}
|
|
760
463
|
else {
|
|
761
|
-
|
|
762
|
-
value = Buffer.from(attribute.value, 'utf-8');
|
|
763
|
-
}
|
|
764
|
-
else {
|
|
765
|
-
value = arrayBufferToBuffer(attribute.value);
|
|
766
|
-
}
|
|
464
|
+
value = arrayBufferToBuffer(attribute.value);
|
|
767
465
|
}
|
|
768
466
|
certAttributes.push([{
|
|
769
467
|
type: 'oid',
|
|
@@ -1297,7 +995,6 @@ export class SharableCertificateAttributes {
|
|
|
1297
995
|
Certificate.SharableAttributes = SharableCertificateAttributes;
|
|
1298
996
|
/** @internal */
|
|
1299
997
|
export const _Testing = {
|
|
1300
|
-
SensitiveAttributeBuilder,
|
|
1301
998
|
SensitiveAttribute,
|
|
1302
999
|
ValidateASN1: ASN1.ValidateASN1,
|
|
1303
1000
|
BufferStorageASN1: ASN1.BufferStorageASN1,
|