@embarkai/ui-kit 0.3.3 → 0.3.4

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.
@@ -15,7 +15,7 @@
15
15
  <meta http-equiv="X-Content-Type-Options" content="nosniff" />
16
16
  <meta http-equiv="Referrer-Policy" content="strict-origin-when-cross-origin" />
17
17
 
18
- <title>EmbarkAI Secure Wallet - iframe version 0.3.3</title>
18
+ <title>EmbarkAI Secure Wallet - iframe version 0.3.4</title>
19
19
 
20
20
  <!-- Styles will be injected by build process -->
21
21
  <style>
@@ -165,8 +165,19 @@ async function encryptKeyshare(data, password, encryptionMethod, credentialId) {
165
165
  credentialId: encryptionMethod === "passkey" ? credentialId : void 0
166
166
  };
167
167
  }
168
+ function serializeAadWithKeyOrder(aad, keyOrder) {
169
+ const ordered = {};
170
+ for (const key of keyOrder) {
171
+ if (key in aad) ordered[key] = aad[key];
172
+ }
173
+ return new TextEncoder().encode(JSON.stringify(ordered));
174
+ }
168
175
  function serializeAad(aad) {
169
- return new TextEncoder().encode(JSON.stringify(aad));
176
+ const sorted = Object.keys(aad).sort().reduce((obj, key) => {
177
+ obj[key] = aad[key];
178
+ return obj;
179
+ }, {});
180
+ return new TextEncoder().encode(JSON.stringify(sorted));
170
181
  }
171
182
  async function envelopeEncryptKeyshare(data, userId) {
172
183
  const { kek: kekBytes, credentialId } = await deriveKEKFromPasskey(userId);
@@ -241,39 +252,47 @@ async function envelopeDecryptKeyshare(envelope, userId) {
241
252
  console.log("[iframe][envelopeDecryptKeyshare] Importing KEK as crypto key...");
242
253
  const kek = await crypto.subtle.importKey("raw", kekBytes, "AES-GCM", false, ["decrypt"]);
243
254
  const useAad = envelope.aad?.version >= 2;
244
- const aadBytes = useAad ? serializeAad(envelope.aad) : void 0;
245
255
  console.log("[iframe][envelopeDecryptKeyshare] Decrypting wrapped DEK...");
246
256
  const wrappedDekWithIv = base64ToBytes(envelope.wrapped_dek);
247
257
  console.log("[iframe][envelopeDecryptKeyshare] Wrapped DEK with IV length:", wrappedDekWithIv.length);
248
258
  const wrapIv = wrappedDekWithIv.slice(0, 12);
249
259
  const wrappedDekData = wrappedDekWithIv.slice(12);
250
260
  console.log("[iframe][envelopeDecryptKeyshare] Wrap IV length:", wrapIv.length, "Wrapped DEK data length:", wrappedDekData.length);
251
- try {
252
- const dekBytes = await crypto.subtle.decrypt({ name: "AES-GCM", iv: wrapIv, ...aadBytes && { additionalData: aadBytes } }, kek, wrappedDekData);
253
- console.log("[iframe][envelopeDecryptKeyshare] DEK decrypted successfully, length:", dekBytes.byteLength);
254
- console.log("[iframe][envelopeDecryptKeyshare] Importing DEK as crypto key...");
255
- const dekCryptoKey = await crypto.subtle.importKey("raw", dekBytes, "AES-GCM", false, ["decrypt"]);
256
- console.log("[iframe][envelopeDecryptKeyshare] Decrypting main data...");
257
- const ciphertextWithIv = base64ToBytes(envelope.ciphertext_share);
258
- console.log("[iframe][envelopeDecryptKeyshare] Ciphertext with IV length:", ciphertextWithIv.length);
259
- const dataIv = ciphertextWithIv.slice(0, 12);
260
- const encryptedData = ciphertextWithIv.slice(12);
261
- console.log("[iframe][envelopeDecryptKeyshare] Data IV length:", dataIv.length, "Encrypted data length:", encryptedData.length);
262
- const decryptedData = await crypto.subtle.decrypt({ name: "AES-GCM", iv: dataIv, ...aadBytes && { additionalData: aadBytes } }, dekCryptoKey, encryptedData);
263
- console.log("[iframe][envelopeDecryptKeyshare] Main data decrypted successfully, length:", decryptedData.byteLength);
264
- console.log("[iframe][envelopeDecryptKeyshare] Parsing JSON...");
265
- const plaintext = new TextDecoder().decode(decryptedData);
266
- const result = JSON.parse(plaintext);
267
- console.log("[iframe][envelopeDecryptKeyshare] Decryption completed successfully");
268
- return result;
269
- } catch (error) {
270
- console.error("[iframe][envelopeDecryptKeyshare] Decryption failed:", error);
271
- if (error instanceof Error && error.name === "OperationError") {
272
- const credentialHint = envelope.credentialId ? `The backup requires a specific passkey (ID: ${envelope.credentialId.slice(-8)}...)` : "The backup was encrypted with a different passkey than the one you selected";
273
- throw new Error(`Passkey mismatch: ${credentialHint}. If you have multiple passkeys, please try again and select the correct passkey that was used when creating this backup.`);
261
+ const aadCandidates = useAad ? [serializeAad(envelope.aad), serializeAadWithKeyOrder(envelope.aad, LEGACY_V2_KEY_ORDER)] : [void 0];
262
+ let lastError;
263
+ for (const aadBytes of aadCandidates) {
264
+ try {
265
+ const dekBytes = await crypto.subtle.decrypt({ name: "AES-GCM", iv: wrapIv, ...aadBytes && { additionalData: aadBytes } }, kek, wrappedDekData);
266
+ console.log("[iframe][envelopeDecryptKeyshare] DEK decrypted successfully, length:", dekBytes.byteLength);
267
+ console.log("[iframe][envelopeDecryptKeyshare] Importing DEK as crypto key...");
268
+ const dekCryptoKey = await crypto.subtle.importKey("raw", dekBytes, "AES-GCM", false, ["decrypt"]);
269
+ console.log("[iframe][envelopeDecryptKeyshare] Decrypting main data...");
270
+ const ciphertextWithIv = base64ToBytes(envelope.ciphertext_share);
271
+ console.log("[iframe][envelopeDecryptKeyshare] Ciphertext with IV length:", ciphertextWithIv.length);
272
+ const dataIv = ciphertextWithIv.slice(0, 12);
273
+ const encryptedData = ciphertextWithIv.slice(12);
274
+ console.log("[iframe][envelopeDecryptKeyshare] Data IV length:", dataIv.length, "Encrypted data length:", encryptedData.length);
275
+ const decryptedData = await crypto.subtle.decrypt({ name: "AES-GCM", iv: dataIv, ...aadBytes && { additionalData: aadBytes } }, dekCryptoKey, encryptedData);
276
+ console.log("[iframe][envelopeDecryptKeyshare] Main data decrypted successfully, length:", decryptedData.byteLength);
277
+ console.log("[iframe][envelopeDecryptKeyshare] Parsing JSON...");
278
+ const plaintext = new TextDecoder().decode(decryptedData);
279
+ const result = JSON.parse(plaintext);
280
+ console.log("[iframe][envelopeDecryptKeyshare] Decryption completed successfully");
281
+ return result;
282
+ } catch (error) {
283
+ lastError = error;
284
+ if (error instanceof Error && error.name === "OperationError" && aadCandidates.indexOf(aadBytes) < aadCandidates.length - 1) {
285
+ console.log("[iframe][envelopeDecryptKeyshare] AAD mismatch, trying fallback key order...");
286
+ continue;
287
+ }
274
288
  }
275
- throw new Error("Failed to decrypt keyshare: " + (error instanceof Error ? error.message : String(error)));
276
289
  }
290
+ console.error("[iframe][envelopeDecryptKeyshare] Decryption failed:", lastError);
291
+ if (lastError instanceof Error && lastError.name === "OperationError") {
292
+ const credentialHint = envelope.credentialId ? `The backup requires a specific passkey (ID: ${envelope.credentialId.slice(-8)}...)` : "The backup was encrypted with a different passkey than the one you selected";
293
+ throw new Error(`Passkey mismatch: ${credentialHint}. If you have multiple passkeys, please try again and select the correct passkey that was used when creating this backup.`);
294
+ }
295
+ throw new Error("Failed to decrypt keyshare: " + (lastError instanceof Error ? lastError.message : String(lastError)));
277
296
  }
278
297
  async function envelopeDecryptKeyshareWithPassword(envelope, password) {
279
298
  console.log("[iframe][envelopeDecryptKeyshareWithPassword] Starting password-based decryption");
@@ -282,29 +301,37 @@ async function envelopeDecryptKeyshareWithPassword(envelope, password) {
282
301
  const wrapIv = wrappedDekWithSaltAndIv.slice(16, 28);
283
302
  const wrappedDekData = wrappedDekWithSaltAndIv.slice(28);
284
303
  const useAad = envelope.aad?.version >= 2;
285
- const aadBytes = useAad ? serializeAad(envelope.aad) : void 0;
286
304
  console.log("[iframe][envelopeDecryptKeyshareWithPassword] Salt length:", salt.length, "Wrap IV length:", wrapIv.length, "Wrapped DEK data length:", wrappedDekData.length);
287
- try {
288
- const kekKey = await deriveKeyFromPassword(password, salt);
289
- const dekBytes = await crypto.subtle.decrypt({ name: "AES-GCM", iv: wrapIv, ...aadBytes && { additionalData: aadBytes } }, kekKey, wrappedDekData);
290
- console.log("[iframe][envelopeDecryptKeyshareWithPassword] DEK decrypted successfully, length:", dekBytes.byteLength);
291
- const dekCryptoKey = await crypto.subtle.importKey("raw", dekBytes, "AES-GCM", false, ["decrypt"]);
292
- const ciphertextWithIv = base64ToBytes(envelope.ciphertext_share);
293
- const dataIv = ciphertextWithIv.slice(0, 12);
294
- const encryptedData = ciphertextWithIv.slice(12);
295
- const decryptedData = await crypto.subtle.decrypt({ name: "AES-GCM", iv: dataIv, ...aadBytes && { additionalData: aadBytes } }, dekCryptoKey, encryptedData);
296
- console.log("[iframe][envelopeDecryptKeyshareWithPassword] Main data decrypted successfully");
297
- const plaintext = new TextDecoder().decode(decryptedData);
298
- const result = JSON.parse(plaintext);
299
- console.log("[iframe][envelopeDecryptKeyshareWithPassword] Decryption completed successfully");
300
- return result;
301
- } catch (error) {
302
- console.error("[iframe][envelopeDecryptKeyshareWithPassword] Decryption failed:", error);
303
- if (error instanceof Error && error.name === "OperationError") {
304
- throw new Error("Incorrect password: Unable to decrypt the backup with the provided password.");
305
+ const aadCandidates = useAad ? [serializeAad(envelope.aad), serializeAadWithKeyOrder(envelope.aad, LEGACY_V2_KEY_ORDER)] : [void 0];
306
+ let lastError;
307
+ for (const aadBytes of aadCandidates) {
308
+ try {
309
+ const kekKey = await deriveKeyFromPassword(password, salt);
310
+ const dekBytes = await crypto.subtle.decrypt({ name: "AES-GCM", iv: wrapIv, ...aadBytes && { additionalData: aadBytes } }, kekKey, wrappedDekData);
311
+ console.log("[iframe][envelopeDecryptKeyshareWithPassword] DEK decrypted successfully, length:", dekBytes.byteLength);
312
+ const dekCryptoKey = await crypto.subtle.importKey("raw", dekBytes, "AES-GCM", false, ["decrypt"]);
313
+ const ciphertextWithIv = base64ToBytes(envelope.ciphertext_share);
314
+ const dataIv = ciphertextWithIv.slice(0, 12);
315
+ const encryptedData = ciphertextWithIv.slice(12);
316
+ const decryptedData = await crypto.subtle.decrypt({ name: "AES-GCM", iv: dataIv, ...aadBytes && { additionalData: aadBytes } }, dekCryptoKey, encryptedData);
317
+ console.log("[iframe][envelopeDecryptKeyshareWithPassword] Main data decrypted successfully");
318
+ const plaintext = new TextDecoder().decode(decryptedData);
319
+ const result = JSON.parse(plaintext);
320
+ console.log("[iframe][envelopeDecryptKeyshareWithPassword] Decryption completed successfully");
321
+ return result;
322
+ } catch (error) {
323
+ lastError = error;
324
+ if (error instanceof Error && error.name === "OperationError" && aadCandidates.indexOf(aadBytes) < aadCandidates.length - 1) {
325
+ console.log("[iframe][envelopeDecryptKeyshareWithPassword] AAD mismatch, trying fallback key order...");
326
+ continue;
327
+ }
305
328
  }
306
- throw new Error("Failed to decrypt keyshare with password: " + (error instanceof Error ? error.message : String(error)));
307
329
  }
330
+ console.error("[iframe][envelopeDecryptKeyshareWithPassword] Decryption failed:", lastError);
331
+ if (lastError instanceof Error && lastError.name === "OperationError") {
332
+ throw new Error("Incorrect password: Unable to decrypt the backup with the provided password.");
333
+ }
334
+ throw new Error("Failed to decrypt keyshare with password: " + (lastError instanceof Error ? lastError.message : String(lastError)));
308
335
  }
309
336
  async function decryptKeyshare(encryptedBackup, password) {
310
337
  console.log("[iframe][decryptKeyshare] Starting file backup decryption");
@@ -379,8 +406,10 @@ async function decryptKeyshare(encryptedBackup, password) {
379
406
  throw new Error(`Failed to decrypt backup: ${message}`);
380
407
  }
381
408
  }
409
+ var LEGACY_V2_KEY_ORDER;
382
410
  var init_crypto_utils = __esm({
383
411
  "src/iframe/lib/backup/crypto-utils.ts"() {
412
+ LEGACY_V2_KEY_ORDER = ["userId", "version", "deviceId"];
384
413
  }
385
414
  });
386
415
 
@@ -4410,7 +4439,7 @@ var SigningManager = class extends TokenRefreshApiClient {
4410
4439
  };
4411
4440
 
4412
4441
  // src/iframe/main.ts
4413
- var IFRAME_VERSION = "0.3.3";
4442
+ var IFRAME_VERSION = "0.3.4";
4414
4443
  var IframeWallet = class {
4415
4444
  constructor() {
4416
4445
  console.log("=".repeat(60));