mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-28 12:12:47 +00:00
Multiplex logical sessions over the monitored daemon connection and wrap original binary bytes in routing headers. Admit channels under their authenticated parent and current grants; preserve scoped delivery and physical send completion.
66 lines
4.5 KiB
Markdown
66 lines
4.5 KiB
Markdown
# Connected hosts
|
|
|
|
A saved host belongs to the daemon that stores it. The app's saved connections remain a separate list.
|
|
Connect A to B in A's settings under **Hosts connected to this daemon**, through `paseo --host A host`,
|
|
or through `paseo.hosts`. Consumers select B by its learned `serverId`; management uses the stable
|
|
`registrationId` created before B is reachable.
|
|
|
|
## Ownership and authority
|
|
|
|
Credentials live in A's `hosts.json`, written atomically with mode `0600` on POSIX systems. Discovery returns a safe
|
|
target description. Replacement inputs never come back through a read API. Keep this file private
|
|
when collecting diagnostics or backing up daemon state.
|
|
|
|
The authenticated producer owns its source key. Repeating an unchanged add returns the saved entry,
|
|
including a user's disabled state. Changed input requires an explicit update. Display labels and
|
|
access can be changed by users with `tunnel.manage`; connection and metadata changes require the
|
|
producer or `access.manage`. Removing a producer-managed entry allows that producer to add it again.
|
|
Disabling retains the opt-out.
|
|
|
|
Each enabled registration owns one physical daemon link, shared by status monitoring and every
|
|
routed API scope. Each scope owns an isolated virtual session on B. A derives its identity from the
|
|
admitted origin session, producer, and logical SDK scope. B admits virtual sessions under the actual
|
|
physical link principal, then intersects forwarded caller grants with that link's current authority.
|
|
Changing or resuming a parent's grants closes its existing channels; reconnect re-admits demand with
|
|
current authority. A routed API cannot select a second hop, and saving a host grants no reverse access.
|
|
|
|
A producer that registers a host through a routed API is qualified on B as
|
|
`route:<B principal>:<A serverId>:<A producer>`, with each component percent-encoded. This namespace belongs to the authenticated link
|
|
principal. An ordinary direct B consumer does not become that producer by supplying a source key.
|
|
The optional `server_info.sourceId` reports this producer identity for source-owner controls; it does not describe the authenticated admission principal.
|
|
Trusted server plugins retain the authority of their runtime; they are not sandboxed by this feature.
|
|
|
|
## Connections and recovery
|
|
|
|
The shared Node connector owns the target grammar and each connection attempt, including a fresh
|
|
SSH process. SSH reaches an already running daemon. The shared client connection lifecycle owns
|
|
physical reconnect and keepalive; the registry retains configuration, identity acceptance, and recovery
|
|
status. Unreachable registrations remain saved. Identity is pinned when discovered. Self and duplicate
|
|
registrations remain inspectable; a changed destination requires explicit identity replacement.
|
|
|
|
Both daemons advertise `connectedHosts`; the shared link additionally requires `hostMultiplexing`.
|
|
A completes capability and pinned-identity checks on each physical recovery before admitting channels. There is no local fallback. An older daemon continues to serve existing local
|
|
operations; requesting this feature gives update guidance.
|
|
|
|
Disposing a routed API releases its observations and session. It does not remove the saved host or
|
|
affect sibling API scopes. Disposing the origin cascades to its derived scopes. Observations restore
|
|
through the usual owned-subscription contract; requests made while offline fail. Losing a response
|
|
returns `outcome_unknown` with the destination ID. Inspect the destination before retrying a mutation.
|
|
No mutation is automatically replayed.
|
|
|
|
Text session envelopes carry a channel identifier. Binary routing adds an opcode, a bounded UTF-8
|
|
channel identifier, and the original terminal or file-transfer bytes. It never converts those bytes to
|
|
base64 JSON. The existing direct binary opcodes and 100 MiB message limit remain unchanged; routed
|
|
payloads reserve space for the routing header inside that limit. Relay encryption retains its own
|
|
existing frame limit.
|
|
|
|
Host links cap saved registrations, simultaneous channels, handshake lifetime, frames, physical
|
|
output, and aggregate queued bytes. Capacity checks use the actual escaped outer JSON or binary
|
|
frame size. Awaitable output completes when the physical send completes. An overflowing channel
|
|
closes without closing siblings or the saved link. Routed sessions release resources on disconnect;
|
|
subscription demand is rebuilt by its owning client on reconnect.
|
|
|
|
See the [SDK reference](../public-docs/sdk/reference.md#clienthosts),
|
|
[CLI reference](../public-docs/cli.md#connected-hosts), and
|
|
[plugin reference](../public-docs/plugins/reference.md#connected-hosts).
|