@arcblock/did-connect-service 4.1.21 → 4.1.23
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/_generated/asset-bytes.js +1 -1
- package/dist/_generated/asset-manifest.js +3 -3
- package/dist/assets/admin-core.1fc3260c.js +1623 -0
- package/dist/assets/admin-core.5a2d69b0.js +2067 -0
- package/dist/assets/admin-core.9fff6042.js +2083 -0
- package/dist/assets/admin-core.a13c2729.js +1461 -0
- package/dist/assets/{admin-core.40671087.js → admin-core.a63bbc69.js} +2 -12
- package/dist/assets/admin-core.c0b5af61.js +1393 -0
- package/dist/assets/admin-core.cbbdbe6d.js +1465 -0
- package/dist/assets/admin-core.e83fd379.js +1397 -0
- package/dist/assets/admin-extra.143b5774.js +2543 -0
- package/dist/assets/admin-extra.35b91f98.js +2543 -0
- package/dist/assets/admin-extra.531b187f.js +2552 -0
- package/dist/assets/admin-extra.7ca9c16b.js +2529 -0
- package/dist/assets/admin-extra.841b2bbe.js +2530 -0
- package/dist/assets/admin-extra.afcb3651.js +2528 -0
- package/dist/assets/admin.7c5d5f04.css +2312 -0
- package/dist/assets/admin.c26bb17a.css +2219 -0
- package/dist/assets/login.4404e695.js +720 -0
- package/dist/assets/login.bb9f8b03.js +720 -0
- package/dist/assets/login.d3f05790.js +720 -0
- package/dist/assets/login.fa25f37a.js +720 -0
- package/dist/blocklet-service-rpc.d.ts.map +1 -1
- package/dist/blocklet-service-rpc.js +11 -8
- package/dist/blocklet-service-rpc.js.map +1 -1
- package/dist/blocklet-service.d.ts +11 -8
- package/dist/blocklet-service.d.ts.map +1 -1
- package/dist/blocklet-service.js +32 -38
- package/dist/blocklet-service.js.map +1 -1
- package/dist/embedded.d.ts +6 -0
- package/dist/embedded.d.ts.map +1 -1
- package/dist/embedded.js +1 -0
- package/dist/embedded.js.map +1 -1
- package/dist/handlers/account-merge-handler.d.ts +63 -0
- package/dist/handlers/account-merge-handler.d.ts.map +1 -0
- package/dist/handlers/account-merge-handler.js +263 -0
- package/dist/handlers/account-merge-handler.js.map +1 -0
- package/dist/handlers/auth-handler.d.ts +9 -5
- package/dist/handlers/auth-handler.d.ts.map +1 -1
- package/dist/handlers/auth-handler.js +28 -7
- package/dist/handlers/auth-handler.js.map +1 -1
- package/dist/handlers/blocklet-js-handler.d.ts +3 -2
- package/dist/handlers/blocklet-js-handler.d.ts.map +1 -1
- package/dist/handlers/blocklet-js-handler.js +4 -2
- package/dist/handlers/blocklet-js-handler.js.map +1 -1
- package/dist/handlers/branding-handler.d.ts +4 -0
- package/dist/handlers/branding-handler.d.ts.map +1 -1
- package/dist/handlers/branding-handler.js +12 -6
- package/dist/handlers/branding-handler.js.map +1 -1
- package/dist/handlers/cimd.d.ts +6 -1
- package/dist/handlers/cimd.d.ts.map +1 -1
- package/dist/handlers/cimd.js +12 -2
- package/dist/handlers/cimd.js.map +1 -1
- package/dist/handlers/did-connect-handler.d.ts +22 -0
- package/dist/handlers/did-connect-handler.d.ts.map +1 -1
- package/dist/handlers/did-connect-handler.js +191 -17
- package/dist/handlers/did-connect-handler.js.map +1 -1
- package/dist/handlers/email-login-handler.d.ts +2 -0
- package/dist/handlers/email-login-handler.d.ts.map +1 -1
- package/dist/handlers/email-login-handler.js +30 -14
- package/dist/handlers/email-login-handler.js.map +1 -1
- package/dist/handlers/oauth-handler.d.ts +15 -0
- package/dist/handlers/oauth-handler.d.ts.map +1 -1
- package/dist/handlers/oauth-handler.js +107 -43
- package/dist/handlers/oauth-handler.js.map +1 -1
- package/dist/handlers/passkey-handler.d.ts.map +1 -1
- package/dist/handlers/passkey-handler.js +40 -8
- package/dist/handlers/passkey-handler.js.map +1 -1
- package/dist/handlers/team-handler.d.ts +1 -1
- package/dist/handlers/team-handler.d.ts.map +1 -1
- package/dist/handlers/team-handler.js +43 -3
- package/dist/handlers/team-handler.js.map +1 -1
- package/dist/handlers/ticket-handler.d.ts.map +1 -1
- package/dist/handlers/ticket-handler.js +4 -2
- package/dist/handlers/ticket-handler.js.map +1 -1
- package/dist/handlers/unbind-account.d.ts +22 -0
- package/dist/handlers/unbind-account.d.ts.map +1 -0
- package/dist/handlers/unbind-account.js +20 -0
- package/dist/handlers/unbind-account.js.map +1 -0
- package/dist/http/security-headers.d.ts +38 -0
- package/dist/http/security-headers.d.ts.map +1 -0
- package/dist/http/security-headers.js +67 -0
- package/dist/http/security-headers.js.map +1 -0
- package/dist/identity/account-state.d.ts +37 -0
- package/dist/identity/account-state.d.ts.map +1 -0
- package/dist/identity/account-state.js +97 -0
- package/dist/identity/account-state.js.map +1 -0
- package/dist/identity/json-content-type.d.ts +14 -0
- package/dist/identity/json-content-type.d.ts.map +1 -0
- package/dist/identity/json-content-type.js +26 -0
- package/dist/identity/json-content-type.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/oauth-adapters/apple.d.ts +1 -1
- package/dist/oauth-adapters/apple.d.ts.map +1 -1
- package/dist/oauth-adapters/apple.js +2 -0
- package/dist/oauth-adapters/apple.js.map +1 -1
- package/dist/oauth-adapters/auth0-legacy.d.ts +1 -1
- package/dist/oauth-adapters/auth0-legacy.d.ts.map +1 -1
- package/dist/oauth-adapters/auth0-legacy.js +2 -0
- package/dist/oauth-adapters/auth0-legacy.js.map +1 -1
- package/dist/oauth-adapters/auth0.d.ts +1 -1
- package/dist/oauth-adapters/auth0.d.ts.map +1 -1
- package/dist/oauth-adapters/auth0.js +2 -0
- package/dist/oauth-adapters/auth0.js.map +1 -1
- package/dist/oauth-adapters/github.d.ts.map +1 -1
- package/dist/oauth-adapters/github.js +19 -12
- package/dist/oauth-adapters/github.js.map +1 -1
- package/dist/oauth-adapters/google.d.ts +1 -1
- package/dist/oauth-adapters/google.d.ts.map +1 -1
- package/dist/oauth-adapters/google.js +2 -0
- package/dist/oauth-adapters/google.js.map +1 -1
- package/dist/oauth-adapters/types.d.ts +7 -0
- package/dist/oauth-adapters/types.d.ts.map +1 -1
- package/dist/oauth-adapters/types.js +4 -1
- package/dist/oauth-adapters/types.js.map +1 -1
- package/dist/package-branding.d.ts +18 -0
- package/dist/package-branding.d.ts.map +1 -0
- package/dist/package-branding.js +103 -0
- package/dist/package-branding.js.map +1 -0
- package/dist/pages/admin/i18n.d.ts.map +1 -1
- package/dist/pages/admin/i18n.js +86 -0
- package/dist/pages/admin/i18n.js.map +1 -1
- package/dist/pages/admin/index.d.ts +4 -0
- package/dist/pages/admin/index.d.ts.map +1 -1
- package/dist/pages/admin/index.js +10 -2
- package/dist/pages/admin/index.js.map +1 -1
- package/dist/pages/admin/merge-confirm-view.d.ts +48 -0
- package/dist/pages/admin/merge-confirm-view.d.ts.map +1 -0
- package/dist/pages/admin/merge-confirm-view.js +85 -0
- package/dist/pages/admin/merge-confirm-view.js.map +1 -0
- package/dist/pages/admin/merge-method-picker.d.ts +12 -0
- package/dist/pages/admin/merge-method-picker.d.ts.map +1 -0
- package/dist/pages/admin/merge-method-picker.js +34 -0
- package/dist/pages/admin/merge-method-picker.js.map +1 -0
- package/dist/pages/admin/oauth-popup-close.d.ts +13 -0
- package/dist/pages/admin/oauth-popup-close.d.ts.map +1 -0
- package/dist/pages/admin/oauth-popup-close.js +15 -0
- package/dist/pages/admin/oauth-popup-close.js.map +1 -0
- package/dist/pages/admin/styles.d.ts +1 -1
- package/dist/pages/admin/styles.d.ts.map +1 -1
- package/dist/pages/admin/styles.js +83 -0
- package/dist/pages/admin/styles.js.map +1 -1
- package/dist/pages/admin/tab-audit.d.ts +1 -1
- package/dist/pages/admin/tab-audit.d.ts.map +1 -1
- package/dist/pages/admin/tab-audit.js +12 -0
- package/dist/pages/admin/tab-audit.js.map +1 -1
- package/dist/pages/admin/tab-profile-accounts.d.ts.map +1 -1
- package/dist/pages/admin/tab-profile-accounts.js +509 -3
- package/dist/pages/admin/tab-profile-accounts.js.map +1 -1
- package/dist/pages/invite-page.d.ts +1 -0
- package/dist/pages/invite-page.d.ts.map +1 -1
- package/dist/pages/invite-page.js +13 -3
- package/dist/pages/invite-page.js.map +1 -1
- package/dist/store/account-merge.d.ts +167 -0
- package/dist/store/account-merge.d.ts.map +1 -0
- package/dist/store/account-merge.js +313 -0
- package/dist/store/account-merge.js.map +1 -0
- package/dist/store/d1-store.d.ts +97 -7
- package/dist/store/d1-store.d.ts.map +1 -1
- package/dist/store/d1-store.js +421 -23
- package/dist/store/d1-store.js.map +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/migrations/0015_connected_accounts_id_index.sql +6 -0
- package/migrations/0016_did_aliases.sql +11 -0
- package/migrations/0017_unbind_revoke_and_cascade.sql +49 -0
- package/migrations/0018_primary_credential_did.sql +54 -0
- package/migrations/0019_account_merge.sql +16 -0
- package/migrations/0020_dedupe_connected_accounts.sql +24 -0
- package/package.json +3 -3
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
* Grouped chip layout: bound accounts as chips, unbound as dashed add-chips.
|
|
4
4
|
*/
|
|
5
5
|
import { ICON_DID_WALLET, ICON_EMAIL, ICON_PASSKEY, OAUTH_ICONS, } from "@arcblock/did-connect-core/ui";
|
|
6
|
+
import { renderMergeConfirmBodyHtml, toMergeConfirmViewModel } from "./merge-confirm-view.js";
|
|
7
|
+
import { renderMergeMethodPickerHtml } from "./merge-method-picker.js";
|
|
8
|
+
import { OAUTH_POPUP_CLOSE_GRACE_MS, oauthPopupClosedShouldCancel } from "./oauth-popup-close.js";
|
|
6
9
|
/** Providers hidden from the Connected Accounts UI. */
|
|
7
10
|
const HIDDEN_PROVIDERS = new Set(["facebook", "auth0-legacy"]);
|
|
8
11
|
/** Build a JS-safe icon map to embed in inline <script>. */
|
|
@@ -26,6 +29,7 @@ export function connectedAccountsCardHtml(t) {
|
|
|
26
29
|
<div class="settings-card-header">
|
|
27
30
|
<span class="settings-card-title">${t("profile.connectedAccounts")}</span>
|
|
28
31
|
</div>
|
|
32
|
+
<div id="merge-candidate-prompt" class="ca-merge-prompt" style="display:none;" hidden></div>
|
|
29
33
|
<div id="connected-accounts-list"></div>
|
|
30
34
|
</div>
|
|
31
35
|
`;
|
|
@@ -35,12 +39,20 @@ export function connectedAccountsCardHtml(t) {
|
|
|
35
39
|
export const CONNECTED_ACCOUNTS_SCRIPT = /* @__PURE__ */ (() => /* js */ `
|
|
36
40
|
var __connectedAccounts = [];
|
|
37
41
|
var __oauthProviders = [];
|
|
42
|
+
var __accountMergeOAuthCleanup = null;
|
|
43
|
+
var __mergePromptDid = "";
|
|
38
44
|
var __providerIcons = ${buildIconMapJSON()};
|
|
39
45
|
var __hiddenProviders = ${JSON.stringify([...HIDDEN_PROVIDERS])};
|
|
46
|
+
${toMergeConfirmViewModel.toString()}
|
|
47
|
+
${renderMergeConfirmBodyHtml.toString()}
|
|
48
|
+
${renderMergeMethodPickerHtml.toString()}
|
|
49
|
+
${oauthPopupClosedShouldCancel.toString()}
|
|
50
|
+
var __oauthPopupCloseGraceMs = ${OAUTH_POPUP_CLOSE_GRACE_MS};
|
|
40
51
|
|
|
41
52
|
async function loadConnectedAccounts() {
|
|
42
53
|
var card = document.getElementById("connected-accounts-card");
|
|
43
54
|
var list = document.getElementById("connected-accounts-list");
|
|
55
|
+
hideMergePrompt();
|
|
44
56
|
|
|
45
57
|
// Show card with skeleton chips while loading
|
|
46
58
|
card.style.display = "";
|
|
@@ -69,6 +81,7 @@ async function loadConnectedAccounts() {
|
|
|
69
81
|
|
|
70
82
|
card.style.display = "";
|
|
71
83
|
renderConnectedAccounts();
|
|
84
|
+
maybeShowMergePrompt(userObj.did);
|
|
72
85
|
}
|
|
73
86
|
|
|
74
87
|
function renderConnectedAccounts() {
|
|
@@ -166,6 +179,12 @@ function renderConnectedAccounts() {
|
|
|
166
179
|
html += '</div></div>';
|
|
167
180
|
}
|
|
168
181
|
|
|
182
|
+
html += '<div class="ca-section">';
|
|
183
|
+
html += '<div class="ca-section-label">' + __t("profile.mergeAccount") + '</div>';
|
|
184
|
+
html += '<p class="ca-merge-hint" style="margin:0 0 8px;color:var(--text-secondary);font-size:13px;">' + __t("profile.mergeAccountHint") + '</p>';
|
|
185
|
+
html += '<button class="btn btn-secondary" onclick="startAccountMerge()">' + __t("profile.mergeChooseMethod") + '</button>';
|
|
186
|
+
html += '</div>';
|
|
187
|
+
|
|
169
188
|
list.innerHTML = html;
|
|
170
189
|
}
|
|
171
190
|
|
|
@@ -200,10 +219,15 @@ function renderBoundCard(a) {
|
|
|
200
219
|
}
|
|
201
220
|
html += '</div>';
|
|
202
221
|
|
|
203
|
-
// Action buttons at top-right
|
|
204
|
-
|
|
222
|
+
// Action buttons at top-right. Wallet / did-connect get a dedicated unbind
|
|
223
|
+
// button (Decision 2: wallet is a credential). Last-credential is enforced
|
|
224
|
+
// server-side; the button is shown even on the main wallet row.
|
|
225
|
+
var isWallet = a.provider === "wallet" || a.provider === "did-connect";
|
|
226
|
+
if (isWallet || !a.isMain) {
|
|
205
227
|
html += '<div class="ca-bound-actions">';
|
|
206
|
-
if (
|
|
228
|
+
if (isWallet) {
|
|
229
|
+
html += '<button class="btn-text" style="color:var(--red-text)" onclick="unbindWallet(\\'' + escapeHtml(a.provider) + '\\')">' + __t("profile.remove") + '</button>';
|
|
230
|
+
} else if (isPasskey) {
|
|
207
231
|
html += '<button class="btn-text" onclick="openRenamePasskeyDialog(\\'' + escapeHtml(a.did) + '\\', \\'' + escapeHtml(getPasskeyName(a)) + '\\')">' + __t("profile.renamePasskey") + '</button>';
|
|
208
232
|
html += '<button class="btn-text" style="color:var(--red-text)" onclick="removePasskey(\\'' + escapeHtml(a.did) + '\\')">' + __t("profile.remove") + '</button>';
|
|
209
233
|
} else {
|
|
@@ -328,6 +352,20 @@ async function unbindOAuth(provider) {
|
|
|
328
352
|
}
|
|
329
353
|
}
|
|
330
354
|
|
|
355
|
+
async function unbindWallet(provider) {
|
|
356
|
+
var ok = await confirmDialog({
|
|
357
|
+
title: __t("profile.removeConfirmTitle"),
|
|
358
|
+
message: __t("profile.removeConfirmMsg"),
|
|
359
|
+
confirmLabel: __t("profile.remove"),
|
|
360
|
+
});
|
|
361
|
+
if (!ok) return;
|
|
362
|
+
var data = await api("POST", "/../wallet/unbind", { provider: provider });
|
|
363
|
+
if (data.ok) {
|
|
364
|
+
showToast(__t("profile.accountRemoved"), "success");
|
|
365
|
+
loadConnectedAccounts();
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
331
369
|
async function addPasskey() {
|
|
332
370
|
try {
|
|
333
371
|
// 1. Get registration options. The server flattens the WebAuthn options to
|
|
@@ -457,6 +495,474 @@ function __openInWallet(url, appInfo, memberAppInfo) {
|
|
|
457
495
|
}
|
|
458
496
|
}
|
|
459
497
|
|
|
498
|
+
function listMergeMethods() {
|
|
499
|
+
var auth = (typeof window !== "undefined" && window.__mergeAuth) || { wallet: true, passkey: true, email: false };
|
|
500
|
+
var methods = [];
|
|
501
|
+
if (auth.wallet !== false) methods.push({ method: "wallet" });
|
|
502
|
+
if (auth.passkey !== false) methods.push({ method: "passkey" });
|
|
503
|
+
for (var i = 0; i < __oauthProviders.length; i++) {
|
|
504
|
+
methods.push({ method: "oauth", provider: __oauthProviders[i] });
|
|
505
|
+
}
|
|
506
|
+
if (auth.email) methods.push({ method: "email" });
|
|
507
|
+
return methods;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
function cleanupAccountMergeOAuth() {
|
|
511
|
+
if (__accountMergeOAuthCleanup) __accountMergeOAuthCleanup();
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
async function proveAccountMergeWithWallet(mergeChallenge) {
|
|
515
|
+
var tokenData;
|
|
516
|
+
try {
|
|
517
|
+
tokenData = await api("GET", "/../did/merge-proof/token");
|
|
518
|
+
} catch (e) {
|
|
519
|
+
showToast(__t("profile.mergeFailed"), "error");
|
|
520
|
+
return null;
|
|
521
|
+
}
|
|
522
|
+
if (!tokenData || !tokenData.token) {
|
|
523
|
+
showToast(__t("profile.mergeFailed"), "error");
|
|
524
|
+
return null;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
var token = tokenData.token;
|
|
528
|
+
var connectUrl = tokenData.url || "";
|
|
529
|
+
var appInfo = tokenData.appInfo || {};
|
|
530
|
+
var memberAppInfo = tokenData.memberAppInfo || {};
|
|
531
|
+
|
|
532
|
+
return new Promise(function(resolve) {
|
|
533
|
+
var d = document.getElementById("wallet-merge-dialog");
|
|
534
|
+
if (!d) {
|
|
535
|
+
d = document.createElement("dialog");
|
|
536
|
+
d.id = "wallet-merge-dialog";
|
|
537
|
+
document.body.appendChild(d);
|
|
538
|
+
}
|
|
539
|
+
d.innerHTML = '<div class="dialog-content" style="text-align:center;">'
|
|
540
|
+
+ '<h3 style="margin-bottom:4px;">' + __t("profile.mergeProveWallet") + '</h3>'
|
|
541
|
+
+ '<div id="wallet-merge-qr" class="wallet-qr-view">'
|
|
542
|
+
+ '<div class="wallet-qr-placeholder"><span class="wallet-qr-spinner"></span></div>'
|
|
543
|
+
+ '</div>'
|
|
544
|
+
+ '<button id="wallet-merge-open" class="btn btn-secondary wallet-deep-link-btn" disabled>'
|
|
545
|
+
+ getProviderIconSvg("did-connect") + ' ' + __t("profile.openInWallet")
|
|
546
|
+
+ '</button>'
|
|
547
|
+
+ '<p id="wallet-merge-status" class="wallet-bind-status">' + __t("profile.scanWithWallet") + '</p>'
|
|
548
|
+
+ '</div>'
|
|
549
|
+
+ '<div class="dialog-actions">'
|
|
550
|
+
+ '<button class="btn btn-secondary" id="wallet-merge-cancel">' + __t("common.cancel") + '</button>'
|
|
551
|
+
+ '</div>';
|
|
552
|
+
|
|
553
|
+
var statusEl = document.getElementById("wallet-merge-status");
|
|
554
|
+
var qrEl = document.getElementById("wallet-merge-qr");
|
|
555
|
+
var openBtn = document.getElementById("wallet-merge-open");
|
|
556
|
+
if (connectUrl && typeof __QRBundle !== "undefined" && __QRBundle.renderQR) {
|
|
557
|
+
__QRBundle.renderQR(qrEl, connectUrl, 212);
|
|
558
|
+
}
|
|
559
|
+
openBtn.disabled = false;
|
|
560
|
+
openBtn.onclick = function() { __openInWallet(connectUrl, appInfo, memberAppInfo); };
|
|
561
|
+
|
|
562
|
+
var pollTimer = null;
|
|
563
|
+
var pollCount = 0;
|
|
564
|
+
var settled = false;
|
|
565
|
+
var polling = false;
|
|
566
|
+
function finish(value) {
|
|
567
|
+
if (settled) return;
|
|
568
|
+
settled = true;
|
|
569
|
+
if (pollTimer) clearInterval(pollTimer);
|
|
570
|
+
pollTimer = null;
|
|
571
|
+
if (d.open) d.close();
|
|
572
|
+
resolve(value);
|
|
573
|
+
}
|
|
574
|
+
document.getElementById("wallet-merge-cancel").onclick = function() { finish(null); };
|
|
575
|
+
d.onclose = function() { finish(null); };
|
|
576
|
+
d.showModal();
|
|
577
|
+
|
|
578
|
+
pollTimer = setInterval(async function() {
|
|
579
|
+
if (polling || settled) return;
|
|
580
|
+
polling = true;
|
|
581
|
+
pollCount++;
|
|
582
|
+
if (pollCount > 120) {
|
|
583
|
+
clearInterval(pollTimer);
|
|
584
|
+
pollTimer = null;
|
|
585
|
+
statusEl.textContent = __t("profile.connectTimeout");
|
|
586
|
+
polling = false;
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
try {
|
|
590
|
+
var status = await api("GET", "/../did/merge-proof/status?_t_=" + encodeURIComponent(token));
|
|
591
|
+
if (status.status === "scanned") {
|
|
592
|
+
statusEl.textContent = __t("profile.confirmInWallet");
|
|
593
|
+
} else if (status.status === "succeed") {
|
|
594
|
+
clearInterval(pollTimer);
|
|
595
|
+
pollTimer = null;
|
|
596
|
+
statusEl.textContent = __t("profile.binding");
|
|
597
|
+
var proved = await api("POST", "/../did/connect/complete", {
|
|
598
|
+
token: token,
|
|
599
|
+
mergeChallenge: mergeChallenge,
|
|
600
|
+
});
|
|
601
|
+
if (!proved || !proved.mergeIntent) {
|
|
602
|
+
statusEl.textContent = (proved && proved.error) || __t("profile.mergeFailed");
|
|
603
|
+
polling = false;
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
finish(proved);
|
|
607
|
+
} else if (status.status === "error") {
|
|
608
|
+
clearInterval(pollTimer);
|
|
609
|
+
pollTimer = null;
|
|
610
|
+
statusEl.textContent = status.error || __t("profile.mergeFailed");
|
|
611
|
+
}
|
|
612
|
+
} catch (e) { /* ignore poll errors */ }
|
|
613
|
+
polling = false;
|
|
614
|
+
}, 1500);
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
async function proveAccountMergeWithPasskey(mergeChallenge) {
|
|
619
|
+
if (typeof PublicKeyCredential === "undefined" || !navigator.credentials || !navigator.credentials.get) {
|
|
620
|
+
showToast(__t("profile.mergePasskeyUnavailable"), "error");
|
|
621
|
+
return null;
|
|
622
|
+
}
|
|
623
|
+
var opts = await api("GET", "/../passkey/auth");
|
|
624
|
+
var publicKey = opts.authentication || opts;
|
|
625
|
+
if (!opts.challengeId || !publicKey || !publicKey.challenge) {
|
|
626
|
+
showToast((opts && opts.error) || __t("profile.mergeFailed"), "error");
|
|
627
|
+
return null;
|
|
628
|
+
}
|
|
629
|
+
publicKey.challenge = base64urlToBuffer(publicKey.challenge);
|
|
630
|
+
if (publicKey.allowCredentials) {
|
|
631
|
+
for (var i = 0; i < publicKey.allowCredentials.length; i++) {
|
|
632
|
+
publicKey.allowCredentials[i].id = base64urlToBuffer(publicKey.allowCredentials[i].id);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
var credential;
|
|
636
|
+
try {
|
|
637
|
+
credential = await navigator.credentials.get({ publicKey: publicKey });
|
|
638
|
+
} catch (e) {
|
|
639
|
+
if (!e || e.name !== "NotAllowedError") {
|
|
640
|
+
showToast((e && e.message) || __t("profile.mergeFailed"), "error");
|
|
641
|
+
}
|
|
642
|
+
return null;
|
|
643
|
+
}
|
|
644
|
+
if (!credential) return null;
|
|
645
|
+
var response = credential.response;
|
|
646
|
+
return api("POST", "/../passkey/auth", {
|
|
647
|
+
challengeId: opts.challengeId,
|
|
648
|
+
credential: {
|
|
649
|
+
id: credential.id,
|
|
650
|
+
rawId: bufferToBase64url(credential.rawId),
|
|
651
|
+
type: credential.type,
|
|
652
|
+
response: {
|
|
653
|
+
authenticatorData: bufferToBase64url(response.authenticatorData),
|
|
654
|
+
clientDataJSON: bufferToBase64url(response.clientDataJSON),
|
|
655
|
+
signature: bufferToBase64url(response.signature),
|
|
656
|
+
userHandle: response.userHandle ? bufferToBase64url(response.userHandle) : undefined,
|
|
657
|
+
},
|
|
658
|
+
},
|
|
659
|
+
mergeChallenge: mergeChallenge,
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
function proveAccountMergeWithOAuth(provider, mergeChallenge) {
|
|
664
|
+
return new Promise(function(resolve) {
|
|
665
|
+
if (__oauthProviders.indexOf(provider) === -1) {
|
|
666
|
+
resolve(null);
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
cleanupAccountMergeOAuth();
|
|
670
|
+
var returnUrl = encodeURIComponent(window.location.href);
|
|
671
|
+
var url = window.__BASE_PATH + "/../oauth/" + encodeURIComponent(provider) + "/login?returnUrl=" + returnUrl;
|
|
672
|
+
var redirectUri = location.origin + "/.well-known/service/oauth/callback/" + encodeURIComponent(provider);
|
|
673
|
+
var w = 500, h = 600;
|
|
674
|
+
var left = (screen.width - w) / 2, top = (screen.height - h) / 2;
|
|
675
|
+
var popup = window.open(url, "oauth_merge", "width=" + w + ",height=" + h + ",left=" + left + ",top=" + top);
|
|
676
|
+
if (!popup) {
|
|
677
|
+
showToast(__t("common.popupBlocked"), "error");
|
|
678
|
+
resolve(null);
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
var settled = false;
|
|
682
|
+
var closeTimer = null;
|
|
683
|
+
var closedAt = 0;
|
|
684
|
+
function cleanup() {
|
|
685
|
+
window.removeEventListener("message", onMessage);
|
|
686
|
+
if (closeTimer) clearInterval(closeTimer);
|
|
687
|
+
closeTimer = null;
|
|
688
|
+
if (__accountMergeOAuthCleanup === cancel) __accountMergeOAuthCleanup = null;
|
|
689
|
+
}
|
|
690
|
+
function finish(value) {
|
|
691
|
+
if (settled) return;
|
|
692
|
+
settled = true;
|
|
693
|
+
cleanup();
|
|
694
|
+
resolve(value);
|
|
695
|
+
}
|
|
696
|
+
async function onMessage(event) {
|
|
697
|
+
if (event.origin !== location.origin) return;
|
|
698
|
+
if (!event.data || event.data.type !== "authorization_response") return;
|
|
699
|
+
if (settled) return;
|
|
700
|
+
// Stop the closed-poll BEFORE tearing down the popup or awaiting network.
|
|
701
|
+
// The callback posts then window.close() at 300ms; closing here used to
|
|
702
|
+
// make the poll toast "Sign-in window closed" while /oauth/login ran.
|
|
703
|
+
cleanup();
|
|
704
|
+
try { popup.close(); } catch (e) {}
|
|
705
|
+
var resp = event.data.response;
|
|
706
|
+
if (event.data.error || !resp || !resp.code) {
|
|
707
|
+
finish(null);
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
try {
|
|
711
|
+
var proved = await api("POST", "/../oauth/login", {
|
|
712
|
+
provider: provider,
|
|
713
|
+
code: resp.code,
|
|
714
|
+
redirectUri: redirectUri,
|
|
715
|
+
mergeChallenge: mergeChallenge,
|
|
716
|
+
});
|
|
717
|
+
finish(proved);
|
|
718
|
+
} catch (e) {
|
|
719
|
+
showToast((e && e.message) || __t("profile.mergeFailed"), "error");
|
|
720
|
+
finish(null);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
window.addEventListener("message", onMessage);
|
|
724
|
+
closeTimer = setInterval(function() {
|
|
725
|
+
if (settled) return;
|
|
726
|
+
var closed = false;
|
|
727
|
+
try { closed = popup.closed; } catch (e) { closed = true; }
|
|
728
|
+
if (!closed) {
|
|
729
|
+
closedAt = 0;
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
if (!closedAt) closedAt = Date.now();
|
|
733
|
+
if (!oauthPopupClosedShouldCancel(closedAt, Date.now(), __oauthPopupCloseGraceMs)) return;
|
|
734
|
+
showToast(__t("profile.mergePopupClosed"), "error");
|
|
735
|
+
finish(null);
|
|
736
|
+
}, 200);
|
|
737
|
+
function cancel() {
|
|
738
|
+
try { popup.close(); } catch (e) {}
|
|
739
|
+
finish(null);
|
|
740
|
+
}
|
|
741
|
+
__accountMergeOAuthCleanup = cancel;
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
async function proveAccountMergeWithEmail(mergeChallenge) {
|
|
746
|
+
return new Promise(function(resolve) {
|
|
747
|
+
var d = document.getElementById("email-merge-dialog");
|
|
748
|
+
if (!d) {
|
|
749
|
+
d = document.createElement("dialog");
|
|
750
|
+
d.id = "email-merge-dialog";
|
|
751
|
+
document.body.appendChild(d);
|
|
752
|
+
}
|
|
753
|
+
d.innerHTML = '<div class="dialog-content">'
|
|
754
|
+
+ '<h3>' + __t("profile.mergeProveEmail") + '</h3>'
|
|
755
|
+
+ '<div class="merge-email-fields">'
|
|
756
|
+
+ '<input class="input" id="email-merge-address" type="email" autocomplete="email" placeholder="' + escapeHtml(__t("profile.mergeEmailPlaceholder")) + '" />'
|
|
757
|
+
+ '<input class="input" id="email-merge-code" inputmode="numeric" autocomplete="one-time-code" placeholder="' + escapeHtml(__t("profile.mergeEmailCodePlaceholder")) + '" disabled />'
|
|
758
|
+
+ '<p id="email-merge-status" class="dialog-desc"></p>'
|
|
759
|
+
+ '</div></div>'
|
|
760
|
+
+ '<div class="dialog-actions">'
|
|
761
|
+
+ '<button type="button" class="btn btn-secondary" id="email-merge-cancel">' + __t("common.cancel") + '</button>'
|
|
762
|
+
+ '<button type="button" class="btn btn-secondary" id="email-merge-send">' + __t("profile.mergeEmailSendCode") + '</button>'
|
|
763
|
+
+ '<button type="button" class="btn" id="email-merge-ok" disabled>' + __t("common.confirm") + '</button>'
|
|
764
|
+
+ '</div>';
|
|
765
|
+
|
|
766
|
+
var emailEl = document.getElementById("email-merge-address");
|
|
767
|
+
var codeEl = document.getElementById("email-merge-code");
|
|
768
|
+
var statusEl = document.getElementById("email-merge-status");
|
|
769
|
+
var sendBtn = document.getElementById("email-merge-send");
|
|
770
|
+
var okBtn = document.getElementById("email-merge-ok");
|
|
771
|
+
var verifyId = null;
|
|
772
|
+
var settled = false;
|
|
773
|
+
function finish(value) {
|
|
774
|
+
if (settled) return;
|
|
775
|
+
settled = true;
|
|
776
|
+
if (d.open) d.close();
|
|
777
|
+
resolve(value);
|
|
778
|
+
}
|
|
779
|
+
document.getElementById("email-merge-cancel").onclick = function() { finish(null); };
|
|
780
|
+
d.onclose = function() { finish(null); };
|
|
781
|
+
sendBtn.onclick = async function() {
|
|
782
|
+
var email = (emailEl.value || "").trim();
|
|
783
|
+
if (!email || email.indexOf("@") === -1) return;
|
|
784
|
+
sendBtn.disabled = true;
|
|
785
|
+
statusEl.textContent = __t("profile.emailSending");
|
|
786
|
+
var sent = await api("POST", "/../email/sendCode", { email: email });
|
|
787
|
+
if (!sent || sent.id == null) {
|
|
788
|
+
statusEl.textContent = (sent && sent.error) || __t("profile.emailSendFailed");
|
|
789
|
+
sendBtn.disabled = false;
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
verifyId = sent.id;
|
|
793
|
+
codeEl.disabled = false;
|
|
794
|
+
okBtn.disabled = false;
|
|
795
|
+
codeEl.focus();
|
|
796
|
+
statusEl.textContent = __t("profile.emailCodeSent");
|
|
797
|
+
sendBtn.disabled = false;
|
|
798
|
+
};
|
|
799
|
+
okBtn.onclick = async function() {
|
|
800
|
+
var code = (codeEl.value || "").trim();
|
|
801
|
+
if (!code || verifyId == null) return;
|
|
802
|
+
okBtn.disabled = true;
|
|
803
|
+
var proved = await api("POST", "/../email/login", {
|
|
804
|
+
code: code,
|
|
805
|
+
id: verifyId,
|
|
806
|
+
mergeChallenge: mergeChallenge,
|
|
807
|
+
});
|
|
808
|
+
if (!proved || !proved.mergeIntent) {
|
|
809
|
+
statusEl.textContent = (proved && proved.error) || __t("profile.mergeFailed");
|
|
810
|
+
okBtn.disabled = false;
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
finish(proved);
|
|
814
|
+
};
|
|
815
|
+
d.showModal();
|
|
816
|
+
emailEl.focus();
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
async function finalizeAccountMerge(proved) {
|
|
821
|
+
if (!proved || !proved.mergeIntent) {
|
|
822
|
+
showToast((proved && proved.error) || __t("profile.mergeFailed"), "error");
|
|
823
|
+
return false;
|
|
824
|
+
}
|
|
825
|
+
var plan = await api("POST", "/../account/merge/dry-run", { mergeIntent: proved.mergeIntent });
|
|
826
|
+
var ok = await confirmMergePlan(plan);
|
|
827
|
+
if (!ok) {
|
|
828
|
+
showToast(__t("profile.mergeCancelled"), "error");
|
|
829
|
+
return false;
|
|
830
|
+
}
|
|
831
|
+
var committed = await api("POST", "/../account/merge/commit", { mergeIntent: proved.mergeIntent });
|
|
832
|
+
if (committed && committed.ok) {
|
|
833
|
+
showToast(__t("profile.mergeSuccess"), "success");
|
|
834
|
+
loadConnectedAccounts();
|
|
835
|
+
return true;
|
|
836
|
+
}
|
|
837
|
+
showToast((committed && committed.error) || __t("profile.mergeFailed"), "error");
|
|
838
|
+
return false;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
function hideMergePrompt() {
|
|
842
|
+
var el = document.getElementById("merge-candidate-prompt");
|
|
843
|
+
if (!el) return;
|
|
844
|
+
el.style.display = "none";
|
|
845
|
+
el.hidden = true;
|
|
846
|
+
el.innerHTML = "";
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
function dismissMergePrompt() {
|
|
850
|
+
var did = __mergePromptDid || "";
|
|
851
|
+
if (did) {
|
|
852
|
+
try { localStorage["connect.mergePrompt.dismissed." + did] = "1"; } catch (e) {}
|
|
853
|
+
}
|
|
854
|
+
hideMergePrompt();
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
async function maybeShowMergePrompt(did) {
|
|
858
|
+
hideMergePrompt();
|
|
859
|
+
__mergePromptDid = did || "";
|
|
860
|
+
if (!did) return;
|
|
861
|
+
try {
|
|
862
|
+
if (localStorage["connect.mergePrompt.dismissed." + did] === "1") return;
|
|
863
|
+
} catch (e) {}
|
|
864
|
+
var data = await api("GET", "/../account/merge/candidate", undefined, { silent: true });
|
|
865
|
+
if (!data || data.mergeCandidate !== true) return;
|
|
866
|
+
try {
|
|
867
|
+
if (localStorage["connect.mergePrompt.dismissed." + did] === "1") return;
|
|
868
|
+
} catch (e) {}
|
|
869
|
+
var el = document.getElementById("merge-candidate-prompt");
|
|
870
|
+
if (!el) return;
|
|
871
|
+
el.innerHTML = '<div class="ca-merge-prompt-title">' + escapeHtml(__t("profile.mergePromptTitle")) + '</div>'
|
|
872
|
+
+ '<p class="ca-merge-prompt-body">' + escapeHtml(__t("profile.mergePromptBody")) + '</p>'
|
|
873
|
+
+ '<div class="ca-merge-prompt-actions">'
|
|
874
|
+
+ '<button type="button" class="btn" id="merge-candidate-prompt-action" onclick="startAccountMerge()">' + escapeHtml(__t("profile.mergePromptAction")) + '</button>'
|
|
875
|
+
+ '<button type="button" class="btn btn-secondary" id="merge-candidate-prompt-dismiss" onclick="dismissMergePrompt()">' + escapeHtml(__t("profile.mergePromptDismiss")) + '</button>'
|
|
876
|
+
+ '</div>';
|
|
877
|
+
el.hidden = false;
|
|
878
|
+
el.style.display = "";
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
async function startAccountMerge() {
|
|
882
|
+
cleanupAccountMergeOAuth();
|
|
883
|
+
var start;
|
|
884
|
+
try {
|
|
885
|
+
start = await api("POST", "/../account/merge/start", {});
|
|
886
|
+
} catch (e) {
|
|
887
|
+
showToast((e && e.message) || __t("profile.mergeFailed"), "error");
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
if (!start || !start.challenge) {
|
|
891
|
+
showToast(__t("profile.mergeFailed"), "error");
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
var d = document.getElementById("account-merge-method-dialog");
|
|
896
|
+
if (!d) {
|
|
897
|
+
d = document.createElement("dialog");
|
|
898
|
+
d.id = "account-merge-method-dialog";
|
|
899
|
+
document.body.appendChild(d);
|
|
900
|
+
}
|
|
901
|
+
d.innerHTML = renderMergeMethodPickerHtml(listMergeMethods(), __t, escapeHtml, getProviderIconSvg, getProviderLabel);
|
|
902
|
+
document.getElementById("account-merge-method-cancel").onclick = function() { d.close(); };
|
|
903
|
+
var buttons = d.querySelectorAll("[data-merge-method]");
|
|
904
|
+
for (var b = 0; b < buttons.length; b++) {
|
|
905
|
+
buttons[b].onclick = async function(event) {
|
|
906
|
+
var button = event.currentTarget;
|
|
907
|
+
var method = button.getAttribute("data-merge-method");
|
|
908
|
+
var selectedProvider = button.getAttribute("data-merge-provider");
|
|
909
|
+
d.close();
|
|
910
|
+
try {
|
|
911
|
+
var proved = null;
|
|
912
|
+
if (method === "wallet") proved = await proveAccountMergeWithWallet(start.challenge);
|
|
913
|
+
else if (method === "passkey") proved = await proveAccountMergeWithPasskey(start.challenge);
|
|
914
|
+
else if (method === "oauth") proved = await proveAccountMergeWithOAuth(selectedProvider, start.challenge);
|
|
915
|
+
else if (method === "email") proved = await proveAccountMergeWithEmail(start.challenge);
|
|
916
|
+
if (proved) await finalizeAccountMerge(proved);
|
|
917
|
+
} catch (e) {
|
|
918
|
+
if (!e || e.name !== "NotAllowedError") {
|
|
919
|
+
showToast((e && e.message) || __t("profile.mergeFailed"), "error");
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
};
|
|
923
|
+
}
|
|
924
|
+
d.showModal();
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
function confirmMergePlan(plan) {
|
|
928
|
+
return new Promise(function(resolve) {
|
|
929
|
+
var d = document.getElementById("merge-confirm-dialog");
|
|
930
|
+
if (!d) {
|
|
931
|
+
d = document.createElement("dialog");
|
|
932
|
+
d.id = "merge-confirm-dialog";
|
|
933
|
+
d.className = "merge-confirm-dialog";
|
|
934
|
+
document.body.appendChild(d);
|
|
935
|
+
}
|
|
936
|
+
d.innerHTML = '<div class="dialog-content">'
|
|
937
|
+
+ '<h3>' + escapeHtml(__t("profile.mergeConfirmTitle")) + '</h3>'
|
|
938
|
+
+ renderMergeConfirmBodyHtml(plan, __t, escapeHtml, getProviderLabel)
|
|
939
|
+
+ '</div>'
|
|
940
|
+
+ '<div class="dialog-actions">'
|
|
941
|
+
+ '<button class="btn btn-secondary" id="merge-confirm-cancel">' + escapeHtml(__t("common.cancel")) + '</button>'
|
|
942
|
+
+ '<button class="btn btn-danger" id="merge-confirm-ok">' + escapeHtml(__t("common.confirm")) + '</button>'
|
|
943
|
+
+ '</div>';
|
|
944
|
+
|
|
945
|
+
var okBtn = document.getElementById("merge-confirm-ok");
|
|
946
|
+
var cancelBtn = document.getElementById("merge-confirm-cancel");
|
|
947
|
+
if (plan && plan.tooLarge) okBtn.disabled = true;
|
|
948
|
+
|
|
949
|
+
var settled = false;
|
|
950
|
+
function finish(result) {
|
|
951
|
+
if (settled) return;
|
|
952
|
+
settled = true;
|
|
953
|
+
okBtn.onclick = null;
|
|
954
|
+
cancelBtn.onclick = null;
|
|
955
|
+
d.onclose = null;
|
|
956
|
+
d.close();
|
|
957
|
+
resolve(result);
|
|
958
|
+
}
|
|
959
|
+
okBtn.onclick = function() { if (okBtn.disabled) return; finish(true); };
|
|
960
|
+
cancelBtn.onclick = function() { finish(false); };
|
|
961
|
+
d.onclose = function() { finish(false); };
|
|
962
|
+
d.showModal();
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
|
|
460
966
|
// ─── DID Wallet Connect (bind) ──────────────────────────────────────
|
|
461
967
|
async function connectWallet() {
|
|
462
968
|
// 1. Create bind session
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tab-profile-accounts.js","sourceRoot":"","sources":["../../../src/pages/admin/tab-profile-accounts.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,eAAe,EACf,UAAU,EACV,YAAY,EACZ,WAAW,GACZ,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"tab-profile-accounts.js","sourceRoot":"","sources":["../../../src/pages/admin/tab-profile-accounts.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,eAAe,EACf,UAAU,EACV,YAAY,EACZ,WAAW,GACZ,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,0BAA0B,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAC9F,OAAO,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,0BAA0B,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAIlG,uDAAuD;AACvD,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC;AAE/D,4DAA4D;AAC5D,SAAS,gBAAgB;IACvB,MAAM,GAAG,GAA2B;QAClC,OAAO,EAAE,YAAY;QACrB,MAAM,EAAE,eAAe;QACvB,aAAa,EAAE,eAAe;QAC9B,KAAK,EAAE,UAAU;KAClB,CAAC;IACF,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QACrD,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/B,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;QACjB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,CAAM;IAC9C,OAAO,UAAU,CAAC;;;0CAGsB,CAAC,CAAC,2BAA2B,CAAC;;;;;CAKvE,CAAC;AACF,CAAC;AAED,mFAAmF;AACnF,+EAA+E;AAC/E,MAAM,CAAC,MAAM,yBAAyB,GAAG,eAAe,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC;;;;;wBAKjD,gBAAgB,EAAE;0BAChB,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC;EAC7D,uBAAuB,CAAC,QAAQ,EAAE;EAClC,0BAA0B,CAAC,QAAQ,EAAE;EACrC,2BAA2B,CAAC,QAAQ,EAAE;EACtC,4BAA4B,CAAC,QAAQ,EAAE;iCACR,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyhC1D,CAAC,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invite-page.d.ts","sourceRoot":"","sources":["../../src/pages/invite-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA2DH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,MAAM,SAAO,EACb,OAAO,CAAC,EAAE;IAAE,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"invite-page.d.ts","sourceRoot":"","sources":["../../src/pages/invite-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA2DH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,MAAM,SAAO,EACb,OAAO,CAAC,EAAE;IAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GACzD,MAAM,CA4PR"}
|
|
@@ -69,6 +69,12 @@ export function buildInvitePageHTML(apiBase, locale = "en", options) {
|
|
|
69
69
|
const masterOAuthOriginJson = JSON.stringify(options?.masterOAuthOrigin ?? null);
|
|
70
70
|
const lang = locale === "zh" ? "zh" : "en";
|
|
71
71
|
const t = INVITE_I18N[lang];
|
|
72
|
+
const appName = (options?.appName ?? "App")
|
|
73
|
+
.replaceAll("&", "&")
|
|
74
|
+
.replaceAll("<", "<")
|
|
75
|
+
.replaceAll(">", ">")
|
|
76
|
+
.replaceAll('"', """)
|
|
77
|
+
.replaceAll("'", "'");
|
|
72
78
|
const clientI18n = JSON.stringify({
|
|
73
79
|
noIdTitle: t.noIdTitle,
|
|
74
80
|
noIdMsg: t.noIdMsg,
|
|
@@ -87,7 +93,7 @@ export function buildInvitePageHTML(apiBase, locale = "en", options) {
|
|
|
87
93
|
<head>
|
|
88
94
|
<meta charset="utf-8" />
|
|
89
95
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
90
|
-
<title>${t.title}</title>
|
|
96
|
+
<title>${t.title} — ${appName}</title>
|
|
91
97
|
<link rel="stylesheet" href="${assetUrl("login.css")}" />
|
|
92
98
|
<style>
|
|
93
99
|
.invite-role {
|
|
@@ -126,6 +132,7 @@ export function buildInvitePageHTML(apiBase, locale = "en", options) {
|
|
|
126
132
|
|
|
127
133
|
<div id="valid-state" class="hidden">
|
|
128
134
|
<h1>${t.title}</h1>
|
|
135
|
+
<p class="subtitle">${appName}</p>
|
|
129
136
|
<div class="invite-info">
|
|
130
137
|
<p class="subtitle">${t.invitedPrefix}<span class="invite-role" id="invite-role"></span>${t.invitedSuffix}</p>
|
|
131
138
|
<p class="invite-remark hidden" id="invite-remark"></p>
|
|
@@ -217,8 +224,11 @@ async function init() {
|
|
|
217
224
|
return;
|
|
218
225
|
}
|
|
219
226
|
|
|
220
|
-
// Persist invitationId in cookie so login methods can pick it up
|
|
221
|
-
|
|
227
|
+
// Persist invitationId in cookie so login methods can pick it up.
|
|
228
|
+
// Secure is gated on https — the browser drops a Secure cookie over plain http
|
|
229
|
+
// (e.g. a LAN dev server), which would silently lose the invitation.
|
|
230
|
+
var securePart = location.protocol === "https:" ? ";Secure" : "";
|
|
231
|
+
document.cookie = "pending_invitation=" + encodeURIComponent(invitationId) + ";path=/;max-age=3600;SameSite=Lax" + securePart;
|
|
222
232
|
|
|
223
233
|
// 1. Check invitation validity
|
|
224
234
|
var invInfo;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invite-page.js","sourceRoot":"","sources":["../../src/pages/invite-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD;;;;GAIG;AACH,MAAM,WAAW,GAAG;IAClB,EAAE,EAAE;QACF,KAAK,EAAE,gBAAgB;QACvB,SAAS,EAAE,yBAAyB;QACpC,UAAU,EAAE,aAAa;QACzB,aAAa,EAAE,mCAAmC;QAClD,aAAa,EAAE,EAAE;QACjB,WAAW,EAAE,gBAAgB;QAC7B,UAAU,EAAE,oBAAoB;QAChC,MAAM,EAAE,gBAAgB;QACxB,OAAO,EAAE,UAAU;QACnB,cAAc,EAAE,4CAA4C;QAC5D,gDAAgD;QAChD,SAAS,EAAE,cAAc;QACzB,OAAO,EAAE,4BAA4B;QACrC,gBAAgB,EAAE,wBAAwB;QAC1C,QAAQ,EAAE,kCAAkC;QAC5C,OAAO,EAAE,8BAA8B;QACvC,MAAM,EAAE,yCAAyC;QACjD,eAAe,EAAE,+BAA+B;QAChD,gBAAgB,EAAE,OAAO;QACzB,cAAc,EAAE,gDAAgD;QAChE,OAAO,EAAE,YAAY;QACrB,YAAY,EAAE,6BAA6B;KAC5C;IACD,EAAE,EAAE;QACF,KAAK,EAAE,SAAS;QAChB,SAAS,EAAE,SAAS;QACpB,UAAU,EAAE,KAAK;QACjB,aAAa,EAAE,QAAQ;QACvB,aAAa,EAAE,QAAQ;QACvB,WAAW,EAAE,OAAO;QACpB,UAAU,EAAE,OAAO;QACnB,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,KAAK;QACd,cAAc,EAAE,cAAc;QAC9B,SAAS,EAAE,MAAM;QACjB,OAAO,EAAE,WAAW;QACpB,gBAAgB,EAAE,OAAO;QACzB,QAAQ,EAAE,UAAU;QACpB,OAAO,EAAE,SAAS;QAClB,MAAM,EAAE,WAAW;QACnB,eAAe,EAAE,QAAQ;QACzB,gBAAgB,EAAE,KAAK;QACvB,cAAc,EAAE,aAAa;QAC7B,OAAO,EAAE,OAAO;QAChB,YAAY,EAAE,QAAQ;KACvB;CACO,CAAC;AAEX,MAAM,UAAU,mBAAmB,CACjC,OAAe,EACf,MAAM,GAAG,IAAI,EACb,
|
|
1
|
+
{"version":3,"file":"invite-page.js","sourceRoot":"","sources":["../../src/pages/invite-page.ts"],"names":[],"mappings":"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"}
|