From 12d4810f4c91ee5b0529a65e9816eaaa71cb6cd9 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 15 Sep 2025 14:24:14 -0400 Subject: [PATCH] login with exposed api for web page fixed. --- lite/build.js | 20 +++-- lite/nostr-lite.js | 201 +++++++++++++++++++++++++++++++++++++++++---- lite/ui/modal.js | 179 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 367 insertions(+), 33 deletions(-) diff --git a/lite/build.js b/lite/build.js index f084773..4cac4e3 100644 --- a/lite/build.js +++ b/lite/build.js @@ -1254,13 +1254,13 @@ class WindowNostr { if (event.detail.method === 'extension') { this.authenticatedExtension = event.detail.extension; console.log('WindowNostr: Captured authenticated extension:', this.authenticatedExtension?.constructor?.name); - - // Re-install our facade to ensure we intercept signEvent calls - // Extensions may overwrite window.nostr after authentication - if (typeof window !== 'undefined') { - console.log('WindowNostr: Re-installing facade after authentication'); - window.nostr = this; - } + } + + // CRITICAL FIX: Re-install our facade for ALL authentication methods + // Extensions may overwrite window.nostr after ANY authentication, not just extension auth + if (typeof window !== 'undefined') { + console.log('WindowNostr: Re-installing facade after', this.authState?.method, 'authentication'); + window.nostr = this; } console.log('WindowNostr: Auth state updated:', this.authState?.method); @@ -1270,6 +1270,12 @@ class WindowNostr { this.authState = null; this.authenticatedExtension = null; console.log('WindowNostr: Auth state cleared'); + + // Re-install facade after logout to ensure we maintain control + if (typeof window !== 'undefined') { + console.log('WindowNostr: Re-installing facade after logout'); + window.nostr = this; + } }); } } diff --git a/lite/nostr-lite.js b/lite/nostr-lite.js index 0bcbeb2..578ff5c 100644 --- a/lite/nostr-lite.js +++ b/lite/nostr-lite.js @@ -8,7 +8,7 @@ * Two-file architecture: * 1. Load nostr.bundle.js (official nostr-tools bundle) * 2. Load nostr-lite.js (this file - NOSTR_LOGIN_LITE library with CSS-only themes) - * Generated on: 2025-09-15T17:48:16.817Z + * Generated on: 2025-09-15T18:15:24.222Z */ // Verify dependencies are loaded @@ -1627,15 +1627,176 @@ class Modal { const warningDiv = document.createElement('div'); warningDiv.textContent = '⚠️ Save your secret key securely!'; - warningDiv.style.cssText = 'background: #fef3c7; color: #92400e; padding: 12px; border-radius: 6px; margin-bottom: 16px; font-size: 14px;'; + warningDiv.style.cssText = 'background: #fef3c7; color: #92400e; padding: 12px; border-radius: 6px; margin-bottom: 16px; font-size: 12px;'; - const nsecDiv = document.createElement('div'); - nsecDiv.innerHTML = `Your Secret Key:
${nsec}`; - nsecDiv.style.cssText = 'margin-bottom: 16px; font-size: 14px;'; + // Helper function to create copy button + const createCopyButton = (text, label) => { + const copyBtn = document.createElement('button'); + copyBtn.textContent = `Copy ${label}`; + copyBtn.style.cssText = ` + margin-left: 8px; + padding: 4px 8px; + font-size: 10px; + background: var(--nl-secondary-color); + color: var(--nl-primary-color); + border: 1px solid var(--nl-primary-color); + border-radius: 4px; + cursor: pointer; + font-family: var(--nl-font-family, 'Courier New', monospace); + `; + copyBtn.onclick = async (e) => { + e.preventDefault(); + try { + await navigator.clipboard.writeText(text); + const originalText = copyBtn.textContent; + copyBtn.textContent = '✓ Copied!'; + copyBtn.style.color = '#059669'; + setTimeout(() => { + copyBtn.textContent = originalText; + copyBtn.style.color = 'var(--nl-primary-color)'; + }, 2000); + } catch (err) { + console.error('Failed to copy:', err); + copyBtn.textContent = '✗ Failed'; + copyBtn.style.color = '#dc2626'; + setTimeout(() => { + copyBtn.textContent = originalText; + copyBtn.style.color = 'var(--nl-primary-color)'; + }, 2000); + } + }; + return copyBtn; + }; - const npubDiv = document.createElement('div'); - npubDiv.innerHTML = `Your Public Key:
${window.NostrTools.nip19.npubEncode(pubkey)}`; - npubDiv.style.cssText = 'margin-bottom: 16px; font-size: 14px;'; + // Convert pubkey to hex for verification + const pubkeyHex = typeof pubkey === 'string' ? pubkey : Array.from(pubkey).map(b => b.toString(16).padStart(2, '0')).join(''); + + // Decode nsec to get secret key as hex + let secretKeyHex = ''; + try { + const decoded = window.NostrTools.nip19.decode(nsec); + secretKeyHex = Array.from(decoded.data).map(b => b.toString(16).padStart(2, '0')).join(''); + } catch (err) { + console.error('Failed to decode nsec for hex display:', err); + } + + // Secret Key Section + const nsecSection = document.createElement('div'); + nsecSection.style.cssText = 'margin-bottom: 16px;'; + + const nsecLabel = document.createElement('div'); + nsecLabel.innerHTML = 'Your Secret Key (nsec):'; + nsecLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;'; + + const nsecContainer = document.createElement('div'); + nsecContainer.style.cssText = 'display: flex; align-items: flex-start; margin-bottom: 8px;'; + + const nsecCode = document.createElement('code'); + nsecCode.textContent = nsec; + nsecCode.style.cssText = ` + flex: 1; + word-break: break-all; + background: #f3f4f6; + padding: 6px; + border-radius: 4px; + font-size: 10px; + line-height: 1.3; + font-family: 'Courier New', monospace; + display: block; + `; + + nsecContainer.appendChild(nsecCode); + nsecContainer.appendChild(createCopyButton(nsec, 'nsec')); + nsecSection.appendChild(nsecLabel); + nsecSection.appendChild(nsecContainer); + + // Secret Key Hex Section + if (secretKeyHex) { + const secretHexLabel = document.createElement('div'); + secretHexLabel.innerHTML = 'Secret Key (hex):'; + secretHexLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;'; + + const secretHexContainer = document.createElement('div'); + secretHexContainer.style.cssText = 'display: flex; align-items: flex-start; margin-bottom: 8px;'; + + const secretHexCode = document.createElement('code'); + secretHexCode.textContent = secretKeyHex; + secretHexCode.style.cssText = ` + flex: 1; + word-break: break-all; + background: #f3f4f6; + padding: 6px; + border-radius: 4px; + font-size: 10px; + line-height: 1.3; + font-family: 'Courier New', monospace; + display: block; + `; + + secretHexContainer.appendChild(secretHexCode); + secretHexContainer.appendChild(createCopyButton(secretKeyHex, 'hex')); + nsecSection.appendChild(secretHexLabel); + nsecSection.appendChild(secretHexContainer); + } + + // Public Key Section + const npubSection = document.createElement('div'); + npubSection.style.cssText = 'margin-bottom: 16px;'; + + const npub = window.NostrTools.nip19.npubEncode(pubkey); + + const npubLabel = document.createElement('div'); + npubLabel.innerHTML = 'Your Public Key (npub):'; + npubLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;'; + + const npubContainer = document.createElement('div'); + npubContainer.style.cssText = 'display: flex; align-items: flex-start; margin-bottom: 8px;'; + + const npubCode = document.createElement('code'); + npubCode.textContent = npub; + npubCode.style.cssText = ` + flex: 1; + word-break: break-all; + background: #f3f4f6; + padding: 6px; + border-radius: 4px; + font-size: 10px; + line-height: 1.3; + font-family: 'Courier New', monospace; + display: block; + `; + + npubContainer.appendChild(npubCode); + npubContainer.appendChild(createCopyButton(npub, 'npub')); + npubSection.appendChild(npubLabel); + npubSection.appendChild(npubContainer); + + // Public Key Hex Section + const pubHexLabel = document.createElement('div'); + pubHexLabel.innerHTML = 'Public Key (hex):'; + pubHexLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;'; + + const pubHexContainer = document.createElement('div'); + pubHexContainer.style.cssText = 'display: flex; align-items: flex-start;'; + + const pubHexCode = document.createElement('code'); + pubHexCode.textContent = pubkeyHex; + pubHexCode.style.cssText = ` + flex: 1; + word-break: break-all; + background: #f3f4f6; + padding: 6px; + border-radius: 4px; + font-size: 10px; + line-height: 1.3; + font-family: 'Courier New', monospace; + display: block; + `; + + pubHexContainer.appendChild(pubHexCode); + pubHexContainer.appendChild(createCopyButton(pubkeyHex, 'hex')); + npubSection.appendChild(pubHexLabel); + npubSection.appendChild(pubHexContainer); const continueButton = document.createElement('button'); continueButton.textContent = 'Continue'; @@ -1644,8 +1805,8 @@ class Modal { this.modalBody.appendChild(title); this.modalBody.appendChild(warningDiv); - this.modalBody.appendChild(nsecDiv); - this.modalBody.appendChild(npubDiv); + this.modalBody.appendChild(nsecSection); + this.modalBody.appendChild(npubSection); this.modalBody.appendChild(continueButton); } @@ -2562,13 +2723,13 @@ class WindowNostr { if (event.detail.method === 'extension') { this.authenticatedExtension = event.detail.extension; console.log('WindowNostr: Captured authenticated extension:', this.authenticatedExtension?.constructor?.name); - - // Re-install our facade to ensure we intercept signEvent calls - // Extensions may overwrite window.nostr after authentication - if (typeof window !== 'undefined') { - console.log('WindowNostr: Re-installing facade after authentication'); - window.nostr = this; - } + } + + // CRITICAL FIX: Re-install our facade for ALL authentication methods + // Extensions may overwrite window.nostr after ANY authentication, not just extension auth + if (typeof window !== 'undefined') { + console.log('WindowNostr: Re-installing facade after', this.authState?.method, 'authentication'); + window.nostr = this; } console.log('WindowNostr: Auth state updated:', this.authState?.method); @@ -2578,6 +2739,12 @@ class WindowNostr { this.authState = null; this.authenticatedExtension = null; console.log('WindowNostr: Auth state cleared'); + + // Re-install facade after logout to ensure we maintain control + if (typeof window !== 'undefined') { + console.log('WindowNostr: Re-installing facade after logout'); + window.nostr = this; + } }); } } diff --git a/lite/ui/modal.js b/lite/ui/modal.js index c208f6f..0628d8c 100644 --- a/lite/ui/modal.js +++ b/lite/ui/modal.js @@ -831,15 +831,176 @@ class Modal { const warningDiv = document.createElement('div'); warningDiv.textContent = '⚠️ Save your secret key securely!'; - warningDiv.style.cssText = 'background: #fef3c7; color: #92400e; padding: 12px; border-radius: 6px; margin-bottom: 16px; font-size: 14px;'; + warningDiv.style.cssText = 'background: #fef3c7; color: #92400e; padding: 12px; border-radius: 6px; margin-bottom: 16px; font-size: 12px;'; - const nsecDiv = document.createElement('div'); - nsecDiv.innerHTML = `Your Secret Key:
${nsec}`; - nsecDiv.style.cssText = 'margin-bottom: 16px; font-size: 14px;'; + // Helper function to create copy button + const createCopyButton = (text, label) => { + const copyBtn = document.createElement('button'); + copyBtn.textContent = `Copy ${label}`; + copyBtn.style.cssText = ` + margin-left: 8px; + padding: 4px 8px; + font-size: 10px; + background: var(--nl-secondary-color); + color: var(--nl-primary-color); + border: 1px solid var(--nl-primary-color); + border-radius: 4px; + cursor: pointer; + font-family: var(--nl-font-family, 'Courier New', monospace); + `; + copyBtn.onclick = async (e) => { + e.preventDefault(); + try { + await navigator.clipboard.writeText(text); + const originalText = copyBtn.textContent; + copyBtn.textContent = '✓ Copied!'; + copyBtn.style.color = '#059669'; + setTimeout(() => { + copyBtn.textContent = originalText; + copyBtn.style.color = 'var(--nl-primary-color)'; + }, 2000); + } catch (err) { + console.error('Failed to copy:', err); + copyBtn.textContent = '✗ Failed'; + copyBtn.style.color = '#dc2626'; + setTimeout(() => { + copyBtn.textContent = originalText; + copyBtn.style.color = 'var(--nl-primary-color)'; + }, 2000); + } + }; + return copyBtn; + }; - const npubDiv = document.createElement('div'); - npubDiv.innerHTML = `Your Public Key:
${window.NostrTools.nip19.npubEncode(pubkey)}`; - npubDiv.style.cssText = 'margin-bottom: 16px; font-size: 14px;'; + // Convert pubkey to hex for verification + const pubkeyHex = typeof pubkey === 'string' ? pubkey : Array.from(pubkey).map(b => b.toString(16).padStart(2, '0')).join(''); + + // Decode nsec to get secret key as hex + let secretKeyHex = ''; + try { + const decoded = window.NostrTools.nip19.decode(nsec); + secretKeyHex = Array.from(decoded.data).map(b => b.toString(16).padStart(2, '0')).join(''); + } catch (err) { + console.error('Failed to decode nsec for hex display:', err); + } + + // Secret Key Section + const nsecSection = document.createElement('div'); + nsecSection.style.cssText = 'margin-bottom: 16px;'; + + const nsecLabel = document.createElement('div'); + nsecLabel.innerHTML = 'Your Secret Key (nsec):'; + nsecLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;'; + + const nsecContainer = document.createElement('div'); + nsecContainer.style.cssText = 'display: flex; align-items: flex-start; margin-bottom: 8px;'; + + const nsecCode = document.createElement('code'); + nsecCode.textContent = nsec; + nsecCode.style.cssText = ` + flex: 1; + word-break: break-all; + background: #f3f4f6; + padding: 6px; + border-radius: 4px; + font-size: 10px; + line-height: 1.3; + font-family: 'Courier New', monospace; + display: block; + `; + + nsecContainer.appendChild(nsecCode); + nsecContainer.appendChild(createCopyButton(nsec, 'nsec')); + nsecSection.appendChild(nsecLabel); + nsecSection.appendChild(nsecContainer); + + // Secret Key Hex Section + if (secretKeyHex) { + const secretHexLabel = document.createElement('div'); + secretHexLabel.innerHTML = 'Secret Key (hex):'; + secretHexLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;'; + + const secretHexContainer = document.createElement('div'); + secretHexContainer.style.cssText = 'display: flex; align-items: flex-start; margin-bottom: 8px;'; + + const secretHexCode = document.createElement('code'); + secretHexCode.textContent = secretKeyHex; + secretHexCode.style.cssText = ` + flex: 1; + word-break: break-all; + background: #f3f4f6; + padding: 6px; + border-radius: 4px; + font-size: 10px; + line-height: 1.3; + font-family: 'Courier New', monospace; + display: block; + `; + + secretHexContainer.appendChild(secretHexCode); + secretHexContainer.appendChild(createCopyButton(secretKeyHex, 'hex')); + nsecSection.appendChild(secretHexLabel); + nsecSection.appendChild(secretHexContainer); + } + + // Public Key Section + const npubSection = document.createElement('div'); + npubSection.style.cssText = 'margin-bottom: 16px;'; + + const npub = window.NostrTools.nip19.npubEncode(pubkey); + + const npubLabel = document.createElement('div'); + npubLabel.innerHTML = 'Your Public Key (npub):'; + npubLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;'; + + const npubContainer = document.createElement('div'); + npubContainer.style.cssText = 'display: flex; align-items: flex-start; margin-bottom: 8px;'; + + const npubCode = document.createElement('code'); + npubCode.textContent = npub; + npubCode.style.cssText = ` + flex: 1; + word-break: break-all; + background: #f3f4f6; + padding: 6px; + border-radius: 4px; + font-size: 10px; + line-height: 1.3; + font-family: 'Courier New', monospace; + display: block; + `; + + npubContainer.appendChild(npubCode); + npubContainer.appendChild(createCopyButton(npub, 'npub')); + npubSection.appendChild(npubLabel); + npubSection.appendChild(npubContainer); + + // Public Key Hex Section + const pubHexLabel = document.createElement('div'); + pubHexLabel.innerHTML = 'Public Key (hex):'; + pubHexLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;'; + + const pubHexContainer = document.createElement('div'); + pubHexContainer.style.cssText = 'display: flex; align-items: flex-start;'; + + const pubHexCode = document.createElement('code'); + pubHexCode.textContent = pubkeyHex; + pubHexCode.style.cssText = ` + flex: 1; + word-break: break-all; + background: #f3f4f6; + padding: 6px; + border-radius: 4px; + font-size: 10px; + line-height: 1.3; + font-family: 'Courier New', monospace; + display: block; + `; + + pubHexContainer.appendChild(pubHexCode); + pubHexContainer.appendChild(createCopyButton(pubkeyHex, 'hex')); + npubSection.appendChild(pubHexLabel); + npubSection.appendChild(pubHexContainer); const continueButton = document.createElement('button'); continueButton.textContent = 'Continue'; @@ -848,8 +1009,8 @@ class Modal { this.modalBody.appendChild(title); this.modalBody.appendChild(warningDiv); - this.modalBody.appendChild(nsecDiv); - this.modalBody.appendChild(npubDiv); + this.modalBody.appendChild(nsecSection); + this.modalBody.appendChild(npubSection); this.modalBody.appendChild(continueButton); }