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>
The getrandom crate (transitive dep via rand/argon2) requires the
"js" feature flag to compile for wasm32-unknown-unknown targets.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The ManifestEntry was being written with group: None instead of
preserving the entry's existing group value during edits.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add optional group: Option<String> to both Entry and ManifestEntry for
logical organization (e.g. "work", "personal"). Backwards-compatible via
skip_serializing_if so existing vaults deserialize with group: None.
Includes three new tests verifying round-trip and legacy deserialization.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Corrected zig-zag scan positions from 4-15 to 6-17 (verified against
standard JPEG zig-zag ordering). Fixed inverted HVS luminance reasoning
to correctly explain that luminance is used because it isn't spatially
subsampled by JPEG, not because of visual sensitivity.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Document every public function, struct, field, constant, and non-trivial
private function across idfoto-core and idfoto-cli. Module-level docs
explain each module's role in the architecture. Comments explain the "why"
(crypto choices, algorithm design, data model rationale) not just the "what".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds dimension-search crop recovery that tries candidate original sizes
to reconstruct the embed grid, and fixes test imports for GenericImageView.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements DCT-based steganography module that hides 256-bit secrets in
JPEG luminance channel using Quantization Index Modulation (QIM) with
redundant copies and majority voting for reliable extraction.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>