fix(desktop): refuse a foreign backend's session token after readiness
The served-token fallback adopts whatever token the dashboard HTML injects. That is correct when our own child regenerated the token (env pin lost across a shell-wrapped spawn), but wrong when the readiness probe answered from a process we did not spawn: /api/status is public, so an orphaned dashboard squatting the port passes waitForHermes while our child dies on the bind conflict. Silently adopting that process's token would authenticate the renderer against a foreign backend, possibly on the wrong profile. Discriminate on child liveness: the desktop pins HERMES_DASHBOARD_SESSION_TOKEN on every spawn, so a live child always serves our token. Served-token mismatch + dead child = foreign backend; fail the boot loudly instead of connecting. Mismatch + live child keeps the adopt-served-token salvage from #43720.
This commit is contained in:
@@ -12,6 +12,7 @@ const {
|
||||
dashboardIndexUrl,
|
||||
extractInjectedDashboardToken,
|
||||
fetchPublicText,
|
||||
isForeignBackendToken,
|
||||
resolveServedDashboardToken
|
||||
} = require('./dashboard-token.cjs')
|
||||
|
||||
@@ -87,3 +88,23 @@ test('resolveServedDashboardToken propagates fetch errors so callers can fall ba
|
||||
test('fetchPublicText rejects unsupported protocols', async () => {
|
||||
await assert.rejects(() => fetchPublicText('file:///tmp/index.html'), /Unsupported Hermes backend URL protocol/)
|
||||
})
|
||||
|
||||
test('isForeignBackendToken flags a mismatched token from a dead child', () => {
|
||||
assert.equal(isForeignBackendToken({ servedToken: 'other', spawnToken: 'mine', childAlive: false }), true)
|
||||
})
|
||||
|
||||
test('isForeignBackendToken trusts a mismatched token while our child is alive', () => {
|
||||
// Live child + different token = our own backend regenerated the token
|
||||
// because the env pin did not survive the spawn. Adopting it is correct.
|
||||
assert.equal(isForeignBackendToken({ servedToken: 'other', spawnToken: 'mine', childAlive: true }), false)
|
||||
})
|
||||
|
||||
test('isForeignBackendToken trusts a matching token regardless of liveness', () => {
|
||||
assert.equal(isForeignBackendToken({ servedToken: 'mine', spawnToken: 'mine', childAlive: false }), false)
|
||||
assert.equal(isForeignBackendToken({ servedToken: 'mine', spawnToken: 'mine', childAlive: true }), false)
|
||||
})
|
||||
|
||||
test('isForeignBackendToken ignores an absent served token', () => {
|
||||
assert.equal(isForeignBackendToken({ servedToken: null, spawnToken: 'mine', childAlive: false }), false)
|
||||
assert.equal(isForeignBackendToken({ servedToken: '', spawnToken: 'mine', childAlive: false }), false)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user