Merge branch 'develop' of github.com:nymtech/nym-client into develop

This commit is contained in:
Dave Hrycyszyn
2019-12-12 16:45:50 +00:00
13 changed files with 212 additions and 58 deletions
Generated
+8
View File
@@ -941,6 +941,7 @@ dependencies = [
"reqwest 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
"sfw-provider-requests 0.1.0",
"sphinx 0.1.0",
"tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1402,6 +1403,13 @@ dependencies = [
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "sfw-provider-requests"
version = "0.1.0"
dependencies = [
"sphinx 0.1.0",
]
[[package]]
name = "sha2"
version = "0.8.0"
+2
View File
@@ -15,6 +15,8 @@ pem = "0.7.0"
reqwest = "0.9.22"
serde = { version = "1.0", features = ["derive"] }
sphinx = { path = "../sphinx" }
sfw-provider-requests = { path = "../nym-sfw-provider/sfw-provider-requests" }
tokio = { version = "0.2", features = ["full"] }
[dev-dependencies]
+47
View File
@@ -0,0 +1,47 @@
use sphinx::route::Node as MixNode;
use sphinx::SphinxPacket;
use tokio::prelude::*;
use sfw_provider_requests::*;
use std::net::Shutdown;
use std::time::Duration;
use sfw_provider_requests::requests::{PullRequest, ProviderRequest};
use sfw_provider_requests::responses::{PullResponse, ProviderResponse};
pub struct ProviderClient {}
impl ProviderClient {
pub fn new() -> Self {
ProviderClient {}
}
pub async fn retrieve_messages(
&self,
// provider: &MixNode,
) -> Result<(), Box<dyn std::error::Error>> {
let address = [42; 32];
let pull_request = PullRequest::new(address);
let bytes = pull_request.to_bytes();
let mut socket = tokio::net::TcpStream::connect("127.0.0.1:9000").await?;
println!("keep alive: {:?}", socket.keepalive());
socket.set_keepalive(Some(tokio::time::Duration::from_secs(2)));
socket.write_all(&bytes[..]).await?;
if let Err(e) = socket.shutdown(Shutdown::Write) {
eprintln!("failed to close write part of the socket; err = {:?}", e)
}
let mut response = Vec::new();
socket.read_to_end(&mut response).await?;
if let Err(e) = socket.shutdown(Shutdown::Read) {
eprintln!("failed to close read part of the socket; err = {:?}", e)
}
println!("Received the following response: {:?}", response);
let parsed_response = PullResponse::from_bytes(&response).unwrap();
for message in parsed_response.messages {
println!("Received: {:?}", String::from_utf8(message).unwrap())
}
Ok(())
}
}
+9 -49
View File
@@ -1,60 +1,20 @@
use crate::banner;
use crate::identity::mixnet;
use crate::persistence::pathfinder::Pathfinder;
use crate::persistence::pemstore::PemStore;
use clap::ArgMatches;
use dirs;
use pem::{encode, Pem};
use std::fs::File;
use std::io::prelude::*;
pub fn execute(matches: &ArgMatches) {
println!("{}", banner());
println!("Initialising client...");
let id = matches.value_of("id").unwrap(); // required for now
let id = matches.value_of("id").unwrap().to_string(); // required for now
let pathfinder = Pathfinder::new(id);
// don't unwrap it, pass it as it is, if it's None, choose a random
let _provider_id = matches.value_of("provider");
let _init_local = matches.is_present("local");
let os_config_dir = dirs::config_dir().unwrap();
let nym_client_config_dir = os_config_dir.join("nym").join("clients").join(id);
println!("Writing keypairs to {:?}...", nym_client_config_dir);
write_pem_files(nym_client_config_dir);
println!("Writing keypairs to {:?}...", pathfinder.config_dir);
let mix_keys = mixnet::KeyPair::new();
let pem_store = PemStore::new(pathfinder);
pem_store.write(mix_keys);
println!("Client configuration completed.\n\n\n")
}
fn write_pem_files(nym_client_config_dir: std::path::PathBuf) {
std::fs::create_dir_all(nym_client_config_dir.clone()).unwrap();
let (private, public) = sphinx::crypto::keygen();
write_pem_file(
nym_client_config_dir.clone(),
String::from("private.pem"),
private.to_bytes().to_vec(),
String::from("SPHINX CURVE25519 PRIVATE KEY"),
);
write_pem_file(
nym_client_config_dir.clone(),
String::from("public.pem"),
public.to_bytes().to_vec(),
String::from("SPHINX CURVE25519 PUBLIC KEY"),
);
}
fn write_pem_file(
nym_client_config_dir: std::path::PathBuf,
filename: String,
data: Vec<u8>,
tag: String,
) {
let pem = Pem {
tag,
contents: data,
};
let key = encode(&pem);
let full_path = nym_client_config_dir.join(filename);
let mut file = File::create(full_path).unwrap();
file.write_all(key.as_bytes()).unwrap();
}
+18 -9
View File
@@ -1,8 +1,9 @@
use crate::clients::directory;
use crate::clients::directory::presence::{MixNodePresence, Topology};
use crate::clients::directory::presence::Topology;
use crate::clients::directory::requests::presence_topology_get::PresenceTopologyGetRequester;
use crate::clients::directory::DirectoryClient;
use crate::clients::mix::MixClient;
use crate::clients::provider::ProviderClient;
use crate::utils::bytes;
use base64;
use clap::ArgMatches;
@@ -15,10 +16,7 @@ use tokio::time::{interval_at, Instant};
pub fn execute(matches: &ArgMatches) {
let custom_cfg = matches.value_of("customCfg");
println!(
"Going to start client with custom config of: {:?}",
custom_cfg
);
println!("Starting client with config: {:?}", custom_cfg);
// Grab the network topology from the remote directory server
let topology = get_topology();
@@ -35,7 +33,7 @@ pub fn execute(matches: &ArgMatches) {
interval.tick().await;
let message = format!("Hello, Sphinx {}", i).as_bytes().to_vec();
let route_len = 3;
let route_len = 2;
// data needed to generate a new Sphinx packet
let route = route_from(&topology, route_len);
@@ -51,6 +49,14 @@ pub fn execute(matches: &ArgMatches) {
let result = mix_client.send(packet, route.first().unwrap()).await;
println!("packet sent: {:?}", i);
i += 1;
// retrieve messages every now and then
if i % 3 == 0 {
interval.tick().await;
println!("going to retrieve messages!");
let provider_client = ProviderClient::new();
provider_client.retrieve_messages().await.unwrap();
}
}
})
}
@@ -76,10 +82,13 @@ fn route_from(topology: &Topology, route_len: usize) -> Vec<SphinxNode> {
let decoded_key_bytes = base64::decode_config(&mix.pub_key, base64::URL_SAFE).unwrap();
let key_bytes = bytes::zero_pad_to_32(decoded_key_bytes);
let key = MontgomeryPoint(key_bytes);
let sphinx_node = SphinxNode {
let mut sphinx_node = SphinxNode {
address: address_bytes,
pub_key: key,
};
// temporary to make it work locally:
sphinx_node.pub_key = Default::default();
route.push(sphinx_node);
}
route
@@ -88,7 +97,7 @@ fn route_from(topology: &Topology, route_len: usize) -> Vec<SphinxNode> {
// TODO: where do we retrieve this guy from?
fn get_destination() -> Destination {
Destination {
address: [0u8; 32],
identifier: [0u8; 16],
address: [42u8; 32],
identifier: [1u8; 16],
}
}
+35
View File
@@ -0,0 +1,35 @@
use curve25519_dalek::montgomery::MontgomeryPoint;
use curve25519_dalek::scalar::Scalar;
// This keypair serves as the user's identity within the Mixnet
pub struct KeyPair {
pub private: Scalar,
pub public: MontgomeryPoint,
}
impl KeyPair {
pub fn new() -> KeyPair {
let (private, public) = sphinx::crypto::keygen();
KeyPair { private, public }
}
pub fn from_bytes(private_bytes: Vec<u8>, public_bytes: Vec<u8>) -> KeyPair {
let mut bytes = [0; 32];
bytes.copy_from_slice(&private_bytes[..]);
let private = Scalar::from_canonical_bytes(bytes).unwrap();
let mut bytes = [0; 32];
bytes.copy_from_slice(&public_bytes[..]);
let public = MontgomeryPoint(bytes);
KeyPair { private, public }
}
pub fn private_bytes(&self) -> Vec<u8> {
self.private.to_bytes().to_vec()
}
pub fn public_bytes(&self) -> Vec<u8> {
self.public.to_bytes().to_vec()
}
}
+1
View File
@@ -0,0 +1 @@
pub mod mixnet;
+1
View File
@@ -0,0 +1 @@
// TODO types for Validator keys will go in here once we hook this up.
+2
View File
@@ -3,6 +3,8 @@ use std::process;
mod clients;
mod commands;
mod identity;
mod persistence;
mod utils;
fn main() {
+2
View File
@@ -0,0 +1,2 @@
pub mod pathfinder;
pub mod pemstore;
+21
View File
@@ -0,0 +1,21 @@
use std::path::PathBuf;
pub struct Pathfinder {
pub config_dir: PathBuf,
pub private_mix_key: PathBuf,
pub public_mix_key: PathBuf,
}
impl Pathfinder {
pub fn new(id: String) -> Pathfinder {
let os_config_dir = dirs::config_dir().unwrap(); // grabs the OS default config dir
let config_dir = os_config_dir.join("nym").join("clients").join(id);
let private_mix_key = config_dir.join("private.pem");
let public_mix_key = config_dir.join("public.pem");
Pathfinder {
config_dir,
private_mix_key,
public_mix_key,
}
}
}
+65
View File
@@ -0,0 +1,65 @@
use crate::identity::mixnet::KeyPair;
use crate::persistence::pathfinder::Pathfinder;
use pem::{encode, parse, Pem};
use std::fs::File;
use std::io::prelude::*;
use std::path::PathBuf;
pub struct PemStore {
config_dir: PathBuf,
private_mix_key: PathBuf,
public_mix_key: PathBuf,
}
impl PemStore {
pub fn new(pathfinder: Pathfinder) -> PemStore {
PemStore {
config_dir: pathfinder.config_dir,
private_mix_key: pathfinder.private_mix_key,
public_mix_key: pathfinder.public_mix_key,
}
}
pub fn read(&self) -> KeyPair {
let private = self.read_file(self.private_mix_key.clone());
let public = self.read_file(self.public_mix_key.clone());
KeyPair::from_bytes(private, public)
}
fn read_file(&self, filepath: PathBuf) -> Vec<u8> {
let mut pem_bytes = File::open(filepath).unwrap();
let mut buf = Vec::new();
pem_bytes.read_to_end(&mut buf).unwrap();
let pem = parse(&buf).unwrap();
pem.contents
}
// This should be refactored and made more generic for when we have other kinds of
// KeyPairs that we want to persist (e.g. validator keypairs, or keys for
// signing vs encryption). However, for the moment, it does the job.
pub fn write(&self, key_pair: KeyPair) {
std::fs::create_dir_all(self.config_dir.clone()).unwrap();
self.write_pem_file(
self.private_mix_key.clone(),
key_pair.private_bytes(),
String::from("SPHINX CURVE25519 PRIVATE KEY"),
);
self.write_pem_file(
self.public_mix_key.clone(),
key_pair.public_bytes(),
String::from("SPHINX CURVE25519 PUBLIC KEY"),
);
}
fn write_pem_file(&self, filepath: PathBuf, data: Vec<u8>, tag: String) {
let pem = Pem {
tag,
contents: data,
};
let key = encode(&pem);
let mut file = File::create(filepath).unwrap();
file.write_all(key.as_bytes()).unwrap();
}
}
+1
View File
@@ -0,0 +1 @@
// TODO: we can put all the TOML config templating code in here once we get to that.