mirror of
https://github.com/stablyai/orca.git
synced 2026-10-21 08:03:33 +00:00
fix(browser): guard auth-host UA switch and cover it in tests
did-start-navigation now reads the guest UA on every main-frame nav; the load-failure replay guest mocks had no WebContents UA surface, so the handler threw. Only touch the session UA when actually leaving an auth host (a Firefox override is in place), give the affected mocks a faithful UA surface, and add direct coverage for the auth-host switch, off-host restore, and native opt-out.
This commit is contained in:
@@ -55,9 +55,17 @@ vi.mock('./popup-origin-bar-window', () => ({
|
||||
}))
|
||||
|
||||
import { browserManager } from './browser-manager'
|
||||
import { googleAuthUserAgent } from './browser-google-auth-ua'
|
||||
|
||||
describe('browserManager', () => {
|
||||
const rendererWebContentsId = 5001
|
||||
// Base (non-Firefox) UA a guest reports off the Google auth hosts.
|
||||
const guestBaseUserAgent = 'Mozilla/5.0 (Test) Chrome/140.0.0.0'
|
||||
const guestUaMethods = () => ({
|
||||
getUserAgent: vi.fn(() => guestBaseUserAgent),
|
||||
setUserAgent: vi.fn(),
|
||||
session: { getUserAgent: vi.fn(() => guestBaseUserAgent) }
|
||||
})
|
||||
type DownloadItemHandlerState = 'progressing' | 'interrupted' | 'completed' | 'cancelled'
|
||||
type DownloadItemHandler = (event: Electron.Event, state: DownloadItemHandlerState) => void
|
||||
|
||||
@@ -1610,7 +1618,8 @@ describe('browserManager', () => {
|
||||
on: guestOnMock,
|
||||
off: guestOffMock,
|
||||
openDevTools: guestOpenDevToolsMock,
|
||||
getURL: vi.fn(() => 'http://localhost:3000/')
|
||||
getURL: vi.fn(() => 'http://localhost:3000/'),
|
||||
...guestUaMethods()
|
||||
}
|
||||
|
||||
webContentsFromIdMock.mockImplementation((id: number) => {
|
||||
@@ -1686,7 +1695,8 @@ describe('browserManager', () => {
|
||||
on: guestOnMock,
|
||||
off: guestOffMock,
|
||||
openDevTools: guestOpenDevToolsMock,
|
||||
getURL: vi.fn(() => 'https://example.com/')
|
||||
getURL: vi.fn(() => 'https://example.com/'),
|
||||
...guestUaMethods()
|
||||
}
|
||||
webContentsFromIdMock.mockImplementation((id: number) =>
|
||||
id === guest.id
|
||||
@@ -1738,7 +1748,8 @@ describe('browserManager', () => {
|
||||
off: guestOffMock,
|
||||
openDevTools: guestOpenDevToolsMock,
|
||||
send: vi.fn(),
|
||||
getURL: vi.fn(() => 'chrome-error://chromewebdata/')
|
||||
getURL: vi.fn(() => 'chrome-error://chromewebdata/'),
|
||||
...guestUaMethods()
|
||||
}
|
||||
webContentsFromIdMock.mockReturnValue(guest)
|
||||
|
||||
@@ -1780,7 +1791,8 @@ describe('browserManager', () => {
|
||||
off: guestOffMock,
|
||||
openDevTools: guestOpenDevToolsMock,
|
||||
send: vi.fn(),
|
||||
getURL: vi.fn(() => 'chrome-error://chromewebdata/')
|
||||
getURL: vi.fn(() => 'chrome-error://chromewebdata/'),
|
||||
...guestUaMethods()
|
||||
}
|
||||
webContentsFromIdMock.mockReturnValue(guest)
|
||||
|
||||
@@ -1819,6 +1831,85 @@ describe('browserManager', () => {
|
||||
expect(browserManager.getBrowserPageLoadError('browser-retry-abort-page')).toBeNull()
|
||||
})
|
||||
|
||||
it('presents the Firefox UA on Google auth hosts and restores the base UA off them', () => {
|
||||
let currentUa = guestBaseUserAgent
|
||||
const setUserAgent = vi.fn((ua: string) => {
|
||||
currentUa = ua
|
||||
})
|
||||
const guest = {
|
||||
id: 408,
|
||||
isDestroyed: vi.fn(() => false),
|
||||
getType: vi.fn(() => 'webview'),
|
||||
setBackgroundThrottling: guestSetBackgroundThrottlingMock,
|
||||
setWindowOpenHandler: guestSetWindowOpenHandlerMock,
|
||||
on: guestOnMock,
|
||||
off: guestOffMock,
|
||||
openDevTools: guestOpenDevToolsMock,
|
||||
getURL: vi.fn(() => 'https://accounts.google.com/'),
|
||||
getUserAgent: vi.fn(() => currentUa),
|
||||
setUserAgent,
|
||||
session: { getUserAgent: vi.fn(() => guestBaseUserAgent) }
|
||||
}
|
||||
webContentsFromIdMock.mockReturnValue(guest)
|
||||
|
||||
browserManager.attachGuestPolicies(guest as never)
|
||||
browserManager.registerGuest({
|
||||
browserPageId: 'browser-auth-ua',
|
||||
webContentsId: guest.id,
|
||||
rendererWebContentsId
|
||||
})
|
||||
const didStartNavigation = guestOnMock.mock.calls.find(
|
||||
([event]) => event === 'did-start-navigation'
|
||||
)?.[1] as (event: unknown, url: string, isInPlace: boolean, isMainFrame: boolean) => void
|
||||
setUserAgent.mockClear()
|
||||
|
||||
didStartNavigation(null, 'https://accounts.google.com/v3/signin/identifier', false, true)
|
||||
expect(setUserAgent).toHaveBeenLastCalledWith(googleAuthUserAgent())
|
||||
|
||||
// Off the auth host, the guest's base identity is restored.
|
||||
didStartNavigation(null, 'https://myaccount.google.com/', false, true)
|
||||
expect(setUserAgent).toHaveBeenLastCalledWith(guestBaseUserAgent)
|
||||
|
||||
// A navigation that doesn't change the required UA must not thrash setUserAgent.
|
||||
setUserAgent.mockClear()
|
||||
didStartNavigation(null, 'https://example.com/', false, true)
|
||||
expect(setUserAgent).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('leaves the UA untouched on Google auth hosts for native-UA profiles', () => {
|
||||
const setUserAgent = vi.fn()
|
||||
const guest = {
|
||||
id: 409,
|
||||
isDestroyed: vi.fn(() => false),
|
||||
getType: vi.fn(() => 'webview'),
|
||||
setBackgroundThrottling: guestSetBackgroundThrottlingMock,
|
||||
setWindowOpenHandler: guestSetWindowOpenHandlerMock,
|
||||
on: guestOnMock,
|
||||
off: guestOffMock,
|
||||
openDevTools: guestOpenDevToolsMock,
|
||||
getURL: vi.fn(() => 'https://accounts.google.com/'),
|
||||
getUserAgent: vi.fn(() => guestBaseUserAgent),
|
||||
setUserAgent,
|
||||
session: { getUserAgent: vi.fn(() => guestBaseUserAgent) }
|
||||
}
|
||||
webContentsFromIdMock.mockReturnValue(guest)
|
||||
|
||||
browserManager.attachGuestPolicies(guest as never)
|
||||
browserManager.registerGuest({
|
||||
browserPageId: 'browser-native-ua',
|
||||
webContentsId: guest.id,
|
||||
rendererWebContentsId,
|
||||
userAgentMode: 'native'
|
||||
})
|
||||
const didStartNavigation = guestOnMock.mock.calls.find(
|
||||
([event]) => event === 'did-start-navigation'
|
||||
)?.[1] as (event: unknown, url: string, isInPlace: boolean, isMainFrame: boolean) => void
|
||||
setUserAgent.mockClear()
|
||||
|
||||
didStartNavigation(null, 'https://accounts.google.com/v3/signin/identifier', false, true)
|
||||
expect(setUserAgent).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('queues permission denials and download requests until the guest registers', () => {
|
||||
const rendererSendMock = vi.fn()
|
||||
const guest = {
|
||||
|
||||
@@ -926,9 +926,16 @@ export class BrowserManager {
|
||||
if (mode === 'native') {
|
||||
return
|
||||
}
|
||||
const desiredUa = isGoogleAuthUrl(url) ? googleAuthUserAgent() : guest.session.getUserAgent()
|
||||
if (guest.getUserAgent() !== desiredUa) {
|
||||
guest.setUserAgent(desiredUa)
|
||||
const firefoxUa = googleAuthUserAgent()
|
||||
const currentUa = guest.getUserAgent()
|
||||
if (isGoogleAuthUrl(url)) {
|
||||
if (currentUa !== firefoxUa) {
|
||||
guest.setUserAgent(firefoxUa)
|
||||
}
|
||||
} else if (currentUa === firefoxUa) {
|
||||
// Only restore when the auth-host override is actually in place, so normal
|
||||
// navigation never touches the session UA.
|
||||
guest.setUserAgent(guest.session.getUserAgent())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user