diff --git a/Cargo.lock b/Cargo.lock index 6bc5dfe..37293dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -405,6 +405,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" + [[package]] name = "hex-literal" version = "0.3.1" @@ -753,6 +759,7 @@ dependencies = [ "color-eyre", "cryptohelpers", "futures", + "hex", "lazy_static", "libc", "pin-project", diff --git a/Cargo.toml b/Cargo.toml index 31b342c..349069b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,7 @@ futures = "0.3.5" chrono = "0.4.15" pin-project = "0.4.23" base64 = "0.12.3" +hex = "0.4.2" #serde_json = "1.0.57" # serde not suitable for our text formatting :/ maybe just use `cbor` -> base64 with text header? would be a PEM-like format. sounds good imo [build-dependencies] diff --git a/src/ext.rs b/src/ext.rs index 887bc55..8d2e0ca 100644 --- a/src/ext.rs +++ b/src/ext.rs @@ -261,7 +261,7 @@ impl<'a, T: AsyncRead+Unpin+?Sized> Future for ReadAllBytes<'a, T> let mut input = this.0; let max = *this.1; let mut buffer =[0u8; 4096]; - let mut read =0; + let mut read; while {read = input.read(&mut buffer[..]).await?; read!=0} { output.extend_from_slice(&buffer[..read]); if let Some(max) = max { diff --git a/src/format/key/mod.rs b/src/format/key/mod.rs index 430ef2f..d07e165 100644 --- a/src/format/key/mod.rs +++ b/src/format/key/mod.rs @@ -115,7 +115,7 @@ impl KeyHeader out.write_u8(b'\n').await?; written += bytes.len() + 1; } - out.write_all(b"\n---").await?; + out.write_all(b"---").await?; Ok(written + 4) } /// Read a superheader as text bytes from this stream @@ -126,10 +126,10 @@ impl KeyHeader let line_sender = async move { //this is actually kinda overkill for this... let mut buffer = String::new(); while input.read_line(&mut buffer).await? != 0 { - tx.send(buffer.clone()); + tx.send(buffer.clone()).await?; buffer.clear(); } - Ok::<(), io::Error>(()) + Ok::<(), eyre::Report>(()) }; let line_reader = async { let mut enc = String::new(); @@ -223,6 +223,7 @@ mod tests #[test] fn now_or_never() { + color_eyre::install().unwrap(); let mut vec = Vec::new(); use tokio::{ prelude::*, @@ -283,9 +284,7 @@ mod tests #[tokio::test] async fn serde_text() -> Result<(), eyre::Report> - { - color_eyre::install()?; - + { let header = KeyHeader::new_now(KeyHeaderKind::Aes, Default::default(), Default::default()); let mut ser = Vec::new(); println!("Writing {:?}", header); @@ -303,10 +302,7 @@ mod tests #[tokio::test] async fn serde_text_with_super() -> Result<(), eyre::Report> { - //color_eyre::install()?; - - panic!("We're going to have to write our own text serialisation to get around the `read_whole_buffer` thingy..."); - /* + let header = KeyHeader::new_now(KeyHeaderKind::Aes, Default::default(), Default::default()); let mut ser = Vec::new(); let superheader = SuperHeader::::new_for(&header); @@ -317,9 +313,10 @@ mod tests println!("{}\n", ser.fmt_view()); let mut read = &ser[..]; - let reads = SuperHeader::read_text(&mut read).await?; + let read = &mut read; + let reads = SuperHeader::read_text(read).await?; println!("Read super: {:?}", reads); - let readheader = KeyHeader::read_text(&mut read).await?; + let readheader = KeyHeader::read_text(read).await?; println!("Read real: {:?}", readheader); reads.verify_for(&header)?; @@ -327,6 +324,7 @@ mod tests assert_eq!(readheader, header); assert_eq!(reads, superheader); - Ok(())*/ + //panic!("\n{}\n",std::str::from_utf8(&ser[..]).unwrap()); + Ok(()) } } diff --git a/src/format/mod.rs b/src/format/mod.rs index 34ee4e4..7c0279d 100644 --- a/src/format/mod.rs +++ b/src/format/mod.rs @@ -96,7 +96,6 @@ impl SuperHeader let line = line.trim(); trace!("Read super-header line: {:?}", line); let mut chunks = line.split_whitespace(); - let mut item = 0; macro_rules! take_one { () => { if let Some(chunk) = chunks.next() { @@ -106,6 +105,7 @@ impl SuperHeader .with_section(|| format!("{:#?}", chunks).header("Split section was")) .with_note(|| "Expect at least 6 items delimited by whitespace")); } + } } macro_rules! check_eq { @@ -114,27 +114,86 @@ impl SuperHeader let val = $val; let chunk = take_one!(); if chunk != val { - return Err(eyre::eyre!("Invalid data at index {}", item) + return Err(eyre::eyre!("Invalid data at chunk {}", chunk) .with_section(|| format!("{:?}", val).header("Expected")) .with_section(|| format!("{:?}", chunk).header("Got"))); } - item +=1; } } } check_eq!("---"); check_eq!(unsafe{std::str::from_utf8_unchecked(&RAE_HEADER_BIT[..])}); - //TODO: Parse text version from hex encoded integer in `2` let version = { let enc_str = take_one!(); // Version should be encoded like: v0.0.0*-0 (v-) - todo!() + let mut spl = enc_str.split('-').fuse(); + match (spl.next(), spl.next()) { + (None, _) => Err(eyre::eyre!("Cannot extract version")), + (Some(x), None) => Err(eyre::eyre!("Cannot extract version integer") + .with_section(|| x.to_owned().header("Version part was"))), + (Some(v), Some(i)) => { + trace!("Found version string part {} and integer part {}", v, i); + + match u32::from_str_radix(i, 16) { + Ok(i) => Version::try_from_u32(i) + .wrap_err_with(|| eyre::eyre!("Failed to convert integer part to version")) + .with_section(|| i.to_string().header("Integer (decoeed u32) was")), + Err(x) => Err(x).wrap_err_with(|| eyre::eyre!("Failed to decode string part into integer")), + }.with_section(|| i.to_owned().header("Integer part was")) + .with_section(|| v.to_owned().header("Version part was")) + .and_then(|vers| { + let vstr = vers.to_string(); + if v.len() < 1 { + Err(eyre::eyre!("Embedded version string was invalid")) + .with_section(|| v.to_owned().header("Embedded was")) + .with_section(move || vstr.header("Decoded was")) + } + else if vstr != &v[1..] { + Err(eyre::eyre!("Embedded version string does not match decoded version string")) + .with_section(|| v.to_owned().header("Embedded was")) + .with_section(move || vstr.header("Decoded was")) + } else { + Ok(vers) + } + }) + }, + }.wrap_err_with(|| eyre::eyre!("Failed to decode version")) + .with_section(|| enc_str.to_owned().header("The version string was"))? + }; + //Parse hash from hex encoded string `3` + let hash = { + let hash_str= take_one!(); + let w = || { + if hash_str.len() < 2 { + return Err(eyre::eyre!("Not long enough")) + } + let hash_str = &hash_str[1..(hash_str.len()-1)]; + use hex::FromHex; + + let bytes = <[u8; crypto::consts::SHA256_SIZE]>::from_hex(hash_str) + .wrap_err_with(|| eyre::eyre!("Hex decode to {} size byte array failed", crypto::consts::SHA256_SIZE)) + .with_section(|| hash_str.to_owned().header("Hash string (cut) was"))?; + + Ok(unsafe{std::mem::transmute::<_, crypto::sha256::Sha256Hash>(bytes)}) //Sha256Hash is repr(transparent) + }; + w() + .wrap_err_with(|| eyre::eyre!("Failed to decode hash")) + .with_section(|| hash_str.to_owned().header("The hash string was"))? }; - //TODO: Parse hash from hex encoded string `3` check_eq!(H::NAME); check_eq!("---"); - debug_assert_eq!(item, 6); - todo!() + if version.should_warn(&CURRENT_VERSION) { + warn!("Header is read to have deprecated version {}, we are on version {}", version, CURRENT_VERSION) + } + Ok( + Self { + head: RAE_HEADER_BIT, + vers: version, + header_hash: hash, + chk: H::CHECK, + _header: PhantomData, + } + ) } /// Write this superheader as bytes to this stream diff --git a/src/main.rs b/src/main.rs index 7fc0261..a086710 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ #![cfg_attr(nightly, feature(label_break_value))] #![cfg_attr(nightly, feature(const_fn))] -#![cfg_attr(nightly, feature(never_type))] - +#![cfg_attr(nightly, feature(const_fn_transmute))] +#![cfg_attr(nightly, feature(never_type))] #![allow(dead_code)] #![allow(unused_macros)] @@ -22,7 +22,6 @@ use lazy_static::lazy_static; use serde::{Serialize, Deserialize}; use tracing_futures::Instrument; - macro_rules! cfg_debug { (if {$($if:tt)*} else {$($else:tt)*}) => { {