Commit Graph

399 Commits

Author SHA1 Message Date
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
adlee-was-taken
9c49e5e148 chore: reconcile Plan 1A branch with idfoto→relicario rename
Renames crate directories and sweeps identifiers so Plan 1B can reference
the post-rename names throughout.

- git mv crates/idfoto-{core,cli,wasm} → crates/relicario-{core,cli,wasm}
- sed sweep: idfoto_core/idfoto-core/IdfotoError/IDFOTO_IMAGE/.idfoto/ etc.
- All 128 relicario-core tests pass post-sweep

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 20:33:04 -04:00
adlee-was-taken
519a6f0e36 chore: rename project from idfoto to relicario
Sweeping rename across crates, CLI binary, WASM bindings, extension, docs,
and vault metadata paths. Git remote updated to relicario.git.

- crates/idfoto-{core,cli,wasm} -> crates/relicario-{core,cli,wasm}
- IdfotoError -> RelicarioError
- IDFOTO_IMAGE env var -> RELICARIO_IMAGE
- ~/.config/idfoto -> ~/.config/relicario
- .idfoto/ vault metadata dir -> .relicario/ (breaking; pre-release)
- Binary name idfoto -> relicario
- Extension wasm module idfoto_wasm -> relicario_wasm
- Storage key idfotoSettings -> relicarioSettings
- All doc filenames and content references updated

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 16:47:02 -04:00
adlee-was-taken
20ff1d9f47 feat: add logo and polish icon presentation
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 16:44:04 -04:00
adlee-was-taken
49b78203f8 chore(core): clean up Plan 1A clippy warnings
Auto-deref at &Zeroizing<[u8;32]> call sites, range pattern in generators,
useless String::into conversions in tests, unused Zeroizing import.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 15:55:32 -04:00
adlee-was-taken
3cf09faf1e test(core): field history integration (capture, prune, round-trip)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 15:52:03 -04:00
adlee-was-taken
557fb95b69 test(core): integration tests for format v2 invariants
VERSION_BYTE = 0x02; v1 blobs rejected with UnsupportedFormatVersion;
length-prefix Argon2 input distinguishes collision-engineerable pairs
(audit H1 regression test).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 15:50:29 -04:00
adlee-was-taken
9cd5924109 test(core): integration tests for generators (balance, BIP39, gate)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 15:49:08 -04:00
adlee-was-taken
08b1735b0e test(core): integration tests for attachments (round-trip, AID, caps)
Also derives Debug on EncryptedAttachment (required by the test's panic arm).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 15:47:16 -04:00
adlee-was-taken
c7064183d6 test(core): rewrite integration test for typed items
- full_workflow_login_and_note: round-trips Login + SecureNote + Manifest + Settings
- two_factor_independence: confirms image_secret + passphrase combine into the master key
- field_history_persists_through_round_trip: history survives encrypt/decrypt
- wrong_key_fails_with_opaque_decrypt: opaque error per audit M4

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 15:45:49 -04:00
adlee-was-taken
950ae3d8dd refactor(core): delete entry.rs; finalize typed-item lib.rs re-exports
The old Entry/ManifestEntry/Manifest types are gone. CLI/extension
references break and will be fixed by Plans 1B and 1C respectively.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 15:43:16 -04:00
adlee-was-taken
2074677278 feat(core): add Item::prune_history honoring retention policy
Forever, LastN, and Days policies all covered. Tests verify drop order
(keeps newest), days cutoff, and forever-no-op semantics.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 15:41:13 -04:00
adlee-was-taken
4a98be0dae feat(core): rewrite vault.rs for typed items
encrypt_item / decrypt_item / encrypt_manifest / decrypt_manifest /
encrypt_settings / decrypt_settings. All plaintext flows through
Zeroizing so JSON buffers are wiped on drop.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 15:38:52 -04:00
adlee-was-taken
f673b1ddee feat(core): add encrypt_attachment + decrypt_attachment
AttachmentId is derived from sha256(plaintext) so identical content
deduplicates naturally. Size cap enforced at encrypt time, returning
IdfotoError::AttachmentTooLarge.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 15:36:19 -04:00
adlee-was-taken
1fb0f8cc03 chore(core): Debug derive on StrengthEstimate + fix stale test comment
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 15:35:01 -04:00
adlee-was-taken
61b1a9710b feat(core): add BIP39 passphrase generator + zxcvbn strength gate
generate_passphrase honors word_count (3-12), separator, capitalization.
validate_passphrase_strength enforces zxcvbn score >= 3 (audit H3).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 15:31:50 -04:00
adlee-was-taken
61d6fb723d fix(core): reject non-ASCII SymbolCharset::Custom at generate time
Avoids from_utf8 panic when Custom contains multi-byte UTF-8 chars
whose individual bytes are independently sampled into the output.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 15:04:13 -04:00
adlee-was-taken
db3f2e15f2 feat(core): add CSPRNG random password generator with safe charset
Uses rand::distributions::Uniform for unbiased sampling (audit H6).
Safe symbols = !@#$%^&*-_=+ (excludes characters that web forms
commonly reject). Test length capped at 128 (validator upper bound).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 15:02:39 -04:00
adlee-was-taken
b2d8a759ef fix(core): SymbolCharset needs content="value" for Custom(String)
Same latent bug as TrashRetention/HistoryRetention — serde's
internally-tagged repr cannot merge a newtype primitive payload
into a tag object. Add regression test for Custom round-trip.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 15:01:09 -04:00
adlee-was-taken
266761232d feat(core): add VaultSettings with retention + generator + caps
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 14:30:17 -04:00
adlee-was-taken
1a30c4ffe0 feat(core): add typed-item Manifest with schema_version 2
ManifestEntry holds the per-item browse summary including derived
icon_hint (Login URL hostname) and attachment_summaries. Search matches
title or tag substring case-insensitively.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 14:27:40 -04:00
adlee-was-taken
a5ddbf2e40 feat(core): add Item envelope with field history + soft-delete
set_field_value() captures old values for Password, Concealed, and Totp
kinds. Soft-delete via trashed_at timestamp; restore clears it. Kind
changes on set_field_value are rejected.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 14:25:11 -04:00
adlee-was-taken
509db707e0 feat(core): add AttachmentRef + AttachmentSummary
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 13:16:15 -04:00
adlee-was-taken
23f7cb76b1 feat(core): add Field, FieldKind, FieldValue, Section
Parallel kind/value enums with a validate() invariant. Password,
Concealed, and Totp kinds are marked history-tracked so the Item setter
(next task) can decide whether to capture history on update.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 13:14:00 -04:00
adlee-was-taken
a95f92fe71 test(core): exhaustive round-trip for all seven ItemCore variants
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 13:11:08 -04:00
adlee-was-taken
91b4b5b7a4 feat(core): flesh out TotpCore + TotpConfig + TotpAlgorithm + TotpKind
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 13:09:34 -04:00
adlee-was-taken
5786d9ef1a feat(core): flesh out DocumentCore
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 13:08:03 -04:00
adlee-was-taken
0b0f1cea73 feat(core): flesh out KeyCore
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 13:06:50 -04:00
adlee-was-taken
0707628d58 feat(core): flesh out CardCore + CardKind
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 13:05:36 -04:00
adlee-was-taken
316036832c feat(core): flesh out IdentityCore
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 13:04:23 -04:00
adlee-was-taken
ee25ffed41 feat(core): flesh out SecureNoteCore (Zeroizing body)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 13:03:03 -04:00
adlee-was-taken
24ed740718 feat(core): flesh out LoginCore with Zeroizing<password> and Url
Also enables zeroize's `serde` feature so Zeroizing<String> can
round-trip through serde_json.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 12:59:46 -04:00
adlee-was-taken
bc60f0a6b4 docs(core): add "type" tag-collision invariant to ItemCore
Reviewer note: flatten semantics of serde tag = "type" means no *Core
struct may ever use "type" as a field name.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 12:58:43 -04:00
adlee-was-taken
0eac9c7991 feat(core): scaffold item_types module with ItemType + ItemCore enum
Stub LoginCore, SecureNoteCore, IdentityCore, CardCore, KeyCore,
DocumentCore, TotpCore. Tag-based serde representation with snake_case
discriminants.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 12:55:34 -04:00
adlee-was-taken
87ead533e5 feat(core): bump VERSION_BYTE to 0x02 with typed UnsupportedFormatVersion
Clean break from v1 — no migration. Decrypting a v1 blob now returns
IdfotoError::UnsupportedFormatVersion { found: 0x01, expected: 0x02 }.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 10:48:49 -04:00
adlee-was-taken
2ea7658036 feat(core): length-prefixed Argon2 input + NFC + Zeroize (audit H1, H2)
derive_master_key now:
- length-prefixes passphrase and image_secret to eliminate concatenation
  ambiguity (H1)
- normalizes passphrase to UTF-8 NFC before hashing
- returns Zeroizing<[u8; 32]> so the master key is wiped on drop (H2)
- wraps the intermediate password buffer in Zeroizing for the same reason

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 09:57:58 -04:00
adlee-was-taken
1bd86bdb13 refactor(core): rewrite IdfotoError variants for typed items
- Decrypt is now opaque (audit M4)
- Add WeakPassphrase, AttachmentTooLarge, ItemNotFound, UnsupportedFormatVersion
- Rename EntryNotFound → ItemNotFound across remaining call sites

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 09:53:28 -04:00
adlee-was-taken
1e8ffb02a3 feat(core): add now_unix() and MonthYear
MonthYear used for card expiries; bounds 2000..=2099 are intentional.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 09:51:35 -04:00
adlee-was-taken
6c601fae08 chore(core): add Default impls + FieldId uniqueness test
Code review fixups:
- ItemId/FieldId need impl Default delegating to ::new() to silence
  clippy::new_without_default
- FieldId was missing the parallel uniqueness test that ItemId has

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 09:50:24 -04:00
adlee-was-taken
69c2c7453b feat(core): add ItemId, FieldId, AttachmentId types
16-char hex (64-bit) random IDs for items and fields (audit M8).
AttachmentId is sha256(plaintext)[..16] for content-addressing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 09:47:23 -04:00
adlee-was-taken
9a5ae2c704 chore(core): add chrono wasmbind feature for WASM target
Code review flagged that chrono's clock feature requires wasmbind for
WASM builds — without it Utc::now() will fail at runtime in the
idfoto-wasm crate. Also drops the redundant hex entry in
[dev-dependencies] (already in [dependencies]).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 09:42:27 -04:00
adlee-was-taken
166f1418f7 chore(core): add deps for typed-item rewrite
zeroize, zxcvbn, bip39, unicode-normalization, chrono, hex, url, getrandom.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 09:37:56 -04:00
adlee-was-taken
be6928c0d1 docs: add Plan 1A — Rust core typed-item implementation
31 bite-sized TDD tasks covering: ID types, time helpers, error rewrite,
crypto fixes (length-prefix KDF, Zeroize, NFC, VERSION_BYTE 0x02), seven
typed cores with per-type modules, Field/FieldKind/FieldValue/Section,
Item envelope with field_history + soft-delete, AttachmentRef + content-
addressed encrypt/decrypt, Manifest with schema_version 2, VaultSettings,
CSPRNG generators with safe charset, BIP39 + zxcvbn strength gate, vault
helpers, retention pruning, full integration test suite.

idfoto-cli is expected to fail compilation at the end of this plan;
Plan 1B fixes it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 09:24:27 -04:00
adlee-was-taken
cc7247e7f6 docs: add security audit + typed-item data model design
Adds the Phase 1 design spec for the polymorphic typed-item rewrite (Login,
SecureNote, Identity, Card, Key, Document, TOTP — with sections, custom
fields, attachments, password history, and the security architecture from
the audit baked in from day one). Also adds the initial full-codebase
security audit that informs both Phase 0 remediation and Phase 1 design.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 01:35:49 -04:00
adlee-was-taken
2524270524 feat: add environment-aware WASM loading for Chrome/Firefox 2026-04-12 13:14:46 -04:00
adlee-was-taken
b71ebcc418 feat: add Firefox manifest and webpack config 2026-04-12 13:14:38 -04:00
adlee-was-taken
051c98dece docs: add Firefox extension port implementation plan
3 tasks: Firefox manifest + webpack config, environment-aware
WASM loading, and build integration with manual testing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 13:11:39 -04:00
adlee-was-taken
39f04a0b97 docs: add Firefox extension port design spec
Shared TypeScript source with separate manifests and webpack configs.
Firefox uses background scripts (not service workers) so WASM loading
uses dynamic import instead of initSync.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 13:01:57 -04:00
adlee-was-taken
ff19faff03 feat: add settings view with capture toggle and blacklist management
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 12:25:25 -04:00