Skip to content

Commit ba3f021

Browse files
committed
fix(desktop): allow private self-hosted origins
Classify only the configured self-hosted hostname as public address space so Chromium Local Network Access checks do not reject the main navigation. Keep the process-wide checks enabled for arbitrary browser destinations.
1 parent 6c0e6ee commit ba3f021

3 files changed

Lines changed: 35 additions & 0 deletions

File tree

‎apps/desktop/src/main/config.test.ts‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { tmpdir } from 'node:os'
33
import { dirname, join } from 'node:path'
44
import { describe, expect, it } from 'vitest'
55
import {
6+
addressSpaceOverrideForOrigin,
67
canonicalOrigin,
78
createConfigStore,
89
DEFAULT_ORIGIN,
@@ -42,6 +43,17 @@ describe('partitionForOrigin', () => {
4243
})
4344
})
4445

46+
describe('addressSpaceOverrideForOrigin', () => {
47+
it('marks only self-hosted deployment hosts as public', () => {
48+
expect(addressSpaceOverrideForOrigin('https://sim.internal.example')).toBe(
49+
'sim.internal.example=public'
50+
)
51+
expect(addressSpaceOverrideForOrigin('https://192.168.50.173')).toBe('192.168.50.173=public')
52+
expect(addressSpaceOverrideForOrigin('https://www.sim.ai')).toBeNull()
53+
expect(addressSpaceOverrideForOrigin('http://localhost:3000')).toBeNull()
54+
})
55+
})
56+
4557
describe('canonicalOrigin', () => {
4658
it('keeps a rewritten install on its existing cookie partition', () => {
4759
// The whole point of rewriting rather than leaving the apex in place: the

‎apps/desktop/src/main/config.ts‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,24 @@ export function isSimCloudOrigin(origin: string): boolean {
203203
}
204204
}
205205

206+
/**
207+
* Chromium's Local Network Access checks reject a top-level navigation when a
208+
* self-hosted deployment name resolves to RFC1918 space, before Electron can
209+
* show a permission prompt or the request reaches the server. The configured
210+
* Sim origin is an explicit trust decision and already owns the shell's preload
211+
* bridge, so classify only that hostname as public instead of disabling the
212+
* process-wide checks that protect arbitrary browser tabs.
213+
*/
214+
export function addressSpaceOverrideForOrigin(origin: string): string | null {
215+
try {
216+
const host = new URL(origin).hostname.toLowerCase()
217+
if (isLoopbackHostname(host) || isSimCloudOrigin(origin)) return null
218+
return `${host}=public`
219+
} catch {
220+
return null
221+
}
222+
}
223+
206224
/**
207225
* Maps a server origin to its cookie/storage partition. Each origin gets an
208226
* isolated persistent partition so sessions never leak across instances.

‎apps/desktop/src/main/index.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ import { NativeComputerUseClient } from '@/main/computer-use/native-client'
6161
import { ComputerUseService } from '@/main/computer-use/service'
6262
import {
6363
APP_NAME_FOR_CHANNEL,
64+
addressSpaceOverrideForOrigin,
6465
channelForOrigin,
6566
createConfigStore,
6667
DEFAULT_ORIGIN,
@@ -147,6 +148,10 @@ function main(): void {
147148

148149
const userDataPath = app.getPath('userData')
149150
const config = createConfigStore(join(userDataPath, 'settings.json'))
151+
const addressSpaceOverride = addressSpaceOverrideForOrigin(config.getOrigin())
152+
if (addressSpaceOverride) {
153+
app.commandLine.appendSwitch('ip-address-space-overrides', addressSpaceOverride)
154+
}
150155
setShellTheme(config.get('themeBackground'))
151156
initializeAccountDataRecovery(join(userDataPath, 'account-data-teardown-required.json'))
152157
const recoveryOrigin = getAccountDataTeardownOrigin()

0 commit comments

Comments
 (0)