@idos-network/enclave 1.1.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.
- package/LICENSE +21 -0
- package/README.md +50 -0
- package/dist/base-0xSNl4rW.d.mts +140 -0
- package/dist/base-0xSNl4rW.d.mts.map +1 -0
- package/dist/client-BSkUuHYm.mjs +1196 -0
- package/dist/client-BSkUuHYm.mjs.map +1 -0
- package/dist/client-Bu0aO5sT.d.mts +38 -0
- package/dist/client-Bu0aO5sT.d.mts.map +1 -0
- package/dist/index.d.mts +16 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +2 -0
- package/dist/keys-RuC1M-_K.mjs +187 -0
- package/dist/keys-RuC1M-_K.mjs.map +1 -0
- package/dist/local.d.mts +96 -0
- package/dist/local.d.mts.map +1 -0
- package/dist/local.mjs +253 -0
- package/dist/local.mjs.map +1 -0
- package/dist/mpc/index.d.mts +3 -0
- package/dist/mpc/index.mjs +2 -0
- package/dist/types-DKsOwtWL.d.mts +73 -0
- package/dist/types-DKsOwtWL.d.mts.map +1 -0
- package/package.json +76 -0
- package/src/base.test.ts +137 -0
- package/src/base.ts +306 -0
- package/src/index.ts +3 -0
- package/src/keys.ts +10 -0
- package/src/local.test.ts +113 -0
- package/src/local.ts +495 -0
- package/src/mpc/api.ts +122 -0
- package/src/mpc/client.ts +411 -0
- package/src/mpc/engine-client.ts +144 -0
- package/src/mpc/generated/IdosContract.ts +92 -0
- package/src/mpc/index.ts +2 -0
- package/src/mpc/secretsharing/f256.ts +122 -0
- package/src/mpc/secretsharing/finite-field-element.ts +50 -0
- package/src/mpc/secretsharing/lagrange.ts +163 -0
- package/src/mpc/secretsharing/polynomial.ts +84 -0
- package/src/mpc/secretsharing/secret-share-factory.ts +30 -0
- package/src/mpc/secretsharing/secret-shares.ts +20 -0
- package/src/mpc/secretsharing/shamir-secret-shares.ts +164 -0
- package/src/mpc/secretsharing/xor-secret-shares.ts +68 -0
- package/src/mpc/types.ts +117 -0
- package/src/types.ts +37 -0
package/src/base.ts
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import type { idOSCredential } from "@idos-network/credentials/types";
|
|
2
|
+
|
|
3
|
+
import { recordFilter } from "@idos-network/credentials/utils";
|
|
4
|
+
import { base64Decode, fromBytesToJson, hexEncode } from "@idos-network/utils/codecs";
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
AddAddressMessageToSign,
|
|
8
|
+
AddAddressSignatureMessage,
|
|
9
|
+
RemoveAddressMessageToSign,
|
|
10
|
+
RemoveAddressSignatureMessage,
|
|
11
|
+
} from "./mpc/types";
|
|
12
|
+
import type { EnclaveOptions, PublicEncryptionProfile } from "./types";
|
|
13
|
+
|
|
14
|
+
export abstract class BaseProvider<K extends EnclaveOptions = EnclaveOptions> {
|
|
15
|
+
readonly options: K;
|
|
16
|
+
|
|
17
|
+
// oxlint-disable-next-line typescript/no-explicit-any -- TODO: Change this when we know how to MPC & other chains
|
|
18
|
+
protected _signMethod?: (domain: any, types: any, value: any) => Promise<string>;
|
|
19
|
+
private _signMethodType?: "signTypedData" | "signMessage" | "signer";
|
|
20
|
+
|
|
21
|
+
constructor(options: K) {
|
|
22
|
+
this.options = options;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Sets the signer for the enclave.
|
|
27
|
+
*
|
|
28
|
+
* @param signer - The signer to set, is later used for MPC if allowed.
|
|
29
|
+
*/
|
|
30
|
+
setSigner(signer: {
|
|
31
|
+
signTypedData?: (domain: string, types: string[], value: string) => Promise<string>;
|
|
32
|
+
// oxlint-disable-next-line typescript/no-explicit-any -- TODO: Change this when we know how to MPC & other chains
|
|
33
|
+
signMessage?: (message: string) => Promise<any>;
|
|
34
|
+
// oxlint-disable-next-line typescript/no-explicit-any -- TODO: Change this when we know how to MPC & other chains
|
|
35
|
+
signer?: (message: string) => Promise<any>;
|
|
36
|
+
}): void {
|
|
37
|
+
if (signer.signTypedData) {
|
|
38
|
+
// EVM wallet
|
|
39
|
+
this._signMethod = signer.signTypedData.bind(signer);
|
|
40
|
+
this._signMethodType = "signTypedData";
|
|
41
|
+
} else if (signer.signMessage) {
|
|
42
|
+
// XRPL wallet
|
|
43
|
+
this._signMethod = signer.signMessage.bind(signer);
|
|
44
|
+
this._signMethodType = "signMessage";
|
|
45
|
+
} else if (signer.signer) {
|
|
46
|
+
// Stellar wallet
|
|
47
|
+
this._signMethod = signer.signer.bind(signer);
|
|
48
|
+
this._signMethodType = "signer";
|
|
49
|
+
} else {
|
|
50
|
+
if (["signMessage", "signer"].some((key) => key in signer)) {
|
|
51
|
+
this._signMethod = signer.signMessage
|
|
52
|
+
? // @ts-expect-error - signMessage for xrpl and near, signer for stellar
|
|
53
|
+
signer.signMessage.bind(signer)
|
|
54
|
+
: // @ts-expect-error - signMessage for xrpl and near, signer for stellar
|
|
55
|
+
signer.signer?.bind(signer);
|
|
56
|
+
} else {
|
|
57
|
+
throw new Error("No sign method found in passed signer");
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// oxlint-disable-next-line typescript/no-explicit-any -- TODO: Change this when we know how to MPC & other chains
|
|
63
|
+
async signTypedData(domain: any, types: any, value: any): Promise<string> {
|
|
64
|
+
if (!this._signMethod || !this._signMethodType) {
|
|
65
|
+
throw new Error("Signer is not set");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let signature: string;
|
|
69
|
+
|
|
70
|
+
// Handle different signing methods based on wallet type
|
|
71
|
+
if (this._signMethodType === "signTypedData") {
|
|
72
|
+
// EVM wallets: use all 3 arguments
|
|
73
|
+
signature =
|
|
74
|
+
await // oxlint-disable-next-line typescript/no-explicit-any -- TODO: Change this when we know how to MPC & other chains
|
|
75
|
+
(this._signMethod as (domain: any, types: any, value: any) => Promise<string>)(
|
|
76
|
+
domain,
|
|
77
|
+
types,
|
|
78
|
+
value,
|
|
79
|
+
);
|
|
80
|
+
} else if (this._signMethodType === "signMessage" || this._signMethodType === "signer") {
|
|
81
|
+
// XRPL/NEAR/Stellar/FaceSign wallets: use only the value as message
|
|
82
|
+
const messageString = JSON.stringify(value);
|
|
83
|
+
// oxlint-disable-next-line typescript/no-explicit-any -- TODO: Change this when we know how to MPC & other chains
|
|
84
|
+
const response = await (this._signMethod as (message: any) => Promise<any>)(messageString);
|
|
85
|
+
|
|
86
|
+
// Extract signature from response object
|
|
87
|
+
if (typeof response === "string") {
|
|
88
|
+
signature = response;
|
|
89
|
+
} else if (response?.result?.signedMessage) {
|
|
90
|
+
signature = response.result.signedMessage;
|
|
91
|
+
} else if (response?.signedMessage) {
|
|
92
|
+
signature = response.signedMessage;
|
|
93
|
+
} else if (response instanceof Uint8Array && response.length === 64) {
|
|
94
|
+
// ed25519 signature size
|
|
95
|
+
return hexEncode(response);
|
|
96
|
+
} else {
|
|
97
|
+
throw new Error(
|
|
98
|
+
`Unexpected response format from ${this._signMethodType}: ${JSON.stringify(response)}`,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
} else {
|
|
102
|
+
throw new Error(`Unknown sign method type: ${this._signMethodType}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return signature;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Helper method to get the user ID.
|
|
110
|
+
*
|
|
111
|
+
* @returns The user ID.
|
|
112
|
+
*/
|
|
113
|
+
get userId(): string {
|
|
114
|
+
if (!this.options.userId) {
|
|
115
|
+
throw new Error("User ID is not present");
|
|
116
|
+
}
|
|
117
|
+
return this.options.userId;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Resets the enclave (storage etc.)
|
|
122
|
+
*/
|
|
123
|
+
async reset(): Promise<void> {
|
|
124
|
+
// Implement this if needed in child classes
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Reconfigures the enclave (theme etc).
|
|
129
|
+
*
|
|
130
|
+
* @param options - The options to reconfigure.
|
|
131
|
+
*/
|
|
132
|
+
async reconfigure(options: Partial<K> = {}): Promise<void> {
|
|
133
|
+
Object.assign(this.options, options);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Loads the enclave (create iframe, open connection, etc.)
|
|
138
|
+
*/
|
|
139
|
+
async load(): Promise<void> {
|
|
140
|
+
await this.reconfigure();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Encrypts a message to a receiver.
|
|
145
|
+
* This method also checks if the user is authorized to use the keys.
|
|
146
|
+
*
|
|
147
|
+
* @param _message - The message to encrypt.
|
|
148
|
+
* @param _receiverPublicKey - The public key of the receiver.
|
|
149
|
+
*
|
|
150
|
+
* @returns The encrypted message.
|
|
151
|
+
*/
|
|
152
|
+
async encrypt(
|
|
153
|
+
_message: Uint8Array,
|
|
154
|
+
_receiverPublicKey: Uint8Array,
|
|
155
|
+
): Promise<{ content: Uint8Array; encryptorPublicKey: Uint8Array }> {
|
|
156
|
+
throw new Error("Method 'encrypt' has to be implemented in the subclass.");
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Decrypts a message from a sender.
|
|
161
|
+
* This method also checks if the user is authorized to use the keys.
|
|
162
|
+
*
|
|
163
|
+
* @param _message - The message to decrypt.
|
|
164
|
+
* @param _senderPublicKey - The public key of the sender.
|
|
165
|
+
*
|
|
166
|
+
* @returns The decrypted message.
|
|
167
|
+
*/
|
|
168
|
+
async decrypt(
|
|
169
|
+
_message: Uint8Array,
|
|
170
|
+
_senderPublicKey: Uint8Array,
|
|
171
|
+
): Promise<Uint8Array<ArrayBufferLike>> {
|
|
172
|
+
throw new Error("Method 'decrypt' has to be implemented in the subclass.");
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* This method is used to confirm the user action.
|
|
177
|
+
*
|
|
178
|
+
* @param _message - The message to confirm.
|
|
179
|
+
*
|
|
180
|
+
* @returns `true` if the user action is confirmed, `false` otherwise.
|
|
181
|
+
*/
|
|
182
|
+
async confirm(_message: string): Promise<boolean> {
|
|
183
|
+
throw new Error("Method 'confirm' has to be implemented in the subclass.");
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* This method is used to backup the password context.
|
|
188
|
+
*/
|
|
189
|
+
async backupUserEncryptionProfile(): Promise<void> {
|
|
190
|
+
throw new Error("Method 'backupUserEncryptionProfile' has to be implemented in the subclass.");
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Gets the public encryption profile.
|
|
195
|
+
*
|
|
196
|
+
* @returns The public encryption profile.
|
|
197
|
+
*/
|
|
198
|
+
async ensureUserEncryptionProfile(): Promise<PublicEncryptionProfile> {
|
|
199
|
+
throw new Error("Method 'ensureUserEncryptionProfile' has to be implemented in the subclass.");
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* This method authorizes the origin in case of enclave
|
|
204
|
+
* to use the keys, without user providing the password or MPC again.
|
|
205
|
+
*
|
|
206
|
+
* @returns `true` if the user action is authorized, `false` otherwise.
|
|
207
|
+
*/
|
|
208
|
+
async guardKeys(): Promise<boolean> {
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Filters the credentials based on the private field filters.
|
|
214
|
+
*
|
|
215
|
+
* @param credentials - The credentials to filter.
|
|
216
|
+
* @param privateFieldFilters - The private field filters.
|
|
217
|
+
*
|
|
218
|
+
* @returns The filtered credentials without the content.
|
|
219
|
+
*/
|
|
220
|
+
async filterCredentials(
|
|
221
|
+
credentials: idOSCredential[],
|
|
222
|
+
privateFieldFilters: { pick: Record<string, unknown[]>; omit: Record<string, unknown[]> },
|
|
223
|
+
): Promise<idOSCredential[]> {
|
|
224
|
+
if (
|
|
225
|
+
Object.keys(privateFieldFilters.pick).length === 0 &&
|
|
226
|
+
Object.keys(privateFieldFilters.omit).length === 0
|
|
227
|
+
) {
|
|
228
|
+
// No filtering needed
|
|
229
|
+
return credentials.map((credential) => ({
|
|
230
|
+
...credential,
|
|
231
|
+
content: "", // Content should never leave the enclave!!!
|
|
232
|
+
}));
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// We need to be sure first that we have the encryption profile
|
|
236
|
+
// otherwise we can end up with a lot of signatures for each credential
|
|
237
|
+
await this.ensureUserEncryptionProfile();
|
|
238
|
+
|
|
239
|
+
const decrypted = await Promise.all(
|
|
240
|
+
credentials.map(async (credential: idOSCredential) => {
|
|
241
|
+
const content = await this.decrypt(
|
|
242
|
+
base64Decode(credential.content),
|
|
243
|
+
base64Decode(credential.encryptor_public_key),
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
let json: Record<string, unknown>;
|
|
247
|
+
|
|
248
|
+
try {
|
|
249
|
+
json = fromBytesToJson(content);
|
|
250
|
+
} catch (_e) {
|
|
251
|
+
throw new Error(`Credential ${credential.id} decrypted contents are not valid JSON`);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
...credential,
|
|
256
|
+
content: json,
|
|
257
|
+
};
|
|
258
|
+
}),
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
return decrypted
|
|
262
|
+
.filter(({ content }) =>
|
|
263
|
+
recordFilter(
|
|
264
|
+
content as Record<string, unknown>,
|
|
265
|
+
privateFieldFilters.pick,
|
|
266
|
+
privateFieldFilters.omit,
|
|
267
|
+
),
|
|
268
|
+
)
|
|
269
|
+
.map((credential) => ({
|
|
270
|
+
...credential,
|
|
271
|
+
content: "", // Content should never leave the enclave!!!
|
|
272
|
+
}));
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async addAddressMessageToSign(
|
|
276
|
+
_address: string,
|
|
277
|
+
_publicKey: string | undefined,
|
|
278
|
+
_addressToAddType: string,
|
|
279
|
+
): Promise<AddAddressMessageToSign> {
|
|
280
|
+
throw new Error("Method 'addAddressMessageToSign' has to be implemented in the subclass.");
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
async removeAddressMessageToSign(
|
|
284
|
+
_address: string,
|
|
285
|
+
_publicKey: string | undefined,
|
|
286
|
+
_addressToRemoveType: string,
|
|
287
|
+
): Promise<RemoveAddressMessageToSign> {
|
|
288
|
+
throw new Error("Method 'removeAddressMessageToSign' has to be implemented in the subclass.");
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
async addAddressToMpcSecret(
|
|
292
|
+
_userId: string,
|
|
293
|
+
_message: AddAddressSignatureMessage,
|
|
294
|
+
_signature: string,
|
|
295
|
+
): Promise<string> {
|
|
296
|
+
throw new Error("Method 'addAddressToMpcSecret' has to be implemented in the subclass.");
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
async removeAddressFromMpcSecret(
|
|
300
|
+
_userId: string,
|
|
301
|
+
_message: RemoveAddressSignatureMessage,
|
|
302
|
+
_signature: string,
|
|
303
|
+
): Promise<string> {
|
|
304
|
+
throw new Error("Method 'removeAddressFromMpcSecret' has to be implemented in the subclass.");
|
|
305
|
+
}
|
|
306
|
+
}
|
package/src/index.ts
ADDED
package/src/keys.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const STORAGE_KEYS = {
|
|
2
|
+
DEPRECATED___ENCRYPTION_PRIVATE_KEY: "encryption-private-key",
|
|
3
|
+
DEPRECATED___ENCRYPTION_SECRET_KEY: "encryption-secret-key",
|
|
4
|
+
OBFUSCATED_BASE64_ENCRYPTION_SECRET_KEY: "obfuscated-base64-encryption-secret-key",
|
|
5
|
+
ENCRYPTION_PUBLIC_KEY: "encryption-public-key",
|
|
6
|
+
DEPRECATED___PASSWORD: "password",
|
|
7
|
+
OBFUSCATED_PASSWORD: "obfuscated-password",
|
|
8
|
+
USER_ID: "user-id",
|
|
9
|
+
ENCRYPTION_PASSWORD_STORE: "encryption-password-store",
|
|
10
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { idOSCredential } from "@idos-network/credentials/types";
|
|
2
|
+
|
|
3
|
+
import { base64Decode, base64Encode, utf8Encode } from "@idos-network/utils/codecs";
|
|
4
|
+
import { encryptContent } from "@idos-network/utils/cryptography";
|
|
5
|
+
import { MemoryStore } from "@idos-network/utils/store";
|
|
6
|
+
import tweetnacl from "tweetnacl";
|
|
7
|
+
import { describe, expect, it, vi } from "vitest";
|
|
8
|
+
|
|
9
|
+
import { LocalEnclave, type LocalEnclaveOptions } from "./local.js";
|
|
10
|
+
|
|
11
|
+
class TestEnclave extends LocalEnclave {
|
|
12
|
+
async getPasswordContext() {
|
|
13
|
+
return {
|
|
14
|
+
encryptionPasswordStore: "user",
|
|
15
|
+
password: "super-secret",
|
|
16
|
+
duration: 1,
|
|
17
|
+
} as const;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe("LocalEnclave", () => {
|
|
22
|
+
const userId = "9f51b3b2-4cbe-4c2b-8ea3-0b0c1b2f1a11";
|
|
23
|
+
|
|
24
|
+
it("creates and exposes a public encryption profile", async () => {
|
|
25
|
+
const store = new MemoryStore();
|
|
26
|
+
const enclave = new TestEnclave({ userId, store } as LocalEnclaveOptions);
|
|
27
|
+
|
|
28
|
+
const profile = await enclave.createEncryptionProfileFromPassword(
|
|
29
|
+
"super-secret",
|
|
30
|
+
userId,
|
|
31
|
+
"user",
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
expect(profile.userId).toBe(userId);
|
|
35
|
+
expect(profile.encryptionPasswordStore).toBe("user");
|
|
36
|
+
|
|
37
|
+
const publicProfile = await enclave.ensureUserEncryptionProfile();
|
|
38
|
+
const publicKeyBytes = base64Decode(publicProfile.userEncryptionPublicKey);
|
|
39
|
+
|
|
40
|
+
expect(publicProfile.userId).toBe(userId);
|
|
41
|
+
expect(publicProfile.encryptionPasswordStore).toBe("user");
|
|
42
|
+
expect(publicKeyBytes).toHaveLength(32);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("encrypts and decrypts with its keypair", async () => {
|
|
46
|
+
const store = new MemoryStore();
|
|
47
|
+
const enclave = new TestEnclave({ userId, store } as LocalEnclaveOptions);
|
|
48
|
+
const { keyPair } = await enclave.getPrivateEncryptionProfile();
|
|
49
|
+
|
|
50
|
+
const message = new Uint8Array([1, 2, 3, 4]);
|
|
51
|
+
const { content, encryptorPublicKey } = await enclave.encrypt(message, keyPair.publicKey);
|
|
52
|
+
const decrypted = await enclave.decrypt(content, encryptorPublicKey);
|
|
53
|
+
|
|
54
|
+
expect(decrypted).toEqual(message);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("filters credentials and strips content", async () => {
|
|
58
|
+
const store = new MemoryStore();
|
|
59
|
+
const enclave = new TestEnclave({ userId, store });
|
|
60
|
+
const { keyPair } = await enclave.getPrivateEncryptionProfile();
|
|
61
|
+
|
|
62
|
+
// Reset enclave locals
|
|
63
|
+
// @ts-expect-error This is fine, it's a custom method simulates the private encryption profile
|
|
64
|
+
enclave.storedEncryptionProfile = undefined;
|
|
65
|
+
|
|
66
|
+
const matches = { type: "kyc", level: "basic" };
|
|
67
|
+
const misses = { type: "aml", level: "basic" };
|
|
68
|
+
|
|
69
|
+
const ephemeralKeyPair = tweetnacl.box.keyPair();
|
|
70
|
+
|
|
71
|
+
const matchesEncryption = encryptContent(
|
|
72
|
+
utf8Encode(JSON.stringify(matches)),
|
|
73
|
+
keyPair.publicKey,
|
|
74
|
+
ephemeralKeyPair.secretKey,
|
|
75
|
+
);
|
|
76
|
+
const missesEncryption = encryptContent(
|
|
77
|
+
utf8Encode(JSON.stringify(misses)),
|
|
78
|
+
keyPair.publicKey,
|
|
79
|
+
ephemeralKeyPair.secretKey,
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const passwordContextSpy = vi.spyOn(enclave, "getPasswordContext");
|
|
83
|
+
|
|
84
|
+
const credentials: idOSCredential[] = [
|
|
85
|
+
{
|
|
86
|
+
id: "cred-1",
|
|
87
|
+
user_id: "user-1",
|
|
88
|
+
public_notes: "{}",
|
|
89
|
+
content: base64Encode(matchesEncryption),
|
|
90
|
+
encryptor_public_key: base64Encode(ephemeralKeyPair.publicKey),
|
|
91
|
+
issuer_auth_public_key: "issuer",
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: "cred-2",
|
|
95
|
+
user_id: "user-1",
|
|
96
|
+
public_notes: "{}",
|
|
97
|
+
content: base64Encode(missesEncryption),
|
|
98
|
+
encryptor_public_key: base64Encode(ephemeralKeyPair.publicKey),
|
|
99
|
+
issuer_auth_public_key: "issuer",
|
|
100
|
+
},
|
|
101
|
+
];
|
|
102
|
+
|
|
103
|
+
const filtered = await enclave.filterCredentials(credentials, {
|
|
104
|
+
pick: { type: ["kyc"] },
|
|
105
|
+
omit: {},
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
expect(filtered).toHaveLength(1);
|
|
109
|
+
expect(filtered[0]?.id).toBe("cred-1");
|
|
110
|
+
expect(filtered[0]?.content).toBe("");
|
|
111
|
+
expect(passwordContextSpy).toHaveBeenCalledTimes(1);
|
|
112
|
+
});
|
|
113
|
+
});
|