v0.0.12: Encrypted backup/restore + history module
Protocol: - history.rs: derive_history_key (HKDF from seed, info="warzone-history") - encrypt_history / decrypt_history (ChaCha20-Poly1305, WZH1 magic) - 2 new tests (roundtrip + wrong seed), total 19/19 CLI: - `warzone backup [output.wzb]` — exports all sessions + pre-keys as encrypted blob (only your seed can decrypt) - `warzone restore <input.wzb>` — imports backup, merges (no overwrite) - Backup format: WZH1 magic + nonce + encrypted JSON Storage: - export_all() — dumps sessions + pre-keys as base64 JSON - import_all() — merges backup data (skip existing entries) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -55,6 +55,17 @@ enum Commands {
|
||||
#[arg(short, long, default_value = "http://localhost:7700")]
|
||||
server: String,
|
||||
},
|
||||
/// Export encrypted backup of local data (sessions, history)
|
||||
Backup {
|
||||
/// Output file path
|
||||
#[arg(default_value = "warzone-backup.wzb")]
|
||||
output: String,
|
||||
},
|
||||
/// Restore from encrypted backup
|
||||
Restore {
|
||||
/// Backup file path
|
||||
input: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
@@ -102,6 +113,25 @@ async fn main() -> anyhow::Result<()> {
|
||||
let db = storage::LocalDb::open()?;
|
||||
tui::run_tui(our_fp, peer, server, identity, poll_seed, db).await?;
|
||||
}
|
||||
Commands::Backup { output } => {
|
||||
let data_dir = keystore::data_dir();
|
||||
// Collect all sled data as JSON
|
||||
let db = storage::LocalDb::open()?;
|
||||
let backup_data = db.export_all()?;
|
||||
let json = serde_json::to_vec(&backup_data)?;
|
||||
let encrypted = warzone_protocol::history::encrypt_history(&seed.0, &json);
|
||||
std::fs::write(&output, &encrypted)?;
|
||||
println!("Backup saved to {} ({} bytes encrypted)", output, encrypted.len());
|
||||
}
|
||||
Commands::Restore { input } => {
|
||||
let encrypted = std::fs::read(&input)?;
|
||||
let json = warzone_protocol::history::decrypt_history(&seed.0, &encrypted)
|
||||
.map_err(|_| anyhow::anyhow!("Decryption failed — wrong seed?"))?;
|
||||
let backup_data: serde_json::Value = serde_json::from_slice(&json)?;
|
||||
let db = storage::LocalDb::open()?;
|
||||
let count = db.import_all(&backup_data)?;
|
||||
println!("Restored {} entries from {}", count, input);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user