feat: gsmol-compatible backup export and import behind the store feature

This commit is contained in:
randogoth 2026-09-29 00:23:04 +03:00
parent 96d2412370
commit 4a780ed648
6 changed files with 528 additions and 17 deletions

View file

@ -86,6 +86,14 @@ enum Command {
Import { uri: String },
/// List known keys and how each was learned
Contacts,
/// Write a gsmol backup: sealed mail, contacts and pins, never the master
Export {
/// Output file
#[arg(default_value = "smol-backup.json")]
file: PathBuf,
},
/// Restore a gsmol backup file; merges, never overwrites a trust binding
ImportBackup { file: PathBuf },
/// Issue an accept token, admit to the main tier, sync the set
Accept { address: String },
/// Withdraw a contact's accept token, sync the set
@ -192,6 +200,8 @@ fn run(cli: Cli) -> Result<()> {
Command::Resolve { address } => resolve(&store, address, cli.timeout),
Command::Import { uri } => import(&store, uri),
Command::Contacts => contacts(&store),
Command::Export { file } => export_backup(&cli.key, &store, file),
Command::ImportBackup { file } => import_backup(&cli.key, &store, file),
Command::Accept { address } => accept(&cli.key, &store, address, cli.timeout),
Command::Block { address } => block(&cli.key, &store, address, cli.timeout),
Command::Send { .. } => send(&cli, &store),
@ -448,6 +458,23 @@ fn contacts(store: &Store) -> Result<()> {
Ok(())
}
fn export_backup(key: &PathBuf, store: &Store, file: &PathBuf) -> Result<()> {
let master = load_master(key)?;
let text = fumi::export::export(store, &master)?;
std::fs::write(file, text)?;
println!("wrote {} (only the master can open it)", file.display());
Ok(())
}
fn import_backup(key: &PathBuf, store: &Store, file: &PathBuf) -> Result<()> {
let master = load_master(key)?;
let text = std::fs::read_to_string(file)
.with_context(|| format!("reading {}", file.display()))?;
let summary = fumi::export::import(store, &master, &text)?;
println!("{summary}");
Ok(())
}
/// An address plus the key we hold for it, for commands naming a contact.
fn target_contact(store: &Store, text: &str) -> Result<(String, [u8; KEY_LEN])> {
let addr = Address::parse(text)?;