chore: merge rename commit into Plan 1B branch

Resolves conflicts from merging origin/main (idfoto→relicario rename):
- Kept Plan 1A's typed-item vault.rs, lib.rs, integration.rs over main's
  old entry-based versions
- Took main's relicario_dir() fix in CLI main.rs (sed had missed idfoto_dir)
- Kept Plan 1A's UnsupportedFormatVersion error variant in crypto.rs
- Kept Plan 1A's opaque Decrypt message (audit M4) in error.rs
- Deleted entry.rs (replaced by item.rs + typed modules in Plan 1A)
- Resolved Cargo.toml description to main's "relicario password manager"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
adlee-was-taken
2026-04-19 20:58:35 -04:00
51 changed files with 1230 additions and 1419 deletions

View File

@@ -1,4 +1,4 @@
//! idfoto CLI -- the platform layer for the idfoto password manager.
//! relicario CLI -- the platform layer for the relicario password manager.
//!
//! This binary provides the filesystem, git, and terminal I/O that
//! [`relicario_core`] intentionally excludes. It is the "glue" between the
@@ -69,7 +69,7 @@ struct Cli {
/// All available CLI subcommands.
#[derive(Subcommand)]
enum Commands {
/// Initialize a new idfoto vault in the current directory.
/// Initialize a new relicario vault in the current directory.
/// Creates the directory structure, generates a random image secret,
/// embeds it in the carrier image, and sets up git.
Init {
@@ -150,14 +150,14 @@ struct DeviceEntry {
// ─── Helper functions ───────────────────────────────────────────────────────
/// Returns the vault root directory (the current working directory).
/// The vault is always rooted at the directory where `idfoto` is invoked.
/// The vault is always rooted at the directory where `relicario` is invoked.
fn vault_dir() -> PathBuf {
std::env::current_dir().expect("failed to get current directory")
}
/// Returns the path to the `.relicario/` configuration directory within the vault.
fn idfoto_dir() -> PathBuf {
vault_dir().join(".idfoto")
fn relicario_dir() -> PathBuf {
vault_dir().join(".relicario")
}
/// Read the 32-byte vault salt from `.relicario/salt`.
@@ -166,7 +166,7 @@ fn idfoto_dir() -> PathBuf {
/// not secret (stored in plaintext) -- its purpose is to prevent precomputed
/// rainbow table attacks against the Argon2id KDF.
fn read_salt() -> Result<[u8; 32]> {
let data = fs::read(idfoto_dir().join("salt")).context("failed to read salt")?;
let data = fs::read(relicario_dir().join("salt")).context("failed to read salt")?;
let mut salt = [0u8; 32];
if data.len() != 32 {
bail!("invalid salt file: expected 32 bytes, got {}", data.len());
@@ -177,7 +177,7 @@ fn read_salt() -> Result<[u8; 32]> {
/// Read the KDF parameters from `.relicario/params.json`.
fn read_params() -> Result<KdfParams> {
let data = fs::read_to_string(idfoto_dir().join("params.json"))
let data = fs::read_to_string(relicario_dir().join("params.json"))
.context("failed to read params.json")?;
let params: KdfParams = serde_json::from_str(&data).context("failed to parse params.json")?;
Ok(params)
@@ -319,7 +319,7 @@ fn generate_password(length: usize) -> String {
// ─── Command implementations ────────────────────────────────────────────────
/// Initialize a new idfoto vault in the current directory.
/// Initialize a new relicario vault in the current directory.
///
/// Full sequence:
/// 1. Read the carrier JPEG provided by the user.
@@ -375,18 +375,18 @@ fn cmd_init(image: PathBuf, output: PathBuf) -> Result<()> {
.context("failed to derive master key")?;
// 8. Create directory structure
let idfoto = idfoto_dir();
fs::create_dir_all(&idfoto).context("failed to create .idfoto directory")?;
let relicario = relicario_dir();
fs::create_dir_all(&relicario).context("failed to create .relicario directory")?;
fs::create_dir_all(vault_dir().join("entries")).context("failed to create entries directory")?;
// 9. Write config files
fs::write(idfoto.join("salt"), &salt).context("failed to write salt")?;
fs::write(relicario.join("salt"), &salt).context("failed to write salt")?;
fs::write(
idfoto.join("params.json"),
relicario.join("params.json"),
serde_json::to_string_pretty(&params)?,
)
.context("failed to write params.json")?;
fs::write(idfoto.join("devices.json"), "[]").context("failed to write devices.json")?;
fs::write(relicario.join("devices.json"), "[]").context("failed to write devices.json")?;
// 10. Encrypt empty manifest
let manifest = Manifest::new();
@@ -404,7 +404,7 @@ fn cmd_init(image: PathBuf, output: PathBuf) -> Result<()> {
if !status.success() {
bail!("git init failed");
}
git_commit("feat: initialize idfoto vault")?;
git_commit("feat: initialize relicario vault")?;
// 13. Success
eprintln!("Vault initialized successfully.");
@@ -760,7 +760,7 @@ fn cmd_sync() -> Result<()> {
/// Read the device registry from `.relicario/devices.json`.
fn read_devices() -> Result<Vec<DeviceEntry>> {
let path = idfoto_dir().join("devices.json");
let path = relicario_dir().join("devices.json");
let data = fs::read_to_string(&path).context("failed to read devices.json")?;
let devices: Vec<DeviceEntry> = serde_json::from_str(&data).context("failed to parse devices.json")?;
Ok(devices)
@@ -769,13 +769,13 @@ fn read_devices() -> Result<Vec<DeviceEntry>> {
/// Write the device registry to `.relicario/devices.json`.
fn write_devices(devices: &[DeviceEntry]) -> Result<()> {
let data = serde_json::to_string_pretty(devices)?;
fs::write(idfoto_dir().join("devices.json"), data).context("failed to write devices.json")?;
fs::write(relicario_dir().join("devices.json"), data).context("failed to write devices.json")?;
Ok(())
}
/// Register a new device by generating an ed25519 keypair.
///
/// The private key is saved to `~/.config/idfoto/<name>.key` with
/// The private key is saved to `~/.config/relicario/<name>.key` with
/// restrictive permissions (0600 on Unix). The public key is added to
/// the vault's devices.json and committed to git.
///