CLI password manager (Rust). Optimize for short context: read this first, then only the files you need.
- Rust edition 2021, package
rpass(src/lib.rs+ binsrc/main.rs) - CLI: clap derive · crypto: argon2 + aes-gcm + rand · secrets wipe: zeroize
- Errors: thiserror (
error::Error/error::Result) — avoid bareunwrapin lib paths - Serde JSON vault file · config TOML · storage under XDG dirs
| Path | Responsibility | Touch when… |
|---|---|---|
src/cli/mod.rs |
dispatch run() |
wire new commands |
src/cli/args.rs |
clap structs / enums | flags, subcommands |
src/cli/handlers.rs |
cmd_* handlers |
command behaviour |
src/cli/prompt.rs |
master-password prompts, open_vault |
UX prompts |
src/cli/clipboard.rs |
clipboard copy / clear | clipboard UX |
src/cli/repl.rs |
interactive mode | REPL commands |
src/vault.rs |
unlocked vault API, CRUD, audit, import/export, tables | business ops on entries |
src/crypto.rs |
KDF, AES-GCM, password gen, TOTP, strength, HIBP, b64 | crypto behaviour |
src/wordlist.txt |
passphrase dictionary | Diceware words |
src/storage.rs |
FileStore, seal/unseal, session, backups, paths | persistence / session / paths |
src/models.rs |
Entry, VaultData, MasterKey, audit types |
data shape / serde fields |
src/config.rs |
TOML config + env + VaultPrefs |
defaults, keys, multi-vault map |
src/error.rs |
error enum (Display via i18n) |
new failure modes |
src/i18n.rs |
EN/FR UI language (t / tfmt! / init) |
new UI strings |
src/main.rs |
parse → cli::run, exit codes |
exit mapping only |
tests/vault_flow.rs |
library lifecycle tests | vault API regressions |
tests/integration.rs |
binary smoke tests | CLI surface smoke |
completions/* |
shell completion scripts | new top-level commands |
Do not invent parallel storage layers. Extend VaultStore / FileStore if needed.
- Disk always encrypted: plaintext
VaultDataexists only in memory after unlock. Mutate →Vault::save()→storage::seal(AES-GCM, fresh nonce each write). - File format
EncryptedVault:version,salt(b64),nonce(b64),ciphertext(b64+tag),written_at. Atomic write:*.tmp+ rename; Unix mode0600. - Key hierarchy: master password + salt → Argon2id (
hash_password_into) → 32-byteMasterKey(zeroized). Session (P0): master key scellée dansdata_dir/.{name}.session; wrap key dansruntime_dir/{name}.wrap($RPASS_RUNTIME_DIRou$XDG_RUNTIME_DIR/rpass, sinondata_dir/runtime/). Jamais les deux dans le même fichier.vault_pathvalidé ;is_session_activene déchiffre pas / ne prolonge pas. - Decrypt errors:
crypto::decrypt→DecryptFailed;storage::unseal(MDP saisi) mappe versWrongMasterPassword. Session invalide → purge +VaultLocked. - Write lock:
FileStore::save_encryptedprend un lock coopératif{name}.vault.lock(PID) ; erreurVaultBusysi concurrent vivant. - Entry keys in map: lowercase service name (
VaultData::entry_key). Display name keeps original casing. - Password change goes through
Entry::set_password(history, max 10, updatespassword_changed_at). - Unlock:
Vault::open_or_prompt/ session first — do not require password if session valid. - Clipboard: effacement non garanti en CLI one-shot ;
RPASS_CLIPBOARD_WAIT=1force l'attente. REPL OK. - No exploit PoCs, no weak crypto “for tests” in production paths. Tests may use temp dirs via
RPASS_DATA_DIR/RPASS_CONFIG/RPASS_RUNTIME_DIR.
- Vault:
$RPASS_DATA_DIRordirs::data_dir()/rpass/{name}.vault→ typically~/.local/share/rpass/default.vault - Config:
$RPASS_CONFIGor~/.config/rpass/config.toml - Session meta: data dir
.{name}.session - Session wrap key: runtime dir
{name}.wrap - Backups: data dir
backups/{name}_{timestamp}.vault.bak - Env overrides:
RPASS_VAULT,RPASS_VAULT_PATH,RPASS_DATA_DIR,RPASS_RUNTIME_DIR,RPASS_TIMEOUT,RPASS_PASSWORD_LENGTH,RPASS_LANG(en/fr),RPASS_CLIPBOARD_WAIT,NO_COLOR
- Vault mgmt:
init|unlock|lock|change-master-password|status|destroy→Vault::*+ session instorage - CRUD:
add|get|show|list|update|delete|search→Vault+vault::print_* - Gen:
generate/ auto onadd→crypto::generate_password/vault::gen_password_from_opts - Audit:
audit|check-breach|strength|expire→Vault::audit,crypto::{check_breach,password_strength} - TOTP:
add-totp|totp→Vault::{add_totp,totp}/crypto::generate_totp* - I/O:
export|import|backup|restore→ vault import/export helpers +storage::{create_backup,restore_backup} - Config/REPL/completions:
config|*,interactive,completions
Global flag: --vault <name> (not short -V; version uses -V).
- Errors: add variants in
error.rs, returnResult<T>, map at boundaries incli.rs. - UI strings: English default; French via
RPASS_LANG=fr/config.languageusingcrate::i18n::{t,tfmt,init}. - Display tables:
colored/comfy-table; respect password masking unless--show. - Clipboard: best-effort (
arboard); failure must not abort core ops. - Sensitive types:
MasterKey,MasterPassworduseZeroize/ZeroizeOnDrop— keep secrets out ofDebuglogs. - Prefer small functions; keep clap structs and handlers in
cli.rs(large file — jump via command name /fn cmd_). - Imports: std → external →
crate::.
cargo test
cargo build # or --release for CLI smoke
./target/debug/rpass --helpTargeted:
cargo test --test vault_flow
cargo test --lib cryptoNeed isolated vault in tests: set RPASS_DATA_DIR + RPASS_CONFIG to a temp dir (see tests/vault_flow.rs).
Multi-user/sync-cloud, team hybrid crypto, full i18n, generated man pages, clap_complete crate (completions are static under completions/).
- Prefer surgical reads of one module; for CLI:
args.rs(flags) →handlers.rs(fn cmd_) →repl.rsif REPL. - After behavior change in vault/crypto/storage: update or add a test in
tests/vault_flow.rsor unit tests in the same module. - Do not re-document the whole README in PRs; change README only if user-facing paths/commands change.
- Avoid drive-by refactors and new heavy deps without need.