diff --git a/src/components/settings-modal/advanced-settings/__tests__/advanced-settings.test.tsx b/src/components/settings-modal/advanced-settings/__tests__/advanced-settings.test.tsx index 39ba632a..c99f13d4 100644 --- a/src/components/settings-modal/advanced-settings/__tests__/advanced-settings.test.tsx +++ b/src/components/settings-modal/advanced-settings/__tests__/advanced-settings.test.tsx @@ -211,6 +211,8 @@ describe('AdvancedSettings', () => { }); it('saves the browser pure p2p toggle through advanced settings', async () => { + localStorage.setItem('5chan:pure-p2p-browser-enabled', 'false'); + await renderSettings(false); const checkbox = container.querySelector('input[type="checkbox"]'); @@ -239,29 +241,29 @@ describe('AdvancedSettings', () => { expect(reloadMock).toHaveBeenCalledOnce(); }); - it('forces the browser pure p2p toggle on p2p subdomains', async () => { + it('allows browser pure p2p to be disabled on p2p subdomains', async () => { localStorage.setItem('5chan:pure-p2p-browser-enabled', 'false'); setTestHostname('p2p.5chan.app'); await renderSettings(false); const checkbox = container.querySelector('input[type="checkbox"]'); - expect(checkbox?.checked).toBe(true); - expect(checkbox?.disabled).toBe(true); + expect(checkbox?.checked).toBe(false); + expect(checkbox?.disabled).toBe(false); await clickButton('save_advanced_settings'); expect(testState.setAccountMock).toHaveBeenCalledWith( expect.objectContaining({ pkcOptions: expect.objectContaining({ - ipfsGatewayUrls: undefined, - libp2pJsClientsOptions: [{ key: 'libp2pjs' }], - pkcRpcClientsOptions: undefined, - pubsubKuboRpcClientsOptions: undefined, + ipfsGatewayUrls: ['https://ipfs.old.example'], + libp2pJsClientsOptions: undefined, + pkcRpcClientsOptions: ['ws://old.example/key'], + pubsubKuboRpcClientsOptions: ['https://pubsub.old.example'], }), }), ); - expect(localStorage.getItem('5chan:pure-p2p-browser-enabled')).toBe('true'); + expect(localStorage.getItem('5chan:pure-p2p-browser-enabled')).toBe('false'); }); it('saves gateway mode defaults when browser pure p2p is disabled', async () => { diff --git a/src/components/settings-modal/advanced-settings/advanced-settings.tsx b/src/components/settings-modal/advanced-settings/advanced-settings.tsx index f3023fef..321c6600 100644 --- a/src/components/settings-modal/advanced-settings/advanced-settings.tsx +++ b/src/components/settings-modal/advanced-settings/advanced-settings.tsx @@ -1,7 +1,7 @@ import { memo, RefObject, useRef, useState } from 'react'; import { setAccount, useAccount, usePkcRpcSettings } from '@bitsocial/bitsocial-react-hooks'; import { useTranslation } from 'react-i18next'; -import { getBrowserGatewayPkcOptions, getBrowserPureP2PPkcOptions, isPureP2PBrowserForced, setPureP2PBrowserPreference } from '../../../lib/p2p-browser-config'; +import { getBrowserGatewayPkcOptions, getBrowserPureP2PPkcOptions, setPureP2PBrowserPreference } from '../../../lib/p2p-browser-config'; import { canConfigureBrowserPureP2P, isBrowserPureP2PEnabled } from '../../../lib/p2p-runtime'; import styles from './advanced-settings.module.css'; @@ -205,18 +205,11 @@ const P2pDataPathSettings = ({ p2pDataPathRef }: SettingsProps) => { const PureP2PBrowserSettings = ({ pureP2PBrowserRef }: SettingsProps) => { const { t } = useTranslation(); const account = useAccount() as AccountShape | undefined; - const isForced = isPureP2PBrowserForced(); return (
{t('enable_pure_p2p_tip')}
@@ -261,7 +254,7 @@ const AdvancedSettings = () => { const pkcRpcClientsOptions = p2pRpcRef.current?.value.trim() ? [p2pRpcRef.current.value.trim()] : undefined; const dataPath = p2pDataPathRef.current?.value.trim() || undefined; - const pureP2PBrowserPreference = canConfigureBrowserPureP2P() ? isPureP2PBrowserForced() || pureP2PBrowserRef.current?.checked : undefined; + const pureP2PBrowserPreference = canConfigureBrowserPureP2P() ? pureP2PBrowserRef.current?.checked : undefined; const chainProviders: Record = {}; if (ethRpcUrls && ethRpcUrls.length > 0) { diff --git a/src/hooks/__tests__/use-state-string.test.tsx b/src/hooks/__tests__/use-state-string.test.tsx index c417fafb..368b9969 100644 --- a/src/hooks/__tests__/use-state-string.test.tsx +++ b/src/hooks/__tests__/use-state-string.test.tsx @@ -113,6 +113,8 @@ describe('use-state-string', () => { }); it('falls back to publishing and updating states when no client states are available', () => { + localStorage.setItem('5chan:pure-p2p-browser-enabled', 'false'); + act(() => { root.render(createElement(StateStringHarness, { value: { publishingState: 'fetching-ipfs', state: 'publishing' } })); }); @@ -130,6 +132,7 @@ describe('use-state-string', () => { }); it('formats raw community loading states when no client or update states are available', () => { + localStorage.setItem('5chan:pure-p2p-browser-enabled', 'false'); testState.community = { state: 'fetching-community-ipfs', }; @@ -156,6 +159,7 @@ describe('use-state-string', () => { }); it('sanitizes single-board feed state strings to board wording', () => { + localStorage.setItem('5chan:pure-p2p-browser-enabled', 'false'); testState.community = { state: 'updating', updatingState: 'fetching-ipfs', diff --git a/src/lib/__tests__/p2p-browser-config.test.ts b/src/lib/__tests__/p2p-browser-config.test.ts index 2d12cb44..81380f38 100644 --- a/src/lib/__tests__/p2p-browser-config.test.ts +++ b/src/lib/__tests__/p2p-browser-config.test.ts @@ -3,8 +3,6 @@ import { describe, expect, it } from 'vitest'; import { configureP2PBrowserPkcOptions, getPureP2PBrowserPreference, - isP2PBrowserHostname, - isPureP2PBrowserForced, P2P_BROWSER_PKC_OPTIONS, PURE_P2P_BROWSER_SETTING_KEY, setPureP2PBrowserPreference, @@ -19,14 +17,7 @@ const createStorage = (values: Record = {}) => ({ }); describe('p2p-browser-config', () => { - it('detects p2p subdomains', () => { - expect(isP2PBrowserHostname('p2p.5chan.app')).toBe(true); - expect(isP2PBrowserHostname('P2P.5chan.app')).toBe(true); - expect(isP2PBrowserHostname('5chan.app')).toBe(false); - expect(isP2PBrowserHostname('www.p2p.5chan.app')).toBe(false); - }); - - it('leaves browser PKC options untouched by default', () => { + it('configures browser PKC options for pure p2p by default', () => { const targetWindow = { location: { hostname: '5chan.app' }, localStorage: createStorage(), @@ -35,27 +26,26 @@ describe('p2p-browser-config', () => { }, }; - expect(configureP2PBrowserPkcOptions(targetWindow)).toBe(false); - expect(targetWindow.defaultPkcOptions).toEqual({ - ipfsGatewayUrls: ['https://gateway.example'], - }); - }); - - it('forces browser PKC options on p2p subdomains', () => { - const targetWindow = { - location: { hostname: 'p2p.5chan.app' }, - localStorage: createStorage({ [PURE_P2P_BROWSER_SETTING_KEY]: 'false' }), - defaultPkcOptions: { - ipfsGatewayUrls: ['https://gateway.example'], - }, - }; - - expect(isPureP2PBrowserForced(targetWindow)).toBe(true); expect(shouldUsePureP2PBrowser(targetWindow)).toBe(true); expect(configureP2PBrowserPkcOptions(targetWindow)).toBe(true); expect(targetWindow.defaultPkcOptions).toEqual(P2P_BROWSER_PKC_OPTIONS); }); + it('respects disabled pure p2p preference on p2p subdomains', () => { + const defaultPkcOptions = { + ipfsGatewayUrls: ['https://gateway.example'], + }; + const targetWindow = { + location: { hostname: 'p2p.5chan.app' }, + localStorage: createStorage({ [PURE_P2P_BROWSER_SETTING_KEY]: 'false' }), + defaultPkcOptions, + }; + + expect(shouldUsePureP2PBrowser(targetWindow)).toBe(false); + expect(configureP2PBrowserPkcOptions(targetWindow)).toBe(false); + expect(targetWindow.defaultPkcOptions).toBe(defaultPkcOptions); + }); + it('configures browser PKC options when pure p2p is enabled', () => { const targetWindow = { location: { hostname: '5chan.app' }, @@ -96,7 +86,6 @@ describe('p2p-browser-config', () => { expect(configureP2PBrowserPkcOptions(targetWindow)).toBe(false); expect(targetWindow.defaultPkcOptions).toBe(defaultPkcOptions); - expect(isPureP2PBrowserForced({ ...targetWindow, location: { hostname: 'p2p.5chan.app' } })).toBe(false); }); it('persists and reads the browser pure p2p preference', () => { @@ -106,7 +95,7 @@ describe('p2p-browser-config', () => { }; expect(getPureP2PBrowserPreference(targetWindow)).toBeUndefined(); - expect(shouldUsePureP2PBrowser(targetWindow)).toBe(false); + expect(shouldUsePureP2PBrowser(targetWindow)).toBe(true); setPureP2PBrowserPreference(false, targetWindow); expect(getPureP2PBrowserPreference(targetWindow)).toBe(false); diff --git a/src/lib/__tests__/p2p-runtime.test.ts b/src/lib/__tests__/p2p-runtime.test.ts index ba14fcc0..ec0c45c5 100644 --- a/src/lib/__tests__/p2p-runtime.test.ts +++ b/src/lib/__tests__/p2p-runtime.test.ts @@ -17,13 +17,23 @@ const browserWindow = { }, } as unknown as Window; +const browserWindowWithDisabledPureP2P = { + electronApi: undefined, + isElectron: false, + location: { hostname: '5chan.app' }, + localStorage: { + getItem: () => 'false', + setItem: () => undefined, + }, +} as unknown as Window; + const electronWindow = { electronApi: { isElectron: true }, isElectron: true, location: { hostname: 'localhost' }, } as unknown as Window; -const p2pBrowserWindow = { +const p2pBrowserWindowWithDisabledPureP2P = { electronApi: undefined, isElectron: false, location: { hostname: 'p2p.5chan.app' }, @@ -46,17 +56,18 @@ describe('p2p-runtime', () => { expect(getP2PRuntimeMode(account, browserWindow)).toBeNull(); }); - it('shows p2p settings in browsers only when pure p2p is enabled or active', () => { - expect(shouldShowP2PSettingsSection(undefined, browserWindow)).toBe(false); - expect(shouldShowP2PSettingsSection({ pkcOptions: { ipfsGatewayUrls: ['https://gateway.example'] } }, browserWindow)).toBe(false); - expect(isBrowserPureP2PEnabled({ pkcOptions: { ipfsGatewayUrls: ['https://gateway.example'] } }, browserWindow)).toBe(false); + it('shows p2p settings in browsers when pure p2p is enabled by default', () => { + expect(shouldShowP2PSettingsSection(undefined, browserWindow)).toBe(true); + expect(shouldShowP2PSettingsSection({ pkcOptions: { ipfsGatewayUrls: ['https://gateway.example'] } }, browserWindow)).toBe(true); + expect(isBrowserPureP2PEnabled({ pkcOptions: { ipfsGatewayUrls: ['https://gateway.example'] } }, browserWindow)).toBe(true); }); - it('forces browser p2p on p2p subdomains even with gateway account options', () => { + it('allows browser gateway mode when pure p2p is disabled', () => { const gatewayAccount = { pkcOptions: { ipfsGatewayUrls: ['https://gateway.example'] } }; - expect(isBrowserPureP2PEnabled(gatewayAccount, p2pBrowserWindow)).toBe(true); - expect(shouldShowP2PSettingsSection(gatewayAccount, p2pBrowserWindow)).toBe(true); + expect(isBrowserPureP2PEnabled(gatewayAccount, browserWindowWithDisabledPureP2P)).toBe(false); + expect(shouldShowP2PSettingsSection(gatewayAccount, browserWindowWithDisabledPureP2P)).toBe(false); + expect(isBrowserPureP2PEnabled(gatewayAccount, p2pBrowserWindowWithDisabledPureP2P)).toBe(false); }); it('builds browser p2p and gateway account options without a direct pkc-js import', () => { diff --git a/src/lib/p2p-browser-config.ts b/src/lib/p2p-browser-config.ts index 3ce4dec6..277ec4f7 100644 --- a/src/lib/p2p-browser-config.ts +++ b/src/lib/p2p-browser-config.ts @@ -26,8 +26,6 @@ type P2PBrowserConfigWindow = { localStorage?: Pick; }; -export const isP2PBrowserHostname = (hostname: string) => hostname.toLowerCase().startsWith('p2p.'); - export const getBrowserPureP2PPkcOptions = () => ({ ...P2P_BROWSER_PKC_OPTIONS, libp2pJsClientsOptions: P2P_BROWSER_PKC_OPTIONS.libp2pJsClientsOptions.map((options) => ({ ...options })), @@ -63,17 +61,13 @@ export const setPureP2PBrowserPreference = (enabled: boolean, targetWindow: P2PB export const isElectronRuntime = (targetWindow: P2PBrowserConfigWindow = window) => targetWindow.electronApi?.isElectron === true || targetWindow.isElectron === true; -export const isPureP2PBrowserForced = (targetWindow: P2PBrowserConfigWindow = window) => - !isElectronRuntime(targetWindow) && isP2PBrowserHostname(targetWindow.location?.hostname ?? ''); - export const shouldUsePureP2PBrowser = (targetWindow: P2PBrowserConfigWindow = window) => { if (isElectronRuntime(targetWindow)) return false; - if (isPureP2PBrowserForced(targetWindow)) return true; const preference = getPureP2PBrowserPreference(targetWindow); if (preference !== undefined) return preference; - return false; + return true; }; export const configureP2PBrowserPkcOptions = (targetWindow: P2PBrowserConfigWindow = window) => { diff --git a/src/lib/p2p-runtime.ts b/src/lib/p2p-runtime.ts index 763895cb..488653bd 100644 --- a/src/lib/p2p-runtime.ts +++ b/src/lib/p2p-runtime.ts @@ -1,4 +1,4 @@ -import { getBrowserGatewayPkcOptions, getBrowserPureP2PPkcOptions, isElectronRuntime, isPureP2PBrowserForced, shouldUsePureP2PBrowser } from './p2p-browser-config'; +import { getBrowserGatewayPkcOptions, getBrowserPureP2PPkcOptions, isElectronRuntime, shouldUsePureP2PBrowser } from './p2p-browser-config'; export const P2P_STATS_SECTION_ID = 'p2p-stats-settings'; @@ -52,11 +52,8 @@ export const shouldShowP2PSettingsSection = (account?: unknown, targetWindow: Wi getP2PRuntimeMode(account, targetWindow) !== null || (canConfigureBrowserPureP2P(targetWindow) && isBrowserPureP2PEnabled(account, targetWindow)); export const isBrowserPureP2PEnabled = (account?: unknown, targetWindow: Window = window) => { - const accountShape = toAccountShape(account); if (!canConfigureBrowserPureP2P(targetWindow)) return false; if (getP2PRuntimeMode(account, targetWindow) === 'browser-libp2p') return true; - if (isPureP2PBrowserForced(targetWindow)) return true; - if (hasArrayItems(accountShape?.pkcOptions?.ipfsGatewayUrls) || hasArrayItems(accountShape?.pkcOptions?.pubsubKuboRpcClientsOptions)) return false; return shouldUsePureP2PBrowser(targetWindow); };