diff --git a/js/app.js b/js/app.js index b2731ee2..93040450 100644 --- a/js/app.js +++ b/js/app.js @@ -2818,7 +2818,7 @@ class Application { throw error; } - if (signer.type === "extension" && nostrClient.ensureExtensionPermissions) { + if ((signer.type === "extension" || signer.type === "nip07") && nostrClient.ensureExtensionPermissions) { const permissionResult = await nostrClient.ensureExtensionPermissions( DEFAULT_NIP07_CORE_METHODS, ); diff --git a/js/nostr/client.js b/js/nostr/client.js index 5ef4bd2b..8f055167 100644 --- a/js/nostr/client.js +++ b/js/nostr/client.js @@ -272,7 +272,7 @@ function shouldRequestExtensionPermissions(signer) { if (!signer || typeof signer !== "object") { return false; } - return signer.type === "extension"; + return signer.type === "extension" || signer.type === "nip07"; } import { @@ -1205,7 +1205,7 @@ export class NostrClient { let extensionPermissionResult = null; if ( - activeSigner?.type === "extension" && + (activeSigner?.type === "extension" || activeSigner?.type === "nip07") && typeof this.ensureExtensionPermissions === "function" ) { extensionPermissionResult = await this.ensureExtensionPermissions( diff --git a/js/relayManager.js b/js/relayManager.js index a7d20bfe..972f49fb 100644 --- a/js/relayManager.js +++ b/js/relayManager.js @@ -665,7 +665,7 @@ class RelayPreferencesManager { throw error; } - if (signer.type === "extension") { + if (signer.type === "extension" || signer.type === "nip07") { const permissionResult = await requestDefaultExtensionPermissions(); if (!permissionResult.ok) { userLogger.warn( diff --git a/js/services/hashtagPreferencesService.js b/js/services/hashtagPreferencesService.js index 557207c6..3bc58cdf 100644 --- a/js/services/hashtagPreferencesService.js +++ b/js/services/hashtagPreferencesService.js @@ -1282,7 +1282,7 @@ class HashtagPreferencesService { throw error; } - if (signer.type === "extension") { + if (signer.type === "extension" || signer.type === "nip07") { const permissionResult = await requestDefaultExtensionPermissions( DEFAULT_NIP07_ENCRYPTION_METHODS, ); diff --git a/js/services/moderationService.js b/js/services/moderationService.js index a5ae291b..27ac31f3 100644 --- a/js/services/moderationService.js +++ b/js/services/moderationService.js @@ -2427,7 +2427,7 @@ export class ModerationService { } if ( - signer.type === "extension" && + (signer.type === "extension" || signer.type === "nip07") && typeof this.nostrClient?.ensureExtensionPermissions === "function" ) { const permissionResult = await this.nostrClient.ensureExtensionPermissions([ diff --git a/js/subscriptions.js b/js/subscriptions.js index fd43fe6d..d7eae458 100644 --- a/js/subscriptions.js +++ b/js/subscriptions.js @@ -1356,7 +1356,7 @@ class SubscriptionsManager { throw error; } - if (signer.type === "extension") { + if (signer.type === "extension" || signer.type === "nip07") { const permissionResult = await requestDefaultExtensionPermissions( DEFAULT_NIP07_ENCRYPTION_METHODS, ); diff --git a/js/ui/components/UploadModal.js b/js/ui/components/UploadModal.js index 905d78bb..6274d96f 100644 --- a/js/ui/components/UploadModal.js +++ b/js/ui/components/UploadModal.js @@ -939,7 +939,7 @@ export class UploadModal { } try { - if (signer?.type === "extension") { + if (signer?.type === "extension" || signer?.type === "nip07") { const permissionResult = await requestDefaultExtensionPermissions(); if (!permissionResult?.ok) { alert("Extension permissions are required to unlock storage."); diff --git a/js/ui/shareNostrController.js b/js/ui/shareNostrController.js index 93750464..669c3423 100644 --- a/js/ui/shareNostrController.js +++ b/js/ui/shareNostrController.js @@ -149,7 +149,7 @@ export default class ShareNostrController { throw new Error("share-missing-relays"); } - if (signer.type === "extension" && this.services.nostrClient.ensureExtensionPermissions) { + if ((signer.type === "extension" || signer.type === "nip07") && this.services.nostrClient.ensureExtensionPermissions) { const permissionResult = await this.services.nostrClient.ensureExtensionPermissions( this.services.permissionMethods, ); diff --git a/js/userBlocks.js b/js/userBlocks.js index fa458cfa..d12acde8 100644 --- a/js/userBlocks.js +++ b/js/userBlocks.js @@ -995,20 +995,26 @@ class UserBlockListManager { return (!requiresNip44 || hasNip44) && (!requiresNip04 || hasNip04); }; + // FIX: Always attempt to resolve the signer if one isn't available, + // regardless of allowPermissionPrompt. The previous guard meant that + // background refreshes (allowPermissionPrompt=false) could never decrypt + // because they skipped signer resolution entirely. ensureActiveSignerForPubkey + // does not itself prompt the user — it only waits for an already-injected + // extension or returns the existing signer. if ( - allowPermissionPrompt && - (!signer || - (!signerHasRequiredDecryptors(signer) && - typeof nostrClient?.ensureActiveSignerForPubkey === "function")) + (!signer || !signerHasRequiredDecryptors(signer)) && + typeof nostrClient?.ensureActiveSignerForPubkey === "function" ) { signer = await nostrClient.ensureActiveSignerForPubkey(normalized); } - const caps = signer?.capabilities || {}; - const signerHasNip04 = - caps.nip04 !== false && typeof signer?.nip04Decrypt === "function"; - const signerHasNip44 = - caps.nip44 !== false && typeof signer?.nip44Decrypt === "function"; + // FIX: Check method existence only, not capabilities. NIP-07 adapters + // always expose decrypt methods that check extension state at call time. + // The capabilities getter dynamically queries window.nostr which may not + // have injected nip04/nip44 modules yet (lazy injection), causing false + // negatives that block decryption even when methods will work at call time. + const signerHasNip04 = typeof signer?.nip04Decrypt === "function"; + const signerHasNip44 = typeof signer?.nip44Decrypt === "function"; const signerAvailable = Boolean(signer); const signerHasDecryptors = signerHasNip04 || signerHasNip44; const signerStatus = signerAvailable @@ -1555,7 +1561,7 @@ class UserBlockListManager { pubkey: normalized, relayUrls: relays, since: fetchSince, - timeoutMs: 6000, + timeoutMs: 10000, }); const legacyFetchPromise = Promise.all([ @@ -2108,7 +2114,7 @@ class UserBlockListManager { throw err; } - if (signer.type === "extension") { + if (signer.type === "extension" || signer.type === "nip07") { const permissionResult = await requestDefaultExtensionPermissions( DEFAULT_NIP07_ENCRYPTION_METHODS, ); diff --git a/js/watchHistoryService.js b/js/watchHistoryService.js index 8d5e750a..85c5e198 100644 --- a/js/watchHistoryService.js +++ b/js/watchHistoryService.js @@ -88,10 +88,12 @@ async function ensureWatchHistoryExtensionPermissions(actorKey, options = {}) { const allowPermissionPrompt = options?.allowPermissionPrompt !== false; + // FIX: Always attempt to resolve the signer regardless of allowPermissionPrompt. + // ensureActiveSignerForPubkey does not prompt the user — it only resolves an + // already-injected extension or returns the existing signer. let signer = getActiveSigner(); if ( - allowPermissionPrompt && - (!signer && typeof nostrClient?.ensureActiveSignerForPubkey === "function") + !signer && typeof nostrClient?.ensureActiveSignerForPubkey === "function" ) { signer = await nostrClient.ensureActiveSignerForPubkey(normalizedActor); } @@ -99,7 +101,9 @@ async function ensureWatchHistoryExtensionPermissions(actorKey, options = {}) { const canSign = typeof signer?.canSign === "function" ? signer.canSign() : typeof signer?.signEvent === "function"; - if (!canSign || signer?.type !== "extension") { + // FIX: NIP-07 adapters use type "nip07", not "extension". Both types + // represent browser extension signers that need permission pre-granting. + if (!canSign || (signer?.type !== "extension" && signer?.type !== "nip07")) { return { ok: true }; }