You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
directory listing under the authorized external root
GET /api/escape/file/read?session_id=&token=&path=
:18123
file content
GET /api/escape/file/raw?session_id=&token=&path=
:14407
raw bytes
Blocker._handle_escape_authorize returns 403 "browser origin required" unless the request carries an Origin header, then runs _check_csrf, which for an authenticated browser-shaped request requires a CSRF token header that matches a cookie the browser receives. Hermex sends neither and has no CSRF cookie flow (HermesMobile/Networking/APIClient.swift). Faking an Origin to pass as a browser and reverse-engineering the CSRF pairing would be a spoof of upstream's deliberate guard, not a client feature.
What the maintainer needs to decide
Ask upstream for a non-browser path: either honor the session cookie alone for escape/authorize when no Origin is present (the same rule _check_csrf already applies to "non-browser clients"), or a dedicated token endpoint. File the request in nesquena/hermes-webui and link it here.
Or close this as wontfix: symlinked paths outside the workspace stay unreadable from the phone, which is the safe default.
If upstream lands a client path, the expected behavior is
In the file tree (feat(workspace): browse the workspace as a lazily loaded file tree #401), a symlink or entry whose target is outside the workspace shows a "Outside workspace" badge. Tapping it authorizes once per session and target, caches the token until expires_at, and browses external_root read-only with the same tree and viewer components. Nothing under an escape token is ever written.
Token expiry re-authorizes transparently on the next request.
Acceptance criteria (deferred until the decision)
Four Endpoint cases; token cached per server, session, and target with expiry.
Read-only enforced in the UI; no 14a or 15 actions under an escape root.
Two servers: tokens never cross servers.
Non-goals
Any workaround that sends a fabricated Origin or CSRF header.
Part of #395 (item 16). Filed
ready-for-humanwithupstream-change: the authorize step is browser-only at the pin.Context
POST /api/escape/authorize{ session_id, path }routes.py:18065→workspace.authorize_escape_target{ token, session_id, workspace_root, surface_path, external_root, external_entry_rel, surface_target, expires_at }(TTL_ESCAPE_AUTH_TTL_SECONDS)GET /api/escape/list?session_id=&token=&path=:18098GET /api/escape/file/read?session_id=&token=&path=:18123GET /api/escape/file/raw?session_id=&token=&path=:14407Blocker.
_handle_escape_authorizereturns 403 "browser origin required" unless the request carries anOriginheader, then runs_check_csrf, which for an authenticated browser-shaped request requires a CSRF token header that matches a cookie the browser receives. Hermex sends neither and has no CSRF cookie flow (HermesMobile/Networking/APIClient.swift). Faking anOriginto pass as a browser and reverse-engineering the CSRF pairing would be a spoof of upstream's deliberate guard, not a client feature.What the maintainer needs to decide
escape/authorizewhen noOriginis present (the same rule_check_csrfalready applies to "non-browser clients"), or a dedicated token endpoint. File the request innesquena/hermes-webuiand link it here.wontfix: symlinked paths outside the workspace stay unreadable from the phone, which is the safe default.If upstream lands a client path, the expected behavior is
expires_at, and browsesexternal_rootread-only with the same tree and viewer components. Nothing under an escape token is ever written.Acceptance criteria (deferred until the decision)
Endpointcases; token cached per server, session, and target with expiry.Non-goals
Any workaround that sends a fabricated
Originor CSRF header.