@keetanetwork/anchor 0.0.45 → 0.0.47
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 +15 -44
- package/lib/certificates.d.ts.map +1 -1
- package/lib/certificates.js +32 -342
- 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 +6 -28
- package/services/asset-movement/common.d.ts.map +1 -1
- package/services/asset-movement/common.js +3286 -2142
- package/services/asset-movement/common.js.map +1 -1
- package/services/asset-movement/lib/data/addresses/bank-account/interac.js +1 -1
- package/services/asset-movement/lib/data/addresses/bank-account/interac.js.map +1 -1
- package/services/asset-movement/lib/data/addresses/types.generated.d.ts +39 -31
- package/services/asset-movement/lib/data/addresses/types.generated.d.ts.map +1 -1
- package/services/asset-movement/lib/data/addresses/types.generated.js +37 -24
- 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 +370 -227
- 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
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import * as KeetaNetClient from '@keetanetwork/keetanet-client';
|
|
2
|
+
import { Buffer } from './utils/buffer.js';
|
|
3
|
+
import type { SensitiveAttributeType, CertificateAttributeValue, CertificateAttributeOIDDB } from '../services/kyc/iso20022.generated.js';
|
|
4
|
+
type AccountKeyAlgorithm = InstanceType<typeof KeetaNetClient.lib.Account>['keyType'];
|
|
5
|
+
/**
|
|
6
|
+
* An alias for the KeetaNetAccount type
|
|
7
|
+
*/
|
|
8
|
+
type KeetaNetAccount = ReturnType<typeof KeetaNetClient.lib.Account.fromSeed<AccountKeyAlgorithm>>;
|
|
9
|
+
/**
|
|
10
|
+
* Type for certificate attribute names (derived from generated OID database)
|
|
11
|
+
*/
|
|
12
|
+
export type CertificateAttributeNames = keyof typeof CertificateAttributeOIDDB;
|
|
13
|
+
/**
|
|
14
|
+
* Encode an attribute value using its ASN.1 schema
|
|
15
|
+
*/
|
|
16
|
+
export declare function encodeAttribute(name: CertificateAttributeNames, value: unknown): ArrayBuffer;
|
|
17
|
+
/**
|
|
18
|
+
* Prepare a value for inclusion in a SensitiveAttribute: pre-encode complex and date types
|
|
19
|
+
*/
|
|
20
|
+
export declare function encodeForSensitive(name: CertificateAttributeNames | undefined, value: SensitiveAttributeType | Buffer | ArrayBuffer): Buffer;
|
|
21
|
+
export type SensitiveAttributeJSON = {
|
|
22
|
+
version: string;
|
|
23
|
+
publicKey: string;
|
|
24
|
+
cipher: {
|
|
25
|
+
algorithm: string;
|
|
26
|
+
iv: string;
|
|
27
|
+
key: string;
|
|
28
|
+
};
|
|
29
|
+
hashedValue: {
|
|
30
|
+
encryptedSalt: string;
|
|
31
|
+
algorithm: string;
|
|
32
|
+
value: string;
|
|
33
|
+
};
|
|
34
|
+
encryptedValue: string;
|
|
35
|
+
};
|
|
36
|
+
export declare class SensitiveAttribute<T = ArrayBuffer> {
|
|
37
|
+
#private;
|
|
38
|
+
private static readonly SensitiveAttributeObjectTypeID;
|
|
39
|
+
private readonly SensitiveAttributeObjectTypeID;
|
|
40
|
+
constructor(account: KeetaNetAccount, data: Buffer | ArrayBuffer, decoder?: (data: Buffer | ArrayBuffer) => T | Promise<T>);
|
|
41
|
+
/**
|
|
42
|
+
* Check if a value is a SensitiveAttribute instance
|
|
43
|
+
*/
|
|
44
|
+
static isInstance(input: unknown): input is SensitiveAttribute<unknown>;
|
|
45
|
+
/**
|
|
46
|
+
* Get the public key this attribute was encrypted for
|
|
47
|
+
*/
|
|
48
|
+
get publicKey(): string;
|
|
49
|
+
/**
|
|
50
|
+
* Get the raw encrypted DER for certificate embedding
|
|
51
|
+
*/
|
|
52
|
+
toDER(): ArrayBuffer;
|
|
53
|
+
private decode;
|
|
54
|
+
/**
|
|
55
|
+
* Get the value of the sensitive attribute
|
|
56
|
+
*
|
|
57
|
+
* This will decrypt the value using the account's private key
|
|
58
|
+
* and return the value as an ArrayBuffer
|
|
59
|
+
*
|
|
60
|
+
* Since sensitive attributes are binary blobs, this returns an
|
|
61
|
+
* ArrayBuffer
|
|
62
|
+
*/
|
|
63
|
+
get(): Promise<ArrayBuffer>;
|
|
64
|
+
getValue(): Promise<T>;
|
|
65
|
+
/**
|
|
66
|
+
* Generate a proof that a sensitive attribute is a given value,
|
|
67
|
+
* which can be validated by a third party using the certificate
|
|
68
|
+
* and the `validateProof` method
|
|
69
|
+
*/
|
|
70
|
+
getProof(): Promise<{
|
|
71
|
+
value: string;
|
|
72
|
+
hash: {
|
|
73
|
+
salt: string;
|
|
74
|
+
};
|
|
75
|
+
}>;
|
|
76
|
+
/**
|
|
77
|
+
* Validate the proof that a sensitive attribute is a given value
|
|
78
|
+
*/
|
|
79
|
+
validateProof(proof: Awaited<ReturnType<this['getProof']>>): Promise<boolean>;
|
|
80
|
+
toJSON(): SensitiveAttributeJSON;
|
|
81
|
+
/**
|
|
82
|
+
* Encrypt a value and create a new SensitiveAttribute
|
|
83
|
+
*/
|
|
84
|
+
static create<K extends CertificateAttributeNames>(account: KeetaNetAccount, name: K, value: CertificateAttributeValue<K> | Buffer | ArrayBuffer): Promise<SensitiveAttribute<CertificateAttributeValue<K>>>;
|
|
85
|
+
}
|
|
86
|
+
export {};
|
|
87
|
+
//# sourceMappingURL=sensitive-attribute.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sensitive-attribute.d.ts","sourceRoot":"","sources":["../../src/lib/sensitive-attribute.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,cAAc,MAAM,+BAA+B,CAAC;AAGhE,OAAO,EAAgD,MAAM,EAAuB,MAAM,mBAAmB,CAAC;AAE9G,OAAO,KAAK,EAAE,sBAAsB,EAAE,yBAAyB,EAAG,yBAAyB,EAAE,MAAM,uCAAuC,CAAC;AAU3I,KAAK,mBAAmB,GAAG,YAAY,CAAC,OAAO,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC;AAEtF;;GAEG;AACH,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC;AAEnG;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG,MAAM,OAAO,yBAAyB,CAAC;AA2E/E;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,yBAAyB,EAAE,KAAK,EAAE,OAAO,GAAG,WAAW,CAqB5F;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CACjC,IAAI,EAAE,yBAAyB,GAAG,SAAS,EAC3C,KAAK,EAAE,sBAAsB,GAAG,MAAM,GAAG,WAAW,GAClD,MAAM,CAoBR;AAyGD,MAAM,MAAM,sBAAsB,GAAG;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE;QACP,SAAS,EAAE,MAAM,CAAC;QAClB,EAAE,EAAE,MAAM,CAAC;QACX,GAAG,EAAE,MAAM,CAAC;KACZ,CAAC;IACF,WAAW,EAAE;QACZ,aAAa,EAAE,MAAM,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;KACd,CAAC;IACF,cAAc,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,qBAAa,kBAAkB,CAAC,CAAC,GAAG,WAAW;;IAC9C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,8BAA8B,CAA0C;IAChG,OAAO,CAAC,QAAQ,CAAC,8BAA8B,CAAU;gBAQxD,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,MAAM,GAAG,WAAW,EAC1B,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAezD;;OAEG;IACH,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,kBAAkB,CAAC,OAAO,CAAC;IAQvE;;OAEG;IACH,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED;;OAEG;IACH,KAAK,IAAI,WAAW;IAIpB,OAAO,CAAC,MAAM;IA6Dd;;;;;;;;OAQG;IACG,GAAG,IAAI,OAAO,CAAC,WAAW,CAAC;IAK3B,QAAQ,IAAI,OAAO,CAAC,CAAC,CAAC;IAiB5B;;;;OAIG;IACG,QAAQ,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,CAAA;KAAC,CAAC;IAYnE;;OAEG;IACG,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;IAcnF,MAAM,IAAI,sBAAsB;IAKhC;;OAEG;WACU,MAAM,CAAC,CAAC,SAAS,yBAAyB,EACtD,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,yBAAyB,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,WAAW,GACxD,OAAO,CAAC,kBAAkB,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC,CAAC;CAoE5D"}
|
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
import * as KeetaNetClient from '@keetanetwork/keetanet-client';
|
|
2
|
+
import * as oids from '../services/kyc/oids.generated.js';
|
|
3
|
+
import * as ASN1 from './utils/asn1.js';
|
|
4
|
+
import { arrayBufferLikeToBuffer, arrayBufferToBuffer, Buffer, bufferToArrayBuffer } from './utils/buffer.js';
|
|
5
|
+
import crypto from './utils/crypto.js';
|
|
6
|
+
import { CertificateAttributeSchema } from '../services/kyc/iso20022.generated.js';
|
|
7
|
+
import { getOID, lookupByOID } from './utils/oid.js';
|
|
8
|
+
/**
|
|
9
|
+
* Short alias for printing a debug representation of an object
|
|
10
|
+
*/
|
|
11
|
+
const DPO = KeetaNetClient.lib.Utils.Helper.debugPrintableObject.bind(KeetaNetClient.lib.Utils.Helper);
|
|
12
|
+
/**
|
|
13
|
+
* Sensitive Attribute Schema
|
|
14
|
+
*
|
|
15
|
+
* ASN.1 Schema:
|
|
16
|
+
* SensitiveAttributes DEFINITIONS ::= BEGIN
|
|
17
|
+
* SensitiveAttribute ::= SEQUENCE {
|
|
18
|
+
* version INTEGER { v1(0) },
|
|
19
|
+
* cipher SEQUENCE {
|
|
20
|
+
* algorithm OBJECT IDENTIFIER,
|
|
21
|
+
* ivOrNonce OCTET STRING,
|
|
22
|
+
* key OCTET STRING
|
|
23
|
+
* },
|
|
24
|
+
* hashedValue SEQUENCE {
|
|
25
|
+
* encryptedSalt OCTET STRING,
|
|
26
|
+
* algorithm OBJECT IDENTIFIER,
|
|
27
|
+
* value OCTET STRING
|
|
28
|
+
* },
|
|
29
|
+
* encryptedValue OCTET STRING
|
|
30
|
+
* }
|
|
31
|
+
* END
|
|
32
|
+
*
|
|
33
|
+
* https://keeta.notion.site/Keeta-KYC-Certificate-Extensions-13e5da848e588042bdcef81fc40458b7
|
|
34
|
+
*
|
|
35
|
+
* @internal
|
|
36
|
+
*/
|
|
37
|
+
const SensitiveAttributeSchemaInternal = [
|
|
38
|
+
0n,
|
|
39
|
+
[
|
|
40
|
+
ASN1.ValidateASN1.IsOID,
|
|
41
|
+
ASN1.ValidateASN1.IsOctetString,
|
|
42
|
+
ASN1.ValidateASN1.IsOctetString
|
|
43
|
+
],
|
|
44
|
+
[
|
|
45
|
+
ASN1.ValidateASN1.IsOctetString,
|
|
46
|
+
ASN1.ValidateASN1.IsOID,
|
|
47
|
+
ASN1.ValidateASN1.IsOctetString
|
|
48
|
+
],
|
|
49
|
+
ASN1.ValidateASN1.IsOctetString
|
|
50
|
+
];
|
|
51
|
+
/*
|
|
52
|
+
* Database of permitted algorithms and their OIDs
|
|
53
|
+
*/
|
|
54
|
+
const sensitiveAttributeOIDDB = {
|
|
55
|
+
'aes-256-gcm': oids.AES_256_GCM,
|
|
56
|
+
'aes-256-cbc': oids.AES_256_CBC,
|
|
57
|
+
'sha2-256': oids.SHA2_256,
|
|
58
|
+
'sha3-256': oids.SHA3_256,
|
|
59
|
+
'sha256': oids.SHA2_256,
|
|
60
|
+
'aes256-gcm': oids.AES_256_GCM,
|
|
61
|
+
'aes256-cbc': oids.AES_256_CBC
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Encode an attribute value using its ASN.1 schema
|
|
65
|
+
*/
|
|
66
|
+
export function encodeAttribute(name, value) {
|
|
67
|
+
const schema = CertificateAttributeSchema[name];
|
|
68
|
+
let encodedJS;
|
|
69
|
+
try {
|
|
70
|
+
encodedJS = new ASN1.ValidateASN1(schema).fromJavaScriptObject(value);
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
74
|
+
throw (new Error(`Attribute ${name}: ${message} (value: ${JSON.stringify(DPO(value))})`));
|
|
75
|
+
}
|
|
76
|
+
if (encodedJS === undefined) {
|
|
77
|
+
throw (new Error(`Unsupported attribute value for encoding: ${JSON.stringify(DPO(value))}`));
|
|
78
|
+
}
|
|
79
|
+
const asn1Object = ASN1.JStoASN1(encodedJS);
|
|
80
|
+
if (!asn1Object) {
|
|
81
|
+
throw (new Error(`Failed to encode value for attribute ${name}`));
|
|
82
|
+
}
|
|
83
|
+
return (asn1Object.toBER(false));
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Prepare a value for inclusion in a SensitiveAttribute: pre-encode complex and date types
|
|
87
|
+
*/
|
|
88
|
+
export function encodeForSensitive(name, value) {
|
|
89
|
+
if (Buffer.isBuffer(value)) {
|
|
90
|
+
return (value);
|
|
91
|
+
}
|
|
92
|
+
if (value instanceof ArrayBuffer) {
|
|
93
|
+
return (arrayBufferToBuffer(value));
|
|
94
|
+
}
|
|
95
|
+
if (typeof value === 'string') {
|
|
96
|
+
const asn1 = ASN1.JStoASN1({ type: 'string', kind: 'utf8', value });
|
|
97
|
+
return (arrayBufferToBuffer(asn1.toBER(false)));
|
|
98
|
+
}
|
|
99
|
+
if (value instanceof Date) {
|
|
100
|
+
const asn1 = ASN1.JStoASN1(value);
|
|
101
|
+
return (arrayBufferToBuffer(asn1.toBER(false)));
|
|
102
|
+
}
|
|
103
|
+
if (typeof value === 'object' && value !== null) {
|
|
104
|
+
if (!name) {
|
|
105
|
+
throw (new Error('attributeName required for complex types'));
|
|
106
|
+
}
|
|
107
|
+
const encoded = encodeAttribute(name, value);
|
|
108
|
+
return (arrayBufferToBuffer(encoded));
|
|
109
|
+
}
|
|
110
|
+
return (Buffer.from(String(value), 'utf-8'));
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Check if value is an ASN.1-like wrapper object
|
|
114
|
+
*/
|
|
115
|
+
function isASN1Wrapper(obj) {
|
|
116
|
+
return ('type' in obj && 'value' in obj && typeof obj.type === 'string');
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Normalize the result (unwrap ASN.1-like objects)
|
|
120
|
+
*/
|
|
121
|
+
function normalizeDecodedValue(input) {
|
|
122
|
+
if (input === undefined || input === null || typeof input !== 'object') {
|
|
123
|
+
return (input);
|
|
124
|
+
}
|
|
125
|
+
if (input instanceof Date || Buffer.isBuffer(input) || input instanceof ArrayBuffer) {
|
|
126
|
+
return (input);
|
|
127
|
+
}
|
|
128
|
+
if (Array.isArray(input)) {
|
|
129
|
+
return (input.map(item => normalizeDecodedValue(item)));
|
|
130
|
+
}
|
|
131
|
+
// Unwrap ASN.1-like objects
|
|
132
|
+
if (isASN1Wrapper(input)) {
|
|
133
|
+
if (input.type === 'string' && typeof input.value === 'string') {
|
|
134
|
+
return (input.value);
|
|
135
|
+
}
|
|
136
|
+
if (input.type === 'date' && input.value instanceof Date) {
|
|
137
|
+
return (input.value);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Recursively normalize object properties
|
|
141
|
+
const result = {};
|
|
142
|
+
for (const [key, value] of Object.entries(input)) {
|
|
143
|
+
result[key] = normalizeDecodedValue(value);
|
|
144
|
+
}
|
|
145
|
+
return (result);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Decode ASN.1 data using a schema
|
|
149
|
+
*
|
|
150
|
+
* Note: The ASN1 library uses dynamic typing internally, so we consolidate
|
|
151
|
+
* the unsafe operations here rather than scattering them throughout the code.
|
|
152
|
+
*/
|
|
153
|
+
function decodeWithSchema(buffer, schema) {
|
|
154
|
+
/* eslint-disable
|
|
155
|
+
@typescript-eslint/no-explicit-any,
|
|
156
|
+
@typescript-eslint/consistent-type-assertions,
|
|
157
|
+
@typescript-eslint/no-unsafe-member-access,
|
|
158
|
+
@typescript-eslint/no-unsafe-call,
|
|
159
|
+
@typescript-eslint/no-unsafe-assignment
|
|
160
|
+
*/
|
|
161
|
+
let decodedASN1;
|
|
162
|
+
try {
|
|
163
|
+
decodedASN1 = new ASN1.BufferStorageASN1(buffer, schema).getASN1();
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
decodedASN1 = ASN1.ASN1toJS(buffer);
|
|
167
|
+
}
|
|
168
|
+
if (decodedASN1 === undefined) {
|
|
169
|
+
throw (new Error('Failed to decode ASN1 data'));
|
|
170
|
+
}
|
|
171
|
+
const validator = new ASN1.ValidateASN1(schema);
|
|
172
|
+
return (validator.toJavaScriptObject(decodedASN1));
|
|
173
|
+
/* eslint-enable */
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* GCM cipher helpers - Node's crypto types don't properly type getAuthTag/setAuthTag
|
|
177
|
+
* when using createCipheriv/createDecipheriv, so we use typed wrappers.
|
|
178
|
+
*/
|
|
179
|
+
/* eslint-disable @typescript-eslint/consistent-type-assertions -- Reflect.get returns unknown */
|
|
180
|
+
function getGCMAuthTag(cipher) {
|
|
181
|
+
const getAuthTag = Reflect.get(cipher, 'getAuthTag');
|
|
182
|
+
if (typeof getAuthTag !== 'function') {
|
|
183
|
+
throw (new TypeError('getAuthTag is not available on cipher'));
|
|
184
|
+
}
|
|
185
|
+
return (getAuthTag.call(cipher));
|
|
186
|
+
}
|
|
187
|
+
function setGCMAuthTag(decipher, tag) {
|
|
188
|
+
const setAuthTag = Reflect.get(decipher, 'setAuthTag');
|
|
189
|
+
if (typeof setAuthTag !== 'function') {
|
|
190
|
+
throw (new TypeError('setAuthTag is not available on decipher'));
|
|
191
|
+
}
|
|
192
|
+
setAuthTag.call(decipher, tag);
|
|
193
|
+
}
|
|
194
|
+
/* eslint-enable @typescript-eslint/consistent-type-assertions */
|
|
195
|
+
/**
|
|
196
|
+
* Decode a value from its ASN.1 representation back to the original type
|
|
197
|
+
*
|
|
198
|
+
* @internal
|
|
199
|
+
*/
|
|
200
|
+
function decodeForSensitive(name, data) {
|
|
201
|
+
const buffer = Buffer.isBuffer(data) ? bufferToArrayBuffer(data) : data;
|
|
202
|
+
const schema = CertificateAttributeSchema[name];
|
|
203
|
+
const plainObject = decodeWithSchema(buffer, schema);
|
|
204
|
+
return (normalizeDecodedValue(plainObject));
|
|
205
|
+
}
|
|
206
|
+
export class SensitiveAttribute {
|
|
207
|
+
static SensitiveAttributeObjectTypeID = 'c0cc9591-cebb-4441-babe-23739279e3f2';
|
|
208
|
+
SensitiveAttributeObjectTypeID;
|
|
209
|
+
#account;
|
|
210
|
+
#encryptedDER;
|
|
211
|
+
#info;
|
|
212
|
+
#decoder;
|
|
213
|
+
constructor(account, data, decoder) {
|
|
214
|
+
Object.defineProperty(this, 'SensitiveAttributeObjectTypeID', {
|
|
215
|
+
value: SensitiveAttribute.SensitiveAttributeObjectTypeID,
|
|
216
|
+
enumerable: false
|
|
217
|
+
});
|
|
218
|
+
this.#account = account;
|
|
219
|
+
this.#encryptedDER = Buffer.isBuffer(data) ? bufferToArrayBuffer(data) : data;
|
|
220
|
+
this.#info = this.decode(data);
|
|
221
|
+
if (decoder) {
|
|
222
|
+
this.#decoder = decoder;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Check if a value is a SensitiveAttribute instance
|
|
227
|
+
*/
|
|
228
|
+
static isInstance(input) {
|
|
229
|
+
if (typeof input !== 'object' || input === null) {
|
|
230
|
+
return (false);
|
|
231
|
+
}
|
|
232
|
+
return (Reflect.get(input, 'SensitiveAttributeObjectTypeID') === SensitiveAttribute.SensitiveAttributeObjectTypeID);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Get the public key this attribute was encrypted for
|
|
236
|
+
*/
|
|
237
|
+
get publicKey() {
|
|
238
|
+
return (this.#account.publicKeyString.get());
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Get the raw encrypted DER for certificate embedding
|
|
242
|
+
*/
|
|
243
|
+
toDER() {
|
|
244
|
+
return (this.#encryptedDER);
|
|
245
|
+
}
|
|
246
|
+
decode(data) {
|
|
247
|
+
if (Buffer.isBuffer(data)) {
|
|
248
|
+
data = bufferToArrayBuffer(data);
|
|
249
|
+
}
|
|
250
|
+
let decodedAttribute;
|
|
251
|
+
try {
|
|
252
|
+
const dataObject = new ASN1.BufferStorageASN1(data, SensitiveAttributeSchemaInternal);
|
|
253
|
+
decodedAttribute = dataObject.getASN1();
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
const js = ASN1.ASN1toJS(data);
|
|
257
|
+
throw (new Error(`SensitiveAttribute.decode: unexpected DER shape ${JSON.stringify(DPO(js))}`));
|
|
258
|
+
}
|
|
259
|
+
const decodedVersion = decodedAttribute[0] + 1n;
|
|
260
|
+
if (decodedVersion !== 1n) {
|
|
261
|
+
throw (new Error(`Unsupported Sensitive Attribute version (${decodedVersion})`));
|
|
262
|
+
}
|
|
263
|
+
return ({
|
|
264
|
+
version: decodedVersion,
|
|
265
|
+
publicKey: this.#account.publicKeyString.get(),
|
|
266
|
+
cipher: {
|
|
267
|
+
algorithm: lookupByOID(decodedAttribute[1][0].oid, sensitiveAttributeOIDDB),
|
|
268
|
+
iv: decodedAttribute[1][1],
|
|
269
|
+
key: decodedAttribute[1][2]
|
|
270
|
+
},
|
|
271
|
+
hashedValue: {
|
|
272
|
+
encryptedSalt: decodedAttribute[2][0],
|
|
273
|
+
algorithm: lookupByOID(decodedAttribute[2][1].oid, sensitiveAttributeOIDDB),
|
|
274
|
+
value: decodedAttribute[2][2]
|
|
275
|
+
},
|
|
276
|
+
encryptedValue: decodedAttribute[3]
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
async #decryptValue(value) {
|
|
280
|
+
const decryptedKey = await this.#account.decrypt(bufferToArrayBuffer(this.#info.cipher.key));
|
|
281
|
+
const algorithm = this.#info.cipher.algorithm;
|
|
282
|
+
const iv = this.#info.cipher.iv;
|
|
283
|
+
const decipher = crypto.createDecipheriv(algorithm, Buffer.from(decryptedKey), iv);
|
|
284
|
+
// For AES-GCM, extract and set the 16-byte authentication tag
|
|
285
|
+
if (algorithm === 'aes-256-gcm') {
|
|
286
|
+
const authTag = value.subarray(-16);
|
|
287
|
+
const ciphertext = value.subarray(0, -16);
|
|
288
|
+
setGCMAuthTag(decipher, authTag);
|
|
289
|
+
const decrypted = decipher.update(ciphertext);
|
|
290
|
+
decipher.final(); // Verify auth tag
|
|
291
|
+
return (decrypted);
|
|
292
|
+
}
|
|
293
|
+
// For other algorithms (like CBC), just decrypt normally
|
|
294
|
+
const decrypted = decipher.update(value);
|
|
295
|
+
decipher.final();
|
|
296
|
+
return (decrypted);
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Get the value of the sensitive attribute
|
|
300
|
+
*
|
|
301
|
+
* This will decrypt the value using the account's private key
|
|
302
|
+
* and return the value as an ArrayBuffer
|
|
303
|
+
*
|
|
304
|
+
* Since sensitive attributes are binary blobs, this returns an
|
|
305
|
+
* ArrayBuffer
|
|
306
|
+
*/
|
|
307
|
+
async get() {
|
|
308
|
+
const decryptedValue = await this.#decryptValue(arrayBufferLikeToBuffer(this.#info.encryptedValue));
|
|
309
|
+
return (bufferToArrayBuffer(decryptedValue));
|
|
310
|
+
}
|
|
311
|
+
async getValue() {
|
|
312
|
+
const value = await this.get();
|
|
313
|
+
if (!this.#decoder) {
|
|
314
|
+
/**
|
|
315
|
+
* TypeScript complains that T may not be the correct
|
|
316
|
+
* type here, but gives us no tools to enforce that it
|
|
317
|
+
* is -- it should always be ArrayBuffer if no decoder
|
|
318
|
+
* is provided, but someone could always specify a
|
|
319
|
+
* type parameter in that case and we cannot check
|
|
320
|
+
* that at runtime since T is only a compile-time type.
|
|
321
|
+
*/
|
|
322
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
323
|
+
return value;
|
|
324
|
+
}
|
|
325
|
+
return (await this.#decoder(value));
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Generate a proof that a sensitive attribute is a given value,
|
|
329
|
+
* which can be validated by a third party using the certificate
|
|
330
|
+
* and the `validateProof` method
|
|
331
|
+
*/
|
|
332
|
+
async getProof() {
|
|
333
|
+
const value = await this.get();
|
|
334
|
+
const salt = await this.#decryptValue(arrayBufferLikeToBuffer(this.#info.hashedValue.encryptedSalt));
|
|
335
|
+
return ({
|
|
336
|
+
value: Buffer.from(value).toString('base64'),
|
|
337
|
+
hash: {
|
|
338
|
+
salt: salt.toString('base64')
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Validate the proof that a sensitive attribute is a given value
|
|
344
|
+
*/
|
|
345
|
+
async validateProof(proof) {
|
|
346
|
+
const plaintextValue = Buffer.from(proof.value, 'base64');
|
|
347
|
+
const proofSaltBuffer = Buffer.from(proof.hash.salt, 'base64');
|
|
348
|
+
const publicKeyBuffer = Buffer.from(this.#account.publicKey.get());
|
|
349
|
+
const encryptedValue = this.#info.encryptedValue;
|
|
350
|
+
const hashInput = Buffer.concat([proofSaltBuffer, publicKeyBuffer, encryptedValue, plaintextValue]);
|
|
351
|
+
const hashedAndSaltedValue = KeetaNetClient.lib.Utils.Hash.Hash(hashInput);
|
|
352
|
+
const hashedAndSaltedValueBuffer = Buffer.from(hashedAndSaltedValue);
|
|
353
|
+
return (this.#info.hashedValue.value.equals(hashedAndSaltedValueBuffer));
|
|
354
|
+
}
|
|
355
|
+
toJSON() {
|
|
356
|
+
const info = KeetaNetClient.lib.Utils.Conversion.toJSONSerializable(this.#info);
|
|
357
|
+
return (info);
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Encrypt a value and create a new SensitiveAttribute
|
|
361
|
+
*/
|
|
362
|
+
static async create(account, name, value) {
|
|
363
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
364
|
+
const encodedValue = encodeForSensitive(name, value);
|
|
365
|
+
const salt = crypto.randomBytes(32);
|
|
366
|
+
const hashingAlgorithm = KeetaNetClient.lib.Utils.Hash.HashFunctionName;
|
|
367
|
+
const publicKey = Buffer.from(account.publicKey.get());
|
|
368
|
+
const cipher = 'aes-256-gcm';
|
|
369
|
+
const key = crypto.randomBytes(32);
|
|
370
|
+
const nonce = crypto.randomBytes(12);
|
|
371
|
+
const encryptedKey = await account.encrypt(bufferToArrayBuffer(key));
|
|
372
|
+
function encrypt(input) {
|
|
373
|
+
const cipherObject = crypto.createCipheriv(cipher, key, nonce);
|
|
374
|
+
let retval = Buffer.concat([cipherObject.update(input), cipherObject.final()]);
|
|
375
|
+
// For AES-GCM, append the 16-byte authentication tag
|
|
376
|
+
if (cipher === 'aes-256-gcm') {
|
|
377
|
+
retval = Buffer.concat([retval, getGCMAuthTag(cipherObject)]);
|
|
378
|
+
}
|
|
379
|
+
return (retval);
|
|
380
|
+
}
|
|
381
|
+
const encryptedValue = encrypt(encodedValue);
|
|
382
|
+
const encryptedSalt = encrypt(arrayBufferLikeToBuffer(salt));
|
|
383
|
+
const saltedValue = Buffer.concat([salt, publicKey, encryptedValue, encodedValue]);
|
|
384
|
+
const hashedAndSaltedValue = KeetaNetClient.lib.Utils.Hash.Hash(saltedValue);
|
|
385
|
+
const attributeStructure = [
|
|
386
|
+
/* Version */
|
|
387
|
+
0n,
|
|
388
|
+
/* Cipher Details */
|
|
389
|
+
[
|
|
390
|
+
/* Algorithm */
|
|
391
|
+
{ type: 'oid', oid: getOID(cipher, sensitiveAttributeOIDDB) },
|
|
392
|
+
/* IV or Nonce */
|
|
393
|
+
nonce,
|
|
394
|
+
/* Symmetric key, encrypted with the public key of the account */
|
|
395
|
+
Buffer.from(encryptedKey)
|
|
396
|
+
],
|
|
397
|
+
/* Hashed Value */
|
|
398
|
+
[
|
|
399
|
+
/* Encrypted Salt */
|
|
400
|
+
Buffer.from(encryptedSalt),
|
|
401
|
+
/* Hashing Algorithm */
|
|
402
|
+
{ type: 'oid', oid: getOID(hashingAlgorithm, sensitiveAttributeOIDDB) },
|
|
403
|
+
/* Hash of <Encrypted Salt> || <Public Key> || <Value> */
|
|
404
|
+
Buffer.from(hashedAndSaltedValue)
|
|
405
|
+
],
|
|
406
|
+
/* Encrypted Value, encrypted with the Cipher above */
|
|
407
|
+
encryptedValue
|
|
408
|
+
];
|
|
409
|
+
const encodedAttributeObject = ASN1.JStoASN1(attributeStructure);
|
|
410
|
+
const encryptedDER = encodedAttributeObject.toBER(false);
|
|
411
|
+
const decoder = function (data) {
|
|
412
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
413
|
+
return decodeForSensitive(name, data);
|
|
414
|
+
};
|
|
415
|
+
const result = new SensitiveAttribute(account, encryptedDER, decoder);
|
|
416
|
+
return (result);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
//# sourceMappingURL=sensitive-attribute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sensitive-attribute.js","sourceRoot":"","sources":["../../src/lib/sensitive-attribute.ts"],"names":[],"mappings":"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","sourcesContent":["import * as KeetaNetClient from '@keetanetwork/keetanet-client';\nimport * as oids from '../services/kyc/oids.generated.js';\nimport * as ASN1 from './utils/asn1.js';\nimport { arrayBufferLikeToBuffer, arrayBufferToBuffer, Buffer, bufferToArrayBuffer } from './utils/buffer.js';\nimport crypto from './utils/crypto.js';\nimport type { SensitiveAttributeType, CertificateAttributeValue , CertificateAttributeOIDDB } from '../services/kyc/iso20022.generated.js';\nimport { CertificateAttributeSchema } from '../services/kyc/iso20022.generated.js';\nimport { getOID, lookupByOID } from './utils/oid.js';\n\n/**\n * Short alias for printing a debug representation of an object\n */\nconst DPO = KeetaNetClient.lib.Utils.Helper.debugPrintableObject.bind(KeetaNetClient.lib.Utils.Helper);\n\n/* ENUM */\ntype AccountKeyAlgorithm = InstanceType<typeof KeetaNetClient.lib.Account>['keyType'];\n\n/**\n * An alias for the KeetaNetAccount type\n */\ntype KeetaNetAccount = ReturnType<typeof KeetaNetClient.lib.Account.fromSeed<AccountKeyAlgorithm>>;\n\n/**\n * Type for certificate attribute names (derived from generated OID database)\n */\nexport type CertificateAttributeNames = keyof typeof CertificateAttributeOIDDB;\n\n/**\n * Sensitive Attribute Schema\n *\n * ASN.1 Schema:\n * SensitiveAttributes DEFINITIONS ::= BEGIN\n * SensitiveAttribute ::= SEQUENCE {\n * version INTEGER { v1(0) },\n * cipher SEQUENCE {\n * algorithm OBJECT IDENTIFIER,\n * ivOrNonce OCTET STRING,\n * key OCTET STRING\n * },\n * hashedValue SEQUENCE {\n * encryptedSalt OCTET STRING,\n * algorithm OBJECT IDENTIFIER,\n * value OCTET STRING\n * },\n * encryptedValue OCTET STRING\n * }\n * END\n *\n * https://keeta.notion.site/Keeta-KYC-Certificate-Extensions-13e5da848e588042bdcef81fc40458b7\n *\n * @internal\n */\nconst SensitiveAttributeSchemaInternal: [\n\tversion: 0n,\n\tcipher: [\n\t\talgorithm: typeof ASN1.ValidateASN1.IsOID,\n\t\tiv: typeof ASN1.ValidateASN1.IsOctetString,\n\t\tkey: typeof ASN1.ValidateASN1.IsOctetString\n\t],\n\thashedValue: [\n\t\tencryptedSalt: typeof ASN1.ValidateASN1.IsOctetString,\n\t\talgorithm: typeof ASN1.ValidateASN1.IsOID,\n\t\tvalue: typeof ASN1.ValidateASN1.IsOctetString\n\t],\n\tencryptedValue: typeof ASN1.ValidateASN1.IsOctetString\n] = [\n\t0n,\n\t[\n\t\tASN1.ValidateASN1.IsOID,\n\t\tASN1.ValidateASN1.IsOctetString,\n\t\tASN1.ValidateASN1.IsOctetString\n\t],\n\t[\n\t\tASN1.ValidateASN1.IsOctetString,\n\t\tASN1.ValidateASN1.IsOID,\n\t\tASN1.ValidateASN1.IsOctetString\n\t],\n\tASN1.ValidateASN1.IsOctetString\n];\n\n/**\n * The Sensitive Attribute Schema Internal\n *\n * @internal\n */\ntype SensitiveAttributeSchema = ASN1.SchemaMap<typeof SensitiveAttributeSchemaInternal>;\n\n/*\n * Database of permitted algorithms and their OIDs\n */\nconst sensitiveAttributeOIDDB = {\n\t'aes-256-gcm': oids.AES_256_GCM,\n\t'aes-256-cbc': oids.AES_256_CBC,\n\t'sha2-256': oids.SHA2_256,\n\t'sha3-256': oids.SHA3_256,\n\t'sha256': oids.SHA2_256,\n\t'aes256-gcm': oids.AES_256_GCM,\n\t'aes256-cbc': oids.AES_256_CBC\n};\n\n/**\n * Encode an attribute value using its ASN.1 schema\n */\nexport function encodeAttribute(name: CertificateAttributeNames, value: unknown): ArrayBuffer {\n\tconst schema = CertificateAttributeSchema[name];\n\n\tlet encodedJS;\n\ttry {\n\t\tencodedJS = new ASN1.ValidateASN1(schema).fromJavaScriptObject(value);\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tthrow(new Error(`Attribute ${name}: ${message} (value: ${JSON.stringify(DPO(value))})`));\n\t}\n\n\tif (encodedJS === undefined) {\n\t\tthrow(new Error(`Unsupported attribute value for encoding: ${JSON.stringify(DPO(value))}`));\n\t}\n\n\tconst asn1Object = ASN1.JStoASN1(encodedJS);\n\tif (!asn1Object) {\n\t\tthrow(new Error(`Failed to encode value for attribute ${name}`));\n\t}\n\n\treturn(asn1Object.toBER(false));\n}\n\n/**\n * Prepare a value for inclusion in a SensitiveAttribute: pre-encode complex and date types\n */\nexport function encodeForSensitive(\n\tname: CertificateAttributeNames | undefined,\n\tvalue: SensitiveAttributeType | Buffer | ArrayBuffer\n): Buffer {\n\tif (Buffer.isBuffer(value)) { return(value); }\n\tif (value instanceof ArrayBuffer) { return(arrayBufferToBuffer(value)); }\n\tif (typeof value === 'string') {\n\t\tconst asn1 = ASN1.JStoASN1({ type: 'string', kind: 'utf8', value });\n\t\treturn(arrayBufferToBuffer(asn1.toBER(false)));\n\t}\n\n\tif (value instanceof Date) {\n\t\tconst asn1 = ASN1.JStoASN1(value);\n\t\treturn(arrayBufferToBuffer(asn1.toBER(false)));\n\t}\n\n\tif (typeof value === 'object' && value !== null) {\n\t\tif (!name) { throw(new Error('attributeName required for complex types')); }\n\t\tconst encoded = encodeAttribute(name, value);\n\t\treturn(arrayBufferToBuffer(encoded));\n\t}\n\n\treturn(Buffer.from(String(value), 'utf-8'));\n}\n\n/**\n * Check if value is an ASN.1-like wrapper object\n */\nfunction isASN1Wrapper(obj: object): obj is { type: string; value: unknown } {\n\treturn('type' in obj && 'value' in obj && typeof obj.type === 'string');\n}\n\n/**\n * Normalize the result (unwrap ASN.1-like objects)\n */\nfunction normalizeDecodedValue(input: unknown): unknown {\n\tif (input === undefined || input === null || typeof input !== 'object') {\n\t\treturn(input);\n\t}\n\tif (input instanceof Date || Buffer.isBuffer(input) || input instanceof ArrayBuffer) {\n\t\treturn(input);\n\t}\n\tif (Array.isArray(input)) {\n\t\treturn(input.map(item => normalizeDecodedValue(item)));\n\t}\n\t// Unwrap ASN.1-like objects\n\tif (isASN1Wrapper(input)) {\n\t\tif (input.type === 'string' && typeof input.value === 'string') {\n\t\t\treturn(input.value);\n\t\t}\n\t\tif (input.type === 'date' && input.value instanceof Date) {\n\t\t\treturn(input.value);\n\t\t}\n\t}\n\t// Recursively normalize object properties\n\tconst result: { [key: string]: unknown } = {};\n\tfor (const [key, value] of Object.entries(input)) {\n\t\tresult[key] = normalizeDecodedValue(value);\n\t}\n\treturn(result);\n}\n\n/**\n * Decode ASN.1 data using a schema\n *\n * Note: The ASN1 library uses dynamic typing internally, so we consolidate\n * the unsafe operations here rather than scattering them throughout the code.\n */\nfunction decodeWithSchema(buffer: ArrayBuffer, schema: unknown): unknown {\n\t/* eslint-disable\n @typescript-eslint/no-explicit-any,\n @typescript-eslint/consistent-type-assertions,\n\t\t@typescript-eslint/no-unsafe-member-access,\n @typescript-eslint/no-unsafe-call,\n\t\t@typescript-eslint/no-unsafe-assignment\n */\n\tlet decodedASN1: ASN1.ASN1AnyJS | undefined;\n\ttry {\n\t\tdecodedASN1 = new (ASN1.BufferStorageASN1 as any)(buffer, schema).getASN1() as ASN1.ASN1AnyJS;\n\t} catch {\n\t\tdecodedASN1 = ASN1.ASN1toJS(buffer);\n\t}\n\tif (decodedASN1 === undefined) {\n\t\tthrow(new Error('Failed to decode ASN1 data'));\n\t}\n\n\tconst validator = new (ASN1.ValidateASN1 as any)(schema);\n\treturn(validator.toJavaScriptObject(decodedASN1));\n\t/* eslint-enable */\n}\n\n/**\n * GCM cipher helpers - Node's crypto types don't properly type getAuthTag/setAuthTag\n * when using createCipheriv/createDecipheriv, so we use typed wrappers.\n */\n/* eslint-disable @typescript-eslint/consistent-type-assertions -- Reflect.get returns unknown */\nfunction getGCMAuthTag(cipher: ReturnType<typeof crypto.createCipheriv>): Buffer {\n\tconst getAuthTag = Reflect.get(cipher, 'getAuthTag') as (() => Buffer) | undefined;\n\tif (typeof getAuthTag !== 'function') {\n\t\tthrow(new TypeError('getAuthTag is not available on cipher'));\n\t}\n\treturn(getAuthTag.call(cipher));\n}\n\nfunction setGCMAuthTag(decipher: ReturnType<typeof crypto.createDecipheriv>, tag: Buffer): void {\n\tconst setAuthTag = Reflect.get(decipher, 'setAuthTag') as ((tag: Buffer) => void) | undefined;\n\tif (typeof setAuthTag !== 'function') {\n\t\tthrow(new TypeError('setAuthTag is not available on decipher'));\n\t}\n\tsetAuthTag.call(decipher, tag);\n}\n/* eslint-enable @typescript-eslint/consistent-type-assertions */\n\n/**\n * Decode a value from its ASN.1 representation back to the original type\n *\n * @internal\n */\nfunction decodeForSensitive(\n\tname: CertificateAttributeNames,\n\tdata: Buffer | ArrayBuffer\n): unknown {\n\tconst buffer = Buffer.isBuffer(data) ? bufferToArrayBuffer(data) : data;\n\tconst schema: unknown = CertificateAttributeSchema[name];\n\tconst plainObject = decodeWithSchema(buffer, schema);\n\treturn(normalizeDecodedValue(plainObject));\n}\n\nexport type SensitiveAttributeJSON = {\n\tversion: string;\n\tpublicKey: string;\n\tcipher: {\n\t\talgorithm: string;\n\t\tiv: string;\n\t\tkey: string;\n\t};\n\thashedValue: {\n\t\tencryptedSalt: string;\n\t\talgorithm: string;\n\t\tvalue: string;\n\t};\n\tencryptedValue: string;\n};\n\nexport class SensitiveAttribute<T = ArrayBuffer> {\n\tprivate static readonly SensitiveAttributeObjectTypeID = 'c0cc9591-cebb-4441-babe-23739279e3f2';\n\tprivate readonly SensitiveAttributeObjectTypeID!: string;\n\n\treadonly #account: KeetaNetAccount;\n\treadonly #encryptedDER: ArrayBuffer;\n\treadonly #info: ReturnType<SensitiveAttribute<T>['decode']>;\n\treadonly #decoder?: (data: Buffer | ArrayBuffer) => T | Promise<T>;\n\n\tconstructor(\n\t\taccount: KeetaNetAccount,\n\t\tdata: Buffer | ArrayBuffer,\n\t\tdecoder?: (data: Buffer | ArrayBuffer) => T | Promise<T>\n\t) {\n\t\tObject.defineProperty(this, 'SensitiveAttributeObjectTypeID', {\n\t\t\tvalue: SensitiveAttribute.SensitiveAttributeObjectTypeID,\n\t\t\tenumerable: false\n\t\t});\n\n\t\tthis.#account = account;\n\t\tthis.#encryptedDER = Buffer.isBuffer(data) ? bufferToArrayBuffer(data) : data;\n\t\tthis.#info = this.decode(data);\n\t\tif (decoder) {\n\t\t\tthis.#decoder = decoder;\n\t\t}\n\t}\n\n\t/**\n\t * Check if a value is a SensitiveAttribute instance\n\t */\n\tstatic isInstance(input: unknown): input is SensitiveAttribute<unknown> {\n\t\tif (typeof input !== 'object' || input === null) {\n\t\t\treturn(false);\n\t\t}\n\n\t\treturn(Reflect.get(input, 'SensitiveAttributeObjectTypeID') === SensitiveAttribute.SensitiveAttributeObjectTypeID);\n\t}\n\n\t/**\n\t * Get the public key this attribute was encrypted for\n\t */\n\tget publicKey(): string {\n\t\treturn(this.#account.publicKeyString.get());\n\t}\n\n\t/**\n\t * Get the raw encrypted DER for certificate embedding\n\t */\n\ttoDER(): ArrayBuffer {\n\t\treturn(this.#encryptedDER);\n\t}\n\n\tprivate decode(data: Buffer | ArrayBuffer) {\n\t\tif (Buffer.isBuffer(data)) {\n\t\t\tdata = bufferToArrayBuffer(data);\n\t\t}\n\n\t\tlet decodedAttribute;\n\t\ttry {\n\t\t\tconst dataObject = new ASN1.BufferStorageASN1(data, SensitiveAttributeSchemaInternal);\n\t\t\tdecodedAttribute = dataObject.getASN1();\n\t\t} catch {\n\t\t\tconst js = ASN1.ASN1toJS(data);\n\t\t\tthrow(new Error(`SensitiveAttribute.decode: unexpected DER shape ${JSON.stringify(DPO(js))}`));\n\t\t}\n\n\t\tconst decodedVersion = decodedAttribute[0] + 1n;\n\t\tif (decodedVersion !== 1n) {\n\t\t\tthrow(new Error(`Unsupported Sensitive Attribute version (${decodedVersion})`));\n\t\t}\n\n\t\treturn({\n\t\t\tversion: decodedVersion,\n\t\t\tpublicKey: this.#account.publicKeyString.get(),\n\t\t\tcipher: {\n\t\t\t\talgorithm: lookupByOID(decodedAttribute[1][0].oid, sensitiveAttributeOIDDB),\n\t\t\t\tiv: decodedAttribute[1][1],\n\t\t\t\tkey: decodedAttribute[1][2]\n\t\t\t},\n\t\t\thashedValue: {\n\t\t\t\tencryptedSalt: decodedAttribute[2][0],\n\t\t\t\talgorithm: lookupByOID(decodedAttribute[2][1].oid, sensitiveAttributeOIDDB),\n\t\t\t\tvalue: decodedAttribute[2][2]\n\t\t\t},\n\t\t\tencryptedValue: decodedAttribute[3]\n\t\t});\n\t}\n\n\tasync #decryptValue(value: Buffer) {\n\t\tconst decryptedKey = await this.#account.decrypt(bufferToArrayBuffer(this.#info.cipher.key));\n\t\tconst algorithm = this.#info.cipher.algorithm;\n\t\tconst iv = this.#info.cipher.iv;\n\n\t\tconst decipher = crypto.createDecipheriv(algorithm, Buffer.from(decryptedKey), iv);\n\n\t\t// For AES-GCM, extract and set the 16-byte authentication tag\n\t\tif (algorithm === 'aes-256-gcm') {\n\t\t\tconst authTag = value.subarray(-16);\n\t\t\tconst ciphertext = value.subarray(0, -16);\n\n\t\t\tsetGCMAuthTag(decipher, authTag);\n\n\t\t\tconst decrypted = decipher.update(ciphertext);\n\t\t\tdecipher.final(); // Verify auth tag\n\t\t\treturn(decrypted);\n\t\t}\n\n\t\t// For other algorithms (like CBC), just decrypt normally\n\t\tconst decrypted = decipher.update(value);\n\t\tdecipher.final();\n\t\treturn(decrypted);\n\t}\n\n\t/**\n\t * Get the value of the sensitive attribute\n\t *\n\t * This will decrypt the value using the account's private key\n\t * and return the value as an ArrayBuffer\n\t *\n\t * Since sensitive attributes are binary blobs, this returns an\n\t * ArrayBuffer\n\t */\n\tasync get(): Promise<ArrayBuffer> {\n\t\tconst decryptedValue = await this.#decryptValue(arrayBufferLikeToBuffer(this.#info.encryptedValue));\n\t\treturn(bufferToArrayBuffer(decryptedValue));\n\t}\n\n\tasync getValue(): Promise<T> {\n\t\tconst value = await this.get();\n\t\tif (!this.#decoder) {\n\t\t\t/**\n\t\t\t * TypeScript complains that T may not be the correct\n\t\t\t * type here, but gives us no tools to enforce that it\n\t\t\t * is -- it should always be ArrayBuffer if no decoder\n\t\t\t * is provided, but someone could always specify a\n\t\t\t * type parameter in that case and we cannot check\n\t\t\t * that at runtime since T is only a compile-time type.\n\t\t\t */\n\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\t\treturn(value as unknown as T);\n\t\t}\n\t\treturn(await this.#decoder(value));\n\t}\n\n\t/**\n\t * Generate a proof that a sensitive attribute is a given value,\n\t * which can be validated by a third party using the certificate\n\t * and the `validateProof` method\n\t */\n\tasync getProof(): Promise<{ value: string; hash: { salt: string }}> {\n\t\tconst value = await this.get();\n\t\tconst salt = await this.#decryptValue(arrayBufferLikeToBuffer(this.#info.hashedValue.encryptedSalt));\n\n\t\treturn({\n\t\t\tvalue: Buffer.from(value).toString('base64'),\n\t\t\thash: {\n\t\t\t\tsalt: salt.toString('base64')\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Validate the proof that a sensitive attribute is a given value\n\t */\n\tasync validateProof(proof: Awaited<ReturnType<this['getProof']>>): Promise<boolean> {\n\t\tconst plaintextValue = Buffer.from(proof.value, 'base64');\n\t\tconst proofSaltBuffer = Buffer.from(proof.hash.salt, 'base64');\n\n\t\tconst publicKeyBuffer = Buffer.from(this.#account.publicKey.get());\n\t\tconst encryptedValue = this.#info.encryptedValue;\n\n\t\tconst hashInput = Buffer.concat([proofSaltBuffer, publicKeyBuffer, encryptedValue, plaintextValue]);\n\t\tconst hashedAndSaltedValue = KeetaNetClient.lib.Utils.Hash.Hash(hashInput);\n\t\tconst hashedAndSaltedValueBuffer = Buffer.from(hashedAndSaltedValue);\n\n\t\treturn(this.#info.hashedValue.value.equals(hashedAndSaltedValueBuffer));\n\t}\n\n\ttoJSON(): SensitiveAttributeJSON {\n\t\tconst info = KeetaNetClient.lib.Utils.Conversion.toJSONSerializable(this.#info);\n\t\treturn(info);\n\t}\n\n\t/**\n\t * Encrypt a value and create a new SensitiveAttribute\n\t */\n\tstatic async create<K extends CertificateAttributeNames>(\n\t\taccount: KeetaNetAccount,\n\t\tname: K,\n\t\tvalue: CertificateAttributeValue<K> | Buffer | ArrayBuffer\n\t): Promise<SensitiveAttribute<CertificateAttributeValue<K>>> {\n\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\tconst encodedValue = encodeForSensitive(name, value as SensitiveAttributeType | Buffer | ArrayBuffer);\n\n\t\tconst salt = crypto.randomBytes(32);\n\n\t\tconst hashingAlgorithm = KeetaNetClient.lib.Utils.Hash.HashFunctionName;\n\t\tconst publicKey = Buffer.from(account.publicKey.get());\n\n\t\tconst cipher = 'aes-256-gcm';\n\t\tconst key = crypto.randomBytes(32);\n\t\tconst nonce = crypto.randomBytes(12);\n\t\tconst encryptedKey = await account.encrypt(bufferToArrayBuffer(key));\n\n\t\tfunction encrypt(input: Buffer) {\n\t\t\tconst cipherObject = crypto.createCipheriv(cipher, key, nonce);\n\t\t\tlet retval = Buffer.concat([cipherObject.update(input), cipherObject.final()]);\n\n\t\t\t// For AES-GCM, append the 16-byte authentication tag\n\t\t\tif (cipher === 'aes-256-gcm') {\n\t\t\t\tretval = Buffer.concat([retval, getGCMAuthTag(cipherObject)]);\n\t\t\t}\n\n\t\t\treturn(retval);\n\t\t}\n\n\t\tconst encryptedValue = encrypt(encodedValue);\n\t\tconst encryptedSalt = encrypt(arrayBufferLikeToBuffer(salt));\n\n\t\tconst saltedValue = Buffer.concat([salt, publicKey, encryptedValue, encodedValue]);\n\t\tconst hashedAndSaltedValue = KeetaNetClient.lib.Utils.Hash.Hash(saltedValue);\n\n\t\tconst attributeStructure: SensitiveAttributeSchema = [\n\t\t\t/* Version */\n\t\t\t0n,\n\t\t\t/* Cipher Details */\n\t\t\t[\n\t\t\t\t/* Algorithm */\n\t\t\t\t{ type: 'oid', oid: getOID(cipher, sensitiveAttributeOIDDB) },\n\t\t\t\t/* IV or Nonce */\n\t\t\t\tnonce,\n\t\t\t\t/* Symmetric key, encrypted with the public key of the account */\n\t\t\t\tBuffer.from(encryptedKey)\n\t\t\t],\n\t\t\t/* Hashed Value */\n\t\t\t[\n\t\t\t\t/* Encrypted Salt */\n\t\t\t\tBuffer.from(encryptedSalt),\n\t\t\t\t/* Hashing Algorithm */\n\t\t\t\t{ type: 'oid', oid: getOID(hashingAlgorithm, sensitiveAttributeOIDDB) },\n\t\t\t\t/* Hash of <Encrypted Salt> || <Public Key> || <Value> */\n\t\t\t\tBuffer.from(hashedAndSaltedValue)\n\t\t\t],\n\t\t\t/* Encrypted Value, encrypted with the Cipher above */\n\t\t\tencryptedValue\n\t\t];\n\n\t\tconst encodedAttributeObject = ASN1.JStoASN1(attributeStructure);\n\t\tconst encryptedDER = encodedAttributeObject.toBER(false);\n\n\t\tconst decoder = function(data: Buffer | ArrayBuffer): CertificateAttributeValue<K> {\n\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\t\treturn(decodeForSensitive(name, data) as CertificateAttributeValue<K>);\n\t\t};\n\n\t\tconst result = new SensitiveAttribute<CertificateAttributeValue<K>>(account, encryptedDER, decoder);\n\t\treturn(result);\n\t}\n}\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface TokenMetadata {
|
|
2
|
+
decimalPlaces: number;
|
|
3
|
+
logoURI?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface TokenMetadataJSON extends Omit<TokenMetadata, "decimalPlaces"> {
|
|
6
|
+
decimalPlaces: number | string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Parse token metadata from a base64-encoded JSON string or a TokenMetadataJSON object, returning a TokenMetadata object.
|
|
10
|
+
* @param encoded the value to parse
|
|
11
|
+
* @returns the parsed TokenMetadata object
|
|
12
|
+
*/
|
|
13
|
+
export declare function decodeTokenMetadata(encoded: string | TokenMetadataJSON | TokenMetadata): TokenMetadata;
|
|
14
|
+
/**
|
|
15
|
+
* Encodes token metadata into a base64-encoded JSON string.
|
|
16
|
+
*
|
|
17
|
+
* @param metadata - The token metadata to encode {@link TokenMetadata}
|
|
18
|
+
* @returns The base64-encoded JSON string containing the token metadata
|
|
19
|
+
*/
|
|
20
|
+
export declare function encodeTokenMetadata(metadata: TokenMetadata | TokenMetadataJSON): string;
|
|
21
|
+
//# sourceMappingURL=token-metadata.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-metadata.d.ts","sourceRoot":"","sources":["../../src/lib/token-metadata.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAGD,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,aAAa,EAAE,eAAe,CAAC;IAC9E,aAAa,EAAE,MAAM,GAAG,MAAM,CAAC;CAC/B;AAgCD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,GAAG,aAAa,GAAG,aAAa,CAYtG;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,aAAa,GAAG,iBAAiB,GAAG,MAAM,CAKvF"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { TokenMetadataJSON } from "./token-metadata.js";
|
|
2
|
+
export declare const parseTokenMetadataJSON: (input: string) => TokenMetadataJSON;
|
|
3
|
+
export declare const stringifyTokenMetadataJSON: (input: TokenMetadataJSON) => string;
|
|
4
|
+
export declare const assertTokenMetadataJSON: (input: unknown) => TokenMetadataJSON;
|
|
5
|
+
//# sourceMappingURL=token-metadata.generated.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-metadata.generated.d.ts","sourceRoot":"","sources":["../../src/lib/token-metadata.generated.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAE7D,eAAO,MAAM,sBAAsB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,iBAA+D,CAAC;AACxH,eAAO,MAAM,0BAA0B,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,MAAkD,CAAC;AAC1H,eAAO,MAAM,uBAAuB,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,iBAAqD,CAAC"}
|