@arcblock/did-connect-service 4.1.60 → 4.1.62
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 +2 -2
- package/dist/assets/{admin-core.bcfa7ce2.js → admin-core.bbd8d53c.js} +963 -194
- package/dist/assets/{admin.bd6c819b.css → admin.7b66e78d.css} +160 -7
- package/dist/blocklet-service-rpc.js +4 -4
- package/dist/blocklet-service-rpc.js.map +1 -1
- package/dist/handler-errors.d.ts +14 -8
- package/dist/handler-errors.d.ts.map +1 -1
- package/dist/handler-errors.js +15 -8
- package/dist/handler-errors.js.map +1 -1
- package/dist/handlers/account-merge-handler.d.ts +32 -5
- package/dist/handlers/account-merge-handler.d.ts.map +1 -1
- package/dist/handlers/account-merge-handler.js +155 -19
- package/dist/handlers/account-merge-handler.js.map +1 -1
- package/dist/handlers/auth-handler.d.ts.map +1 -1
- package/dist/handlers/auth-handler.js +11 -6
- package/dist/handlers/auth-handler.js.map +1 -1
- package/dist/handlers/did-connect-handler.d.ts +2 -2
- package/dist/handlers/did-connect-handler.d.ts.map +1 -1
- package/dist/handlers/did-connect-handler.js +9 -14
- package/dist/handlers/did-connect-handler.js.map +1 -1
- package/dist/handlers/email-login-handler.d.ts.map +1 -1
- package/dist/handlers/email-login-handler.js +15 -10
- package/dist/handlers/email-login-handler.js.map +1 -1
- package/dist/handlers/oauth-handler.d.ts +2 -0
- package/dist/handlers/oauth-handler.d.ts.map +1 -1
- package/dist/handlers/oauth-handler.js +71 -22
- package/dist/handlers/oauth-handler.js.map +1 -1
- package/dist/handlers/passkey-handler.d.ts +8 -2
- package/dist/handlers/passkey-handler.d.ts.map +1 -1
- package/dist/handlers/passkey-handler.js +27 -18
- package/dist/handlers/passkey-handler.js.map +1 -1
- package/dist/handlers/team-handler.js +2 -2
- package/dist/handlers/team-handler.js.map +1 -1
- 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/session-epoch.d.ts +11 -0
- package/dist/identity/session-epoch.d.ts.map +1 -1
- package/dist/identity/session-epoch.js +12 -0
- package/dist/identity/session-epoch.js.map +1 -1
- package/dist/og/font-fallback.d.ts +38 -8
- package/dist/og/font-fallback.d.ts.map +1 -1
- package/dist/og/font-fallback.js +66 -7
- package/dist/og/font-fallback.js.map +1 -1
- package/dist/og/font-subset.d.ts +10 -6
- package/dist/og/font-subset.d.ts.map +1 -1
- package/dist/og/font-subset.js +5 -3
- package/dist/og/font-subset.js.map +1 -1
- package/dist/og/node-font-files.d.ts +7 -0
- package/dist/og/node-font-files.d.ts.map +1 -1
- package/dist/og/node-font-files.js +19 -1
- package/dist/og/node-font-files.js.map +1 -1
- package/dist/og/tree-node.d.ts +3 -2
- package/dist/og/tree-node.d.ts.map +1 -1
- package/dist/og/tree-node.js +9 -5
- package/dist/og/tree-node.js.map +1 -1
- package/dist/og/worker.d.ts +3 -1
- package/dist/og/worker.d.ts.map +1 -1
- package/dist/og/worker.js +19 -10
- package/dist/og/worker.js.map +1 -1
- package/dist/pages/admin/i18n.d.ts.map +1 -1
- package/dist/pages/admin/i18n.js +271 -47
- package/dist/pages/admin/i18n.js.map +1 -1
- package/dist/pages/admin/merge-confirm-view.d.ts +75 -18
- package/dist/pages/admin/merge-confirm-view.d.ts.map +1 -1
- package/dist/pages/admin/merge-confirm-view.js +304 -72
- package/dist/pages/admin/merge-confirm-view.js.map +1 -1
- package/dist/pages/admin/merge-method-picker.d.ts +34 -3
- package/dist/pages/admin/merge-method-picker.d.ts.map +1 -1
- package/dist/pages/admin/merge-method-picker.js +188 -14
- package/dist/pages/admin/merge-method-picker.js.map +1 -1
- package/dist/pages/admin/styles.d.ts.map +1 -1
- package/dist/pages/admin/styles.js +160 -7
- package/dist/pages/admin/styles.js.map +1 -1
- package/dist/pages/admin/tab-profile-accounts.d.ts.map +1 -1
- package/dist/pages/admin/tab-profile-accounts.js +490 -114
- package/dist/pages/admin/tab-profile-accounts.js.map +1 -1
- package/dist/pages/oauth-callback-page.d.ts +5 -0
- package/dist/pages/oauth-callback-page.d.ts.map +1 -1
- package/dist/pages/oauth-callback-page.js +19 -0
- package/dist/pages/oauth-callback-page.js.map +1 -1
- package/dist/store/account-merge.d.ts +139 -3
- package/dist/store/account-merge.d.ts.map +1 -1
- package/dist/store/account-merge.js +381 -11
- package/dist/store/account-merge.js.map +1 -1
- package/dist/store/d1-store.d.ts +20 -3
- package/dist/store/d1-store.d.ts.map +1 -1
- package/dist/store/d1-store.js +37 -26
- package/dist/store/d1-store.js.map +1 -1
- package/package.json +3 -3
|
@@ -3,8 +3,8 @@
|
|
|
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";
|
|
6
|
+
import { renderMergeConfirmBodyHtml, renderMergeDoneBodyHtml, toMergeConfirmViewModel, } from "./merge-confirm-view.js";
|
|
7
|
+
import { formatMergeCandidateWhen, partitionMergeMethods, renderMergeMethodPickerHtml, renderMergePromptHtml, } from "./merge-method-picker.js";
|
|
8
8
|
/** Providers hidden from the Connected Accounts UI. */
|
|
9
9
|
const HIDDEN_PROVIDERS = new Set(["facebook", "auth0-legacy"]);
|
|
10
10
|
/** Build a JS-safe icon map to embed in inline <script>. */
|
|
@@ -40,11 +40,16 @@ var __connectedAccounts = [];
|
|
|
40
40
|
var __oauthProviders = [];
|
|
41
41
|
var __accountMergeOAuthCleanup = null;
|
|
42
42
|
var __mergePromptDid = "";
|
|
43
|
+
var __mergePromptCandidates = [];
|
|
43
44
|
var __providerIcons = ${buildIconMapJSON()};
|
|
44
45
|
var __hiddenProviders = ${JSON.stringify([...HIDDEN_PROVIDERS])};
|
|
45
46
|
${toMergeConfirmViewModel.toString()}
|
|
46
47
|
${renderMergeConfirmBodyHtml.toString()}
|
|
48
|
+
${renderMergeDoneBodyHtml.toString()}
|
|
47
49
|
${renderMergeMethodPickerHtml.toString()}
|
|
50
|
+
${formatMergeCandidateWhen.toString()}
|
|
51
|
+
${partitionMergeMethods.toString()}
|
|
52
|
+
${renderMergePromptHtml.toString()}
|
|
48
53
|
|
|
49
54
|
async function loadConnectedAccounts() {
|
|
50
55
|
var card = document.getElementById("connected-accounts-card");
|
|
@@ -179,7 +184,7 @@ function renderConnectedAccounts() {
|
|
|
179
184
|
html += '<div class="ca-section">';
|
|
180
185
|
html += '<div class="ca-section-label">' + __t("profile.mergeAccount") + '</div>';
|
|
181
186
|
html += '<p class="ca-merge-hint" style="margin:0 0 8px;color:var(--text-secondary);font-size:13px;">' + __t("profile.mergeAccountHint") + '</p>';
|
|
182
|
-
html += '<button class="btn btn-secondary" onclick="startAccountMerge()">' + __t("profile.
|
|
187
|
+
html += '<button class="btn btn-secondary" onclick="startAccountMerge()">' + __t("profile.mergeStart") + '</button>';
|
|
183
188
|
html += '</div>';
|
|
184
189
|
|
|
185
190
|
list.innerHTML = html;
|
|
@@ -510,17 +515,29 @@ function cleanupAccountMergeOAuth() {
|
|
|
510
515
|
if (__accountMergeOAuthCleanup) __accountMergeOAuthCleanup();
|
|
511
516
|
}
|
|
512
517
|
|
|
518
|
+
function mergeChallengeLooksExpired(error) {
|
|
519
|
+
return error === "Invalid or expired merge challenge"
|
|
520
|
+
|| error === "合并验证无效或已过期"
|
|
521
|
+
|| error === "合併驗證無效或已過期"
|
|
522
|
+
|| error === "統合チャレンジが無効か、期限切れです";
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function emailCodeAlreadySent(error) {
|
|
526
|
+
return error === "Code already sent, please wait"
|
|
527
|
+
|| error === "验证码已发送,请稍候"
|
|
528
|
+
|| error === "驗證碼已寄出,請稍候"
|
|
529
|
+
|| error === "確認コードは送信済みです。しばらくお待ちください";
|
|
530
|
+
}
|
|
531
|
+
|
|
513
532
|
async function proveAccountMergeWithWallet(mergeChallenge) {
|
|
514
533
|
var tokenData;
|
|
515
534
|
try {
|
|
516
|
-
tokenData = await api("GET", "/../did/merge-proof/token");
|
|
535
|
+
tokenData = await api("GET", "/../did/merge-proof/token", undefined, { silent: true });
|
|
517
536
|
} catch (e) {
|
|
518
|
-
|
|
519
|
-
return null;
|
|
537
|
+
return { ok: false, error: __t("profile.mergeFailed") };
|
|
520
538
|
}
|
|
521
539
|
if (!tokenData || !tokenData.token) {
|
|
522
|
-
|
|
523
|
-
return null;
|
|
540
|
+
return { ok: false, error: (tokenData && tokenData.error) || __t("profile.mergeFailed") };
|
|
524
541
|
}
|
|
525
542
|
|
|
526
543
|
var token = tokenData.token;
|
|
@@ -596,17 +613,16 @@ async function proveAccountMergeWithWallet(mergeChallenge) {
|
|
|
596
613
|
var proved = await api("POST", "/../did/connect/complete", {
|
|
597
614
|
token: token,
|
|
598
615
|
mergeChallenge: mergeChallenge,
|
|
599
|
-
});
|
|
616
|
+
}, { silent: true });
|
|
600
617
|
if (!proved || !proved.mergeIntent) {
|
|
601
|
-
|
|
602
|
-
polling = false;
|
|
618
|
+
finish(proved || { ok: false, error: __t("profile.mergeFailed") });
|
|
603
619
|
return;
|
|
604
620
|
}
|
|
605
621
|
finish(proved);
|
|
606
622
|
} else if (status.status === "error") {
|
|
607
623
|
clearInterval(pollTimer);
|
|
608
624
|
pollTimer = null;
|
|
609
|
-
|
|
625
|
+
finish({ ok: false, error: status.error || __t("profile.mergeFailed") });
|
|
610
626
|
}
|
|
611
627
|
} catch (e) { /* ignore poll errors */ }
|
|
612
628
|
polling = false;
|
|
@@ -616,14 +632,12 @@ async function proveAccountMergeWithWallet(mergeChallenge) {
|
|
|
616
632
|
|
|
617
633
|
async function proveAccountMergeWithPasskey(mergeChallenge) {
|
|
618
634
|
if (typeof PublicKeyCredential === "undefined" || !navigator.credentials || !navigator.credentials.get) {
|
|
619
|
-
|
|
620
|
-
return null;
|
|
635
|
+
return { ok: false, error: __t("profile.mergePasskeyUnavailable") };
|
|
621
636
|
}
|
|
622
|
-
var opts = await api("GET", "/../passkey/auth");
|
|
637
|
+
var opts = await api("GET", "/../passkey/auth", undefined, { silent: true });
|
|
623
638
|
var publicKey = opts.authentication || opts;
|
|
624
|
-
if (!opts.challengeId || !publicKey || !publicKey.challenge) {
|
|
625
|
-
|
|
626
|
-
return null;
|
|
639
|
+
if (!opts || opts.ok === false || !opts.challengeId || !publicKey || !publicKey.challenge) {
|
|
640
|
+
return { ok: false, error: (opts && opts.error) || __t("profile.mergeFailed") };
|
|
627
641
|
}
|
|
628
642
|
publicKey.challenge = base64urlToBuffer(publicKey.challenge);
|
|
629
643
|
if (publicKey.allowCredentials) {
|
|
@@ -636,7 +650,7 @@ async function proveAccountMergeWithPasskey(mergeChallenge) {
|
|
|
636
650
|
credential = await navigator.credentials.get({ publicKey: publicKey });
|
|
637
651
|
} catch (e) {
|
|
638
652
|
if (!e || e.name !== "NotAllowedError") {
|
|
639
|
-
|
|
653
|
+
return { ok: false, error: (e && e.message) || __t("profile.mergeFailed") };
|
|
640
654
|
}
|
|
641
655
|
return null;
|
|
642
656
|
}
|
|
@@ -656,7 +670,7 @@ async function proveAccountMergeWithPasskey(mergeChallenge) {
|
|
|
656
670
|
},
|
|
657
671
|
},
|
|
658
672
|
mergeChallenge: mergeChallenge,
|
|
659
|
-
});
|
|
673
|
+
}, { silent: true });
|
|
660
674
|
}
|
|
661
675
|
|
|
662
676
|
function proveAccountMergeWithOAuth(provider, mergeChallenge) {
|
|
@@ -666,15 +680,23 @@ function proveAccountMergeWithOAuth(provider, mergeChallenge) {
|
|
|
666
680
|
return;
|
|
667
681
|
}
|
|
668
682
|
cleanupAccountMergeOAuth();
|
|
683
|
+
var mergeResultPrefix = "connect.mergeOAuthResult.";
|
|
684
|
+
try {
|
|
685
|
+
var staleKeys = [];
|
|
686
|
+
for (var s = 0; s < localStorage.length; s++) {
|
|
687
|
+
var staleKey = localStorage.key(s);
|
|
688
|
+
if (staleKey && staleKey.indexOf(mergeResultPrefix) === 0) staleKeys.push(staleKey);
|
|
689
|
+
}
|
|
690
|
+
for (var t = 0; t < staleKeys.length; t++) localStorage.removeItem(staleKeys[t]);
|
|
691
|
+
} catch (e0) {}
|
|
669
692
|
var returnUrl = encodeURIComponent(window.location.href);
|
|
670
|
-
var url = window.__BASE_PATH + "/../oauth/" + encodeURIComponent(provider) + "/login?returnUrl=" + returnUrl;
|
|
693
|
+
var url = window.__BASE_PATH + "/../oauth/" + encodeURIComponent(provider) + "/login?returnUrl=" + returnUrl + "&mergeChallenge=" + encodeURIComponent(mergeChallenge);
|
|
671
694
|
var redirectUri = location.origin + "/.well-known/service/oauth/callback/" + encodeURIComponent(provider);
|
|
672
695
|
var w = 500, h = 600;
|
|
673
696
|
var left = (screen.width - w) / 2, top = (screen.height - h) / 2;
|
|
674
697
|
var popup = window.open(url, "oauth_merge", "width=" + w + ",height=" + h + ",left=" + left + ",top=" + top);
|
|
675
698
|
if (!popup) {
|
|
676
|
-
|
|
677
|
-
resolve(null);
|
|
699
|
+
resolve({ ok: false, error: __t("common.popupBlocked") });
|
|
678
700
|
return;
|
|
679
701
|
}
|
|
680
702
|
var settled = false;
|
|
@@ -685,6 +707,7 @@ function proveAccountMergeWithOAuth(provider, mergeChallenge) {
|
|
|
685
707
|
}, 5 * 60 * 1000);
|
|
686
708
|
function cleanup() {
|
|
687
709
|
window.removeEventListener("message", onMessage);
|
|
710
|
+
window.removeEventListener("storage", onStorage);
|
|
688
711
|
clearTimeout(abandonTimer);
|
|
689
712
|
if (__accountMergeOAuthCleanup === cancel) __accountMergeOAuthCleanup = null;
|
|
690
713
|
}
|
|
@@ -694,6 +717,37 @@ function proveAccountMergeWithOAuth(provider, mergeChallenge) {
|
|
|
694
717
|
cleanup();
|
|
695
718
|
resolve(value);
|
|
696
719
|
}
|
|
720
|
+
function parseMergeOAuthResult(raw) {
|
|
721
|
+
if (!raw) return null;
|
|
722
|
+
try {
|
|
723
|
+
var parsed = JSON.parse(raw);
|
|
724
|
+
if (!parsed || typeof parsed !== "object") return { ok: false, error: __t("profile.mergeFailed") };
|
|
725
|
+
return parsed;
|
|
726
|
+
} catch (e1) {
|
|
727
|
+
return { ok: false, error: __t("profile.mergeFailed") };
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
function readMergeOAuthResultOnce() {
|
|
731
|
+
try {
|
|
732
|
+
for (var i = 0; i < localStorage.length; i++) {
|
|
733
|
+
var key = localStorage.key(i);
|
|
734
|
+
if (!key || key.indexOf(mergeResultPrefix) !== 0) continue;
|
|
735
|
+
var raw = localStorage.getItem(key);
|
|
736
|
+
try { localStorage.removeItem(key); } catch (e2) {}
|
|
737
|
+
return parseMergeOAuthResult(raw);
|
|
738
|
+
}
|
|
739
|
+
} catch (e3) {}
|
|
740
|
+
return null;
|
|
741
|
+
}
|
|
742
|
+
function onStorage(event) {
|
|
743
|
+
if (settled || !event || !event.key || event.key.indexOf(mergeResultPrefix) !== 0) return;
|
|
744
|
+
var raw = event.newValue;
|
|
745
|
+
try { localStorage.removeItem(event.key); } catch (e4) {}
|
|
746
|
+
var payload = parseMergeOAuthResult(raw);
|
|
747
|
+
if (!payload) return;
|
|
748
|
+
try { popup.close(); } catch (e5) {}
|
|
749
|
+
finish(payload);
|
|
750
|
+
}
|
|
697
751
|
async function onMessage(event) {
|
|
698
752
|
if (event.origin !== location.origin) return;
|
|
699
753
|
if (!event.data || event.data.type !== "authorization_response") return;
|
|
@@ -711,23 +765,28 @@ function proveAccountMergeWithOAuth(provider, mergeChallenge) {
|
|
|
711
765
|
code: resp.code,
|
|
712
766
|
redirectUri: redirectUri,
|
|
713
767
|
mergeChallenge: mergeChallenge,
|
|
714
|
-
});
|
|
768
|
+
}, { silent: true });
|
|
715
769
|
finish(proved);
|
|
716
770
|
} catch (e) {
|
|
717
|
-
|
|
718
|
-
finish(null);
|
|
771
|
+
finish({ ok: false, error: (e && e.message) || __t("profile.mergeFailed") });
|
|
719
772
|
}
|
|
720
773
|
}
|
|
721
774
|
window.addEventListener("message", onMessage);
|
|
775
|
+
window.addEventListener("storage", onStorage);
|
|
722
776
|
function cancel() {
|
|
723
777
|
try { popup.close(); } catch (e) {}
|
|
724
778
|
finish(null);
|
|
725
779
|
}
|
|
726
780
|
__accountMergeOAuthCleanup = cancel;
|
|
781
|
+
var existing = readMergeOAuthResultOnce();
|
|
782
|
+
if (existing) {
|
|
783
|
+
try { popup.close(); } catch (e6) {}
|
|
784
|
+
finish(existing);
|
|
785
|
+
}
|
|
727
786
|
});
|
|
728
787
|
}
|
|
729
788
|
|
|
730
|
-
async function proveAccountMergeWithEmail(mergeChallenge) {
|
|
789
|
+
async function proveAccountMergeWithEmail(mergeChallenge, prefillEmail) {
|
|
731
790
|
return new Promise(function(resolve) {
|
|
732
791
|
var d = document.getElementById("email-merge-dialog");
|
|
733
792
|
if (!d) {
|
|
@@ -744,6 +803,7 @@ async function proveAccountMergeWithEmail(mergeChallenge) {
|
|
|
744
803
|
+ '</div></div>'
|
|
745
804
|
+ '<div class="dialog-actions">'
|
|
746
805
|
+ '<button type="button" class="btn btn-secondary" id="email-merge-cancel">' + __t("common.cancel") + '</button>'
|
|
806
|
+
+ '<button type="button" class="btn btn-secondary" id="email-merge-switch">' + __t("profile.mergeEmailSwitchMethod") + '</button>'
|
|
747
807
|
+ '<button type="button" class="btn btn-secondary" id="email-merge-send">' + __t("profile.mergeEmailSendCode") + '</button>'
|
|
748
808
|
+ '<button type="button" class="btn" id="email-merge-ok" disabled>' + __t("common.confirm") + '</button>'
|
|
749
809
|
+ '</div>';
|
|
@@ -755,31 +815,86 @@ async function proveAccountMergeWithEmail(mergeChallenge) {
|
|
|
755
815
|
var okBtn = document.getElementById("email-merge-ok");
|
|
756
816
|
var verifyId = null;
|
|
757
817
|
var settled = false;
|
|
818
|
+
var activeChallenge = mergeChallenge;
|
|
819
|
+
var sentAt = 0;
|
|
820
|
+
var cooldownTimer = null;
|
|
821
|
+
var lastError = "";
|
|
758
822
|
function finish(value) {
|
|
759
823
|
if (settled) return;
|
|
760
824
|
settled = true;
|
|
825
|
+
if (cooldownTimer) clearInterval(cooldownTimer);
|
|
826
|
+
cooldownTimer = null;
|
|
761
827
|
if (d.open) d.close();
|
|
762
828
|
resolve(value);
|
|
763
829
|
}
|
|
830
|
+
function secondsLeft() {
|
|
831
|
+
if (!sentAt) return 0;
|
|
832
|
+
var left = 60000 - (Date.now() - sentAt);
|
|
833
|
+
if (left <= 0) return 0;
|
|
834
|
+
return Math.ceil(left / 1000);
|
|
835
|
+
}
|
|
836
|
+
function paintSendButton() {
|
|
837
|
+
var left = secondsLeft();
|
|
838
|
+
if (left > 0) {
|
|
839
|
+
sendBtn.disabled = true;
|
|
840
|
+
sendBtn.textContent = __t("profile.mergeEmailResendWait", { seconds: String(left) });
|
|
841
|
+
return;
|
|
842
|
+
}
|
|
843
|
+
sendBtn.disabled = false;
|
|
844
|
+
sendBtn.textContent = sentAt ? __t("profile.mergeEmailResend") : __t("profile.mergeEmailSendCode");
|
|
845
|
+
}
|
|
846
|
+
function startCooldown() {
|
|
847
|
+
if (cooldownTimer) clearInterval(cooldownTimer);
|
|
848
|
+
paintSendButton();
|
|
849
|
+
cooldownTimer = setInterval(function() {
|
|
850
|
+
paintSendButton();
|
|
851
|
+
if (secondsLeft() <= 0 && cooldownTimer) {
|
|
852
|
+
clearInterval(cooldownTimer);
|
|
853
|
+
cooldownTimer = null;
|
|
854
|
+
}
|
|
855
|
+
}, 1000);
|
|
856
|
+
}
|
|
857
|
+
function markCodeConsumed(message) {
|
|
858
|
+
codeEl.value = "";
|
|
859
|
+
codeEl.disabled = true;
|
|
860
|
+
okBtn.disabled = true;
|
|
861
|
+
lastError = message || "";
|
|
862
|
+
statusEl.textContent = lastError
|
|
863
|
+
? lastError + " " + __t("profile.mergeEmailRequestNewCode")
|
|
864
|
+
: __t("profile.mergeEmailRequestNewCode");
|
|
865
|
+
if (secondsLeft() > 0) startCooldown();
|
|
866
|
+
else paintSendButton();
|
|
867
|
+
}
|
|
764
868
|
document.getElementById("email-merge-cancel").onclick = function() { finish(null); };
|
|
869
|
+
document.getElementById("email-merge-switch").onclick = function() {
|
|
870
|
+
finish({ switchMethod: true, error: lastError, challenge: activeChallenge });
|
|
871
|
+
};
|
|
765
872
|
d.onclose = function() { finish(null); };
|
|
766
873
|
sendBtn.onclick = async function() {
|
|
767
874
|
var email = (emailEl.value || "").trim();
|
|
768
875
|
if (!email || email.indexOf("@") === -1) return;
|
|
769
876
|
sendBtn.disabled = true;
|
|
770
877
|
statusEl.textContent = __t("profile.emailSending");
|
|
771
|
-
var sent = await api("POST", "/../email/sendCode", { email: email });
|
|
878
|
+
var sent = await api("POST", "/../email/sendCode", { email: email }, { silent: true });
|
|
772
879
|
if (!sent || sent.id == null) {
|
|
773
|
-
|
|
774
|
-
|
|
880
|
+
var sendError = (sent && sent.error) || __t("profile.emailSendFailed");
|
|
881
|
+
statusEl.textContent = sendError;
|
|
882
|
+
if (emailCodeAlreadySent(sendError)) {
|
|
883
|
+
if (!sentAt) sentAt = Date.now();
|
|
884
|
+
startCooldown();
|
|
885
|
+
} else {
|
|
886
|
+
sendBtn.disabled = false;
|
|
887
|
+
}
|
|
775
888
|
return;
|
|
776
889
|
}
|
|
777
890
|
verifyId = sent.id;
|
|
891
|
+
sentAt = Date.now();
|
|
892
|
+
codeEl.value = "";
|
|
778
893
|
codeEl.disabled = false;
|
|
779
894
|
okBtn.disabled = false;
|
|
780
895
|
codeEl.focus();
|
|
781
896
|
statusEl.textContent = __t("profile.emailCodeSent");
|
|
782
|
-
|
|
897
|
+
startCooldown();
|
|
783
898
|
};
|
|
784
899
|
okBtn.onclick = async function() {
|
|
785
900
|
var code = (codeEl.value || "").trim();
|
|
@@ -788,39 +903,58 @@ async function proveAccountMergeWithEmail(mergeChallenge) {
|
|
|
788
903
|
var proved = await api("POST", "/../email/login", {
|
|
789
904
|
code: code,
|
|
790
905
|
id: verifyId,
|
|
791
|
-
mergeChallenge:
|
|
792
|
-
});
|
|
793
|
-
if (
|
|
794
|
-
|
|
795
|
-
okBtn.disabled = false;
|
|
906
|
+
mergeChallenge: activeChallenge,
|
|
907
|
+
}, { silent: true });
|
|
908
|
+
if (proved && proved.mergeIntent) {
|
|
909
|
+
finish(proved);
|
|
796
910
|
return;
|
|
797
911
|
}
|
|
798
|
-
|
|
912
|
+
var err = (proved && proved.error) || __t("profile.mergeFailed");
|
|
913
|
+
if (mergeChallengeLooksExpired(err)) {
|
|
914
|
+
var restarted = await api("POST", "/../account/merge/start", {}, { silent: true });
|
|
915
|
+
if (restarted && restarted.challenge) activeChallenge = restarted.challenge;
|
|
916
|
+
}
|
|
917
|
+
markCodeConsumed(err);
|
|
799
918
|
};
|
|
919
|
+
if (typeof prefillEmail === "string" && prefillEmail) emailEl.value = prefillEmail;
|
|
800
920
|
d.showModal();
|
|
801
921
|
emailEl.focus();
|
|
802
922
|
});
|
|
803
923
|
}
|
|
804
924
|
|
|
805
|
-
async function finalizeAccountMerge(proved) {
|
|
925
|
+
async function finalizeAccountMerge(proved, candidate) {
|
|
806
926
|
if (!proved || !proved.mergeIntent) {
|
|
807
927
|
showToast((proved && proved.error) || __t("profile.mergeFailed"), "error");
|
|
808
928
|
return false;
|
|
809
929
|
}
|
|
810
930
|
var plan = await api("POST", "/../account/merge/dry-run", { mergeIntent: proved.mergeIntent });
|
|
811
|
-
|
|
812
|
-
|
|
931
|
+
if (!plan || plan.ok === false || !plan.accounts) return false;
|
|
932
|
+
// Server omits keep → session. The first paint must match recommendedKeep.
|
|
933
|
+
if ((plan.recommendedKeep === "session" || plan.recommendedKeep === "proved") && plan.keep !== plan.recommendedKeep) {
|
|
934
|
+
var next = plan.recommendedKeep;
|
|
935
|
+
var aligned = await api("POST", "/../account/merge/dry-run", { mergeIntent: proved.mergeIntent, keep: next }, { silent: true });
|
|
936
|
+
if (aligned && aligned.ok !== false && aligned.accounts) plan = aligned;
|
|
937
|
+
else showToast((aligned && aligned.error) || __t("profile.mergeFailed"), "error");
|
|
938
|
+
}
|
|
939
|
+
var candidateEmail = candidate && typeof candidate.email === "string" ? candidate.email : "";
|
|
940
|
+
plan.__hasCandidate = !!(candidate && typeof candidate === "object");
|
|
941
|
+
var confirmed = await confirmMergePlan(plan, proved.mergeIntent, candidateEmail);
|
|
942
|
+
if (!confirmed) {
|
|
813
943
|
showToast(__t("profile.mergeCancelled"), "error");
|
|
814
944
|
return false;
|
|
815
945
|
}
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
946
|
+
return true;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
function mergeCandidateWhenLabel(iso) {
|
|
950
|
+
var lang = (document.documentElement && document.documentElement.lang) || "en";
|
|
951
|
+
return formatMergeCandidateWhen(iso, Date.now(), lang, __t);
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
function mergePromptIcon(provider) {
|
|
955
|
+
if (provider && __providerIcons[provider]) return getProviderIconSvg(provider);
|
|
956
|
+
var ch = provider ? provider.charAt(0).toUpperCase() : "?";
|
|
957
|
+
return '<span class="ca-merge-prompt-fallback">' + escapeHtml(ch) + '</span>';
|
|
824
958
|
}
|
|
825
959
|
|
|
826
960
|
function hideMergePrompt() {
|
|
@@ -831,10 +965,48 @@ function hideMergePrompt() {
|
|
|
831
965
|
el.innerHTML = "";
|
|
832
966
|
}
|
|
833
967
|
|
|
834
|
-
function
|
|
968
|
+
function paintMergePrompt(rows, hiddenProviders) {
|
|
969
|
+
var el = document.getElementById("merge-candidate-prompt");
|
|
970
|
+
if (!el) return;
|
|
971
|
+
if (!rows || !rows.length) {
|
|
972
|
+
hideMergePrompt();
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
el.innerHTML = renderMergePromptHtml(rows[0].email || "", rows, __t, escapeHtml, mergePromptIcon, getProviderLabel, mergeCandidateWhenLabel, hiddenProviders || __hiddenProviders);
|
|
976
|
+
el.hidden = false;
|
|
977
|
+
el.style.display = "";
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
function startMergeCandidate(btn) {
|
|
981
|
+
var ref = btn && btn.getAttribute ? btn.getAttribute("data-merge-ref") : "";
|
|
982
|
+
var list = __mergePromptCandidates || [];
|
|
983
|
+
for (var i = 0; i < list.length; i++) {
|
|
984
|
+
if (list[i].ref === ref) {
|
|
985
|
+
startAccountMerge(list[i]);
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
function hideMergeCandidate(btn) {
|
|
992
|
+
var ref = btn && btn.getAttribute ? btn.getAttribute("data-merge-ref") : "";
|
|
993
|
+
var did = __mergePromptDid || "";
|
|
994
|
+
if (did && ref) {
|
|
995
|
+
try { localStorage["connect.mergePrompt.notMine." + did + "." + ref] = "1"; } catch (e) {}
|
|
996
|
+
}
|
|
997
|
+
var next = [];
|
|
998
|
+
var list = __mergePromptCandidates || [];
|
|
999
|
+
for (var i = 0; i < list.length; i++) {
|
|
1000
|
+
if (list[i].ref !== ref) next.push(list[i]);
|
|
1001
|
+
}
|
|
1002
|
+
__mergePromptCandidates = next;
|
|
1003
|
+
paintMergePrompt(next, __hiddenProviders);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
function dismissMergePromptLater() {
|
|
835
1007
|
var did = __mergePromptDid || "";
|
|
836
1008
|
if (did) {
|
|
837
|
-
try {
|
|
1009
|
+
try { sessionStorage["connect.mergePrompt.later." + did] = "1"; } catch (e) {}
|
|
838
1010
|
}
|
|
839
1011
|
hideMergePrompt();
|
|
840
1012
|
}
|
|
@@ -842,74 +1014,117 @@ function dismissMergePrompt() {
|
|
|
842
1014
|
async function maybeShowMergePrompt(did) {
|
|
843
1015
|
hideMergePrompt();
|
|
844
1016
|
__mergePromptDid = did || "";
|
|
1017
|
+
__mergePromptCandidates = [];
|
|
845
1018
|
if (!did) return;
|
|
846
1019
|
try {
|
|
847
|
-
if (
|
|
1020
|
+
if (sessionStorage["connect.mergePrompt.later." + did] === "1") return;
|
|
848
1021
|
} catch (e) {}
|
|
849
1022
|
var data = await api("GET", "/../account/merge/candidate", undefined, { silent: true });
|
|
850
|
-
if (!data || data.mergeCandidate !== true) return;
|
|
1023
|
+
if (!data || data.mergeCandidate !== true || !data.candidates || !data.candidates.length) return;
|
|
851
1024
|
try {
|
|
852
|
-
if (
|
|
853
|
-
} catch (
|
|
1025
|
+
if (sessionStorage["connect.mergePrompt.later." + did] === "1") return;
|
|
1026
|
+
} catch (e2) {}
|
|
1027
|
+
var email = typeof data.email === "string" ? data.email : "";
|
|
1028
|
+
if (!email) return;
|
|
1029
|
+
var visible = [];
|
|
1030
|
+
for (var i = 0; i < data.candidates.length && visible.length < 5; i++) {
|
|
1031
|
+
var c = data.candidates[i];
|
|
1032
|
+
if (!c || typeof c.ref !== "string" || !c.ref) continue;
|
|
1033
|
+
try {
|
|
1034
|
+
if (localStorage["connect.mergePrompt.notMine." + did + "." + c.ref] === "1") continue;
|
|
1035
|
+
} catch (e3) {}
|
|
1036
|
+
visible.push({
|
|
1037
|
+
ref: c.ref,
|
|
1038
|
+
methods: Array.isArray(c.methods) ? c.methods : [],
|
|
1039
|
+
emailLogin: c.emailLogin === true,
|
|
1040
|
+
email: email,
|
|
1041
|
+
createdAt: typeof c.createdAt === "string" ? c.createdAt : "",
|
|
1042
|
+
lastLoginAt: typeof c.lastLoginAt === "string" ? c.lastLoginAt : "",
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
if (!visible.length) return;
|
|
854
1046
|
var el = document.getElementById("merge-candidate-prompt");
|
|
855
1047
|
if (!el) return;
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
+ '<div class="ca-merge-prompt-actions">'
|
|
859
|
-
+ '<button type="button" class="btn" id="merge-candidate-prompt-action" onclick="startAccountMerge()">' + escapeHtml(__t("profile.mergePromptAction")) + '</button>'
|
|
860
|
-
+ '<button type="button" class="btn btn-secondary" id="merge-candidate-prompt-dismiss" onclick="dismissMergePrompt()">' + escapeHtml(__t("profile.mergePromptDismiss")) + '</button>'
|
|
861
|
-
+ '</div>';
|
|
862
|
-
el.hidden = false;
|
|
863
|
-
el.style.display = "";
|
|
1048
|
+
__mergePromptCandidates = visible;
|
|
1049
|
+
paintMergePrompt(visible, __hiddenProviders);
|
|
864
1050
|
}
|
|
865
1051
|
|
|
866
|
-
async function startAccountMerge() {
|
|
1052
|
+
async function startAccountMerge(candidate) {
|
|
867
1053
|
cleanupAccountMergeOAuth();
|
|
868
|
-
var
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
} catch (e) {
|
|
872
|
-
showToast((e && e.message) || __t("profile.mergeFailed"), "error");
|
|
873
|
-
return;
|
|
874
|
-
}
|
|
875
|
-
if (!start || !start.challenge) {
|
|
876
|
-
showToast(__t("profile.mergeFailed"), "error");
|
|
877
|
-
return;
|
|
1054
|
+
var guided = null;
|
|
1055
|
+
if (candidate && typeof candidate.ref === "string" && candidate.ref) {
|
|
1056
|
+
guided = partitionMergeMethods(candidate, listMergeMethods(), __hiddenProviders);
|
|
878
1057
|
}
|
|
879
|
-
|
|
880
1058
|
var d = document.getElementById("account-merge-method-dialog");
|
|
881
1059
|
if (!d) {
|
|
882
1060
|
d = document.createElement("dialog");
|
|
883
1061
|
d.id = "account-merge-method-dialog";
|
|
884
1062
|
document.body.appendChild(d);
|
|
885
1063
|
}
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
1064
|
+
var challenge = null;
|
|
1065
|
+
function paint(errorText) {
|
|
1066
|
+
d.innerHTML = renderMergeMethodPickerHtml(guided ? [] : listMergeMethods(), __t, escapeHtml, getProviderIconSvg, getProviderLabel, errorText || "", guided);
|
|
1067
|
+
var cancel = document.getElementById("account-merge-method-cancel");
|
|
1068
|
+
if (cancel) cancel.onclick = function() { d.close(); };
|
|
1069
|
+
var buttons = d.querySelectorAll("[data-merge-method]");
|
|
1070
|
+
for (var b = 0; b < buttons.length; b++) {
|
|
1071
|
+
buttons[b].onclick = onPick;
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
paint("");
|
|
1075
|
+
d.showModal();
|
|
1076
|
+
|
|
1077
|
+
async function ensureChallenge(force) {
|
|
1078
|
+
if (challenge && !force) return challenge;
|
|
1079
|
+
var start = await api("POST", "/../account/merge/start", {}, { silent: true });
|
|
1080
|
+
if (!start || !start.challenge) {
|
|
1081
|
+
paint((start && start.error) || __t("profile.mergeFailed"));
|
|
1082
|
+
return null;
|
|
1083
|
+
}
|
|
1084
|
+
challenge = start.challenge;
|
|
1085
|
+
return challenge;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
async function onPick(event) {
|
|
1089
|
+
var button = event.currentTarget;
|
|
1090
|
+
var method = button.getAttribute("data-merge-method");
|
|
1091
|
+
var selectedProvider = button.getAttribute("data-merge-provider");
|
|
1092
|
+
paint("");
|
|
1093
|
+
var active = await ensureChallenge(false);
|
|
1094
|
+
if (!active) return;
|
|
1095
|
+
try {
|
|
1096
|
+
var proved = null;
|
|
1097
|
+
if (method === "wallet") proved = await proveAccountMergeWithWallet(active);
|
|
1098
|
+
else if (method === "passkey") proved = await proveAccountMergeWithPasskey(active);
|
|
1099
|
+
else if (method === "oauth") proved = await proveAccountMergeWithOAuth(selectedProvider, active);
|
|
1100
|
+
else if (method === "email") proved = await proveAccountMergeWithEmail(active, button.getAttribute("data-merge-email") || "");
|
|
1101
|
+
if (proved && proved.switchMethod) {
|
|
1102
|
+
if (typeof proved.challenge === "string" && proved.challenge) challenge = proved.challenge;
|
|
1103
|
+
paint(proved.error || "");
|
|
1104
|
+
return;
|
|
1105
|
+
}
|
|
1106
|
+
if (proved && proved.mergeIntent) {
|
|
1107
|
+
if (d.open) d.close();
|
|
1108
|
+
await finalizeAccountMerge(proved, candidate);
|
|
1109
|
+
return;
|
|
1110
|
+
}
|
|
1111
|
+
if (proved && proved.error) {
|
|
1112
|
+
if (mergeChallengeLooksExpired(proved.error)) {
|
|
1113
|
+
challenge = null;
|
|
1114
|
+
await ensureChallenge(true);
|
|
905
1115
|
}
|
|
1116
|
+
paint(proved.error);
|
|
1117
|
+
return;
|
|
906
1118
|
}
|
|
907
|
-
}
|
|
1119
|
+
} catch (e) {
|
|
1120
|
+
if (!e || e.name !== "NotAllowedError") {
|
|
1121
|
+
paint((e && e.message) || __t("profile.mergeFailed"));
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
908
1124
|
}
|
|
909
|
-
d.showModal();
|
|
910
1125
|
}
|
|
911
1126
|
|
|
912
|
-
function confirmMergePlan(plan) {
|
|
1127
|
+
function confirmMergePlan(plan, mergeIntent, candidateEmail) {
|
|
913
1128
|
return new Promise(function(resolve) {
|
|
914
1129
|
var d = document.getElementById("merge-confirm-dialog");
|
|
915
1130
|
if (!d) {
|
|
@@ -918,32 +1133,193 @@ function confirmMergePlan(plan) {
|
|
|
918
1133
|
d.className = "merge-confirm-dialog";
|
|
919
1134
|
document.body.appendChild(d);
|
|
920
1135
|
}
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
1136
|
+
var current = plan || {};
|
|
1137
|
+
var selectedKeep = current.keep === "proved" || current.keep === "session" ? current.keep : "session";
|
|
1138
|
+
// accounts.session.did stays the signed-in DID. intoDid follows keep.
|
|
1139
|
+
var sessionAccount = current.accounts && current.accounts.session;
|
|
1140
|
+
var sessionDid = sessionAccount && typeof sessionAccount.did === "string" ? sessionAccount.did : "";
|
|
1141
|
+
var hasCandidate = current.__hasCandidate === true;
|
|
1142
|
+
var loading = false;
|
|
1143
|
+
var generation = 0;
|
|
1144
|
+
var phase = "preview";
|
|
1145
|
+
var settled = false;
|
|
1146
|
+
var resultPayload = null;
|
|
929
1147
|
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
1148
|
+
function keptDid() {
|
|
1149
|
+
var side = selectedKeep === "proved" ? current.accounts && current.accounts.proved : current.accounts && current.accounts.session;
|
|
1150
|
+
if (side && typeof side.did === "string" && side.did) return side.did;
|
|
1151
|
+
return typeof current.intoDid === "string" ? current.intoDid : "";
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
function submitLabel() {
|
|
1155
|
+
if (selectedKeep === "session") return __t("profile.mergeConfirmSubmitKeep");
|
|
1156
|
+
return __t("profile.mergeConfirmSubmitSwitch", { did: truncateDid(keptDid()) });
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
function paint() {
|
|
1160
|
+
d.innerHTML = '<div class="dialog-content">'
|
|
1161
|
+
+ '<h3 id="merge-confirm-title">' + escapeHtml(__t("profile.mergeConfirmTitle")) + '</h3>'
|
|
1162
|
+
+ renderMergeConfirmBodyHtml(current, __t, escapeHtml, getProviderLabel, {
|
|
1163
|
+
selectedKeep: selectedKeep,
|
|
1164
|
+
hasCandidate: hasCandidate,
|
|
1165
|
+
candidateEmail: candidateEmail || "",
|
|
1166
|
+
shortDid: truncateDid,
|
|
1167
|
+
loading: loading
|
|
1168
|
+
})
|
|
1169
|
+
+ '</div>'
|
|
1170
|
+
+ '<div class="dialog-actions">'
|
|
1171
|
+
+ '<button type="button" class="btn btn-secondary" id="merge-confirm-cancel">' + escapeHtml(__t("common.cancel")) + '</button>'
|
|
1172
|
+
+ '<button type="button" class="btn btn-danger" id="merge-confirm-ok">' + escapeHtml(submitLabel()) + '</button>'
|
|
1173
|
+
+ '</div>';
|
|
1174
|
+
var okBtn = document.getElementById("merge-confirm-ok");
|
|
1175
|
+
var cancelBtn = document.getElementById("merge-confirm-cancel");
|
|
1176
|
+
if (loading || current.tooLarge || phase !== "preview") okBtn.disabled = true;
|
|
1177
|
+
cancelBtn.onclick = function() { finish(false); };
|
|
1178
|
+
okBtn.onclick = onOk;
|
|
1179
|
+
var radios = d.querySelectorAll('input[name="merge-keep"]');
|
|
1180
|
+
for (var i = 0; i < radios.length; i++) radios[i].onchange = onKeepChange;
|
|
1181
|
+
var copies = d.querySelectorAll("[data-copy-did]");
|
|
1182
|
+
for (var c = 0; c < copies.length; c++) copies[c].onclick = onCopy;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
function onCopy(event) {
|
|
1186
|
+
if (event) {
|
|
1187
|
+
if (event.preventDefault) event.preventDefault();
|
|
1188
|
+
if (event.stopPropagation) event.stopPropagation();
|
|
1189
|
+
}
|
|
1190
|
+
var btn = event && event.currentTarget;
|
|
1191
|
+
var full = btn && btn.getAttribute ? btn.getAttribute("data-copy-did") : "";
|
|
1192
|
+
if (full) copyToClipboard(full);
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
function onKeepChange(event) {
|
|
1196
|
+
if (phase !== "preview") return;
|
|
1197
|
+
var input = event && event.currentTarget;
|
|
1198
|
+
var next = input && input.value;
|
|
1199
|
+
if (next !== "session" && next !== "proved") return;
|
|
1200
|
+
if (next === selectedKeep) return;
|
|
1201
|
+
selectedKeep = next;
|
|
1202
|
+
loading = true;
|
|
1203
|
+
var token = ++generation;
|
|
1204
|
+
var okBtn = document.getElementById("merge-confirm-ok");
|
|
1205
|
+
if (okBtn) okBtn.disabled = true;
|
|
1206
|
+
setTimeout(function() {
|
|
1207
|
+
if (token !== generation || !loading || phase !== "preview") return;
|
|
1208
|
+
paint();
|
|
1209
|
+
}, 0);
|
|
1210
|
+
refreshKeep(next, token);
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
async function refreshKeep(next, token) {
|
|
1214
|
+
var refreshed = await api("POST", "/../account/merge/dry-run", { mergeIntent: mergeIntent, keep: next }, { silent: true });
|
|
1215
|
+
if (token !== generation) return;
|
|
1216
|
+
loading = false;
|
|
1217
|
+
if (!refreshed || refreshed.ok === false || !refreshed.accounts) {
|
|
1218
|
+
showToast((refreshed && refreshed.error) || __t("profile.mergeFailed"), "error");
|
|
1219
|
+
selectedKeep = current.keep === "proved" || current.keep === "session" ? current.keep : "session";
|
|
1220
|
+
paint();
|
|
1221
|
+
return;
|
|
1222
|
+
}
|
|
1223
|
+
current = refreshed;
|
|
1224
|
+
selectedKeep = current.keep === "proved" || current.keep === "session" ? current.keep : next;
|
|
1225
|
+
paint();
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
async function onOk() {
|
|
1229
|
+
if (phase !== "preview" || loading || current.tooLarge) return;
|
|
1230
|
+
var okBtn = document.getElementById("merge-confirm-ok");
|
|
1231
|
+
if (!okBtn || okBtn.disabled) return;
|
|
1232
|
+
okBtn.disabled = true;
|
|
1233
|
+
phase = "committing";
|
|
1234
|
+
generation += 1;
|
|
1235
|
+
var committed = await api("POST", "/../account/merge/commit", { mergeIntent: mergeIntent, keep: selectedKeep });
|
|
1236
|
+
if (settled) return;
|
|
1237
|
+
if (!committed || committed.ok === false || !committed.survivorDid) {
|
|
1238
|
+
phase = "preview";
|
|
1239
|
+
if (!d.open) {
|
|
1240
|
+
try { d.showModal(); } catch (err) {}
|
|
1241
|
+
}
|
|
1242
|
+
paint();
|
|
1243
|
+
return;
|
|
1244
|
+
}
|
|
1245
|
+
phase = "done";
|
|
1246
|
+
resultPayload = committed;
|
|
1247
|
+
showDone(committed);
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
function showDone(committed) {
|
|
1251
|
+
var survivorDid = committed && typeof committed.survivorDid === "string" ? committed.survivorDid : "";
|
|
1252
|
+
d.innerHTML = '<div class="dialog-content">'
|
|
1253
|
+
+ '<h3 id="merge-confirm-title">' + escapeHtml(__t("profile.mergeDoneTitle")) + '</h3>'
|
|
1254
|
+
+ renderMergeDoneBodyHtml({
|
|
1255
|
+
survivorDid: survivorDid,
|
|
1256
|
+
survivorMethods: current.survivorMethods
|
|
1257
|
+
}, __t, escapeHtml, getProviderLabel, truncateDid)
|
|
1258
|
+
+ '</div>'
|
|
1259
|
+
+ '<div class="dialog-actions">'
|
|
1260
|
+
+ '<button type="button" class="btn" id="merge-confirm-finish">' + escapeHtml(__t("profile.mergeDoneFinish")) + '</button>'
|
|
1261
|
+
+ '</div>';
|
|
1262
|
+
var finishBtn = document.getElementById("merge-confirm-finish");
|
|
1263
|
+
finishBtn.onclick = function() { finishDone(survivorDid); };
|
|
1264
|
+
if (!d.open) {
|
|
1265
|
+
try { d.showModal(); } catch (err) {}
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
function finishDone(survivorDid) {
|
|
1270
|
+
if (settled) return;
|
|
1271
|
+
settled = true;
|
|
1272
|
+
d.oncancel = null;
|
|
1273
|
+
d.onclose = null;
|
|
1274
|
+
if (d.open) d.close();
|
|
1275
|
+
if (survivorDid && sessionDid && survivorDid !== sessionDid) location.reload();
|
|
1276
|
+
else loadConnectedAccounts();
|
|
1277
|
+
resolve(true);
|
|
1278
|
+
}
|
|
933
1279
|
|
|
934
|
-
var settled = false;
|
|
935
1280
|
function finish(result) {
|
|
936
1281
|
if (settled) return;
|
|
1282
|
+
if (phase === "done") {
|
|
1283
|
+
finishDone(resultPayload && resultPayload.survivorDid ? resultPayload.survivorDid : "");
|
|
1284
|
+
return;
|
|
1285
|
+
}
|
|
1286
|
+
if (phase === "committing") {
|
|
1287
|
+
if (!d.open) {
|
|
1288
|
+
try { d.showModal(); } catch (err) {}
|
|
1289
|
+
}
|
|
1290
|
+
return;
|
|
1291
|
+
}
|
|
937
1292
|
settled = true;
|
|
938
|
-
|
|
939
|
-
cancelBtn.onclick = null;
|
|
1293
|
+
d.oncancel = null;
|
|
940
1294
|
d.onclose = null;
|
|
941
|
-
d.close();
|
|
1295
|
+
if (d.open) d.close();
|
|
942
1296
|
resolve(result);
|
|
943
1297
|
}
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
1298
|
+
|
|
1299
|
+
d.oncancel = function(event) {
|
|
1300
|
+
if (event && event.preventDefault) event.preventDefault();
|
|
1301
|
+
if (phase === "committing") return;
|
|
1302
|
+
if (phase === "done") {
|
|
1303
|
+
finishDone(resultPayload && resultPayload.survivorDid ? resultPayload.survivorDid : "");
|
|
1304
|
+
return;
|
|
1305
|
+
}
|
|
1306
|
+
finish(false);
|
|
1307
|
+
};
|
|
1308
|
+
d.onclose = function() {
|
|
1309
|
+
if (settled) return;
|
|
1310
|
+
if (phase === "committing") {
|
|
1311
|
+
if (!d.open) {
|
|
1312
|
+
try { d.showModal(); } catch (err) {}
|
|
1313
|
+
}
|
|
1314
|
+
return;
|
|
1315
|
+
}
|
|
1316
|
+
if (phase === "done") {
|
|
1317
|
+
finishDone(resultPayload && resultPayload.survivorDid ? resultPayload.survivorDid : "");
|
|
1318
|
+
return;
|
|
1319
|
+
}
|
|
1320
|
+
finish(false);
|
|
1321
|
+
};
|
|
1322
|
+
paint();
|
|
947
1323
|
d.showModal();
|
|
948
1324
|
});
|
|
949
1325
|
}
|