use crate::error::{Error, Result};
use crate::{
compress::CompressType,
de::FogDeserializer,
element::{serialize_elem, Element},
ser::FogSerializer,
MAX_ENTRY_SIZE,
};
use byteorder::{LittleEndian, ReadBytesExt};
use fog_crypto::{
hash::{Hash, HashState},
identity::{Identity, IdentityKey},
};
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
pub(crate) const ENTRY_PREFIX_LEN: usize = 3;
pub(crate) struct SplitEntry<'a> {
pub compress_raw: u8,
pub data: &'a [u8],
pub signature_raw: &'a [u8],
}
impl<'a> SplitEntry<'a> {
pub(crate) fn split(buf: &'a [u8]) -> Result<SplitEntry> {
let (&compress_raw, mut buf) = buf.split_first().ok_or(Error::LengthTooShort {
step: "get compress type",
actual: 0,
expected: 1,
})?;
let data_len = buf
.read_u16::<LittleEndian>()
.map_err(|_| Error::LengthTooShort {
step: "get data length",
actual: buf.len(),
expected: 2,
})? as usize;
if data_len > buf.len() {
return Err(Error::LengthTooShort {
step: "get document data",
actual: buf.len(),
expected: data_len,
});
}
let (data, signature_raw) = buf.split_at(data_len);
Ok(Self {
compress_raw,
data,
signature_raw,
})
}
}
pub struct NewEntry {
buf: Vec<u8>,
hash_state: HashState,
key: String,
parent_hash: Hash,
entry_hash: Hash,
has_signature: bool,
set_compress: Option<Option<u8>>,
}
impl NewEntry {
fn new_from<F>(key: &str, parent: &Hash, encoder: F) -> Result<Self>
where
F: FnOnce(Vec<u8>) -> Result<Vec<u8>>,
{
let buf: Vec<u8> = vec![CompressType::NoCompress.into(), 0u8, 0u8];
let mut buf = encoder(buf)?;
if buf.len() > MAX_ENTRY_SIZE {
return Err(Error::LengthTooLong {
max: MAX_ENTRY_SIZE,
actual: buf.len(),
});
}
let data_len = (buf.len() - ENTRY_PREFIX_LEN).to_le_bytes();
buf[1] = data_len[0];
buf[2] = data_len[1];
let mut hash_state = HashState::new();
let mut prefix = Vec::new();
serialize_elem(&mut prefix, Element::Hash(parent.clone()));
serialize_elem(&mut prefix, Element::Str(key));
hash_state.update(&prefix);
hash_state.update(&buf[ENTRY_PREFIX_LEN..]);
let entry_hash = hash_state.hash();
Ok(Self {
buf,
hash_state,
key: key.to_owned(),
parent_hash: parent.to_owned(),
entry_hash,
has_signature: false,
set_compress: None,
})
}
pub fn new<S: Serialize>(data: S, key: &str, parent: &Hash) -> Result<Self> {
Self::new_from(key, parent, |buf| {
let mut ser = FogSerializer::from_vec(buf, false);
data.serialize(&mut ser)?;
Ok(ser.finish())
})
}
pub fn new_ordered<S: Serialize>(data: S, key: &str, parent: &Hash) -> Result<Self> {
Self::new_from(key, parent, |buf| {
let mut ser = FogSerializer::from_vec(buf, false);
data.serialize(&mut ser)?;
Ok(ser.finish())
})
}
pub fn compression(mut self, setting: Option<u8>) -> Self {
self.set_compress = Some(setting);
self
}
pub fn sign(mut self, key: &IdentityKey) -> Result<Self> {
let signature = key.sign(&self.entry_hash);
let new_len = if self.has_signature {
self.buf.len() - self.split().signature_raw.len() + signature.size()
} else {
self.buf.len() + signature.size()
};
if new_len > MAX_ENTRY_SIZE {
return Err(Error::LengthTooLong {
max: MAX_ENTRY_SIZE,
actual: self.buf.len(),
});
}
if self.has_signature {
let split = SplitEntry::split(&self.buf).unwrap();
let new_len = split.data.len() + ENTRY_PREFIX_LEN;
let mut hash_state = HashState::new();
let mut prefix = Vec::new();
serialize_elem(&mut prefix, Element::Hash(self.parent_hash.clone()));
serialize_elem(&mut prefix, Element::Str(&self.key));
hash_state.update(&prefix);
hash_state.update(split.data);
self.buf.resize(new_len, 0);
self.hash_state = hash_state;
}
let pre_len = self.buf.len();
signature.encode_vec(&mut self.buf);
self.hash_state.update(&self.buf[pre_len..]);
self.has_signature = true;
Ok(self)
}
pub fn hash(&self) -> Hash {
self.hash_state.hash()
}
pub(crate) fn split(&self) -> SplitEntry {
SplitEntry::split(&self.buf).unwrap()
}
pub(crate) fn data(&self) -> &[u8] {
self.split().data
}
pub fn parent(&self) -> &Hash {
&self.parent_hash
}
pub fn key(&self) -> &str {
&self.key
}
pub(crate) fn complete(self) -> (Hash, Vec<u8>, Option<Option<u8>>) {
(self.hash_state.finalize(), self.buf, self.set_compress)
}
}
pub struct Entry {
buf: Vec<u8>,
hash_state: HashState,
key: String,
parent_hash: Hash,
entry_hash: Hash,
signer: Option<Identity>,
set_compress: Option<Option<u8>>,
}
impl Entry {
pub(crate) fn new(buf: Vec<u8>, key: &str, parent: &Hash) -> Result<Self> {
if buf.len() > MAX_ENTRY_SIZE {
return Err(Error::LengthTooLong {
max: MAX_ENTRY_SIZE,
actual: buf.len(),
});
}
let split = SplitEntry::split(&buf)?;
let mut hash_state = HashState::new();
let mut prefix = Vec::new();
serialize_elem(&mut prefix, Element::Hash(parent.clone()));
serialize_elem(&mut prefix, Element::Str(key));
hash_state.update(&prefix);
hash_state.update(split.data);
let entry_hash = hash_state.hash();
hash_state.update(split.signature_raw);
let signer = if !split.signature_raw.is_empty() {
let unverified =
fog_crypto::identity::UnverifiedSignature::try_from(split.signature_raw)?;
let verified = unverified.verify(&entry_hash)?;
Some(verified.signer().clone())
} else {
None
};
Ok(Self {
buf,
hash_state,
key: key.to_owned(),
parent_hash: parent.to_owned(),
entry_hash,
signer,
set_compress: None,
})
}
pub(crate) fn split(&self) -> SplitEntry {
SplitEntry::split(&self.buf).unwrap()
}
pub(crate) fn data(&self) -> &[u8] {
self.split().data
}
pub fn parent(&self) -> &Hash {
&self.parent_hash
}
pub fn key(&self) -> &str {
&self.key
}
pub fn signer(&self) -> Option<&Identity> {
self.signer.as_ref()
}
pub fn hash(&self) -> Hash {
self.hash_state.hash()
}
pub fn deserialize<'de, D: Deserialize<'de>>(&'de self) -> Result<D> {
let buf = self.data();
let mut de = FogDeserializer::new(buf);
D::deserialize(&mut de)
}
pub fn compression(mut self, setting: Option<u8>) -> Self {
self.set_compress = Some(setting);
self
}
pub fn sign(mut self, key: &IdentityKey) -> Result<Self> {
let signature = key.sign(&self.entry_hash);
let new_len = if self.signer.is_some() {
self.buf.len() - self.split().signature_raw.len() + signature.size()
} else {
self.buf.len() + signature.size()
};
if new_len > MAX_ENTRY_SIZE {
return Err(Error::LengthTooLong {
max: MAX_ENTRY_SIZE,
actual: self.buf.len(),
});
}
if self.signer.is_some() {
let split = SplitEntry::split(&self.buf).unwrap();
let new_len = split.data.len() + ENTRY_PREFIX_LEN;
let mut hash_state = HashState::new();
let mut prefix = Vec::new();
serialize_elem(&mut prefix, Element::Hash(self.parent_hash.clone()));
serialize_elem(&mut prefix, Element::Str(&self.key));
hash_state.update(&prefix);
hash_state.update(split.data);
self.buf.resize(new_len, 0);
self.hash_state = hash_state;
}
let pre_len = self.buf.len();
signature.encode_vec(&mut self.buf);
self.hash_state.update(&self.buf[pre_len..]);
self.signer = Some(key.id().clone());
Ok(self)
}
pub(crate) fn complete(self) -> (Hash, Vec<u8>, Option<Option<u8>>) {
(self.hash_state.finalize(), self.buf, self.set_compress)
}
}