Bound a panel credential to its own widgets, and let one screen be re-paired
Three things a paired wall panel needed.
The scope check now walks the panel's widgets instead of allowing the
`/messages/` prefix wholesale: a screen may publish what its own controls and
querying charts point at, read the history of what its tiles draw, and nothing
else — the catalogue of every message in the installation included. The same
walk that already bounds its socket, so both surfaces agree.
Pending pairing codes moved out of the per-process dictionary into Redis, keyed
per code with the code's own TTL and indexed in a zset so the fifty-code cap
means the same thing to every worker. Without a Redis there is one process by
definition, and the dictionary stays.
And a per-panel nonce in the token, bumped by `POST /panels/{id}/unpair`: that
refuses the screen hanging there without touching the panel, its dashboards or
their arrangement. A save cannot write the nonce back, so a stale client cannot
undo a revocation. Only for a credential this installation signed — one the
portal minted carries no nonce and is revoked at the hub.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018tULRZJUkZsw7rMJ3h4xvu
This commit is contained in:
@@ -146,6 +146,7 @@ code normally reaches these through `fluksio.save_artifact` /
|
||||
| `GET` `PUT` | `/panels/` | which device shows which dashboards |
|
||||
| `POST` | `/panels/pair` | start a pairing |
|
||||
| `GET` | `/panels/pair/{code}` | what is holding a code |
|
||||
| `POST` | `/panels/{id}/unpair` | drop this panel's credential, keep the panel |
|
||||
|
||||
## Secrets, modules, alerts
|
||||
|
||||
|
||||
@@ -100,13 +100,18 @@ A wall tablet has no keyboard, so it pairs.
|
||||
up within a few seconds and never asks again.
|
||||
|
||||
What the screen holds is not a login. It reaches that panel's published
|
||||
dashboards and the message endpoints its widgets speak, and nothing else.
|
||||
dashboards and the messages its own widgets read or publish, and nothing else —
|
||||
a message no tile on it draws is refused in both directions.
|
||||
|
||||
It cannot be made strictly read-only, and that is honest rather than an
|
||||
oversight: a querying chart publishes its request, and a control on a panel is
|
||||
the reason you put one there. Deleting the panel revokes the credential, which
|
||||
is also how you retire a device — the screen falls back to asking for a new
|
||||
code.
|
||||
the reason you put one there.
|
||||
|
||||
Deleting the panel revokes the credential and the assignment together, which is
|
||||
how you retire a device and what it showed. Unpairing revokes only the
|
||||
credential: the panel, its dashboards and their arrangement stay exactly where
|
||||
they are, and the screen falls back to asking for a new code — which is how you
|
||||
swap the device out without rebuilding what hangs there.
|
||||
|
||||
!!! note "If the link is wrong"
|
||||
|
||||
@@ -128,7 +133,9 @@ The portal names the panel and nothing else. What the panel may read is decided
|
||||
on the installation, on every call, by the same check a locally paired screen
|
||||
passes. Two differences: it acts as the account the installation was enrolled
|
||||
with rather than as whoever approved it, and deleting the panel stops it here
|
||||
immediately while the portal's copy of the token expires on its own.
|
||||
immediately while the portal's copy of the token expires on its own — which is
|
||||
also why unpairing, which works on a credential this installation signed, does
|
||||
not reach a remote screen. Revoke that one at the hub.
|
||||
|
||||
## See also
|
||||
|
||||
|
||||
Reference in New Issue
Block a user