diff --git a/desktop/src/lib/desktopRuntime.test.ts b/desktop/src/lib/desktopRuntime.test.ts index 8bae06d6..023dcbab 100644 --- a/desktop/src/lib/desktopRuntime.test.ts +++ b/desktop/src/lib/desktopRuntime.test.ts @@ -56,7 +56,9 @@ describe('desktopRuntime browser H5 bootstrap', () => { globalThis.fetch = vi.fn().mockResolvedValue( new Response(null, { status: 200 }), ) as typeof fetch - clientMocks.postVerify.mockRejectedValueOnce(new Error('Unauthorized')) + clientMocks.postVerify.mockRejectedValueOnce( + Object.assign(new Error('Invalid or missing H5 access token'), { status: 401 }), + ) await expect(initializeDesktopServerUrl()).rejects.toMatchObject({ name: 'H5ConnectionRequiredError', @@ -70,6 +72,20 @@ describe('desktopRuntime browser H5 bootstrap', () => { expect(window.localStorage.getItem(H5_TOKEN_STORAGE_KEY)).toBeNull() }) + it('does not reuse stored remote H5 tokens for loopback browser startup', async () => { + window.history.pushState({}, '', '/?serverUrl=http%3A%2F%2F%5B%3A%3A1%5D%3A3456') + window.localStorage.setItem(H5_TOKEN_STORAGE_KEY, 'remote-token') + globalThis.fetch = vi.fn().mockResolvedValue( + new Response(null, { status: 200 }), + ) as typeof fetch + + await expect(initializeDesktopServerUrl()).resolves.toBe('http://[::1]:3456') + + expect(clientMocks.setBaseUrl).toHaveBeenLastCalledWith('http://[::1]:3456') + expect(clientMocks.setAuthToken).toHaveBeenLastCalledWith(null) + expect(clientMocks.postVerify).not.toHaveBeenCalled() + }) + it('normalizes unreachable remote browser startup into a recoverable H5 error', async () => { vi.useFakeTimers() window.history.pushState({}, '', '/?serverUrl=https%3A%2F%2Funreachable.example.com') diff --git a/desktop/src/lib/desktopRuntime.ts b/desktop/src/lib/desktopRuntime.ts index 77682689..22a1b079 100644 --- a/desktop/src/lib/desktopRuntime.ts +++ b/desktop/src/lib/desktopRuntime.ts @@ -135,7 +135,7 @@ async function initializeBrowserServerUrl(fallbackUrl: string) { const browserH5Runtime = requiresH5AuthForServerUrl(requestedUrl) setBaseUrl(requestedUrl) - setAuthToken(token) + setAuthToken(browserH5Runtime ? token : null) if (browserH5Runtime) { rememberStoredH5ServerUrl(requestedUrl) } @@ -247,7 +247,10 @@ function normalizeBrowserH5Error(error: unknown, serverUrl: string) { const message = error instanceof Error ? error.message : 'Unable to verify the H5 access token.' - const unauthorized = message.includes('401') || message.toLowerCase().includes('unauthorized') + const status = typeof error === 'object' && error !== null && 'status' in error + ? (error as { status?: unknown }).status + : undefined + const unauthorized = status === 401 || message.includes('401') || message.toLowerCase().includes('unauthorized') return new H5ConnectionRequiredError( unauthorized ? 'The saved H5 token is no longer valid.' : 'Unable to verify the H5 access token.', serverUrl,