@arcblock/did-connect-service 4.1.61 → 4.1.63
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/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 +14 -0
- package/dist/pages/oauth-callback-page.d.ts.map +1 -1
- package/dist/pages/oauth-callback-page.js +35 -3
- 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
|
@@ -735,116 +735,514 @@ var __connectedAccounts = [];
|
|
|
735
735
|
var __oauthProviders = [];
|
|
736
736
|
var __accountMergeOAuthCleanup = null;
|
|
737
737
|
var __mergePromptDid = "";
|
|
738
|
+
var __mergePromptCandidates = [];
|
|
738
739
|
var __providerIcons = {"passkey":"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\"><path fill=\"currentColor\" d=\"M3 20v-2.8q0-.85.438-1.562T4.6 14.55q1.55-.775 3.15-1.162T11 13q.5 0 1 .038t1 .112q-.1 1.45.525 2.738T15.35 18v2zm16 3l-1.5-1.5v-4.65q-1.1-.325-1.8-1.237T15 13.5q0-1.45 1.025-2.475T18.5 10t2.475 1.025T22 13.5q0 1.125-.638 2t-1.612 1.25L21 18l-1.5 1.5L21 21zm-8-11q-1.65 0-2.825-1.175T7 8t1.175-2.825T11 4t2.825 1.175T15 8t-1.175 2.825T11 12m7.5 2q.425 0 .713-.288T19.5 13t-.288-.712T18.5 12t-.712.288T17.5 13t.288.713t.712.287\"/></svg>","wallet":"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\"><rect x=\"2\" y=\"4\" width=\"20\" height=\"16\" rx=\"3\" fill=\"#4598FA\"/><rect x=\"3\" y=\"6\" width=\"18\" height=\"12\" rx=\"2\" fill=\"white\" opacity=\"0.9\"/><rect x=\"0\" y=\"14\" width=\"24\" height=\"10\" rx=\"0\" fill=\"url(#dw_g)\"/><path d=\"M5.5 9.5h4.5c.3 0 .5.2.5.5v2.5c0 .3-.2.5-.5.5H5.5c-.3 0-.5-.2-.5-.5V10c0-.3.2-.5.5-.5z\" fill=\"#4598FA\"/><defs><linearGradient id=\"dw_g\" x1=\"12\" y1=\"14\" x2=\"12\" y2=\"24\" gradientUnits=\"userSpaceOnUse\"><stop stop-color=\"#77B2F6\"/><stop offset=\"1\" stop-color=\"#4598FA\"/></linearGradient></defs></svg>","did-connect":"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\"><rect x=\"2\" y=\"4\" width=\"20\" height=\"16\" rx=\"3\" fill=\"#4598FA\"/><rect x=\"3\" y=\"6\" width=\"18\" height=\"12\" rx=\"2\" fill=\"white\" opacity=\"0.9\"/><rect x=\"0\" y=\"14\" width=\"24\" height=\"10\" rx=\"0\" fill=\"url(#dw_g)\"/><path d=\"M5.5 9.5h4.5c.3 0 .5.2.5.5v2.5c0 .3-.2.5-.5.5H5.5c-.3 0-.5-.2-.5-.5V10c0-.3.2-.5.5-.5z\" fill=\"#4598FA\"/><defs><linearGradient id=\"dw_g\" x1=\"12\" y1=\"14\" x2=\"12\" y2=\"24\" gradientUnits=\"userSpaceOnUse\"><stop stop-color=\"#77B2F6\"/><stop offset=\"1\" stop-color=\"#4598FA\"/></linearGradient></defs></svg>","email":"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\"><path fill=\"currentColor\" d=\"M22 7.535V17a3 3 0 0 1-2.824 2.995L19 20H5a3 3 0 0 1-2.995-2.824L2 17V7.535l9.445 6.297l.116.066a1 1 0 0 0 .878 0l.116-.066z\"/><path fill=\"currentColor\" d=\"M19 4c1.08 0 2.027.57 2.555 1.427L12 11.797l-9.555-6.37a2.999 2.999 0 0 1 2.354-1.42L5 4z\"/></svg>","google":"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 256 262\"><path fill=\"#4285F4\" d=\"M255.878 133.451c0-10.734-.871-18.567-2.756-26.69H130.55v48.448h71.947c-1.45 12.04-9.283 30.172-26.69 42.356l-.244 1.622l38.755 30.023l2.685.268c24.659-22.774 38.875-56.282 38.875-96.027\"/><path fill=\"#34A853\" d=\"M130.55 261.1c35.248 0 64.839-11.605 86.453-31.622l-41.196-31.913c-11.024 7.688-25.82 13.055-45.257 13.055c-34.523 0-63.824-22.773-74.269-54.25l-1.531.13l-40.298 31.187l-.527 1.465C35.393 231.798 79.49 261.1 130.55 261.1\"/><path fill=\"#FBBC05\" d=\"M56.281 156.37c-2.756-8.123-4.351-16.827-4.351-25.82c0-8.994 1.595-17.697 4.206-25.82l-.073-1.73L15.26 71.312l-1.335.635C5.077 89.644 0 109.517 0 130.55s5.077 40.905 13.925 58.602z\"/><path fill=\"#EB4335\" d=\"M130.55 50.479c24.514 0 41.05 10.589 50.479 19.438l36.844-35.974C195.245 12.91 165.798 0 130.55 0C79.49 0 35.393 29.301 13.925 71.947l42.211 32.783c10.59-31.477 39.891-54.251 74.414-54.251\"/></svg>","github":"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 256 250\" fill=\"currentColor\"><path d=\"M128.001 0C57.317 0 0 57.307 0 128.001c0 56.554 36.676 104.535 87.535 121.46c6.397 1.185 8.746-2.777 8.746-6.158c0-3.052-.12-13.135-.174-23.83c-35.61 7.742-43.124-15.103-43.124-15.103c-5.823-14.795-14.213-18.73-14.213-18.73c-11.613-7.944.876-7.78.876-7.78c12.853.902 19.621 13.19 19.621 13.19c11.417 19.568 29.945 13.911 37.249 10.64c1.149-8.272 4.466-13.92 8.127-17.116c-28.431-3.236-58.318-14.212-58.318-63.258c0-13.975 5-25.394 13.188-34.358c-1.329-3.224-5.71-16.242 1.24-33.874c0 0 10.749-3.44 35.21 13.121c10.21-2.836 21.16-4.258 32.038-4.307c10.878.049 21.837 1.47 32.066 4.307c24.431-16.56 35.165-13.12 35.165-13.12c6.967 17.63 2.584 30.65 1.255 33.873c8.207 8.964 13.173 20.383 13.173 34.358c0 49.163-29.944 59.988-58.447 63.157c4.591 3.972 8.682 11.762 8.682 23.704c0 17.126-.148 30.91-.148 35.126c0 3.407 2.304 7.398 8.792 6.14C219.37 232.5 256 184.537 256 128.002C256 57.307 198.691 0 128.001 0\"/></svg>","apple":"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 256 315\" fill=\"currentColor\"><path d=\"M213.803 167.03c.442 47.58 41.74 63.413 42.197 63.615c-.35 1.116-6.599 22.563-21.757 44.716c-13.104 19.153-26.705 38.235-48.13 38.63c-21.05.388-27.82-12.483-51.888-12.483c-24.061 0-31.582 12.088-51.51 12.871c-20.68.783-36.428-20.71-49.64-39.793c-27-39.033-47.633-110.3-19.928-158.406c13.763-23.89 38.36-39.017 65.056-39.405c20.307-.388 39.475 13.675 51.889 13.675c12.406 0 35.699-16.895 60.186-14.414c10.25.427 39.026 4.14 57.503 31.186c-1.49.923-34.335 20.044-33.978 59.808M174.24 50.199c10.98-13.29 18.369-31.79 16.353-50.199c-15.826.636-34.962 10.546-46.314 23.828c-10.173 11.763-19.082 30.589-16.678 48.633c17.64 1.365 35.66-8.964 46.639-22.262\"/></svg>","twitter":"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 256 256\" fill=\"currentColor\"><path d=\"M149.079 108.399L242.33 0h-22.098l-80.97 94.12L74.59 0H0l97.796 142.328L0 256h22.1l85.507-99.395L175.905 256h74.59L149.073 108.399zM118.81 143.58l-9.909-14.172l-78.84-112.773h33.943l63.625 91.011l9.909 14.173l82.705 118.3H186.3l-67.49-96.533z\"/></svg>","auth0":"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 256 256\"><path fill=\"#EB5424\" d=\"M203.97 200.38L167.47 88l-39.5 112.38h75.98zm0-144.76L167.47 168l75.97-26.16l19.76-60.82c6.64-20.4-1.94-42.72-21.18-52.76l-38.06 27.36zM52.03 55.62L88.54 168l39.5-112.38H52.02zM52.03 200.38L88.54 88L12.56 114.16l-5.92 18.2c-6.64 20.4 1.94 42.72 21.18 52.76l24.2-17.38l.01.01v-.01l-.01.01.01-.37z\"/></svg>"};
|
|
739
740
|
var __hiddenProviders = ["facebook","auth0-legacy"];
|
|
740
741
|
function toMergeConfirmViewModel(plan) {
|
|
741
|
-
const
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
742
|
+
const raw = plan ?? {};
|
|
743
|
+
function textOrEmpty(value) {
|
|
744
|
+
return typeof value === "string" ? value : "";
|
|
745
|
+
}
|
|
746
|
+
function normalizeProvider(provider) {
|
|
747
|
+
const name = textOrEmpty(provider).trim();
|
|
748
|
+
if (name === "did-connect")
|
|
749
|
+
return "wallet";
|
|
750
|
+
return name;
|
|
751
|
+
}
|
|
752
|
+
function readSide(value) {
|
|
753
|
+
const methods = [];
|
|
754
|
+
const seen = new Set();
|
|
755
|
+
const listed = Array.isArray(value?.methods) ? value.methods : [];
|
|
756
|
+
for (const provider of listed) {
|
|
757
|
+
const name = normalizeProvider(provider);
|
|
758
|
+
if (!name || seen.has(name))
|
|
759
|
+
continue;
|
|
760
|
+
seen.add(name);
|
|
761
|
+
methods.push(name);
|
|
762
|
+
}
|
|
763
|
+
return {
|
|
764
|
+
did: textOrEmpty(value?.did),
|
|
765
|
+
methods,
|
|
766
|
+
createdAt: textOrEmpty(value?.createdAt),
|
|
767
|
+
globalRole: textOrEmpty(value?.globalRole),
|
|
768
|
+
fullName: textOrEmpty(value?.fullName),
|
|
769
|
+
handle: textOrEmpty(value?.handle),
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
const movedMethods = [];
|
|
773
|
+
const seenMethods = new Set();
|
|
774
|
+
const credentials = Array.isArray(raw.credentialsByProvider) ? raw.credentialsByProvider : [];
|
|
775
|
+
for (const row of credentials) {
|
|
776
|
+
const name = normalizeProvider(row?.provider);
|
|
777
|
+
if (!name || seenMethods.has(name))
|
|
778
|
+
continue;
|
|
779
|
+
seenMethods.add(name);
|
|
780
|
+
movedMethods.push(name);
|
|
781
|
+
}
|
|
782
|
+
const roleChanges = [];
|
|
783
|
+
const membershipChanges = Array.isArray(raw.membershipChanges) ? raw.membershipChanges : [];
|
|
784
|
+
for (const row of membershipChanges) {
|
|
785
|
+
const intoRoleBefore = textOrEmpty(row?.intoRoleBefore);
|
|
786
|
+
const keptRole = textOrEmpty(row?.keptRole);
|
|
787
|
+
if (!keptRole || keptRole === intoRoleBefore)
|
|
788
|
+
continue;
|
|
789
|
+
roleChanges.push({
|
|
790
|
+
fromRole: textOrEmpty(row?.fromRole),
|
|
791
|
+
intoRoleBefore,
|
|
792
|
+
keptRole,
|
|
793
|
+
instanceName: textOrEmpty(row?.instanceName),
|
|
794
|
+
});
|
|
795
|
+
}
|
|
796
|
+
const movedMemberships = [];
|
|
797
|
+
const moved = Array.isArray(raw.movedMemberships) ? raw.movedMemberships : [];
|
|
798
|
+
for (const row of moved) {
|
|
799
|
+
const instanceName = textOrEmpty(row?.instanceName);
|
|
800
|
+
const role = textOrEmpty(row?.role);
|
|
801
|
+
if (!instanceName && !role)
|
|
802
|
+
continue;
|
|
803
|
+
movedMemberships.push({ instanceName, role });
|
|
804
|
+
}
|
|
805
|
+
const change = raw.globalRoleChange;
|
|
806
|
+
const before = textOrEmpty(change?.before);
|
|
807
|
+
const after = textOrEmpty(change?.after);
|
|
808
|
+
const globalRoleChange = before && after && before !== after ? { before, after } : null;
|
|
809
|
+
const count = raw.accessKeyCount;
|
|
810
|
+
const accessKeyCount = typeof count === "number" && Number.isFinite(count) && count > 0 ? count : 0;
|
|
811
|
+
const recommendedKeep = raw.recommendedKeep === "proved" ? "proved" : "session";
|
|
812
|
+
const reasons = Array.isArray(raw.recommendReasons) ? raw.recommendReasons : [];
|
|
745
813
|
return {
|
|
746
|
-
tooLarge:
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
814
|
+
tooLarge: raw.tooLarge === true,
|
|
815
|
+
recommendedKeep,
|
|
816
|
+
fromDid: textOrEmpty(raw.fromDid),
|
|
817
|
+
intoDid: textOrEmpty(raw.intoDid),
|
|
818
|
+
session: readSide(raw.accounts?.session),
|
|
819
|
+
proved: readSide(raw.accounts?.proved),
|
|
820
|
+
recommendReasons: reasons.filter((code) => typeof code === "string"),
|
|
821
|
+
movedMethods,
|
|
822
|
+
roleChanges,
|
|
823
|
+
movedMemberships,
|
|
824
|
+
globalRoleChange,
|
|
825
|
+
accessKeyCount,
|
|
826
|
+
mergedHandle: textOrEmpty(raw.mergedHandle),
|
|
827
|
+
matchesCandidate: raw.matchesCandidate === true,
|
|
755
828
|
};
|
|
756
829
|
}
|
|
757
|
-
function renderMergeConfirmBodyHtml(plan, t, escapeHtml, providerLabel) {
|
|
830
|
+
function renderMergeConfirmBodyHtml(plan, t, escapeHtml, providerLabel, options) {
|
|
758
831
|
const view = toMergeConfirmViewModel(plan);
|
|
759
|
-
const
|
|
832
|
+
const requested = options?.selectedKeep;
|
|
833
|
+
const picked = requested === "session" || requested === "proved" ? requested : view.recommendedKeep;
|
|
834
|
+
function plain(value) {
|
|
835
|
+
return String(value ?? "").replace(/[{}]/g, "");
|
|
836
|
+
}
|
|
837
|
+
function text(key, params) {
|
|
838
|
+
let safe;
|
|
839
|
+
if (params) {
|
|
840
|
+
safe = {};
|
|
841
|
+
for (const name of Object.keys(params))
|
|
842
|
+
safe[name] = plain(params[name]);
|
|
843
|
+
}
|
|
844
|
+
return escapeHtml(t(key, safe));
|
|
845
|
+
}
|
|
846
|
+
function shortOf(did) {
|
|
847
|
+
if (typeof options?.shortDid === "function")
|
|
848
|
+
return options.shortDid(did);
|
|
849
|
+
if (!did)
|
|
850
|
+
return "";
|
|
851
|
+
if (did.length <= 17)
|
|
852
|
+
return did;
|
|
853
|
+
return `${did.slice(0, 8)}...${did.slice(-6)}`;
|
|
854
|
+
}
|
|
855
|
+
function roleLabel(role) {
|
|
760
856
|
const key = `common.${role}`;
|
|
761
857
|
const translated = t(key);
|
|
762
858
|
return translated === key ? role : translated;
|
|
763
|
-
};
|
|
764
|
-
const labelFor = (provider) => (providerLabel ? providerLabel(provider) : provider);
|
|
765
|
-
const skippedReason = (reason) => reason === "UNIQUE(provider,id)" ? t("profile.mergeConfirmSkippedReason") : reason;
|
|
766
|
-
const hostWarning = (code) => {
|
|
767
|
-
if (code === "blocklet-owner-clash")
|
|
768
|
-
return t("profile.mergeHostBlockletOwnerClash");
|
|
769
|
-
if (code === "external-token-rebind")
|
|
770
|
-
return t("profile.mergeHostExternalTokenRebind");
|
|
771
|
-
return code;
|
|
772
|
-
};
|
|
773
|
-
const wrapDid = (did) => `<code class="merge-confirm-did">${escapeHtml(did)}</code>`;
|
|
774
|
-
const credentialItems = view.credentialsByProvider
|
|
775
|
-
.map((provider) => `<li>${escapeHtml(labelFor(provider))}</li>`)
|
|
776
|
-
.join("");
|
|
777
|
-
const skippedItems = view.skippedConflicts
|
|
778
|
-
.map((row) => `<li>${escapeHtml(labelFor(row.provider))} — ${escapeHtml(skippedReason(row.reason))}</li>`)
|
|
779
|
-
.join("");
|
|
780
|
-
const roleItems = view.roleChanges
|
|
781
|
-
.map((row) => `<li>${escapeHtml(t("profile.mergeConfirmRoleChange", {
|
|
782
|
-
fromRole: roleLabel(row.fromRole),
|
|
783
|
-
intoRoleBefore: roleLabel(row.intoRoleBefore),
|
|
784
|
-
keptRole: roleLabel(row.keptRole),
|
|
785
|
-
}))}</li>`)
|
|
786
|
-
.join("");
|
|
787
|
-
const hostItems = view.hostWarningCodes
|
|
788
|
-
.map((code) => `<li>${escapeHtml(hostWarning(code))}</li>`)
|
|
789
|
-
.join("");
|
|
790
|
-
let html = `<p class="dialog-desc">${t("profile.mergeConfirmSurviving", {
|
|
791
|
-
intoDid: wrapDid(view.survivingDid),
|
|
792
|
-
fromDid: wrapDid(view.mergedDid),
|
|
793
|
-
})}</p>`;
|
|
794
|
-
html += `<p class="merge-confirm-keep-other">${t("profile.mergeConfirmKeepOther")}</p>`;
|
|
795
|
-
if (credentialItems) {
|
|
796
|
-
html += `<div class="merge-confirm-section"><h4>${escapeHtml(t("profile.mergeConfirmCredentials"))}</h4><ul class="merge-confirm-list">${credentialItems}</ul></div>`;
|
|
797
|
-
}
|
|
798
|
-
if (skippedItems) {
|
|
799
|
-
html += `<div class="merge-confirm-section"><h4>${escapeHtml(t("profile.mergeConfirmSkipped"))}</h4><ul class="merge-confirm-list">${skippedItems}</ul></div>`;
|
|
800
|
-
}
|
|
801
|
-
if (roleItems) {
|
|
802
|
-
html += `<div class="merge-confirm-section"><h4>${escapeHtml(t("profile.mergeConfirmRoles"))}</h4><ul class="merge-confirm-list">${roleItems}</ul></div>`;
|
|
803
|
-
}
|
|
804
|
-
if (view.accessKeyCount > 0) {
|
|
805
|
-
html += `<div class="merge-confirm-section"><h4>${escapeHtml(t("profile.mergeConfirmAccessKeysTitle"))}</h4><p class="merge-confirm-note">${escapeHtml(t("profile.mergeConfirmAccessKeys", { count: String(view.accessKeyCount) }))}</p></div>`;
|
|
806
|
-
}
|
|
807
|
-
html += `<div class="merge-confirm-section"><h4>${escapeHtml(t("profile.mergeConfirmDidSpaceTitle"))}</h4><p class="merge-confirm-note">${t("profile.mergeDidSpace", {
|
|
808
|
-
pointer: wrapDid(view.didSpacePointer),
|
|
809
|
-
})}</p></div>`;
|
|
810
|
-
if (hostItems) {
|
|
811
|
-
html += `<div class="merge-confirm-section"><h4>${escapeHtml(t("profile.mergeConfirmHostWarnings"))}</h4><ul class="merge-confirm-list">${hostItems}</ul></div>`;
|
|
812
|
-
}
|
|
813
|
-
html += `<p class="merge-confirm-irreversible">${escapeHtml(t("profile.mergeConfirmIrreversible"))}</p>`;
|
|
814
|
-
if (view.tooLarge) {
|
|
815
|
-
html += `<p class="merge-confirm-too-large">${escapeHtml(t("profile.mergeConfirmTooLarge"))}</p>`;
|
|
816
859
|
}
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
860
|
+
function methodLabels(methods) {
|
|
861
|
+
const labels = [];
|
|
862
|
+
for (const provider of methods) {
|
|
863
|
+
labels.push(typeof providerLabel === "function" ? providerLabel(provider) : provider);
|
|
864
|
+
}
|
|
865
|
+
return labels.join(t("profile.mergePromptMethodSep"));
|
|
866
|
+
}
|
|
867
|
+
function createdOn(iso) {
|
|
868
|
+
const match = /^(\d{4}-\d{2}-\d{2})/.exec(iso);
|
|
869
|
+
return match?.[1] ?? iso;
|
|
870
|
+
}
|
|
871
|
+
function accountCard(keep) {
|
|
872
|
+
const account = keep === "session" ? view.session : view.proved;
|
|
873
|
+
const lines = [];
|
|
874
|
+
const nameBits = [];
|
|
875
|
+
if (account.fullName)
|
|
876
|
+
nameBits.push(account.fullName);
|
|
877
|
+
if (account.handle)
|
|
878
|
+
nameBits.push(`@${account.handle}`);
|
|
879
|
+
if (nameBits.length > 0) {
|
|
880
|
+
lines.push(`<span class="merge-confirm-line">${escapeHtml(nameBits.join(" · "))}</span>`);
|
|
881
|
+
}
|
|
882
|
+
if (account.methods.length > 0) {
|
|
883
|
+
lines.push(`<span class="merge-confirm-line">${escapeHtml(methodLabels(account.methods))}</span>`);
|
|
884
|
+
}
|
|
885
|
+
const meta = [];
|
|
886
|
+
if (account.globalRole)
|
|
887
|
+
meta.push(roleLabel(account.globalRole));
|
|
888
|
+
if (account.createdAt)
|
|
889
|
+
meta.push(t("profile.mergeConfirmCreated", { date: plain(createdOn(account.createdAt)) }));
|
|
890
|
+
if (meta.length > 0)
|
|
891
|
+
lines.push(`<span class="merge-confirm-line">${escapeHtml(meta.join(" · "))}</span>`);
|
|
892
|
+
if (keep === "session") {
|
|
893
|
+
lines.push(`<span class="merge-confirm-current">${text("profile.mergeConfirmCurrent")}</span>`);
|
|
894
|
+
}
|
|
895
|
+
const copy = account.did
|
|
896
|
+
? `<button type="button" class="merge-confirm-copy" data-copy-did="${escapeHtml(account.did)}">${text("common.copy")}</button>`
|
|
897
|
+
: "";
|
|
898
|
+
const badge = view.recommendedKeep === keep
|
|
899
|
+
? `<span class="merge-confirm-badge">${text("profile.mergeConfirmRecommended")}</span>`
|
|
900
|
+
: "";
|
|
901
|
+
const selected = picked === keep ? " checked" : "";
|
|
902
|
+
const selectedClass = picked === keep ? " is-selected" : "";
|
|
903
|
+
return (`<label class="merge-confirm-card${selectedClass}" data-keep="${keep}">` +
|
|
904
|
+
`<input type="radio" name="merge-keep" value="${keep}"${selected}>` +
|
|
905
|
+
`<span class="merge-confirm-card-main">` +
|
|
906
|
+
`<span class="merge-confirm-card-head"><span class="merge-confirm-did">${escapeHtml(shortOf(account.did))}</span>${copy}${badge}</span>` +
|
|
907
|
+
lines.join("") +
|
|
908
|
+
`</span></label>`);
|
|
909
|
+
}
|
|
910
|
+
let banner = "";
|
|
911
|
+
if (options?.hasCandidate === true && view.matchesCandidate && options.candidateEmail) {
|
|
912
|
+
banner = `<p class="merge-confirm-match">${text("profile.mergeConfirmMatch", { email: options.candidateEmail })}</p>`;
|
|
913
|
+
}
|
|
914
|
+
else if (options?.hasCandidate === true && !view.matchesCandidate) {
|
|
915
|
+
banner = `<p class="merge-confirm-not-match">${text("profile.mergeConfirmNotMatch")}</p>`;
|
|
916
|
+
}
|
|
917
|
+
const primary = view.recommendedKeep === "proved" ? "proved" : "session";
|
|
918
|
+
const secondary = primary === "session" ? "proved" : "session";
|
|
919
|
+
const recommendedAccount = view.recommendedKeep === "proved" ? view.proved : view.session;
|
|
920
|
+
const reasonBits = [];
|
|
921
|
+
for (const code of view.recommendReasons) {
|
|
922
|
+
if (code === "global-role" || code === "instance-role")
|
|
923
|
+
reasonBits.push(t("profile.mergeConfirmReasonHigher"));
|
|
924
|
+
else if (code === "handle") {
|
|
925
|
+
reasonBits.push(t("profile.mergeConfirmReasonHandle", { handle: plain(recommendedAccount.handle) }));
|
|
926
|
+
}
|
|
927
|
+
else if (code === "wallet-did")
|
|
928
|
+
reasonBits.push(t("profile.mergeConfirmReasonWallet"));
|
|
929
|
+
else if (code === "older")
|
|
930
|
+
reasonBits.push(t("profile.mergeConfirmReasonOlder"));
|
|
931
|
+
}
|
|
932
|
+
const reason = reasonBits.length
|
|
933
|
+
? text("profile.mergeConfirmReasonLead", {
|
|
934
|
+
did: shortOf(recommendedAccount.did),
|
|
935
|
+
reason: reasonBits.join(" "),
|
|
936
|
+
})
|
|
937
|
+
: text("profile.mergeConfirmReasonSimilar");
|
|
938
|
+
let changes = "";
|
|
939
|
+
if (options?.loading === true) {
|
|
940
|
+
changes =
|
|
941
|
+
`<div id="merge-confirm-changes" class="merge-confirm-section">` +
|
|
942
|
+
`<h4>${text("profile.mergeConfirmChanges")}</h4>` +
|
|
943
|
+
`<p class="merge-confirm-loading">${text("profile.mergeConfirmLoading")}</p>` +
|
|
944
|
+
`</div>`;
|
|
945
|
+
}
|
|
946
|
+
else {
|
|
947
|
+
const rows = [];
|
|
948
|
+
if (view.movedMethods.length > 0) {
|
|
949
|
+
rows.push(`<li>${text("profile.mergeConfirmMovedMethods", { methods: methodLabels(view.movedMethods) })}</li>`);
|
|
950
|
+
}
|
|
951
|
+
if (view.globalRoleChange) {
|
|
952
|
+
rows.push(`<li>${text("profile.mergeConfirmGlobalRole", {
|
|
953
|
+
before: roleLabel(view.globalRoleChange.before),
|
|
954
|
+
after: roleLabel(view.globalRoleChange.after),
|
|
955
|
+
})}</li>`);
|
|
956
|
+
}
|
|
957
|
+
for (const row of view.roleChanges) {
|
|
958
|
+
const before = roleLabel(row.intoRoleBefore);
|
|
959
|
+
const after = roleLabel(row.keptRole);
|
|
960
|
+
const line = row.instanceName
|
|
961
|
+
? text("profile.mergeConfirmSpaceRole", { space: row.instanceName, before, after })
|
|
962
|
+
: text("profile.mergeConfirmSpaceRoleUnnamed", { before, after });
|
|
963
|
+
rows.push(`<li>${line}</li>`);
|
|
964
|
+
}
|
|
965
|
+
if (view.movedMemberships.length > 0) {
|
|
966
|
+
const parts = [];
|
|
967
|
+
for (const row of view.movedMemberships) {
|
|
968
|
+
const role = roleLabel(row.role);
|
|
969
|
+
parts.push(row.instanceName
|
|
970
|
+
? t("profile.mergeConfirmJoinedSpace", { space: plain(row.instanceName), role: plain(role) })
|
|
971
|
+
: t("profile.mergeConfirmJoinedSpaceUnnamed", { role: plain(role) }));
|
|
972
|
+
}
|
|
973
|
+
rows.push(`<li>${text("profile.mergeConfirmJoinedSpaces", {
|
|
974
|
+
spaces: parts.join(t("profile.mergePromptMethodSep")),
|
|
975
|
+
})}</li>`);
|
|
976
|
+
}
|
|
977
|
+
if (view.accessKeyCount > 0) {
|
|
978
|
+
rows.push(`<li>${text("profile.mergeConfirmAccessKeys", { count: String(view.accessKeyCount) })}</li>`);
|
|
979
|
+
}
|
|
980
|
+
if (view.mergedHandle) {
|
|
981
|
+
rows.push(`<li>${text("profile.mergeConfirmHandleStays", {
|
|
982
|
+
handle: view.mergedHandle,
|
|
983
|
+
did: shortOf(view.fromDid),
|
|
984
|
+
})}</li>`);
|
|
985
|
+
}
|
|
986
|
+
rows.push(`<li>${text("profile.mergeConfirmNameAvatar", { did: shortOf(view.fromDid) })}</li>`);
|
|
987
|
+
rows.push(`<li>${text("profile.mergeConfirmDidSpaceNotCopied", { did: shortOf(view.fromDid) })}</li>`);
|
|
988
|
+
const tooLarge = view.tooLarge
|
|
989
|
+
? `<p class="merge-confirm-too-large">${text("profile.mergeConfirmTooLarge")}</p>`
|
|
990
|
+
: "";
|
|
991
|
+
changes =
|
|
992
|
+
`<div id="merge-confirm-changes" class="merge-confirm-section">` +
|
|
993
|
+
`<h4>${text("profile.mergeConfirmChanges")}</h4>` +
|
|
994
|
+
`<ul class="merge-confirm-list">${rows.join("")}</ul>` +
|
|
995
|
+
`<p class="merge-confirm-host">${text("profile.mergeConfirmHostMaybe", { did: shortOf(view.fromDid) })}</p>` +
|
|
996
|
+
`<p class="merge-confirm-irreversible">${text("profile.mergeConfirmIrreversible")}</p>` +
|
|
997
|
+
tooLarge +
|
|
998
|
+
`</div>`;
|
|
999
|
+
}
|
|
1000
|
+
return (banner +
|
|
1001
|
+
`<p class="merge-confirm-choose">${text("profile.mergeConfirmChoose")}</p>` +
|
|
1002
|
+
`<div class="merge-confirm-cards">${accountCard(primary)}${accountCard(secondary)}</div>` +
|
|
1003
|
+
`<p class="merge-confirm-reason">${reason}</p>` +
|
|
1004
|
+
`<p class="merge-confirm-alias">${text("profile.mergeConfirmAlias")}</p>` +
|
|
1005
|
+
changes);
|
|
1006
|
+
}
|
|
1007
|
+
function renderMergeDoneBodyHtml(input, t, escapeHtml, providerLabel, shortDid) {
|
|
1008
|
+
const data = input ?? {};
|
|
1009
|
+
const did = typeof data.survivorDid === "string" ? data.survivorDid : "";
|
|
1010
|
+
function plain(value) {
|
|
1011
|
+
return String(value ?? "").replace(/[{}]/g, "");
|
|
1012
|
+
}
|
|
1013
|
+
function text(key, params) {
|
|
1014
|
+
let safe;
|
|
1015
|
+
if (params) {
|
|
1016
|
+
safe = {};
|
|
1017
|
+
for (const name of Object.keys(params))
|
|
1018
|
+
safe[name] = plain(params[name]);
|
|
1019
|
+
}
|
|
1020
|
+
return escapeHtml(t(key, safe));
|
|
1021
|
+
}
|
|
1022
|
+
function shortOf(value) {
|
|
1023
|
+
if (typeof shortDid === "function")
|
|
1024
|
+
return shortDid(value);
|
|
1025
|
+
if (!value)
|
|
1026
|
+
return "";
|
|
1027
|
+
if (value.length <= 17)
|
|
1028
|
+
return value;
|
|
1029
|
+
return `${value.slice(0, 8)}...${value.slice(-6)}`;
|
|
1030
|
+
}
|
|
1031
|
+
const seen = new Set();
|
|
1032
|
+
const labels = [];
|
|
1033
|
+
const methods = Array.isArray(data.survivorMethods) ? data.survivorMethods : [];
|
|
1034
|
+
for (const provider of methods) {
|
|
1035
|
+
if (typeof provider !== "string")
|
|
1036
|
+
continue;
|
|
1037
|
+
const name = provider.trim() === "did-connect" ? "wallet" : provider.trim();
|
|
1038
|
+
if (!name || seen.has(name))
|
|
1039
|
+
continue;
|
|
1040
|
+
seen.add(name);
|
|
1041
|
+
labels.push(typeof providerLabel === "function" ? providerLabel(name) : name);
|
|
1042
|
+
}
|
|
1043
|
+
const didLine = `<p class="merge-confirm-done-did">${text("profile.mergeDoneDid", { did: shortOf(did) })}</p>`;
|
|
1044
|
+
if (labels.length === 0)
|
|
1045
|
+
return didLine;
|
|
1046
|
+
return (didLine +
|
|
1047
|
+
`<p class="merge-confirm-done-methods">${text("profile.mergeDoneMethods", {
|
|
1048
|
+
methods: labels.join(t("profile.mergePromptMethodSep")),
|
|
1049
|
+
})}</p>`);
|
|
1050
|
+
}
|
|
1051
|
+
function renderMergeMethodPickerHtml(options, t, escapeHtml, iconFor, labelFor, errorText, guide) {
|
|
1052
|
+
const button = (opt, primary) => {
|
|
1053
|
+
const cls = primary ? "btn merge-method-btn" : "btn btn-secondary merge-method-btn";
|
|
822
1054
|
if (opt.method === "wallet") {
|
|
823
|
-
return (`<button type="button" class="
|
|
1055
|
+
return (`<button type="button" class="${cls}" data-merge-method="wallet">` +
|
|
824
1056
|
`${iconFor("did-connect")} ${escapeHtml(t("profile.mergeProveWallet"))}</button>`);
|
|
825
1057
|
}
|
|
826
1058
|
if (opt.method === "passkey") {
|
|
827
|
-
return (`<button type="button" class="
|
|
1059
|
+
return (`<button type="button" class="${cls}" data-merge-method="passkey">` +
|
|
828
1060
|
`${iconFor("passkey")} ${escapeHtml(t("profile.mergeProvePasskey"))}</button>`);
|
|
829
1061
|
}
|
|
830
1062
|
if (opt.method === "email") {
|
|
831
|
-
|
|
832
|
-
|
|
1063
|
+
const label = opt.email ? t("profile.mergeProveEmailAddress", { email: opt.email }) : t("profile.mergeProveEmail");
|
|
1064
|
+
const emailAttr = opt.email ? ` data-merge-email="${escapeHtml(opt.email)}"` : "";
|
|
1065
|
+
return (`<button type="button" class="${cls}" data-merge-method="email"${emailAttr}>` +
|
|
1066
|
+
`${iconFor("email")} ${escapeHtml(label)}</button>`);
|
|
833
1067
|
}
|
|
834
1068
|
const provider = opt.provider || "";
|
|
835
|
-
return (`<button type="button" class="
|
|
1069
|
+
return (`<button type="button" class="${cls}" data-merge-method="oauth" data-merge-provider="${escapeHtml(provider)}">` +
|
|
836
1070
|
`${iconFor(provider)} ${escapeHtml(t("profile.mergeProveOAuth", { provider: labelFor(provider) }))}</button>`);
|
|
837
|
-
}
|
|
838
|
-
|
|
1071
|
+
};
|
|
1072
|
+
const alert = errorText
|
|
1073
|
+
? `<p id="account-merge-method-error" class="dialog-desc" role="alert">${escapeHtml(errorText)}</p>`
|
|
1074
|
+
: "";
|
|
1075
|
+
const hintKey = guide ? "profile.mergeCandidateProveHint" : "profile.mergeAccountHint";
|
|
1076
|
+
let listHtml = "";
|
|
1077
|
+
if (guide) {
|
|
1078
|
+
if (guide.unavailable) {
|
|
1079
|
+
listHtml += `<p class="merge-method-unavailable">${escapeHtml(t("profile.mergePromptMethodsDisabled"))}</p>`;
|
|
1080
|
+
}
|
|
1081
|
+
else {
|
|
1082
|
+
const recommended = (guide.recommended || []).map((opt) => button(opt, true)).join("");
|
|
1083
|
+
listHtml +=
|
|
1084
|
+
`<div class="merge-method-recommended">` +
|
|
1085
|
+
`<p class="merge-method-kicker">${escapeHtml(t("profile.mergePromptMethodsLabel"))}</p>` +
|
|
1086
|
+
`<div class="merge-method-list">${recommended}</div></div>`;
|
|
1087
|
+
}
|
|
1088
|
+
const others = guide.others || [];
|
|
1089
|
+
if (others.length) {
|
|
1090
|
+
const open = guide.othersOpen ? " open" : "";
|
|
1091
|
+
listHtml +=
|
|
1092
|
+
`<details class="merge-method-others"${open}>` +
|
|
1093
|
+
`<summary>${escapeHtml(t("profile.mergePromptOtherMethods"))}</summary>` +
|
|
1094
|
+
`<div class="merge-method-list">${others.map((opt) => button(opt, false)).join("")}</div></details>`;
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
else {
|
|
1098
|
+
listHtml = `<div class="merge-method-list">${(options || []).map((opt) => button(opt, false)).join("")}</div>`;
|
|
1099
|
+
}
|
|
839
1100
|
return (`<div class="dialog-content">` +
|
|
840
1101
|
`<h3>${escapeHtml(t("profile.mergeChooseMethod"))}</h3>` +
|
|
841
|
-
`<p class="dialog-desc">${escapeHtml(t(
|
|
842
|
-
|
|
1102
|
+
`<p class="dialog-desc">${escapeHtml(t(hintKey))}</p>` +
|
|
1103
|
+
alert +
|
|
1104
|
+
listHtml +
|
|
843
1105
|
`</div>` +
|
|
844
1106
|
`<div class="dialog-actions">` +
|
|
845
1107
|
`<button type="button" class="btn btn-secondary" id="account-merge-method-cancel">${escapeHtml(t("common.cancel"))}</button>` +
|
|
846
1108
|
`</div>`);
|
|
847
1109
|
}
|
|
1110
|
+
function formatMergeCandidateWhen(iso, nowMs, lang, t) {
|
|
1111
|
+
if (!iso)
|
|
1112
|
+
return "";
|
|
1113
|
+
const then = new Date(iso).getTime();
|
|
1114
|
+
if (Number.isNaN(then))
|
|
1115
|
+
return "";
|
|
1116
|
+
const dayMs = 86400000;
|
|
1117
|
+
let days = Math.floor((nowMs - then) / dayMs);
|
|
1118
|
+
if (days < 0)
|
|
1119
|
+
days = 0;
|
|
1120
|
+
if (days >= 365) {
|
|
1121
|
+
const locale = lang || "en";
|
|
1122
|
+
try {
|
|
1123
|
+
return new Intl.DateTimeFormat(locale, { year: "numeric", month: "long" }).format(new Date(then));
|
|
1124
|
+
}
|
|
1125
|
+
catch {
|
|
1126
|
+
return new Intl.DateTimeFormat("en", { year: "numeric", month: "long" }).format(new Date(then));
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
if (days >= 30) {
|
|
1130
|
+
const months = Math.max(1, Math.floor(days / 30));
|
|
1131
|
+
return months === 1 ? t("profile.mergePromptMonthAgo") : t("profile.mergePromptMonthsAgo", { count: String(months) });
|
|
1132
|
+
}
|
|
1133
|
+
if (days === 0)
|
|
1134
|
+
return t("profile.mergePromptToday");
|
|
1135
|
+
if (days === 1)
|
|
1136
|
+
return t("profile.mergePromptDayAgo");
|
|
1137
|
+
return t("profile.mergePromptDaysAgo", { count: String(days) });
|
|
1138
|
+
}
|
|
1139
|
+
function partitionMergeMethods(candidate, enabled, hiddenProviders) {
|
|
1140
|
+
const enabledList = enabled || [];
|
|
1141
|
+
const hidden = hiddenProviders || [];
|
|
1142
|
+
const methods = (candidate && candidate.methods) || [];
|
|
1143
|
+
const emailLogin = !!(candidate && candidate.emailLogin === true);
|
|
1144
|
+
const email = (candidate && typeof candidate.email === "string" && candidate.email) || "";
|
|
1145
|
+
const recommended = [];
|
|
1146
|
+
const used = {};
|
|
1147
|
+
const isHidden = (name) => hidden.indexOf(name) !== -1;
|
|
1148
|
+
const findEnabled = (method, provider) => {
|
|
1149
|
+
for (let i = 0; i < enabledList.length; i++) {
|
|
1150
|
+
const opt = enabledList[i];
|
|
1151
|
+
if (!opt || opt.method !== method)
|
|
1152
|
+
continue;
|
|
1153
|
+
if (method === "oauth" && opt.provider !== provider)
|
|
1154
|
+
continue;
|
|
1155
|
+
return opt;
|
|
1156
|
+
}
|
|
1157
|
+
return null;
|
|
1158
|
+
};
|
|
1159
|
+
for (let m = 0; m < methods.length; m++) {
|
|
1160
|
+
const name = methods[m];
|
|
1161
|
+
if (!name || isHidden(name) || name === "email")
|
|
1162
|
+
continue;
|
|
1163
|
+
const method = name === "wallet" || name === "passkey" ? name : "oauth";
|
|
1164
|
+
const provider = method === "oauth" ? name : "";
|
|
1165
|
+
const hit = findEnabled(method, provider);
|
|
1166
|
+
if (!hit)
|
|
1167
|
+
continue;
|
|
1168
|
+
const key = `${method}:${hit.provider || ""}`;
|
|
1169
|
+
if (used[key])
|
|
1170
|
+
continue;
|
|
1171
|
+
used[key] = true;
|
|
1172
|
+
if (method === "oauth")
|
|
1173
|
+
recommended.push({ method: "oauth", provider: hit.provider || provider });
|
|
1174
|
+
else if (method === "wallet")
|
|
1175
|
+
recommended.push({ method: "wallet" });
|
|
1176
|
+
else
|
|
1177
|
+
recommended.push({ method: "passkey" });
|
|
1178
|
+
}
|
|
1179
|
+
if (emailLogin && email && findEnabled("email", "")) {
|
|
1180
|
+
recommended.push({ method: "email", email });
|
|
1181
|
+
used["email:"] = true;
|
|
1182
|
+
}
|
|
1183
|
+
const others = [];
|
|
1184
|
+
for (let e = 0; e < enabledList.length; e++) {
|
|
1185
|
+
const opt = enabledList[e];
|
|
1186
|
+
if (!opt || opt.method === "email")
|
|
1187
|
+
continue;
|
|
1188
|
+
const key = `${opt.method}:${opt.provider || ""}`;
|
|
1189
|
+
if (used[key])
|
|
1190
|
+
continue;
|
|
1191
|
+
others.push(opt.method === "oauth" ? { method: "oauth", provider: opt.provider || "" } : { method: opt.method });
|
|
1192
|
+
}
|
|
1193
|
+
const unavailable = recommended.length === 0;
|
|
1194
|
+
return { recommended, others, othersOpen: unavailable, unavailable };
|
|
1195
|
+
}
|
|
1196
|
+
function renderMergePromptHtml(email, candidates, t, escapeHtml, iconFor, labelFor, formatWhen, hiddenProviders) {
|
|
1197
|
+
const hidden = hiddenProviders || [];
|
|
1198
|
+
const rows = candidates || [];
|
|
1199
|
+
const many = rows.length > 1;
|
|
1200
|
+
const title = many
|
|
1201
|
+
? t("profile.mergePromptTitleMany", { email, count: String(rows.length) })
|
|
1202
|
+
: t("profile.mergePromptTitleOne", { email });
|
|
1203
|
+
const body = many ? t("profile.mergePromptBodyMany") : t("profile.mergePromptBodyOne");
|
|
1204
|
+
let html = `<div class="ca-merge-prompt-title">${escapeHtml(title)}</div>` +
|
|
1205
|
+
`<p class="ca-merge-prompt-body">${escapeHtml(body)}</p>`;
|
|
1206
|
+
for (let i = 0; i < rows.length; i++) {
|
|
1207
|
+
const row = rows[i];
|
|
1208
|
+
if (!row)
|
|
1209
|
+
continue;
|
|
1210
|
+
const methods = row.methods || [];
|
|
1211
|
+
const icons = [];
|
|
1212
|
+
const names = [];
|
|
1213
|
+
for (let m = 0; m < methods.length; m++) {
|
|
1214
|
+
const name = methods[m];
|
|
1215
|
+
if (!name || hidden.indexOf(name) !== -1)
|
|
1216
|
+
continue;
|
|
1217
|
+
icons.push(`<span class="ca-merge-prompt-icon">${iconFor(name)}</span>`);
|
|
1218
|
+
names.push(escapeHtml(labelFor(name)));
|
|
1219
|
+
}
|
|
1220
|
+
const bits = [];
|
|
1221
|
+
if (names.length) {
|
|
1222
|
+
bits.push(`<span class="ca-merge-prompt-methods">${icons.join("")}` +
|
|
1223
|
+
`<span class="ca-merge-prompt-method-names">${names.join(escapeHtml(t("profile.mergePromptMethodSep")))}</span></span>`);
|
|
1224
|
+
}
|
|
1225
|
+
const created = row.createdAt ? formatWhen(row.createdAt) : "";
|
|
1226
|
+
if (created)
|
|
1227
|
+
bits.push(escapeHtml(t("profile.mergePromptCreated", { when: created })));
|
|
1228
|
+
const last = row.lastLoginAt ? formatWhen(row.lastLoginAt) : "";
|
|
1229
|
+
if (last)
|
|
1230
|
+
bits.push(escapeHtml(t("profile.mergePromptLastLogin", { when: last })));
|
|
1231
|
+
const ref = escapeHtml(row.ref || "");
|
|
1232
|
+
html +=
|
|
1233
|
+
`<div class="ca-merge-prompt-row">` +
|
|
1234
|
+
`<div class="ca-merge-prompt-meta">${bits.join('<span class="ca-merge-prompt-dot"> · </span>')}</div>` +
|
|
1235
|
+
`<div class="ca-merge-prompt-actions">` +
|
|
1236
|
+
`<button type="button" class="btn" data-merge-ref="${ref}" onclick="startMergeCandidate(this)">${escapeHtml(t("profile.mergePromptMergeThis"))}</button>` +
|
|
1237
|
+
`<button type="button" class="btn btn-secondary" data-merge-ref="${ref}" onclick="hideMergeCandidate(this)">${escapeHtml(t("profile.mergePromptNotMine"))}</button>` +
|
|
1238
|
+
`</div></div>`;
|
|
1239
|
+
}
|
|
1240
|
+
html +=
|
|
1241
|
+
`<div class="ca-merge-prompt-later">` +
|
|
1242
|
+
`<button type="button" class="btn btn-secondary" id="merge-candidate-prompt-later" onclick="dismissMergePromptLater()">` +
|
|
1243
|
+
`${escapeHtml(t("profile.mergePromptLater"))}</button></div>`;
|
|
1244
|
+
return html;
|
|
1245
|
+
}
|
|
848
1246
|
|
|
849
1247
|
async function loadConnectedAccounts() {
|
|
850
1248
|
var card = document.getElementById("connected-accounts-card");
|
|
@@ -979,7 +1377,7 @@ function renderConnectedAccounts() {
|
|
|
979
1377
|
html += '<div class="ca-section">';
|
|
980
1378
|
html += '<div class="ca-section-label">' + __t("profile.mergeAccount") + '</div>';
|
|
981
1379
|
html += '<p class="ca-merge-hint" style="margin:0 0 8px;color:var(--text-secondary);font-size:13px;">' + __t("profile.mergeAccountHint") + '</p>';
|
|
982
|
-
html += '<button class="btn btn-secondary" onclick="startAccountMerge()">' + __t("profile.
|
|
1380
|
+
html += '<button class="btn btn-secondary" onclick="startAccountMerge()">' + __t("profile.mergeStart") + '</button>';
|
|
983
1381
|
html += '</div>';
|
|
984
1382
|
|
|
985
1383
|
list.innerHTML = html;
|
|
@@ -1310,17 +1708,29 @@ function cleanupAccountMergeOAuth() {
|
|
|
1310
1708
|
if (__accountMergeOAuthCleanup) __accountMergeOAuthCleanup();
|
|
1311
1709
|
}
|
|
1312
1710
|
|
|
1711
|
+
function mergeChallengeLooksExpired(error) {
|
|
1712
|
+
return error === "Invalid or expired merge challenge"
|
|
1713
|
+
|| error === "合并验证无效或已过期"
|
|
1714
|
+
|| error === "合併驗證無效或已過期"
|
|
1715
|
+
|| error === "統合チャレンジが無効か、期限切れです";
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
function emailCodeAlreadySent(error) {
|
|
1719
|
+
return error === "Code already sent, please wait"
|
|
1720
|
+
|| error === "验证码已发送,请稍候"
|
|
1721
|
+
|| error === "驗證碼已寄出,請稍候"
|
|
1722
|
+
|| error === "確認コードは送信済みです。しばらくお待ちください";
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1313
1725
|
async function proveAccountMergeWithWallet(mergeChallenge) {
|
|
1314
1726
|
var tokenData;
|
|
1315
1727
|
try {
|
|
1316
|
-
tokenData = await api("GET", "/../did/merge-proof/token");
|
|
1728
|
+
tokenData = await api("GET", "/../did/merge-proof/token", undefined, { silent: true });
|
|
1317
1729
|
} catch (e) {
|
|
1318
|
-
|
|
1319
|
-
return null;
|
|
1730
|
+
return { ok: false, error: __t("profile.mergeFailed") };
|
|
1320
1731
|
}
|
|
1321
1732
|
if (!tokenData || !tokenData.token) {
|
|
1322
|
-
|
|
1323
|
-
return null;
|
|
1733
|
+
return { ok: false, error: (tokenData && tokenData.error) || __t("profile.mergeFailed") };
|
|
1324
1734
|
}
|
|
1325
1735
|
|
|
1326
1736
|
var token = tokenData.token;
|
|
@@ -1396,17 +1806,16 @@ async function proveAccountMergeWithWallet(mergeChallenge) {
|
|
|
1396
1806
|
var proved = await api("POST", "/../did/connect/complete", {
|
|
1397
1807
|
token: token,
|
|
1398
1808
|
mergeChallenge: mergeChallenge,
|
|
1399
|
-
});
|
|
1809
|
+
}, { silent: true });
|
|
1400
1810
|
if (!proved || !proved.mergeIntent) {
|
|
1401
|
-
|
|
1402
|
-
polling = false;
|
|
1811
|
+
finish(proved || { ok: false, error: __t("profile.mergeFailed") });
|
|
1403
1812
|
return;
|
|
1404
1813
|
}
|
|
1405
1814
|
finish(proved);
|
|
1406
1815
|
} else if (status.status === "error") {
|
|
1407
1816
|
clearInterval(pollTimer);
|
|
1408
1817
|
pollTimer = null;
|
|
1409
|
-
|
|
1818
|
+
finish({ ok: false, error: status.error || __t("profile.mergeFailed") });
|
|
1410
1819
|
}
|
|
1411
1820
|
} catch (e) { /* ignore poll errors */ }
|
|
1412
1821
|
polling = false;
|
|
@@ -1416,14 +1825,12 @@ async function proveAccountMergeWithWallet(mergeChallenge) {
|
|
|
1416
1825
|
|
|
1417
1826
|
async function proveAccountMergeWithPasskey(mergeChallenge) {
|
|
1418
1827
|
if (typeof PublicKeyCredential === "undefined" || !navigator.credentials || !navigator.credentials.get) {
|
|
1419
|
-
|
|
1420
|
-
return null;
|
|
1828
|
+
return { ok: false, error: __t("profile.mergePasskeyUnavailable") };
|
|
1421
1829
|
}
|
|
1422
|
-
var opts = await api("GET", "/../passkey/auth");
|
|
1830
|
+
var opts = await api("GET", "/../passkey/auth", undefined, { silent: true });
|
|
1423
1831
|
var publicKey = opts.authentication || opts;
|
|
1424
|
-
if (!opts.challengeId || !publicKey || !publicKey.challenge) {
|
|
1425
|
-
|
|
1426
|
-
return null;
|
|
1832
|
+
if (!opts || opts.ok === false || !opts.challengeId || !publicKey || !publicKey.challenge) {
|
|
1833
|
+
return { ok: false, error: (opts && opts.error) || __t("profile.mergeFailed") };
|
|
1427
1834
|
}
|
|
1428
1835
|
publicKey.challenge = base64urlToBuffer(publicKey.challenge);
|
|
1429
1836
|
if (publicKey.allowCredentials) {
|
|
@@ -1436,7 +1843,7 @@ async function proveAccountMergeWithPasskey(mergeChallenge) {
|
|
|
1436
1843
|
credential = await navigator.credentials.get({ publicKey: publicKey });
|
|
1437
1844
|
} catch (e) {
|
|
1438
1845
|
if (!e || e.name !== "NotAllowedError") {
|
|
1439
|
-
|
|
1846
|
+
return { ok: false, error: (e && e.message) || __t("profile.mergeFailed") };
|
|
1440
1847
|
}
|
|
1441
1848
|
return null;
|
|
1442
1849
|
}
|
|
@@ -1456,7 +1863,7 @@ async function proveAccountMergeWithPasskey(mergeChallenge) {
|
|
|
1456
1863
|
},
|
|
1457
1864
|
},
|
|
1458
1865
|
mergeChallenge: mergeChallenge,
|
|
1459
|
-
});
|
|
1866
|
+
}, { silent: true });
|
|
1460
1867
|
}
|
|
1461
1868
|
|
|
1462
1869
|
function proveAccountMergeWithOAuth(provider, mergeChallenge) {
|
|
@@ -1466,15 +1873,23 @@ function proveAccountMergeWithOAuth(provider, mergeChallenge) {
|
|
|
1466
1873
|
return;
|
|
1467
1874
|
}
|
|
1468
1875
|
cleanupAccountMergeOAuth();
|
|
1876
|
+
var mergeResultPrefix = "connect.mergeOAuthResult.";
|
|
1877
|
+
try {
|
|
1878
|
+
var staleKeys = [];
|
|
1879
|
+
for (var s = 0; s < localStorage.length; s++) {
|
|
1880
|
+
var staleKey = localStorage.key(s);
|
|
1881
|
+
if (staleKey && staleKey.indexOf(mergeResultPrefix) === 0) staleKeys.push(staleKey);
|
|
1882
|
+
}
|
|
1883
|
+
for (var t = 0; t < staleKeys.length; t++) localStorage.removeItem(staleKeys[t]);
|
|
1884
|
+
} catch (e0) {}
|
|
1469
1885
|
var returnUrl = encodeURIComponent(window.location.href);
|
|
1470
|
-
var url = window.__BASE_PATH + "/../oauth/" + encodeURIComponent(provider) + "/login?returnUrl=" + returnUrl;
|
|
1886
|
+
var url = window.__BASE_PATH + "/../oauth/" + encodeURIComponent(provider) + "/login?returnUrl=" + returnUrl + "&mergeChallenge=" + encodeURIComponent(mergeChallenge);
|
|
1471
1887
|
var redirectUri = location.origin + "/.well-known/service/oauth/callback/" + encodeURIComponent(provider);
|
|
1472
1888
|
var w = 500, h = 600;
|
|
1473
1889
|
var left = (screen.width - w) / 2, top = (screen.height - h) / 2;
|
|
1474
1890
|
var popup = window.open(url, "oauth_merge", "width=" + w + ",height=" + h + ",left=" + left + ",top=" + top);
|
|
1475
1891
|
if (!popup) {
|
|
1476
|
-
|
|
1477
|
-
resolve(null);
|
|
1892
|
+
resolve({ ok: false, error: __t("common.popupBlocked") });
|
|
1478
1893
|
return;
|
|
1479
1894
|
}
|
|
1480
1895
|
var settled = false;
|
|
@@ -1485,6 +1900,7 @@ function proveAccountMergeWithOAuth(provider, mergeChallenge) {
|
|
|
1485
1900
|
}, 5 * 60 * 1000);
|
|
1486
1901
|
function cleanup() {
|
|
1487
1902
|
window.removeEventListener("message", onMessage);
|
|
1903
|
+
window.removeEventListener("storage", onStorage);
|
|
1488
1904
|
clearTimeout(abandonTimer);
|
|
1489
1905
|
if (__accountMergeOAuthCleanup === cancel) __accountMergeOAuthCleanup = null;
|
|
1490
1906
|
}
|
|
@@ -1494,6 +1910,37 @@ function proveAccountMergeWithOAuth(provider, mergeChallenge) {
|
|
|
1494
1910
|
cleanup();
|
|
1495
1911
|
resolve(value);
|
|
1496
1912
|
}
|
|
1913
|
+
function parseMergeOAuthResult(raw) {
|
|
1914
|
+
if (!raw) return null;
|
|
1915
|
+
try {
|
|
1916
|
+
var parsed = JSON.parse(raw);
|
|
1917
|
+
if (!parsed || typeof parsed !== "object") return { ok: false, error: __t("profile.mergeFailed") };
|
|
1918
|
+
return parsed;
|
|
1919
|
+
} catch (e1) {
|
|
1920
|
+
return { ok: false, error: __t("profile.mergeFailed") };
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
function readMergeOAuthResultOnce() {
|
|
1924
|
+
try {
|
|
1925
|
+
for (var i = 0; i < localStorage.length; i++) {
|
|
1926
|
+
var key = localStorage.key(i);
|
|
1927
|
+
if (!key || key.indexOf(mergeResultPrefix) !== 0) continue;
|
|
1928
|
+
var raw = localStorage.getItem(key);
|
|
1929
|
+
try { localStorage.removeItem(key); } catch (e2) {}
|
|
1930
|
+
return parseMergeOAuthResult(raw);
|
|
1931
|
+
}
|
|
1932
|
+
} catch (e3) {}
|
|
1933
|
+
return null;
|
|
1934
|
+
}
|
|
1935
|
+
function onStorage(event) {
|
|
1936
|
+
if (settled || !event || !event.key || event.key.indexOf(mergeResultPrefix) !== 0) return;
|
|
1937
|
+
var raw = event.newValue;
|
|
1938
|
+
try { localStorage.removeItem(event.key); } catch (e4) {}
|
|
1939
|
+
var payload = parseMergeOAuthResult(raw);
|
|
1940
|
+
if (!payload) return;
|
|
1941
|
+
try { popup.close(); } catch (e5) {}
|
|
1942
|
+
finish(payload);
|
|
1943
|
+
}
|
|
1497
1944
|
async function onMessage(event) {
|
|
1498
1945
|
if (event.origin !== location.origin) return;
|
|
1499
1946
|
if (!event.data || event.data.type !== "authorization_response") return;
|
|
@@ -1511,23 +1958,28 @@ function proveAccountMergeWithOAuth(provider, mergeChallenge) {
|
|
|
1511
1958
|
code: resp.code,
|
|
1512
1959
|
redirectUri: redirectUri,
|
|
1513
1960
|
mergeChallenge: mergeChallenge,
|
|
1514
|
-
});
|
|
1961
|
+
}, { silent: true });
|
|
1515
1962
|
finish(proved);
|
|
1516
1963
|
} catch (e) {
|
|
1517
|
-
|
|
1518
|
-
finish(null);
|
|
1964
|
+
finish({ ok: false, error: (e && e.message) || __t("profile.mergeFailed") });
|
|
1519
1965
|
}
|
|
1520
1966
|
}
|
|
1521
1967
|
window.addEventListener("message", onMessage);
|
|
1968
|
+
window.addEventListener("storage", onStorage);
|
|
1522
1969
|
function cancel() {
|
|
1523
1970
|
try { popup.close(); } catch (e) {}
|
|
1524
1971
|
finish(null);
|
|
1525
1972
|
}
|
|
1526
1973
|
__accountMergeOAuthCleanup = cancel;
|
|
1974
|
+
var existing = readMergeOAuthResultOnce();
|
|
1975
|
+
if (existing) {
|
|
1976
|
+
try { popup.close(); } catch (e6) {}
|
|
1977
|
+
finish(existing);
|
|
1978
|
+
}
|
|
1527
1979
|
});
|
|
1528
1980
|
}
|
|
1529
1981
|
|
|
1530
|
-
async function proveAccountMergeWithEmail(mergeChallenge) {
|
|
1982
|
+
async function proveAccountMergeWithEmail(mergeChallenge, prefillEmail) {
|
|
1531
1983
|
return new Promise(function(resolve) {
|
|
1532
1984
|
var d = document.getElementById("email-merge-dialog");
|
|
1533
1985
|
if (!d) {
|
|
@@ -1544,6 +1996,7 @@ async function proveAccountMergeWithEmail(mergeChallenge) {
|
|
|
1544
1996
|
+ '</div></div>'
|
|
1545
1997
|
+ '<div class="dialog-actions">'
|
|
1546
1998
|
+ '<button type="button" class="btn btn-secondary" id="email-merge-cancel">' + __t("common.cancel") + '</button>'
|
|
1999
|
+
+ '<button type="button" class="btn btn-secondary" id="email-merge-switch">' + __t("profile.mergeEmailSwitchMethod") + '</button>'
|
|
1547
2000
|
+ '<button type="button" class="btn btn-secondary" id="email-merge-send">' + __t("profile.mergeEmailSendCode") + '</button>'
|
|
1548
2001
|
+ '<button type="button" class="btn" id="email-merge-ok" disabled>' + __t("common.confirm") + '</button>'
|
|
1549
2002
|
+ '</div>';
|
|
@@ -1555,31 +2008,86 @@ async function proveAccountMergeWithEmail(mergeChallenge) {
|
|
|
1555
2008
|
var okBtn = document.getElementById("email-merge-ok");
|
|
1556
2009
|
var verifyId = null;
|
|
1557
2010
|
var settled = false;
|
|
2011
|
+
var activeChallenge = mergeChallenge;
|
|
2012
|
+
var sentAt = 0;
|
|
2013
|
+
var cooldownTimer = null;
|
|
2014
|
+
var lastError = "";
|
|
1558
2015
|
function finish(value) {
|
|
1559
2016
|
if (settled) return;
|
|
1560
2017
|
settled = true;
|
|
2018
|
+
if (cooldownTimer) clearInterval(cooldownTimer);
|
|
2019
|
+
cooldownTimer = null;
|
|
1561
2020
|
if (d.open) d.close();
|
|
1562
2021
|
resolve(value);
|
|
1563
2022
|
}
|
|
2023
|
+
function secondsLeft() {
|
|
2024
|
+
if (!sentAt) return 0;
|
|
2025
|
+
var left = 60000 - (Date.now() - sentAt);
|
|
2026
|
+
if (left <= 0) return 0;
|
|
2027
|
+
return Math.ceil(left / 1000);
|
|
2028
|
+
}
|
|
2029
|
+
function paintSendButton() {
|
|
2030
|
+
var left = secondsLeft();
|
|
2031
|
+
if (left > 0) {
|
|
2032
|
+
sendBtn.disabled = true;
|
|
2033
|
+
sendBtn.textContent = __t("profile.mergeEmailResendWait", { seconds: String(left) });
|
|
2034
|
+
return;
|
|
2035
|
+
}
|
|
2036
|
+
sendBtn.disabled = false;
|
|
2037
|
+
sendBtn.textContent = sentAt ? __t("profile.mergeEmailResend") : __t("profile.mergeEmailSendCode");
|
|
2038
|
+
}
|
|
2039
|
+
function startCooldown() {
|
|
2040
|
+
if (cooldownTimer) clearInterval(cooldownTimer);
|
|
2041
|
+
paintSendButton();
|
|
2042
|
+
cooldownTimer = setInterval(function() {
|
|
2043
|
+
paintSendButton();
|
|
2044
|
+
if (secondsLeft() <= 0 && cooldownTimer) {
|
|
2045
|
+
clearInterval(cooldownTimer);
|
|
2046
|
+
cooldownTimer = null;
|
|
2047
|
+
}
|
|
2048
|
+
}, 1000);
|
|
2049
|
+
}
|
|
2050
|
+
function markCodeConsumed(message) {
|
|
2051
|
+
codeEl.value = "";
|
|
2052
|
+
codeEl.disabled = true;
|
|
2053
|
+
okBtn.disabled = true;
|
|
2054
|
+
lastError = message || "";
|
|
2055
|
+
statusEl.textContent = lastError
|
|
2056
|
+
? lastError + " " + __t("profile.mergeEmailRequestNewCode")
|
|
2057
|
+
: __t("profile.mergeEmailRequestNewCode");
|
|
2058
|
+
if (secondsLeft() > 0) startCooldown();
|
|
2059
|
+
else paintSendButton();
|
|
2060
|
+
}
|
|
1564
2061
|
document.getElementById("email-merge-cancel").onclick = function() { finish(null); };
|
|
2062
|
+
document.getElementById("email-merge-switch").onclick = function() {
|
|
2063
|
+
finish({ switchMethod: true, error: lastError, challenge: activeChallenge });
|
|
2064
|
+
};
|
|
1565
2065
|
d.onclose = function() { finish(null); };
|
|
1566
2066
|
sendBtn.onclick = async function() {
|
|
1567
2067
|
var email = (emailEl.value || "").trim();
|
|
1568
2068
|
if (!email || email.indexOf("@") === -1) return;
|
|
1569
2069
|
sendBtn.disabled = true;
|
|
1570
2070
|
statusEl.textContent = __t("profile.emailSending");
|
|
1571
|
-
var sent = await api("POST", "/../email/sendCode", { email: email });
|
|
2071
|
+
var sent = await api("POST", "/../email/sendCode", { email: email }, { silent: true });
|
|
1572
2072
|
if (!sent || sent.id == null) {
|
|
1573
|
-
|
|
1574
|
-
|
|
2073
|
+
var sendError = (sent && sent.error) || __t("profile.emailSendFailed");
|
|
2074
|
+
statusEl.textContent = sendError;
|
|
2075
|
+
if (emailCodeAlreadySent(sendError)) {
|
|
2076
|
+
if (!sentAt) sentAt = Date.now();
|
|
2077
|
+
startCooldown();
|
|
2078
|
+
} else {
|
|
2079
|
+
sendBtn.disabled = false;
|
|
2080
|
+
}
|
|
1575
2081
|
return;
|
|
1576
2082
|
}
|
|
1577
2083
|
verifyId = sent.id;
|
|
2084
|
+
sentAt = Date.now();
|
|
2085
|
+
codeEl.value = "";
|
|
1578
2086
|
codeEl.disabled = false;
|
|
1579
2087
|
okBtn.disabled = false;
|
|
1580
2088
|
codeEl.focus();
|
|
1581
2089
|
statusEl.textContent = __t("profile.emailCodeSent");
|
|
1582
|
-
|
|
2090
|
+
startCooldown();
|
|
1583
2091
|
};
|
|
1584
2092
|
okBtn.onclick = async function() {
|
|
1585
2093
|
var code = (codeEl.value || "").trim();
|
|
@@ -1588,39 +2096,58 @@ async function proveAccountMergeWithEmail(mergeChallenge) {
|
|
|
1588
2096
|
var proved = await api("POST", "/../email/login", {
|
|
1589
2097
|
code: code,
|
|
1590
2098
|
id: verifyId,
|
|
1591
|
-
mergeChallenge:
|
|
1592
|
-
});
|
|
1593
|
-
if (
|
|
1594
|
-
|
|
1595
|
-
okBtn.disabled = false;
|
|
2099
|
+
mergeChallenge: activeChallenge,
|
|
2100
|
+
}, { silent: true });
|
|
2101
|
+
if (proved && proved.mergeIntent) {
|
|
2102
|
+
finish(proved);
|
|
1596
2103
|
return;
|
|
1597
2104
|
}
|
|
1598
|
-
|
|
2105
|
+
var err = (proved && proved.error) || __t("profile.mergeFailed");
|
|
2106
|
+
if (mergeChallengeLooksExpired(err)) {
|
|
2107
|
+
var restarted = await api("POST", "/../account/merge/start", {}, { silent: true });
|
|
2108
|
+
if (restarted && restarted.challenge) activeChallenge = restarted.challenge;
|
|
2109
|
+
}
|
|
2110
|
+
markCodeConsumed(err);
|
|
1599
2111
|
};
|
|
2112
|
+
if (typeof prefillEmail === "string" && prefillEmail) emailEl.value = prefillEmail;
|
|
1600
2113
|
d.showModal();
|
|
1601
2114
|
emailEl.focus();
|
|
1602
2115
|
});
|
|
1603
2116
|
}
|
|
1604
2117
|
|
|
1605
|
-
async function finalizeAccountMerge(proved) {
|
|
2118
|
+
async function finalizeAccountMerge(proved, candidate) {
|
|
1606
2119
|
if (!proved || !proved.mergeIntent) {
|
|
1607
2120
|
showToast((proved && proved.error) || __t("profile.mergeFailed"), "error");
|
|
1608
2121
|
return false;
|
|
1609
2122
|
}
|
|
1610
2123
|
var plan = await api("POST", "/../account/merge/dry-run", { mergeIntent: proved.mergeIntent });
|
|
1611
|
-
|
|
1612
|
-
|
|
2124
|
+
if (!plan || plan.ok === false || !plan.accounts) return false;
|
|
2125
|
+
// Server omits keep → session. The first paint must match recommendedKeep.
|
|
2126
|
+
if ((plan.recommendedKeep === "session" || plan.recommendedKeep === "proved") && plan.keep !== plan.recommendedKeep) {
|
|
2127
|
+
var next = plan.recommendedKeep;
|
|
2128
|
+
var aligned = await api("POST", "/../account/merge/dry-run", { mergeIntent: proved.mergeIntent, keep: next }, { silent: true });
|
|
2129
|
+
if (aligned && aligned.ok !== false && aligned.accounts) plan = aligned;
|
|
2130
|
+
else showToast((aligned && aligned.error) || __t("profile.mergeFailed"), "error");
|
|
2131
|
+
}
|
|
2132
|
+
var candidateEmail = candidate && typeof candidate.email === "string" ? candidate.email : "";
|
|
2133
|
+
plan.__hasCandidate = !!(candidate && typeof candidate === "object");
|
|
2134
|
+
var confirmed = await confirmMergePlan(plan, proved.mergeIntent, candidateEmail);
|
|
2135
|
+
if (!confirmed) {
|
|
1613
2136
|
showToast(__t("profile.mergeCancelled"), "error");
|
|
1614
2137
|
return false;
|
|
1615
2138
|
}
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
2139
|
+
return true;
|
|
2140
|
+
}
|
|
2141
|
+
|
|
2142
|
+
function mergeCandidateWhenLabel(iso) {
|
|
2143
|
+
var lang = (document.documentElement && document.documentElement.lang) || "en";
|
|
2144
|
+
return formatMergeCandidateWhen(iso, Date.now(), lang, __t);
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2147
|
+
function mergePromptIcon(provider) {
|
|
2148
|
+
if (provider && __providerIcons[provider]) return getProviderIconSvg(provider);
|
|
2149
|
+
var ch = provider ? provider.charAt(0).toUpperCase() : "?";
|
|
2150
|
+
return '<span class="ca-merge-prompt-fallback">' + escapeHtml(ch) + '</span>';
|
|
1624
2151
|
}
|
|
1625
2152
|
|
|
1626
2153
|
function hideMergePrompt() {
|
|
@@ -1631,10 +2158,48 @@ function hideMergePrompt() {
|
|
|
1631
2158
|
el.innerHTML = "";
|
|
1632
2159
|
}
|
|
1633
2160
|
|
|
1634
|
-
function
|
|
2161
|
+
function paintMergePrompt(rows, hiddenProviders) {
|
|
2162
|
+
var el = document.getElementById("merge-candidate-prompt");
|
|
2163
|
+
if (!el) return;
|
|
2164
|
+
if (!rows || !rows.length) {
|
|
2165
|
+
hideMergePrompt();
|
|
2166
|
+
return;
|
|
2167
|
+
}
|
|
2168
|
+
el.innerHTML = renderMergePromptHtml(rows[0].email || "", rows, __t, escapeHtml, mergePromptIcon, getProviderLabel, mergeCandidateWhenLabel, hiddenProviders || __hiddenProviders);
|
|
2169
|
+
el.hidden = false;
|
|
2170
|
+
el.style.display = "";
|
|
2171
|
+
}
|
|
2172
|
+
|
|
2173
|
+
function startMergeCandidate(btn) {
|
|
2174
|
+
var ref = btn && btn.getAttribute ? btn.getAttribute("data-merge-ref") : "";
|
|
2175
|
+
var list = __mergePromptCandidates || [];
|
|
2176
|
+
for (var i = 0; i < list.length; i++) {
|
|
2177
|
+
if (list[i].ref === ref) {
|
|
2178
|
+
startAccountMerge(list[i]);
|
|
2179
|
+
return;
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
|
|
2184
|
+
function hideMergeCandidate(btn) {
|
|
2185
|
+
var ref = btn && btn.getAttribute ? btn.getAttribute("data-merge-ref") : "";
|
|
2186
|
+
var did = __mergePromptDid || "";
|
|
2187
|
+
if (did && ref) {
|
|
2188
|
+
try { localStorage["connect.mergePrompt.notMine." + did + "." + ref] = "1"; } catch (e) {}
|
|
2189
|
+
}
|
|
2190
|
+
var next = [];
|
|
2191
|
+
var list = __mergePromptCandidates || [];
|
|
2192
|
+
for (var i = 0; i < list.length; i++) {
|
|
2193
|
+
if (list[i].ref !== ref) next.push(list[i]);
|
|
2194
|
+
}
|
|
2195
|
+
__mergePromptCandidates = next;
|
|
2196
|
+
paintMergePrompt(next, __hiddenProviders);
|
|
2197
|
+
}
|
|
2198
|
+
|
|
2199
|
+
function dismissMergePromptLater() {
|
|
1635
2200
|
var did = __mergePromptDid || "";
|
|
1636
2201
|
if (did) {
|
|
1637
|
-
try {
|
|
2202
|
+
try { sessionStorage["connect.mergePrompt.later." + did] = "1"; } catch (e) {}
|
|
1638
2203
|
}
|
|
1639
2204
|
hideMergePrompt();
|
|
1640
2205
|
}
|
|
@@ -1642,74 +2207,117 @@ function dismissMergePrompt() {
|
|
|
1642
2207
|
async function maybeShowMergePrompt(did) {
|
|
1643
2208
|
hideMergePrompt();
|
|
1644
2209
|
__mergePromptDid = did || "";
|
|
2210
|
+
__mergePromptCandidates = [];
|
|
1645
2211
|
if (!did) return;
|
|
1646
2212
|
try {
|
|
1647
|
-
if (
|
|
2213
|
+
if (sessionStorage["connect.mergePrompt.later." + did] === "1") return;
|
|
1648
2214
|
} catch (e) {}
|
|
1649
2215
|
var data = await api("GET", "/../account/merge/candidate", undefined, { silent: true });
|
|
1650
|
-
if (!data || data.mergeCandidate !== true) return;
|
|
2216
|
+
if (!data || data.mergeCandidate !== true || !data.candidates || !data.candidates.length) return;
|
|
1651
2217
|
try {
|
|
1652
|
-
if (
|
|
1653
|
-
} catch (
|
|
2218
|
+
if (sessionStorage["connect.mergePrompt.later." + did] === "1") return;
|
|
2219
|
+
} catch (e2) {}
|
|
2220
|
+
var email = typeof data.email === "string" ? data.email : "";
|
|
2221
|
+
if (!email) return;
|
|
2222
|
+
var visible = [];
|
|
2223
|
+
for (var i = 0; i < data.candidates.length && visible.length < 5; i++) {
|
|
2224
|
+
var c = data.candidates[i];
|
|
2225
|
+
if (!c || typeof c.ref !== "string" || !c.ref) continue;
|
|
2226
|
+
try {
|
|
2227
|
+
if (localStorage["connect.mergePrompt.notMine." + did + "." + c.ref] === "1") continue;
|
|
2228
|
+
} catch (e3) {}
|
|
2229
|
+
visible.push({
|
|
2230
|
+
ref: c.ref,
|
|
2231
|
+
methods: Array.isArray(c.methods) ? c.methods : [],
|
|
2232
|
+
emailLogin: c.emailLogin === true,
|
|
2233
|
+
email: email,
|
|
2234
|
+
createdAt: typeof c.createdAt === "string" ? c.createdAt : "",
|
|
2235
|
+
lastLoginAt: typeof c.lastLoginAt === "string" ? c.lastLoginAt : "",
|
|
2236
|
+
});
|
|
2237
|
+
}
|
|
2238
|
+
if (!visible.length) return;
|
|
1654
2239
|
var el = document.getElementById("merge-candidate-prompt");
|
|
1655
2240
|
if (!el) return;
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
+ '<div class="ca-merge-prompt-actions">'
|
|
1659
|
-
+ '<button type="button" class="btn" id="merge-candidate-prompt-action" onclick="startAccountMerge()">' + escapeHtml(__t("profile.mergePromptAction")) + '</button>'
|
|
1660
|
-
+ '<button type="button" class="btn btn-secondary" id="merge-candidate-prompt-dismiss" onclick="dismissMergePrompt()">' + escapeHtml(__t("profile.mergePromptDismiss")) + '</button>'
|
|
1661
|
-
+ '</div>';
|
|
1662
|
-
el.hidden = false;
|
|
1663
|
-
el.style.display = "";
|
|
2241
|
+
__mergePromptCandidates = visible;
|
|
2242
|
+
paintMergePrompt(visible, __hiddenProviders);
|
|
1664
2243
|
}
|
|
1665
2244
|
|
|
1666
|
-
async function startAccountMerge() {
|
|
2245
|
+
async function startAccountMerge(candidate) {
|
|
1667
2246
|
cleanupAccountMergeOAuth();
|
|
1668
|
-
var
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
} catch (e) {
|
|
1672
|
-
showToast((e && e.message) || __t("profile.mergeFailed"), "error");
|
|
1673
|
-
return;
|
|
2247
|
+
var guided = null;
|
|
2248
|
+
if (candidate && typeof candidate.ref === "string" && candidate.ref) {
|
|
2249
|
+
guided = partitionMergeMethods(candidate, listMergeMethods(), __hiddenProviders);
|
|
1674
2250
|
}
|
|
1675
|
-
if (!start || !start.challenge) {
|
|
1676
|
-
showToast(__t("profile.mergeFailed"), "error");
|
|
1677
|
-
return;
|
|
1678
|
-
}
|
|
1679
|
-
|
|
1680
2251
|
var d = document.getElementById("account-merge-method-dialog");
|
|
1681
2252
|
if (!d) {
|
|
1682
2253
|
d = document.createElement("dialog");
|
|
1683
2254
|
d.id = "account-merge-method-dialog";
|
|
1684
2255
|
document.body.appendChild(d);
|
|
1685
2256
|
}
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
2257
|
+
var challenge = null;
|
|
2258
|
+
function paint(errorText) {
|
|
2259
|
+
d.innerHTML = renderMergeMethodPickerHtml(guided ? [] : listMergeMethods(), __t, escapeHtml, getProviderIconSvg, getProviderLabel, errorText || "", guided);
|
|
2260
|
+
var cancel = document.getElementById("account-merge-method-cancel");
|
|
2261
|
+
if (cancel) cancel.onclick = function() { d.close(); };
|
|
2262
|
+
var buttons = d.querySelectorAll("[data-merge-method]");
|
|
2263
|
+
for (var b = 0; b < buttons.length; b++) {
|
|
2264
|
+
buttons[b].onclick = onPick;
|
|
2265
|
+
}
|
|
2266
|
+
}
|
|
2267
|
+
paint("");
|
|
2268
|
+
d.showModal();
|
|
2269
|
+
|
|
2270
|
+
async function ensureChallenge(force) {
|
|
2271
|
+
if (challenge && !force) return challenge;
|
|
2272
|
+
var start = await api("POST", "/../account/merge/start", {}, { silent: true });
|
|
2273
|
+
if (!start || !start.challenge) {
|
|
2274
|
+
paint((start && start.error) || __t("profile.mergeFailed"));
|
|
2275
|
+
return null;
|
|
2276
|
+
}
|
|
2277
|
+
challenge = start.challenge;
|
|
2278
|
+
return challenge;
|
|
2279
|
+
}
|
|
2280
|
+
|
|
2281
|
+
async function onPick(event) {
|
|
2282
|
+
var button = event.currentTarget;
|
|
2283
|
+
var method = button.getAttribute("data-merge-method");
|
|
2284
|
+
var selectedProvider = button.getAttribute("data-merge-provider");
|
|
2285
|
+
paint("");
|
|
2286
|
+
var active = await ensureChallenge(false);
|
|
2287
|
+
if (!active) return;
|
|
2288
|
+
try {
|
|
2289
|
+
var proved = null;
|
|
2290
|
+
if (method === "wallet") proved = await proveAccountMergeWithWallet(active);
|
|
2291
|
+
else if (method === "passkey") proved = await proveAccountMergeWithPasskey(active);
|
|
2292
|
+
else if (method === "oauth") proved = await proveAccountMergeWithOAuth(selectedProvider, active);
|
|
2293
|
+
else if (method === "email") proved = await proveAccountMergeWithEmail(active, button.getAttribute("data-merge-email") || "");
|
|
2294
|
+
if (proved && proved.switchMethod) {
|
|
2295
|
+
if (typeof proved.challenge === "string" && proved.challenge) challenge = proved.challenge;
|
|
2296
|
+
paint(proved.error || "");
|
|
2297
|
+
return;
|
|
2298
|
+
}
|
|
2299
|
+
if (proved && proved.mergeIntent) {
|
|
2300
|
+
if (d.open) d.close();
|
|
2301
|
+
await finalizeAccountMerge(proved, candidate);
|
|
2302
|
+
return;
|
|
2303
|
+
}
|
|
2304
|
+
if (proved && proved.error) {
|
|
2305
|
+
if (mergeChallengeLooksExpired(proved.error)) {
|
|
2306
|
+
challenge = null;
|
|
2307
|
+
await ensureChallenge(true);
|
|
1705
2308
|
}
|
|
2309
|
+
paint(proved.error);
|
|
2310
|
+
return;
|
|
1706
2311
|
}
|
|
1707
|
-
}
|
|
2312
|
+
} catch (e) {
|
|
2313
|
+
if (!e || e.name !== "NotAllowedError") {
|
|
2314
|
+
paint((e && e.message) || __t("profile.mergeFailed"));
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
1708
2317
|
}
|
|
1709
|
-
d.showModal();
|
|
1710
2318
|
}
|
|
1711
2319
|
|
|
1712
|
-
function confirmMergePlan(plan) {
|
|
2320
|
+
function confirmMergePlan(plan, mergeIntent, candidateEmail) {
|
|
1713
2321
|
return new Promise(function(resolve) {
|
|
1714
2322
|
var d = document.getElementById("merge-confirm-dialog");
|
|
1715
2323
|
if (!d) {
|
|
@@ -1718,32 +2326,193 @@ function confirmMergePlan(plan) {
|
|
|
1718
2326
|
d.className = "merge-confirm-dialog";
|
|
1719
2327
|
document.body.appendChild(d);
|
|
1720
2328
|
}
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
2329
|
+
var current = plan || {};
|
|
2330
|
+
var selectedKeep = current.keep === "proved" || current.keep === "session" ? current.keep : "session";
|
|
2331
|
+
// accounts.session.did stays the signed-in DID. intoDid follows keep.
|
|
2332
|
+
var sessionAccount = current.accounts && current.accounts.session;
|
|
2333
|
+
var sessionDid = sessionAccount && typeof sessionAccount.did === "string" ? sessionAccount.did : "";
|
|
2334
|
+
var hasCandidate = current.__hasCandidate === true;
|
|
2335
|
+
var loading = false;
|
|
2336
|
+
var generation = 0;
|
|
2337
|
+
var phase = "preview";
|
|
2338
|
+
var settled = false;
|
|
2339
|
+
var resultPayload = null;
|
|
1729
2340
|
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
2341
|
+
function keptDid() {
|
|
2342
|
+
var side = selectedKeep === "proved" ? current.accounts && current.accounts.proved : current.accounts && current.accounts.session;
|
|
2343
|
+
if (side && typeof side.did === "string" && side.did) return side.did;
|
|
2344
|
+
return typeof current.intoDid === "string" ? current.intoDid : "";
|
|
2345
|
+
}
|
|
2346
|
+
|
|
2347
|
+
function submitLabel() {
|
|
2348
|
+
if (selectedKeep === "session") return __t("profile.mergeConfirmSubmitKeep");
|
|
2349
|
+
return __t("profile.mergeConfirmSubmitSwitch", { did: truncateDid(keptDid()) });
|
|
2350
|
+
}
|
|
2351
|
+
|
|
2352
|
+
function paint() {
|
|
2353
|
+
d.innerHTML = '<div class="dialog-content">'
|
|
2354
|
+
+ '<h3 id="merge-confirm-title">' + escapeHtml(__t("profile.mergeConfirmTitle")) + '</h3>'
|
|
2355
|
+
+ renderMergeConfirmBodyHtml(current, __t, escapeHtml, getProviderLabel, {
|
|
2356
|
+
selectedKeep: selectedKeep,
|
|
2357
|
+
hasCandidate: hasCandidate,
|
|
2358
|
+
candidateEmail: candidateEmail || "",
|
|
2359
|
+
shortDid: truncateDid,
|
|
2360
|
+
loading: loading
|
|
2361
|
+
})
|
|
2362
|
+
+ '</div>'
|
|
2363
|
+
+ '<div class="dialog-actions">'
|
|
2364
|
+
+ '<button type="button" class="btn btn-secondary" id="merge-confirm-cancel">' + escapeHtml(__t("common.cancel")) + '</button>'
|
|
2365
|
+
+ '<button type="button" class="btn btn-danger" id="merge-confirm-ok">' + escapeHtml(submitLabel()) + '</button>'
|
|
2366
|
+
+ '</div>';
|
|
2367
|
+
var okBtn = document.getElementById("merge-confirm-ok");
|
|
2368
|
+
var cancelBtn = document.getElementById("merge-confirm-cancel");
|
|
2369
|
+
if (loading || current.tooLarge || phase !== "preview") okBtn.disabled = true;
|
|
2370
|
+
cancelBtn.onclick = function() { finish(false); };
|
|
2371
|
+
okBtn.onclick = onOk;
|
|
2372
|
+
var radios = d.querySelectorAll('input[name="merge-keep"]');
|
|
2373
|
+
for (var i = 0; i < radios.length; i++) radios[i].onchange = onKeepChange;
|
|
2374
|
+
var copies = d.querySelectorAll("[data-copy-did]");
|
|
2375
|
+
for (var c = 0; c < copies.length; c++) copies[c].onclick = onCopy;
|
|
2376
|
+
}
|
|
2377
|
+
|
|
2378
|
+
function onCopy(event) {
|
|
2379
|
+
if (event) {
|
|
2380
|
+
if (event.preventDefault) event.preventDefault();
|
|
2381
|
+
if (event.stopPropagation) event.stopPropagation();
|
|
2382
|
+
}
|
|
2383
|
+
var btn = event && event.currentTarget;
|
|
2384
|
+
var full = btn && btn.getAttribute ? btn.getAttribute("data-copy-did") : "";
|
|
2385
|
+
if (full) copyToClipboard(full);
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2388
|
+
function onKeepChange(event) {
|
|
2389
|
+
if (phase !== "preview") return;
|
|
2390
|
+
var input = event && event.currentTarget;
|
|
2391
|
+
var next = input && input.value;
|
|
2392
|
+
if (next !== "session" && next !== "proved") return;
|
|
2393
|
+
if (next === selectedKeep) return;
|
|
2394
|
+
selectedKeep = next;
|
|
2395
|
+
loading = true;
|
|
2396
|
+
var token = ++generation;
|
|
2397
|
+
var okBtn = document.getElementById("merge-confirm-ok");
|
|
2398
|
+
if (okBtn) okBtn.disabled = true;
|
|
2399
|
+
setTimeout(function() {
|
|
2400
|
+
if (token !== generation || !loading || phase !== "preview") return;
|
|
2401
|
+
paint();
|
|
2402
|
+
}, 0);
|
|
2403
|
+
refreshKeep(next, token);
|
|
2404
|
+
}
|
|
2405
|
+
|
|
2406
|
+
async function refreshKeep(next, token) {
|
|
2407
|
+
var refreshed = await api("POST", "/../account/merge/dry-run", { mergeIntent: mergeIntent, keep: next }, { silent: true });
|
|
2408
|
+
if (token !== generation) return;
|
|
2409
|
+
loading = false;
|
|
2410
|
+
if (!refreshed || refreshed.ok === false || !refreshed.accounts) {
|
|
2411
|
+
showToast((refreshed && refreshed.error) || __t("profile.mergeFailed"), "error");
|
|
2412
|
+
selectedKeep = current.keep === "proved" || current.keep === "session" ? current.keep : "session";
|
|
2413
|
+
paint();
|
|
2414
|
+
return;
|
|
2415
|
+
}
|
|
2416
|
+
current = refreshed;
|
|
2417
|
+
selectedKeep = current.keep === "proved" || current.keep === "session" ? current.keep : next;
|
|
2418
|
+
paint();
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
async function onOk() {
|
|
2422
|
+
if (phase !== "preview" || loading || current.tooLarge) return;
|
|
2423
|
+
var okBtn = document.getElementById("merge-confirm-ok");
|
|
2424
|
+
if (!okBtn || okBtn.disabled) return;
|
|
2425
|
+
okBtn.disabled = true;
|
|
2426
|
+
phase = "committing";
|
|
2427
|
+
generation += 1;
|
|
2428
|
+
var committed = await api("POST", "/../account/merge/commit", { mergeIntent: mergeIntent, keep: selectedKeep });
|
|
2429
|
+
if (settled) return;
|
|
2430
|
+
if (!committed || committed.ok === false || !committed.survivorDid) {
|
|
2431
|
+
phase = "preview";
|
|
2432
|
+
if (!d.open) {
|
|
2433
|
+
try { d.showModal(); } catch (err) {}
|
|
2434
|
+
}
|
|
2435
|
+
paint();
|
|
2436
|
+
return;
|
|
2437
|
+
}
|
|
2438
|
+
phase = "done";
|
|
2439
|
+
resultPayload = committed;
|
|
2440
|
+
showDone(committed);
|
|
2441
|
+
}
|
|
2442
|
+
|
|
2443
|
+
function showDone(committed) {
|
|
2444
|
+
var survivorDid = committed && typeof committed.survivorDid === "string" ? committed.survivorDid : "";
|
|
2445
|
+
d.innerHTML = '<div class="dialog-content">'
|
|
2446
|
+
+ '<h3 id="merge-confirm-title">' + escapeHtml(__t("profile.mergeDoneTitle")) + '</h3>'
|
|
2447
|
+
+ renderMergeDoneBodyHtml({
|
|
2448
|
+
survivorDid: survivorDid,
|
|
2449
|
+
survivorMethods: current.survivorMethods
|
|
2450
|
+
}, __t, escapeHtml, getProviderLabel, truncateDid)
|
|
2451
|
+
+ '</div>'
|
|
2452
|
+
+ '<div class="dialog-actions">'
|
|
2453
|
+
+ '<button type="button" class="btn" id="merge-confirm-finish">' + escapeHtml(__t("profile.mergeDoneFinish")) + '</button>'
|
|
2454
|
+
+ '</div>';
|
|
2455
|
+
var finishBtn = document.getElementById("merge-confirm-finish");
|
|
2456
|
+
finishBtn.onclick = function() { finishDone(survivorDid); };
|
|
2457
|
+
if (!d.open) {
|
|
2458
|
+
try { d.showModal(); } catch (err) {}
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
|
|
2462
|
+
function finishDone(survivorDid) {
|
|
2463
|
+
if (settled) return;
|
|
2464
|
+
settled = true;
|
|
2465
|
+
d.oncancel = null;
|
|
2466
|
+
d.onclose = null;
|
|
2467
|
+
if (d.open) d.close();
|
|
2468
|
+
if (survivorDid && sessionDid && survivorDid !== sessionDid) location.reload();
|
|
2469
|
+
else loadConnectedAccounts();
|
|
2470
|
+
resolve(true);
|
|
2471
|
+
}
|
|
1733
2472
|
|
|
1734
|
-
var settled = false;
|
|
1735
2473
|
function finish(result) {
|
|
1736
2474
|
if (settled) return;
|
|
2475
|
+
if (phase === "done") {
|
|
2476
|
+
finishDone(resultPayload && resultPayload.survivorDid ? resultPayload.survivorDid : "");
|
|
2477
|
+
return;
|
|
2478
|
+
}
|
|
2479
|
+
if (phase === "committing") {
|
|
2480
|
+
if (!d.open) {
|
|
2481
|
+
try { d.showModal(); } catch (err) {}
|
|
2482
|
+
}
|
|
2483
|
+
return;
|
|
2484
|
+
}
|
|
1737
2485
|
settled = true;
|
|
1738
|
-
|
|
1739
|
-
cancelBtn.onclick = null;
|
|
2486
|
+
d.oncancel = null;
|
|
1740
2487
|
d.onclose = null;
|
|
1741
|
-
d.close();
|
|
2488
|
+
if (d.open) d.close();
|
|
1742
2489
|
resolve(result);
|
|
1743
2490
|
}
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
2491
|
+
|
|
2492
|
+
d.oncancel = function(event) {
|
|
2493
|
+
if (event && event.preventDefault) event.preventDefault();
|
|
2494
|
+
if (phase === "committing") return;
|
|
2495
|
+
if (phase === "done") {
|
|
2496
|
+
finishDone(resultPayload && resultPayload.survivorDid ? resultPayload.survivorDid : "");
|
|
2497
|
+
return;
|
|
2498
|
+
}
|
|
2499
|
+
finish(false);
|
|
2500
|
+
};
|
|
2501
|
+
d.onclose = function() {
|
|
2502
|
+
if (settled) return;
|
|
2503
|
+
if (phase === "committing") {
|
|
2504
|
+
if (!d.open) {
|
|
2505
|
+
try { d.showModal(); } catch (err) {}
|
|
2506
|
+
}
|
|
2507
|
+
return;
|
|
2508
|
+
}
|
|
2509
|
+
if (phase === "done") {
|
|
2510
|
+
finishDone(resultPayload && resultPayload.survivorDid ? resultPayload.survivorDid : "");
|
|
2511
|
+
return;
|
|
2512
|
+
}
|
|
2513
|
+
finish(false);
|
|
2514
|
+
};
|
|
2515
|
+
paint();
|
|
1747
2516
|
d.showModal();
|
|
1748
2517
|
});
|
|
1749
2518
|
}
|