Commit Graph

297 Commits

Author SHA1 Message Date
adlee-was-taken
3d2b021cb2 test(ext): vitest + router sender-check + origin-bound autofill 2026-04-20 20:15:49 -04:00
adlee-was-taken
2d4dcb5f6b feat(ext/sw): collapse flat index onto router 2026-04-20 20:11:59 -04:00
adlee-was-taken
56ab58cbe9 feat(ext/sw): router index with sender-based dispatch 2026-04-20 20:11:20 -04:00
adlee-was-taken
be32ea13c6 feat(ext/sw): router/content-callable handlers with origin derivation 2026-04-20 20:11:02 -04:00
adlee-was-taken
533bfd5bea feat(ext/sw): router/popup-only handlers 2026-04-20 20:10:34 -04:00
adlee-was-taken
2fd6daad8e docs(ext/sw): tighten slice-3 comments per code review
Non-functional tightening flagged in the slice-3 code review:

- session.ts: document future multi-vault refactor (β+) so the module-
  scope singleton is explicitly "deliberately simple," not an oversight.
- vault.ts: move findByHostname doc comment above the function; note
  α's intentionally-coarse hostname match (no www-stripping, no
  public-suffix matching) and that tighter matching is a β/γ concern.
- index.ts: expand the passphrase scope-clearing comment to make
  the theatre explicit rather than leaving it looking like real defense.
- index.ts: TODO(slice-4) marker on delete_item's non-atomic two-write
  path — consider manifest-first ordering or retry/rollback at router-
  split time.
- index.ts: cross-reference comment on itemToManifestEntry pointing at
  the Rust-side ManifestEntry::from_item derivation it must mirror.

No behavior change; build still compiles with 2 bundle-size warnings.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 20:07:27 -04:00
adlee-was-taken
c0fba2a8dc chore(ext): silence popup/content errors until slice 6 2026-04-20 19:57:32 -04:00
adlee-was-taken
20144e8e02 feat(ext/sw): rewire flat handler onto typed-item vault + SessionHandle 2026-04-20 19:55:50 -04:00
adlee-was-taken
bd9dd206ac feat(ext/sw): typed-item vault ops via SessionHandle 2026-04-20 19:53:28 -04:00
adlee-was-taken
7781a51848 feat(ext/sw): SessionHandle lifecycle module 2026-04-20 19:52:54 -04:00
adlee-was-taken
dc8afcb634 feat(ext): base32 encode/decode for TOTP secret parse 2026-04-20 19:44:18 -04:00
adlee-was-taken
b4da5bffcf feat(ext): split PopupMessage / ContentMessage unions + capability sets 2026-04-20 19:43:09 -04:00
adlee-was-taken
04c9503036 feat(ext): typed-item TS types mirroring relicario-core serde 2026-04-20 19:42:31 -04:00
adlee-was-taken
14aaac672c build(ext): align wasm.d.ts with relicario-wasm surface
Add initSync named export (Chrome MV3 service worker path — can't use
dynamic import()), and correct TotpCode.expires_at from number to bigint
to match the u64 wasm-bindgen output.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 19:36:54 -04:00
adlee-was-taken
c03a492ee3 docs: Plan 1C-α (extension foundation) implementation plan
28 tasks across 6 slices + pre-flight + acceptance, following the 1C-α
design spec (a1d733d/ad6d8af). Each task is a single commit; each step
is 2-5 minutes of work. Design choices locked in:

- Slice 1 (Tasks 1-3): WASM artifact rebuild (replace stale idfoto_wasm)
- Slice 2 (Tasks 4-6): shared TS types + message unions + base32 util
- Slice 3 (Tasks 7-10): session.ts, vault.ts, transitional index.ts
- Slice 4 (Tasks 11-15): split router + Vitest + sender-check matrix
- Slice 5 (Tasks 16-20): WAR cleanup, setup-via-tabs, closed Shadow DOM
  for capture/icon/picker/ack, popup captured-tab snapshot
- Slice 6 (Tasks 21-27): popup rename + Login-parity + zxcvbn + manual
  cross-browser verification
- Slice 7 (Task 28): acceptance checks (cargo test, build, lint greps)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 19:28:13 -04:00
adlee-was-taken
ad6d8af2f6 docs(1c-alpha): correct TS type definitions to match actual serde shapes
Verified against the Plan 1A Rust sources:
- ItemType / ItemCore use snake_case with tag="type" internal tagging
  (not the external tagging I initially wrote)
- TotpKind is default-externally-tagged (no tag attr), so it serializes
  as bare "totp"/"steam" for unit variants and { hotp: { counter } }
- GeneratorRequest uses tag="kind" internal tagging
- FieldValue / TrashRetention / HistoryRetention / SymbolCharset use
  adjacent tagging { tag: "kind", content: "value" }
- Fix Login form TOTP parse example and "gen" button payload

No scope change — this is a bookkeeping correction so the plan
author references the correct wire shapes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 19:19:44 -04:00
adlee-was-taken
a1d733ddeb docs: Plan 1C-α (extension foundation) design spec
Foundation slice of the browser-extension migration onto the typed-item
core from Plans 1A+1B. Scope: WASM artifact rebuild, typed-item shared
types, SessionHandle-based service worker, split router with sender
checks, full security architecture (origin-bound autofill, TOFU ack,
closed Shadow DOM, popup captured-tab verification), zxcvbn setup gate,
Login-parity popup. Other 6 item types land in 1C-β; attachments/trash/
history/device UI in 1C-γ.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 19:14:25 -04:00
adlee-was-taken
76f34bfcf5 chore: remove stray vault files from Plan 1B + add plan doc
A Task 6 implementer subagent ran `relicario init` inside the worktree
root during manual testing and committed the resulting vault skeleton
(.relicario/, manifest.enc, settings.enc) plus overwrote .gitignore.
None of these should be in the source repo.

Restores the original .gitignore (adds reference.jpg and ref.jpg to it)
and checks in the Plan 1B design doc that describes the work just merged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 18:50:37 -04:00
adlee-was-taken
e0c511e320 Merge Plan 1B: typed-item CLI + WASM bridge
34 commits from plan-1a-rust-core-complete landing:
- Rename reconciliation (Task 1)
- Core imgsecret MAX_DIMENSION cap (Task 2, audit M3)
- CLI rewrite against typed-item core API (Tasks 3-17)
- WASM opaque SessionHandle bridge (Tasks 18-21)
- CLI integration test harness + tests (Tasks 22-24)
- CLAUDE.md typed-item layout refresh (Task 25)

Audit fixes: H4 H5 H6 H7 M3 M6 M7 M11 L8.
Tests: 151 passing (core + CLI + WASM native), WASM target builds clean.
Tag: plan-1b-cli-wasm-complete
2026-04-20 18:48:56 -04:00
adlee-was-taken
65e0d3cb80 docs: update CLAUDE.md for the typed-item module layout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
plan-1b-cli-wasm-complete
2026-04-20 18:47:08 -04:00
adlee-was-taken
c3edf9d413 test(cli): vault_dir detection (L8) + v1 vault rejection
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 18:39:13 -04:00
adlee-was-taken
20350d509b test(cli): integration tests for edit/history, attachments, settings
Adds RELICARIO_TEST_ITEM_SECRET env hatch for rpassword calls in
cmd_add / cmd_edit so piped-stdin tests can exercise the password
prompt paths without a TTY.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 18:37:56 -04:00
adlee-was-taken
b263c27da9 test(cli): integration harness + basic flow tests
Uses assert_cmd + tempfile to spin up a fresh vault per test.
Covers init layout, add/list/get mask semantics, rm/restore/purge cycle,
and generate smoke. Adds RELICARIO_TEST_PASSPHRASE env-var hatch in
unlock_interactive and cmd_init so tests don't need a TTY.

Also fixes read_params in session.rs to correctly parse the nested
params.json format (kdf sub-object) rather than trying to deserialize
the whole file as KdfParams.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 18:32:45 -04:00
adlee-was-taken
494eedbbb8 init: new relicario vault (format v2) 2026-04-20 18:31:46 -04:00
adlee-was-taken
b8afec3560 feat(wasm): configure serde_wasm_bindgen for plain-object HashMap
Maps serialize as JS objects, not Maps — what the extension popup
expects. Also ships hand-written TS declarations for the bridge
(consumed by Plan 1C).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 17:41:41 -04:00
adlee-was-taken
92b9e64ef9 feat(wasm): attachment / generator / totp / imgsecret / id bridges
Also ports TOTP RFC 6238 compute to relicario-core::item_types::totp
so native + CLI + WASM share one implementation (audit H5: CSPRNG
via core's Uniform-sampling generator).

Adds hmac = "0.12" and sha1 = "0.10" to relicario-core deps to support
HOTP/TOTP HMAC with Sha1/Sha256/Sha512. RFC 6238 test vector (t=59,
SHA-1, 8 digits) passes: "94287082".
2026-04-20 17:39:45 -04:00
adlee-was-taken
fac2e49cf1 feat(wasm): manifest / item / settings encrypt+decrypt via SessionHandle
Adds six #[wasm_bindgen] functions (manifest_encrypt/decrypt,
item_encrypt/decrypt, settings_encrypt/decrypt) plus a native
round-trip test that verifies encrypt→core_decrypt and nonce
uniqueness without calling js-sys (serde_wasm_bindgen::from_value
is wasm32-only; documented in test comment).
2026-04-20 17:37:50 -04:00
adlee-was-taken
f3ce76d9fb feat(wasm): opaque SessionHandle bridge with unlock/lock
Master key never leaves WASM linear memory. Held in Zeroizing<[u8;32]>
inside a thread_local HashMap keyed by u32. lock() removes + zeroizes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 17:34:50 -04:00
adlee-was-taken
8c315654ae feat(cli): device add / list / revoke rewired to hardened git 2026-04-20 17:32:09 -04:00
adlee-was-taken
a3871ac890 feat(cli): relicario sync — pull --rebase then push via hardened git 2026-04-20 17:31:45 -04:00
adlee-was-taken
10f249d95e feat(cli): relicario settings show / trash-retention / history-retention / attachment-cap 2026-04-20 17:31:27 -04:00
adlee-was-taken
a6bad4bb3e feat(cli): relicario generate delegates to core (audit H6)
CLI no longer has its own charset-sampling path — uses the CSPRNG
generate_password / generate_passphrase in relicario-core, which use
rand::distributions::Uniform internally.
2026-04-20 17:30:56 -04:00
adlee-was-taken
cbd1dbd706 feat(cli): attachment ops — attach / attachments / extract
Respects AttachmentCaps from settings.enc; content-addressed aid
comes from core::encrypt_attachment.
2026-04-19 22:27:13 -04:00
adlee-was-taken
b5015b3e9b fix(cli): trash empty unlocks vault once, not per item
Extracted purge_item helper so cmd_trash_empty loops over it without
re-prompting for passphrase per item. Single git commit per trash empty
summarizing the count. Caught in Task 12 review.
2026-04-19 22:25:57 -04:00
adlee-was-taken
cc279bac0b feat(cli): trash ops — rm / restore / purge / trash empty
Soft-delete sets trashed_at via Item::soft_delete; restore clears it.
Purge deletes item + attachment dir and removes manifest entry.
Trash empty scans for items past settings.trash_retention.
2026-04-19 22:24:32 -04:00
adlee-was-taken
06c8903e2b feat(cli): relicario edit — interactive field updates + history
Title/group/tags always optional. Per-type prompts for core secret
fields (Login.password, Card.number, Key.material, SecureNote.body)
push the old value to field_history via a synthetic core:<key>
FieldId so rotation is audit-traceable.
2026-04-19 22:22:45 -04:00
adlee-was-taken
377d73355b feat(cli): relicario list with --type/--group/--tag/--trashed filters
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 22:20:26 -04:00
adlee-was-taken
ed451041b0 feat(cli): relicario get with masking, --show, and zeroize-clipboard
Secrets masked by default (audit M7). --show reveals plaintext.
--copy writes to clipboard and spawns a detached 30s auto-clear
thread holding a Zeroizing copy that wipes on drop (audit M6).
2026-04-19 22:19:15 -04:00
adlee-was-taken
fe017455d3 feat(cli): relicario add — remaining 6 item types
SecureNote, Identity, Card, Key, Document (with inline attachment),
and Totp with base32 secret decoding. Document widens the commit
to include the attachment blob path.
2026-04-19 22:16:51 -04:00
adlee-was-taken
89b22cb089 feat(cli): relicario add login with flag + interactive prompting
Unlocks vault, builds LoginCore from flags (password via rpassword if
--password-prompt), saves item + manifest, commits via hardened git.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 22:13:17 -04:00
adlee-was-taken
5dce2c10f9 fix(cli): init stages salt, handles --output ..-paths, zeroizes image_secret
1. Add .relicario/salt to the initial git commit so it syncs across
   devices (Argon2 salt must match at unlock time).
2. Return a proper error instead of panicking when --output has no
   filename component (e.g., trailing ..).
3. Wrap the generated 32-byte image_secret in Zeroizing for
   consistency with the passphrase + master_key handling in Task 4.

Caught in Task 6 review.
2026-04-19 22:11:10 -04:00
adlee-was-taken
a50099a066 feat(cli): relicario init creates a format-v2 vault
Prompts for a strong passphrase (zxcvbn gate via core), generates a
32-byte image secret, embeds it in the carrier JPEG, writes the
standard vault skeleton, and makes an initial git commit via the
hardened git_command helper.
2026-04-19 22:02:53 -04:00
adlee-was-taken
15e6ed9c75 feat(cli): scaffold clap surface for all typed-item commands
Every subcommand from the Plan 1B CLI spec present; bodies return
'not yet implemented' so subsequent tasks land one command at a time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 22:00:14 -04:00
adlee-was-taken
589d7b90b4 fix(cli): zeroize image_secret + correct atomic_write temp path
atomic_write now appends .tmp instead of replacing the extension
(manifest.enc.tmp, not manifest.tmp). image_secret is wrapped in
Zeroizing so both KDF inputs wipe on drop. Caught in Task 4 review.
2026-04-19 21:57:42 -04:00
adlee-was-taken
06d21bf7c9 feat(cli): add UnlockedVault session wrapping master_key in Zeroizing
Provides load/save helpers for Manifest/Settings/Item; atomic_write keeps
vault files consistent across crashes. main.rs is transiently broken
against the old Entry API — Task 5+ rewrites the command handlers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:44:44 -04:00
adlee-was-taken
6890926e31 feat(cli): add helpers module (vault_dir/L8, git_command/H4, iso8601/M11)
Bumps rpassword to 7.x (H7) and adds zeroize/chrono/assert_cmd dev-deps.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 21:37:28 -04:00
adlee-was-taken
c8535e11f5 fix(core): correct off-by-one in imgsecret SOF bounds guard
peek_jpeg_dimensions reads jpeg[i+8] as the last byte, so the guard
should be \`i + 8 >= jpeg.len()\`, not \`i + 9 >= jpeg.len()\`. The old
guard would reject a valid SOF marker ending exactly at len()-1.
Caught in Task 2 code-quality review.
2026-04-19 21:34:53 -04:00
adlee-was-taken
7853db061e fix(core): cap imgsecret MAX_DIMENSION at 10000px (audit M3) 2026-04-19 21:27:17 -04:00
adlee-was-taken
3e0cafb269 chore: update Cargo.lock after typed-item dependency additions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 20:58:50 -04:00
adlee-was-taken
17bf47611f chore: merge rename commit into Plan 1B branch
Resolves conflicts from merging origin/main (idfoto→relicario rename):
- Kept Plan 1A's typed-item vault.rs, lib.rs, integration.rs over main's
  old entry-based versions
- Took main's relicario_dir() fix in CLI main.rs (sed had missed idfoto_dir)
- Kept Plan 1A's UnsupportedFormatVersion error variant in crypto.rs
- Kept Plan 1A's opaque Decrypt message (audit M4) in error.rs
- Deleted entry.rs (replaced by item.rs + typed modules in Plan 1A)
- Resolved Cargo.toml description to main's "relicario password manager"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 20:58:35 -04:00