From 12d770483188ebe6caf2ed22d817cd069afbc66e Mon Sep 17 00:00:00 2001 From: Silberengel Date: Wed, 18 Feb 2026 10:55:42 +0100 Subject: [PATCH] bug-fixes --- src/hooks.server.ts | 4 +- src/lib/components/NavBar.svelte | 18 ++++- src/lib/services/nostr/user-level-service.ts | 14 +++- src/routes/+layout.svelte | 20 +++-- src/routes/+page.svelte | 21 ++++-- src/routes/repos/+page.svelte | 79 +++++++++++--------- 6 files changed, 100 insertions(+), 56 deletions(-) diff --git a/src/hooks.server.ts b/src/hooks.server.ts index 5fe5093..d8ebb3f 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -103,9 +103,9 @@ export const handle: Handle = async ({ event, resolve }) => { const csp = [ "default-src 'self'", "script-src 'self' 'unsafe-inline' 'unsafe-eval'", // unsafe-eval needed for Svelte - "style-src 'self' 'unsafe-inline'", + "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com", "img-src 'self' data: https:", - "font-src 'self' data:", + "font-src 'self' data: https://fonts.gstatic.com", "connect-src 'self' wss: https:", "frame-ancestors 'none'", "base-uri 'self'", diff --git a/src/lib/components/NavBar.svelte b/src/lib/components/NavBar.svelte index 7424bb7..1028882 100644 --- a/src/lib/components/NavBar.svelte +++ b/src/lib/components/NavBar.svelte @@ -12,8 +12,10 @@ let userPubkey = $state(null); let mobileMenuOpen = $state(false); - onMount(async () => { - await checkAuth(); + onMount(() => { + // Check auth asynchronously (don't await in onMount cleanup) + checkAuth(); + // Update activity on mount updateActivity(); @@ -41,6 +43,13 @@ } async function checkAuth() { + // Don't check auth if user store indicates user is logged out + const currentState = $userStore; + if (!currentState.userPubkey) { + userPubkey = null; + return; + } + try { if (isNIP07Available()) { userPubkey = await getPublicKeyWithNIP07(); @@ -63,14 +72,15 @@ } } - function logout() { + async function logout() { userPubkey = null; // Reset user store userStore.reset(); // Clear activity tracking clearActivity(); // Navigate to home page to reset all component state to anonymous - goto('/'); + // Use replace to prevent back button from going back to logged-in state + await goto('/', { replaceState: true, invalidateAll: true }); } function isActive(path: string): boolean { diff --git a/src/lib/services/nostr/user-level-service.ts b/src/lib/services/nostr/user-level-service.ts index 075c3d4..52bceca 100644 --- a/src/lib/services/nostr/user-level-service.ts +++ b/src/lib/services/nostr/user-level-service.ts @@ -118,15 +118,25 @@ export async function determineUserLevel( /** * Helper to decode npub to hex if needed + * Handles both npub (bech32) and hex formats */ export function decodePubkey(pubkey: string): string | null { + if (!pubkey) return null; + + // Check if it's already hex (64 characters, hex format) + if (/^[0-9a-f]{64}$/i.test(pubkey)) { + return pubkey.toLowerCase(); + } + + // Try to decode as npub (bech32) try { const decoded = nip19.decode(pubkey); if (decoded.type === 'npub') { return decoded.data as string; } - return pubkey; // Assume it's already hex + return pubkey; // Unknown type, return as-is } catch { - return pubkey; // Assume it's already hex + // Not a valid npub, assume it's already hex or return as-is + return pubkey; } } diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 2c05431..4c9d2c2 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -21,6 +21,9 @@ let checkingUserLevel = $state(false); onMount(() => { + // Only run client-side code + if (typeof window === 'undefined') return; + // Check for saved theme preference or default to dark const savedTheme = localStorage.getItem('theme') as 'light' | 'dark' | null; if (savedTheme === 'light' || savedTheme === 'dark') { @@ -32,14 +35,12 @@ applyTheme(); // Watch for system theme changes (only if user hasn't set a preference) - if (typeof window !== 'undefined') { - window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => { - if (!localStorage.getItem('theme')) { - theme = e.matches ? 'dark' : 'light'; - applyTheme(); - } - }); - } + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => { + if (!localStorage.getItem('theme')) { + theme = e.matches ? 'dark' : 'light'; + applyTheme(); + } + }); // Check for session expiry (24 hours) if (isSessionExpired()) { @@ -81,6 +82,9 @@ }); async function checkUserLevel() { + // Only run client-side + if (typeof window === 'undefined') return; + // Skip if already checking or if user store is already set const currentState = $userStore; if (checkingUserLevel || (currentState.userPubkey && currentState.userLevel !== 'strictly_rate_limited')) { diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 9167d61..7cb54e0 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -34,13 +34,22 @@ try { userPubkey = await getPublicKeyWithNIP07(); // Convert npub to hex for API calls - try { - const decoded = nip19.decode(userPubkey); - if (decoded.type === 'npub') { - userPubkeyHex = decoded.data as string; + // NIP-07 may return either npub or hex + if (/^[0-9a-f]{64}$/i.test(userPubkey)) { + // Already hex format + userPubkeyHex = userPubkey.toLowerCase(); + } else { + // Try to decode as npub + try { + const decoded = nip19.decode(userPubkey); + if (decoded.type === 'npub') { + userPubkeyHex = decoded.data as string; + } else { + userPubkeyHex = userPubkey; // Unknown type, use as-is + } + } catch { + userPubkeyHex = userPubkey; // Assume it's already hex or use as-is } - } catch { - userPubkeyHex = userPubkey; // Assume it's already hex } } catch (err) { console.warn('Failed to load user pubkey:', err); diff --git a/src/routes/repos/+page.svelte b/src/routes/repos/+page.svelte index a311ac9..9665257 100644 --- a/src/routes/repos/+page.svelte +++ b/src/routes/repos/+page.svelte @@ -48,45 +48,56 @@ if (!userPubkey) return; // Convert npub to hex for API calls - try { - const decoded = nip19.decode(userPubkey); - if (decoded.type === 'npub') { - userPubkeyHex = decoded.data as string; - contactPubkeys.add(userPubkeyHex); // Include user's own repos - - // Fetch user's kind 3 contact list - const contactEvents = await nostrClient.fetchEvents([ - { - kinds: [KIND.CONTACT_LIST], - authors: [userPubkeyHex], - limit: 1 - } - ]); - - if (contactEvents.length > 0) { - const contactEvent = contactEvents[0]; - // Extract pubkeys from 'p' tags - for (const tag of contactEvent.tags) { - if (tag[0] === 'p' && tag[1]) { - let pubkey = tag[1]; - // Try to decode if it's an npub - try { - const decoded = nip19.decode(pubkey); - if (decoded.type === 'npub') { - pubkey = decoded.data as string; - } - } catch { - // Assume it's already a hex pubkey - } - if (pubkey) { - contactPubkeys.add(pubkey); + // NIP-07 may return either npub or hex, so check format first + if (/^[0-9a-f]{64}$/i.test(userPubkey)) { + // Already hex format + userPubkeyHex = userPubkey.toLowerCase(); + contactPubkeys.add(userPubkeyHex); // Include user's own repos + } else { + // Try to decode as npub + try { + const decoded = nip19.decode(userPubkey); + if (decoded.type === 'npub') { + userPubkeyHex = decoded.data as string; + contactPubkeys.add(userPubkeyHex); // Include user's own repos + } + } catch (err) { + // If decode fails, might still be hex or invalid - skip + console.warn('Failed to decode user pubkey:', err); + } + } + + if (userPubkeyHex) { + // Fetch user's kind 3 contact list + const contactEvents = await nostrClient.fetchEvents([ + { + kinds: [KIND.CONTACT_LIST], + authors: [userPubkeyHex], + limit: 1 + } + ]); + + if (contactEvents.length > 0) { + const contactEvent = contactEvents[0]; + // Extract pubkeys from 'p' tags + for (const tag of contactEvent.tags) { + if (tag[0] === 'p' && tag[1]) { + let pubkey = tag[1]; + // Try to decode if it's an npub + try { + const decoded = nip19.decode(pubkey); + if (decoded.type === 'npub') { + pubkey = decoded.data as string; } + } catch { + // Assume it's already a hex pubkey + } + if (pubkey) { + contactPubkeys.add(pubkey); } } } } - } catch (err) { - console.warn('Failed to decode user pubkey:', err); } } catch (err) { console.warn('Failed to load user or contacts:', err);