@@ -10,6 +10,35 @@ range may break in any release.
1010
1111### Added
1212
13+ - ** PIN unlock.** Unlock the vault with a short PIN instead of the master
14+ password (like the Bitwarden extension/desktop), built on the encrypted cache.
15+ - ` vault pin set ` (requires an unlocked agent) encrypts the user key under a
16+ key derived from the PIN — same KDF/stretch/` EncString ` crypto as the
17+ master path, PIN as the secret, email as salt — and stores it as
18+ ` pin_protected_user_key ` in the cache (envelope schema 3). `vault pin
19+ disable` forgets it; ` vault pin status` reports enabled + attempts left.
20+ - ` vault unlock --pin ` recovers the user key from the cache with the PIN and
21+ builds a ** read-only** session (no token — ` sync ` /` add ` /` edit ` /` remove `
22+ return ` Error::Offline ` , like an offline unlock). Plain ` vault unlock `
23+ stays master-password.
24+ - ** Lockout:** wrong PINs are counted in the cache (so the limit survives an
25+ agent restart); the 5th wrong PIN wipes ` pin_protected_user_key ` and
26+ returns ` PinLockedOut ` — re-enable after a master-password unlock. Wrong
27+ PINs before that return ` BadPin { attempts_remaining } ` . New typed errors
28+ ` BadPin ` / ` PinLockedOut ` / ` PinNotSet ` (CLI exit codes 12/13/14). PIN must
29+ be ≥ 4 characters (validated client-side).
30+ - The cache→vault recovery core is shared between the offline-master and PIN
31+ paths (` recover_user_key ` + ` vault_from_user_key ` ); the attempt/lockout
32+ logic is a pure ` pin_attempt ` over an in-memory cache, with a thin
33+ disk-backed ` unlock_pin ` wrapper.
34+ - Tests: store pin-field round-trip; pure ` pin_attempt ` lifecycle (recover →
35+ reset counter → 5-strike lockout + key wipe → stays locked), ` PinNotSet `
36+ with no enrollment, and ` pin_protect_user_key ` ↔ ` recover_user_key `
37+ round-trip. No new dependencies.
38+ - Out of scope (tracked): TUI PIN entry; a PIN/offline session syncing once
39+ token persistence lands; Bitwarden's "require master password on restart"
40+ (memory-only pin key) mode.
41+
1342- ** Encrypted-cache persistence + offline unlock.** The agent now writes its
1443 vault to disk and can unlock without the network — the substrate for the
1544 upcoming ** PIN unlock** (and useful on its own).
0 commit comments