Skip to content

Commit

Permalink
Merge pull request #41 from ip-v8/community
Browse files Browse the repository at this point in the history
Added the basis of communities.
  • Loading branch information
Dany Sluijk authored Jun 13, 2019
2 parents 2b58875 + c091b5e commit ccfa197
Show file tree
Hide file tree
Showing 9 changed files with 313 additions and 30 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ serde = { version = "1.0", features = ["derive"] }
bincode = "1.1.3"
rust_sodium = "0.10.2"
openssl = { version = "0.10", features = ["vendored"] }
lazy_static = "1.2.0"
log = "0.4"

[dev-dependencies]
criterion = "0.2.11"
Expand Down
7 changes: 4 additions & 3 deletions hooks/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,18 @@ SUCCESS="${GREEN}ok${RC}"

# Check if rustfmt is installed
printf "${PREFIX} Checking for rustfmt ... "
command -v cargo fmt &>/dev/null
if [[ $? == 0 ]]; then
OUT=$(cargo +stable fmt --version 2>&1 > /dev/null ) # Save the output of the command to OUT for later printing
if [[ $? -eq 0 ]]; then
printf "${SUCCESS}\n"
else
printf "${FAILURE}\n"
printf "${OUT}\n"
exit 1
fi

# Check rustfmt against the git tree
printf "${PREFIX} Checking formatting ... "
command cargo fmt -- --check > /dev/null
command cargo +stable fmt -- --check > /dev/null
if [[ $? == 0 ]]; then
printf "${SUCCESS}\n"
exit 0
Expand Down
209 changes: 209 additions & 0 deletions src/community/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
use crate::serialization::{Packet, PacketDeserializer};
use crate::serialization::header::Header;
use std::error::Error;
use std::collections::HashMap;
use crate::networking::address::Address;
use std::fmt;

pub mod peer;

create_error!(
HeaderUnwrapError,
"The community experienced an error trying to deserialize the header of a packet"
);
create_error!(MidError, "Failed to get the mid");
create_error!(
UnknownCommunityError,
"No community with matching mid found"
);
create_error!(InsertionError, "Error inserting community into hashmap");

/// Example Community
///
/// _**Note:** Try to avoid the use of .unwrap() in actual production code, this is just an example_
/// ```
/// use ipv8::community::peer::Peer;
/// use ipv8::community::Community;
/// use ipv8::serialization::header::Header;
/// use ipv8::serialization::{PacketDeserializer, Packet};
/// use std::net::Ipv4Addr;
/// use ipv8::networking::address::Address;
/// use std::error::Error;
/// use ipv8::IPv8;
/// use ipv8::configuration::Config;
/// use ipv8::serialization::header::HeaderVersion::PyIPV8Header;
/// use ipv8::crypto::keytypes::PublicKey;
///
/// pub struct TestCommunity{
/// peer: Peer
/// }
///
/// impl TestCommunity{
/// fn new() -> Option<Self> {
///
/// // Use the highest available key
/// let pk: PublicKey = PublicKey::from_vec(vec![
/// 48, 129, 167, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 39, 3,
/// 129, 146, 0, 4, 2, 86, 251, 75, 206, 159, 133, 120, 63, 176, 235, 178, 14, 8, 197, 59,
/// 107, 51, 179, 139, 3, 155, 20, 194, 112, 113, 15, 40, 67, 115, 37, 223, 152, 7, 102,
/// 154, 214, 90, 110, 180, 226, 5, 190, 99, 163, 54, 116, 173, 121, 40, 80, 129, 142, 82,
/// 118, 154, 96, 127, 164, 248, 217, 91, 13, 80, 91, 94, 210, 16, 110, 108, 41, 57, 4,
/// 243, 49, 52, 194, 254, 130, 98, 229, 50, 84, 21, 206, 134, 223, 157, 189, 133, 50, 210,
/// 181, 93, 229, 32, 179, 228, 179, 132, 143, 147, 96, 207, 68, 48, 184, 160, 47, 227, 70,
/// 147, 23, 159, 213, 105, 134, 60, 211, 226, 8, 235, 186, 20, 241, 85, 170, 4, 3, 40,
/// 183, 98, 103, 80, 164, 128, 87, 205, 101, 67, 254, 83, 142, 133,
/// ])?;
///
/// // Actually create the community
/// Some(TestCommunity {
/// peer: Peer::new(
/// pk,
/// Address{
/// address: Ipv4Addr::new(0,0,0,0),
/// port: 0
/// },
/// true,
/// )
/// })
/// }
/// }
///
/// impl Community for TestCommunity{
///
/// // Returns the hash of our master peer
/// fn get_mid(&self) -> Option<Vec<u8>> {
/// Some(self.peer.get_sha1()?.to_vec())
/// }
///
/// // The function which will be called when the community receives a packet
/// fn on_receive(&self, header: Header, deserializer: PacketDeserializer, address: Address) -> Result<(),Box<dyn Error>>{
/// # assert_eq!(header.mid_hash, self.get_mid());
/// # assert_eq!(header.version, PyIPV8Header);
/// # assert_eq!(header.message_type, Some(42));
/// // Do some stuff here like to distribute the message based on it's message_type (in the header)
/// Ok(())
/// }
/// }
///
/// let mut config = Config::default();
/// let community = TestCommunity::new().unwrap();
/// let mid = community.get_mid();
/// config.communities.add_community(Box::new(community));
/// let ipv8 = IPv8::new(config);
///
/// // now simulate a packet coming in
///
/// // Create a packet to test the community with
/// let packet = Packet::new(Header{
/// size: 23,
/// version: PyIPV8Header,
/// mid_hash: mid,
/// message_type: Some(42),
/// }).unwrap();
///
/// // Normally you would want to sign the packet here
///
/// // Yeet the packet
/// ipv8.config.communities.forward_message(packet,Address{
/// address: Ipv4Addr::new(42,42,42,42),
/// port: 42,
/// });
///
/// ```
pub trait Community {
// fn new() -> Option<Self>
// where
// Self: Sized;

/// Returns the hash of our master peer public key
fn get_mid(&self) -> Option<Vec<u8>>;

/// Gets called whenever a packet is received directed at this community
/// DO NOT OVERRIDE
fn receive(
&self,
header: Header,
deserializer: PacketDeserializer,
address: Address,
) -> Result<(), Box<dyn Error>> {
// DO NOT OVERRIDE
//! used to pre-decode the header and filter out messages
fn warn_deprecated(message: &str, address: Address) -> Result<(), Box<dyn Error>> {
warn!(
"Received deprecated message {} from ({:?})",
message, address
);
Ok(())
}
match header.message_type.ok_or(HeaderUnwrapError)? {
255 => warn_deprecated("reserved-255", address),
254 => warn_deprecated("on-missing-sequence", address),
253 => warn_deprecated("missing-proof", address),
252 => warn_deprecated("signature-request", address),
251 => warn_deprecated("signature-response", address),
248 => warn_deprecated("on-identity", address),
247 => warn_deprecated("on-missing-identity", address),
244 => warn_deprecated("destroy-community", address),
243 => warn_deprecated("authorize", address),
242 => warn_deprecated("revoke", address),
241 => warn_deprecated("subjective-set", address),
240 => warn_deprecated("missing-subjective-set", address),
239 => warn_deprecated("on-missing-message", address),
238 => warn_deprecated("undo-own", address),
237 => warn_deprecated("undo-other", address),
236 => warn_deprecated("dynamic-settings", address),
235 => warn_deprecated("missing-last-message", address),
_ => self.on_receive(header, deserializer, address),
}
}

fn on_receive(
&self,
header: Header,
deserializer: PacketDeserializer,
address: Address,
) -> Result<(), Box<dyn Error>>;
}

pub struct CommunityRegistry {
// mid, community
communities: HashMap<Vec<u8>, Box<dyn Community>>,
}

impl CommunityRegistry {
pub fn add_community(&mut self, item: Box<dyn Community>) -> Result<(), Box<dyn Error>> {
self.communities
.insert(item.get_mid().ok_or(MidError)?, item)
.ok_or(InsertionError)?;
Ok(())
}

/// Forwards the message to the corresponding community
pub fn forward_message(&self, packet: Packet, address: Address) -> Result<(), Box<dyn Error>> {
// deserialize the header
let deserializer = packet.start_deserialize();

// We use peek here instead of get, even though we give the header along with the receive call
// this is because at this point, the header is not verified yet so we still assume the message is valid.
// We can't verify the header here yet as not all messages have a signature. Communities will have to decide
// on their own if they want to verify the header. We do give it along as only having to deserialize the header once
// makes it slightly more efficient.
let header = deserializer.peek_header()?;

// get the mid from the header and use it for a hashtable lookup
let mid = header.mid_hash.as_ref().ok_or(MidError)?;
let community = self.communities.get(mid).ok_or(UnknownCommunityError)?;

// Actually forward it
community.receive(header, deserializer, address)
}
}

impl Default for CommunityRegistry {
fn default() -> Self {
Self {
communities: HashMap::new(),
}
}
}
22 changes: 22 additions & 0 deletions src/community/peer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use crate::crypto::keytypes::PublicKey;
use crate::networking::address::Address;

pub struct Peer {
key: PublicKey,
address: Address,
intro: bool,
}

impl Peer {
pub fn new(key: PublicKey, address: Address, intro: bool) -> Self {
Self {
key,
address,
intro,
}
}

pub fn get_sha1(&self) -> Option<[u8; 20]> {
self.key.sha1()
}
}
6 changes: 6 additions & 0 deletions src/configuration.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
use crate::networking::address::Address;
use std::net::Ipv4Addr;
use crate::community::CommunityRegistry;

pub struct Config {
/// Default list of host used for peer discovery
pub default_hosts: Vec<Address>,
/// from py-ipv8 configuration. UDP socket address.
/// There split up in "address" and "port"
pub socketaddress: Address,

/// The registry containing all the communities
pub communities: CommunityRegistry,
}

impl Default for Config {
Expand All @@ -17,6 +21,8 @@ impl Default for Config {
port: 8090,
},

communities: CommunityRegistry::default(),

default_hosts: vec![
// Dispersy
Address {
Expand Down
29 changes: 28 additions & 1 deletion src/crypto/keytypes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
//! | HIGH_SIGNATURE_LENGTH | 144 | 153 | 9 | 144 |
//! | ED25519_SIGNATURE_LENGTH | 64 | 64 | 0 | 64 |
use std::fmt;

use openssl;
use openssl::sha::sha1;
use rust_sodium::crypto::sign::ed25519;
use std::fmt;

// TODO: when ed25519 becomes available for rust OpenSSL, rust_sodium will be removed.

Expand Down Expand Up @@ -129,6 +131,10 @@ impl PublicKey {
Some(m)
}
}

pub fn sha1(&self) -> Option<[u8; 20]> {
Some(sha1(&self.to_vec()?))
}
}

impl PartialEq for PublicKey {
Expand Down Expand Up @@ -350,4 +356,25 @@ mod tests {
keyvec
);
}

#[test]
fn test_sha1() {
let keyvec = vec![
48, 64, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 1, 3, 44, 0, 4,
0, 80, 239, 172, 104, 165, 76, 172, 6, 229, 136, 156, 105, 23, 249, 46, 30, 148, 87,
105, 57, 6, 105, 134, 2, 229, 115, 169, 44, 162, 41, 190, 228, 56, 20, 100, 64, 79,
167, 224, 118, 14,
];

let key = PublicKey::from_vec(keyvec.clone()).unwrap();
let sha1sum = key.sha1().unwrap();

assert_eq!(
[
254, 127, 138, 49, 67, 126, 206, 58, 169, 85, 132, 14, 211, 247, 13, 170, 244, 166,
152, 180,
],
sha1sum
)
}
}
8 changes: 6 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#[macro_use]
extern crate log;

pub mod error;
pub mod serialization;

pub mod community;
pub mod configuration;
pub mod crypto;
pub mod event;
Expand All @@ -17,10 +21,10 @@ use configuration::Config;
/// use ipv8::IPv8;
/// use ipv8::configuration::Config;
///
/// let ipv8_instance = IPv8::new(Config::default());
/// let ipv8 = IPv8::new(Config::default());
/// ```
pub struct IPv8 {
config: Config,
pub config: Config,
}

impl IPv8 {
Expand Down
Loading

0 comments on commit ccfa197

Please sign in to comment.