mirror of
https://github.com/stablyai/orca.git
synced 2026-10-23 08:03:39 +00:00
Prevent duplicate Kagi session tokens and redact load error credentials
Canonicalize navigation URLs to strip duplicate token parameters before queueing. Redact Kagi session tokens from loadError.validatedUrl in tab listings to prevent credential leakage in error displays.
This commit is contained in:
@@ -192,6 +192,28 @@ describe('AgentBrowserBridge', () => {
|
||||
expect(JSON.stringify(result)).not.toContain('session-secret')
|
||||
})
|
||||
|
||||
it('redacts Kagi session credentials from a listed load error', () => {
|
||||
const tabs = new Map([['tab-a', 1]])
|
||||
const wc = mockWebContents(1, 'chrome-error://chromewebdata/', '')
|
||||
webContentsFromIdMock.mockReturnValue(wc)
|
||||
const loadError = {
|
||||
code: -105,
|
||||
description: 'Name not resolved',
|
||||
validatedUrl: 'https://kagi.com/search?token=session-secret&q=private+project'
|
||||
}
|
||||
|
||||
const result = new AgentBrowserBridge(
|
||||
mockBrowserManager(tabs, new Map(), {
|
||||
getBrowserPageLoadError: vi.fn((tabId: string) => (tabId === 'tab-a' ? loadError : null))
|
||||
})
|
||||
).tabList()
|
||||
|
||||
expect(result.tabs[0]?.loadError?.validatedUrl).toBe(
|
||||
'https://kagi.com/search?q=private+project'
|
||||
)
|
||||
expect(JSON.stringify(result)).not.toContain('session-secret')
|
||||
})
|
||||
|
||||
it('does not mutate active-tab routing when tab-list infers the first live tab', () => {
|
||||
const tabs = new Map([
|
||||
['tab-a', 1],
|
||||
|
||||
@@ -751,7 +751,9 @@ export class AgentBrowserBridge {
|
||||
url: redactKagiSessionToken(loadError?.validatedUrl ?? wc.getURL() ?? ''),
|
||||
title: redactKagiSessionToken(wc.getTitle() ?? ''),
|
||||
active: wcId === activeWcId,
|
||||
loadError,
|
||||
loadError: loadError
|
||||
? { ...loadError, validatedUrl: redactKagiSessionToken(loadError.validatedUrl) }
|
||||
: loadError,
|
||||
certificateFailure
|
||||
})
|
||||
}
|
||||
|
||||
@@ -88,6 +88,20 @@ describe('Kagi private initial navigation', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('queues a single bearer token when the link carries duplicates', () => {
|
||||
const modelUrl = 'https://kagi.com/search?q=private+project'
|
||||
queueKagiPrivateInitialNavigation(
|
||||
'page-duplicate',
|
||||
'https://kagi.com/search?token=first-secret&q=private+project&token=second-secret'
|
||||
)
|
||||
|
||||
expect(getKagiPrivateInitialNavigation('page-duplicate', modelUrl)).toEqual({
|
||||
modelUrl,
|
||||
navigationUrl: 'https://kagi.com/search?token=first-secret&q=private+project'
|
||||
})
|
||||
discardKagiPrivateInitialNavigation('page-duplicate')
|
||||
})
|
||||
|
||||
it('redacts a defensive model fallback', () => {
|
||||
const privateUrl = 'https://kagi.com/search?token=session-secret&q=private+project'
|
||||
|
||||
|
||||
@@ -25,13 +25,29 @@ function prunePendingNavigations(now: number): void {
|
||||
}
|
||||
}
|
||||
|
||||
// Why: queue the validator's canonical link so duplicate `token` params can't send a second bearer to Kagi.
|
||||
function canonicalizeKagiNavigationUrl(url: string): string | null {
|
||||
const normalized = normalizeKagiSessionLink(url)
|
||||
if (!normalized) {
|
||||
return null
|
||||
}
|
||||
const query = new URL(url).searchParams.get('q')
|
||||
if (query === null) {
|
||||
return normalized
|
||||
}
|
||||
const canonical = new URL(normalized)
|
||||
canonical.searchParams.set('q', query)
|
||||
return canonical.toString()
|
||||
}
|
||||
|
||||
export function queueKagiPrivateInitialNavigation(pageId: string, url: string): void {
|
||||
if (!normalizeKagiSessionLink(url)) {
|
||||
const canonicalUrl = canonicalizeKagiNavigationUrl(url)
|
||||
if (!canonicalUrl) {
|
||||
throw new Error('Expected a Kagi private-session URL.')
|
||||
}
|
||||
const now = Date.now()
|
||||
pendingNavigations.delete(pageId)
|
||||
pendingNavigations.set(pageId, { queuedAt: now, url })
|
||||
pendingNavigations.set(pageId, { queuedAt: now, url: canonicalUrl })
|
||||
prunePendingNavigations(now)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user