Pair a wall panel through the portal
A screen somewhere this installation is not reachable from asks the portal for a code instead, and the portal mints its credential — because a token signed here is one such a device could never present. Where it was minted changes nothing about what it may do. The panel gate moved off the branch that decodes a local panel token and onto whatever claims name a panel, so the portal's and this installation's are bounded by the same check against the same panel's dashboards. A token of that scope naming no panel is refused rather than left holding the account it borrows. The connector marks what arrives on its socket, since that is the only thing that makes it true, and the approval screen now names what is holding a code — approving adopts whatever answers, so it is worth a look first. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017F9RnYCJgASuBTcAjxmnsp
This commit is contained in:
+14
-12
@@ -310,18 +310,20 @@ Shares components with the admin view. See `docs/architecture/structure.canvas`
|
||||
dashboards overview, and the credential that mints is scoped to that
|
||||
panel's dashboards and the message endpoints its widgets speak. Deleting
|
||||
the panel revokes it
|
||||
- [ ] Pair a panel through the portal, for a screen hanging somewhere the
|
||||
installation is not reachable from. Three gates today: the hub's app shell
|
||||
redirects a browser carrying no portal session, its proxy authorizes before
|
||||
forwarding so the unauthenticated pairing call never crosses the tunnel,
|
||||
and the app under a portal takes its bearer from the injected config rather
|
||||
than from storage. A hub token with a `panel` scope opens all three —
|
||||
`decode_portal_token` already branches on scope, and `_panel_may` then
|
||||
applies unchanged, so the installation stays the authority on what the
|
||||
panel reads. The owner check in the hub's `_authorize` is what a panel
|
||||
token must not fall through, and the rate-limit key beside it assumes a
|
||||
user id too. Milestone-level rationale, and the alternative worth weighing
|
||||
first, are in `docs/private/roadmap.md` § M5
|
||||
- [x] Pair a panel through the portal, for a screen hanging somewhere the
|
||||
installation is not reachable from. A fourth hub token class, `scope=panel`,
|
||||
named by panel instead of by person: it passes the hub's `_authorize`
|
||||
without the owner check no panel could satisfy, and arrives here through
|
||||
`decode_portal_token` carrying the panel, where the same `_panel_may` that
|
||||
bounds a locally paired screen bounds it. The installation asks for it
|
||||
holding the credential it dials the tunnel with, so the portal decides
|
||||
nothing but which installation it is for. The three gates opened one each:
|
||||
the shell serves `/panel` alone without a session, the proxy forwards the
|
||||
two pairing calls without one — rate-limited per installation and per
|
||||
address, and stripped of any bearer the browser tried to send — and the
|
||||
credential is traded for the hub's cookie rather than carried in the URL a
|
||||
year-long token must never sit in. What is waiting on a code is named
|
||||
before anyone approves it
|
||||
|
||||
## Phase 5 — Website and docs
|
||||
|
||||
|
||||
Reference in New Issue
Block a user