use rustc_serialize::{Decoder, Encodable, Encoder};
use routing_table::RoutingTable;
use NameType;
use sodiumoxide::crypto;
use std::fmt::{Debug, Formatter, Error};
use messages::{RoutingMessage, Content, ExternalRequest, InternalRequest};
use types::Address;
#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Eq, Ord, Clone, Hash)]
pub enum Authority {
ClientManager(NameType),
NaeManager(NameType),
NodeManager(NameType),
ManagedNode(NameType),
Client(NameType, crypto::sign::PublicKey),
}
impl Authority {
pub fn is_group(&self) -> bool {
match self {
&Authority::ClientManager(_) => true,
&Authority::NaeManager(_) => true,
&Authority::NodeManager(_) => true,
&Authority::ManagedNode(_) => false,
&Authority::Client(_, _) => false,
}
}
pub fn get_location(&self) -> &NameType {
match self {
&Authority::ClientManager(ref loc) => loc,
&Authority::NaeManager(ref loc) => loc,
&Authority::NodeManager(ref loc) => loc,
&Authority::ManagedNode(ref loc) => loc,
&Authority::Client(ref loc, _) => loc,
}
}
pub fn get_address(&self) -> Option<Address> {
match self {
&Authority::ClientManager(_) => None,
&Authority::NaeManager(_) => None,
&Authority::NodeManager(_) => None,
&Authority::ManagedNode(ref name) => Some(Address::Node(name.clone())),
&Authority::Client(_, ref public_key) => Some(Address::Client(public_key.clone())),
}
}
}
impl Debug for Authority {
fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
match self {
&Authority::ClientManager(ref name) => {
formatter.write_str(&format!("ClientManager(name:{:?})", name))
}
&Authority::NaeManager(ref name) => {
formatter.write_str(&format!("NaeManager(name:{:?})", name))
}
&Authority::NodeManager(ref name) => {
formatter.write_str(&format!("NodeManager(name:{:?})", name))
}
&Authority::ManagedNode(ref name) => {
formatter.write_str(&format!("ManagedNode(name:{:?})", name))
}
&Authority::Client(ref relay, ref public_key) => {
formatter.write_str(&format!("Client(relay:{:?}, public_key:{:?})",
relay, NameType::new(crypto::hash::sha512::hash(&public_key[..]).0)))
}
}
}
}
pub fn our_authority(message: &RoutingMessage, routing_table: &RoutingTable) -> Option<Authority> {
let element = match message.content {
Content::ExternalRequest(ref request) => {
match *request {
ExternalRequest::Get(ref data_request, _) => Some(data_request.name().clone()),
ExternalRequest::Put(ref data) => Some(data.name()),
ExternalRequest::Post(ref data) => Some(data.name()),
ExternalRequest::Delete(ref data) => Some(data.name()),
}
}
Content::InternalRequest(ref request) => {
match *request {
InternalRequest::Connect(_) => None,
InternalRequest::RequestNetworkName(ref public_id) => Some(public_id.name()),
InternalRequest::CacheNetworkName(ref public_id, _) => Some(public_id.name()),
InternalRequest::Refresh(_, _, _) => {
let destination = message.destination();
if destination != message.source() { return None; };
if destination.is_group()
&& routing_table.address_in_our_close_group_range(
destination.get_location()) {
return Some(destination);
};
None
},
}
}
Content::ExternalResponse(_) => None,
Content::InternalResponse(_) => None,
};
let element = match element {
Some(e) => e,
None => {
return None;
}
};
determine_authority(message, routing_table, element)
}
fn determine_authority(message: &RoutingMessage,
routing_table: &RoutingTable,
element: NameType)
-> Option<Authority> {
match message.client_key_as_name() {
Some(client_name) => {
if routing_table.address_in_our_close_group_range(&client_name) &&
*message.destination().get_location() != element {
return Some(Authority::ClientManager(client_name));
}
}
None => {
}
};
if routing_table.address_in_our_close_group_range(&element) &&
*message.destination().get_location() == element &&
element != routing_table.our_name() {
return Some(Authority::NaeManager(element));
} else if message.from_group().is_some() &&
routing_table.address_in_our_close_group_range(message.destination().get_location()) &&
*message.destination().get_location() != routing_table.our_name() {
return Some(Authority::NodeManager(message.destination().get_location().clone()));
} else if message.from_group()
.map(|group| routing_table.address_in_our_close_group_range(&group))
.unwrap_or(false) &&
*message.destination().get_location() == routing_table.our_name() {
return Some(Authority::ManagedNode(routing_table.our_name()));
}
return None;
}
#[cfg(test)]
mod test {
use routing_table::{RoutingTable, NodeInfo};
use public_id::PublicId;
use messages::{RoutingMessage, Content, ExternalRequest};
use id::Id;
use test_utils::{Random, xor, test};
use utils::public_key_to_client_name;
use name_type::{closer_to_target, NameType};
use authority::Authority;
use sodiumoxide::crypto;
use data::Data;
use immutable_data::{ImmutableData, ImmutableDataType};
#[test]
fn our_authority_full_routing_table() {
let id = Id::new();
let mut routing_table = RoutingTable::new(&id.name());
let mut count : usize = 0;
loop {
let _ = routing_table.add_node(NodeInfo::new(
PublicId::new(&Id::new()),
test::random_endpoints(),
Some(test::random_connection())));
count += 1;
if count > 100 {
break;
}
}
let our_name = id.name();
let (mut client_public_key, _) = crypto::sign::gen_keypair();
count = 0;
loop {
let client_name = public_key_to_client_name(&client_public_key);
if routing_table.address_in_our_close_group_range(&client_name) {
break;
} else {
let (new_client_public_key, _) = crypto::sign::gen_keypair();
client_public_key = new_client_public_key;
count += 1;
}
if count > 1000 {
panic!("Failed to find a ClientName in our range.")
};
}
let our_close_group : Vec<NodeInfo> = routing_table.our_close_group();
let furthest_node_close_group : NodeInfo
= our_close_group.last().unwrap().clone();
let closest_node_in_our_close_group = our_close_group.first().unwrap().clone();
let second_closest_node_in_our_close_group : NodeInfo = our_close_group[1].clone();
let nae_or_client_in_our_close_group : NameType
= xor(&xor(&closest_node_in_our_close_group.id, &our_name),
&second_closest_node_in_our_close_group.id);
assert!(closer_to_target(&nae_or_client_in_our_close_group,
&furthest_node_close_group.id,
&our_name));
for close_node in our_close_group {
assert!(close_node.id != nae_or_client_in_our_close_group);
}
let name_outside_close_group : NameType
= xor(&furthest_node_close_group.id, &NameType::new([255u8; 64]));
assert!(closer_to_target(&furthest_node_close_group.id,
&name_outside_close_group,
&our_name));
let some_data : Data = Data::ImmutableData(ImmutableData::new(
ImmutableDataType::Normal, ::types::generate_random_vec_u8(20usize)));
let client_manager_message = RoutingMessage {
from_authority : Authority::Client(Random::generate_random(), client_public_key.clone()),
to_authority : Authority::ClientManager(public_key_to_client_name(&client_public_key)),
content : Content::ExternalRequest(ExternalRequest::Put(some_data.clone())),
};
assert_eq!(super::determine_authority(&client_manager_message,
&routing_table,
some_data.name()).unwrap(),
Authority::ClientManager(public_key_to_client_name(&client_public_key)));
let nae_manager_message = RoutingMessage {
from_authority : Authority::ClientManager(public_key_to_client_name(&client_public_key)),
to_authority : Authority::NaeManager(nae_or_client_in_our_close_group.clone()),
content : Content::ExternalRequest(ExternalRequest::Put(some_data.clone())),
};
assert_eq!(super::determine_authority(&nae_manager_message, &routing_table,
nae_or_client_in_our_close_group).unwrap(),
Authority::NaeManager(nae_or_client_in_our_close_group));
let node_manager_message = RoutingMessage {
from_authority : Authority::NaeManager(Random::generate_random()),
to_authority : Authority::NodeManager(second_closest_node_in_our_close_group.id.clone()),
content : Content::ExternalRequest(ExternalRequest::Put(some_data.clone())),
};
assert_eq!(super::determine_authority(&node_manager_message,
&routing_table, some_data.name()).unwrap(),
Authority::NodeManager(second_closest_node_in_our_close_group.id.clone()));
let managed_node_message = RoutingMessage {
from_authority : Authority::NodeManager(our_name.clone()),
to_authority : Authority::ManagedNode(our_name.clone()),
content : Content::ExternalRequest(ExternalRequest::Put(some_data.clone())),
};
assert_eq!(super::determine_authority(&managed_node_message, &routing_table,
some_data.name()).unwrap(),
Authority::ManagedNode(our_name.clone()));
let some_bytes = ::types::generate_random_vec_u8(20usize);
let refresh_message = RoutingMessage {
from_authority : Authority::NaeManager(nae_or_client_in_our_close_group.clone()),
to_authority : Authority::NaeManager(nae_or_client_in_our_close_group.clone()),
content : Content::InternalRequest(::messages::InternalRequest::Refresh(0u64,
some_bytes.clone(), Random::generate_random())),
};
assert_eq!(super::our_authority(&refresh_message, &routing_table),
Some(Authority::NaeManager(nae_or_client_in_our_close_group.clone())));
let refresh_message = RoutingMessage {
from_authority : Authority::ClientManager(nae_or_client_in_our_close_group.clone()),
to_authority : Authority::NaeManager(nae_or_client_in_our_close_group.clone()),
content : Content::InternalRequest(::messages::InternalRequest::Refresh(0u64,
some_bytes.clone(), Random::generate_random())),
};
assert!(super::our_authority(&refresh_message, &routing_table).is_none());
let refresh_message = RoutingMessage {
from_authority : Authority::NaeManager(closest_node_in_our_close_group.id.clone()),
to_authority : Authority::NaeManager(nae_or_client_in_our_close_group.clone()),
content : Content::InternalRequest(::messages::InternalRequest::Refresh(0u64,
some_bytes.clone(), Random::generate_random())),
};
assert!(super::our_authority(&refresh_message, &routing_table).is_none());
}
}