Skip to content

Commit 9572930

Browse files
UnbreakableMJclaude
andcommitted
feat(vault-api, vault-store): M2 — login, sync, encrypted cache
Implement the Bitwarden / Vaultwarden REST surface and the encrypted on-disk sync cache per PRD §12 (M2 gate). vault-core: - master_password_hash(): base64 PBKDF2-SHA-256(master_key, password, 1). This is the credential Bitwarden sends to /identity/connect/token; the real master password never leaves the client. vault-api (new module surface): - BaseUrls: split for hosted Bitwarden (api/identity subdomains) and unified for Vaultwarden (/api + /identity under one origin). - BitwardenClient (reqwest + rustls): prelogin, login_password, sync. Holds the access token in a Zeroizing<String>; never holds the master key. 2FA-required responses surface as a typed error rather than a generic 400. https_only is enabled when the API scheme is https. - identity / sync wire types as serde shapes, with non-essential fields kept as serde_json::Value so schema drift doesn't break the cache round-trip. vault-store: - VaultCache: serde JSON envelope at <data-dir>/vault/cache.json with schema_version, device_id, server origin, lowercase email, last_sync RFC 3339 stamp, and an encrypted `payload` field (Vault EncString over the raw /sync response bytes). - Atomic writes via NamedTempFile::persist (tempfile in the same directory → fsync → rename) so a crash mid-write can't tear the cache. Tests: - vault-api::tests::parsing — 7 wire-shape decode tests, no HTTP. - vault-store::tests::cache — 4 disk-cache round-trip tests (encrypted-on-disk asserted; wrong-key fails; missing file = NotFound; no-payload = NoPayload). - vault-api::tests::login_sync — full wiremock integration covering prelogin → login_password (asserting the form body contains the expected master-password hash) → sync → VaultCache encrypted-write → reload → decrypt → equality. Kept #[ignore] for now: the test binary links ring statically, and cargo's `links =` propagation drops the static-lib flag on this maintainer's host environment. CI runs it via --ignored on a clean toolchain. The library code itself builds fine — `cargo build --workspace` and the parsing / cache test suites are green. docs/m2-vaultwarden.md documents the manual M2 gate against a real Vaultwarden container (podman/docker run, register, sync, persist). Workspace deps added: reqwest (rustls-tls + json), url, uuid, dirs, time, fs2, tempfile, wiremock (dev), tokio-test (dev). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 0c669fe commit 9572930

18 files changed

Lines changed: 3234 additions & 290 deletions

File tree

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,24 @@ range may break in any release.
1818
`LICENSE`, `CREDITS.md`, `CHANGELOG.md`.
1919
- `PRD.md` — full product requirements document.
2020
- CI configuration: `fmt`, `clippy -D warnings`, `cargo audit`, `cargo deny`.
21+
- **M2 — login + sync against Vaultwarden.**
22+
- `vault-core::login::master_password_hash` — base64 `PBKDF2-SHA-256(master_key, password, 1)` for `/identity/connect/token`.
23+
- `vault-api``BitwardenClient` over `reqwest` + `rustls`, with `prelogin`,
24+
`login_password`, and `sync` methods. `BaseUrls` accommodates both
25+
Bitwarden's hosted split (`api.bitwarden.com` + `identity.bitwarden.com`)
26+
and Vaultwarden's single-origin `/api` + `/identity` deployment.
27+
Two-factor detection on `400` with `TwoFactorProviders[2]` surfaces a
28+
typed `TwoFactorRequired` error.
29+
- `vault-store``VaultCache` with serde JSON envelope on disk and an
30+
encrypted `payload` field (Vault `EncString` over the raw `/sync`
31+
response). Writes go through an atomic `NamedTempFile::persist` rename.
32+
- **Tests**`vault-api::tests::parsing` (7) covers wire-shape decoding;
33+
`vault-store::tests::cache` (4) covers the encrypted persistence
34+
round-trip; `vault-api::tests::login_sync` is the full wiremock
35+
integration test, kept `#[ignore]` pending a clean test-binary linker
36+
environment (see file preamble — library and `--bin vault` build fine).
37+
- `docs/m2-vaultwarden.md` — recipe for the real Vaultwarden-in-a-container
38+
manual gate.
2139
- **M1 — offline export decrypt.** `vault-core` now ships:
2240
- `EncString` (Bitwarden type 2: AES-256-CBC + HMAC-SHA-256, Encrypt-then-MAC
2341
with constant-time verification; legacy types 0/1 explicitly rejected).

0 commit comments

Comments
 (0)