mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-02 02:42:28 +00:00
Fix double-click issue in LoginModal and add Generate Keys button
- Prevent race condition where double-clicking "Create Account" could stack multiple views, causing navigation issues on cancel. - Implement "Generate Keys" button in the Create Account view to defer key generation until user action, as requested by the user. - Ensure keys are not generated immediately upon opening the view. - Fix memory leak in LoginModalController destroy method.
This commit is contained in:
1 parent
0e6bc392c6
commit
a27dcd7a1e
1 file changed
+79
-20
@@ -292,6 +292,7 @@ export default class LoginModalController {
|
||||
// Track modal close state to reset generated keys when the modal closes.
|
||||
this.modalCloseObserver = null;
|
||||
this.modalCloseIntervalId = null;
|
||||
this.isSelectionInProgress = false;
|
||||
|
||||
this.initializeRemoteSignerStatus();
|
||||
this.initialized = false;
|
||||
@@ -1696,29 +1697,76 @@ export default class LoginModalController {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Always generate fresh keys for each "Create Account" session.
|
||||
const sk = tools.generateSecretKey();
|
||||
const pk = tools.getPublicKey(sk);
|
||||
const npubGen = tools.nip19?.npubEncode ? tools.nip19.npubEncode(pk) : pk;
|
||||
const nsecGen = tools.nip19?.nsecEncode ? tools.nip19.nsecEncode(sk) : "";
|
||||
const hexSkGen = nsecGen
|
||||
? nsecGen
|
||||
: tools.nip19?.bytesToHex
|
||||
? tools.nip19.bytesToHex(sk)
|
||||
: "";
|
||||
// Do not generate keys immediately. Wait for user action.
|
||||
this.generatedKeypair = null;
|
||||
let npub = "";
|
||||
let nsec = "";
|
||||
let hexSk = "";
|
||||
|
||||
this.generatedKeypair = {
|
||||
npub: npubGen,
|
||||
nsec: nsecGen,
|
||||
hexSk: hexSkGen,
|
||||
pubkey: pk,
|
||||
};
|
||||
// Reset fields
|
||||
if (npubEl) {
|
||||
npubEl.textContent = "";
|
||||
}
|
||||
if (nsecEl instanceof HTMLInputElement) {
|
||||
nsecEl.value = "";
|
||||
}
|
||||
|
||||
const { npub, nsec, hexSk } = this.generatedKeypair;
|
||||
// Insert "Generate" button
|
||||
const generateBtn = this.document.createElement("button");
|
||||
generateBtn.type = "button";
|
||||
generateBtn.className = "btn w-full mb-4";
|
||||
generateBtn.textContent = "Generate New Keys";
|
||||
// Insert before the first key field container, or at top of view?
|
||||
// view structure: h3, p, div(space-y-3)
|
||||
const contentContainer = view.querySelector(".space-y-3");
|
||||
if (contentContainer) {
|
||||
contentContainer.insertBefore(generateBtn, contentContainer.firstChild);
|
||||
}
|
||||
|
||||
// Display keys
|
||||
if (npubEl) npubEl.textContent = npub;
|
||||
if (nsecEl instanceof HTMLInputElement) nsecEl.value = nsec || "Error generating nsec";
|
||||
const keyContainer = contentContainer
|
||||
? contentContainer.querySelector(".space-y-2")
|
||||
: null;
|
||||
if (keyContainer) {
|
||||
keyContainer.classList.add("hidden");
|
||||
}
|
||||
// Also hide the nsec container
|
||||
const nsecContainer = contentContainer
|
||||
? contentContainer.querySelectorAll(".space-y-2")[1]
|
||||
: null;
|
||||
if (nsecContainer) {
|
||||
nsecContainer.classList.add("hidden");
|
||||
}
|
||||
|
||||
generateBtn.addEventListener("click", () => {
|
||||
const sk = tools.generateSecretKey();
|
||||
const pk = tools.getPublicKey(sk);
|
||||
const npubGen = tools.nip19?.npubEncode ? tools.nip19.npubEncode(pk) : pk;
|
||||
const nsecGen = tools.nip19?.nsecEncode ? tools.nip19.nsecEncode(sk) : "";
|
||||
const hexSkGen = nsecGen
|
||||
? nsecGen
|
||||
: tools.nip19?.bytesToHex
|
||||
? tools.nip19.bytesToHex(sk)
|
||||
: "";
|
||||
|
||||
this.generatedKeypair = {
|
||||
npub: npubGen,
|
||||
nsec: nsecGen,
|
||||
hexSk: hexSkGen,
|
||||
pubkey: pk,
|
||||
};
|
||||
|
||||
npub = npubGen;
|
||||
nsec = nsecGen;
|
||||
hexSk = hexSkGen;
|
||||
|
||||
if (npubEl) npubEl.textContent = npub;
|
||||
if (nsecEl instanceof HTMLInputElement) nsecEl.value = nsec;
|
||||
|
||||
generateBtn.classList.add("hidden");
|
||||
if (keyContainer) keyContainer.classList.remove("hidden");
|
||||
if (nsecContainer) nsecContainer.classList.remove("hidden");
|
||||
if (loginBtn) loginBtn.disabled = true; // Still requires checkbox confirmation
|
||||
});
|
||||
|
||||
const elementsToHide = [];
|
||||
for (const child of Array.from(this.modalBody.children)) {
|
||||
@@ -1778,6 +1826,11 @@ export default class LoginModalController {
|
||||
|
||||
if (loginBtn) {
|
||||
loginBtn.addEventListener("click", () => {
|
||||
if (!this.generatedKeypair) {
|
||||
return;
|
||||
}
|
||||
const { npub, nsec, hexSk } = this.generatedKeypair;
|
||||
|
||||
// Block generated accounts if whitelist-only access is enforced.
|
||||
const accessControl = this.services?.authService?.accessControl;
|
||||
if (accessControl && typeof accessControl.canAccess === "function") {
|
||||
@@ -2239,6 +2292,10 @@ export default class LoginModalController {
|
||||
}
|
||||
|
||||
async handleProviderSelection(providerId) {
|
||||
if (this.isSelectionInProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
const entry = this.getProviderEntry(providerId);
|
||||
if (!entry) {
|
||||
devLogger.warn(
|
||||
@@ -2261,6 +2318,7 @@ export default class LoginModalController {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isSelectionInProgress = true;
|
||||
safeInvoke(this.callbacks.onProviderSelected, providerId);
|
||||
|
||||
let providerOptions = {};
|
||||
@@ -2426,6 +2484,7 @@ export default class LoginModalController {
|
||||
message,
|
||||
});
|
||||
} finally {
|
||||
this.isSelectionInProgress = false;
|
||||
this.setLoadingState(providerId, false);
|
||||
if (this.pendingNip46Cleanup) {
|
||||
try {
|
||||
|
||||
Reference in new issue
Block a user