Skip to content

v1.2.9 — the desktop panel can reach its own API again

Choose a tag to compare

@stallenlu stallenlu released this 09 Nov 19:06
· 3 commits to main since this release

fix: let the desktop panel reach its own API

1.2.7 tightened sameOrigin to refuse any request without an Origin header, on
the reasoning that a browser POST to the panel always carries one. That is true
for a browser. It is false for the desktop app, and the difference is invisible
from the server side, so the release shipped a panel that could not talk to its
own backend: every request came back 403 origin rejected and the status card
sat on "not running / external".

The desktop app does not load the web UI over http. It serves it from a custom
dsh-app:// scheme and proxies the panel's requests through its own forwarder,
which deletes origin and host from the forwarded headers and re-adds only
the session cookie. So the plugin receives a POST with no Origin at all — and
even a build that keeps the header sends dsh-app://app, which no http://
comparison can ever match. Both shapes were refused.

The guard now asks where the request came from rather than only what it claims:

  • no Origin, or null -> allowed only on a loopback Host
  • dsh-app://... -> allowed only on a loopback Host
  • any other Origin -> must still equal the Host

Nothing is loosened for the case the check exists for. A web page cannot reach a
loopback port without an Origin, Origin is set by the user agent and cannot be
forged, and the desktop scheme can only be served by the harness itself. The
remote-host branches are refused exactly as before.

The regression test asserts behaviour instead of grepping for a source string:
the old check was written as assert.match(index, /typeof origin !== 'string'/),
so shipping the bug kept the test green. It now calls sameOrigin with the real
header shapes — no Origin, null, dsh-app://app, dsh-app://shell, a browser
same-origin POST, plus six refusals — which would have failed on 1.2.7 and does
fail if the loopback gate is dropped.