Made gateway mandatory during init (#331)

This commit is contained in:
Jędrzej Stuczyński
2020-09-10 10:57:35 +01:00
committed by GitHub
parent 82b0d7cbcf
commit 66eb1913ba
2 changed files with 85 additions and 203 deletions
+42 -101
View File
@@ -40,8 +40,9 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
)
.arg(Arg::with_name("gateway")
.long("gateway")
.help("Id of the gateway we have preference to connect to. If left empty, a random gateway will be chosen.")
.help("Id of the gateway we are going to connect to")
.takes_value(true)
.required(true)
)
.arg(Arg::with_name("directory")
.long("directory")
@@ -65,85 +66,40 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
)
}
async fn try_gateway_registration(
gateways: &[gateway::Node],
async fn register_with_gateway(
gateway: &gateway::Node,
our_identity: Arc<identity::KeyPair>,
) -> Option<(String, String, SharedKeys)> {
) -> SharedKeys {
let timeout = Duration::from_millis(1500);
for gateway in gateways {
let mut gateway_client = GatewayClient::new_init(
url::Url::parse(&gateway.client_listener).unwrap(),
gateway.identity_key,
our_identity.clone(),
timeout,
);
if gateway_client.establish_connection().await.is_ok() {
if let Ok(shared_key) = gateway_client.register().await {
if let Err(err) = gateway_client.close_connection().await {
eprintln!("Error while closing connection to the gateway! - {:?}", err);
continue;
} else {
return Some((
gateway.identity_key.to_base58_string(),
gateway.client_listener.clone(),
shared_key,
));
}
}
}
}
None
let mut gateway_client = GatewayClient::new_init(
url::Url::parse(&gateway.client_listener).unwrap(),
gateway.identity_key,
our_identity.clone(),
timeout,
);
gateway_client
.establish_connection()
.await
.expect("failed to establish connection with the gateway!");
gateway_client
.register()
.await
.expect("failed to register with the gateway!")
}
async fn choose_gateway(
directory_server: String,
our_identity: Arc<identity::KeyPair>,
) -> (String, String, SharedKeys) {
let directory_client_config = directory_client::Config::new(directory_server.clone());
async fn gateway_details(directory_server: &str, gateway_id: &str) -> gateway::Node {
let directory_client_config = directory_client::Config::new(directory_server.to_string());
let directory_client = directory_client::Client::new(directory_client_config);
let topology = directory_client.get_topology().await.unwrap();
let nym_topology: NymTopology = topology.try_into().expect("Invalid topology data!");
let version_filtered_topology = nym_topology.filter_system_version(built_info::PKG_VERSION);
// don't care about health of the networks as mixes can go up and down any time,
// but DO care about gateways
let gateways = version_filtered_topology.gateways();
// try to perform registration so that we wouldn't need to do it at startup
// + at the same time we'll know if we can actually talk with that gateway
let registration_result = try_gateway_registration(gateways, our_identity).await;
match registration_result {
None => {
// while technically there's no issue client-side, it will be impossible to execute
// `nym-client run` as no gateway is available so it might be best to not finalize
// the init and rely on users trying to init another time?
panic!(
"Currently there are no valid gateways available on the network ({}). \
Please try to run `init` again at later time or change your directory server",
directory_server
)
}
Some((gateway_id, gateway_listener, shared_key)) => {
(gateway_id, gateway_listener, shared_key)
}
}
}
async fn get_gateway_listener(directory_server: String, gateway_identity: &str) -> Option<String> {
let directory_client_config = directory_client::Config::new(directory_server);
let directory_client = directory_client::Client::new(directory_client_config);
let topology = directory_client.get_topology().await.unwrap();
// technically we don't need to do conversion here, but let's be consistent
let nym_topology: NymTopology = topology.try_into().ok()?;
let gateways = nym_topology.gateways();
for gateway in gateways {
if gateway.identity_key.to_base58_string() == gateway_identity {
return Some(gateway.client_listener.clone());
}
}
None
version_filtered_topology
.gateways()
.iter()
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
.expect(&*format!("no gateway with id {} exists!", gateway_id))
.clone()
}
pub fn execute(matches: &ArgMatches) {
@@ -161,38 +117,23 @@ pub fn execute(matches: &ArgMatches) {
// create identity, encryption and ack keys.
let mut key_manager = KeyManager::new(&mut rng);
// if there is no gateway chosen, get a random-ish one from the topology
if config.get_base().get_gateway_id().is_empty() {
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
let mut rt = tokio::runtime::Runtime::new().unwrap();
let (gateway_id, gateway_listener, shared_key) = rt.block_on(choose_gateway(
config.get_base().get_directory_server(),
key_manager.identity_keypair(),
));
let gateway_id = matches.value_of("gateway").unwrap();
config.get_base_mut().with_gateway_id(gateway_id);
config
.get_base_mut()
.with_gateway_listener(gateway_listener);
let registration_fut = async {
let gate_details =
gateway_details(&config.get_base().get_directory_server(), gateway_id).await;
let shared_keys =
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
(shared_keys, gate_details.client_listener)
};
key_manager.insert_gateway_shared_key(shared_key)
}
// we specified our gateway but don't know its physical address
if config.get_base().get_gateway_listener().is_empty() {
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
let mut rt = tokio::runtime::Runtime::new().unwrap();
let gateway_listener = rt
.block_on(get_gateway_listener(
config.get_base().get_directory_server(),
&config.get_base().get_gateway_id(),
))
.expect("No gateway with provided id exists!");
config
.get_base_mut()
.with_gateway_listener(gateway_listener);
}
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
let mut rt = tokio::runtime::Runtime::new().unwrap();
let (shared_keys, gateway_listener) = rt.block_on(registration_fut);
config
.get_base_mut()
.with_gateway_listener(gateway_listener);
key_manager.insert_gateway_shared_key(shared_keys);
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
key_manager
+43 -102
View File
@@ -46,8 +46,9 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
)
.arg(Arg::with_name("gateway")
.long("gateway")
.help("Id of the gateway we have preference to connect to. If left empty, a random gateway will be chosen.")
.help("Id of the gateway we are going to connect to")
.takes_value(true)
.required(true)
)
.arg(Arg::with_name("directory")
.long("directory")
@@ -67,85 +68,40 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
)
}
async fn try_gateway_registration(
gateways: &[gateway::Node],
async fn register_with_gateway(
gateway: &gateway::Node,
our_identity: Arc<identity::KeyPair>,
) -> Option<(String, String, SharedKeys)> {
) -> SharedKeys {
let timeout = Duration::from_millis(1500);
for gateway in gateways {
let mut gateway_client = GatewayClient::new_init(
url::Url::parse(&gateway.client_listener).unwrap(),
gateway.identity_key,
our_identity.clone(),
timeout,
);
if gateway_client.establish_connection().await.is_ok() {
if let Ok(shared_key) = gateway_client.register().await {
if let Err(err) = gateway_client.close_connection().await {
eprintln!("Error while closing connection to the gateway! - {:?}", err);
continue;
} else {
return Some((
gateway.identity_key.to_base58_string(),
gateway.client_listener.clone(),
shared_key,
));
}
}
}
}
None
let mut gateway_client = GatewayClient::new_init(
url::Url::parse(&gateway.client_listener).unwrap(),
gateway.identity_key,
our_identity.clone(),
timeout,
);
gateway_client
.establish_connection()
.await
.expect("failed to establish connection with the gateway!");
gateway_client
.register()
.await
.expect("failed to register with the gateway!")
}
async fn choose_gateway(
directory_server: String,
our_identity: Arc<identity::KeyPair>,
) -> (String, String, SharedKeys) {
let directory_client_config = directory_client::Config::new(directory_server.clone());
async fn gateway_details(directory_server: &str, gateway_id: &str) -> gateway::Node {
let directory_client_config = directory_client::Config::new(directory_server.to_string());
let directory_client = directory_client::Client::new(directory_client_config);
let topology = directory_client.get_topology().await.unwrap();
let nym_topology: NymTopology = topology.try_into().expect("Invalid topology data!");
let version_filtered_topology = nym_topology.filter_system_version(built_info::PKG_VERSION);
// don't care about health of the networks as mixes can go up and down any time,
// but DO care about gateways
let gateways = version_filtered_topology.gateways();
// try to perform registration so that we wouldn't need to do it at startup
// + at the same time we'll know if we can actually talk with that gateway
let registration_result = try_gateway_registration(gateways, our_identity).await;
match registration_result {
None => {
// while technically there's no issue client-side, it will be impossible to execute
// `nym-client run` as no gateway is available so it might be best to not finalize
// the init and rely on users trying to init another time?
panic!(
"Currently there are no valid gateways available on the network ({}). \
Please try to run `init` again at later time or change your directory server",
directory_server
)
}
Some((gateway_id, gateway_listener, shared_key)) => {
(gateway_id, gateway_listener, shared_key)
}
}
}
async fn get_gateway_listener(directory_server: String, gateway_identity: &str) -> Option<String> {
let directory_client_config = directory_client::Config::new(directory_server);
let directory_client = directory_client::Client::new(directory_client_config);
let topology = directory_client.get_topology().await.unwrap();
// technically we don't need to do conversion here, but let's be consistent
let nym_topology: NymTopology = topology.try_into().ok()?;
let gateways = nym_topology.gateways();
for gateway in gateways {
if gateway.identity_key.to_base58_string() == gateway_identity {
return Some(gateway.client_listener.clone());
}
}
None
version_filtered_topology
.gateways()
.iter()
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
.expect(&*format!("no gateway with id {} exists!", gateway_id))
.clone()
}
pub fn execute(matches: &ArgMatches) {
@@ -165,38 +121,23 @@ pub fn execute(matches: &ArgMatches) {
// create identity, encryption and ack keys.
let mut key_manager = KeyManager::new(&mut rng);
// if there is no gateway chosen, get a random-ish one from the topology
if config.get_base().get_gateway_id().is_empty() {
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
let mut rt = tokio::runtime::Runtime::new().unwrap();
let (gateway_id, gateway_listener, shared_key) = rt.block_on(choose_gateway(
config.get_base().get_directory_server(),
key_manager.identity_keypair(),
));
let gateway_id = matches.value_of("gateway").unwrap();
config.get_base_mut().with_gateway_id(gateway_id);
config
.get_base_mut()
.with_gateway_listener(gateway_listener);
let registration_fut = async {
let gate_details =
gateway_details(&config.get_base().get_directory_server(), gateway_id).await;
let shared_keys =
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
(shared_keys, gate_details.client_listener)
};
key_manager.insert_gateway_shared_key(shared_key)
}
// we specified our gateway but don't know its physical address
if config.get_base().get_gateway_listener().is_empty() {
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
let mut rt = tokio::runtime::Runtime::new().unwrap();
let gateway_listener = rt
.block_on(get_gateway_listener(
config.get_base().get_directory_server(),
&config.get_base().get_gateway_id(),
))
.expect("No gateway with provided id exists!");
config
.get_base_mut()
.with_gateway_listener(gateway_listener);
}
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
let mut rt = tokio::runtime::Runtime::new().unwrap();
let (shared_keys, gateway_listener) = rt.block_on(registration_fut);
config
.get_base_mut()
.with_gateway_listener(gateway_listener);
key_manager.insert_gateway_shared_key(shared_keys);
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
key_manager
@@ -211,7 +152,7 @@ pub fn execute(matches: &ArgMatches) {
println!("Saved configuration file to {:?}", config_save_location);
println!(
"Unless overridden in all `nym-client run` we will be talking to the following gateway: {}...",
"Unless overridden in all `nym-socks5-client run` we will be talking to the following gateway: {}...",
config.get_base().get_gateway_id(),
);