The setup wizard was 1205 lines in a single file. Extract the
state-independent helpers (escapeHtml, ratePassphrase, scheduleRate,
entropyText, STRENGTH_LABELS, the Strength interface) into a sibling
setup-helpers.ts. updateStrengthUi stays in setup.ts since it walks the
live wizard state object and would force every caller to thread that
state through.
setup.ts: 1205 → 1137 lines. Pure mechanical extraction; no behavior
change. Existing tests are the safety net (24 vitest files, all pass).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Mirrors Step 3b's discipline. Previously, if save_setup failed or addDevice
threw, state.verifiedHandle (the WASM session from Step 3b) would remain
in linear memory until tab close. Now lock+null on every exit path.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace placeholder renderStep3Attach/attachStep3Attach with the real
attach flow: file-picker for reference JPEG, passphrase input with
visibility toggle, then fetch salt+params+manifest.enc, call
unlock()+manifest_decrypt() to AEAD-verify credentials before
advancing to Step 4. Wrong passphrase/image shows a clear error;
partial handles are locked on failure to avoid key-material leaks.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add default_vault_settings_json() to the hand-written wasm.d.ts
declarations, then use it in attachStep3New to encrypt and push
settings.enc after manifest.enc during new-vault creation. Wizard-
created vaults now have all four files the SW expects (salt,
params.json, manifest.enc, settings.enc), preventing the
get_vault_settings 404 on first unlock.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the placeholder Step 0 with two clickable mode-card buttons (create
new vault / attach this device). Picking a card highlights it and enables
the next button; the back button on Step 1 returns to Step 0 without losing
state. Add .mode-card CSS using the existing dark palette (#30363d, #58a6ff).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Expand WizardState with mode/vaultProbe/referenceImageBytesAttach/
verifiedHandle/attaching fields; start wizard at step 0; grow progress
bar to 6 segments; rename renderStep3/attachStep3 to *New variants;
add placeholder renderStep0/attachStep0/renderStep3Attach/attachStep3Attach.
No behaviour change for the existing new-vault flow.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New step 4 after vault creation: enter device name (defaults to
"Chrome on Linux" based on detected browser/OS). Generates ed25519
keypair, stores private key in chrome.storage.local, registers
device with vault. Wizard is now 5 steps (was 4).
Also adds generate_device_keypair() to wasm.d.ts type declarations.
Co-Authored-By: Claude <noreply@anthropic.com>
Setup wizard step 3 now has self-explanatory passphrase feedback:
- Strength meter: 5 segments with smooth color transitions
(very-weak/weak/fair/good/strong). Tier 4 gets a subtle glow.
- Nuanced label (lowercase, tracked): "very weak" / "weak" / "fair" /
"good" / "strong" — color-matched to each tier.
- Entropy readout line: "~10^N guesses — <time to crack>" with
tiered shorthand (trivial / minutes-on-GPU / hours-to-days /
years-on-consumer / beyond consumer / uncrackable).
- Live char counter in the strength row.
- Eye toggle buttons on both passphrase fields. Flip type="password"
<-> type="text" without re-render, preserving focus + cursor.
- Live match indicator (✓ / ✗) between the confirm field and its eye
toggle. Updates per keystroke.
- Create button gate widened: now requires score >= 3 AND confirm
field filled AND confirm matches. Disabled button carries a
tooltip saying which condition failed.
- Contextual help box above the passphrase field explaining the
"long phrase > complex password" idea + the score >= 3 threshold.
All live-update paths (counter, label, entropy, match indicator,
button gate) go through updateStrengthUi() which targets the DOM
directly — no full re-render, so focus/cursor survive every keystroke.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bug: setup tab's zxcvbn meter silently stayed at score=-1 because the
router's isSetup exception only allowed save_setup, so rate_passphrase
got unauthorized_sender. Result: the "create vault" button stayed
disabled forever even with a strong passphrase.
Fix: add a narrow SETUP_ALLOWED set containing save_setup,
rate_passphrase, and is_unlocked (step-4 extension detection). Reject
everything else from the setup tab. Also clean up setup.ts's unlock
call — it was passing the raw 32-byte imageSecret where JPEG bytes with
embedded secret are required; the Rust-side unlock calls imgsecret::
extract internally.
Diagnostic logging across the message path so the next silent failure
speaks up:
- [relicario setup] staged logs through vault-init; console.error
with the failure stage name in the UI banner.
- [relicario setup] rate_passphrase lastError / rejected / threw
branches each log their own warning.
- [relicario router] console.warn on unauthorized_sender (with sender
classification) and unknown_message_type.
- [relicario sw] first-message wasm init announced; per-message
non-ok result logged; thrown errors console.error'd.
Tests: +3 setup-allowlist tests (rate_passphrase accepted, is_unlocked
accepted, fill_credentials + unlock rejected). 55/55 green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the ad-hoc char-class passphraseStrength() with a 5-segment
bar backed by a SW round-trip to rate_passphrase (zxcvbn). Input
handler debounces 150ms so we don't hammer the worker per keystroke.
The create-vault button is disabled unless the last score is ≥ 3
(zxcvbn's "safely unguessable" threshold), and the handler re-rates
synchronously on click as defence-in-depth. Label flips between "Too
weak" (red) and "Strong enough" (green).
Also:
- rewrites the vault-creation path to use the typed-item unlock +
manifest_encrypt APIs (derive_master_key/encrypt_manifest are gone);
the new initial manifest is { schema_version: 2, items: {} }.
- wasm.d.ts is now a pure `declare module 'relicario-wasm'` block;
tsconfig's stale `paths` alias is removed.
- @ts-nocheck removed from setup.ts.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>