pub const MAX_BODY_SIZE: usize = 102_400 - 512 - super::MAX_HEADER_METADATA_SIZE;
use super::{Error, MpidHeader};
use maidsafe_utilities::serialisation::serialise;
use rust_sodium::crypto::sign::{self, PublicKey, SecretKey, Signature};
use std::fmt::{self, Debug, Formatter};
use utils;
use xor_name::XorName;
#[derive(PartialEq, Eq, Hash, Clone, Deserialize, Serialize)]
struct Detail {
recipient: XorName,
body: Vec<u8>,
}
#[derive(PartialEq, Eq, Hash, Clone, Deserialize, Serialize)]
pub struct MpidMessage {
header: MpidHeader,
detail: Detail,
signature: Signature,
}
impl MpidMessage {
pub fn new(
sender: XorName,
metadata: Vec<u8>,
recipient: XorName,
body: Vec<u8>,
secret_key: &SecretKey,
) -> Result<MpidMessage, Error> {
if body.len() > MAX_BODY_SIZE {
return Err(Error::BodyTooLarge);
}
let header = MpidHeader::new(sender, metadata, secret_key)?;
let detail = Detail { recipient, body };
let recipient_and_body = serialise(&detail)?;
Ok(MpidMessage {
header,
detail,
signature: sign::sign_detached(&recipient_and_body, secret_key),
})
}
pub fn header(&self) -> &MpidHeader {
&self.header
}
pub fn recipient(&self) -> &XorName {
&self.detail.recipient
}
pub fn body(&self) -> &Vec<u8> {
&self.detail.body
}
pub fn name(&self) -> Result<XorName, Error> {
self.header.name()
}
pub fn verify(&self, public_key: &PublicKey) -> bool {
match serialise(&self.detail) {
Ok(recipient_and_body) => {
sign::verify_detached(&self.signature, &recipient_and_body, public_key)
&& self.header.verify(public_key)
}
Err(_) => false,
}
}
}
impl Debug for MpidMessage {
fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> {
write!(
formatter,
"MpidMessage {{ header: {:?}, recipient: {:?}, body: {}, signature: {} }}",
self.header,
self.detail.recipient,
utils::format_binary_array(&self.detail.body),
utils::format_binary_array(&self.signature)
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use messaging;
use rand;
use rust_sodium::crypto::sign;
use xor_name::XorName;
#[test]
fn full() {
let (mut public_key, secret_key) = sign::gen_keypair();
let sender: XorName = rand::random();
let metadata = messaging::generate_random_bytes(messaging::MAX_HEADER_METADATA_SIZE);
let recipient: XorName = rand::random();
{
let message = unwrap!(MpidMessage::new(
sender,
metadata.clone(),
recipient,
vec![],
&secret_key,
));
assert!(message.body().is_empty());
}
let mut body = messaging::generate_random_bytes(MAX_BODY_SIZE);
let message = unwrap!(MpidMessage::new(
sender,
metadata.clone(),
recipient,
body.clone(),
&secret_key,
));
assert_eq!(*message.body(), body);
body.push(0);
assert!(
MpidMessage::new(
sender,
metadata.clone(),
recipient,
body.clone(),
&secret_key,
).is_err()
);
let _ = body.pop();
assert!(message.verify(&public_key));
if public_key.0[0] != 255 {
public_key.0[0] += 1;
} else {
public_key.0[0] = 0;
}
assert!(!message.verify(&public_key));
}
}