hub v0.66.0 + ISO v1.20.0: customer self-bind (R-27 slice 1)
Let a customer bind their own freshly-installed appliance without the operator: operator "Send self-bind link" mints a 7-day tokenized capability link, emailed (Hungarian, sibling sender) to the customer, who opens a public /bind/<token> page and proves two factors — the console pairing code shown on the box screen + their retrieval passphrase — and the hub stages the bind via the same BindAppliance (provenance customer_selfbind). The box's ~30s appliance poll delivers. Viktor's three rulings verbatim: console pairing code (no appliance list ever rendered), operator-sent tokenized link, 5-attempt lockout -> "call support". Wrong code == wrong passphrase (one generic failure, no oracle, both factors compared unconditionally); expiry falls back to operator-bind unchanged. THE TRAP: one public prefix /bind/, exempt from auth+CSRF at both /login gate sites via a single isPublicBindPath predicate (tight trailing-slash match; ServeMux ..-cleans; handler rejects '/' in token). 9 tests (Scenarios A-F + F1/F2); 4 red-proofs verified red-then-green (lockout, oracle, widened-prefix, single-active). GC verdict: no appliance GC -> the 7-day TTL stands alone. Controller/agent untouched; R-27b deferred. Green: full hub build/vet/test (17 ok) + bash -n + hub confirm gate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017qDiBqKKQ5vPB5fXBqu7Kp
This commit is contained in:
@@ -39,7 +39,7 @@
|
||||
<div style="overflow-x: auto;">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr><th>Appliance</th><th>MACs</th><th>Hardware</th><th>SSH host keys</th><th>Seen</th><th>Bind to customer</th><th></th></tr>
|
||||
<tr><th>Appliance</th><th>Pairing code</th><th>MACs</th><th>Hardware</th><th>SSH host keys</th><th>Seen</th><th>Bind to customer</th><th></th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .Unclaimed}}
|
||||
@@ -48,6 +48,7 @@
|
||||
{{if .Stale}}<br><span class="status-badge status-warn" title="No poll in over 7 days">stale</span>{{end}}
|
||||
{{if .Bound}}<br><span class="status-badge status-ok" title="Bound — awaiting the box's next poll">bound → {{.BoundCustomer}}</span>{{end}}
|
||||
</td>
|
||||
<td style="font-family: var(--font-mono); letter-spacing: 0.05em;">{{if .PairingCode}}<strong>{{.PairingCode}}</strong>{{else}}<span class="text-muted">—</span>{{end}}</td>
|
||||
<td style="font-size: 0.78em; font-family: var(--font-mono)">{{range .MACs}}{{.}}<br>{{end}}</td>
|
||||
<td style="font-size: 0.8em;">{{if .Product}}{{.Product}}<br>{{end}}{{if .CPU}}<span class="text-muted">{{.CPU}}</span><br>{{end}}{{if .MemGB}}<span class="text-muted">{{.MemGB}}</span>{{end}}</td>
|
||||
<td style="font-size: 0.72em; font-family: var(--font-mono)">{{range .SSHFingerprints}}{{.}}<br>{{end}}</td>
|
||||
|
||||
Reference in New Issue
Block a user