pub const MAX_BODY_SIZE: usize = 102400 - 512 - super::MAX_HEADER_METADATA_SIZE;
use std::fmt::{self, Debug, Formatter};
use messaging;
use maidsafe_utilities::serialisation::serialise;
use sodiumoxide::crypto::sign::{self, PublicKey, SecretKey, Signature};
use super::{Error, MpidHeader};
use routing::XorName;
#[derive(PartialEq, Eq, Hash, Clone, RustcDecodable, RustcEncodable)]
struct Detail {
recipient: XorName,
body: Vec<u8>,
}
#[derive(PartialEq, Eq, Hash, Clone, RustcDecodable, RustcEncodable)]
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 = try!(MpidHeader::new(sender, metadata, secret_key));
let detail = Detail {
recipient: recipient,
body: body,
};
let recipient_and_body = try!(serialise(&detail));
Ok(MpidMessage {
header: header,
detail: 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,
messaging::format_binary_array(&self.detail.body),
messaging::format_binary_array(&self.signature))
}
}
#[cfg(test)]
mod test {
use super::*;
use rand;
use routing::XorName;
use sodiumoxide::crypto::sign;
use messaging;
#[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_result!(MpidMessage::new(sender.clone(),
metadata.clone(),
recipient.clone(),
vec![],
&secret_key));
assert!(message.body().is_empty());
}
let mut body = messaging::generate_random_bytes(MAX_BODY_SIZE);
let message = unwrap_result!(MpidMessage::new(sender.clone(),
metadata.clone(),
recipient.clone(),
body.clone(),
&secret_key));
assert!(*message.body() == body);
body.push(0);
assert!(MpidMessage::new(sender.clone(),
metadata.clone(),
recipient.clone(),
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));
}
}