From 602d563a7cfadcbb4feeaa886843f82cfc882b45 Mon Sep 17 00:00:00 2001 From: mleku Date: Thu, 18 Dec 2025 06:25:38 +0100 Subject: [PATCH] Fix WebSocket auth flow and improve header user profile display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix NIP-42 auth race condition: wait for AUTH challenge before authenticating - Header user profile: avatar fills vertical space, username vertically centered - Remove username truncation to show full name/npub - Standardize header height to 3em across all components 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- app/web/src/App.svelte | 2 +- app/web/src/Header.svelte | 48 +++++++++++++++++++++-------------- app/web/src/Sidebar.svelte | 2 +- app/web/src/websocket-auth.js | 44 +++++++++++++++++++------------- 4 files changed, 58 insertions(+), 38 deletions(-) diff --git a/app/web/src/App.svelte b/app/web/src/App.svelte index b07849d..ded2a6a 100644 --- a/app/web/src/App.svelte +++ b/app/web/src/App.svelte @@ -3466,7 +3466,7 @@ .main-content { position: fixed; left: 200px; - top: 2.5em; + top: 3em; right: 0; bottom: 0; padding: 0; diff --git a/app/web/src/Header.svelte b/app/web/src/Header.svelte index 3add844..a7f7791 100644 --- a/app/web/src/Header.svelte +++ b/app/web/src/Header.svelte @@ -45,7 +45,7 @@
👤
{/if} - {userProfile?.name || userPubkey.slice(0, 8) + "..."} + {userProfile?.name || userPubkey} {:else} @@ -64,32 +64,35 @@ top: 0; left: 0; right: 0; + height: 3em; background: var(--header-bg); border: 0; z-index: 1000; display: flex; - align-items: space-between; - padding: 0.25em; + align-items: stretch; + padding: 0 0.25em; } .header-content { display: flex; - align-items: center; + align-items: stretch; width: 100%; padding: 0; margin: 0; } .logo { - height: 2em; + height: 2.5em; width: auto; flex-shrink: 0; + align-self: center; } .header-title { flex: 1; display: flex; align-items: center; + align-self: center; } .app-title { @@ -114,8 +117,8 @@ .header-buttons { display: flex; - align-items: center; - height: 100%; + align-items: stretch; + align-self: stretch; margin-left: auto; } @@ -124,15 +127,14 @@ background: transparent; color: var(--button-text); border: 0; - height: 100%; cursor: pointer; font-size: 1em; transition: background-color 0.2s; flex-shrink: 0; padding: 0.5em; margin: 0; - display: block; - align-items: center; + display: flex !important; + align-items: center !important; justify-content: center; } @@ -144,32 +146,40 @@ .user-profile-btn { gap: 0.5em; justify-content: flex-start; - padding: 0 0.75em; + padding: 0 0.5em; } .user-avatar { - width: 1.5em; - height: 1.5em; + height: 2.5em; + width: 2.5em; border-radius: 50%; object-fit: cover; + flex-shrink: 0; + align-self: center; + vertical-align: middle; } .user-avatar-placeholder { - width: 1.5em; - height: 1.5em; + height: 2.5em; + width: 2.5em; border-radius: 50%; background: var(--bg-color); display: flex; align-items: center; justify-content: center; - font-size: 0.8em; + font-size: 1.2em; + flex-shrink: 0; + align-self: center; } .user-name { font-weight: 500; - max-width: 120px; - overflow: hidden; - text-overflow: ellipsis; white-space: nowrap; + line-height: 1; + align-self: center; + max-width: none !important; + overflow: visible !important; + text-overflow: unset !important; + width: auto !important; } diff --git a/app/web/src/Sidebar.svelte b/app/web/src/Sidebar.svelte index 4b471e1..52d89a0 100644 --- a/app/web/src/Sidebar.svelte +++ b/app/web/src/Sidebar.svelte @@ -47,7 +47,7 @@ .sidebar { position: fixed; left: 0; - top: 2.5em; + top: 3em; width: 200px; bottom: 0; background: var(--sidebar-bg); diff --git a/app/web/src/websocket-auth.js b/app/web/src/websocket-auth.js index c1f2210..698f82c 100644 --- a/app/web/src/websocket-auth.js +++ b/app/web/src/websocket-auth.js @@ -175,33 +175,43 @@ export class NostrWebSocketAuth { const [messageType, eventId, success, reason] = data; if (messageType === 'OK' && eventId === event.id) { - clearTimeout(timeout); - this.ws.onmessage = originalOnMessage; - if (success) { + clearTimeout(timeout); + this.ws.onmessage = originalOnMessage; console.log('Event published successfully:', eventId); resolve({ success: true, eventId, reason }); } else { console.error('Event publish failed:', reason); - + // Check if authentication is required if (reason && reason.includes('auth-required')) { - console.log('Authentication required, attempting to authenticate...'); - try { - await this.authenticate(); - // Re-send the event after authentication - const retryMessage = ["EVENT", event]; - this.ws.send(JSON.stringify(retryMessage)); - // Don't resolve yet, wait for the retry response - return; - } catch (authError) { - reject(new Error(`Authentication failed: ${authError.message}`)); - return; - } + console.log('Authentication required, waiting for AUTH challenge...'); + // Don't restore original handler yet - we need to receive the AUTH challenge + // The AUTH message will be handled by the else branch below + return; } - + + clearTimeout(timeout); + this.ws.onmessage = originalOnMessage; reject(new Error(`Publish failed: ${reason}`)); } + } else if (messageType === 'AUTH') { + // Handle AUTH challenge during publish flow + this.challenge = data[1]; + console.log('Received AUTH challenge during publish:', this.challenge); + + try { + await this.authenticate(); + console.log('Authentication successful, retrying event publish...'); + // Re-send the event after authentication + const retryMessage = ["EVENT", event]; + this.ws.send(JSON.stringify(retryMessage)); + // Don't resolve yet, wait for the retry response + } catch (authError) { + clearTimeout(timeout); + this.ws.onmessage = originalOnMessage; + reject(new Error(`Authentication failed: ${authError.message}`)); + } } else { // Handle other messages normally await this.handleMessage(data);