From a352e2616e7dd7972a203aa190c3eeec78bbd016 Mon Sep 17 00:00:00 2001 From: Gigi Date: Thu, 16 Oct 2025 22:51:58 +0200 Subject: [PATCH] fix: prevent decrypt hangs with timeout + fallback - Wrap nip44/nip04 decrypt and unlockHiddenTags in timeouts - Fallback nip44->nip04 if nip44 hangs/fails - Add detailed [bunker] logs for each stage - Keeps UI responsive while debugging bunker responses --- src/services/bookmarkProcessing.ts | 53 +++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/src/services/bookmarkProcessing.ts b/src/services/bookmarkProcessing.ts index 4b1df2f7..c2501f5a 100644 --- a/src/services/bookmarkProcessing.ts +++ b/src/services/bookmarkProcessing.ts @@ -11,6 +11,21 @@ type UnlockHiddenTagsFn = typeof Helpers.unlockHiddenTags type HiddenContentSigner = Parameters[1] type UnlockMode = Parameters[2] +// Timeout helper to avoid hanging decrypt/unlock calls +async function withTimeout(promise: Promise, ms: number, label: string): Promise { + let timer: number | NodeJS.Timeout | undefined + try { + return await Promise.race([ + promise, + new Promise((_, reject) => { + timer = setTimeout(() => reject(new Error(`[timeout] ${label} after ${ms}ms`)), ms) + }) + ]) + } finally { + if (timer) clearTimeout(timer as NodeJS.Timeout) + } +} + export async function collectBookmarksFromEvents( bookmarkListEvents: NostrEvent[], activeAccount: ActiveAccount, @@ -81,15 +96,23 @@ export async function collectBookmarksFromEvents( hasHiddenTags: true }) try { - await Helpers.unlockHiddenTags(evt, signerCandidate as HiddenContentSigner) + await withTimeout( + Helpers.unlockHiddenTags(evt, signerCandidate as HiddenContentSigner), + 5000, + 'unlockHiddenTags(nip04)' + ) console.log('[bunker] ✅ Unlocked hidden tags with nip04') } catch (err) { - console.log('[bunker] ⚠️ nip04 unlock failed, trying nip44:', err) + console.log('[bunker] ⚠️ nip04 unlock failed (or timed out), trying nip44:', err) try { - await Helpers.unlockHiddenTags(evt, signerCandidate as HiddenContentSigner, 'nip44' as UnlockMode) + await withTimeout( + Helpers.unlockHiddenTags(evt, signerCandidate as HiddenContentSigner, 'nip44' as UnlockMode), + 5000, + 'unlockHiddenTags(nip44)' + ) console.log('[bunker] ✅ Unlocked hidden tags with nip44') } catch (err2) { - console.log('[bunker] ❌ nip44 unlock failed:', err2) + console.log('[bunker] ❌ nip44 unlock failed (or timed out):', err2) } } } else if (evt.content && evt.content.length > 0 && signerCandidate) { @@ -104,23 +127,31 @@ export async function collectBookmarksFromEvents( try { if (hasNip44Decrypt(signerCandidate)) { console.log('[bunker] Trying nip44 decrypt...') - decryptedContent = await (signerCandidate as { nip44: { decrypt: DecryptFn } }).nip44.decrypt( - evt.pubkey, - evt.content + decryptedContent = await withTimeout( + (signerCandidate as { nip44: { decrypt: DecryptFn } }).nip44.decrypt( + evt.pubkey, + evt.content + ), + 6000, + 'nip44.decrypt' ) console.log('[bunker] ✅ nip44 decrypt succeeded') } } catch (err) { - console.log('[bunker] ⚠️ nip44 decrypt failed:', err) + console.log('[bunker] ⚠️ nip44 decrypt failed (or timed out):', err) } if (!decryptedContent) { try { if (hasNip04Decrypt(signerCandidate)) { console.log('[bunker] Trying nip04 decrypt...') - decryptedContent = await (signerCandidate as { nip04: { decrypt: DecryptFn } }).nip04.decrypt( - evt.pubkey, - evt.content + decryptedContent = await withTimeout( + (signerCandidate as { nip04: { decrypt: DecryptFn } }).nip04.decrypt( + evt.pubkey, + evt.content + ), + 6000, + 'nip04.decrypt' ) console.log('[bunker] ✅ nip04 decrypt succeeded') }