diff --git a/Cargo.lock b/Cargo.lock index 422057c..8fd358e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,6 +21,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + [[package]] name = "bitflags" version = "1.2.1" @@ -492,6 +498,8 @@ checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" name = "snekcloud-node" version = "0.1.0" dependencies = [ + "base64", + "rand", "rusqlite", "vented", ] @@ -555,9 +563,9 @@ checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c" [[package]] name = "vented" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1b9a45811ac7741c477738e79759119950cc09f1afc2d53673b83560c35e53d" +checksum = "b92984cc8ed261509126ebc9b043c814e98f3d8da9dbf2e1d21e072c6906c8a7" dependencies = [ "byteorder", "crossbeam-utils", diff --git a/Cargo.toml b/Cargo.toml index 147b6ea..6c3027e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,5 +7,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -vented = "0.1.0" -rusqlite = "0.24.1" \ No newline at end of file +vented = "0.1.2" +rusqlite = "0.24.1" +rand = "0.7.3" +base64 = "0.13.0" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 115087d..ca17819 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ -mod utils; +pub(crate) mod utils; +pub(crate) mod server; fn main() { unimplemented!() diff --git a/src/server/mod.rs b/src/server/mod.rs new file mode 100644 index 0000000..673c3ff --- /dev/null +++ b/src/server/mod.rs @@ -0,0 +1,37 @@ +use vented::server::VentedServer; +use crate::utils::result::SnekcloudResult; +use vented::crypto::SecretKey; +use std::path::PathBuf; +use vented::server::data::Node; +use vented::WaitGroup; + +pub struct SnekcloudServer { + inner: VentedServer, + listen_addresses: Vec, + listeners: Vec, +} + +impl SnekcloudServer { + /// Creates a new snekcloud server with the provided keys and number of threads + pub fn new(id: String, private_key: SecretKey, keys: Vec, num_threads: usize) -> Self { + Self { + inner: VentedServer::new(id, private_key, keys, num_threads), + listen_addresses: Vec::new(), + listeners: Vec::new(), + } + } + + /// Adds an address the server should listen on + pub fn add_listen_address(&mut self, address: String) { + self.listen_addresses.push(address); + } + + /// Starts listening on all addresses + pub fn run(&mut self) -> SnekcloudResult<()> { + for address in &self.listen_addresses { + self.listeners.push(self.inner.listen(address.clone())) + } + + Ok(()) + } +} \ No newline at end of file diff --git a/src/utils/keys.rs b/src/utils/keys.rs new file mode 100644 index 0000000..a86043a --- /dev/null +++ b/src/utils/keys.rs @@ -0,0 +1,67 @@ +use std::path::PathBuf; +use vented::crypto::{SecretKey, PublicKey}; +use std::fs; +use crate::utils::result::{SnekcloudResult, SnekcloudError}; +use vented::server::data::Node; + +const PRIVATE_KEY_HEADER_LINE: &str = "---BEGIN-SNEKCLOUD-PRIVATE-KEY---\n"; +const PRIVATE_KEY_FOOTER_LINE: &str = "\n---END-SNEKCLOUD-PRIVATE-KEY---"; + +const PUBLIC_KEY_HEADER_LINE: &str = "---BEGIN-SNEKCLOUD-PUBLIC-KEY---\n"; +const PUBLIC_KEY_FOOTER_LINE: &str = "\n---END-SNEKCLOUD-PUBLIC-KEY---"; + +/// Reads a folder of node public keys +pub fn read_node_keys(path: &PathBuf) -> SnekcloudResult> { + let dir_content = path.read_dir()?; + + let content = dir_content + .filter_map(|entry| { + let entry = entry.ok()?; + + Some((entry.metadata().ok()?, entry)) + }) + .filter(|(meta, _)|meta.is_file()) + .filter_map(|(_, entry)|{ + let key = read_public_key(&entry.path()).ok()?; + + let file_name = entry.file_name(); + let file_name = file_name.to_string_lossy(); + let node_id = file_name.trim_end_matches(".pub"); + + Some(Node {public_key: key, address: None, id: node_id.to_string()}) + }).collect(); + + Ok(content) +} + +/// Reads the private key from a file +pub fn read_private_key(filename: &PathBuf) -> SnekcloudResult { + let content = fs::read_to_string(filename)?; + + let bytes = extract_key(content, PUBLIC_KEY_HEADER_LINE, PUBLIC_KEY_FOOTER_LINE)?; + + Ok(SecretKey::from(bytes)) +} + +/// Reads the public key from a file +pub fn read_public_key(filename: &PathBuf) -> SnekcloudResult { + let content = fs::read_to_string(filename)?; + let bytes = extract_key(content, PUBLIC_KEY_HEADER_LINE, PUBLIC_KEY_FOOTER_LINE)?; + + Ok(PublicKey::from(bytes)) +} + +/// Extracts a base64 encoded key between the prefix and suffix +fn extract_key(content: String, prefix: &str, suffix: &str) -> SnekcloudResult<[u8; 32]> { + let mut content = content.strip_prefix(prefix).ok_or(SnekcloudError::InvalidKey)?; + content = content.strip_suffix(suffix).ok_or(SnekcloudError::InvalidKey)?; + + let key = base64::decode(content)?; + if key.len() != 32 { + return Err(SnekcloudError::InvalidKey); + } + let mut key_bytes = [0u8; 32]; + key_bytes.copy_from_slice(&key[..]); + + Ok(key_bytes) +} \ No newline at end of file diff --git a/src/utils/mod.rs b/src/utils/mod.rs index d11ca02..566d7ad 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1 +1,2 @@ -pub mod result; \ No newline at end of file +pub mod result; +pub mod keys; \ No newline at end of file diff --git a/src/utils/result.rs b/src/utils/result.rs index 002443a..5ea3632 100644 --- a/src/utils/result.rs +++ b/src/utils/result.rs @@ -1,18 +1,26 @@ use vented::result::VentedError; use std::fmt; +use std::io; use std::error::Error; + pub type SnekcloudResult = Result; #[derive(Debug)] pub enum SnekcloudError { Vented(VentedError), + IoError(io::Error), + Base64DecodeError(base64::DecodeError), + InvalidKey, } impl fmt::Display for SnekcloudError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::Vented(v) => write!(f, "Vented Error: {}", v) + Self::Vented(v) => write!(f, "Vented Error: {}", v), + Self::IoError(e) => write!(f, "IO Error: {}", e), + Self::Base64DecodeError(e) => write!(f, "Base 64 Decode error: {}", e), + Self::InvalidKey => write!(f, "Invalid Key!"), } } } @@ -23,4 +31,16 @@ impl From for SnekcloudError { fn from(error: VentedError) -> Self { Self::Vented(error) } +} + +impl From for SnekcloudError { + fn from(error: io::Error) -> Self { + Self::IoError(error) + } +} + +impl From for SnekcloudError { + fn from(error: base64::DecodeError) -> Self { + Self::Base64DecodeError(error) + } } \ No newline at end of file