cotp 0.1.9

Trustworthy, encrypted, command-line TOTP/HOTP authenticator app with import functionality.
use std::fs::read_to_string;

use data_encoding::BASE32_NOPAD;
use serde::Deserialize;
use serde_json;

use crate::otp::otp_element::OTPElement;

#[derive(Deserialize)]
struct FreeOTPPlusJson{
    #[serde(rename = "tokenOrder")]
    token_order: Vec<String>,
    tokens: Vec<FreeOTPElement>,
}

#[derive(Deserialize)]
struct FreeOTPElement {
    algo: String,
    counter: u64,
    digits: u64,
    #[serde(rename = "issuerExt")]
    issuer_ext: String,
    #[serde(rename = "label")]
    _label: String,
    period: u64,
    secret: Vec<i8>,
    #[serde(rename = "type")]
    _type: String,
}

pub fn import(file_path: &str) -> Result<Vec<OTPElement>,String>{
    let json = match read_to_string(file_path) {
        Ok(r) => r,
        Err(e) => return Err(format!("{:?}",e)),
    };

    let freeotp: FreeOTPPlusJson = match serde_json::from_str(json.as_str()){
        Ok(r) => r,
        Err(e)=> return Err(format!("Error during deserializing: {:?}",e)),
    };

    let mut converted_elements: Vec<OTPElement> = vec![];
    let mut i = 0;
    for token in freeotp.tokens {
        converted_elements.push(
            OTPElement::new(
                encode_secret(&token.secret),
                token.issuer_ext,
                freeotp.token_order.get(i).unwrap_or(&String::from("No label")).to_owned(),
                token.digits,
                token._type,
                token.algo,
                String::from(""),
                0,
                0,
                token.period,
                token.counter,
                vec![])
        );
        i += 1;
    }

    Ok(converted_elements)
}

fn encode_secret(secret: &Vec<i8>) -> String {
    BASE32_NOPAD.encode(secret
        .iter()
        .map(|n| *n as u8)
        .collect::<Vec<u8>>()
        .as_slice()
    )
}

#[cfg(test)]
mod tests{
    use super::encode_secret;

    #[test]
    fn test_secret_conversion(){
        let secret: Vec<i8> =
        vec![-34,104,-37,-33,82,-89,-93,-105,-14,5,100,-73,-84,1,11,73,101,-92
        ,106,122,-90,111,-119,30,87,-6,16,-57,-126,25,0,-65,-35,-76,-38];

        assert_eq!(encode_secret(&secret), String::from("3ZUNXX2SU6RZP4QFMS32YAILJFS2I2T2UZXYSHSX7IIMPAQZAC753NG2"));
    }
}