Files
orca/src/main/window/renderer-document-navigation.ts
T
mirror 34fa2cd5ca
Skill update round trip / roundtrip (false, macos-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, macos-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, symlink, latest) (push) Canceled after 0s
Skill update round trip / roundtrip (false, windows-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, windows-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, macos-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, macos-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, ubuntu-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, ubuntu-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, windows-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, windows-latest, symlink, 1.5.17) (push) Canceled after 0s
source snapshot 2026-09-02
2026-09-02 02:03:16 +08:00

89 lines
2.7 KiB
TypeScript

import type { WebContents } from 'electron'
/**
* True when the target stays inside the window's own privileged document: for `file:`
* the exact same host+path (query/hash may differ, as a reload keeps them), for http(s)
* the same origin. Also gates preload privilege in installPrivilegedWindowNavigationPolicy,
* so loosening it past a same-origin document hands a foreign page the Orca bridge.
*/
export function isRendererDocumentNavigation(currentUrl: string, nextUrl: string): boolean {
try {
const current = new URL(currentUrl)
const next = new URL(nextUrl)
if (current.protocol === 'file:') {
return (
next.protocol === 'file:' &&
next.host === current.host &&
next.pathname === current.pathname
)
}
return (
(current.protocol === 'http:' || current.protocol === 'https:') &&
(next.protocol === 'http:' || next.protocol === 'https:') &&
next.origin === current.origin
)
} catch {
return false
}
}
export function registerRendererDocumentNavigation(
webContents: Pick<WebContents, 'getURL' | 'isLoadingMainFrame' | 'on'>,
onStarted: () => (() => void) | void
): void {
let documentGeneration = 0
let fenceGeneration = 0
let fenceActive = false
let cancelReload: (() => void) | null = null
const restoreSurvivingDocument = (): void => {
if (
!fenceActive ||
fenceGeneration !== documentGeneration ||
webContents.isLoadingMainFrame()
) {
return
}
fenceActive = false
const cancel = cancelReload
cancelReload = null
cancel?.()
}
// Why: did-start-loading also fires for blocked external links whose renderer document survives.
webContents.on('did-start-navigation', (_event, url, isSameDocument, isMainFrame) => {
if (isMainFrame && !isSameDocument && isRendererDocumentNavigation(webContents.getURL(), url)) {
if (!fenceActive) {
fenceActive = true
fenceGeneration = documentGeneration
cancelReload = onStarted() ?? null
}
}
})
webContents.on(
'did-fail-provisional-load',
(_event, _errorCode, _errorDescription, _validatedUrl, isMainFrame) => {
if (!isMainFrame) {
return
}
queueMicrotask(restoreSurvivingDocument)
}
)
webContents.on('will-navigate', (event, _url, _sameDocument, isMainFrame) => {
if (!isMainFrame) {
return
}
queueMicrotask(() => {
if (event.defaultPrevented) {
restoreSurvivingDocument()
}
})
})
webContents.on('did-stop-loading', restoreSurvivingDocument)
webContents.on('did-frame-navigate', (_event, _url, _code, _status, isMainFrame) => {
if (isMainFrame) {
documentGeneration += 1
fenceActive = false
cancelReload = null
}
})
}