Documentation
¶
Overview ¶
Package pairflow owns the device-pairing mint flow shared by the CLI (`gadak pairing`, GDK-433/450/797) and the desktop app's Devices tab (GDK-1047): endpoint resolution and validation, the scoped mint plus offer encode, the _home routing-token guard, list row shaping, and the two QR encodings (the terminal module matrix and the PNG a phone scans).
One owner so the surfaces cannot drift. The guard that motivates the extraction is ensureHomeRoutingToken: once one device token exists the serve gate takes Bearer only — no loopback bypass — so a mint that skips the home routing token locks the local-origin home out of its own passthrough. The CLI carried that guard; before this package the desktop would have had to copy it, and a copy is where a guard goes missing.
Presentation stays with the callers: this package returns values (the offer, the loopback flag, which _home action ran) and prints nothing.
Index ¶
- Constants
- func AdvertisedEndpoint(cfg *config.Config) string
- func DefaultTTLFlag() string
- func Dir(cfg *config.Config) (string, error)
- func EndpointFromAdvertise(addr string) string
- func GateOpen(dir string, now time.Time) bool
- func MintHome(dir string, cfg *config.Config, endpoint string, now time.Time) (pairing.Meta, error)
- func PairedLine(cfg *config.Config, rem *pairing.Remote) string
- func ParseTTL(s string) (time.Duration, error)
- func QRModules(offer string) ([][]bool, error)
- func QRPNG(offer string) ([]byte, error)
- func Revoke(dir, selector string, now time.Time) (pairing.Meta, error)
- type HomeRoutingAction
- type MintResult
- type Row
Constants ¶
const DefaultTTL = 90 * 24 * time.Hour
DefaultTTL is 90 days: a device token is revocable, so it does not need a short life, but an unattended one should not outlive a quarter by default either.
Variables ¶
This section is empty.
Functions ¶
func AdvertisedEndpoint ¶
AdvertisedEndpoint turns a live UI-serve listen address into the URL form endpoint validation wants. Discovery is origin.LiveServeFor, the single owner of the serveaddr walk. An explicit endpoint is not normalized: making the user name the scheme is the point.
func DefaultTTLFlag ¶
func DefaultTTLFlag() string
DefaultTTLFlag renders DefaultTTL in the <N><unit> syntax --ttl speaks, so the 90-day default has one owner.
func Dir ¶
Dir is the profile directory the token store lives in. Pairing protects both gated surfaces of a home serve — the origin passthrough (localOrigin, GDK-433) and the mirror REST a phone companion reads (GDK-797) — so both workspace kinds may mint; what stays closed for a connected workspace is the passthrough itself (origin_rest.go 404s it). A workspace that is itself paired away cannot mint: its home is another machine.
func EndpointFromAdvertise ¶
EndpointFromAdvertise upgrades the raw bind address the advertise file stores (host:port) to the URL form, leaving an address that already carries a scheme alone.
func GateOpen ¶
GateOpen reports whether the serve gate has fallen back open: no active token exists (including _home). The GDK-481 sentence callers print is theirs; this is the one boolean behind it.
func MintHome ¶
MintHome is `pairing mint --label _home`: routing-token rotation, not a device offer. No offer is produced. Local-origin only — a connected workspace writes go straight to its site, and the routing file here would make origin.pairedRemote read this workspace as paired with its own serve.
func PairedLine ¶
PairedLine is the self-status sentence a paired workspace gets where it tried to act as a home.
func ParseTTL ¶
ParseTTL accepts one integer with a single unit — "90d", "24h", "30m", "45s". time.ParseDuration rejects "d", and inventing compound syntax ("1d12h") is surface nobody asked for; a clear error beats guessing.
func QRModules ¶
QRModules encodes the offer at EC Medium and returns the module matrix, quiet zone included (the library default 4-module border). Medium rather than Lower: pairing happens once per device, and a code that scans from a phone held at an angle beats a dense one; higher than Medium buys almost nothing at this payload size.
func QRPNG ¶
QRPNG renders the offer QR as a PNG: white background, black modules, quiet zone included via the module matrix, square. The desktop serves it to the webview as a data URI; the geometry matches what the terminal half-block renderer draws, so both encodings are the same code.
Types ¶
type HomeRoutingAction ¶
type HomeRoutingAction string
HomeRoutingAction is what a mint did about the _home routing token.
const ( // HomeRoutingNone: the existing credential is valid, or the gate is // off, or the workspace is connected (no routing token by design). HomeRoutingNone HomeRoutingAction = "" // HomeRoutingMinted: this mint created the first _home credential. HomeRoutingMinted HomeRoutingAction = "minted" // HomeRoutingReissued: the stored credential was stale or revoked // while the gate was on (GDK-450 recovery). HomeRoutingReissued HomeRoutingAction = "reissued" )
type MintResult ¶
type MintResult struct {
Offer, Label, Scope, Endpoint, ExpiresAt string
Meta pairing.Meta
// LoopbackWarning says the endpoint is a loopback address — remote
// devices cannot reach it. The caller renders its own copy.
LoopbackWarning bool
// HomeRouting names what ensureHomeRoutingToken did, so the CLI can
// print its stderr note and the desktop can stay quiet.
HomeRouting HomeRoutingAction
}
MintResult is everything a mint produced. The offer is a credential: it exists here and in the caller output, never in a log or an error.
func MintDevice ¶
func MintDevice(dir string, cfg *config.Config, label, scope, ttl, endpoint string, now time.Time) (MintResult, error)
MintDevice is the device-mint flow: validate, resolve the endpoint, mint the scoped token, encode the offer, and — for a local-origin home — keep the _home routing token valid. Callers pre-validate their own input surface (flags, form fields); this function re-validates because it is the structural owner, not a trusted callee.
endpoint may be empty: a live serve for cfg's profile is then discovered via origin.LiveServeFor. ttl may be empty: DefaultTTL applies. On a failure after the token was minted (the routing-token step is the only one) the result still carries the offer: the plaintext exists exactly once, in the caller output, or a minted token would be stranded unrecoverable.
type Row ¶
type Row struct {
Hash string `json:"hash"`
Label string `json:"label"`
Scope string `json:"scope"`
Created string `json:"created"`
Expires string `json:"expires"`
LastUsed string `json:"last_used"`
State string `json:"state"`
}
Row is one pairing-list row. JSON tags are the table columns — never the plaintext token, never the full hash (only the 8-char prefix the list already showed).