extern crate ctap_hmac as ctap;

use crypto::digest::Digest;
use crypto::sha2::Sha256;
use ctap::extensions::hmac::HmacExtension;
use ctap::{FidoAssertionRequestBuilder, FidoCredential, FidoCredentialRequestBuilder};
use hex;
use std::env::args;
use std::io::prelude::*;
use std::io::stdin;
use std::io::stdout;

const RP_ID: &str = "ctap_demo";

fn main() -> ctap::FidoResult<()> {
    let mut devices = ctap::get_devices()?;
    let device_info = &mut devices.next().expect("No authenticator found");
    let mut device = ctap::FidoDevice::new(device_info)?;

    let credential = match args().skip(1).next().map(|h| FidoCredential {
        id: hex::decode(&h).expect("Invalid credential"),
        public_key: None,
    }) {
        Some(cred) => cred,
        _ => {
            let req = FidoCredentialRequestBuilder::default()
                .rp_id(RP_ID)
                .rp_name("ctap_hmac crate")
                .user_name("example")
                .uv(false)
                .build()
                .unwrap();

            println!("Authorize using your device");
            let cred = device
                .make_hmac_credential(&req)
                .expect("Failed to request credential");
            println!("Credential: {}\nNote: You can pass this credential as first argument in order to reproduce results", hex::encode(&cred.id));
            cred
        }
    };
    print!("Type in your message: ");
    stdout().flush().unwrap();
    let mut message = String::new();
    stdin()
        .read_line(&mut message)
        .expect("Couldn't get your message\nNote: this demo does not accept binary data");
    println!("Authorize using your device");

    let mut salt = [0u8; 32];
    let mut digest = Sha256::new();
    digest.input(&message.as_bytes());
    digest.result(&mut salt);
    let credential = &&credential;
    let request = FidoAssertionRequestBuilder::default()
        .rp_id(RP_ID)
        .credential(credential)
        .build()
        .unwrap();
    let (_cred, (hash1, _hash2)) = device.get_hmac_assertion(&request, &salt, None)?;
    println!("Hash: {}", hex::encode(&hash1));
    Ok(())
}
