Commit Graph

151 Commits

Author SHA1 Message Date
adlee-was-taken
ab5a885f10 test(ext/vault): vitest for the Import panel
Mocks sendMessage. Covers: file-picker fires
parse_lastpass_csv, preview text matches the parsed counts,
confirm fires import_lastpass_commit with the parsed items,
warnings render after import, cancel clears the preview.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 18:45:23 -04:00
adlee-was-taken
66981588e7 feat(ext/vault): Import panel — LastPass CSV
New vault.html#import panel with a file picker, parse-preview
("N logins, M notes, K skipped — proceed?"), confirm/cancel
buttons, inline progress, and a post-import warnings list. The
popup's settings-vault view links to it via a new
"LastPass CSV →" button next to "Backup & restore →".

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 18:43:35 -04:00
adlee-was-taken
da6f08fa35 test(ext/router): sender matrix for LastPass import messages
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 23:33:52 -04:00
adlee-was-taken
ecb137a120 test(ext/sw): unit tests for parse + commit handlers
Mocks the WASM bridge and vault helpers. Covers:
- parse_lastpass_csv pass-through + error surface
- commit happy path: 3 items → 3 encryptAndWriteItem +
  1 encryptAndWriteManifest call
- vault_locked + empty-items rejections
- IDs re-minted by SW so manifest keys match the new IDs

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 23:33:16 -04:00
adlee-was-taken
b29a138411 feat(ext/sw): parse + commit handlers for LastPass import
parse_lastpass_csv is a pure pass-through to the WASM bridge.
import_lastpass_commit re-mints each item's ID via
state.wasm.new_item_id() (same pattern as add_item), encrypts
and writes per-item via git.writeFile, then writes the manifest
last. Per-item commits + a final manifest commit — extension
GitHost has no atomic-batch API, so the single-commit semantics
the CLI provides aren't replicable here.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 23:30:26 -04:00
adlee-was-taken
fbd029e4cb feat(ext/shared): message types for LastPass import
Adds parse_lastpass_csv (preview) and import_lastpass_commit
(write) to the popup-only message set, plus typed response
helpers. SW handlers + UI follow in Tasks 12-14.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 23:30:18 -04:00
adlee-was-taken
218ccb8efa test(ext/sw): export/restore handler unit tests 2026-04-28 22:20:07 -04:00
adlee-was-taken
c1f48ecb71 test(ext): vault-tab Backup & Restore panel 2026-04-28 22:17:09 -04:00
adlee-was-taken
419408bbad feat(ext): vault-tab Backup & Restore panel
Two cards — Export (passphrase + include-image checkbox → download)
and Restore (file picker + passphrase + new-remote form). Deep-linked
from settings-vault > 'Backup & restore →'.
2026-04-28 22:11:51 -04:00
adlee-was-taken
06913a0aed test(ext/sw): router accepts/rejects backup messages per sender 2026-04-28 22:03:02 -04:00
adlee-was-taken
9ec5e9b4e1 fix(ext/sw): atomic chrome.storage update in restore_backup
Single set({vaultConfig, imageBase64?}) instead of two sequential sets,
so a partial-write window can't leave vaultConfig pointing to the new
remote while imageBase64 still references the old vault.
2026-04-28 22:01:56 -04:00
adlee-was-taken
2e825a9d33 feat(ext/sw): restore_backup handler
Unpacks .relbak via WASM, writes every vault artifact to the
user-specified fresh remote via writeFileCreateOnly (refuses to
clobber), and updates chrome.storage.local so subsequent unlocks
hit the restored vault. The reference image — when bundled — is
restored to imageBase64; otherwise the user keeps using their
existing reference.jpg.
2026-04-28 21:58:14 -04:00
adlee-was-taken
5d9ea37b7f feat(ext/sw): export_backup handler
Reads vault state via GitHost, calls pack_backup_json in WASM, returns
the .relbak bytes back to the panel for chrome.downloads.download.
Reference image inclusion comes from chrome.storage.local.imageBase64.
Git history is never bundled from the extension (CLI is the source of
full backups).
2026-04-28 20:16:52 -04:00
adlee-was-taken
f32c14f939 feat(ext/sw): export_backup / restore_backup message types 2026-04-28 20:12:07 -04:00
adlee-was-taken
f79a67bb15 refactor(ext/setup): extract pure helpers to setup-helpers.ts
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>
2026-04-27 21:13:13 -04:00
adlee-was-taken
a7dbf35126 feat(ext): sync now button + device register from popup; vault tab parity
Closes three audit gaps in one pass:

1. Sync now button in the popup settings view (📤). Triggers the existing
   { type: 'sync' } SW message and surfaces success / failure inline. The
   SW message was already wired but had no UI entry point.

2. Device registration from the popup. The "Register this device" button
   on the devices view used to error out with a "not yet implemented"
   message; it now opens an inline name input (default = browser+OS), and
   on confirm sends a new register_this_device SW message that generates
   an ed25519 keypair via WASM, persists private_key + name to
   chrome.storage.local, and writes the public key to the remote
   devices.json. No setup-wizard detour.

3. Vault tab is now an authorized sender for popup-only SW messages. The
   router accepts vault.html alongside popup.html, so the fullscreen tab
   can drive the same flows. Test covers acceptance from the vault tab.

New SW message: register_this_device { name }. Added to PopupMessage and
POPUP_ONLY_TYPES, handled in router/popup-only.ts.

Tests: 5 new vitest cases (3 in settings.test.ts, 2 in devices.test.ts)
+ 1 router test for vault-tab acceptance. All 194 extension tests pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-27 21:13:05 -04:00
adlee-was-taken
beff092818 fix(ext/setup): lock verified handle on Step 5 error + early-return paths
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>
2026-04-27 19:12:22 -04:00
adlee-was-taken
2756033bf9 feat(ext/setup): unified device registration in Step 5; fixes silent dropped pubkey
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 18:34:35 -04:00
adlee-was-taken
e79e80b000 feat(ext/setup): Step 3b attach flow with decrypt verification
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>
2026-04-27 18:32:27 -04:00
adlee-was-taken
214f8da673 fix(ext/setup): wizard writes settings.enc to match CLI init
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>
2026-04-27 18:29:10 -04:00
adlee-was-taken
399a276fdd feat(ext/setup): refuse to overwrite existing vault files (Step 3a clobber guard)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 18:24:16 -04:00
adlee-was-taken
f44aedfa76 feat(ext/setup): vault-presence probe + mode-mismatch banners on Step 2
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 18:22:45 -04:00
adlee-was-taken
a182c1ac5a feat(ext/setup): Step 0 mode picker (new vs attach) + Step 1 back button
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>
2026-04-27 18:20:24 -04:00
adlee-was-taken
7fa1f2990f refactor(ext/setup): wizard state shape for mode-aware flow
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>
2026-04-27 18:14:42 -04:00
adlee-was-taken
8e72ed8714 feat(ext/setup): vault-presence probe helper
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 18:12:04 -04:00
adlee-was-taken
19bb5b5293 test(ext/sw): assert PUT method on GitHub writeFileCreateOnly create path
Mirrors the POST assertion already present in the Gitea "creates" test —
catches accidental method drift.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-27 18:10:32 -04:00
adlee-was-taken
86b5941875 feat(ext/sw): GitHost.writeFileCreateOnly() refuses to overwrite
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 18:06:48 -04:00
adlee-was-taken
98c962796f test(ext/sw): assert lastCommit URL structure + comment limit/per_page divergence
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 18:04:56 -04:00
adlee-was-taken
2c94dfaf90 feat(ext/sw): GitHost.lastCommit() for vault-presence metadata
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 17:48:24 -04:00
adlee-was-taken
ce59223fc0 feat(ext): shared state host — decouple components from popup.ts
Introduce shared/state.ts as a service-locator so popup components
(item-detail, item-form, trash, devices, settings, etc.) work in both
the popup and vault tab bundles. Both entry points register themselves
as the host; components import from shared/state instead of popup.ts.
Vault.ts now delegates to the real popup components, removing ~300 lines
of placeholder renderers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-27 16:38:06 -04:00
adlee-was-taken
6c8ebb3548 feat(ext/vault): scaffold vault.html tab with sidebar+pane layout and hash routing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-27 15:53:53 -04:00
adlee-was-taken
7e0950e364 feat(ext/popup): session expiry listener, open-vault links, Shift+F shortcut
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-27 15:46:32 -04:00
adlee-was-taken
101f0093a4 fix(ext/sw): review fixes — storage key, timer reset scope, imports
- Rename storage key sessionTimeoutConfig → session_timeout (plan spec)
- Only call resetTimer() for non-content-script message types so content
  script polling cannot keep the session alive
- Collapse two same-module imports into one line; add CONTENT_CALLABLE_TYPES

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 15:44:13 -04:00
adlee-was-taken
86621f075f feat(ext/sw): add session inactivity timer with configurable timeout
Implements a service-worker-side session timer that locks the vault
after a configurable period of inactivity (default 15 min). Supports
two modes: 'inactivity' (timer-based) and 'every_time' (no timer).
Config persists via chrome.storage.local and is exposed through
get_session_config / update_session_config popup messages.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-27 02:24:26 -04:00
adlee-was-taken
9488670b1b fix(ext/popup): fix reversed search, remove auto-focus, Enter opens items
- Search no longer auto-focuses; use "/" to focus it
- Typing in search no longer re-renders the entire view, just the
  item list — fixes backwards text caused by cursor reset to pos 0
- Arrow keys also update list without full re-render
- Enter opens the selected item even when search is focused

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-27 02:10:23 -04:00
adlee-was-taken
8f603ec069 fix(ext/router): allow popup.html with query params
The router was doing exact URL match for popup.html, but when
opened in a tab with params (?view=add&type=card), it failed.
Changed to startsWith match like setup.html already uses.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-27 01:49:59 -04:00
adlee-was-taken
446949c5ce fix(ext/popup): auto-popout for attachment types, keep login/note in popup
- Login and secure_note types stay in popup without attachment UI
- All other types (identity, card, key, totp, document) auto-redirect
  to full tab when selected
- Attachments only shown for login/secure_note when opened in tab

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-27 01:42:35 -04:00
adlee-was-taken
c59e6892d8 feat(ext/popup): add pop-out to tab for forms
Forms can now be opened in a full browser tab via the ⤴ button,
solving Chrome's popup closure on file picker interaction. Deep
linking via URL params preserves view, item type, and item ID.

Also removes the unused dropdown picker code from item-list.ts.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-27 01:32:39 -04:00
adlee-was-taken
39db697ce5 fix(ext/popup): replace item type dropdown with selection view
Clicking "+ new" now navigates to a type selection view instead of
showing a dropdown that gets clipped by popup bounds. The selection
view displays all item types as buttons in a scrollable list.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-27 01:21:14 -04:00
adlee-was-taken
eb14946f06 feat(ext/setup): add device name step to setup wizard
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>
2026-04-27 01:04:10 -04:00
adlee-was-taken
abfc5aed42 feat(ext/popup): wire navigation for trash, devices, field-history screens
Adds View variants, render cases, teardown calls, and entry points
in settings menu for trash and devices.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-27 00:42:53 -04:00
adlee-was-taken
b55c59bd35 feat(ext/popup): add attachment cap setting to vault settings
Dropdown with 5/10/25/50 MB presets for per_attachment_max_bytes.
Other caps remain at defaults.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-27 00:37:43 -04:00
adlee-was-taken
2fa54e2144 feat(ext/popup): add "View history" link to login detail view
Shows button when item.field_history is non-empty. Navigates to
field-history screen with historyItemId set.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-27 00:32:16 -04:00
adlee-was-taken
3b4788e5dc feat(ext/popup): field history view — masked values with reveal toggle
Shows current + historical values for tracked fields (password/concealed).
Click to reveal, copy button per entry (plaintext stored in a module-level
Map, never embedded in the DOM). Grouped by field name if multiple tracked
fields exist. Adds historyItemId to PopupState and 'field-history' to View.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-27 00:23:54 -04:00
adlee-was-taken
7fe54472b3 feat(ext/popup): devices view — list devices with revoke actions
Shows registered devices with "← you" indicator on current device.
Revoke button on other devices. Unregistered banner if current
device not in list.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-27 00:19:59 -04:00
adlee-was-taken
9fbf9bb3ee feat(ext/popup): trash view — list trashed items with restore/purge
Shows trashed items sorted newest-first with restore buttons.
Empty trash button purges all items + orphan blobs. Header shows
count and days until oldest auto-purges.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-26 19:28:56 -04:00
adlee-was-taken
39a8e12438 feat(ext/sw): get_field_history handler
Decrypts item and calls WASM get_field_history to extract tracked
field history for the popup's history view.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-26 17:49:59 -04:00
adlee-was-taken
d2cb6d8461 feat(ext/sw): trash operations — listTrashed, restoreItem, purgeItem, purgeAllTrash
listTrashed filters manifest for trashed_at != null, sorted newest-first.
restoreItem clears trashed_at. purgeItem deletes item + attachments.
purgeAllTrash also scans for orphan blobs in attachments/ directory.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-26 15:57:08 -04:00
adlee-was-taken
0003c3e658 feat(ext/sw): device management — devices.ts + router handlers
Adds readDevices, addDevice, revokeDevice helpers that read/write
.relicario/devices.json. Router handlers: list_devices, add_device,
revoke_device.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-26 15:53:08 -04:00
adlee-was-taken
5a001a805c feat(ext/shared): add Device + FieldHistory types + 8 new message types
Device: name, public_key (hex), added_at.
FieldHistoryView: field_id, field_name, current_value, entries[].
Messages: list_devices, add_device, revoke_device, list_trashed,
restore_item, purge_item, purge_all_trash, get_field_history.

Also adds stub cases in popup-only.ts switch to keep tsc happy until
Tasks 3-5 wire up the real handlers.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-26 15:49:01 -04:00