The Secret Key encoder used 26 base-30 characters which can only
represent 30^26 ≈ 2^127.58 values. Since the key is 128 bits,
~25% of generated keys silently lost their high bits during
formatting, making the Emergency Kit key unable to reconstruct
the original bytes on a new browser.
Changed KEY_CHAR_LENGTH from 26 to 27 (30^27 > 2^128). Parser
accepts both old 26-char and new 27-char keys for backward
compatibility. Format: A3-XXXXXX-XXXXXX-XXXXXX-XXXXXX-XXX
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The target input showed "8.8.8.8" as placeholder text but the actual
value was empty. Clicking Ping/Traceroute silently returned because
the empty target guard fired. Users saw the placeholder and assumed
the tool was broken.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The server-generated PDF had a placeholder for the Secret Key that was
never filled in client-side, making the Emergency Kit useless. Users
who relied on it could not recover their Secret Key on new devices.
Now generates the PDF entirely client-side via browser print dialog,
with the real Secret Key embedded. No server round-trip, key never
leaves the browser.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a user logs in from a browser with an outdated Secret Key in
IndexedDB (e.g. after server rebuild/re-enrollment), the SRP handshake
fails with 401 but the Secret Key input field was never shown — leaving
the user stuck with no way to enter their current key.
Now detects stale-key 401s and prompts for manual Secret Key entry.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The FleetTable empty state navigated with ?add=true but the devices page
never read that param. Now it opens the AddDeviceForm when add=true is
in the search params.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>