@embarkai/ui-kit 0.4.25 → 0.4.27
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/index.html +2 -2
- package/dist/iframe/main.js +298 -171
- package/dist/index.cjs +29318 -6
- package/dist/index.d.cts +329 -197
- package/dist/index.d.ts +329 -197
- package/dist/index.js +29229 -86
- package/dist/styles.css +1 -1
- package/package.json +34 -41
- package/dist/auth-GP4VPOSM.js +0 -115
- package/dist/auth-LTJ6Z736.cjs +0 -115
- package/dist/chunk-7G3OIJGJ.js +0 -1091
- package/dist/chunk-B254FLAW.cjs +0 -1515
- package/dist/chunk-DACL62OU.cjs +0 -29
- package/dist/chunk-DBFKMKYT.js +0 -29
- package/dist/chunk-MLUPZCC3.js +0 -1515
- package/dist/chunk-NES46LXF.cjs +0 -1091
- package/dist/chunk-YVHXT2JX.cjs +0 -20193
- package/dist/chunk-YW3BCDPE.js +0 -20193
- package/dist/clients-IMZKL3HS.js +0 -78
- package/dist/clients-MCQWHPWS.cjs +0 -78
- package/dist/cloudStorage-SXE7HVID.cjs +0 -207
- package/dist/cloudStorage-WASWQ4KL.js +0 -207
- package/dist/hyperbridge-4LS4PDRE.cjs +0 -980
- package/dist/hyperbridge-ISLQLJ65.js +0 -980
- package/dist/iframe-manager-AHR3NZ5R.js +0 -14
- package/dist/iframe-manager-UB24HCDP.cjs +0 -14
- package/dist/passkey-NPYNRJ6E.js +0 -19
- package/dist/passkey-OBANL6DX.cjs +0 -13
- package/dist/passkey-QB5LNGMI.js +0 -13
- package/dist/passkey-XK3KFDCF.cjs +0 -19
- package/dist/profile-DDV24U6Z.js +0 -14
- package/dist/profile-GSUE4MDA.cjs +0 -14
- package/dist/vaultClient-MWKJKXZC.js +0 -50
- package/dist/vaultClient-UDM5MCO6.cjs +0 -50
package/dist/chunk-MLUPZCC3.js
DELETED
|
@@ -1,1515 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
__esm,
|
|
3
|
-
__export,
|
|
4
|
-
__toCommonJS
|
|
5
|
-
} from "./chunk-DBFKMKYT.js";
|
|
6
|
-
|
|
7
|
-
// src/config/assets.tsx
|
|
8
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
-
var GoogleIcon, TelegramIcon, TwitterIcon, DiscordIcon;
|
|
10
|
-
var init_assets = __esm({
|
|
11
|
-
"src/config/assets.tsx"() {
|
|
12
|
-
GoogleIcon = ({ className }) => /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", className, children: [
|
|
13
|
-
/* @__PURE__ */ jsx(
|
|
14
|
-
"path",
|
|
15
|
-
{
|
|
16
|
-
fill: "#4285F4",
|
|
17
|
-
d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
|
|
18
|
-
}
|
|
19
|
-
),
|
|
20
|
-
/* @__PURE__ */ jsx(
|
|
21
|
-
"path",
|
|
22
|
-
{
|
|
23
|
-
fill: "#34A853",
|
|
24
|
-
d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
|
|
25
|
-
}
|
|
26
|
-
),
|
|
27
|
-
/* @__PURE__ */ jsx(
|
|
28
|
-
"path",
|
|
29
|
-
{
|
|
30
|
-
fill: "#FBBC05",
|
|
31
|
-
d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
|
|
32
|
-
}
|
|
33
|
-
),
|
|
34
|
-
/* @__PURE__ */ jsx(
|
|
35
|
-
"path",
|
|
36
|
-
{
|
|
37
|
-
fill: "#EA4335",
|
|
38
|
-
d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
|
|
39
|
-
}
|
|
40
|
-
)
|
|
41
|
-
] });
|
|
42
|
-
TelegramIcon = ({ className }) => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className, fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M9.78 18.65l.28-4.23 7.68-6.92c.34-.31-.07-.46-.52-.19L7.74 13.3 3.64 12c-.88-.25-.89-.86.2-1.3l15.97-6.16c.73-.33 1.43.18 1.15 1.3l-2.72 12.81c-.19.91-.74 1.13-1.5.71L12.6 16.3l-1.99 1.93c-.23.23-.42.42-.83.42z" }) });
|
|
43
|
-
TwitterIcon = ({ className }) => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className, fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" }) });
|
|
44
|
-
DiscordIcon = ({ className }) => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className, children: /* @__PURE__ */ jsx(
|
|
45
|
-
"path",
|
|
46
|
-
{
|
|
47
|
-
fill: "currentColor",
|
|
48
|
-
d: "M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515a.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0a12.64 12.64 0 0 0-.617-1.25a.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057a19.9 19.9 0 0 0 5.993 3.03a.078.078 0 0 0 .084-.028a14.09 14.09 0 0 0 1.226-1.994a.076.076 0 0 0-.041-.106a13.107 13.107 0 0 1-1.872-.892a.077.077 0 0 1-.008-.128a10.2 10.2 0 0 0 .372-.292a.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127a12.299 12.299 0 0 1-1.873.892a.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028a19.839 19.839 0 0 0 6.002-3.03a.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.956-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.955-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.946 2.418-2.157 2.418Z"
|
|
49
|
-
}
|
|
50
|
-
) });
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
// src/config/initial.tsx
|
|
55
|
-
var initial_exports = {};
|
|
56
|
-
__export(initial_exports, {
|
|
57
|
-
DEFAULT_PROVIDER_CONFIG: () => DEFAULT_PROVIDER_CONFIG,
|
|
58
|
-
getBlockscoutApiUrl: () => getBlockscoutApiUrl,
|
|
59
|
-
getIframeUrl: () => getIframeUrl,
|
|
60
|
-
getServiceUrls: () => getServiceUrls
|
|
61
|
-
});
|
|
62
|
-
import { BSC_TESTNET } from "@embarkai/core/read";
|
|
63
|
-
function getServiceUrls() {
|
|
64
|
-
const config = DEFAULT_PROVIDER_CONFIG;
|
|
65
|
-
const globalOverride = typeof window !== "undefined" && window.__EMBARK_SERVICES__ || {};
|
|
66
|
-
const searchParams = typeof window !== "undefined" ? new URLSearchParams(window.location.search) : void 0;
|
|
67
|
-
const paramTss = searchParams?.get("tssUrl") || void 0;
|
|
68
|
-
const paramVault = searchParams?.get("shareVaultUrl") || void 0;
|
|
69
|
-
const paramDashboard = searchParams?.get("dashboardApiUrl") || void 0;
|
|
70
|
-
const buildTss = "https://api.lumiapassport.com/tss";
|
|
71
|
-
const buildVault = "https://api.lumiapassport.com/vault";
|
|
72
|
-
const buildRequireWasm = false;
|
|
73
|
-
const buildWasmDebug = false;
|
|
74
|
-
const defaultTss = "/tss";
|
|
75
|
-
const defaultVault = "/vault";
|
|
76
|
-
const result = {
|
|
77
|
-
tssUrl: paramTss || globalOverride.tssUrl || buildTss || config.services.tssUrl || defaultTss,
|
|
78
|
-
shareVaultUrl: paramVault || globalOverride.shareVaultUrl || buildVault || config.services.shareVaultUrl || defaultVault,
|
|
79
|
-
dashboardApiUrl: paramDashboard || globalOverride.dashboardApiUrl || config.services.dashboardApiUrl || "https://dashboard.lumiapassport.com/api",
|
|
80
|
-
tssRequireWasm: globalOverride.tssRequireWasm ?? buildRequireWasm ?? config.services.tssRequireWasm ?? false,
|
|
81
|
-
tssWasmDebug: globalOverride.tssWasmDebug ?? buildWasmDebug ?? config.services.tssWasmDebug ?? false
|
|
82
|
-
};
|
|
83
|
-
return result;
|
|
84
|
-
}
|
|
85
|
-
function getIframeUrl() {
|
|
86
|
-
const config = DEFAULT_PROVIDER_CONFIG;
|
|
87
|
-
const buildIframeUrl = "https://auth.lumiapassport.com";
|
|
88
|
-
const iframeUrl = buildIframeUrl || config.services.iframeUrl || "https://auth.lumiapassport.com";
|
|
89
|
-
return iframeUrl;
|
|
90
|
-
}
|
|
91
|
-
function getBlockscoutApiUrl(chainConfig) {
|
|
92
|
-
return chainConfig?.blockscoutApiUrl || null;
|
|
93
|
-
}
|
|
94
|
-
var DEFAULT_PROVIDER_CONFIG;
|
|
95
|
-
var init_initial = __esm({
|
|
96
|
-
"src/config/initial.tsx"() {
|
|
97
|
-
init_assets();
|
|
98
|
-
DEFAULT_PROVIDER_CONFIG = {
|
|
99
|
-
passkey: {
|
|
100
|
-
enabled: true,
|
|
101
|
-
showCreateButton: true,
|
|
102
|
-
primaryButtonText: "Sign in with Passkey"
|
|
103
|
-
},
|
|
104
|
-
email: {
|
|
105
|
-
enabled: true,
|
|
106
|
-
placeholder: "Enter your email",
|
|
107
|
-
buttonText: "Continue",
|
|
108
|
-
verificationTitle: "Check your email"
|
|
109
|
-
},
|
|
110
|
-
social: {
|
|
111
|
-
enabled: true,
|
|
112
|
-
providers: [
|
|
113
|
-
{ id: "google", name: "Google", enabled: true, icon: GoogleIcon, comingSoon: true },
|
|
114
|
-
{
|
|
115
|
-
id: "telegram",
|
|
116
|
-
name: "Telegram",
|
|
117
|
-
enabled: true,
|
|
118
|
-
icon: TelegramIcon,
|
|
119
|
-
comingSoon: false,
|
|
120
|
-
meta: {
|
|
121
|
-
botUsername: "LumiaPassportDevBot",
|
|
122
|
-
salt: "demo"
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
]
|
|
126
|
-
},
|
|
127
|
-
wallet: {
|
|
128
|
-
enabled: false,
|
|
129
|
-
supportedChains: [1, 137, 56],
|
|
130
|
-
requireSignature: true,
|
|
131
|
-
walletConnectProjectId: void 0,
|
|
132
|
-
mode: "linked",
|
|
133
|
-
allowedWallets: void 0
|
|
134
|
-
},
|
|
135
|
-
// preferedColorMode: 'light', // undefined means 'auto'
|
|
136
|
-
ui: {
|
|
137
|
-
title: "Sign in",
|
|
138
|
-
subtitle: void 0,
|
|
139
|
-
authOrder: ["email", "social", "wallet"]
|
|
140
|
-
},
|
|
141
|
-
network: {
|
|
142
|
-
name: BSC_TESTNET.name,
|
|
143
|
-
symbol: BSC_TESTNET.nativeCurrency.symbol,
|
|
144
|
-
chainId: BSC_TESTNET.id,
|
|
145
|
-
rpcUrl: BSC_TESTNET.rpcUrls[0],
|
|
146
|
-
explorerUrl: BSC_TESTNET.blockExplorerUrl,
|
|
147
|
-
testnet: true,
|
|
148
|
-
forceChain: false
|
|
149
|
-
},
|
|
150
|
-
services: {
|
|
151
|
-
tssUrl: "",
|
|
152
|
-
// Will fallback to build-time env vars
|
|
153
|
-
shareVaultUrl: "",
|
|
154
|
-
// Will fallback to build-time env vars
|
|
155
|
-
iframeUrl: "https://auth.lumiapassport.com",
|
|
156
|
-
// Secure iframe for MPC operations
|
|
157
|
-
tssRequireWasm: false,
|
|
158
|
-
tssWasmDebug: false
|
|
159
|
-
},
|
|
160
|
-
features: {
|
|
161
|
-
mpcSecurity: true,
|
|
162
|
-
strictMode: false,
|
|
163
|
-
requestDeduplication: true,
|
|
164
|
-
kycNeeded: false,
|
|
165
|
-
displayNameNeeded: false,
|
|
166
|
-
showActiveBalanceAsFiat: false
|
|
167
|
-
},
|
|
168
|
-
warnings: {
|
|
169
|
-
backupWarning: true,
|
|
170
|
-
emailNotConnectedWarning: true
|
|
171
|
-
},
|
|
172
|
-
kyc: {
|
|
173
|
-
provider: void 0,
|
|
174
|
-
options: void 0
|
|
175
|
-
}
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
// src/lib/errors.ts
|
|
181
|
-
var AccountAbstractionError = class _AccountAbstractionError extends Error {
|
|
182
|
-
constructor(message, code) {
|
|
183
|
-
super(message);
|
|
184
|
-
this.code = code;
|
|
185
|
-
this.name = "LumiaPassportError";
|
|
186
|
-
if (Error.captureStackTrace) {
|
|
187
|
-
Error.captureStackTrace(this, _AccountAbstractionError);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
};
|
|
191
|
-
var UserRejectedError = class _UserRejectedError extends AccountAbstractionError {
|
|
192
|
-
static {
|
|
193
|
-
this.CODE = "USER_REJECTED";
|
|
194
|
-
}
|
|
195
|
-
constructor(message = "User rejected transaction") {
|
|
196
|
-
super(message, _UserRejectedError.CODE);
|
|
197
|
-
this.name = "UserRejectedError";
|
|
198
|
-
}
|
|
199
|
-
};
|
|
200
|
-
var ErrorCodes = {
|
|
201
|
-
MPC_SIGNING_ERROR: "MPC_SIGNING_ERROR",
|
|
202
|
-
USER_REJECTED: UserRejectedError.CODE
|
|
203
|
-
};
|
|
204
|
-
function createAccountAbstractionError(params) {
|
|
205
|
-
const { message, code } = params;
|
|
206
|
-
if (!code) {
|
|
207
|
-
return new Error(message);
|
|
208
|
-
}
|
|
209
|
-
switch (code) {
|
|
210
|
-
case UserRejectedError.CODE:
|
|
211
|
-
return new UserRejectedError(message);
|
|
212
|
-
default:
|
|
213
|
-
return new AccountAbstractionError(message, code);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// src/internal/lib/iframe-manager.ts
|
|
218
|
-
var IframeManager = class {
|
|
219
|
-
constructor(config) {
|
|
220
|
-
this.iframe = null;
|
|
221
|
-
this.channelToken = null;
|
|
222
|
-
this.isReady = false;
|
|
223
|
-
this.initPromise = null;
|
|
224
|
-
// Message handling
|
|
225
|
-
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
226
|
-
this.usedNonces = /* @__PURE__ */ new Set();
|
|
227
|
-
this.messageListener = null;
|
|
228
|
-
// Track hidden dialog elements for restoration
|
|
229
|
-
this.hiddenElements = [];
|
|
230
|
-
this.pointerGuardCleanup = null;
|
|
231
|
-
this.iframeHideTimeout = null;
|
|
232
|
-
this.iframeActive = false;
|
|
233
|
-
this.providerSessions = /* @__PURE__ */ new Map();
|
|
234
|
-
this.providerConnections = /* @__PURE__ */ new Map();
|
|
235
|
-
// Timeouts
|
|
236
|
-
this.REQUEST_TIMEOUT = 3e5;
|
|
237
|
-
// 5 minutes (for user interactions like consent)
|
|
238
|
-
this.NONCE_EXPIRY = 3e5;
|
|
239
|
-
// 5 minutes
|
|
240
|
-
this.HEARTBEAT_INTERVAL = 5 * 60 * 1e3;
|
|
241
|
-
this.isReconnecting = false;
|
|
242
|
-
// SSE event listeners
|
|
243
|
-
this.sseListeners = /* @__PURE__ */ new Set();
|
|
244
|
-
this.iframeUrl = config.iframeUrl;
|
|
245
|
-
this.projectId = config.projectId;
|
|
246
|
-
this.debug = config.debug || false;
|
|
247
|
-
this.onWalletReadyCallback = config.onWalletReady;
|
|
248
|
-
this.readyPromise = new Promise((resolve) => {
|
|
249
|
-
this.readyResolve = resolve;
|
|
250
|
-
});
|
|
251
|
-
this.log("[IframeManager] Initialized with:", {
|
|
252
|
-
iframeUrl: this.iframeUrl,
|
|
253
|
-
projectId: this.projectId
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
setDebug(debug) {
|
|
257
|
-
this.debug = debug;
|
|
258
|
-
}
|
|
259
|
-
/**
|
|
260
|
-
* Initialize iframe and wait for it to be ready
|
|
261
|
-
*/
|
|
262
|
-
async initialize() {
|
|
263
|
-
if (this.initPromise) {
|
|
264
|
-
return this.initPromise;
|
|
265
|
-
}
|
|
266
|
-
this.initPromise = this.doInitialize();
|
|
267
|
-
return this.initPromise;
|
|
268
|
-
}
|
|
269
|
-
async doInitialize() {
|
|
270
|
-
this.iframe = document.createElement("iframe");
|
|
271
|
-
let iframeUrl = this.iframeUrl;
|
|
272
|
-
this.iframe.src = iframeUrl;
|
|
273
|
-
this.iframe.id = "lumia-passport-iframe";
|
|
274
|
-
this.iframe.style.display = "none";
|
|
275
|
-
this.iframe.style.position = "fixed";
|
|
276
|
-
this.iframe.style.top = "0";
|
|
277
|
-
this.iframe.style.left = "0";
|
|
278
|
-
this.iframe.style.width = "100%";
|
|
279
|
-
this.iframe.style.height = "100%";
|
|
280
|
-
this.iframe.style.border = "none";
|
|
281
|
-
this.iframe.style.zIndex = "999999";
|
|
282
|
-
this.iframe.style.background = "rgba(0, 0, 0, 0.5)";
|
|
283
|
-
this.iframe.setAttribute("sandbox", "allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox");
|
|
284
|
-
this.iframe.setAttribute("allow", "publickey-credentials-get *; publickey-credentials-create *");
|
|
285
|
-
this.messageListener = this.handleMessage.bind(this);
|
|
286
|
-
window.addEventListener("message", this.messageListener);
|
|
287
|
-
document.body.appendChild(this.iframe);
|
|
288
|
-
await this.readyPromise;
|
|
289
|
-
await this.authenticateSDK();
|
|
290
|
-
await this.primeProviderSessions();
|
|
291
|
-
this.startHeartbeat();
|
|
292
|
-
this.setupVisibilityHandler();
|
|
293
|
-
this.log("[IframeManager] \u2705 Iframe ready and authenticated");
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
|
-
* Set the onWalletReady callback
|
|
297
|
-
*/
|
|
298
|
-
setOnWalletReady(callback) {
|
|
299
|
-
this.onWalletReadyCallback = callback;
|
|
300
|
-
}
|
|
301
|
-
/**
|
|
302
|
-
* Authenticate SDK with iframe to establish secure channel
|
|
303
|
-
*/
|
|
304
|
-
async authenticateSDK() {
|
|
305
|
-
const response = await this.sendMessage("SDK_AUTH", {
|
|
306
|
-
projectId: this.projectId
|
|
307
|
-
});
|
|
308
|
-
if (response.type === "IFRAME_MSG_SDK_AUTH_SUCCESS") {
|
|
309
|
-
this.channelToken = response.sessionToken;
|
|
310
|
-
} else {
|
|
311
|
-
throw new Error("SDK channel authentication failed");
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
/**
|
|
315
|
-
* Start periodic heartbeat to check SDK channel validity
|
|
316
|
-
*/
|
|
317
|
-
startHeartbeat() {
|
|
318
|
-
if (this.heartbeatInterval) {
|
|
319
|
-
clearInterval(this.heartbeatInterval);
|
|
320
|
-
}
|
|
321
|
-
this.heartbeatInterval = setInterval(async () => {
|
|
322
|
-
if (!this.channelToken) return;
|
|
323
|
-
try {
|
|
324
|
-
const response = await this.sendMessage("SDK_CHANNEL_HEARTBEAT", {});
|
|
325
|
-
if (!response.valid) {
|
|
326
|
-
this.log("[IframeManager] SDK channel invalid, reconnecting...");
|
|
327
|
-
await this.reconnect();
|
|
328
|
-
}
|
|
329
|
-
} catch (error) {
|
|
330
|
-
this.log("[IframeManager] Heartbeat failed:", error);
|
|
331
|
-
await this.reconnect();
|
|
332
|
-
}
|
|
333
|
-
}, this.HEARTBEAT_INTERVAL);
|
|
334
|
-
this.log("[IframeManager] Heartbeat started (interval: 5 min)");
|
|
335
|
-
}
|
|
336
|
-
/**
|
|
337
|
-
* Stop heartbeat
|
|
338
|
-
*/
|
|
339
|
-
stopHeartbeat() {
|
|
340
|
-
if (this.heartbeatInterval) {
|
|
341
|
-
clearInterval(this.heartbeatInterval);
|
|
342
|
-
this.heartbeatInterval = void 0;
|
|
343
|
-
this.log("[IframeManager] Heartbeat stopped");
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
/**
|
|
347
|
-
* Reconnect SDK channel after it becomes invalid
|
|
348
|
-
*/
|
|
349
|
-
async reconnect() {
|
|
350
|
-
if (this.isReconnecting) {
|
|
351
|
-
this.log("[IframeManager] Already reconnecting, skipping...");
|
|
352
|
-
return;
|
|
353
|
-
}
|
|
354
|
-
this.isReconnecting = true;
|
|
355
|
-
this.log("[IframeManager] Reconnecting SDK channel...");
|
|
356
|
-
try {
|
|
357
|
-
this.channelToken = null;
|
|
358
|
-
await this.authenticateSDK();
|
|
359
|
-
this.log("[IframeManager] \u2705 SDK channel reconnected");
|
|
360
|
-
} catch (error) {
|
|
361
|
-
this.log("[IframeManager] \u274C Reconnect failed:", error);
|
|
362
|
-
throw error;
|
|
363
|
-
} finally {
|
|
364
|
-
this.isReconnecting = false;
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
/**
|
|
368
|
-
* Setup visibility change handler to check channel when tab becomes visible
|
|
369
|
-
*/
|
|
370
|
-
setupVisibilityHandler() {
|
|
371
|
-
if (typeof document === "undefined") return;
|
|
372
|
-
document.addEventListener("visibilitychange", async () => {
|
|
373
|
-
if (document.visibilityState === "visible" && this.channelToken) {
|
|
374
|
-
this.log("[IframeManager] Tab visible, checking SDK channel...");
|
|
375
|
-
try {
|
|
376
|
-
const response = await this.sendMessage("SDK_CHANNEL_HEARTBEAT", {});
|
|
377
|
-
if (!response.valid) {
|
|
378
|
-
this.log("[IframeManager] SDK channel expired while tab was hidden");
|
|
379
|
-
await this.reconnect();
|
|
380
|
-
}
|
|
381
|
-
} catch (error) {
|
|
382
|
-
this.log("[IframeManager] Channel check failed, reconnecting...");
|
|
383
|
-
await this.reconnect();
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
});
|
|
387
|
-
this.log("[IframeManager] Visibility handler setup");
|
|
388
|
-
}
|
|
389
|
-
/**
|
|
390
|
-
* Normalize legacy message types from cached iframe versions.
|
|
391
|
-
* Old iframe sends LUMIA_PASSPORT_*, new iframe sends IFRAME_MSG_*.
|
|
392
|
-
* This ensures both work until all browser caches expire.
|
|
393
|
-
*/
|
|
394
|
-
normalizeMessageType(type) {
|
|
395
|
-
if (type.startsWith("LUMIA_PASSPORT_")) {
|
|
396
|
-
return type.replace("LUMIA_PASSPORT_", "IFRAME_MSG_");
|
|
397
|
-
}
|
|
398
|
-
return type;
|
|
399
|
-
}
|
|
400
|
-
/**
|
|
401
|
-
* Handle incoming postMessage events
|
|
402
|
-
*/
|
|
403
|
-
handleMessage(event) {
|
|
404
|
-
const message = event.data;
|
|
405
|
-
if (!message || typeof message !== "object" || !message.type) {
|
|
406
|
-
return;
|
|
407
|
-
}
|
|
408
|
-
message.type = this.normalizeMessageType(message.type);
|
|
409
|
-
const validIframeTypes = [
|
|
410
|
-
"IFRAME_MSG_IFRAME_READY",
|
|
411
|
-
"IFRAME_MSG_WALLET_READY",
|
|
412
|
-
"IFRAME_MSG_SHOW_IFRAME",
|
|
413
|
-
"IFRAME_MSG_HIDE_IFRAME",
|
|
414
|
-
"IFRAME_MSG_SDK_AUTH_SUCCESS",
|
|
415
|
-
"IFRAME_MSG_AUTH_SUCCESS",
|
|
416
|
-
"IFRAME_MSG_DKG_SUCCESS",
|
|
417
|
-
"IFRAME_MSG_SIGNATURE",
|
|
418
|
-
"IFRAME_MSG_ADDRESS",
|
|
419
|
-
"IFRAME_MSG_KEYSHARE_STATUS",
|
|
420
|
-
"IFRAME_MSG_TRUSTED_APPS_LIST",
|
|
421
|
-
"IFRAME_MSG_TRUSTED_APP_REMOVED",
|
|
422
|
-
"IFRAME_MSG_REQUEST_NEW_TOKEN",
|
|
423
|
-
"IFRAME_MSG_TOKEN_REFRESHED",
|
|
424
|
-
"IFRAME_MSG_HEARTBEAT_RESPONSE",
|
|
425
|
-
"IFRAME_MSG_RESPONSE",
|
|
426
|
-
"IFRAME_MSG_ERROR",
|
|
427
|
-
"IFRAME_SSE_EVENT"
|
|
428
|
-
];
|
|
429
|
-
if (!validIframeTypes.includes(message.type) && !message.messageId) {
|
|
430
|
-
return;
|
|
431
|
-
}
|
|
432
|
-
const iframeOrigin = new URL(this.iframeUrl).origin;
|
|
433
|
-
if (event.origin !== iframeOrigin) {
|
|
434
|
-
this.log("[IframeManager] \u26A0\uFE0F Ignored message from invalid origin:", {
|
|
435
|
-
received: event.origin,
|
|
436
|
-
expected: iframeOrigin
|
|
437
|
-
});
|
|
438
|
-
return;
|
|
439
|
-
}
|
|
440
|
-
if (message.type === "IFRAME_SSE_EVENT") {
|
|
441
|
-
this.log("[IframeManager] \u{1F4E8} Received IFRAME_SSE_EVENT", message.data);
|
|
442
|
-
for (const listener of this.sseListeners) {
|
|
443
|
-
try {
|
|
444
|
-
listener(message.data);
|
|
445
|
-
} catch (err) {
|
|
446
|
-
console.error("[IframeManager] SSE listener error:", err);
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
return;
|
|
450
|
-
}
|
|
451
|
-
if (message.type === "IFRAME_MSG_IFRAME_READY") {
|
|
452
|
-
this.log("[IframeManager] \u{1F4E8} Received IFRAME_MSG_IFRAME_READY");
|
|
453
|
-
this.isReady = true;
|
|
454
|
-
this.readyResolve();
|
|
455
|
-
return;
|
|
456
|
-
}
|
|
457
|
-
if (message.type === "IFRAME_MSG_WALLET_READY") {
|
|
458
|
-
this.log("[IframeManager] \u{1F4E8} Received IFRAME_MSG_WALLET_READY", message.data);
|
|
459
|
-
if (this.onWalletReadyCallback) {
|
|
460
|
-
this.onWalletReadyCallback(message.data);
|
|
461
|
-
}
|
|
462
|
-
return;
|
|
463
|
-
}
|
|
464
|
-
if (message.type === "IFRAME_MSG_SHOW_IFRAME") {
|
|
465
|
-
this.log("[IframeManager] \u{1F4E8} Received IFRAME_MSG_SHOW_IFRAME");
|
|
466
|
-
this.showIframe();
|
|
467
|
-
return;
|
|
468
|
-
}
|
|
469
|
-
if (message.type === "IFRAME_MSG_HIDE_IFRAME") {
|
|
470
|
-
this.log("[IframeManager] \u{1F4E8} Received IFRAME_MSG_HIDE_IFRAME");
|
|
471
|
-
this.hideIframe();
|
|
472
|
-
return;
|
|
473
|
-
}
|
|
474
|
-
if (message.type === "IFRAME_MSG_REQUEST_NEW_TOKEN") {
|
|
475
|
-
this.log("[IframeManager] \u{1F4E8} Received IFRAME_MSG_REQUEST_NEW_TOKEN");
|
|
476
|
-
this.handleTokenRefreshRequest(message).catch((error) => {
|
|
477
|
-
this.log("[IframeManager] \u274C Token refresh error:", error);
|
|
478
|
-
});
|
|
479
|
-
return;
|
|
480
|
-
}
|
|
481
|
-
if (message.messageId) {
|
|
482
|
-
const pending = this.pendingRequests.get(message.messageId);
|
|
483
|
-
if (pending) {
|
|
484
|
-
this.pendingRequests.delete(message.messageId);
|
|
485
|
-
if (message.type === "IFRAME_MSG_ERROR") {
|
|
486
|
-
const passportError = createAccountAbstractionError({
|
|
487
|
-
message: message.error || "Unknown error",
|
|
488
|
-
code: message.code
|
|
489
|
-
});
|
|
490
|
-
pending.reject(passportError);
|
|
491
|
-
} else {
|
|
492
|
-
pending.resolve(message.data || message);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
/**
|
|
498
|
-
* Handle token refresh request from iframe
|
|
499
|
-
*/
|
|
500
|
-
async handleTokenRefreshRequest(message) {
|
|
501
|
-
try {
|
|
502
|
-
const { jwtTokenManager } = await import("./auth-GP4VPOSM.js");
|
|
503
|
-
const refreshSuccess = await jwtTokenManager.refreshAccessToken();
|
|
504
|
-
if (refreshSuccess) {
|
|
505
|
-
const newAccessToken = jwtTokenManager.getAccessToken();
|
|
506
|
-
if (this.iframe && this.iframe.contentWindow) {
|
|
507
|
-
const iframeOrigin = new URL(this.iframeUrl).origin;
|
|
508
|
-
this.iframe.contentWindow.postMessage(
|
|
509
|
-
{
|
|
510
|
-
type: "IFRAME_MSG_TOKEN_REFRESHED",
|
|
511
|
-
messageId: message.messageId,
|
|
512
|
-
accessToken: newAccessToken,
|
|
513
|
-
timestamp: Date.now()
|
|
514
|
-
},
|
|
515
|
-
iframeOrigin
|
|
516
|
-
);
|
|
517
|
-
}
|
|
518
|
-
} else {
|
|
519
|
-
if (this.iframe && this.iframe.contentWindow) {
|
|
520
|
-
const iframeOrigin = new URL(this.iframeUrl).origin;
|
|
521
|
-
this.iframe.contentWindow.postMessage(
|
|
522
|
-
{
|
|
523
|
-
type: "IFRAME_MSG_TOKEN_REFRESHED",
|
|
524
|
-
messageId: message.messageId,
|
|
525
|
-
error: "Token refresh failed",
|
|
526
|
-
timestamp: Date.now()
|
|
527
|
-
},
|
|
528
|
-
iframeOrigin
|
|
529
|
-
);
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
} catch (error) {
|
|
533
|
-
if (this.iframe && this.iframe.contentWindow) {
|
|
534
|
-
const iframeOrigin = new URL(this.iframeUrl).origin;
|
|
535
|
-
this.iframe.contentWindow.postMessage(
|
|
536
|
-
{
|
|
537
|
-
type: "IFRAME_MSG_TOKEN_REFRESHED",
|
|
538
|
-
messageId: message.messageId,
|
|
539
|
-
error: error instanceof Error ? error.message : "Unknown error",
|
|
540
|
-
timestamp: Date.now()
|
|
541
|
-
},
|
|
542
|
-
iframeOrigin
|
|
543
|
-
);
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
/**
|
|
548
|
-
* Send secure message to iframe
|
|
549
|
-
*/
|
|
550
|
-
async sendMessage(type, data) {
|
|
551
|
-
if (this.initPromise && type !== "SDK_AUTH") {
|
|
552
|
-
await this.initPromise;
|
|
553
|
-
}
|
|
554
|
-
if (!this.iframe || !this.iframe.contentWindow) {
|
|
555
|
-
throw new Error("Iframe not initialized");
|
|
556
|
-
}
|
|
557
|
-
if (!this.channelToken && type !== "SDK_AUTH") {
|
|
558
|
-
throw createAccountAbstractionError({ message: "SDK channel not established. Initialize iframe first." });
|
|
559
|
-
}
|
|
560
|
-
const messageId = this.generateMessageId();
|
|
561
|
-
const nonce = this.generateNonce();
|
|
562
|
-
const timestamp = Date.now();
|
|
563
|
-
const message = {
|
|
564
|
-
type,
|
|
565
|
-
messageId,
|
|
566
|
-
timestamp,
|
|
567
|
-
nonce,
|
|
568
|
-
projectId: this.projectId,
|
|
569
|
-
data: {
|
|
570
|
-
...data,
|
|
571
|
-
sessionToken: this.channelToken
|
|
572
|
-
// named sessionToken for backward compatibility with iframe
|
|
573
|
-
}
|
|
574
|
-
};
|
|
575
|
-
if (this.channelToken) {
|
|
576
|
-
message.hmac = await this.computeHMAC(message);
|
|
577
|
-
}
|
|
578
|
-
const responsePromise = new Promise((resolve, reject) => {
|
|
579
|
-
this.pendingRequests.set(messageId, {
|
|
580
|
-
resolve,
|
|
581
|
-
reject,
|
|
582
|
-
timestamp
|
|
583
|
-
});
|
|
584
|
-
setTimeout(() => {
|
|
585
|
-
if (this.pendingRequests.has(messageId)) {
|
|
586
|
-
this.pendingRequests.delete(messageId);
|
|
587
|
-
reject(new Error(`Request timeout: ${type}`));
|
|
588
|
-
}
|
|
589
|
-
}, this.REQUEST_TIMEOUT);
|
|
590
|
-
});
|
|
591
|
-
const iframeOrigin = new URL(this.iframeUrl).origin;
|
|
592
|
-
this.iframe.contentWindow.postMessage(message, iframeOrigin);
|
|
593
|
-
this.log(`[IframeManager] \u{1F4E4} Sent message: ${type}`, { messageId });
|
|
594
|
-
return responsePromise;
|
|
595
|
-
}
|
|
596
|
-
onSseEvent(listener) {
|
|
597
|
-
this.sseListeners.add(listener);
|
|
598
|
-
return () => {
|
|
599
|
-
this.sseListeners.delete(listener);
|
|
600
|
-
};
|
|
601
|
-
}
|
|
602
|
-
/**
|
|
603
|
-
* Compute HMAC for message authentication using SDK channel token
|
|
604
|
-
*/
|
|
605
|
-
async computeHMAC(message) {
|
|
606
|
-
const encoder = new TextEncoder();
|
|
607
|
-
const payload = JSON.stringify({
|
|
608
|
-
type: message.type,
|
|
609
|
-
messageId: message.messageId,
|
|
610
|
-
timestamp: message.timestamp,
|
|
611
|
-
nonce: message.nonce,
|
|
612
|
-
data: JSON.stringify(message.data)
|
|
613
|
-
});
|
|
614
|
-
const data = encoder.encode(payload);
|
|
615
|
-
const key = encoder.encode(this.channelToken);
|
|
616
|
-
const cryptoKey = await crypto.subtle.importKey("raw", key, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
617
|
-
const signature = await crypto.subtle.sign("HMAC", cryptoKey, data);
|
|
618
|
-
return Array.from(new Uint8Array(signature)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
619
|
-
}
|
|
620
|
-
/**
|
|
621
|
-
* Generate unique message ID
|
|
622
|
-
*/
|
|
623
|
-
generateMessageId() {
|
|
624
|
-
return `msg_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
|
|
625
|
-
}
|
|
626
|
-
/**
|
|
627
|
-
* Generate nonce for replay protection
|
|
628
|
-
*/
|
|
629
|
-
generateNonce() {
|
|
630
|
-
const randomBytes = new Uint8Array(16);
|
|
631
|
-
crypto.getRandomValues(randomBytes);
|
|
632
|
-
return Array.from(randomBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
633
|
-
}
|
|
634
|
-
// ========================================
|
|
635
|
-
// UI Methods
|
|
636
|
-
// ========================================
|
|
637
|
-
/**
|
|
638
|
-
* Show iframe (for consent/confirmation UI)
|
|
639
|
-
*/
|
|
640
|
-
showIframe() {
|
|
641
|
-
if (this.iframe) {
|
|
642
|
-
if (this.iframeHideTimeout) {
|
|
643
|
-
clearTimeout(this.iframeHideTimeout);
|
|
644
|
-
this.iframeHideTimeout = null;
|
|
645
|
-
}
|
|
646
|
-
this.hideAllDialogs();
|
|
647
|
-
this.iframeActive = true;
|
|
648
|
-
this.enablePointerEventGuards();
|
|
649
|
-
this.iframe.style.display = "block";
|
|
650
|
-
this.iframe.style.zIndex = "2147483648";
|
|
651
|
-
this.iframe.style.pointerEvents = "auto";
|
|
652
|
-
this.iframe.style.visibility = "visible";
|
|
653
|
-
this.iframe.style.background = "rgba(0, 0, 0, 0.5)";
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
/**
|
|
657
|
-
* Hide iframe
|
|
658
|
-
*/
|
|
659
|
-
hideIframe() {
|
|
660
|
-
if (this.iframe) {
|
|
661
|
-
this.log("[IframeManager] hideIframe called - making iframe non-blocking");
|
|
662
|
-
this.iframeActive = false;
|
|
663
|
-
this.iframe.style.zIndex = "1";
|
|
664
|
-
this.iframe.style.background = "transparent";
|
|
665
|
-
this.iframe.style.pointerEvents = "none";
|
|
666
|
-
this.iframe.style.visibility = "hidden";
|
|
667
|
-
this.log("[IframeManager] iframe z-index set to 1, transparent, pointer-events: none");
|
|
668
|
-
this.restoreAllDialogs();
|
|
669
|
-
this.disablePointerEventGuards();
|
|
670
|
-
this.iframeHideTimeout = setTimeout(() => {
|
|
671
|
-
if (this.iframe) {
|
|
672
|
-
this.log("[IframeManager] Fully hiding iframe with display: none");
|
|
673
|
-
this.iframe.style.display = "none";
|
|
674
|
-
this.iframe.style.zIndex = "999999";
|
|
675
|
-
this.iframe.style.background = "rgba(0, 0, 0, 0.5)";
|
|
676
|
-
this.iframe.style.pointerEvents = "auto";
|
|
677
|
-
this.iframe.style.visibility = "visible";
|
|
678
|
-
}
|
|
679
|
-
this.iframeHideTimeout = null;
|
|
680
|
-
}, 200);
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
/**
|
|
684
|
-
* Hide all Radix Dialog modals (SendModal, etc.)
|
|
685
|
-
*/
|
|
686
|
-
hideAllDialogs() {
|
|
687
|
-
this.hiddenElements = [];
|
|
688
|
-
const allElements = document.body.querySelectorAll("*");
|
|
689
|
-
allElements.forEach((element) => {
|
|
690
|
-
const htmlElement = element;
|
|
691
|
-
if (htmlElement.id === "lumia-passport-iframe" || htmlElement.closest("#lumia-passport-iframe")) {
|
|
692
|
-
return;
|
|
693
|
-
}
|
|
694
|
-
if (htmlElement.hasAttribute("data-lumia-auth-modal") || htmlElement.closest("[data-lumia-auth-modal]")) {
|
|
695
|
-
return;
|
|
696
|
-
}
|
|
697
|
-
const computedStyle = window.getComputedStyle(htmlElement);
|
|
698
|
-
const zIndex = parseInt(computedStyle.zIndex, 10);
|
|
699
|
-
const isRadixElement = htmlElement.hasAttribute("data-radix-focus-guard") || htmlElement.hasAttribute("data-radix-portal") || htmlElement.hasAttribute("data-radix-popper-content-wrapper");
|
|
700
|
-
if (!isNaN(zIndex) && zIndex > 1e6 || isRadixElement) {
|
|
701
|
-
this.hiddenElements.push({
|
|
702
|
-
element: htmlElement,
|
|
703
|
-
originalDisplay: htmlElement.style.display || "",
|
|
704
|
-
originalVisibility: htmlElement.style.visibility || "",
|
|
705
|
-
originalPointerEvents: htmlElement.style.pointerEvents || "",
|
|
706
|
-
originalZIndex: htmlElement.style.zIndex || ""
|
|
707
|
-
});
|
|
708
|
-
htmlElement.style.display = "none";
|
|
709
|
-
htmlElement.style.visibility = "hidden";
|
|
710
|
-
htmlElement.style.pointerEvents = "none";
|
|
711
|
-
htmlElement.style.zIndex = "-1";
|
|
712
|
-
const elementType = isRadixElement ? "Radix element" : `z-index ${zIndex}`;
|
|
713
|
-
this.log(
|
|
714
|
-
`[IframeManager] Hiding ${elementType}: ${htmlElement.className || "(no class)"} (Tag: ${htmlElement.tagName})`
|
|
715
|
-
);
|
|
716
|
-
}
|
|
717
|
-
});
|
|
718
|
-
this.log(`[IframeManager] Hidden ${this.hiddenElements.length} elements total`);
|
|
719
|
-
}
|
|
720
|
-
/**
|
|
721
|
-
* Restore all previously hidden Radix Dialog modals
|
|
722
|
-
*/
|
|
723
|
-
restoreAllDialogs() {
|
|
724
|
-
this.log(`[IframeManager] Restoring ${this.hiddenElements.length} elements`);
|
|
725
|
-
this.hiddenElements.forEach(
|
|
726
|
-
({ element, originalDisplay, originalVisibility, originalPointerEvents, originalZIndex }) => {
|
|
727
|
-
element.style.display = originalDisplay;
|
|
728
|
-
element.style.visibility = originalVisibility;
|
|
729
|
-
element.style.pointerEvents = originalPointerEvents || "auto";
|
|
730
|
-
element.style.zIndex = originalZIndex;
|
|
731
|
-
this.log(
|
|
732
|
-
`[IframeManager] Restored element: ${element.className} (Tag: ${element.tagName}), pointerEvents set to: ${element.style.pointerEvents}`
|
|
733
|
-
);
|
|
734
|
-
}
|
|
735
|
-
);
|
|
736
|
-
this.hiddenElements = [];
|
|
737
|
-
this.log(`[IframeManager] All elements restored`);
|
|
738
|
-
}
|
|
739
|
-
/**
|
|
740
|
-
* Stop Radix dismissable layers from swallowing the first click on the iframe.
|
|
741
|
-
* Radix attaches pointer event guards at the document level; we intercept at window
|
|
742
|
-
* capture phase so user clicks flow straight into the consent iframe.
|
|
743
|
-
*/
|
|
744
|
-
enablePointerEventGuards() {
|
|
745
|
-
if (this.pointerGuardCleanup) {
|
|
746
|
-
return;
|
|
747
|
-
}
|
|
748
|
-
const handler = (event) => {
|
|
749
|
-
if (!this.iframeActive || !this.iframe) {
|
|
750
|
-
return;
|
|
751
|
-
}
|
|
752
|
-
const target = event.target;
|
|
753
|
-
const composedPath = typeof event.composedPath === "function" ? event.composedPath() : [];
|
|
754
|
-
const hitsIframe = target === this.iframe || Array.isArray(composedPath) && composedPath.includes(this.iframe);
|
|
755
|
-
if (!hitsIframe) {
|
|
756
|
-
return;
|
|
757
|
-
}
|
|
758
|
-
if (typeof event.stopImmediatePropagation === "function") {
|
|
759
|
-
;
|
|
760
|
-
event.stopImmediatePropagation();
|
|
761
|
-
}
|
|
762
|
-
event.stopPropagation();
|
|
763
|
-
};
|
|
764
|
-
const options = { capture: true };
|
|
765
|
-
const eventNames = ["pointerdown", "mousedown", "mouseup", "click", "touchstart", "focusin"];
|
|
766
|
-
eventNames.forEach((eventName) => {
|
|
767
|
-
window.addEventListener(eventName, handler, options);
|
|
768
|
-
});
|
|
769
|
-
this.pointerGuardCleanup = () => {
|
|
770
|
-
eventNames.forEach((eventName) => {
|
|
771
|
-
window.removeEventListener(eventName, handler, options);
|
|
772
|
-
});
|
|
773
|
-
this.pointerGuardCleanup = null;
|
|
774
|
-
};
|
|
775
|
-
this.log("[IframeManager] Enabled pointer event guards for iframe consent");
|
|
776
|
-
}
|
|
777
|
-
/**
|
|
778
|
-
* Remove pointer interception once iframe is hidden again.
|
|
779
|
-
*/
|
|
780
|
-
disablePointerEventGuards() {
|
|
781
|
-
if (this.pointerGuardCleanup) {
|
|
782
|
-
this.pointerGuardCleanup();
|
|
783
|
-
this.pointerGuardCleanup = null;
|
|
784
|
-
this.log("[IframeManager] Disabled pointer event guards for iframe consent");
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
// ========================================
|
|
788
|
-
// Public API Methods
|
|
789
|
-
// ========================================
|
|
790
|
-
/**
|
|
791
|
-
* Authenticate user with application
|
|
792
|
-
*/
|
|
793
|
-
async authenticate(userId, avatar, displayName) {
|
|
794
|
-
const response = await this.sendMessage("AUTHENTICATE", {
|
|
795
|
-
userId,
|
|
796
|
-
projectId: this.projectId,
|
|
797
|
-
avatar,
|
|
798
|
-
displayName
|
|
799
|
-
});
|
|
800
|
-
if (response.type === "IFRAME_MSG_AUTH_SUCCESS") {
|
|
801
|
-
return {
|
|
802
|
-
userId: response.userId,
|
|
803
|
-
address: response.address
|
|
804
|
-
};
|
|
805
|
-
}
|
|
806
|
-
throw new Error("Authentication failed");
|
|
807
|
-
}
|
|
808
|
-
/**
|
|
809
|
-
* Start DKG (Distributed Key Generation)
|
|
810
|
-
*/
|
|
811
|
-
async startDKG(userId, accessToken) {
|
|
812
|
-
const response = await this.sendMessage("START_DKG", {
|
|
813
|
-
userId,
|
|
814
|
-
projectId: this.projectId,
|
|
815
|
-
accessToken
|
|
816
|
-
// Pass access token for TSS API authentication
|
|
817
|
-
});
|
|
818
|
-
if (response.type === "IFRAME_MSG_DKG_SUCCESS") {
|
|
819
|
-
return response.ownerAddress;
|
|
820
|
-
}
|
|
821
|
-
throw new Error("DKG failed");
|
|
822
|
-
}
|
|
823
|
-
/**
|
|
824
|
-
* Sign transaction
|
|
825
|
-
*/
|
|
826
|
-
async signTransaction(userId, transaction, accessToken, avatar, displayName) {
|
|
827
|
-
if (!avatar || !displayName) {
|
|
828
|
-
const { jwtTokenManager } = await import("@embarkai/core/auth");
|
|
829
|
-
avatar = avatar || jwtTokenManager.getAvatar();
|
|
830
|
-
displayName = displayName || jwtTokenManager.getDisplayName();
|
|
831
|
-
}
|
|
832
|
-
const response = await this.sendMessage("SIGN_TRANSACTION", {
|
|
833
|
-
userId,
|
|
834
|
-
projectId: this.projectId,
|
|
835
|
-
transaction,
|
|
836
|
-
accessToken,
|
|
837
|
-
// Pass access token for TSS API authentication
|
|
838
|
-
avatar,
|
|
839
|
-
displayName
|
|
840
|
-
});
|
|
841
|
-
if (response.type === "IFRAME_MSG_SIGNATURE") {
|
|
842
|
-
return response.signature;
|
|
843
|
-
}
|
|
844
|
-
throw new Error("Transaction signing failed");
|
|
845
|
-
}
|
|
846
|
-
/**
|
|
847
|
-
* Sign EIP712 typed data
|
|
848
|
-
*/
|
|
849
|
-
async signTypedData(userId, typedData, digest32, accessToken, avatar, displayName) {
|
|
850
|
-
console.log("[IframeManager] signTypedData: Sending SIGN_TYPED_DATA message", {
|
|
851
|
-
userId,
|
|
852
|
-
primaryType: typedData.primaryType,
|
|
853
|
-
digest32
|
|
854
|
-
});
|
|
855
|
-
if (!avatar || !displayName) {
|
|
856
|
-
const { jwtTokenManager } = await import("@embarkai/core/auth");
|
|
857
|
-
avatar = avatar || jwtTokenManager.getAvatar();
|
|
858
|
-
displayName = displayName || jwtTokenManager.getDisplayName();
|
|
859
|
-
}
|
|
860
|
-
const response = await this.sendMessage("SIGN_TYPED_DATA", {
|
|
861
|
-
userId,
|
|
862
|
-
projectId: this.projectId,
|
|
863
|
-
typedData,
|
|
864
|
-
digest32,
|
|
865
|
-
accessToken,
|
|
866
|
-
// Pass access token for TSS API authentication
|
|
867
|
-
avatar,
|
|
868
|
-
displayName
|
|
869
|
-
});
|
|
870
|
-
console.log("[IframeManager] signTypedData: Response received", {
|
|
871
|
-
type: response.type,
|
|
872
|
-
hasSignature: !!response.signature
|
|
873
|
-
});
|
|
874
|
-
if (response.type === "IFRAME_MSG_EIP712_SIGNATURE") {
|
|
875
|
-
return response.signature;
|
|
876
|
-
}
|
|
877
|
-
throw new Error("EIP712 signing failed");
|
|
878
|
-
}
|
|
879
|
-
/**
|
|
880
|
-
* Get user's wallet address
|
|
881
|
-
*/
|
|
882
|
-
async getAddress(userId) {
|
|
883
|
-
const response = await this.sendMessage("GET_ADDRESS", {
|
|
884
|
-
userId
|
|
885
|
-
});
|
|
886
|
-
if (response.type === "IFRAME_MSG_ADDRESS") {
|
|
887
|
-
return response.address;
|
|
888
|
-
}
|
|
889
|
-
return void 0;
|
|
890
|
-
}
|
|
891
|
-
/**
|
|
892
|
-
* Check if user has a keyshare
|
|
893
|
-
*/
|
|
894
|
-
async checkKeyshare(userId) {
|
|
895
|
-
const response = await this.sendMessage("CHECK_KEYSHARE", {
|
|
896
|
-
userId
|
|
897
|
-
});
|
|
898
|
-
if (response.type === "IFRAME_MSG_KEYSHARE_STATUS") {
|
|
899
|
-
return {
|
|
900
|
-
hasKeyshare: response.hasKeyshare,
|
|
901
|
-
address: response.address
|
|
902
|
-
};
|
|
903
|
-
}
|
|
904
|
-
return { hasKeyshare: false };
|
|
905
|
-
}
|
|
906
|
-
/**
|
|
907
|
-
* Open social auth popup (Telegram, Discord, Twitter, etc.)
|
|
908
|
-
*/
|
|
909
|
-
async openSocialAuthPopup(provider, config) {
|
|
910
|
-
this.log(`[IframeManager] Opening social auth popup for provider: ${provider}`);
|
|
911
|
-
return new Promise((resolve, reject) => {
|
|
912
|
-
const normalizedProviderName = provider.toLowerCase();
|
|
913
|
-
const providerKey = normalizedProviderName === "twitter" ? "x" : normalizedProviderName;
|
|
914
|
-
const xMode = config?.mode === "link" ? "link" : "login";
|
|
915
|
-
const sessionBeforeFlow = providerKey === "x" ? this.getKnownSessionId("x") : null;
|
|
916
|
-
const connectionBeforeFlow = providerKey === "x" ? this.getKnownProviderConnection("x") : null;
|
|
917
|
-
let popupUrl;
|
|
918
|
-
if (providerKey === "telegram") {
|
|
919
|
-
const iframeOrigin = new URL(this.iframeUrl).origin;
|
|
920
|
-
const botUsername = config?.botUsername;
|
|
921
|
-
this.log("[IframeManager] Telegram config:", config);
|
|
922
|
-
this.log("[IframeManager] Bot username:", botUsername);
|
|
923
|
-
const url = new URL(`${iframeOrigin}/oauth/telegram.html`);
|
|
924
|
-
if (botUsername) {
|
|
925
|
-
url.searchParams.set("bot", botUsername);
|
|
926
|
-
}
|
|
927
|
-
popupUrl = url.toString();
|
|
928
|
-
this.log("[IframeManager] Popup URL:", popupUrl);
|
|
929
|
-
} else if (providerKey === "x") {
|
|
930
|
-
const iframeOrigin = new URL(this.iframeUrl).origin;
|
|
931
|
-
this.log("[IframeManager] X OAuth config:", config);
|
|
932
|
-
const url = new URL(`${iframeOrigin}/oauth/x.html`);
|
|
933
|
-
const { getServiceUrls: getServiceUrls2 } = (init_initial(), __toCommonJS(initial_exports));
|
|
934
|
-
const { tssUrl } = getServiceUrls2();
|
|
935
|
-
const projectId = typeof window !== "undefined" ? window.__EMBARK_PROJECT_ID__ : void 0;
|
|
936
|
-
this.log("[IframeManager] TSS URL from config:", tssUrl);
|
|
937
|
-
this.log("[IframeManager] Project ID:", projectId);
|
|
938
|
-
url.searchParams.set("tssUrl", tssUrl);
|
|
939
|
-
url.searchParams.set("mode", xMode);
|
|
940
|
-
if (projectId) {
|
|
941
|
-
url.searchParams.set("projectId", projectId);
|
|
942
|
-
}
|
|
943
|
-
if (xMode === "link" && config?.token) {
|
|
944
|
-
url.searchParams.set("token", config.token);
|
|
945
|
-
}
|
|
946
|
-
popupUrl = url.toString();
|
|
947
|
-
this.log("[IframeManager] X OAuth Popup URL:", popupUrl);
|
|
948
|
-
} else {
|
|
949
|
-
reject(new Error(`Provider ${provider} not supported yet`));
|
|
950
|
-
return;
|
|
951
|
-
}
|
|
952
|
-
const popup = window.open(
|
|
953
|
-
popupUrl,
|
|
954
|
-
`${provider}_auth`,
|
|
955
|
-
"width=550,height=650,menubar=no,toolbar=no,location=no,status=no"
|
|
956
|
-
);
|
|
957
|
-
if (!popup) {
|
|
958
|
-
reject(new Error("Failed to open popup. Please allow popups for this site."));
|
|
959
|
-
return;
|
|
960
|
-
}
|
|
961
|
-
let checkClosed;
|
|
962
|
-
let resolved = false;
|
|
963
|
-
let messageHandler = null;
|
|
964
|
-
let pendingCancellation = false;
|
|
965
|
-
const cleanup = (closePopup = true) => {
|
|
966
|
-
if (messageHandler) {
|
|
967
|
-
window.removeEventListener("message", messageHandler);
|
|
968
|
-
}
|
|
969
|
-
if (checkClosed) {
|
|
970
|
-
clearInterval(checkClosed);
|
|
971
|
-
checkClosed = void 0;
|
|
972
|
-
}
|
|
973
|
-
if (closePopup && !popup.closed) {
|
|
974
|
-
popup.close();
|
|
975
|
-
}
|
|
976
|
-
};
|
|
977
|
-
const finalize = (result, closePopup = true) => {
|
|
978
|
-
if (resolved) {
|
|
979
|
-
return;
|
|
980
|
-
}
|
|
981
|
-
resolved = true;
|
|
982
|
-
cleanup(closePopup);
|
|
983
|
-
if (result.success && providerKey === "x") {
|
|
984
|
-
this.updateProviderTrackingFromUser("x", result.user);
|
|
985
|
-
}
|
|
986
|
-
resolve({
|
|
987
|
-
provider,
|
|
988
|
-
...result
|
|
989
|
-
});
|
|
990
|
-
};
|
|
991
|
-
messageHandler = (event) => {
|
|
992
|
-
const iframeOrigin = new URL(this.iframeUrl).origin;
|
|
993
|
-
if (event.origin !== iframeOrigin) {
|
|
994
|
-
return;
|
|
995
|
-
}
|
|
996
|
-
const eventProvider = event.data.provider?.toLowerCase();
|
|
997
|
-
if (event.data.type === "TELEGRAM_AUTH_SUCCESS" && eventProvider === "telegram" && providerKey === "telegram") {
|
|
998
|
-
this.log("[IframeManager] Telegram auth successful from popup:", event.data);
|
|
999
|
-
finalize({
|
|
1000
|
-
success: true,
|
|
1001
|
-
user: event.data.user
|
|
1002
|
-
});
|
|
1003
|
-
} else if (event.data.type === "X_AUTH_SUCCESS" && eventProvider === "x" && providerKey === "x") {
|
|
1004
|
-
this.log("[IframeManager] X auth successful from popup:", event.data);
|
|
1005
|
-
if (event.data.tokens) {
|
|
1006
|
-
this.log("[IframeManager] Tokens received in postMessage, storing via jwtTokenManager");
|
|
1007
|
-
import("./auth-GP4VPOSM.js").then(({ jwtTokenManager }) => {
|
|
1008
|
-
return jwtTokenManager.setTokens({
|
|
1009
|
-
accessToken: event.data.tokens.accessToken,
|
|
1010
|
-
refreshToken: event.data.tokens.refreshToken,
|
|
1011
|
-
userId: event.data.user.userId,
|
|
1012
|
-
expiresIn: event.data.user.expiresIn || 3600,
|
|
1013
|
-
hasKeyshare: event.data.user.hasKeyshare || false,
|
|
1014
|
-
displayName: event.data.user.displayName || null,
|
|
1015
|
-
providers: event.data.user.providers || ["x"]
|
|
1016
|
-
});
|
|
1017
|
-
}).then(() => {
|
|
1018
|
-
this.log("[IframeManager] Tokens stored successfully");
|
|
1019
|
-
}).catch((tokenError) => {
|
|
1020
|
-
this.log("[IframeManager] Warning: Failed to store tokens:", tokenError);
|
|
1021
|
-
});
|
|
1022
|
-
}
|
|
1023
|
-
finalize({
|
|
1024
|
-
success: true,
|
|
1025
|
-
user: event.data.user,
|
|
1026
|
-
mode: event.data.mode
|
|
1027
|
-
});
|
|
1028
|
-
} else if (event.data.type === "TELEGRAM_AUTH_CANCELLED" && eventProvider === "telegram" && providerKey === "telegram") {
|
|
1029
|
-
this.log("[IframeManager] Telegram auth cancelled by user");
|
|
1030
|
-
finalize(
|
|
1031
|
-
{
|
|
1032
|
-
success: false,
|
|
1033
|
-
error: "User cancelled authentication"
|
|
1034
|
-
},
|
|
1035
|
-
false
|
|
1036
|
-
);
|
|
1037
|
-
} else if (event.data.type === "X_AUTH_CANCELLED" && eventProvider === "x" && providerKey === "x") {
|
|
1038
|
-
this.log("[IframeManager] X auth cancelled by user");
|
|
1039
|
-
pendingCancellation = true;
|
|
1040
|
-
this.verifyAuthSession({ provider: "x" }).then((verification) => {
|
|
1041
|
-
const sessionId = verification.sessionId || null;
|
|
1042
|
-
const providers = verification.providers || [];
|
|
1043
|
-
const isConnectedNow = providers.includes("x");
|
|
1044
|
-
const sessionChanged = !!sessionId && sessionId !== sessionBeforeFlow;
|
|
1045
|
-
const connectionGained = connectionBeforeFlow === false && isConnectedNow;
|
|
1046
|
-
if (verification.success) {
|
|
1047
|
-
if (sessionChanged || connectionGained) {
|
|
1048
|
-
this.log(
|
|
1049
|
-
"[IframeManager] X auth cancellation fallback found active session change, treating as success"
|
|
1050
|
-
);
|
|
1051
|
-
finalize(
|
|
1052
|
-
{
|
|
1053
|
-
success: true,
|
|
1054
|
-
user: verification.user,
|
|
1055
|
-
mode: xMode
|
|
1056
|
-
},
|
|
1057
|
-
true
|
|
1058
|
-
);
|
|
1059
|
-
} else {
|
|
1060
|
-
this.log("[IframeManager] X auth fallback did not detect new session, treating as cancellation");
|
|
1061
|
-
if (popup.closed) {
|
|
1062
|
-
finalize(
|
|
1063
|
-
{
|
|
1064
|
-
success: false,
|
|
1065
|
-
error: "User cancelled authentication"
|
|
1066
|
-
},
|
|
1067
|
-
false
|
|
1068
|
-
);
|
|
1069
|
-
}
|
|
1070
|
-
}
|
|
1071
|
-
} else {
|
|
1072
|
-
this.log("[IframeManager] X auth fallback verification reported no session, treating as cancellation");
|
|
1073
|
-
if (popup.closed) {
|
|
1074
|
-
finalize(
|
|
1075
|
-
{
|
|
1076
|
-
success: false,
|
|
1077
|
-
error: "User cancelled authentication"
|
|
1078
|
-
},
|
|
1079
|
-
false
|
|
1080
|
-
);
|
|
1081
|
-
}
|
|
1082
|
-
}
|
|
1083
|
-
}).catch((error) => {
|
|
1084
|
-
this.log("[IframeManager] X auth fallback verification error:", error);
|
|
1085
|
-
if (popup.closed) {
|
|
1086
|
-
finalize(
|
|
1087
|
-
{
|
|
1088
|
-
success: false,
|
|
1089
|
-
error: "User cancelled authentication"
|
|
1090
|
-
},
|
|
1091
|
-
false
|
|
1092
|
-
);
|
|
1093
|
-
}
|
|
1094
|
-
});
|
|
1095
|
-
} else if (event.data.type === "X_AUTH_ERROR" && eventProvider === "x" && providerKey === "x") {
|
|
1096
|
-
this.log("[IframeManager] X auth error from popup:", event.data.error);
|
|
1097
|
-
finalize({
|
|
1098
|
-
success: false,
|
|
1099
|
-
error: event.data.error || "Authentication failed"
|
|
1100
|
-
});
|
|
1101
|
-
}
|
|
1102
|
-
};
|
|
1103
|
-
window.addEventListener("message", messageHandler);
|
|
1104
|
-
checkClosed = setInterval(() => {
|
|
1105
|
-
if (popup.closed) {
|
|
1106
|
-
if (checkClosed) {
|
|
1107
|
-
clearInterval(checkClosed);
|
|
1108
|
-
checkClosed = void 0;
|
|
1109
|
-
}
|
|
1110
|
-
if (!resolved) {
|
|
1111
|
-
if (providerKey === "x" && pendingCancellation) {
|
|
1112
|
-
finalize(
|
|
1113
|
-
{
|
|
1114
|
-
success: false,
|
|
1115
|
-
error: "User cancelled authentication"
|
|
1116
|
-
},
|
|
1117
|
-
false
|
|
1118
|
-
);
|
|
1119
|
-
} else {
|
|
1120
|
-
finalize(
|
|
1121
|
-
{
|
|
1122
|
-
success: false,
|
|
1123
|
-
error: "Popup was closed"
|
|
1124
|
-
},
|
|
1125
|
-
false
|
|
1126
|
-
);
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1130
|
-
}, 500);
|
|
1131
|
-
});
|
|
1132
|
-
}
|
|
1133
|
-
/**
|
|
1134
|
-
* Verify current auth session with the backend.
|
|
1135
|
-
* Can optionally track session state for a specific provider.
|
|
1136
|
-
* @param options.silent - If true, suppress logging
|
|
1137
|
-
* @param options.provider - Optional provider key to track session state for (e.g., 'x', 'telegram')
|
|
1138
|
-
*/
|
|
1139
|
-
async verifyAuthSession(options = {}) {
|
|
1140
|
-
if (typeof window === "undefined" || typeof fetch === "undefined") {
|
|
1141
|
-
return { success: false };
|
|
1142
|
-
}
|
|
1143
|
-
try {
|
|
1144
|
-
const { getServiceUrls: getServiceUrls2 } = (init_initial(), __toCommonJS(initial_exports));
|
|
1145
|
-
const { tssUrl } = getServiceUrls2();
|
|
1146
|
-
const projectId = typeof window !== "undefined" ? window.__EMBARK_PROJECT_ID__ : void 0;
|
|
1147
|
-
if (!tssUrl) {
|
|
1148
|
-
this.log("[IframeManager] Session verify aborted: missing TSS URL");
|
|
1149
|
-
return { success: false };
|
|
1150
|
-
}
|
|
1151
|
-
const verifyUrl = new URL(`${tssUrl}/api/auth/verify`);
|
|
1152
|
-
if (projectId) {
|
|
1153
|
-
verifyUrl.searchParams.set("projectId", projectId);
|
|
1154
|
-
}
|
|
1155
|
-
const { jwtTokenManager, ensureValidToken } = await import("./auth-GP4VPOSM.js");
|
|
1156
|
-
const hasValidToken = await ensureValidToken();
|
|
1157
|
-
const headers = {
|
|
1158
|
-
"Content-Type": "application/json"
|
|
1159
|
-
};
|
|
1160
|
-
if (hasValidToken) {
|
|
1161
|
-
const accessToken = jwtTokenManager.getAccessToken();
|
|
1162
|
-
if (accessToken) {
|
|
1163
|
-
headers["Authorization"] = `Bearer ${accessToken}`;
|
|
1164
|
-
}
|
|
1165
|
-
}
|
|
1166
|
-
let response = await fetch(verifyUrl.toString(), {
|
|
1167
|
-
method: "GET",
|
|
1168
|
-
headers,
|
|
1169
|
-
credentials: "include"
|
|
1170
|
-
});
|
|
1171
|
-
if (response.status === 401) {
|
|
1172
|
-
this.log("[IframeManager] Session verify got 401, attempting token refresh...");
|
|
1173
|
-
const refreshSuccess = await jwtTokenManager.refreshAccessToken();
|
|
1174
|
-
if (refreshSuccess) {
|
|
1175
|
-
const newAccessToken = jwtTokenManager.getAccessToken();
|
|
1176
|
-
if (newAccessToken) {
|
|
1177
|
-
headers["Authorization"] = `Bearer ${newAccessToken}`;
|
|
1178
|
-
this.log("[IframeManager] Token refreshed, retrying verify...");
|
|
1179
|
-
response = await fetch(verifyUrl.toString(), {
|
|
1180
|
-
method: "GET",
|
|
1181
|
-
headers,
|
|
1182
|
-
credentials: "include"
|
|
1183
|
-
});
|
|
1184
|
-
}
|
|
1185
|
-
}
|
|
1186
|
-
}
|
|
1187
|
-
if (!response.ok) {
|
|
1188
|
-
this.log("[IframeManager] Session verify returned status:", response.status);
|
|
1189
|
-
if (options.provider) {
|
|
1190
|
-
this.recordProviderSession(options.provider, null);
|
|
1191
|
-
this.recordProviderConnection(options.provider, false);
|
|
1192
|
-
}
|
|
1193
|
-
return { success: false };
|
|
1194
|
-
}
|
|
1195
|
-
let userData = void 0;
|
|
1196
|
-
try {
|
|
1197
|
-
userData = await response.json();
|
|
1198
|
-
} catch (jsonError) {
|
|
1199
|
-
this.log("[IframeManager] Session verify JSON parse failed:", jsonError);
|
|
1200
|
-
}
|
|
1201
|
-
const sessionId = this.extractSessionId(userData);
|
|
1202
|
-
const providers = this.getProvidersList(userData);
|
|
1203
|
-
if (options.provider) {
|
|
1204
|
-
this.recordProviderSession(options.provider, sessionId);
|
|
1205
|
-
this.recordProviderConnection(options.provider, providers.includes(options.provider));
|
|
1206
|
-
}
|
|
1207
|
-
if (!options.silent) {
|
|
1208
|
-
this.log("[IframeManager] Session verify result:", {
|
|
1209
|
-
sessionId,
|
|
1210
|
-
providers
|
|
1211
|
-
});
|
|
1212
|
-
}
|
|
1213
|
-
return {
|
|
1214
|
-
success: true,
|
|
1215
|
-
user: userData,
|
|
1216
|
-
sessionId,
|
|
1217
|
-
providers
|
|
1218
|
-
};
|
|
1219
|
-
} catch (error) {
|
|
1220
|
-
this.log("[IframeManager] Session verify error:", error);
|
|
1221
|
-
if (options.provider) {
|
|
1222
|
-
this.recordProviderSession(options.provider, null);
|
|
1223
|
-
this.recordProviderConnection(options.provider, false);
|
|
1224
|
-
}
|
|
1225
|
-
return { success: false };
|
|
1226
|
-
}
|
|
1227
|
-
}
|
|
1228
|
-
/**
|
|
1229
|
-
* Prime provider session/cache state to detect future changes.
|
|
1230
|
-
*/
|
|
1231
|
-
async primeProviderSessions() {
|
|
1232
|
-
try {
|
|
1233
|
-
await this.verifyAuthSession({ silent: true });
|
|
1234
|
-
} catch (error) {
|
|
1235
|
-
this.log("[IframeManager] Prime provider sessions failed:", error);
|
|
1236
|
-
}
|
|
1237
|
-
}
|
|
1238
|
-
getKnownSessionId(providerKey) {
|
|
1239
|
-
return this.providerSessions.has(providerKey) ? this.providerSessions.get(providerKey) ?? null : null;
|
|
1240
|
-
}
|
|
1241
|
-
getKnownProviderConnection(providerKey) {
|
|
1242
|
-
if (!this.providerConnections.has(providerKey)) {
|
|
1243
|
-
return null;
|
|
1244
|
-
}
|
|
1245
|
-
const value = this.providerConnections.get(providerKey);
|
|
1246
|
-
return typeof value === "boolean" ? value : null;
|
|
1247
|
-
}
|
|
1248
|
-
recordProviderSession(providerKey, sessionId) {
|
|
1249
|
-
this.providerSessions.set(providerKey, sessionId ?? null);
|
|
1250
|
-
}
|
|
1251
|
-
recordProviderConnection(providerKey, connected) {
|
|
1252
|
-
this.providerConnections.set(providerKey, connected);
|
|
1253
|
-
}
|
|
1254
|
-
updateProviderTrackingFromUser(providerKey, user) {
|
|
1255
|
-
if (!user) {
|
|
1256
|
-
return;
|
|
1257
|
-
}
|
|
1258
|
-
if (providerKey === "x") {
|
|
1259
|
-
const sessionId = this.extractSessionId(user);
|
|
1260
|
-
this.recordProviderSession("x", sessionId);
|
|
1261
|
-
const providers = this.getProvidersList(user);
|
|
1262
|
-
this.recordProviderConnection("x", providers.includes("x"));
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1265
|
-
extractSessionId(user) {
|
|
1266
|
-
if (!user || typeof user !== "object") {
|
|
1267
|
-
return null;
|
|
1268
|
-
}
|
|
1269
|
-
if (typeof user.sessionId === "string") {
|
|
1270
|
-
return user.sessionId;
|
|
1271
|
-
}
|
|
1272
|
-
if (user.data && typeof user.data.sessionId === "string") {
|
|
1273
|
-
return user.data.sessionId;
|
|
1274
|
-
}
|
|
1275
|
-
return null;
|
|
1276
|
-
}
|
|
1277
|
-
getProvidersList(user) {
|
|
1278
|
-
if (!user || typeof user !== "object") {
|
|
1279
|
-
return [];
|
|
1280
|
-
}
|
|
1281
|
-
const providersRaw = user.providers || user.data?.providers;
|
|
1282
|
-
if (!Array.isArray(providersRaw)) {
|
|
1283
|
-
return [];
|
|
1284
|
-
}
|
|
1285
|
-
return providersRaw.map((provider) => typeof provider === "string" ? provider.toLowerCase() : null).filter((provider) => provider !== null);
|
|
1286
|
-
}
|
|
1287
|
-
/**
|
|
1288
|
-
* Get trusted apps for user
|
|
1289
|
-
*/
|
|
1290
|
-
async getTrustedApps(userId) {
|
|
1291
|
-
const response = await this.sendMessage("GET_TRUSTED_APPS", {
|
|
1292
|
-
userId
|
|
1293
|
-
});
|
|
1294
|
-
if (response.type === "IFRAME_MSG_TRUSTED_APPS_LIST") {
|
|
1295
|
-
return response.apps || [];
|
|
1296
|
-
}
|
|
1297
|
-
return [];
|
|
1298
|
-
}
|
|
1299
|
-
/**
|
|
1300
|
-
* Remove app from trusted list
|
|
1301
|
-
*/
|
|
1302
|
-
async removeTrustedApp(userId, projectId, origin) {
|
|
1303
|
-
const response = await this.sendMessage("REMOVE_TRUSTED_APP", {
|
|
1304
|
-
userId,
|
|
1305
|
-
projectId,
|
|
1306
|
-
appOrigin: origin
|
|
1307
|
-
});
|
|
1308
|
-
if (response.type === "IFRAME_MSG_TRUSTED_APP_REMOVED") {
|
|
1309
|
-
return response.success;
|
|
1310
|
-
}
|
|
1311
|
-
return false;
|
|
1312
|
-
}
|
|
1313
|
-
/**
|
|
1314
|
-
* Clear all authorizations for current project (for testing consent flow)
|
|
1315
|
-
* This will force the consent modal to appear on next authentication
|
|
1316
|
-
*/
|
|
1317
|
-
async clearAuthorizations() {
|
|
1318
|
-
try {
|
|
1319
|
-
const response = await this.sendMessage("CLEAR_AUTHORIZATIONS", {
|
|
1320
|
-
projectId: this.projectId
|
|
1321
|
-
});
|
|
1322
|
-
this.log("[IframeManager] Cleared authorizations for project:", this.projectId);
|
|
1323
|
-
return response.success || true;
|
|
1324
|
-
} catch (error) {
|
|
1325
|
-
this.log("[IframeManager] Failed to clear authorizations:", error);
|
|
1326
|
-
return false;
|
|
1327
|
-
}
|
|
1328
|
-
}
|
|
1329
|
-
/**
|
|
1330
|
-
* Create backup of keyshare
|
|
1331
|
-
*/
|
|
1332
|
-
async createBackup(userId, backupRequest, accessToken) {
|
|
1333
|
-
const response = await this.sendMessage("CREATE_BACKUP", {
|
|
1334
|
-
userId,
|
|
1335
|
-
backupRequest,
|
|
1336
|
-
accessToken
|
|
1337
|
-
// Pass access token for TSS API authentication
|
|
1338
|
-
});
|
|
1339
|
-
if (response.type === "IFRAME_MSG_BACKUP_CREATED") {
|
|
1340
|
-
return response.result;
|
|
1341
|
-
}
|
|
1342
|
-
throw new Error("Unexpected response type");
|
|
1343
|
-
}
|
|
1344
|
-
/**
|
|
1345
|
-
* Restore keyshare from server backup
|
|
1346
|
-
*/
|
|
1347
|
-
async restoreFromServer(userId, password, accessToken) {
|
|
1348
|
-
const response = await this.sendMessage("RESTORE_BACKUP", {
|
|
1349
|
-
userId,
|
|
1350
|
-
password,
|
|
1351
|
-
accessToken
|
|
1352
|
-
// Pass access token for TSS API authentication
|
|
1353
|
-
});
|
|
1354
|
-
if (response.type === "IFRAME_MSG_BACKUP_RESTORED") {
|
|
1355
|
-
return response.result;
|
|
1356
|
-
}
|
|
1357
|
-
throw new Error("Unexpected response type");
|
|
1358
|
-
}
|
|
1359
|
-
/**
|
|
1360
|
-
* Encrypt backup data without uploading (for cloud/local backups)
|
|
1361
|
-
* Returns encrypted data that parent can upload/download
|
|
1362
|
-
*/
|
|
1363
|
-
async encryptBackupData(userId, password) {
|
|
1364
|
-
const response = await this.sendMessage("ENCRYPT_BACKUP_DATA", {
|
|
1365
|
-
userId,
|
|
1366
|
-
password
|
|
1367
|
-
});
|
|
1368
|
-
if (response.type === "IFRAME_MSG_BACKUP_ENCRYPTED") {
|
|
1369
|
-
return response.encryptedData;
|
|
1370
|
-
}
|
|
1371
|
-
throw new Error("Unexpected response type");
|
|
1372
|
-
}
|
|
1373
|
-
/**
|
|
1374
|
-
* Encrypt current keyshare as EnvelopeEncryptedShare (for Guardian backup)
|
|
1375
|
-
*/
|
|
1376
|
-
async encryptEnvelopeData(userId, password) {
|
|
1377
|
-
const response = await this.sendMessage("ENCRYPT_ENVELOPE_DATA", { userId, password });
|
|
1378
|
-
if (response.type === "IFRAME_MSG_ENVELOPE_ENCRYPTED") {
|
|
1379
|
-
return response.envelopeJson;
|
|
1380
|
-
}
|
|
1381
|
-
throw new Error("Unexpected response type");
|
|
1382
|
-
}
|
|
1383
|
-
/**
|
|
1384
|
-
* Decrypt EnvelopeEncryptedShare and restore keyshare (for Guardian restore)
|
|
1385
|
-
*/
|
|
1386
|
-
async decryptAndRestoreEnvelope(userId, envelopeJson, password) {
|
|
1387
|
-
const response = await this.sendMessage("DECRYPT_AND_RESTORE_ENVELOPE", {
|
|
1388
|
-
userId,
|
|
1389
|
-
envelopeJson,
|
|
1390
|
-
password
|
|
1391
|
-
});
|
|
1392
|
-
if (response.type === "IFRAME_MSG_ENVELOPE_RESTORED") {
|
|
1393
|
-
return response.result;
|
|
1394
|
-
}
|
|
1395
|
-
throw new Error("Unexpected response type");
|
|
1396
|
-
}
|
|
1397
|
-
/**
|
|
1398
|
-
* Restore keyshare from local file backup
|
|
1399
|
-
*/
|
|
1400
|
-
async restoreFromLocalFile(userId, fileContent, password) {
|
|
1401
|
-
const response = await this.sendMessage("RESTORE_FROM_FILE", {
|
|
1402
|
-
userId,
|
|
1403
|
-
fileContent,
|
|
1404
|
-
password
|
|
1405
|
-
});
|
|
1406
|
-
if (response.type === "IFRAME_MSG_FILE_RESTORED") {
|
|
1407
|
-
return response.result;
|
|
1408
|
-
}
|
|
1409
|
-
throw new Error("Unexpected response type");
|
|
1410
|
-
}
|
|
1411
|
-
/**
|
|
1412
|
-
* Get backup status for user
|
|
1413
|
-
*/
|
|
1414
|
-
async getBackupStatus(userId) {
|
|
1415
|
-
const response = await this.sendMessage("GET_BACKUP_STATUS", {
|
|
1416
|
-
userId
|
|
1417
|
-
});
|
|
1418
|
-
if (response.type === "IFRAME_MSG_BACKUP_STATUS") {
|
|
1419
|
-
return response.status;
|
|
1420
|
-
}
|
|
1421
|
-
throw new Error("Unexpected response type");
|
|
1422
|
-
}
|
|
1423
|
-
/**
|
|
1424
|
-
* Get available cloud providers
|
|
1425
|
-
*/
|
|
1426
|
-
async getCloudProviders() {
|
|
1427
|
-
const response = await this.sendMessage("GET_CLOUD_PROVIDERS", {});
|
|
1428
|
-
if (response.type === "IFRAME_MSG_CLOUD_PROVIDERS") {
|
|
1429
|
-
return response.providers;
|
|
1430
|
-
}
|
|
1431
|
-
throw new Error("Unexpected response type");
|
|
1432
|
-
}
|
|
1433
|
-
/**
|
|
1434
|
-
* Cleanup and destroy iframe
|
|
1435
|
-
*/
|
|
1436
|
-
destroy() {
|
|
1437
|
-
this.log("[IframeManager] Destroying iframe...");
|
|
1438
|
-
this.stopHeartbeat();
|
|
1439
|
-
this.pendingRequests.forEach((pending) => {
|
|
1440
|
-
pending.reject(new Error("Iframe manager destroyed"));
|
|
1441
|
-
});
|
|
1442
|
-
this.pendingRequests.clear();
|
|
1443
|
-
if (this.messageListener) {
|
|
1444
|
-
window.removeEventListener("message", this.messageListener);
|
|
1445
|
-
this.messageListener = null;
|
|
1446
|
-
}
|
|
1447
|
-
if (this.iframe && this.iframe.parentNode) {
|
|
1448
|
-
this.iframe.parentNode.removeChild(this.iframe);
|
|
1449
|
-
}
|
|
1450
|
-
this.iframe = null;
|
|
1451
|
-
this.isReady = false;
|
|
1452
|
-
this.channelToken = null;
|
|
1453
|
-
this.initPromise = null;
|
|
1454
|
-
this.readyPromise = new Promise((resolve) => {
|
|
1455
|
-
this.readyResolve = resolve;
|
|
1456
|
-
});
|
|
1457
|
-
this.log("[IframeManager] \u2705 Destroyed");
|
|
1458
|
-
}
|
|
1459
|
-
/**
|
|
1460
|
-
* Debug logging
|
|
1461
|
-
*/
|
|
1462
|
-
log(message, data) {
|
|
1463
|
-
if (this.debug) {
|
|
1464
|
-
if (data) {
|
|
1465
|
-
console.log(message, data);
|
|
1466
|
-
} else {
|
|
1467
|
-
console.log(message);
|
|
1468
|
-
}
|
|
1469
|
-
}
|
|
1470
|
-
}
|
|
1471
|
-
};
|
|
1472
|
-
var iframeManagerInstance = null;
|
|
1473
|
-
function getIframeManager(config) {
|
|
1474
|
-
if (!iframeManagerInstance && config) {
|
|
1475
|
-
iframeManagerInstance = new IframeManager(config);
|
|
1476
|
-
}
|
|
1477
|
-
if (!iframeManagerInstance) {
|
|
1478
|
-
throw new Error(
|
|
1479
|
-
'IframeManager not initialized. This usually means projectId is not configured.\n\nTo fix this:\n1. Get your projectId from https://dashboard.lumiapassport.com/\n2. Add it to Provider:\n <Provider projectId="your-project-id">\n\nFor more details, see the documentation.'
|
|
1480
|
-
);
|
|
1481
|
-
}
|
|
1482
|
-
return iframeManagerInstance;
|
|
1483
|
-
}
|
|
1484
|
-
async function waitForIframe() {
|
|
1485
|
-
const manager = getIframeManager();
|
|
1486
|
-
await manager.initialize();
|
|
1487
|
-
}
|
|
1488
|
-
function destroyIframeManager() {
|
|
1489
|
-
if (iframeManagerInstance) {
|
|
1490
|
-
iframeManagerInstance.destroy();
|
|
1491
|
-
iframeManagerInstance = null;
|
|
1492
|
-
}
|
|
1493
|
-
}
|
|
1494
|
-
|
|
1495
|
-
export {
|
|
1496
|
-
GoogleIcon,
|
|
1497
|
-
TelegramIcon,
|
|
1498
|
-
TwitterIcon,
|
|
1499
|
-
DiscordIcon,
|
|
1500
|
-
init_assets,
|
|
1501
|
-
DEFAULT_PROVIDER_CONFIG,
|
|
1502
|
-
getServiceUrls,
|
|
1503
|
-
getIframeUrl,
|
|
1504
|
-
getBlockscoutApiUrl,
|
|
1505
|
-
init_initial,
|
|
1506
|
-
AccountAbstractionError,
|
|
1507
|
-
UserRejectedError,
|
|
1508
|
-
ErrorCodes,
|
|
1509
|
-
createAccountAbstractionError,
|
|
1510
|
-
IframeManager,
|
|
1511
|
-
getIframeManager,
|
|
1512
|
-
waitForIframe,
|
|
1513
|
-
destroyIframeManager
|
|
1514
|
-
};
|
|
1515
|
-
//# sourceMappingURL=chunk-MLUPZCC3.js.map
|