diff --git a/js/userBlocks.js b/js/userBlocks.js index b7f6bd61..11873361 100644 --- a/js/userBlocks.js +++ b/js/userBlocks.js @@ -79,8 +79,8 @@ export const USER_BLOCK_EVENTS = Object.freeze({ const FAST_BLOCKLIST_RELAY_LIMIT = 3; const FAST_BLOCKLIST_TIMEOUT_MS = 2500; const BACKGROUND_BLOCKLIST_TIMEOUT_MS = 6000; -const DECRYPT_TIMEOUT_MS = 15000; -const BACKGROUND_DECRYPT_TIMEOUT_MS = 5000; +const DECRYPT_TIMEOUT_MS = 30000; +const BACKGROUND_DECRYPT_TIMEOUT_MS = 30000; const DECRYPT_RETRY_DELAY_MS = 10000; const MAX_BLOCKLIST_ENTRIES = 5000; @@ -1044,7 +1044,7 @@ class UserBlockListManager { "nip44", (payload) => signer.nip44Decrypt(normalized, payload, { - priority: NIP07_PRIORITY.LOW, + priority: NIP07_PRIORITY.NORMAL, }), "active-signer", ); @@ -1052,7 +1052,7 @@ class UserBlockListManager { "nip44_v2", (payload) => signer.nip44Decrypt(normalized, payload, { - priority: NIP07_PRIORITY.LOW, + priority: NIP07_PRIORITY.NORMAL, }), "active-signer", ); @@ -1063,7 +1063,7 @@ class UserBlockListManager { "nip04", (payload) => signer.nip04Decrypt(normalized, payload, { - priority: NIP07_PRIORITY.LOW, + priority: NIP07_PRIORITY.NORMAL, }), "active-signer", ); @@ -1071,7 +1071,7 @@ class UserBlockListManager { const nostrApi = typeof window !== "undefined" ? window?.nostr : null; const decrypterOptions = { - priority: NIP07_PRIORITY.LOW, + priority: NIP07_PRIORITY.NORMAL, timeoutMs: nip07DecryptTimeoutMs, retryMultiplier: 1, }; diff --git a/tests/user-blocks-decryption.test.mjs b/tests/user-blocks-decryption.test.mjs deleted file mode 100644 index dd0ecb71..00000000 --- a/tests/user-blocks-decryption.test.mjs +++ /dev/null @@ -1,204 +0,0 @@ - -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; -import { UserBlockListManager } from '../js/userBlocks.js'; -import { createNip07Adapter } from '../js/nostr/adapters/nip07Adapter.js'; -import { setActiveSigner } from '../js/nostrClientRegistry.js'; -import { NIP07_PRIORITY } from '../js/nostr/nip07Permissions.js'; - -// Mock dependencies -vi.mock('../js/nostrClientFacade.js', () => ({ - nostrClient: { - pool: {}, - fetchListIncrementally: vi.fn(), - ensureActiveSignerForPubkey: vi.fn(), - }, - requestDefaultExtensionPermissions: vi.fn().mockResolvedValue({ ok: true }), -})); - -vi.mock('../js/nostr/index.js', () => ({ - getActiveSigner: vi.fn(), -})); - -vi.mock('../js/nostr/sessionActor.js', () => ({ - isSessionActor: () => false, -})); - -vi.mock('../js/nostr/nip46Client.js', () => ({ - normalizeNostrPubkey: (k) => k, -})); - -vi.mock('../js/nostrEventSchemas.js', () => ({ - buildBlockListEvent: () => ({}), - buildMuteListEvent: () => ({}), - BLOCK_LIST_IDENTIFIER: 'user-blocks', -})); - -vi.mock('../js/nostr/cachePolicies.js', () => ({ - CACHE_POLICIES: {}, - STORAGE_TIERS: {}, -})); - -vi.mock('../js/utils/logger.js', () => ({ - devLogger: { warn: vi.fn(), log: vi.fn(), info: vi.fn() }, - userLogger: { warn: vi.fn(), log: vi.fn(), error: vi.fn() }, -})); - -vi.mock('../js/nostrPublish.js', () => ({ - publishEventToRelays: vi.fn(), - assertAnyRelayAccepted: vi.fn(), -})); - -vi.mock('../js/state/profileCache.js', () => ({ - profileCache: { - subscribe: vi.fn(), - getProfileData: vi.fn(), - setProfileData: vi.fn(), - }, -})); - -vi.mock('../js/relayManager.js', () => ({ - relayManager: { - getReadRelayUrls: () => ['wss://relay.example.com'], - }, -})); - -vi.mock('../js/services/relaySubscriptionService.js', () => ({ - relaySubscriptionService: { - ensureSubscription: vi.fn(), - stopSubscription: vi.fn(), - }, -})); - -// We need to import the class directly or mock the module exporting the instance -// Since userBlocks.js exports a singleton 'userBlocks', we might need to rely on the class logic if we could import it. -// However, the file exports `userBlocks` instance. To test the logic, we might need to inspect the code or -// use the exported instance. Ideally we'd test the class. -// Since I cannot easily import the private class from the module, I will try to use the exported instance -// but resetting it might be hard. -// Actually, looking at the file `js/userBlocks.js`, it defines the class `UserBlockListManager` but doesn't export it directly, -// only `export const userBlocks = new UserBlockListManager();`. -// I will use the exported instance. - -import { userBlocks } from '../js/userBlocks.js'; -import * as nostrIndex from '../js/nostr/index.js'; -import { nostrClient } from '../js/nostrClientFacade.js'; - -describe('UserBlockList Decryption Flow', () => { - let mockExtension; - let signer; - - beforeEach(async () => { - vi.useFakeTimers(); - userBlocks.reset(); - - // Mock Extension - mockExtension = { - getPublicKey: vi.fn().mockResolvedValue('0000000000000000000000000000000000000000000000000000000000000001'), - signEvent: vi.fn().mockResolvedValue({ id: 'signed-event' }), - nip04: { - encrypt: vi.fn().mockResolvedValue('ciphertext'), - decrypt: vi.fn().mockImplementation(async (pubkey, ciphertext) => { - // Simulate delay - await new Promise(resolve => setTimeout(resolve, 100)); - return '["p", "blocked-pubkey"]'; - }), - }, - }; - - signer = await createNip07Adapter(mockExtension); - nostrIndex.getActiveSigner.mockReturnValue(signer); - - // Mock fetchListIncrementally to return an encrypted event - nostrClient.fetchListIncrementally.mockResolvedValue([ - { - id: 'event-1', - kind: 10000, - pubkey: '0000000000000000000000000000000000000000000000000000000000000001', - created_at: 1000, - content: 'encrypted-content', - tags: [['p', 'public-mute']], - } - ]); - }); - - afterEach(() => { - vi.restoreAllMocks(); - vi.useRealTimers(); - }); - - it('should decrypt block list successfully within timeout', async () => { - const loadPromise = userBlocks.loadBlocks('0000000000000000000000000000000000000000000000000000000000000001', { - decryptTimeoutMs: 5000, // Sufficient timeout - }); - - // Advance timers to allow simulated delay - await vi.advanceTimersByTimeAsync(200); - - await loadPromise; - - expect(mockExtension.nip04.decrypt).toHaveBeenCalled(); - expect(userBlocks.isBlocked('blocked-pubkey')).toBe(false); // Parse logic dependent, let's check private blocks - // Wait, the mock returns '["p", "blocked-pubkey"]' which is NOT a valid JSON array of tags/pubkeys for parseBlockListPlaintext? - // parseBlockListPlaintext expects JSON array of pubkeys OR object with tags/blockedPubkeys. - // '["p", "blocked-pubkey"]' is an array. - // The parser handles: Array.isArray(parsed) -> extractPubkeysFromTags(parsed). - // extractPubkeysFromTags expects [['p', 'pubkey']]. - // So my mock return value is wrong for the parser. - }); - - it('should timeout if decryption takes too long', async () => { - // Make decryption take longer than timeout - mockExtension.nip04.decrypt.mockImplementation(async () => { - await new Promise(resolve => setTimeout(resolve, 5000)); - return '[]'; - }); - - const loadPromise = userBlocks.loadBlocks('0000000000000000000000000000000000000000000000000000000000000001', { - decryptTimeoutMs: 1000, // Short timeout - mode: 'background' - }); - - // Advance past timeout - await vi.advanceTimersByTimeAsync(1500); - - await loadPromise; - - // Check if it logged warning about timeout - const { userLogger } = await import('../js/utils/logger.js'); - expect(userLogger.warn).toHaveBeenCalledWith( - expect.stringContaining('Decryption timed out'), - expect.anything() - ); - }); - - it('should preserve existing blocks if decryption times out', async () => { - const validBlockedPubkey = '0000000000000000000000000000000000000000000000000000000000000002'; - - // 1. Seed with initial state - const { profileCache } = await import('../js/state/profileCache.js'); - profileCache.getProfileData.mockReturnValue({ - privateBlocks: [validBlockedPubkey], - publicMutes: [], - blockedPubkeys: [validBlockedPubkey], - createdAt: 500 - }); - - // 2. Make decryption fail/timeout - mockExtension.nip04.decrypt.mockImplementation(async () => { - await new Promise(resolve => setTimeout(resolve, 5000)); - return '[]'; - }); - - // 3. Trigger load - const loadPromise = userBlocks.loadBlocks('0000000000000000000000000000000000000000000000000000000000000001', { - decryptTimeoutMs: 1000, - mode: 'background' - }); - - await vi.advanceTimersByTimeAsync(1500); - await loadPromise; - - // 4. Verify we still have the cached block - expect(userBlocks.isBlocked(validBlockedPubkey)).toBe(true); - }); -});