routing 0.37.1

A secured storage DHT
// Copyright 2018 MaidSafe.net limited.
//
// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3.
// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed
// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. Please review the Licences for the specific language governing
// permissions and limitations relating to use of the SAFE Network Software.

/// Maximum allowed length for a [message's `body`](struct.MpidMessage.html#method.new) (101,760
/// bytes).
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>,
}

/// A full message including header and body which can be sent to or retrieved from the network.
#[derive(PartialEq, Eq, Hash, Clone, Deserialize, Serialize)]
pub struct MpidMessage {
    header: MpidHeader,
    detail: Detail,
    signature: Signature,
}

impl MpidMessage {
    /// Constructor.
    ///
    /// `sender` and `metadata` are used to construct an `MpidHeader` member, accessed via the
    /// [`header()`](#method.header) getter.  For details on these arguments, see
    /// [MpidHeader::new()](struct.MpidHeader.html#method.new).
    ///
    /// `recipient` represents the name of the intended receiver of the message.
    ///
    /// `body` is arbitrary, user-supplied data representing the main portion of the message.  It
    /// must not exceed [`MAX_BODY_SIZE`](constant.MAX_BODY_SIZE.html).  It can be empty if desired.
    ///
    /// An error will be returned if `body` exceeds `MAX_BODY_SIZE`, if
    /// [MpidHeader::new()](struct.MpidHeader.html#method.new) fails or if
    /// serialisation during the signing process fails.
    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),
        })
    }

    /// Getter for `MpidHeader` member, created when calling `new()`.
    pub fn header(&self) -> &MpidHeader {
        &self.header
    }

    /// The name of the intended receiver of the message.
    pub fn recipient(&self) -> &XorName {
        &self.detail.recipient
    }

    /// Arbitrary, user-supplied data representing the main portion of the message.
    pub fn body(&self) -> &Vec<u8> {
        &self.detail.body
    }

    /// The name of the message, equivalent to the
    /// [`MpidHeader::name()`](../struct.MpidHeader.html#method.name).  As per that getter, this is
    /// relatively expensive, so its use should be minimised.
    pub fn name(&self) -> Result<XorName, Error> {
        self.header.name()
    }

    /// Validates the message and header signatures against the provided `PublicKey`.
    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();

        // Check with body which is empty, then at size limit, then just above limit.
        {
            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();

        // Check verify function with a valid and invalid key
        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));
    }
}