seedtool-cli 0.4.0

A command-line tool for generating and transforming cryptographic seeds.
use anyhow::{Result, bail};
use bc_envelope::Envelope;
use bc_ur::{MultipartDecoder, MultipartEncoder, URDecodable, UREncodable};

use super::{Format, InputFormat, OutputFormat};
use crate::{cli::Cli, seed::Seed};

pub struct MultipartFormat;

impl Format for MultipartFormat {
    fn name(&self) -> &str { "multipart" }

    fn round_trippable(&self) -> bool { true }
}

impl InputFormat for MultipartFormat {
    fn process_input(&self, mut state: Cli) -> Result<Cli> {
        let input = state.expect_input()?;
        let shares: Vec<&str> = input.split_whitespace().collect();

        let mut decoder = MultipartDecoder::new();
        for share in shares {
            decoder.receive(share)?;
            if decoder.is_complete() {
                break;
            }
        }

        if !decoder.is_complete() {
            bail!("Insufficient SSKR shares");
        }
        let ur = decoder.message().unwrap().unwrap();
        let envelope = Envelope::from_ur(&ur)?;
        let seed = Seed::try_from(envelope)?;
        state.seed = Some(seed);
        Ok(state)
    }
}

impl OutputFormat for MultipartFormat {
    fn process_output(&self, state: Cli) -> Result<String> {
        let ur = state.to_envelope().ur();
        let mut encoder = MultipartEncoder::new(&ur, state.max_fragment_len)?;
        let parts_count = encoder.parts_count() + state.additional_parts;
        let parts = (0..parts_count)
            .map(|_| encoder.next_part().map_err(anyhow::Error::from))
            .collect::<Result<Vec<String>>>()?;
        Ok(parts.join("\n"))
    }
}