tiny-encrypt 1.9.20

A simple and tiny file encrypt tool
// syntax
// tiny-encrypt-key:type:sid:key_id:public_part[?key=value]
// e.g.
// tiny-encrypt-key:ext-p256:ext-key-1:02536aef5742b4288f1b44b3cc96f1556c35e4fac4e8e117e1f7ae091e42d0835b:04536aef5742b4288f1b44b3cc96f1556c35e4fac4e8e117e1f7ae091e42d0835bf3f95d932c22a74a91859bd7fdd8829a02d38cf4ec598b1cf6e02fa09f707a6f

use crate::config::TinyEncryptConfigEnvelop;
use crate::spec::TinyEncryptEnvelopType;
use rust_util::{debugging, iff, opt_result, opt_value_result, simple_error, XResult};

const TINY_ENCRYPT_KEY_PREFIX: &str = "tiny-encrypt-key:";

pub fn serialize_config_envelop(config_envelop: &TinyEncryptConfigEnvelop) -> String {
    let mut s = String::new();
    s.push_str(TINY_ENCRYPT_KEY_PREFIX);
    s.push_str(config_envelop.r#type.get_name());
    s.push(':');
    s.push_str(&encode(config_envelop.sid.as_deref().unwrap_or("")));
    s.push(':');
    s.push_str(&encode(&config_envelop.kid));
    s.push(':');
    s.push_str(&encode(&config_envelop.public_part));
    s
}

pub fn parse_temporary_keys(temporary_keys: &Option<Vec<String>>) -> XResult<Vec<TinyEncryptConfigEnvelop>> {
    let mut temporary_envelops = vec![];
    if let Some(temporary_key) = temporary_keys {
        for t_key in temporary_key {
            let envelop = opt_result!(deserialize_config_envelop(t_key), "Parse temporary key: {} failed: {}", t_key);
            temporary_envelops.push(envelop);
        }
        debugging!("Temporary envelops: {:?}", temporary_envelops);
    }
    Ok(temporary_envelops)
}

pub fn deserialize_config_envelop(k: &str) -> XResult<TinyEncryptConfigEnvelop> {
    if !k.starts_with(TINY_ENCRYPT_KEY_PREFIX) {
        return simple_error!("invalid temporary key");
    }
    let k_parts = k.split(":").collect::<Vec<_>>();
    if k_parts.len() != 5 {
        return simple_error!("invalid temporary key (parts)");
    }
    let envelop_type = opt_value_result!(
        TinyEncryptEnvelopType::from_name(k_parts[1]), "Unknown envelop type: {}", k_parts[1]);
    Ok(TinyEncryptConfigEnvelop {
        r#type: envelop_type,
        sid: iff!(k_parts[2].is_empty(), None, Some(decode(k_parts[2])?)),
        kid: decode(k_parts[3])?,
        desc: None,
        args: None,
        public_part: decode(k_parts[4])?,
        profiles: None,
    })
}

fn encode(s: &str) -> String {
    percent_encoding::utf8_percent_encode(s, percent_encoding::NON_ALPHANUMERIC).to_string()
}

fn decode(s: &str) -> XResult<String> {
    Ok(opt_result!(
        percent_encoding::percent_decode_str(s).decode_utf8(),
        "decode: {} failed: {}",
        s
    )
    .to_string())
}