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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
5 tasks: types/messages, service worker handlers, capture content
script with bar/toast prompts, settings popup view, and integration.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Experimental feature for auto-detecting login form submissions and
prompting to save/update credentials. Configurable bar or toast
prompt style, off by default, with per-site blacklist.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The popup is too constrained for multi-step setup (file pickers
close it, fields duplicate the init wizard). Now it just shows
a single button that opens the full-page setup wizard.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Chrome closes popups when file pickers steal focus. Instead, check
chrome.storage.local for an existing image (pushed by init wizard),
and redirect to the full-page setup.html if no image is found.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Calling setState() after FileReader.onload triggered a full popup
re-render which could crash or close the popup with large images.
Update DOM elements in place instead, and add error handling.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Chrome MV3 service workers do not support dynamic import().
Switch to static import of the wasm-pack JS glue and use
initSync() with fetch() to load the WASM binary at runtime.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>