@lumiapassport/ui-kit 1.4.6 → 1.4.8
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/dist/iframe/main.js +1 -1
- package/dist/iframe/main.js.map +1 -1
- package/dist/index.cjs +62 -115
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +58 -111
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -750,41 +750,34 @@ var init_passkey = __esm({
|
|
|
750
750
|
});
|
|
751
751
|
|
|
752
752
|
// src/internal/lib/iframe-mpc-client.ts
|
|
753
|
+
import { logSdkError } from "@lumiapassport/core/internal/error-tracking";
|
|
753
754
|
async function ensureDkgAndGetOwner(userId, _clientSeedHex) {
|
|
754
755
|
try {
|
|
755
|
-
console.info("[IframeMPC][DKG] Starting DKG via iframe for user:", userId);
|
|
756
756
|
const iframeManager = getIframeManager();
|
|
757
757
|
const keyshareStatus = await iframeManager.checkKeyshare(userId);
|
|
758
758
|
if (keyshareStatus.hasKeyshare && keyshareStatus.address) {
|
|
759
|
-
console.info("[IframeMPC][DKG] User already has keyshare in iframe:", {
|
|
760
|
-
userId,
|
|
761
|
-
address: keyshareStatus.address
|
|
762
|
-
});
|
|
763
759
|
return {
|
|
764
760
|
sessionId: "iframe-session",
|
|
765
761
|
ownerAddress: keyshareStatus.address
|
|
766
762
|
};
|
|
767
763
|
}
|
|
768
|
-
console.info("[IframeMPC][DKG] Authenticating user with iframe...");
|
|
769
764
|
await iframeManager.authenticate(userId);
|
|
770
765
|
const { jwtTokenManager: jwtTokenManager3 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
|
|
771
766
|
const accessToken = jwtTokenManager3.getAccessToken();
|
|
772
767
|
if (!accessToken) {
|
|
773
768
|
throw new Error("No access token available for DKG");
|
|
774
769
|
}
|
|
775
|
-
console.info("[IframeMPC][DKG] Starting DKG in iframe...");
|
|
776
770
|
const ownerAddress = await iframeManager.startDKG(userId, accessToken);
|
|
777
|
-
console.info("[IframeMPC][DKG] \u2705 DKG completed successfully:", {
|
|
778
|
-
userId,
|
|
779
|
-
ownerAddress,
|
|
780
|
-
note: "Key share is securely stored in iframe localStorage at auth.lumiapassport.com"
|
|
781
|
-
});
|
|
782
771
|
return {
|
|
783
772
|
sessionId: "iframe-session",
|
|
784
773
|
ownerAddress
|
|
785
774
|
};
|
|
786
775
|
} catch (error) {
|
|
787
|
-
|
|
776
|
+
logSdkError(
|
|
777
|
+
error instanceof Error ? error : new Error("DKG failed"),
|
|
778
|
+
{ userId },
|
|
779
|
+
"iframe-mpc"
|
|
780
|
+
);
|
|
788
781
|
throw error;
|
|
789
782
|
}
|
|
790
783
|
}
|
|
@@ -795,11 +788,6 @@ async function signDigestWithMpc(userId, digest32, userOpDetails) {
|
|
|
795
788
|
rounds: []
|
|
796
789
|
};
|
|
797
790
|
try {
|
|
798
|
-
console.info("[IframeMPC][Sign] Starting signature via iframe:", {
|
|
799
|
-
userId,
|
|
800
|
-
digest32: `${digest32.substring(0, 20)}...`,
|
|
801
|
-
hasDetails: !!userOpDetails
|
|
802
|
-
});
|
|
803
791
|
const iframeManager = getIframeManager();
|
|
804
792
|
const { jwtTokenManager: jwtTokenManager3 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
|
|
805
793
|
const accessToken = jwtTokenManager3.getAccessToken();
|
|
@@ -819,14 +807,13 @@ async function signDigestWithMpc(userId, digest32, userOpDetails) {
|
|
|
819
807
|
const endTime = performance.now();
|
|
820
808
|
currentSigningStats.endTime = endTime;
|
|
821
809
|
currentSigningStats.totalDurationMs = endTime - startTime;
|
|
822
|
-
console.info("[IframeMPC][Sign] \u2705 Signature obtained from iframe:", {
|
|
823
|
-
signature: `${signature.substring(0, 20)}...`,
|
|
824
|
-
duration: `${(endTime - startTime).toFixed(2)}ms`,
|
|
825
|
-
note: "All signing operations happened securely inside iframe"
|
|
826
|
-
});
|
|
827
810
|
return signature;
|
|
828
811
|
} catch (error) {
|
|
829
|
-
|
|
812
|
+
logSdkError(
|
|
813
|
+
error instanceof Error ? error : new Error("MPC signing failed"),
|
|
814
|
+
{ userId, hasUserOpDetails: !!userOpDetails },
|
|
815
|
+
"iframe-mpc"
|
|
816
|
+
);
|
|
830
817
|
const endTime = performance.now();
|
|
831
818
|
if (currentSigningStats) {
|
|
832
819
|
currentSigningStats.endTime = endTime;
|
|
@@ -853,6 +840,7 @@ var init_iframe_mpc_client = __esm({
|
|
|
853
840
|
});
|
|
854
841
|
|
|
855
842
|
// src/internal/clients/httpClient.ts
|
|
843
|
+
import { logSdkError as logSdkError2 } from "@lumiapassport/core/internal/error-tracking";
|
|
856
844
|
function createHttpClient(baseUrl) {
|
|
857
845
|
return new HttpClient(baseUrl);
|
|
858
846
|
}
|
|
@@ -891,14 +879,11 @@ var init_httpClient = __esm({
|
|
|
891
879
|
if (body && method !== "GET") {
|
|
892
880
|
requestConfig.body = typeof body === "string" ? body : JSON.stringify(body);
|
|
893
881
|
}
|
|
894
|
-
console.log(`[HttpClient] Making ${method} request to: ${url}`);
|
|
895
882
|
try {
|
|
896
883
|
const response = await fetch(url, requestConfig);
|
|
897
884
|
if (response.status === 401 && requireAuth) {
|
|
898
|
-
console.log("[HttpClient] Got 401, attempting token refresh...");
|
|
899
885
|
const refreshSuccess = await jwtTokenManager2.refreshAccessToken();
|
|
900
886
|
if (refreshSuccess) {
|
|
901
|
-
console.log("[HttpClient] Token refreshed, retrying request...");
|
|
902
887
|
const newAccessToken = jwtTokenManager2.getAccessToken();
|
|
903
888
|
if (newAccessToken) {
|
|
904
889
|
requestHeaders["Authorization"] = `Bearer ${newAccessToken}`;
|
|
@@ -907,7 +892,6 @@ var init_httpClient = __esm({
|
|
|
907
892
|
const retryResponse = await fetch(url, requestConfig);
|
|
908
893
|
return await this.processResponse(retryResponse);
|
|
909
894
|
} else {
|
|
910
|
-
console.error("[HttpClient] Token refresh failed");
|
|
911
895
|
return {
|
|
912
896
|
success: false,
|
|
913
897
|
error: "Authentication failed - unable to refresh token",
|
|
@@ -917,7 +901,11 @@ var init_httpClient = __esm({
|
|
|
917
901
|
}
|
|
918
902
|
return await this.processResponse(response);
|
|
919
903
|
} catch (error) {
|
|
920
|
-
|
|
904
|
+
logSdkError2(
|
|
905
|
+
error instanceof Error ? error : new Error("Network error"),
|
|
906
|
+
{ url, method },
|
|
907
|
+
"http-client"
|
|
908
|
+
);
|
|
921
909
|
return {
|
|
922
910
|
success: false,
|
|
923
911
|
error: error instanceof Error ? error.message : "Network error",
|
|
@@ -930,7 +918,6 @@ var init_httpClient = __esm({
|
|
|
930
918
|
try {
|
|
931
919
|
const data = await response.json();
|
|
932
920
|
if (!response.ok) {
|
|
933
|
-
console.log(`[HttpClient] Request failed with status ${status}:`, data);
|
|
934
921
|
return {
|
|
935
922
|
success: false,
|
|
936
923
|
error: data.message || data.error || `HTTP ${status}`,
|
|
@@ -938,14 +925,17 @@ var init_httpClient = __esm({
|
|
|
938
925
|
data
|
|
939
926
|
};
|
|
940
927
|
}
|
|
941
|
-
console.log(`[HttpClient] Request successful (${status})`);
|
|
942
928
|
return {
|
|
943
929
|
success: true,
|
|
944
930
|
data,
|
|
945
931
|
status
|
|
946
932
|
};
|
|
947
933
|
} catch (parseError) {
|
|
948
|
-
|
|
934
|
+
logSdkError2(
|
|
935
|
+
parseError instanceof Error ? parseError : new Error("Failed to parse response"),
|
|
936
|
+
{ status },
|
|
937
|
+
"http-client"
|
|
938
|
+
);
|
|
949
939
|
return {
|
|
950
940
|
success: false,
|
|
951
941
|
error: "Invalid response format",
|
|
@@ -1037,11 +1027,9 @@ var init_cloudStorage = __esm({
|
|
|
1037
1027
|
discoveryDocs: [this.DISCOVERY_DOC]
|
|
1038
1028
|
});
|
|
1039
1029
|
this.gapiInitialized = true;
|
|
1040
|
-
console.log("[GoogleDrive] Google API client initialized");
|
|
1041
1030
|
}
|
|
1042
1031
|
if (!this.gisInitialized) {
|
|
1043
1032
|
this.gisInitialized = true;
|
|
1044
|
-
console.log("[GoogleDrive] Google Identity Services initialized");
|
|
1045
1033
|
}
|
|
1046
1034
|
}
|
|
1047
1035
|
loadScript(src) {
|
|
@@ -1080,7 +1068,6 @@ var init_cloudStorage = __esm({
|
|
|
1080
1068
|
}
|
|
1081
1069
|
this.accessToken = response.access_token;
|
|
1082
1070
|
window.gapi.client.setToken({ access_token: this.accessToken });
|
|
1083
|
-
console.log("[GoogleDrive] Successfully authenticated");
|
|
1084
1071
|
resolve(true);
|
|
1085
1072
|
}
|
|
1086
1073
|
});
|
|
@@ -1099,7 +1086,6 @@ var init_cloudStorage = __esm({
|
|
|
1099
1086
|
window.google?.accounts.oauth2.revoke(this.accessToken);
|
|
1100
1087
|
this.accessToken = null;
|
|
1101
1088
|
window.gapi?.client.setToken(null);
|
|
1102
|
-
console.log("[GoogleDrive] Signed out successfully");
|
|
1103
1089
|
}
|
|
1104
1090
|
}
|
|
1105
1091
|
async upload(fileName, content, usePrivateStorage = true) {
|
|
@@ -1110,18 +1096,15 @@ var init_cloudStorage = __esm({
|
|
|
1110
1096
|
if (usePrivateStorage) {
|
|
1111
1097
|
try {
|
|
1112
1098
|
const fileId = await this.uploadToAppDataFolder(fileName, content);
|
|
1113
|
-
console.log("[GoogleDrive] File uploaded to appDataFolder successfully:", fileId);
|
|
1114
1099
|
return fileId;
|
|
1115
1100
|
} catch (error) {
|
|
1116
1101
|
console.warn("[GoogleDrive] AppDataFolder upload failed, trying fallback to regular folder:", error);
|
|
1117
1102
|
const fileId = await this.uploadToAppFolder(fileName, content);
|
|
1118
|
-
console.log("[GoogleDrive] File uploaded to app folder successfully:", fileId);
|
|
1119
1103
|
return fileId;
|
|
1120
1104
|
}
|
|
1121
1105
|
} else {
|
|
1122
1106
|
try {
|
|
1123
1107
|
const fileId = await this.uploadToAppFolder(fileName, content);
|
|
1124
|
-
console.log("[GoogleDrive] File uploaded to app folder successfully:", fileId);
|
|
1125
1108
|
return fileId;
|
|
1126
1109
|
} catch (error) {
|
|
1127
1110
|
console.error("[GoogleDrive] Upload failed:", error);
|
|
@@ -1177,7 +1160,6 @@ var init_cloudStorage = __esm({
|
|
|
1177
1160
|
throw new Error(`Failed to create folder: ${createResponse.status}`);
|
|
1178
1161
|
}
|
|
1179
1162
|
const createResult = await createResponse.json();
|
|
1180
|
-
console.log(`[GoogleDrive] Created folder '${folderName}':`, createResult.id);
|
|
1181
1163
|
return createResult.id;
|
|
1182
1164
|
}
|
|
1183
1165
|
async performUpload(metadata, content) {
|
|
@@ -1232,6 +1214,7 @@ __export(vaultClient_exports, {
|
|
|
1232
1214
|
updateBackupStatus: () => updateBackupStatus,
|
|
1233
1215
|
uploadShare: () => uploadShare
|
|
1234
1216
|
});
|
|
1217
|
+
import { logSdkError as logSdkError3 } from "@lumiapassport/core/internal/error-tracking";
|
|
1235
1218
|
function getBackupEncryptionMethod(backupFile) {
|
|
1236
1219
|
if (backupFile.encryptionMethod) return backupFile.encryptionMethod;
|
|
1237
1220
|
return "unknown";
|
|
@@ -1307,11 +1290,8 @@ async function deleteShare() {
|
|
|
1307
1290
|
if (!response.ok && response.status !== 404) throw new Error(`Failed to delete share: ${response.status} ${response.statusText}`);
|
|
1308
1291
|
}
|
|
1309
1292
|
async function deriveKEKFromPasskey(userId, requiredCredentialId) {
|
|
1310
|
-
console.log("[deriveKEKFromPasskey] Starting passkey derivation for userId:", userId);
|
|
1311
|
-
console.log("[deriveKEKFromPasskey] Required credential ID:", requiredCredentialId);
|
|
1312
1293
|
const challengeString = `lumia-kek:${userId}`;
|
|
1313
1294
|
const challenge = new TextEncoder().encode(challengeString);
|
|
1314
|
-
console.log("[deriveKEKFromPasskey] Challenge string:", challengeString);
|
|
1315
1295
|
function base64urlToUint8Array3(base64url) {
|
|
1316
1296
|
const base64 = base64url.replace(/-/g, "+").replace(/_/g, "/");
|
|
1317
1297
|
const pad = base64.length % 4 ? 4 - base64.length % 4 : 0;
|
|
@@ -1324,14 +1304,8 @@ async function deriveKEKFromPasskey(userId, requiredCredentialId) {
|
|
|
1324
1304
|
return bytes;
|
|
1325
1305
|
}
|
|
1326
1306
|
const targetCredentialId = requiredCredentialId || createPasskeyHelpers(userId).getCredId();
|
|
1327
|
-
console.log("[deriveKEKFromPasskey] Target credential ID:", targetCredentialId);
|
|
1328
1307
|
const allowCredentials = targetCredentialId ? [{ id: base64urlToUint8Array3(targetCredentialId), type: "public-key" }] : [];
|
|
1329
|
-
console.log("[deriveKEKFromPasskey] Using allowCredentials:", allowCredentials.length > 0 ? "specific credential" : "any credential");
|
|
1330
|
-
if (!targetCredentialId) {
|
|
1331
|
-
console.warn("[deriveKEKFromPasskey] Warning: No credential ID available. User must select the correct passkey manually.");
|
|
1332
|
-
}
|
|
1333
1308
|
try {
|
|
1334
|
-
console.log("[deriveKEKFromPasskey] Calling navigator.credentials.get...");
|
|
1335
1309
|
const credential = await navigator.credentials.get({
|
|
1336
1310
|
publicKey: {
|
|
1337
1311
|
challenge,
|
|
@@ -1340,27 +1314,22 @@ async function deriveKEKFromPasskey(userId, requiredCredentialId) {
|
|
|
1340
1314
|
extensions: { prf: { eval: { first: challenge } } }
|
|
1341
1315
|
}
|
|
1342
1316
|
});
|
|
1343
|
-
console.log("[deriveKEKFromPasskey] Credential received:", !!credential);
|
|
1344
1317
|
if (credential) {
|
|
1345
|
-
console.log("[deriveKEKFromPasskey] Credential ID:", credential.id);
|
|
1346
|
-
console.log("[deriveKEKFromPasskey] Credential ID length:", credential.id.length);
|
|
1347
1318
|
const extensionResults = credential.getClientExtensionResults?.();
|
|
1348
|
-
console.log("[deriveKEKFromPasskey] Extension results:", extensionResults);
|
|
1349
1319
|
if (extensionResults?.prf?.results?.first) {
|
|
1350
|
-
console.log("[deriveKEKFromPasskey] PRF result found, returning KEK");
|
|
1351
|
-
console.log("[deriveKEKFromPasskey] PRF result length:", extensionResults.prf.results.first.byteLength);
|
|
1352
1320
|
return extensionResults.prf.results.first;
|
|
1353
1321
|
}
|
|
1354
1322
|
}
|
|
1355
|
-
console.log("[deriveKEKFromPasskey] No PRF result, falling back to HKDF...");
|
|
1356
1323
|
const credentialIdBytes = new TextEncoder().encode(credential.id);
|
|
1357
|
-
console.log("[deriveKEKFromPasskey] Credential ID length:", credential.id.length);
|
|
1358
1324
|
const keyMaterial = await crypto.subtle.importKey("raw", credentialIdBytes, "HKDF", false, ["deriveBits"]);
|
|
1359
1325
|
const kekBytes = await crypto.subtle.deriveBits({ name: "HKDF", hash: "SHA-256", salt: challenge, info: new TextEncoder().encode("client-share") }, keyMaterial, 256);
|
|
1360
|
-
console.log("[deriveKEKFromPasskey] HKDF fallback completed successfully");
|
|
1361
1326
|
return kekBytes;
|
|
1362
1327
|
} catch (error) {
|
|
1363
|
-
|
|
1328
|
+
logSdkError3(
|
|
1329
|
+
error instanceof Error ? error : new Error("Passkey operation failed"),
|
|
1330
|
+
{ userId },
|
|
1331
|
+
"vault"
|
|
1332
|
+
);
|
|
1364
1333
|
throw error;
|
|
1365
1334
|
}
|
|
1366
1335
|
}
|
|
@@ -1445,7 +1414,6 @@ async function deriveBackupPasswordFromPasskey(userId, credentialId) {
|
|
|
1445
1414
|
type: "public-key",
|
|
1446
1415
|
transports: ["internal", "hybrid"]
|
|
1447
1416
|
}];
|
|
1448
|
-
console.log("[deriveBackupPasswordFromPasskey] Using specific credential ID:", credentialId);
|
|
1449
1417
|
} catch (error) {
|
|
1450
1418
|
console.warn("[deriveBackupPasswordFromPasskey] Failed to parse credentialId, falling back to open selection:", error);
|
|
1451
1419
|
}
|
|
@@ -1525,7 +1493,6 @@ async function downloadShareFromVault(token) {
|
|
|
1525
1493
|
async function envelopeEncryptKeyshare(data, userId) {
|
|
1526
1494
|
const passkeyHelpers = createPasskeyHelpers(userId);
|
|
1527
1495
|
const credentialId = passkeyHelpers.getCredId();
|
|
1528
|
-
console.log("[envelopeEncryptKeyshare] Using credential ID for encryption:", credentialId);
|
|
1529
1496
|
const dek = crypto.getRandomValues(new Uint8Array(32));
|
|
1530
1497
|
const kekBytes = await deriveKEKFromPasskey(userId);
|
|
1531
1498
|
const kek = await crypto.subtle.importKey("raw", kekBytes, "AES-GCM", false, ["encrypt"]);
|
|
@@ -1557,7 +1524,6 @@ async function envelopeEncryptKeyshare(data, userId) {
|
|
|
1557
1524
|
};
|
|
1558
1525
|
}
|
|
1559
1526
|
async function envelopeEncryptKeyshareWithPassword(data, password) {
|
|
1560
|
-
console.log("[envelopeEncryptKeyshareWithPassword] Encrypting with password");
|
|
1561
1527
|
const dek = crypto.getRandomValues(new Uint8Array(32));
|
|
1562
1528
|
const salt = crypto.getRandomValues(new Uint8Array(16));
|
|
1563
1529
|
const kekKey = await deriveKeyFromPassword(password, salt);
|
|
@@ -1588,39 +1554,27 @@ async function envelopeEncryptKeyshareWithPassword(data, password) {
|
|
|
1588
1554
|
};
|
|
1589
1555
|
}
|
|
1590
1556
|
async function envelopeDecryptKeyshare(envelope, userId) {
|
|
1591
|
-
console.log("[envelopeDecryptKeyshare] Starting decryption process");
|
|
1592
|
-
console.log("[envelopeDecryptKeyshare] Envelope credential ID:", envelope.credentialId);
|
|
1593
|
-
console.log("[envelopeDecryptKeyshare] Deriving KEK from passkey...");
|
|
1594
1557
|
const kekBytes = await deriveKEKFromPasskey(userId, envelope.credentialId);
|
|
1595
|
-
console.log("[envelopeDecryptKeyshare] KEK bytes length:", kekBytes.byteLength);
|
|
1596
|
-
console.log("[envelopeDecryptKeyshare] Importing KEK as crypto key...");
|
|
1597
1558
|
const kek = await crypto.subtle.importKey("raw", kekBytes, "AES-GCM", false, ["decrypt"]);
|
|
1598
|
-
console.log("[envelopeDecryptKeyshare] Decrypting wrapped DEK...");
|
|
1599
1559
|
const wrappedDekWithIv = base64ToBytes(envelope.wrapped_dek);
|
|
1600
|
-
console.log("[envelopeDecryptKeyshare] Wrapped DEK with IV length:", wrappedDekWithIv.length);
|
|
1601
1560
|
const wrapIv = wrappedDekWithIv.slice(0, 12);
|
|
1602
1561
|
const wrappedDekData = wrappedDekWithIv.slice(12);
|
|
1603
|
-
console.log("[envelopeDecryptKeyshare] Wrap IV length:", wrapIv.length, "Wrapped DEK data length:", wrappedDekData.length);
|
|
1604
1562
|
try {
|
|
1605
1563
|
const dekBytes = await crypto.subtle.decrypt({ name: "AES-GCM", iv: wrapIv }, kek, wrappedDekData);
|
|
1606
|
-
console.log("[envelopeDecryptKeyshare] DEK decrypted successfully, length:", dekBytes.byteLength);
|
|
1607
|
-
console.log("[envelopeDecryptKeyshare] Importing DEK as crypto key...");
|
|
1608
1564
|
const dekCryptoKey = await crypto.subtle.importKey("raw", dekBytes, "AES-GCM", false, ["decrypt"]);
|
|
1609
|
-
console.log("[envelopeDecryptKeyshare] Decrypting main data...");
|
|
1610
1565
|
const ciphertextWithIv = base64ToBytes(envelope.ciphertext_share);
|
|
1611
|
-
console.log("[envelopeDecryptKeyshare] Ciphertext with IV length:", ciphertextWithIv.length);
|
|
1612
1566
|
const dataIv = ciphertextWithIv.slice(0, 12);
|
|
1613
1567
|
const encryptedData = ciphertextWithIv.slice(12);
|
|
1614
|
-
console.log("[envelopeDecryptKeyshare] Data IV length:", dataIv.length, "Encrypted data length:", encryptedData.length);
|
|
1615
1568
|
const decryptedData = await crypto.subtle.decrypt({ name: "AES-GCM", iv: dataIv }, dekCryptoKey, encryptedData);
|
|
1616
|
-
console.log("[envelopeDecryptKeyshare] Main data decrypted successfully, length:", decryptedData.byteLength);
|
|
1617
|
-
console.log("[envelopeDecryptKeyshare] Parsing JSON...");
|
|
1618
1569
|
const plaintext = new TextDecoder().decode(decryptedData);
|
|
1619
1570
|
const result = JSON.parse(plaintext);
|
|
1620
|
-
console.log("[envelopeDecryptKeyshare] Decryption completed successfully");
|
|
1621
1571
|
return result;
|
|
1622
1572
|
} catch (error) {
|
|
1623
|
-
|
|
1573
|
+
logSdkError3(
|
|
1574
|
+
error instanceof Error ? error : new Error("Envelope decryption failed"),
|
|
1575
|
+
{ hasCredentialId: !!envelope.credentialId },
|
|
1576
|
+
"vault"
|
|
1577
|
+
);
|
|
1624
1578
|
if (error instanceof Error && error.name === "OperationError") {
|
|
1625
1579
|
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";
|
|
1626
1580
|
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.`);
|
|
@@ -1629,28 +1583,27 @@ async function envelopeDecryptKeyshare(envelope, userId) {
|
|
|
1629
1583
|
}
|
|
1630
1584
|
}
|
|
1631
1585
|
async function envelopeDecryptKeyshareWithPassword(envelope, password) {
|
|
1632
|
-
console.log("[envelopeDecryptKeyshareWithPassword] Starting password-based decryption");
|
|
1633
1586
|
const wrappedDekWithSaltAndIv = base64ToBytes(envelope.wrapped_dek);
|
|
1634
1587
|
const salt = wrappedDekWithSaltAndIv.slice(0, 16);
|
|
1635
1588
|
const wrapIv = wrappedDekWithSaltAndIv.slice(16, 28);
|
|
1636
1589
|
const wrappedDekData = wrappedDekWithSaltAndIv.slice(28);
|
|
1637
|
-
console.log("[envelopeDecryptKeyshareWithPassword] Salt length:", salt.length, "Wrap IV length:", wrapIv.length, "Wrapped DEK data length:", wrappedDekData.length);
|
|
1638
1590
|
try {
|
|
1639
1591
|
const kekKey = await deriveKeyFromPassword(password, salt);
|
|
1640
1592
|
const dekBytes = await crypto.subtle.decrypt({ name: "AES-GCM", iv: wrapIv }, kekKey, wrappedDekData);
|
|
1641
|
-
console.log("[envelopeDecryptKeyshareWithPassword] DEK decrypted successfully, length:", dekBytes.byteLength);
|
|
1642
1593
|
const dekCryptoKey = await crypto.subtle.importKey("raw", dekBytes, "AES-GCM", false, ["decrypt"]);
|
|
1643
1594
|
const ciphertextWithIv = base64ToBytes(envelope.ciphertext_share);
|
|
1644
1595
|
const dataIv = ciphertextWithIv.slice(0, 12);
|
|
1645
1596
|
const encryptedData = ciphertextWithIv.slice(12);
|
|
1646
1597
|
const decryptedData = await crypto.subtle.decrypt({ name: "AES-GCM", iv: dataIv }, dekCryptoKey, encryptedData);
|
|
1647
|
-
console.log("[envelopeDecryptKeyshareWithPassword] Main data decrypted successfully");
|
|
1648
1598
|
const plaintext = new TextDecoder().decode(decryptedData);
|
|
1649
1599
|
const result = JSON.parse(plaintext);
|
|
1650
|
-
console.log("[envelopeDecryptKeyshareWithPassword] Decryption completed successfully");
|
|
1651
1600
|
return result;
|
|
1652
1601
|
} catch (error) {
|
|
1653
|
-
|
|
1602
|
+
logSdkError3(
|
|
1603
|
+
error instanceof Error ? error : new Error("Password decryption failed"),
|
|
1604
|
+
{ errorName: error instanceof Error ? error.name : "unknown" },
|
|
1605
|
+
"vault"
|
|
1606
|
+
);
|
|
1654
1607
|
if (error instanceof Error && error.name === "OperationError") {
|
|
1655
1608
|
throw new Error("Incorrect password: Unable to decrypt the backup with the provided password.");
|
|
1656
1609
|
}
|
|
@@ -1670,22 +1623,15 @@ async function backupToServer(userId, password) {
|
|
|
1670
1623
|
updateBackupStatus(userId, "server", { enabled: true, lastBackup: Date.now(), error: void 0 });
|
|
1671
1624
|
}
|
|
1672
1625
|
async function restoreFromServer(userId, password = null) {
|
|
1673
|
-
console.log("[restoreFromServer] Starting restore for userId:", userId);
|
|
1674
|
-
console.log("[restoreFromServer] Using password:", !!password);
|
|
1675
|
-
console.log("[restoreFromServer] Getting vault token...");
|
|
1676
1626
|
const vaultToken = await getShareVaultToken(["share:get"]);
|
|
1677
|
-
console.log("[restoreFromServer] Downloading share from vault...");
|
|
1678
1627
|
const envelope = await downloadShareFromVault(vaultToken.token);
|
|
1679
|
-
console.log("[restoreFromServer] Envelope encryption method:", envelope.encryptionMethod);
|
|
1680
1628
|
const backupData = password ? await envelopeDecryptKeyshareWithPassword(envelope, password) : await envelopeDecryptKeyshare(envelope, userId);
|
|
1681
1629
|
if (backupData.userId !== userId) throw new Error("Server backup does not match current user");
|
|
1682
1630
|
const storage = typeof window !== "undefined" ? window.localStorage : void 0;
|
|
1683
1631
|
if (!storage) throw new Error("localStorage not available");
|
|
1684
|
-
console.log("[restoreFromServer] Saving keyshare to localStorage...");
|
|
1685
1632
|
storage.setItem(`tss.${userId}.keyshare`, backupData.keyshare);
|
|
1686
1633
|
storage.setItem(`tss.${userId}.sessionId`, backupData.sessionId);
|
|
1687
1634
|
storage.setItem(`tss.${userId}.ownerAddress`, backupData.ownerAddress);
|
|
1688
|
-
console.log("[restoreFromServer] Restore completed successfully");
|
|
1689
1635
|
}
|
|
1690
1636
|
async function restoreFromBackup(file, password, userId) {
|
|
1691
1637
|
const fileContent = await file.text();
|
|
@@ -1731,7 +1677,11 @@ function getCurrentKeyshareBackupData(userId) {
|
|
|
1731
1677
|
version: BACKUP_VERSION
|
|
1732
1678
|
};
|
|
1733
1679
|
} catch (error) {
|
|
1734
|
-
|
|
1680
|
+
logSdkError3(
|
|
1681
|
+
error instanceof Error ? error : new Error("Failed to get keyshare data"),
|
|
1682
|
+
{ userId },
|
|
1683
|
+
"vault"
|
|
1684
|
+
);
|
|
1735
1685
|
return null;
|
|
1736
1686
|
}
|
|
1737
1687
|
}
|
|
@@ -1751,7 +1701,6 @@ async function backupToLocalFile(userId, password) {
|
|
|
1751
1701
|
});
|
|
1752
1702
|
backupPassword = result.password;
|
|
1753
1703
|
credentialId = result.credentialId;
|
|
1754
|
-
console.log("[backupToLocalFile] Using credential ID from passkey:", credentialId);
|
|
1755
1704
|
}
|
|
1756
1705
|
const encryptedBackup = await encryptKeyshare(backupData, backupPassword, encryptionMethod, credentialId);
|
|
1757
1706
|
const fileName = `lumia-keyshare-backup-${userId}-${Date.now()}.json`;
|
|
@@ -1784,7 +1733,6 @@ async function backupToCloud(userId, password, providerId, usePrivateStorage = t
|
|
|
1784
1733
|
});
|
|
1785
1734
|
backupPassword = result.password;
|
|
1786
1735
|
credentialId = result.credentialId;
|
|
1787
|
-
console.log("[backupToCloud] Using credential ID from passkey:", credentialId);
|
|
1788
1736
|
}
|
|
1789
1737
|
const encryptedBackup = await encryptKeyshare(backupData, backupPassword, encryptionMethod, credentialId);
|
|
1790
1738
|
const timestamp = Date.now();
|
|
@@ -1815,9 +1763,12 @@ async function backupToCloud(userId, password, providerId, usePrivateStorage = t
|
|
|
1815
1763
|
console.info(`[BACKUP] Uploading backup to ${provider.name}`);
|
|
1816
1764
|
const fileId = await provider.upload(fileName, fileContent, usePrivateStorage);
|
|
1817
1765
|
updateBackupStatus(userId, "cloud", { enabled: true, lastBackup: timestamp, error: void 0 });
|
|
1818
|
-
console.info(`[BACKUP] Successfully uploaded backup to ${provider.name}, file ID: ${fileId}`);
|
|
1819
1766
|
} catch (error) {
|
|
1820
|
-
|
|
1767
|
+
logSdkError3(
|
|
1768
|
+
error instanceof Error ? error : new Error("Cloud backup failed"),
|
|
1769
|
+
{ userId, providerId },
|
|
1770
|
+
"vault"
|
|
1771
|
+
);
|
|
1821
1772
|
const errorMsg = error instanceof Error ? error.message : "Cloud backup failed";
|
|
1822
1773
|
updateBackupStatus(userId, "cloud", { error: errorMsg });
|
|
1823
1774
|
throw new Error(errorMsg);
|
|
@@ -2960,6 +2911,7 @@ var init_iframe_manager = __esm({
|
|
|
2960
2911
|
|
|
2961
2912
|
// src/context/LumiaPassportContext.tsx
|
|
2962
2913
|
import { createContext, useCallback, useContext, useEffect, useState } from "react";
|
|
2914
|
+
import { initSdkErrorTracking } from "@lumiapassport/core/internal/error-tracking";
|
|
2963
2915
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
2964
2916
|
var LumiaPassportContext, LumiaPassportProvider, useLumiaPassportConfig;
|
|
2965
2917
|
var init_LumiaPassportContext = __esm({
|
|
@@ -3025,6 +2977,13 @@ var init_LumiaPassportContext = __esm({
|
|
|
3025
2977
|
}
|
|
3026
2978
|
} catch {
|
|
3027
2979
|
}
|
|
2980
|
+
try {
|
|
2981
|
+
initSdkErrorTracking();
|
|
2982
|
+
} catch (error) {
|
|
2983
|
+
if (process.env.NODE_ENV === "development") {
|
|
2984
|
+
console.warn("[LumiaPassport] Failed to initialize SDK error tracking:", error);
|
|
2985
|
+
}
|
|
2986
|
+
}
|
|
3028
2987
|
return merged;
|
|
3029
2988
|
});
|
|
3030
2989
|
const updateConfig = useCallback((updates) => {
|
|
@@ -4091,25 +4050,19 @@ var init_VerificationCodeInput = __esm({
|
|
|
4091
4050
|
|
|
4092
4051
|
// src/internal/clients/profile.ts
|
|
4093
4052
|
async function getUserProfile() {
|
|
4094
|
-
console.log("[ProfileClient] Fetching user profile...");
|
|
4095
4053
|
const response = await tssClient.get("/api/auth/profile", true);
|
|
4096
4054
|
if (!response.success || !response.data) {
|
|
4097
4055
|
const error = response.error || "Failed to fetch user profile";
|
|
4098
|
-
console.error("[ProfileClient] Failed to fetch profile:", error);
|
|
4099
4056
|
throw new Error(error);
|
|
4100
4057
|
}
|
|
4101
|
-
console.log("[ProfileClient] Profile fetched successfully:", response.data);
|
|
4102
4058
|
return response.data;
|
|
4103
4059
|
}
|
|
4104
4060
|
async function updateUserProfile(updates) {
|
|
4105
|
-
console.log("[ProfileClient] Updating user profile:", updates);
|
|
4106
4061
|
const response = await tssClient.patch("/api/auth/profile", updates, true);
|
|
4107
4062
|
if (!response.success || !response.data) {
|
|
4108
4063
|
const error = response.error || "Failed to update user profile";
|
|
4109
|
-
console.error("[ProfileClient] Failed to update profile:", error);
|
|
4110
4064
|
throw new Error(error);
|
|
4111
4065
|
}
|
|
4112
|
-
console.log("[ProfileClient] Profile updated successfully:", response.data);
|
|
4113
4066
|
return response.data;
|
|
4114
4067
|
}
|
|
4115
4068
|
var init_profile = __esm({
|
|
@@ -5293,10 +5246,7 @@ async function sendUserOperation(session, callTarget, amountWei, innerData = "0x
|
|
|
5293
5246
|
paymasterAndData = `0x${paymasterAddr}${packedPaymasterGasLimits.slice(2)}${paymasterDataClean}`;
|
|
5294
5247
|
}
|
|
5295
5248
|
const packedForHash = { sender: session.smartAccountAddress, nonce: BigInt(nonce2), initCode, callData, accountGasLimits, preVerificationGas: BigInt(userOp.preVerificationGas), gasFees, paymasterAndData, signature: "0x" };
|
|
5296
|
-
console.log("[Account] Computing hash for signing with sender:", session.smartAccountAddress);
|
|
5297
|
-
console.log("[Account] PackedForHash for hash computation:", JSON.stringify(packedForHash, (key, value) => typeof value === "bigint" ? `0x${value.toString(16)}` : value, 2));
|
|
5298
5249
|
opHash = await publicClient.readContract({ address: entryPointAddress, abi: entryPoint07Abi, functionName: "getUserOpHash", args: [packedForHash] });
|
|
5299
|
-
console.log("[Account] \u{1F511} HASH FOR SIGNING:", opHash);
|
|
5300
5250
|
}
|
|
5301
5251
|
let signature;
|
|
5302
5252
|
if (session.mpcUserId) {
|
|
@@ -5324,10 +5274,8 @@ async function sendUserOperation(session, callTarget, amountWei, innerData = "0x
|
|
|
5324
5274
|
}
|
|
5325
5275
|
userOp.signature = signature;
|
|
5326
5276
|
if (typeof userOp.sender !== "string") {
|
|
5327
|
-
console.error("[Account] CRITICAL ERROR: userOp.sender is not a string!", userOp.sender);
|
|
5328
5277
|
userOp.sender = session.smartAccountAddress;
|
|
5329
5278
|
}
|
|
5330
|
-
console.log("[Account] \u2705 Final UserOp before sending:", JSON.stringify(userOp, (key, value) => typeof value === "bigint" ? `0x${value.toString(16)}` : value, 2));
|
|
5331
5279
|
return userOp;
|
|
5332
5280
|
};
|
|
5333
5281
|
try {
|
|
@@ -5542,8 +5490,6 @@ async function prepareUserOperation(session, callTarget, amountWei, innerData =
|
|
|
5542
5490
|
if (typeof userOp.sender !== "string") {
|
|
5543
5491
|
userOp.sender = session.smartAccountAddress;
|
|
5544
5492
|
}
|
|
5545
|
-
console.log("[Account] \u2705 Prepared signed UserOp (not sent):", JSON.stringify(userOp, (key, value) => typeof value === "bigint" ? `0x${value.toString(16)}` : value, 2));
|
|
5546
|
-
console.log("[Account] \u{1F511} UserOp Hash:", opHash);
|
|
5547
5493
|
if (entryPointVersion === "v0.6") {
|
|
5548
5494
|
const userOpV06 = convertUserOpV07ToV06(userOp);
|
|
5549
5495
|
return { userOp: userOpV06, userOpHash: opHash };
|
|
@@ -8566,7 +8512,7 @@ function useLumiaPassportLinkedProfiles() {
|
|
|
8566
8512
|
// package.json
|
|
8567
8513
|
var package_default = {
|
|
8568
8514
|
name: "@lumiapassport/ui-kit",
|
|
8569
|
-
version: "1.4.
|
|
8515
|
+
version: "1.4.8",
|
|
8570
8516
|
description: "React UI components and hooks for Lumia Passport authentication and Account Abstraction",
|
|
8571
8517
|
type: "module",
|
|
8572
8518
|
main: "./dist/index.cjs",
|
|
@@ -8617,6 +8563,7 @@ var package_default = {
|
|
|
8617
8563
|
dependencies: {
|
|
8618
8564
|
"@lumiapassport/core": "workspace:*",
|
|
8619
8565
|
"@rainbow-me/rainbowkit": "^2.2.8",
|
|
8566
|
+
"@sentry/browser": "^10.22.0",
|
|
8620
8567
|
"lucide-react": "^0.454.0",
|
|
8621
8568
|
qrcode: "^1.5.0"
|
|
8622
8569
|
},
|