confitul 0.1.4

ConfitUL contains utilities for ConfitDB which is an experimental, distributed, real-time database, giving full control on conflict resolution.
Documentation
use crate::crypto::verify;
use crate::Host;
use crate::HostInfo;
use ed25519_dalek;
use std::convert::TryFrom;
use std::fmt::Formatter;

/// A remote host, for which this program instance is not responsible.
///
/// Typically, this is a host about which we gathered informations,
/// but it is not local so, among other things, we can not really trust
/// it and we do not have its private key.
///
/// This should *NOT* be serialized as it is not trustable. Instead,
/// de-serialize from the HostInfo struct then call the constructor,
/// which checks for integrity.
#[derive(Debug)]
pub struct RemoteHost {
    info: HostInfo,
    pubkey: ed25519_dalek::PublicKey,
}

impl RemoteHost {
    /// Create a new remote host.
    ///
    /// The typical way to build this is from host info which has been
    /// serialized, sent over the wire, then de-serialized into a host info.
    ///
    /// # Examples
    /// ```
    /// use confitul::LocalHost;
    /// use confitul::RemoteHost;
    /// use confitul::Host;
    ///
    /// let lh = LocalHost::new(None).unwrap();
    /// let rh = RemoteHost::new(&lh.info()).unwrap();
    /// print!("{}\n{}\n", lh, rh);
    /// ```
    pub fn new(info: &HostInfo) -> Result<RemoteHost, signature::Error> {
        let pubkey = ed25519_dalek::PublicKey::try_from(info.id)?;
        let remote_host = RemoteHost {
            info: info.clone(),
            pubkey,
        };
        match &info.sig {
            Some(_) => {}
            None => return Err(signature::Error::new()),
        }
        print!("{:?}\n", remote_host.info.sig.as_ref().unwrap());
        print!("{:?}\n", info.sig.as_ref().unwrap());
        remote_host.verify_self()?;
        Ok(remote_host)
    }
}

impl Host for RemoteHost {
    fn info(&self) -> &HostInfo {
        &self.info
    }
    fn verify_msg(&self, msg: &[u8], sig: &[u8]) -> Result<(), signature::Error> {
        verify(&self.pubkey, msg, sig)
    }
}

impl std::fmt::Display for RemoteHost {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "{{\"type\":\"remote\",\"info\":{}}}", self.info)
    }
}

#[cfg(test)]
mod tests {
    use super::Host;
    use super::HostInfo;
    use super::RemoteHost;
    use crate::LocalHost;
    use serde_json;

    #[test]
    fn test_remote_host_serde_json() {
        let local_host = LocalHost::new(None).unwrap();
        let serialized = serde_json::to_string(local_host.info()).unwrap();
        let deserialized: HostInfo = serde_json::from_str(&serialized).unwrap();
        assert_eq!(local_host.info(), &deserialized);
        let remote_host = RemoteHost::new(&deserialized).unwrap();
        assert!(matches!(remote_host.verify_self(), Ok(())));

        let msg = "this is the message".as_bytes();
        let sig = local_host.sign_msg(msg);
        assert!(matches!(remote_host.verify_msg(msg, &sig), Ok(())));
    }
}