mirror of
https://github.com/stablyai/orca.git
synced 2026-11-15 10:27:33 +00:00
fix(browser): preserve backslashes in POSIX file paths (#42257)
On macOS and Linux a backslash is an ordinary filename character, but absolutePathToFileUrl converted every backslash into a path separator, so typing /tmp/site\draft.html opened /tmp/site/draft.html instead. Keep backslashes (encoded as %5C) for rooted paths when the local host is not Windows. On Windows every path still has backslashes normalized to slashes, so drive, UNC and rooted /foo\bar inputs behave as before. Fixes #42256 Co-authored-by: Neil <neil@stably.ai>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import {
|
||||
isEligibleLocalCertificateHost,
|
||||
@@ -43,6 +43,30 @@ describe('browser-url helpers', () => {
|
||||
expect(normalizeExternalBrowserUrl('about:blank')).toBeNull()
|
||||
})
|
||||
|
||||
describe('file path backslashes', () => {
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals()
|
||||
})
|
||||
|
||||
it('preserves backslashes as filename characters on POSIX hosts', () => {
|
||||
vi.stubGlobal('navigator', { userAgent: 'Linux' })
|
||||
expect(normalizeBrowserNavigationUrl('/tmp/site\\draft.html')).toBe(
|
||||
'file:///tmp/site%5Cdraft.html'
|
||||
)
|
||||
})
|
||||
|
||||
it('normalizes backslashes to separators on Windows hosts', () => {
|
||||
vi.stubGlobal('navigator', { userAgent: 'Windows' })
|
||||
expect(normalizeBrowserNavigationUrl('/foo\\bar.html')).toBe('file:///foo/bar.html')
|
||||
expect(normalizeBrowserNavigationUrl('C:\\site\\draft.html')).toBe(
|
||||
'file:///C:/site/draft.html'
|
||||
)
|
||||
expect(normalizeBrowserNavigationUrl('\\\\server\\share\\draft.html')).toBe(
|
||||
'file://server/share/draft.html'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
// Refuse file URLs externally: a remote page must not drive Finder/Explorer to arbitrary paths.
|
||||
it('rejects file:// for external opens even though it is allowed in-app', () => {
|
||||
expect(normalizeExternalBrowserUrl('file:///etc/passwd')).toBeNull()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import './constants'
|
||||
import { ORCA_BROWSER_BLANK_URL } from './browser/browser-blank-page'
|
||||
import { getCurrentLocalPlatform } from './execution-host'
|
||||
|
||||
const LOCAL_ADDRESS_PATTERN =
|
||||
/^(?:localhost|127(?:\.\d{1,3}){3}|0\.0\.0\.0|\[[0-9a-f:]+\])(?::\d+)?(?:[/?#].*)?$/i
|
||||
@@ -245,7 +246,9 @@ export function isAbsoluteFilesystemPathInput(input: string): boolean {
|
||||
}
|
||||
|
||||
function absolutePathToFileUrl(filePath: string): string {
|
||||
const normalizedPath = filePath.replaceAll('\\', '/')
|
||||
// Why: `\` is a filename char on POSIX but a separator on Windows, even in rooted paths like `/foo\bar`.
|
||||
const isPosixPath = filePath.startsWith('/') && getCurrentLocalPlatform() !== 'win32'
|
||||
const normalizedPath = isPosixPath ? filePath : filePath.replaceAll('\\', '/')
|
||||
const segments = normalizedPath.split('/').map((segment, index) => {
|
||||
if (index === 0 && /^[A-Za-z]:$/.test(segment)) {
|
||||
return segment
|
||||
|
||||
@@ -23,7 +23,7 @@ export type ParsedExecutionHost =
|
||||
| { kind: 'ssh'; id: `ssh:${string}`; targetId: string }
|
||||
| { kind: 'runtime'; id: `runtime:${string}`; environmentId: string }
|
||||
|
||||
function getCurrentLocalPlatform(): NodeJS.Platform | null {
|
||||
export function getCurrentLocalPlatform(): NodeJS.Platform | null {
|
||||
const globalNavigator = (globalThis as { navigator?: { userAgent?: string; platform?: string } })
|
||||
.navigator
|
||||
const userAgent = globalNavigator?.userAgent || globalNavigator?.platform || ''
|
||||
|
||||
Reference in New Issue
Block a user