2 Commits

Author SHA1 Message Date
Your Name
3109a93163 Fixed issue not recognizing browser extension 2025-09-22 15:37:53 -04:00
Your Name
4505167246 Change key entry 2025-09-21 11:51:33 -04:00
6 changed files with 978 additions and 1137 deletions

View File

@@ -1,3 +1,3 @@
#!/bin/bash #!/bin/bash
rsync -avz --progress lite/{nostr-lite.js,nostr.bundle.js} ubuntu@laantungir.net:WWW/nostr-login-lite/ rsync -avz --chmod=644 --progress lite/{nostr-lite.js,nostr.bundle.js} ubuntu@laantungir.net:WWW/nostr-login-lite/

View File

@@ -104,6 +104,18 @@
}}); }});
// Check for existing authentication state on page load
const authState = getAuthState();
if (authState && authState.method) {
console.log('Found existing authentication:', authState.method);
document.getElementById('status').textContent = `Authenticated with: ${authState.method}`;
document.getElementById('test-section').style.display = 'block';
// Store some test data for encryption/decryption
window.testCiphertext = null;
window.testCiphertext44 = null;
}
// Listen for authentication events // Listen for authentication events
window.addEventListener('nlMethodSelected', (event) => { window.addEventListener('nlMethodSelected', (event) => {
console.log('User authenticated:', event.detail); console.log('User authenticated:', event.detail);

View File

@@ -1 +1 @@
0.1.3 0.1.5

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -700,62 +700,8 @@ class Modal {
_showLocalKeyScreen() { _showLocalKeyScreen() {
this.modalBody.innerHTML = ''; this.modalBody.innerHTML = '';
const title = document.createElement('h3');
title.textContent = 'Local Key';
title.style.cssText = 'margin: 0 0 20px 0; font-size: 18px; font-weight: 600;';
const createButton = document.createElement('button');
createButton.textContent = 'Create New Key';
createButton.onclick = () => this._createLocalKey();
createButton.style.cssText = this._getButtonStyle();
const importButton = document.createElement('button');
importButton.textContent = 'Import Existing Key';
importButton.onclick = () => this._showImportKeyForm();
importButton.style.cssText = this._getButtonStyle() + 'margin-top: 12px;';
const backButton = document.createElement('button');
backButton.textContent = 'Back';
backButton.onclick = () => this._renderLoginOptions();
backButton.style.cssText = `
display: block;
margin-top: 20px;
padding: 12px;
background: #6b7280;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
`;
this.modalBody.appendChild(title);
this.modalBody.appendChild(createButton);
this.modalBody.appendChild(importButton);
this.modalBody.appendChild(backButton);
}
_createLocalKey() {
try {
const sk = window.NostrTools.generateSecretKey();
const pk = window.NostrTools.getPublicKey(sk);
const nsec = window.NostrTools.nip19.nsecEncode(sk);
const npub = window.NostrTools.nip19.npubEncode(pk);
this._showKeyDisplay(pk, nsec, 'created');
} catch (error) {
this._showError('Failed to create key: ' + error.message);
}
}
_showImportKeyForm() {
this.modalBody.innerHTML = '';
const title = document.createElement('h3');
title.textContent = 'Import Local Key';
title.style.cssText = 'margin: 0 0 16px 0; font-size: 18px; font-weight: 600;';
const description = document.createElement('p'); const description = document.createElement('p');
description.textContent = 'Enter your secret key in either nsec or hex format:'; description.innerHTML = 'Enter your secret key in nsec or hex format, or <span id="generate-new" style="text-decoration: underline; cursor: pointer; color: var(--nl-primary-color);">generate new</span>.';
description.style.cssText = 'margin-bottom: 12px; color: #6b7280; font-size: 14px;'; description.style.cssText = 'margin-bottom: 12px; color: #6b7280; font-size: 14px;';
const textarea = document.createElement('textarea'); const textarea = document.createElement('textarea');
@@ -777,10 +723,40 @@ class Modal {
const formatHint = document.createElement('div'); const formatHint = document.createElement('div');
formatHint.style.cssText = 'margin-bottom: 16px; font-size: 12px; color: #6b7280; min-height: 16px;'; formatHint.style.cssText = 'margin-bottom: 16px; font-size: 12px; color: #6b7280; min-height: 16px;';
const importButton = document.createElement('button');
importButton.textContent = 'Import Key';
importButton.disabled = true;
importButton.onclick = () => {
if (!importButton.disabled) {
this._importLocalKey(textarea.value);
}
};
// Set initial disabled state
importButton.style.cssText = `
display: block;
width: 100%;
padding: 12px;
border: var(--nl-border-width) solid var(--nl-muted-color);
border-radius: var(--nl-border-radius);
font-size: 16px;
font-weight: 500;
cursor: not-allowed;
transition: all 0.2s;
font-family: var(--nl-font-family, 'Courier New', monospace);
background: var(--nl-secondary-color);
color: var(--nl-muted-color);
`;
textarea.oninput = () => { textarea.oninput = () => {
const value = textarea.value.trim(); const value = textarea.value.trim();
if (!value) { if (!value) {
formatHint.textContent = ''; formatHint.textContent = '';
// Disable button
importButton.disabled = true;
importButton.style.borderColor = 'var(--nl-muted-color)';
importButton.style.color = 'var(--nl-muted-color)';
importButton.style.cursor = 'not-allowed';
return; return;
} }
@@ -788,32 +764,93 @@ class Modal {
if (format === 'nsec') { if (format === 'nsec') {
formatHint.textContent = '✅ Valid nsec format detected'; formatHint.textContent = '✅ Valid nsec format detected';
formatHint.style.color = '#059669'; formatHint.style.color = '#059669';
// Enable button
importButton.disabled = false;
importButton.style.borderColor = 'var(--nl-primary-color)';
importButton.style.color = 'var(--nl-primary-color)';
importButton.style.cursor = 'pointer';
} else if (format === 'hex') { } else if (format === 'hex') {
formatHint.textContent = '✅ Valid hex format detected'; formatHint.textContent = '✅ Valid hex format detected';
formatHint.style.color = '#059669'; formatHint.style.color = '#059669';
// Enable button
importButton.disabled = false;
importButton.style.borderColor = 'var(--nl-primary-color)';
importButton.style.color = 'var(--nl-primary-color)';
importButton.style.cursor = 'pointer';
} else { } else {
formatHint.textContent = '❌ Invalid key format - must be nsec1... or 64-character hex'; formatHint.textContent = '❌ Invalid key format - must be nsec1... or 64-character hex';
formatHint.style.color = '#dc2626'; formatHint.style.color = '#dc2626';
// Disable button
importButton.disabled = true;
importButton.style.borderColor = 'var(--nl-muted-color)';
importButton.style.color = 'var(--nl-muted-color)';
importButton.style.cursor = 'not-allowed';
} }
}; };
const importButton = document.createElement('button');
importButton.textContent = 'Import Key';
importButton.onclick = () => this._importLocalKey(textarea.value);
importButton.style.cssText = this._getButtonStyle();
const backButton = document.createElement('button'); const backButton = document.createElement('button');
backButton.textContent = 'Back'; backButton.textContent = 'Back';
backButton.onclick = () => this._showLocalKeyScreen(); backButton.onclick = () => this._renderLoginOptions();
backButton.style.cssText = this._getButtonStyle('secondary') + 'margin-top: 12px;'; backButton.style.cssText = this._getButtonStyle('secondary') + 'margin-top: 12px;';
this.modalBody.appendChild(title);
this.modalBody.appendChild(description); this.modalBody.appendChild(description);
this.modalBody.appendChild(textarea); this.modalBody.appendChild(textarea);
this.modalBody.appendChild(formatHint); this.modalBody.appendChild(formatHint);
this.modalBody.appendChild(importButton); this.modalBody.appendChild(importButton);
this.modalBody.appendChild(backButton); this.modalBody.appendChild(backButton);
// Add click handler for the "generate new" link
const generateLink = document.getElementById('generate-new');
if (generateLink) {
generateLink.addEventListener('mouseenter', () => {
generateLink.style.color = 'var(--nl-accent-color)';
});
generateLink.addEventListener('mouseleave', () => {
generateLink.style.color = 'var(--nl-primary-color)';
});
generateLink.addEventListener('click', () => {
this._generateNewLocalKey(textarea, formatHint);
});
} }
}
_generateNewLocalKey(textarea, formatHint) {
try {
// Generate a new secret key using NostrTools
const sk = window.NostrTools.generateSecretKey();
const nsec = window.NostrTools.nip19.nsecEncode(sk);
// Set the generated key in the textarea
textarea.value = nsec;
// Trigger the oninput event to properly validate and enable the button
if (textarea.oninput) {
textarea.oninput();
}
console.log('Generated new local secret key (nsec format)');
} catch (error) {
console.error('Failed to generate local key:', error);
formatHint.textContent = '❌ Failed to generate key - NostrTools not available';
formatHint.style.color = '#dc2626';
}
}
_createLocalKey() {
try {
const sk = window.NostrTools.generateSecretKey();
const pk = window.NostrTools.getPublicKey(sk);
const nsec = window.NostrTools.nip19.nsecEncode(sk);
const npub = window.NostrTools.nip19.npubEncode(pk);
this._showKeyDisplay(pk, nsec, 'created');
} catch (error) {
this._showError('Failed to create key: ' + error.message);
}
}
_detectKeyFormat(keyValue) { _detectKeyFormat(keyValue) {
const trimmed = keyValue.trim(); const trimmed = keyValue.trim();
@@ -1094,7 +1131,6 @@ class Modal {
} }
_setAuthMethod(method, options = {}) { _setAuthMethod(method, options = {}) {
// SINGLE-EXTENSION ARCHITECTURE: Handle method switching
console.log('Modal: _setAuthMethod called with:', method, options); console.log('Modal: _setAuthMethod called with:', method, options);
// CRITICAL: Never install facade for extension methods - leave window.nostr as the extension // CRITICAL: Never install facade for extension methods - leave window.nostr as the extension
@@ -1117,46 +1153,57 @@ class Modal {
return; return;
} }
// For non-extension methods, we need to ensure WindowNostr facade is available // FOR NON-EXTENSION METHODS: Force-install facade with resilience
console.log('Modal: Non-extension method detected:', method); console.log('Modal: Non-extension method - FORCE-INSTALLING facade with resilience:', method);
// Check if we have a preserved extension but no WindowNostr facade installed // Store the current extension if any (for potential restoration later)
const hasPreservedExtension = !!window.NOSTR_LOGIN_LITE?._instance?.preservedExtension; const currentExtension = (window.nostr?.constructor?.name !== 'WindowNostr') ? window.nostr : null;
const hasWindowNostrFacade = window.nostr?.constructor?.name === 'WindowNostr';
console.log('Modal: Method switching check:'); // Get NostrLite instance for facade operations
console.log(' method:', method);
console.log(' hasPreservedExtension:', hasPreservedExtension);
console.log(' hasWindowNostrFacade:', hasWindowNostrFacade);
console.log(' current window.nostr constructor:', window.nostr?.constructor?.name);
// If we have a preserved extension but no facade, install facade for method switching
if (hasPreservedExtension && !hasWindowNostrFacade) {
console.log('Modal: Installing WindowNostr facade for method switching (non-extension authentication)');
// Get the NostrLite instance and install facade with preserved extension
const nostrLiteInstance = window.NOSTR_LOGIN_LITE?._instance; const nostrLiteInstance = window.NOSTR_LOGIN_LITE?._instance;
if (nostrLiteInstance && typeof nostrLiteInstance._installFacade === 'function') { if (!nostrLiteInstance || typeof nostrLiteInstance._installFacade !== 'function') {
const preservedExtension = nostrLiteInstance.preservedExtension;
console.log('Modal: Installing facade with preserved extension:', preservedExtension?.constructor?.name);
nostrLiteInstance._installFacade(preservedExtension);
console.log('Modal: WindowNostr facade installed for method switching');
} else {
console.error('Modal: Cannot access NostrLite instance or _installFacade method'); console.error('Modal: Cannot access NostrLite instance or _installFacade method');
} // Fallback: emit event anyway
const event = new CustomEvent('nlMethodSelected', {
detail: { method, ...options }
});
window.dispatchEvent(event);
this.close();
return;
} }
// If no extension at all, ensure facade is installed for local/NIP-46/readonly methods // IMMEDIATE FACADE INSTALLATION
else if (!hasPreservedExtension && !hasWindowNostrFacade) { console.log('Modal: Installing WindowNostr facade immediately for method:', method);
console.log('Modal: Installing WindowNostr facade for non-extension methods (no extension detected)'); const preservedExtension = nostrLiteInstance.preservedExtension || currentExtension;
nostrLiteInstance._installFacade(preservedExtension, true);
console.log('Modal: WindowNostr facade force-installed, current window.nostr:', window.nostr?.constructor?.name);
const nostrLiteInstance = window.NOSTR_LOGIN_LITE?._instance; // DELAYED FACADE RESILIENCE - Reinstall after extension override attempts
if (nostrLiteInstance && typeof nostrLiteInstance._installFacade === 'function') { const forceReinstallFacade = () => {
nostrLiteInstance._installFacade(); console.log('Modal: RESILIENCE CHECK - Current window.nostr after delay:', window.nostr?.constructor?.name);
console.log('Modal: WindowNostr facade installed for non-extension methods');
// If facade was overridden by extension, reinstall it
if (window.nostr?.constructor?.name !== 'WindowNostr') {
console.log('Modal: FACADE OVERRIDDEN! Force-reinstalling WindowNostr facade for user choice:', method);
nostrLiteInstance._installFacade(preservedExtension, true);
console.log('Modal: Resilient facade force-reinstall complete, window.nostr:', window.nostr?.constructor?.name);
// Schedule another check in case of persistent extension override
setTimeout(() => {
if (window.nostr?.constructor?.name !== 'WindowNostr') {
console.log('Modal: PERSISTENT OVERRIDE! Final facade force-reinstall for method:', method);
nostrLiteInstance._installFacade(preservedExtension, true);
} }
}, 1000);
} else {
console.log('Modal: Facade persistence verified - no override detected');
} }
};
// Schedule resilience checks at multiple intervals
setTimeout(forceReinstallFacade, 100); // Quick check
setTimeout(forceReinstallFacade, 500); // Main check
setTimeout(forceReinstallFacade, 1500); // Final check
// Emit auth method selection // Emit auth method selection
const event = new CustomEvent('nlMethodSelected', { const event = new CustomEvent('nlMethodSelected', {