# Changelog ## v0.6.0 — 2026-05-30 Rolls up four weeks of post-v0.5.0 work into one tag: the Phase 2B polish foundation, the v0.5.1 train (Streams A/B/C — 3-column vault layout, left-nav settings, Recovery QR), the 1C-γ slice (Document type, attachments, device registration from popup, trash & history UI), the Plan B multi-stream refactor (Cycles 1+2), the vault-tab management surfaces revamp, and the doc-structure redesign. The in-flight scope outgrew the original v0.5.1 plan, so this cuts as a minor bump. ### Added - **Recovery QR — 1-of-2 disaster-recovery path.** `image_secret` is encrypted under an Argon2id-derived key from the passphrase, packed into a 109-byte binary payload (magic `RREC` + version 0x01 + salt + nonce + AEAD ciphertext), and rendered as a QR code that is never written to disk. Surfaces: - Rust core: `relicario-core/src/recovery_qr.rs` — `generate_recovery_qr` / `unwrap_recovery_qr` / `recovery_qr_to_svg`. Production KDF params (`m=64MiB, t=3, p=4`) live behind a private-fields type so they cannot drift. - WASM: `generate_recovery_qr` / `unwrap_recovery_qr` exported; the session now stashes `image_secret` so the QR can be regenerated without re-running steganography extraction. - CLI: `relicario recovery-qr generate` (TTY render) and `relicario recovery-qr unwrap` subcommands. - Extension: three-state Security settings card (no QR → amber warning; QR exists → green status + show/regenerate; explicit view → modal with print). - Setup wizard: skippable "generate before you go" banner on the final step. - **Document item type.** New typed item for storing a signed document with a primary attachment. Form takes signature + signed-on date; detail view renders a signature-block layout. Wired into the popup add/view/edit dispatchers. Refuses to drop its primary attachment (use `purge` instead). - **Attachments end-to-end.** Service worker uploads attachments via the GitHost putBlob path (GitHub + Gitea Git Data API with fallback); popup attachments-disclosure component handles add/remove/download inside all six item-type forms; `📎` indicator shows on item-list rows that have attachments. Per-vault attachment bytes cap is enforced both at attach-time and during backup restore. - **Device registration from the popup.** "Register this device" triggers an inline name input + WASM keypair generation + persisted device entry — no setup-wizard detour. - **Trash + field-history UI.** Trash view shows per-item purge countdown with restore / per-item purge / empty-all actions. Field-history view groups changes per field with reveal/copy glyph buttons. New top-level item-history-index pane lists every item that has captured history. `#history/` route normalizes the legacy `#field-history/` URL form. - **3-column fullscreen vault tab.** Sidebar (200px, type-category nav) + list (flex) + detail drawer (440px, slides in on row click). Below 720px the drawer pushes the list full-pane. Bottom sheet for "new item" type picker uses a pane-only scrim so the sidebar stays interactive. - **Left-nav settings page.** Replaces the flat settings dump. Sections grouped Device (Autofill, Display — password coloring) vs Vault (Security — Recovery QR + trusted devices, Generator, Retention, Backup, Import). The standalone Devices sidebar entry is subsumed into Security. - **Two-column login form in fullscreen.** Identity (title / URL / group) and Credentials (username / password / TOTP) render as side-by-side glass cards above 720px viewport; single-column at narrow widths. Notes / custom sections / attachments stay full-width below the grid. Sticky save bar at the bottom of the form pane; header shows title + dirty subtitle ("unsaved · esc to cancel" or "no changes") + platform-aware save hint (⌘+S / Ctrl+S). - **Polish vocabulary.** Patina gold palette tokens (`--gold-base` `#a88a4a` replacing the brighter `#d2ab43`), `.surface-backdrop` (subtle radial top-glow + 18px grid texture) applied to popup body / setup body / vault body, `.glass` card class with `backdrop-filter: blur(8px)`, `.btn-primary` / `.btn-secondary` button hierarchy, and `GLYPH_NEXT = '▸'` replacing ASCII `→` in next/continue buttons. - **Vault lock-screen logo.** `` added to the lock-screen render for parity with the popup unlock view and the setup wizard. - **Setup wizard Style C.** Centered hero card + colored progress track + glyph mode icons, replacing the prior vertical glass-card wizard. - **Toast notification system.** Shared `showToast(message, type, durationMs)` at `extension/src/shared/toast.ts`. Used for sync success/failure, copy confirmation, device registration result. Replaces the ad-hoc `sync-status` div. - **Empty-state treatments.** Popup item list (vault empty / search returns nothing), vault list (section empty) — each gets a centered glyph + headline + hint. - **Per-type glyph icons in popup item rows.** `◉ login`, `◫ secure_note`, `⊡ totp`, `▭ card`, `⌬ identity`, `⊹ key`, `≡ document`. ### Changed - **Vault-tab management surfaces revamp (2026-05-24..05-30).** Settings pane splits synced (cross-device via Chrome storage) from local (per-browser) controls and gains a session-timeout UI. Devices pane shows SHA-256 fingerprint + added-by display + inline two-step revoke confirm via glyph button. Trash pane shows per-item purge countdown via `daysUntilPurge`. Field-history pane gets section headers and reveal/copy glyph buttons. New shared utilities: `relative-time.ts` (consolidating five duplicate inline copies), webcrypto `ssh-fingerprint.ts`, shared section-header / glyph-btn / kv-row / fingerprint CSS. - **Emoji sweep.** Every remaining UI emoji replaced with a monochrome glyph constant from `shared/glyphs.ts`. The pop-out button is now `⧉` (U+29C9, `GLYPH_VAULT_TAB`) instead of `⤴`. - **License switched to GPL-3.0-or-later.** Was MIT for the early prototype phase. License headers + `AUTHORS` + crate `Cargo.toml` authors updated. - **AttachmentId expanded to 128 bits with `is_valid` check.** Backup restore now validates IDs (audit I2 / B4). - **Per-vault attachment bytes cap enforced.** Both CLI attach and backup restore (audit I3). ### Internal - **Plan B multi-stream refactor (Cycles 1+2).** CLI `main.rs` split into per-command modules under `crates/relicario-cli/src/commands/` with a shared `git_run` helper. New `prompt_or_flag` and `prompt_or_flag_optional` helpers compress all the `build_*_item` helpers. `Vault::after_manifest_change` wrapper plus a single canonical `ParamsFile` in the session avoid duplicated file-system rebuilds. Core/WASM seam: `base32_decode_lenient`, `parse_month_year`, `guess_mime` exported from WASM; CLI parsers migrated to `relicario-core::parse`. Extracted `base32` module from core, deduplicated two RFC-4648 implementations. - **Doc-structure redesign (2026-05-30).** Renamed `ARCHITECTURE.md` → `DESIGN.md`, `docs/ARCHITECTURE.md` → `docs/CRYPTO.md`, `FORMATS.md` → `docs/FORMATS.md`. Added scope headers and "Next:" footers to all tour docs so the reading order is canonical. `CLAUDE.md` gains a living-docs table and four discipline rules (scope-boundary check, code-constant pinning, new-doc rule, plan-state hygiene). - **CLI quality-of-life.** `gen` alias for `generate`, `-l`/`-w` short flags, batched purge in `cmd_purge` and `cmd_trash_empty`. - **Workspace audit cycle.** Stale local branches and worktrees pruned. Several plan files moved into `docs/superpowers/audits/` for the record. ## v0.5.0 — 2026-05-02 Three release trains roll into one tag — backup/restore + LastPass import (originally v0.3.0), device authentication (originally v0.4.0), and the v0.5.0 polish + harden bundle (security fixes + UX fixes + two confirmed bugs). ### Security - **Pre-receive hook now actually verifies signatures (audit S1, HIGH).** Earlier `relicario-server` builds accepted any commit with a `Good signature` line on stderr regardless of which key signed it — device-auth was a no-op. The hook now builds an `allowed_signers` file from `devices.json` at the commit (via `GIT_CONFIG_*` env, no global git-config mutation), parses the SSH SHA-256 fingerprint out of `git verify-commit --raw` stderr, and rejects unregistered keys or revoked keys whose committer-date is at or after the revocation timestamp. Bootstrap mode is preserved only when **both** `devices.json` AND `revoked.json` are empty (closes an empty-devices.json privilege-escalation route). - **Backup-restore tar unpacking hardened (audit S2).** `relicario backup restore` no longer trusts `tar::Archive::unpack`'s defaults. A new `relicario_core::safe_unpack_git_archive` validates each entry's path components (rejects `..`, absolute paths, Windows drive prefixes), rejects symlinks/hardlinks, and caps total uncompressed size at the lower of 100×compressed-bytes or 1 GiB. The CLI restore path adds a paranoid `dest.starts_with(.git/)` check after path-joining as defense-in-depth. - **`RELICARIO_*` env-var surface audited (audit S3).** `docs/SECURITY.md` gains a per-variable trust table. `RELICARIO_NO_GROUPS_CACHE` (a developer escape hatch, not a user knob) is now `cfg(debug_assertions)`-gated and is a no-op in `--release` builds; the env-var lookup is removed from the binary by the optimiser. ### Fixed - **Strength meter no longer goes stale after the regenerate button (B1).** Programmatic `input.value = newPassword` doesn't fire `input` events; the regenerate handler now dispatches a synthetic `InputEvent('input', { bubbles: true })` so the meter listener re-rates the new value. - **Snake_case error codes no longer leak into the UI (B2 / P4).** Errors like `vault_locked`, `origin_mismatch`, `unauthorized_sender` used to render verbatim in the fullscreen vault tab and (in some cases) the popup. New `extension/src/shared/error-copy.ts` central registry maps every service-worker error code to friendly title/body/CTA copy; the popup and fullscreen tab consume the same map. The fullscreen lock screen's `vault_locked` block now reads `Vault locked / Unlock your vault to continue. / [Unlock vault]`. A generated test enumerates the live error codes via grep so the registry can't drift. ### Added - **Sidebar logo in the fullscreen vault tab.** The `vault-sidebar__header` now renders the 16-optimized SVG logo inline before the "Relicario" wordmark (20×20 px, `flex-shrink: 0` so it survives narrow-pane wraps). Popup unaffected. - **Password coloring (P1).** Revealed passwords in the popup item-detail, fullscreen item view, field-history viewer, and generator preview render digits and symbols in distinct colors. Defaults: blue digits, red symbols. Users can override via the new Display section in settings (color pickers + live preview swatch + reset). Defaults round-trip via `chrome.storage.sync.password_display_scheme`; cross-device when Chrome sync is enabled. - **Setup wizard hands off to the fullscreen vault tab on completion (P2).** Both create-new and attach-existing flows now open `vault.html` in a new tab and best-effort close the setup tab after device registration succeeds — replaces the prior setup-tab-stays-open terminal screen. - **Sync now button** in the extension settings view — surfaces the previously hidden `{ type: 'sync' }` SW message to users with success / error feedback. - **Device registration from the popup.** The "Register this device" button on the devices view now opens an inline name input and (on confirm) generates a keypair via WASM, persists the private key + name locally, and writes the device to the remote — no setup-wizard detour. Backed by a new `register_this_device` SW message. - **`relicario settings generator-defaults`** — view-and-edit access to the generator defaults stored in `VaultSettings`. Flags: `--random` / `--bip39` to switch mode, `--length`, `--words`, `--symbols`, `--separator` to update fields of the active mode. - **`relicario edit` now supports TOTP items.** Issuer, label, and secret rotation work; rotated secrets are pushed to `field_history` (key: `core:totp_secret`). - **`relicario history `** — view captured field history. Values are masked by default; `--show` reveals them; `--field ` filters to one synthetic key (e.g. `login_password`, `totp_secret`). - **`relicario detach `** — remove an individual attachment from an item. Refuses to drop a Document item's primary attachment (use `purge` instead). - **`relicario status`** — vault summary: root path, item count (active / trashed), attachment count + total bytes, registered device count, last commit (`%h %s`). - **Backup & restore.** New `relicario backup export ` and `relicario backup restore []` commands. The `.relbak` format is a single encrypted file: Argon2id-derived key from a user-chosen backup passphrase (independent of the vault factor), XChaCha20-Poly1305 ciphertext, zstd-compressed JSON envelope. Reference image and `.git/` history are opt-in inclusions (`--include-image`, `--no-history`). - **Vault-tab Backup & Restore panel.** Export downloads the `.relbak` via `chrome.downloads`. Restore takes a file + backup passphrase + new-remote config and writes the vault into a fresh empty repo (refuses to clobber existing). Git history is never bundled from the extension — CLI is the source of full backups. - **LastPass CSV import.** New `relicario import lastpass ` command + vault-tab Import panel (`vault.html#import`). Logins map to `Login` items; rows with `url == "http://sn"` map to `SecureNote` (extra column → body verbatim, structured data preserved as-is for manual re-categorization). TOTP secrets in the `totp` column are base32-decoded into `LoginCore.totp`; bad base32 surfaces a warning and the login is imported without TOTP. Failed rows (missing `name`, missing password on a login) are skipped with a per-row warning. Each row gets a freshly-minted ID — re-running the import creates duplicates rather than corrupting state. - **Popup deep link to the Import panel.** `settings-vault` gains an "import" section with a `LastPass CSV →` button next to the existing `Backup & restore →` button. - **`relicario status` shows last export age.** New `Last export: ` line reading `.relicario/last_backup` (a marker file `cmd_backup_export` writes on success). Reads "never" for fresh vaults, "4 days ago" otherwise. ### Changed - **Form layout in the fullscreen vault tab is now visually consistent (P3).** Notes, custom-fields disclosure, attachments disclosure, and form-actions in fullscreen logins now sit inside a `.form-lower` wrapper with the same `max-width: 960px; margin: 0 auto` envelope as the `.form-grid` cards above. Removes the visual rhythm break at the 2-col → full-width transition. The popup surface is unchanged. - **Documentation refreshed for v0.5.0 (doc audit, 14 findings).** `DESIGN.md` now describes four codebases (the `relicario-server` pre-receive hook crate is no longer invisible); `CLAUDE.md` project tree and roadmap reflect current state; `docs/SECURITY.md` names the server crate and its `verify-commit` / `generate-hook` subcommands and notes the without-the-hook-it's- advisory caveat; `docs/CRYPTO.md` shows `settings.enc` as a parallel artifact in the vault-creation flow; the foundational design spec gains a "historical" status banner pointing readers at the current docs. - `relicario generate` now consults `VaultSettings.generator_defaults` when invoked inside an initialized vault. Explicit flags (`--length`, `--bip39`, `--words`, `--symbols`, `--separator`) override the vault default. Outside a vault, behavior is unchanged (length 20, safe symbol set, 5 BIP39 words, space separator). ### Known limitations - **Mid-restore failure leaves the target remote in a half-written state.** `cmd_backup_restore` and the vault-tab Restore panel both write artifacts sequentially via `writeFileCreateOnly`. If the process is interrupted partway, a retry against the same remote refuses to clobber. Workaround: delete the partial repo and retry. - **Cross-tool backup compatibility.** CLI-exported backups stored attachments at `/.enc`; extension stores at flat `.bin`. The `.relbak` envelope canonicalizes to `/` keys and each tool translates at the boundary. Round-trip works in both directions. ### Internal - 5 stale local feature branches and 3 worktrees pruned (audit C1). - Pre-existing clippy warnings cleaned up across `relicario-{core,cli}` (deref operators, `Option::is_none_or` over `map_or(true, ...)`, `iter_mut().enumerate()` patterns, `div_ceil()`) so the workspace builds clean under `-D warnings`. - `Cargo.lock` regenerated and committed; was stale since the `--totp-qr` commit. - Refactored `cmd_add` and `cmd_edit` in the CLI: each `ItemCore` variant now has its own `build_*_item` / `edit_*` helper. Pure mechanical extraction; behavior unchanged. The dispatcher matches and delegates. - Extracted pure helpers (`escapeHtml`, `ratePassphrase`, `scheduleRate`, `entropyText`, `STRENGTH_LABELS`) from `extension/src/setup/setup.ts` into `setup-helpers.ts`. State-coupled `updateStrengthUi` stays in `setup.ts` since it walks live wizard state. Setup.ts went from 1205 → 1137 lines. ## v0.2.0 — 2026-04-27 ### Fixed - **Setup wizard could silently overwrite an existing vault.** Pointing the wizard at a remote that already contained a Relicario vault would clobber `manifest.enc`, `.relicario/salt`, and friends with no warning. The wizard now probes the remote after the connection test and refuses to create a new vault on top of an existing one. Affected users whose vault was wiped by this bug should restore from the git history of the affected repo (`git log` + `git checkout -- .`). - **New devices registered during initial setup were silently dropped.** The wizard's Step 5 fired `add_device` over a service-worker channel that required an unlocked vault, which is unavailable mid-wizard. Device pubkeys now write directly to `.relicario/devices.json` from the wizard. - **Wizard-created vaults were missing `settings.enc`.** The CLI's `init` writes a default-`VaultSettings` `settings.enc` alongside `manifest.enc`, but the wizard skipped it, causing every `get_vault_settings` SW call to 404. The wizard now encrypts and writes `settings.enc` using a new `default_vault_settings_json` WASM helper that keeps defaults in sync with Rust core. ### Added - **Attach this device to an existing vault — purely from the GUI.** New Step 0 mode picker splits the wizard into "create new vault" and "attach this device." The attach path takes a passphrase + reference image, fetches the existing manifest, verifies the credentials by decrypting it, and only then registers a new device key. No CLI required for multi-device setup. - `GitHost.lastCommit(path)` and `GitHost.writeFileCreateOnly(path, ...)`. - `default_vault_settings_json()` WASM export. ## v0.1.0 — 2026-04-22 Initial release.