use crate::base::{BaseError, Body, Header, PrivateOptions};
use crate::crypto;
use crate::options::{Options, OptionsList};
use crate::types::*;
use crate::base::Base;
pub mod header;
pub mod builder;
pub use builder::Builder;
pub mod container;
pub use container::Container;
impl<'a, T: AsRef<[u8]>> Container<T> {
pub fn parse<P, S>(
data: T,
mut pub_key_s: P,
mut sec_key_s: S,
) -> Result<(Base, usize), BaseError>
where
P: FnMut(&Id) -> Option<PublicKey>,
S: FnMut(&Id) -> Option<SecretKey>,
{
let mut verified = false;
let (container, n) = Container::from(data);
let header = container.header();
let flags = header.flags();
let id: Id = container.id().into();
let signature: Signature = container.signature().into();
if !flags.contains(Flags::SECONDARY) {
if let Some(key) = (pub_key_s)(&id) {
if id != crypto::hash(&key).unwrap() {
return Err(BaseError::PublicKeyIdMismatch);
}
verified = crypto::pk_validate(&key, &signature, container.signed())
.map_err(|_e| BaseError::ValidateError)?;
if !verified {
info!("Invalid signature with known pubkey");
return Err(BaseError::InvalidSignature);
}
}
}
let mut peer_id = None;
let mut pub_key = None;
let mut parent = None;
let public_options: Vec<_> = container
.public_options()
.filter_map(|o| match &o {
Options::PeerId(v) => {
peer_id = Some(v.peer_id.clone());
None
}
Options::PubKey(v) => {
pub_key = Some(v.public_key.clone());
None
}
Options::PrevSig(v) => {
parent = Some(v.sig.clone());
None
}
_ => Some(o),
})
.collect();
let signing_id: Id = match (flags.contains(Flags::SECONDARY), &peer_id) {
(false, _) => Ok(container.id().into()),
(true, Some(id)) => Ok(id.clone()),
_ => Err(BaseError::NoPeerId),
}?;
let public_key: Option<PublicKey> = match ((pub_key_s)(&signing_id), &pub_key) {
(Some(key), _) => Some(key),
(None, Some(key)) => Some(key.clone()),
_ => {
warn!(
"Missing public key for message: {:?} signing id: {:?}",
id, signing_id
);
None
}
};
match (verified, public_key) {
(false, Some(public_key)) => {
if signing_id != crypto::hash(&public_key).unwrap() {
return Err(BaseError::PublicKeyIdMismatch);
}
verified = crypto::pk_validate(&public_key, &signature, container.signed())
.map_err(|_e| BaseError::ValidateError)?;
if !verified {
info!("Invalid signature for self-signed object");
return Err(BaseError::InvalidSignature);
}
}
_ => {
warn!("No verification for object");
}
}
let mut body_data = container.body().to_vec();
let mut private_options_data = container.private_options().to_vec();
let body = match (flags.contains(Flags::ENCRYPTED), sec_key_s(&id)) {
(true, Some(sk)) if body_data.len() > 0 => {
let n = crypto::sk_decrypt2(&sk, &mut body_data)
.map_err(|_e| BaseError::InvalidSignature)?;
body_data = (&body_data[..n]).to_vec();
Body::Cleartext(body_data)
}
(true, None) if body_data.len() > 0 => {
debug!("No encryption key found for data");
Body::Encrypted(body_data)
}
(false, _) if body_data.len() > 0 => Body::Cleartext(body_data),
_ => Body::None,
};
let private_options = match (flags.contains(Flags::ENCRYPTED), sec_key_s(&id)) {
(true, Some(sk)) if private_options_data.len() > 0 => {
let n = crypto::sk_decrypt2(&sk, &mut private_options_data)
.map_err(|_e| BaseError::InvalidSignature)?;
private_options_data = (&private_options_data[..n]).to_vec();
let (private_options, _n) = Options::parse_vec(&private_options_data)?;
PrivateOptions::Cleartext(private_options)
}
(true, None) if private_options_data.len() > 0 => {
debug!("No encryption key found for data");
PrivateOptions::Encrypted(private_options_data)
}
_ => PrivateOptions::None,
};
Ok((
Base {
id,
header: Header::new(
header.application_id(),
header.kind(),
header.index(),
header.flags(),
),
body,
private_options,
public_options,
parent,
peer_id: peer_id.clone(),
public_key: pub_key.clone(),
signature: Some(signature),
verified,
raw: Some(container.raw().to_vec()),
},
n,
))
}
}
impl<'a, T: AsRef<[u8]> + AsMut<[u8]>> Container<T> {
pub fn encode(
buff: T,
base: &Base,
signing_key: &PrivateKey,
encryption_key: Option<&SecretKey>,
) -> (Self, usize) {
let bb = Builder::new(buff).id(base.id()).header(base.header());
let encryption_key = match (base.flags().contains(Flags::ENCRYPTED), encryption_key) {
(true, Some(k)) => Some(k),
(true, None) => panic!("Attempted to encrypt object with no secret key"),
_ => None,
};
let bb = bb.body(base.body(), encryption_key).unwrap();
let mut bb = bb
.private_options(base.private_options(), encryption_key)
.unwrap();
if let Some(k) = &base.public_key {
bb.public_option(&Options::pub_key(k.clone())).unwrap();
}
if let Some(s) = &base.parent {
bb.public_option(&Options::prev_sig(s)).unwrap();
}
if let Some(i) = &base.peer_id {
bb.public_option(&Options::peer_id(i.clone())).unwrap();
}
let opts = OptionsList::<_, &[u8]>::Cleartext(base.public_options());
let bb = bb.public_options(&opts).unwrap();
let c = bb.sign(signing_key).unwrap();
let len = c.len;
(c, len)
}
}
#[cfg(test)]
mod test {}