use cbor;
use rustc_serialize::{Decoder, Encodable, Encoder};
use sodiumoxide::crypto::sign;
use sodiumoxide::crypto::box_;
use NameType;
use error::RoutingError;
use id::Id;
use utils;
use std::fmt::{Debug, Formatter, Error};
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, RustcEncodable, RustcDecodable)]
pub struct PublicId {
public_encrypt_key: box_::PublicKey,
public_sign_key: sign::PublicKey,
name: NameType,
}
impl Debug for PublicId {
fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
formatter.write_str(&format!("PublicId(name:{:?})", self.name))
}
}
impl PublicId {
pub fn new(id: &Id) -> PublicId {
PublicId {
public_encrypt_key: id.encrypting_public_key().clone(),
public_sign_key: id.signing_public_key().clone(),
name: id.name(),
}
}
pub fn name(&self) -> NameType {
self.name
}
pub fn set_name(&mut self, name: NameType) {
self.name = name;
}
pub fn client_name(&self) -> NameType {
utils::public_key_to_client_name(&self.public_sign_key)
}
pub fn serialised_contents(&self) -> Result<Vec<u8>, RoutingError> {
let mut e = cbor::Encoder::from_memory();
try!(e.encode(&[&self]));
Ok(e.into_bytes())
}
pub fn assign_relocated_name(&mut self, relocated_name: NameType) {
self.name = relocated_name;
}
pub fn signing_public_key(&self) -> sign::PublicKey {
self.public_sign_key
}
pub fn is_relocated(&self) -> bool {
self.name != utils::public_key_to_client_name(&self.public_sign_key)
}
}
#[cfg(test)]
mod test {
extern crate cbor;
#[test]
fn serialisation_public_id() {
let obj_before = ::public_id::PublicId::new(&::id::Id::new());
let mut e = ::cbor::Encoder::from_memory();
e.encode(&[&obj_before]).unwrap();
let mut d = ::cbor::Decoder::from_bytes(e.as_bytes());
let obj_after: ::public_id::PublicId = d.decode().next().unwrap().unwrap();
assert_eq!(obj_before, obj_after);
}
#[test]
fn set_name() {
let id = ::id::Id::new();
let id_name = id.name().clone();
let relocated_name: ::name_type::NameType = ::test_utils::Random::generate_random();
let mut public_id = ::public_id::PublicId::new(&id);
let cloned_signing_public_key = public_id.signing_public_key().clone().0.to_vec();
public_id.set_name(relocated_name);
assert_eq!(relocated_name, public_id.name());
assert_eq!(id_name, id.name());
assert_eq!(cloned_signing_public_key, public_id.signing_public_key().0.to_vec());
}
#[test]
fn assign_relocated_name_public_id() {
let before = ::public_id::PublicId::new(&::id::Id::new());
let original_name = before.name();
assert_eq!(original_name,
::NameType::new(::sodiumoxide::crypto::hash::sha512::hash(
&before.signing_public_key()[..]).0));
assert!(!before.is_relocated());
let relocated_name: ::NameType = ::test_utils::Random::generate_random();
let mut relocated = before.clone();
relocated.assign_relocated_name(relocated_name.clone());
assert!(relocated.is_relocated());
assert_eq!(before.signing_public_key(), relocated.signing_public_key());
assert_eq!(relocated.client_name(), original_name);
assert_eq!(relocated.name(), relocated_name);
}
#[test]
fn is_relocated() {
let mut public_id: ::public_id::PublicId = ::test_utils::Random::generate_random();
let name_before = public_id.name();
let relocated_name: ::name_type::NameType = ::test_utils::Random::generate_random();
let cloned_signing_public_key = public_id.signing_public_key().clone().0.to_vec();
assert!(!public_id.is_relocated());
public_id.assign_relocated_name(relocated_name);
assert!(public_id.is_relocated());
assert_eq!(cloned_signing_public_key, public_id.signing_public_key().0.to_vec());
public_id.assign_relocated_name(name_before);
assert!(!public_id.is_relocated());
}
}