use super::{AppendWrapper, AppendedData, DataIdentifier, Filter, NO_OWNER_PUB_KEY};
use error::RoutingError;
use maidsafe_utilities::serialisation::{deserialise, serialise, serialised_size};
use rust_sodium::crypto::{box_, sealedbox};
use rust_sodium::crypto::sign::{self, PublicKey, SecretKey, Signature};
use rustc_serialize::{Decodable, Decoder};
use std::collections::{BTreeMap, BTreeSet};
use std::fmt::{self, Debug, Formatter};
use xor_name::XorName;
pub const MAX_PRIV_APPENDABLE_DATA_SIZE_IN_BYTES: u64 = 102400;
pub const MAX_PRIV_APPENDED_DATA_BYTES: usize = 220;
#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Clone, RustcEncodable, Debug)]
pub struct PrivAppendedData(pub Vec<u8>);
impl PrivAppendedData {
pub fn new(appended_data: &AppendedData,
encrypt_pub_key: &box_::PublicKey)
-> Result<PrivAppendedData, RoutingError> {
let encoded_appended_data = serialise(&appended_data)?;
let encrypted_appended_data = sealedbox::seal(&encoded_appended_data, encrypt_pub_key);
Ok(PrivAppendedData(encrypted_appended_data))
}
pub fn open(&self,
pub_key: &box_::PublicKey,
secret_key: &box_::SecretKey)
-> Result<AppendedData, RoutingError> {
let decipher_result = sealedbox::open(&self.0, pub_key, secret_key)
.map_err(|()| RoutingError::AsymmetricDecryptionFailure)?;
Ok(deserialise(&decipher_result)?)
}
}
impl Decodable for PrivAppendedData {
fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
let data: Vec<u8> = Decodable::decode(d)?;
if data.len() > MAX_PRIV_APPENDED_DATA_BYTES {
return Err(d.error("wrong private appended data size"));
}
Ok(PrivAppendedData(data))
}
}
#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Clone, RustcDecodable, RustcEncodable)]
pub struct PrivAppendableData {
pub name: XorName,
pub version: u64,
pub filter: Filter,
pub encrypt_key: box_::PublicKey,
pub deleted_data: BTreeSet<PrivAppendedData>,
pub owners: BTreeSet<PublicKey>,
pub signatures: BTreeMap<PublicKey, Signature>,
pub data: BTreeSet<PrivAppendedData>, }
impl PrivAppendableData {
#[cfg_attr(feature="cargo-clippy", allow(too_many_arguments))]
pub fn new(name: XorName,
version: u64,
owners: BTreeSet<PublicKey>,
deleted_data: BTreeSet<PrivAppendedData>,
filter: Filter,
encrypt_key: box_::PublicKey)
-> Result<PrivAppendableData, RoutingError> {
if owners.len() > 1 {
return Err(RoutingError::InvalidOwners);
}
Ok(PrivAppendableData {
name: name,
version: version,
filter: filter,
encrypt_key: encrypt_key,
deleted_data: deleted_data,
owners: owners,
signatures: BTreeMap::new(),
data: BTreeSet::new(),
})
}
pub fn update_with_other(&mut self, other: PrivAppendableData) -> Result<(), RoutingError> {
self.validate_self_against_successor(&other)?;
self.name = other.name;
self.version = other.version;
self.filter = other.filter;
self.encrypt_key = other.encrypt_key;
self.deleted_data = other.deleted_data;
self.signatures = other.signatures;
self.owners = other.owners;
self.data.extend(other.data);
for ad in &self.deleted_data {
if self.data.contains(ad) {
let _remove = self.data.remove(ad);
}
}
Ok(())
}
pub fn validate_self_against_successor(&self,
other: &PrivAppendableData)
-> Result<(), RoutingError> {
if other.owners.len() > 1 || other.signatures.len() > 1 ||
self.owners.contains(&NO_OWNER_PUB_KEY) {
return Err(RoutingError::InvalidOwners);
}
if other.name != self.name || other.version != self.version + 1 {
return Err(RoutingError::UnknownMessageType);
}
let data = other.data_to_sign()?;
super::verify_signatures(&self.owners, &data, &other.signatures)
}
pub fn append(&mut self, priv_appended_data: PrivAppendedData, sign_key: &PublicKey) -> bool {
if match self.filter {
Filter::WhiteList(ref white_list) => !white_list.contains(sign_key),
Filter::BlackList(ref black_list) => black_list.contains(sign_key),
} || self.deleted_data.contains(&priv_appended_data) {
return false;
}
self.data.insert(priv_appended_data)
}
pub fn apply_wrapper(&mut self, wrapper: AppendWrapper) -> bool {
if !wrapper.verify_signature() || &self.version != wrapper.version() {
return false;
}
match wrapper.priv_appended_data() {
None => false,
Some(priv_appended_data) => self.append(priv_appended_data.clone(), wrapper.sign_key()),
}
}
pub fn name(&self) -> &XorName {
&self.name
}
pub fn identifier(&self) -> DataIdentifier {
DataIdentifier::PrivAppendable(self.name)
}
fn data_to_sign(&self) -> Result<Vec<u8>, RoutingError> {
let sd = SerialisablePrivAppendableData {
name: self.name,
version: self.version
.to_string()
.as_bytes()
.to_vec(),
filter: &self.filter,
encrypt_key: &self.encrypt_key,
owners: &self.owners,
deleted_data: &self.deleted_data,
};
serialise(&sd).map_err(From::from)
}
pub fn add_signature(&mut self, keys: &(PublicKey, SecretKey)) -> Result<usize, RoutingError> {
if !self.signatures.is_empty() {
return Err(RoutingError::InvalidOwners);
}
let data = self.data_to_sign()?;
let sig = sign::sign_detached(&data, &keys.1);
if self.signatures.insert(keys.0, sig).is_none() {
return Ok(((self.owners.len() / 2) + 1).saturating_sub(self.signatures.len()));
}
Err(RoutingError::FailedSignature)
}
pub fn replace_signatures(&mut self, new_signatures: BTreeMap<PublicKey, Signature>) {
self.signatures = new_signatures;
}
pub fn get_data(&self) -> &BTreeSet<PrivAppendedData> {
&self.data
}
pub fn get_version(&self) -> u64 {
self.version
}
pub fn get_owners(&self) -> &BTreeSet<PublicKey> {
&self.owners
}
pub fn get_signatures(&self) -> &BTreeMap<PublicKey, Signature> {
&self.signatures
}
pub fn validate_size(&self) -> bool {
serialised_size(self) <= MAX_PRIV_APPENDABLE_DATA_SIZE_IN_BYTES
}
}
impl Debug for PrivAppendableData {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter,
"PrivAppendableData {{ name: {}, version: {}, owners: {:?}, signatures: {:?} }}",
self.name(),
self.version,
self.owners,
self.signatures)
}
}
#[derive(RustcEncodable)]
struct SerialisablePrivAppendableData<'a> {
name: XorName,
version: Vec<u8>,
filter: &'a Filter,
encrypt_key: &'a box_::PublicKey,
owners: &'a BTreeSet<PublicKey>,
deleted_data: &'a BTreeSet<PrivAppendedData>,
}
#[cfg(test)]
mod tests {
use super::*;
use data::{self, AppendWrapper, AppendedData, DataIdentifier, Filter};
use maidsafe_utilities::serialisation::serialise;
use rand;
use rust_sodium::crypto::{box_, sign};
use std::collections::BTreeSet;
use xor_name::XorName;
#[test]
fn serialised_priv_appended_data_size() {
let keys = sign::gen_keypair();
let pointer = DataIdentifier::Structured(rand::random(), 10000);
let appended_data = unwrap!(AppendedData::new(pointer, keys.0, &keys.1));
let encrypt_keys = box_::gen_keypair();
let priv_appended_data = unwrap!(PrivAppendedData::new(&appended_data, &encrypt_keys.0));
let serialised = unwrap!(serialise(&priv_appended_data));
assert_eq!(MAX_PRIV_APPENDED_DATA_BYTES, serialised.len());
}
#[test]
fn single_owner() {
let keys = sign::gen_keypair();
let encrypt_keys = box_::gen_keypair();
let mut owner_keys = BTreeSet::new();
owner_keys.insert(keys.0);
match PrivAppendableData::new(rand::random(),
0,
owner_keys.clone(),
BTreeSet::new(),
Filter::white_list(None),
encrypt_keys.0) {
Ok(mut priv_appendable_data) => {
let data = match priv_appendable_data.data_to_sign() {
Ok(data) => data,
Err(error) => panic!("Error: {:?}", error),
};
assert!(data::verify_signatures(&owner_keys,
&data,
priv_appendable_data.get_signatures())
.is_err());
assert!(priv_appendable_data.add_signature(&keys).is_ok());
assert!(data::verify_signatures(&owner_keys,
&data,
priv_appendable_data.get_signatures())
.is_ok());
}
Err(error) => panic!("Error: {:?}", error),
}
}
#[test]
fn single_owner_other_signature() {
let keys = sign::gen_keypair();
let other_keys = sign::gen_keypair();
let encrypt_keys = box_::gen_keypair();
let mut owner_keys = BTreeSet::new();
owner_keys.insert(keys.0);
match PrivAppendableData::new(rand::random(),
0,
owner_keys.clone(),
BTreeSet::new(),
Filter::white_list(None),
encrypt_keys.0) {
Ok(mut priv_appendable_data) => {
assert!(priv_appendable_data.add_signature(&other_keys).is_ok());
let data = match priv_appendable_data.data_to_sign() {
Ok(data) => data,
Err(error) => panic!("Error: {:?}", error),
};
assert!(data::verify_signatures(&owner_keys,
&data,
priv_appendable_data.get_signatures())
.is_err());
}
Err(error) => panic!("Error: {:?}", error),
}
}
#[test]
fn appending_with_white_list() {
let keys = sign::gen_keypair();
let encrypt_keys = box_::gen_keypair();
let white_key = sign::gen_keypair();
let black_key = sign::gen_keypair();
let data = PrivAppendableData::new(rand::random(),
0,
BTreeSet::new(),
BTreeSet::new(),
Filter::white_list(vec![white_key.0]),
encrypt_keys.0);
let mut priv_appendable_data = unwrap!(data);
let pointer = DataIdentifier::Structured(rand::random(), 10000);
let appended_data = unwrap!(AppendedData::new(pointer, keys.0, &keys.1));
let priv_appended_data = unwrap!(PrivAppendedData::new(&appended_data, &encrypt_keys.0));
assert!(!priv_appendable_data.append(priv_appended_data.clone(), &black_key.0));
assert!(priv_appendable_data.append(priv_appended_data, &white_key.0));
}
#[test]
fn appending_with_black_list() {
let keys = sign::gen_keypair();
let encrypt_keys = box_::gen_keypair();
let white_key = sign::gen_keypair();
let black_key = sign::gen_keypair();
let data = PrivAppendableData::new(rand::random(),
0,
BTreeSet::new(),
BTreeSet::new(),
Filter::black_list(vec![black_key.0]),
encrypt_keys.0);
let mut priv_appendable_data = unwrap!(data);
let pointer = DataIdentifier::Structured(rand::random(), 10000);
let appended_data = unwrap!(AppendedData::new(pointer, keys.0, &keys.1));
let priv_appended_data = unwrap!(PrivAppendedData::new(&appended_data, &encrypt_keys.0));
assert!(!priv_appendable_data.append(priv_appended_data.clone(), &black_key.0));
assert!(priv_appendable_data.append(priv_appended_data, &white_key.0));
}
#[test]
fn apply_wrapper() {
let keys = sign::gen_keypair();
let encrypt_keys = box_::gen_keypair();
let name: XorName = rand::random();
let data = PrivAppendableData::new(name,
0,
BTreeSet::new(),
BTreeSet::new(),
Filter::black_list(None),
encrypt_keys.0);
let mut priv_appendable_data = unwrap!(data);
let pointer = DataIdentifier::Structured(rand::random(), 10000);
let appended_data = unwrap!(AppendedData::new(pointer, keys.0, &keys.1));
let priv_appended_data = unwrap!(PrivAppendedData::new(&appended_data, &encrypt_keys.0));
let append_wrapper = unwrap!(AppendWrapper::new_priv(name,
priv_appended_data.clone(),
(&keys.0, &keys.1),
0));
assert!(priv_appendable_data.apply_wrapper(append_wrapper));
let append_wrapper =
unwrap!(AppendWrapper::new_priv(name, priv_appended_data, (&keys.0, &keys.1), 1));
assert!(!priv_appendable_data.apply_wrapper(append_wrapper));
}
#[test]
fn transfer_ownership() {
let keys = sign::gen_keypair();
let other_keys = sign::gen_keypair();
let mut owner = BTreeSet::new();
owner.insert(keys.0);
let mut new_owner = BTreeSet::new();
new_owner.insert(other_keys.0);
let name: XorName = rand::random();
let encrypt_keys = box_::gen_keypair();
let mut data = PrivAppendableData::new(name,
0,
owner,
BTreeSet::new(),
Filter::black_list(None),
encrypt_keys.0);
let mut ad = unwrap!(data);
data = PrivAppendableData::new(name,
1,
new_owner.clone(),
BTreeSet::new(),
Filter::black_list(None),
encrypt_keys.0);
let mut ad_new = unwrap!(data);
assert!(ad_new.add_signature(&keys).is_ok());
assert!(ad.update_with_other(ad_new).is_ok());
data = PrivAppendableData::new(name,
2,
new_owner.clone(),
BTreeSet::new(),
Filter::black_list(None),
encrypt_keys.0);
let mut ad_fail = unwrap!(data);
assert!(ad_fail.add_signature(&keys).is_ok());
assert!(ad.update_with_other(ad_fail).is_err());
}
}