From 0dfd17cc9458603dc7799a95b6dff01b22dbc791 Mon Sep 17 00:00:00 2001 From: s-prechtl Date: Tue, 13 Jun 2023 00:26:42 +0200 Subject: [PATCH 1/9] Added readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..d404e1c --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Wifi-Connector +Written in Rust. There will be GUI as well, hopefully. From e30ecd06e6ff47bfaf65c543d43311ef9a418f4e Mon Sep 17 00:00:00 2001 From: s-prechtl Date: Fri, 23 Jun 2023 16:06:30 +0200 Subject: [PATCH 2/9] feat: Moved Network to its own file --- src/lib.rs | 1 + src/main.rs | 55 ++++++++++++++++++++----------------- src/network.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 25 deletions(-) create mode 100644 src/lib.rs create mode 100644 src/network.rs diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..a61610b --- /dev/null +++ b/src/lib.rs @@ -0,0 +1 @@ +pub mod network; diff --git a/src/main.rs b/src/main.rs index e8fad5c..0295bf3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,19 +1,6 @@ -use std::{process::Command, vec}; +use wifi_connector::network::Network; use anyhow::*; - -struct Network { - in_use: bool, - ssid: String, - signal: u8, -} - -impl Network { - fn from_nmcli_stdout(line: String) { - for element in line.split(' ') { - println!("{}", element); - } - } -} +use std::{process::Command, vec}; fn get_available_wifis() -> Result { let output = Command::new("nmcli") @@ -23,26 +10,44 @@ fn get_available_wifis() -> Result { .output() .expect("Failed to execute command"); - Ok(String::from_utf8_lossy(output.stdout.as_slice()).into()) + Ok(String::from_utf8_lossy(output.stdout.as_slice()).into()) } fn get_descriptor_positions(header_line: &String) -> Vec { let mut positions: Vec = vec![]; positions.push(0); - positions.push(header_line.find(" SSID").expect("SSID not found in header string") as u8 +1); - positions.push(header_line.find("SIGNAL").expect("SIGNAL not found in header string") as u8); + positions.push( + header_line + .find(" SSID") + .expect("SSID not found in header string") as u8 + + 1, + ); + positions.push( + header_line + .find("SIGNAL") + .expect("SIGNAL not found in header string") as u8, + ); return positions; } fn main() { - let all_wifis: String = get_available_wifis().expect("Wifi fetching exploded"); - let positions = get_descriptor_positions(&all_wifis); - for position in (positions) { - println!("{}", position); + let nmcli_output: String = get_available_wifis().expect("Wifi fetching exploded"); + let positions = get_descriptor_positions(&nmcli_output); + + let mut all_wifi_lines: Vec = nmcli_output.split('\n').map(|s| String::from(s)).collect(); + let mut all_networks: Vec = vec![]; + all_wifi_lines.remove(0); + + for line in all_wifi_lines { + if line.is_empty() { + continue; + } + all_networks.push(Network::from_nmcli_stdout(line.to_owned(), &positions)); + } + + for network in all_networks { + dbg!("{}", network); } - // for line in all_wifis.split("\n") { - // Network::from_nmcli_stdout(line.to_owned()); - // } } diff --git a/src/network.rs b/src/network.rs new file mode 100644 index 0000000..1cfc4a3 --- /dev/null +++ b/src/network.rs @@ -0,0 +1,73 @@ +#[derive(Debug)] +pub struct Network { + in_use: bool, + ssid: String, + signal: u8, +} + +impl Network { + pub fn from_nmcli_stdout(line: String, header_positions: &Vec) -> Self { + let mut network = Self { + in_use: false, + ssid: "".to_string(), + signal: 0, + }; + + let ssid_pos = header_positions + .get(1) + .expect("header_positions has no index for SSID") + .to_owned() as usize; + let signal_pos = header_positions + .get(2) + .expect("header_positions has no index for SSID") + .to_owned() as usize; + + if line + .chars() + .nth( + header_positions + .get(0) + .expect("header_positions has no index 0") + .to_owned() as usize, + ) + .expect("Given line has no index 0") + == '*' + { + network.in_use = true; + } + + let mut current_spaces = 0; + for char in line.chars().skip(ssid_pos) { + if char == ' ' { + current_spaces += 1; + if current_spaces == 2 { + break; + } + } else { + if current_spaces == 1 { + network.ssid.push(' '); + } + current_spaces = 0; + network.ssid.push(char); + } + } + + let mut signal_as_string: String = line + .chars() + .nth(signal_pos) + .expect("Line has no Signal pos") + .to_string(); + + signal_as_string.push( + line.chars() + .nth(signal_pos + 1) + .expect("Line has no Signal pos"), + ); + + network.signal = signal_as_string + .parse::() + .expect("Could not parse signal"); + + return network; + } +} From 0ce0705e1962ac6202e4b6b3cf240110ba9146a4 Mon Sep 17 00:00:00 2001 From: s-prechtl Date: Fri, 23 Jun 2023 17:08:03 +0200 Subject: [PATCH 3/9] feat: Networks can be connected via console now --- src/main.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++---- src/network.rs | 14 +++++++++++--- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/src/main.rs b/src/main.rs index 0295bf3..3f49050 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ use wifi_connector::network::Network; use anyhow::*; -use std::{process::Command, vec}; +use std::{process::Command, vec, io::Write}; fn get_available_wifis() -> Result { let output = Command::new("nmcli") @@ -32,7 +32,7 @@ fn get_descriptor_positions(header_line: &String) -> Vec { return positions; } -fn main() { +fn get_all_networks() -> Vec { let nmcli_output: String = get_available_wifis().expect("Wifi fetching exploded"); let positions = get_descriptor_positions(&nmcli_output); @@ -47,7 +47,48 @@ fn main() { all_networks.push(Network::from_nmcli_stdout(line.to_owned(), &positions)); } - for network in all_networks { - dbg!("{}", network); + return all_networks; +} + +fn connect_to_network(network: &Network, password: &str) -> Result<()> { + let output = Command::new("nmcli") + .arg("device") + .arg("wifi") + .arg("connect") + .arg(&network.ssid.trim()) + .arg("password") + .arg(password) + .output() + .expect("Failed to execute command"); + + println!("{:?}", password); + + if output.status.success() { + Ok(()) + } else { + Err(anyhow!("Failed to connect to network")) + } +} + +fn main() { + let all_networks = get_all_networks(); + + for (idx, network) in all_networks.iter().enumerate() { + println!("{} - {}", idx, network); + } + + println!("Which network do you choose? (0-{})", all_networks.len() - 1); + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + let network = all_networks.get(input.trim().parse::().unwrap()).expect("Given number does not reference a network"); + let mut password = String::new(); + print!("Now enter the password for the selected wifi '{}': ", network.ssid); + std::io::stdout().flush(); + std::io::stdin().read_line(&mut password).unwrap(); + let result = connect_to_network(&network, password.trim()); + if result.is_ok() { + println!("Successfully connected to network '{}'", network.ssid); + } else { + println!("Connection failed"); } } diff --git a/src/network.rs b/src/network.rs index 1cfc4a3..59f342d 100644 --- a/src/network.rs +++ b/src/network.rs @@ -1,8 +1,10 @@ +use std::fmt::Display; + #[derive(Debug)] pub struct Network { - in_use: bool, - ssid: String, - signal: u8, + pub in_use: bool, + pub ssid: String, + pub signal: u8, } impl Network { @@ -71,3 +73,9 @@ impl Network { return network; } } + +impl Display for Network { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + return write!(f, "{} - {} - {} ", self.in_use, self.ssid, self.signal); + } +} From fb68623acbf3122cddae2130240f0e702a003dbb Mon Sep 17 00:00:00 2001 From: s-prechtl Date: Fri, 23 Jun 2023 17:09:08 +0200 Subject: [PATCH 4/9] fix: fixed warning on flush() --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 3f49050..4f132f1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -83,7 +83,7 @@ fn main() { let network = all_networks.get(input.trim().parse::().unwrap()).expect("Given number does not reference a network"); let mut password = String::new(); print!("Now enter the password for the selected wifi '{}': ", network.ssid); - std::io::stdout().flush(); + std::io::stdout().flush().unwrap(); std::io::stdin().read_line(&mut password).unwrap(); let result = connect_to_network(&network, password.trim()); if result.is_ok() { From c6fd190660f5591d922416fbb72ec118dedf9b77 Mon Sep 17 00:00:00 2001 From: s-prechtl Date: Fri, 23 Jun 2023 18:22:02 +0200 Subject: [PATCH 5/9] feat: Connection is now established to known networks without password --- src/main.rs | 63 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/src/main.rs b/src/main.rs index 4f132f1..4ad9312 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ -use wifi_connector::network::Network; use anyhow::*; -use std::{process::Command, vec, io::Write}; +use std::{io::Write, process::Command, }; +use wifi_connector::network::Network; fn get_available_wifis() -> Result { let output = Command::new("nmcli") @@ -36,7 +36,8 @@ fn get_all_networks() -> Vec { let nmcli_output: String = get_available_wifis().expect("Wifi fetching exploded"); let positions = get_descriptor_positions(&nmcli_output); - let mut all_wifi_lines: Vec = nmcli_output.split('\n').map(|s| String::from(s)).collect(); + let mut all_wifi_lines: Vec = + nmcli_output.split('\n').map(|s| String::from(s)).collect(); let mut all_networks: Vec = vec![]; all_wifi_lines.remove(0); @@ -61,8 +62,6 @@ fn connect_to_network(network: &Network, password: &str) -> Result<()> { .output() .expect("Failed to execute command"); - println!("{:?}", password); - if output.status.success() { Ok(()) } else { @@ -70,25 +69,57 @@ fn connect_to_network(network: &Network, password: &str) -> Result<()> { } } +fn try_connect_to_network_without_password(network: &Network) -> Result<()> { + let output = Command::new("nmcli") + .arg("device") + .arg("wifi") + .arg("connect") + .arg(&network.ssid.trim()) + .output() + .expect("Failed to execute command"); + + + if output.status.success() { + Ok(()) + } else { + dbg!(output.stderr); + Err(anyhow!("Couldn't connect to wifi without password")) + } +} + fn main() { let all_networks = get_all_networks(); for (idx, network) in all_networks.iter().enumerate() { - println!("{} - {}", idx, network); + println!("{} - {}", idx, network); } - println!("Which network do you choose? (0-{})", all_networks.len() - 1); + println!( + "Which network do you choose? (0-{})", + all_networks.len() - 1 + ); let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); - let network = all_networks.get(input.trim().parse::().unwrap()).expect("Given number does not reference a network"); - let mut password = String::new(); - print!("Now enter the password for the selected wifi '{}': ", network.ssid); - std::io::stdout().flush().unwrap(); - std::io::stdin().read_line(&mut password).unwrap(); - let result = connect_to_network(&network, password.trim()); - if result.is_ok() { - println!("Successfully connected to network '{}'", network.ssid); + let network = all_networks + .get(input.trim().parse::().unwrap()) + .expect("Given number does not reference a network"); + let connected = try_connect_to_network_without_password(network); + + if !connected.is_ok() { + let mut password = String::new(); + print!( + "Now enter the password for the selected wifi '{}': ", + network.ssid + ); + std::io::stdout().flush().unwrap(); + std::io::stdin().read_line(&mut password).unwrap(); + let result = connect_to_network(&network, password.trim()); + if result.is_ok() { + println!("Successfully connected to network '{}'", network.ssid); + } else { + println!("Connection failed"); + } } else { - println!("Connection failed"); + println!("Successfully connected to network '{}'", network.ssid); } } From bcb17136d9418ef0b78f718497f449d01202a2e7 Mon Sep 17 00:00:00 2001 From: s-prechtl Date: Fri, 23 Jun 2023 18:34:28 +0200 Subject: [PATCH 6/9] feat: refactored main() --- src/main.rs | 60 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/src/main.rs b/src/main.rs index 4ad9312..6b63e58 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ use anyhow::*; -use std::{io::Write, process::Command, }; +use std::{io::Write, mem::align_of_val, process::Command}; use wifi_connector::network::Network; fn get_available_wifis() -> Result { @@ -78,48 +78,56 @@ fn try_connect_to_network_without_password(network: &Network) -> Result<()> { .output() .expect("Failed to execute command"); - if output.status.success() { Ok(()) } else { - dbg!(output.stderr); Err(anyhow!("Couldn't connect to wifi without password")) } } -fn main() { - let all_networks = get_all_networks(); - - for (idx, network) in all_networks.iter().enumerate() { +fn print_networks(networks: &Vec) { + for (idx, network) in networks.iter().enumerate() { println!("{} - {}", idx, network); } +} - println!( - "Which network do you choose? (0-{})", - all_networks.len() - 1 +fn password_prompt_for_network(network: &Network) -> String { + let mut password = String::new(); + print!( + "Now enter the password for the selected wifi '{}': ", + network.ssid ); + std::io::stdout().flush().unwrap(); + std::io::stdin().read_line(&mut password).unwrap(); + password +} + +fn choose_network(max: usize) -> String { + println!("Which network do you choose? (0-{})", max); let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); + input +} + +fn main() { + let all_networks = get_all_networks(); + print_networks(&all_networks); + + let chosen_network_index = choose_network(all_networks.len() - 1); + let network = all_networks - .get(input.trim().parse::().unwrap()) + .get(chosen_network_index.trim().parse::().unwrap()) .expect("Given number does not reference a network"); - let connected = try_connect_to_network_without_password(network); + let mut connected = try_connect_to_network_without_password(network); if !connected.is_ok() { - let mut password = String::new(); - print!( - "Now enter the password for the selected wifi '{}': ", - network.ssid - ); - std::io::stdout().flush().unwrap(); - std::io::stdin().read_line(&mut password).unwrap(); - let result = connect_to_network(&network, password.trim()); - if result.is_ok() { - println!("Successfully connected to network '{}'", network.ssid); - } else { - println!("Connection failed"); - } - } else { + let password = password_prompt_for_network(network); + connected = connect_to_network(&network, password.trim()); + } + + if connected.is_ok() { println!("Successfully connected to network '{}'", network.ssid); + } else { + println!("Connection failed"); } } From a005d923faad2adc979a172b1a2e1af7a91b7c04 Mon Sep 17 00:00:00 2001 From: s-prechtl Date: Fri, 23 Jun 2023 18:41:13 +0200 Subject: [PATCH 7/9] feat: lil header printering --- src/main.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main.rs b/src/main.rs index 6b63e58..71e23e2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -109,8 +109,14 @@ fn choose_network(max: usize) -> String { input } +fn print_header() { + println!("Index - In use - SSID - Signal"); +} + fn main() { let all_networks = get_all_networks(); + + print_header(); print_networks(&all_networks); let chosen_network_index = choose_network(all_networks.len() - 1); From e5cb2d05f9dff4b0b35cba0836973a03086ba57b Mon Sep 17 00:00:00 2001 From: s-prechtl Date: Fri, 23 Jun 2023 19:45:49 +0200 Subject: [PATCH 8/9] feat: List now shows only unique SSIDs with the strongest corresponding signal --- src/main.rs | 21 +++++++++++++++++++-- src/network.rs | 2 +- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index 71e23e2..e2a8658 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ use anyhow::*; -use std::{io::Write, mem::align_of_val, process::Command}; +use std::{collections::HashMap, io::Write, process::Command, vec}; use wifi_connector::network::Network; fn get_available_wifis() -> Result { @@ -113,8 +113,25 @@ fn print_header() { println!("Index - In use - SSID - Signal"); } +fn uniquify_networks(networks: Vec) -> Vec { + let mut unique_networks: HashMap = HashMap::new(); + + for network in &networks { + let current_ssid = &network.ssid; + if unique_networks.keys().any(|key| key == current_ssid) { + if unique_networks[current_ssid].signal < network.signal { + unique_networks.insert(current_ssid.to_owned(), network.to_owned()); + } + } else { + unique_networks.insert(current_ssid.to_owned(), network.to_owned()); + } + } + + return unique_networks.into_values().collect(); +} + fn main() { - let all_networks = get_all_networks(); + let all_networks = uniquify_networks(get_all_networks()); print_header(); print_networks(&all_networks); diff --git a/src/network.rs b/src/network.rs index 59f342d..757813a 100644 --- a/src/network.rs +++ b/src/network.rs @@ -1,6 +1,6 @@ use std::fmt::Display; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Network { pub in_use: bool, pub ssid: String, From 815c4db23bdca1813a502ccc9cdaafd8d136e8a1 Mon Sep 17 00:00:00 2001 From: s-prechtl Date: Wed, 28 Jun 2023 11:51:38 +0200 Subject: [PATCH 9/9] feat: trimmed password in function for safer usage --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index e2a8658..16b2872 100644 --- a/src/main.rs +++ b/src/main.rs @@ -58,7 +58,7 @@ fn connect_to_network(network: &Network, password: &str) -> Result<()> { .arg("connect") .arg(&network.ssid.trim()) .arg("password") - .arg(password) + .arg(password.trim()) .output() .expect("Failed to execute command");