Add purpose, architecture, and public API summary to each crate README following chanora_resolver pattern. Update verification master plan with new evidence sources and entry/exit criteria.
69 lines
3.3 KiB
Markdown
69 lines
3.3 KiB
Markdown
# chanora_storage
|
|
|
|
Two strictly separated storage concerns per SAD-067:
|
|
|
|
1. **`BookmarkRepository`** — non-secret bookmark state via SQLite with optional encrypted password fields (`rusqlite` bundled, DEC-013.1).
|
|
2. **`IdentityFileStore`** — Beta fallback storage for identity material while platform secure-storage backends mature.
|
|
|
|
## Architecture
|
|
|
|
### IdentityFileStore
|
|
|
|
- Persists a single TS3 identity to `<dir>/identity.tskey` encrypted with ChaCha20-Poly1305.
|
|
- The Data Encryption Key (DEK) is 32 random bytes stored in the platform keyring (Linux Secret Service, macOS Keychain, Windows Credential Manager, iOS Keychain) when available, with a best-effort file fallback at `identity.dek` (mode 0600 on Unix).
|
|
- Legacy plaintext files from pre-Beta are still readable; the next `save()` upgrades them to encrypted form.
|
|
- Audio metadata (`transmit_mode`, `release_tail_ms`, PTT binding) is persisted alongside as `audio_meta.json` (plaintext, non-secret).
|
|
|
|
### BookmarkRepository
|
|
|
|
- SQLite-backed store at `<dir>/chanora.db`.
|
|
- Schema v1: basic bookmark columns. Schema v2: adds `password_blob` for encrypted passwords.
|
|
- When constructed via `with_crypto()`, the `password` column is replaced by a ChaCha20-Poly1305 envelope under the same per-install DEK.
|
|
- Legacy plaintext passwords are transparently read and upgraded on the next `update()`.
|
|
|
|
### Crypto abstraction
|
|
|
|
- `Crypto` trait: `encrypt(plaintext)` / `decrypt(blob)` — callers see only the encrypt/decrypt pair.
|
|
- `DekCrypto` — concrete implementation sharing the same per-install DEK with `IdentityFileStore`.
|
|
|
|
## Public API Summary
|
|
|
|
### Types
|
|
|
|
| Type | Role |
|
|
|---|---|
|
|
| `IdentityFileStore` | Encrypted identity file store |
|
|
| `BookmarkRepository` | SQLite bookmark store with optional password encryption |
|
|
| `Bookmark` | Bookmark DTO: id, display_name, host, nickname, password |
|
|
| `PttBindingMeta` | Persisted PTT binding metadata |
|
|
| `StorageError` | NotFound, Migration, Sqlite, SecureStore, Io, Crypto |
|
|
| `Crypto` trait | Encrypt/decrypt abstraction |
|
|
|
|
### IdentityFileStore methods
|
|
|
|
- `new(dir)` — create or open store, ensure DEK exists
|
|
- `load()` → `Option<String>` — read identity (handles legacy plaintext)
|
|
- `save(identity)` — persist encrypted (ChaCha20-Poly1305, atomic write)
|
|
- `clear()` — remove identity file
|
|
- `crypto()` — obtain a `Crypto` handle sharing the DEK
|
|
- `set_transmit_mode(mode)` / `get_transmit_mode()` — audio settings persistence
|
|
- `set_release_tail_ms(ms)` / `get_release_tail_ms()` — release-tail persistence
|
|
- `set_ptt_binding(...)` / `get_ptt_binding()` — PTT binding persistence
|
|
|
|
### BookmarkRepository methods
|
|
|
|
- `new(dir)` / `with_crypto(dir, crypto)` — open (plain or encrypted)
|
|
- `add(bookmark)` → `i64` — insert, return id
|
|
- `update(bookmark)` — replace by id
|
|
- `delete(id)` — remove by id
|
|
- `list()` → `Vec<Bookmark>` — all bookmarks ordered by id
|
|
- `upsert_or_add(bookmark)` — insert or update by host, preserves user's display name
|
|
- `encrypts_passwords()` — whether password encryption is active
|
|
|
|
## Platform notes
|
|
|
|
- Unix: files written with mode 0600.
|
|
- Keyring access can be disabled via `CHANORA_DISABLE_KEYRING=1` for tests/headless environments.
|
|
- Android: file in app-private storage (not encrypted at rest — documented Beta gap).
|
|
- iOS/Windows/macOS: caller provides the storage directory; platform sandbox handles access control.
|