Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions masq/src/command_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::commands::descriptor_command::DescriptorCommand;
use crate::commands::exit_location_command::SetExitLocationCommand;
use crate::commands::financials_command::FinancialsCommand;
use crate::commands::generate_wallets_command::GenerateWalletsCommand;
use crate::commands::neighborhood_graph_command::GetNeighborhoodGraphCommand;
use crate::commands::recover_wallets_command::RecoverWalletsCommand;
use crate::commands::scan_command::ScanCommand;
use crate::commands::set_configuration_command::SetConfigurationCommand;
Expand Down Expand Up @@ -65,6 +66,10 @@ impl CommandFactory for CommandFactoryReal {
Ok(command) => Box::new(command),
Err(msg) => return Err(CommandSyntax(msg)),
},
"neighborhood-graph" => match GetNeighborhoodGraphCommand::new(pieces) {
Ok(command) => Box::new(command),
Err(msg) => return Err(CommandSyntax(msg)),
},
"recover-wallets" => match RecoverWalletsCommand::new(pieces) {
Ok(command) => Box::new(command),
Err(msg) => return Err(CommandSyntax(msg)),
Expand Down Expand Up @@ -292,6 +297,21 @@ mod tests {
);
}

#[test]
fn factory_produces_neighborhood_graph() {
let subject = CommandFactoryReal::new();

let command = subject.make(&["neighborhood-graph".to_string()]).unwrap();

assert_eq!(
command
.as_any()
.downcast_ref::<GetNeighborhoodGraphCommand>()
.unwrap(),
&GetNeighborhoodGraphCommand {}
);
}

#[test]
fn complains_about_set_configuration_command_with_no_parameters() {
let subject = CommandFactoryReal::new();
Expand Down
2 changes: 2 additions & 0 deletions masq/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ pub mod setup_command;
pub mod shutdown_command;
pub mod start_command;
pub mod wallet_addresses_command;

pub mod neighborhood_graph_command;
93 changes: 93 additions & 0 deletions masq/src/commands/neighborhood_graph_command.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use clap::{App, SubCommand};
use masq_lib::{as_any_ref_in_trait_impl, short_writeln};

use crate::command_context::CommandContext;
use crate::commands::commands_common::CommandError::Payload;
use crate::commands::commands_common::{
transaction, Command, CommandError, STANDARD_COMMAND_TIMEOUT_MILLIS,
};
use masq_lib::messages::{UiGetNeighborhoodGraphRequest, UiGetNeighborhoodGraphResponse};

const NEIGHBORHOOD_GRAPH_HELP: &str = "Use this command plainly, without any flags or arguments. The result will be delivered in digraph format, documentation at https://graphviz.org/documentation/";

pub fn get_neighborhood_graph_subcommand() -> App<'static, 'static> {
SubCommand::with_name("neighborhood-graph").about(NEIGHBORHOOD_GRAPH_HELP)
}

#[derive(Debug, PartialEq, Eq)]
pub struct GetNeighborhoodGraphCommand {}

impl GetNeighborhoodGraphCommand {
pub fn new(pieces: &[String]) -> Result<Self, String> {
match get_neighborhood_graph_subcommand().get_matches_from_safe(pieces) {
Ok(_) => Ok(GetNeighborhoodGraphCommand {}),
Err(e) => Err(format!("GetNeighborhoodGraphCommand {}", e)),
}
}
}

impl Command for GetNeighborhoodGraphCommand {
fn execute(&self, context: &mut dyn CommandContext) -> Result<(), CommandError> {
let input = UiGetNeighborhoodGraphRequest {};
let output: Result<UiGetNeighborhoodGraphResponse, CommandError> =
transaction(input, context, STANDARD_COMMAND_TIMEOUT_MILLIS);
match output {
Ok(neighborhood_graph) => {
short_writeln!(
context.stdout(),
"Graph of the Node's neighborhood database: {}",
neighborhood_graph.graph.as_str()
);
Ok(())
}
Err(Payload(code, message)) => {
short_writeln!(context.stderr(), "code: {}\nmessage: {}", code, message);
Err(Payload(code, message))
}
Err(err) => {
short_writeln!(context.stderr(), "Error: {}", err);
Err(err)
}
}
}

as_any_ref_in_trait_impl!();
}

#[cfg(test)]
pub mod tests {
use super::*;
use crate::test_utils::mocks::CommandContextMock;
use masq_lib::messages::ToMessageBody;
use std::sync::{Arc, Mutex};

#[test]
fn can_deserialize_ui_get_neighborhood_graph() {
let transact_params_arc = Arc::new(Mutex::new(vec![]));
let mut context = CommandContextMock::new()
.transact_params(&transact_params_arc)
.transact_result(Ok(UiGetNeighborhoodGraphResponse {
graph: "digraph db { \"AQIDBA\" [label=\"AR v0 AU\\nAQIDBA\\n1.2.3.4:1234\"]; \"HZ5vwwJPhfUZVy85E76GZUUam9SMgyaw+QaZvAMuizo\" [label=\"AR v0 ZZ\\nHZ5vwwJP\\n9.9.9.9:9999\"] [style=filled]; \"AgMEBQ\" [label=\"AR v0 FR\\nAgMEBQ\\n2.3.4.5:2345\"]; \"AwQFBg\" [label=\"AR v0 CN\\nAwQFBg\\n3.4.5.6:3456\"]; \"BAUGBw\" [label=\"AR v0 US\\nBAUGBw\\n4.5.6.7:4567\"]; \"AQIDBA\" -> \"HZ5vwwJPhfUZVy85E76GZUUam9SMgyaw+QaZvAMuizo\"; \"AQIDBA\" -> \"AgMEBQ\"; \"HZ5vwwJPhfUZVy85E76GZUUam9SMgyaw+QaZvAMuizo\" -> \"AQIDBA\"; \"AgMEBQ\" -> \"AwQFBg\"; \"AgMEBQ\" -> \"AQIDBA\"; \"AwQFBg\" -> \"BAUGBw\"; \"AwQFBg\" -> \"AgMEBQ\"; \"BAUGBw\" -> \"AwQFBg\"; }".to_string()
}.tmb(0)));
let stderr_arc = context.stderr_arc();
let stdout_arc = context.stdout_arc();
let subject =
GetNeighborhoodGraphCommand::new(&["neighborhood-graph".to_string()]).unwrap();

let result = subject.execute(&mut context);

assert_eq!(result, Ok(()));
let expected_request = UiGetNeighborhoodGraphRequest {};
let transact_params = transact_params_arc.lock().unwrap();
let expected_message_body = expected_request.tmb(0);
assert_eq!(
transact_params.as_slice(),
&[(expected_message_body, STANDARD_COMMAND_TIMEOUT_MILLIS)]
);
let stdout = stdout_arc.lock().unwrap();
let graph_str = "Graph of the Node's neighborhood database: digraph db { \"AQIDBA\" [label=\"AR v0 AU\\nAQIDBA\\n1.2.3.4:1234\"]; \"HZ5vwwJPhfUZVy85E76GZUUam9SMgyaw+QaZvAMuizo\" [label=\"AR v0 ZZ\\nHZ5vwwJP\\n9.9.9.9:9999\"] [style=filled]; \"AgMEBQ\" [label=\"AR v0 FR\\nAgMEBQ\\n2.3.4.5:2345\"]; \"AwQFBg\" [label=\"AR v0 CN\\nAwQFBg\\n3.4.5.6:3456\"]; \"BAUGBw\" [label=\"AR v0 US\\nBAUGBw\\n4.5.6.7:4567\"]; \"AQIDBA\" -> \"HZ5vwwJPhfUZVy85E76GZUUam9SMgyaw+QaZvAMuizo\"; \"AQIDBA\" -> \"AgMEBQ\"; \"HZ5vwwJPhfUZVy85E76GZUUam9SMgyaw+QaZvAMuizo\" -> \"AQIDBA\"; \"AgMEBQ\" -> \"AwQFBg\"; \"AgMEBQ\" -> \"AQIDBA\"; \"AwQFBg\" -> \"BAUGBw\"; \"AwQFBg\" -> \"AgMEBQ\"; \"BAUGBw\" -> \"AwQFBg\"; }\n";
assert_eq!(&stdout.get_string(), graph_str);
let stderr = stderr_arc.lock().unwrap();
assert_eq!(&stderr.get_string(), "");
}
}
2 changes: 2 additions & 0 deletions masq/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::commands::descriptor_command::descriptor_subcommand;
use crate::commands::exit_location_command::exit_location_subcommand;
use crate::commands::financials_command::args_validation::financials_subcommand;
use crate::commands::generate_wallets_command::generate_wallets_subcommand;
use crate::commands::neighborhood_graph_command::get_neighborhood_graph_subcommand;
use crate::commands::recover_wallets_command::recover_wallets_subcommand;
use crate::commands::scan_command::scan_subcommand;
use crate::commands::set_configuration_command::set_configuration_subcommand;
Expand Down Expand Up @@ -71,6 +72,7 @@ pub fn app() -> App<'static, 'static> {
.subcommand(exit_location_subcommand())
.subcommand(financials_subcommand())
.subcommand(generate_wallets_subcommand())
.subcommand(get_neighborhood_graph_subcommand())
.subcommand(recover_wallets_subcommand())
.subcommand(scan_subcommand())
.subcommand(set_configuration_subcommand())
Expand Down
12 changes: 12 additions & 0 deletions masq_lib/src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,18 @@ pub struct UiSetExitLocationResponse {
}
conversation_message!(UiSetExitLocationResponse, "exitLocation");

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct UiGetNeighborhoodGraphRequest {}

conversation_message!(UiGetNeighborhoodGraphRequest, "neighborhoodGraph");

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct UiGetNeighborhoodGraphResponse {
pub graph: String,
}

conversation_message!(UiGetNeighborhoodGraphResponse, "neighborhoodGraph");

#[cfg(test)]
mod tests {
use super::*;
Expand Down
4 changes: 2 additions & 2 deletions multinode_integration_tests/tests/bookkeeping_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ fn provided_and_consumed_services_are_recorded_in_databases() {

let mut client = originating_node.make_client(8080, STANDARD_CLIENT_TIMEOUT_MILLIS);
client.set_timeout(Duration::from_secs(10));
let request = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n".as_bytes();
let request = "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n".as_bytes();

client.send_chunk(request);
let response = String::from_utf8(client.wait_for_chunk()).unwrap();
assert!(
response.contains("<h1>Example Domain</h1>"),
"Not from example.com:\n{}",
"Not from www.example.com:\n{}",
response
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ fn neighborhood_notified_of_newly_missing_node() {

//Establish a client on the originating Node and send some ill-fated traffic.
let mut client = originating_node.make_client(8080, STANDARD_CLIENT_TIMEOUT_MILLIS);
client.send_chunk("GET http://example.com HTTP/1.1\r\n\r\n".as_bytes());
client.send_chunk("GET http://www.example.com HTTP/1.1\r\n\r\n".as_bytes());

// Now direct the witness Node to wait for Gossip about the disappeared Node.
let (disappearance_gossip, _) = witness_node
Expand Down Expand Up @@ -405,7 +405,7 @@ fn dns_resolution_failure_no_longer_blacklists_exit_node_for_all_hosts() {
),
);

client.send_chunk("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n".as_bytes());
client.send_chunk("GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n".as_bytes());
let cheapest_node = node_list.first().unwrap();
let cheapest_node_expired_cores_package = cheapest_node
.wait_for_specific_package(
Expand Down
4 changes: 2 additions & 2 deletions multinode_integration_tests/tests/data_routing_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ fn tls_end_to_end_routing_test() {
.expect("Could not set read timeout to 1000ms");
let connector = TlsConnector::new().expect("Could not build TlsConnector");
match connector.connect(
"example.com",
"www.example.com",
stream.try_clone().expect("Couldn't clone TcpStream"),
) {
Ok(s) => {
Expand All @@ -199,7 +199,7 @@ fn tls_end_to_end_routing_test() {

tls_stream.expect("Couldn't handshake")
};
let request = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n".as_bytes();
let request = "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n".as_bytes();
tls_stream
.write(request.clone())
.expect("Could not write request to TLS stream");
Expand Down
2 changes: 1 addition & 1 deletion node/src/blockchain/blockchain_bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ mod tests {
#[test]
fn blockchain_interface_is_constructed_with_a_blockchain_service_url() {
init_test_logging();
let blockchain_service_url = "https://example.com";
let blockchain_service_url = "https://www.example.com";
let subject = BlockchainBridge::initialize_blockchain_interface(
Some(blockchain_service_url.to_string()),
TEST_DEFAULT_CHAIN,
Expand Down
93 changes: 92 additions & 1 deletion node/src/neighborhood/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ use masq_lib::exit_locations::ExitLocationSet;
use masq_lib::logger::Logger;
use masq_lib::messages::{
ExitLocation, FromMessageBody, ToMessageBody, UiConnectionStage, UiConnectionStatusRequest,
UiSetExitLocationRequest, UiSetExitLocationResponse,
UiGetNeighborhoodGraphRequest, UiGetNeighborhoodGraphResponse, UiSetExitLocationRequest,
UiSetExitLocationResponse,
};
use masq_lib::messages::{UiConnectionStatusResponse, UiShutdownRequest};
use masq_lib::ui_gateway::MessagePath::Conversation;
Expand Down Expand Up @@ -366,6 +367,8 @@ impl Handler<NodeFromUiMessage> for Neighborhood {
self.handle_connection_status_message(client_id, context_id);
} else if let Ok((body, _)) = UiShutdownRequest::fmb(msg.body.clone()) {
self.handle_shutdown_order(client_id, body);
} else if let Ok((_, context_id)) = UiGetNeighborhoodGraphRequest::fmb(msg.body.clone()) {
self.handle_neighborhood_graph_message(client_id, context_id);
} else {
handle_ui_crash_request(msg, &self.logger, self.crashable, CRASH_KEY)
}
Expand Down Expand Up @@ -1611,6 +1614,19 @@ impl Neighborhood {
undesirability + node_undesirability
}

fn handle_neighborhood_graph_message(&self, client_id: u64, context_id: u64) {
let graph = self.neighborhood_database.to_dot_graph();
let message = NodeToUiMessage {
target: MessageTarget::ClientId(client_id),
body: UiGetNeighborhoodGraphResponse { graph }.tmb(context_id),
};
self.node_to_ui_recipient_opt
.as_ref()
.expect("UI Gateway is unbound")
.try_send(message)
.expect("UiGateway is dead");
}

fn handle_exit_location_message(
&mut self,
message: UiSetExitLocationRequest,
Expand Down Expand Up @@ -3634,6 +3650,81 @@ mod tests {
assert_eq!(juicy_parts(result_1), (1, 1));
}

#[test]
fn handle_neighborhood_graph_message_works() {
let test_name = "handle_neighborhood_graph_message_works";
let system = System::new(test_name);
let (ui_gateway, _recorder, arc_recorder) = make_recorder();
let mut subject = make_standard_subject();
let root_node_ch = subject.neighborhood_database.root().clone();
let neighbor_one_au = make_node_record_cc(1234, true, "AU");
let neighbor_two_fr = make_node_record_cc(2345, true, "FR");
let neighbor_three_cn = make_node_record_cc(3456, true, "CN");
let neighbor_four_us = make_node_record_cc(4567, true, "US");
let root_pubkey = format!("{}", root_node_ch.public_key());
let neighbor_one_pubkey = format!("{}", neighbor_one_au.public_key());
let neighbor_two_pubkey = format!("{}", neighbor_two_fr.public_key());
let neighbor_three_pubkey = format!("{}", neighbor_three_cn.public_key());
let neighbor_four_pubkey = format!("{}", neighbor_four_us.public_key());
subject
.neighborhood_database
.add_node(neighbor_one_au.clone())
.unwrap();
subject
.neighborhood_database
.add_node(neighbor_two_fr.clone())
.unwrap();
subject
.neighborhood_database
.add_node(neighbor_three_cn.clone())
.unwrap();
subject
.neighborhood_database
.add_node(neighbor_four_us.clone())
.unwrap();
subject
.neighborhood_database
.add_arbitrary_full_neighbor(root_node_ch.public_key(), neighbor_one_au.public_key());
subject.neighborhood_database.add_arbitrary_full_neighbor(
neighbor_one_au.public_key(),
neighbor_two_fr.public_key(),
);
subject.neighborhood_database.add_arbitrary_full_neighbor(
neighbor_two_fr.public_key(),
neighbor_three_cn.public_key(),
);
subject.neighborhood_database.add_arbitrary_full_neighbor(
neighbor_three_cn.public_key(),
neighbor_four_us.public_key(),
);
let request = UiGetNeighborhoodGraphRequest {};
let message = NodeFromUiMessage {
client_id: 456,
body: request.tmb(465),
};
let subject_addr = subject.start();
let peer_actors = peer_actors_builder().ui_gateway(ui_gateway).build();
subject_addr.try_send(BindMessage { peer_actors }).unwrap();

subject_addr.try_send(message).unwrap();
System::current().stop();
system.run();

let recorder_result = arc_recorder.lock().unwrap();
let result = recorder_result
.get_record::<NodeToUiMessage>(0)
.body
.clone()
.payload
.unwrap();
let result_object: UiGetNeighborhoodGraphResponse = serde_json::from_str(&result).unwrap();
assert!(result_object.graph.contains(&root_pubkey));
assert!(result_object.graph.contains(&neighbor_one_pubkey));
assert!(result_object.graph.contains(&neighbor_two_pubkey));
assert!(result_object.graph.contains(&neighbor_three_pubkey));
assert!(result_object.graph.contains(&neighbor_four_pubkey));
}

#[test]
fn min_hops_change_affects_db_countries_and_exit_location_settings() {
let mut subject = make_standard_subject();
Expand Down
11 changes: 7 additions & 4 deletions node/src/proxy_server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6378,8 +6378,11 @@ mod tests {

#[test]
fn hostname_works() {
assert_on_hostname("https://example.com/folder/file.html", "example.com");
assert_on_hostname("example.com/index.php?arg=test", "example.com");
assert_on_hostname(
"https://www.example.com/folder/file.html",
"www.example.com",
);
assert_on_hostname("www.example.com/index.php?arg=test", "www.example.com");
assert_on_hostname("sub.example.com/index.php?arg=test", "sub.example.com");
assert_on_hostname("1.1.1.1", "1.1.1.1");
assert_on_hostname("", "");
Expand Down Expand Up @@ -6428,11 +6431,11 @@ mod tests {
Err("localhost".to_string())
);
assert_eq!(
Hostname::new("example.com").validate_non_loopback_host(),
Hostname::new("www.example.com").validate_non_loopback_host(),
Ok(())
);
assert_eq!(
Hostname::new("https://example.com").validate_non_loopback_host(),
Hostname::new("https://www.example.com").validate_non_loopback_host(),
Ok(())
);
}
Expand Down
Loading
Loading