Chore(Linux): Add Connect To WPA & WPA

This commit is contained in:
Tochukwu Nkemdilim
2018-07-02 16:19:48 +01:00
parent ca49d9ba21
commit bfd9385844
7 changed files with 115 additions and 74 deletions
+1
View File
@@ -4,3 +4,4 @@ version = "0.1.0"
authors = ["Tochukwu Nkemdilim <[email protected]>"] authors = ["Tochukwu Nkemdilim <[email protected]>"]
[dependencies] [dependencies]
tempfile = "3.0.2"
+17 -13
View File
@@ -1,30 +1,34 @@
pub mod profile_network;
mod handlers; mod handlers;
mod stubs; pub mod profile_network;
mod providers; mod providers;
mod stubs;
use std::{fmt, io}; use std::{fmt, io};
use std::string::FromUtf8Error;
pub trait Network { pub trait Network: fmt::Debug {
/// Makes an attempt to connect to a selected wireless network with password specified. /// Makes an attempt to connect to a selected wireless network with password specified.
fn connect(&self, password: &str) -> bool; fn connect(&self, password: &str) -> bool;
} }
// Improve upon this. #[derive(Debug)]
impl fmt::Debug for Network {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Network")
}
}
pub enum NetworkType { pub enum NetworkType {
WEP, WEP,
WPA, WPA,
WPA2, WPA2,
} }
pub enum NetworkTypeParseError { #[derive(Debug)]
FromUtf8Error(FromUtf8Error), pub enum NetworkError {
// FromUtf8Error(FromUtf8Error),
SsidNotFound,
OsNotSupported,
IpAssignFailed,
IoError(io::Error), IoError(io::Error),
FailedToConnect(String),
}
impl From<io::Error> for NetworkError {
fn from(error: io::Error) -> Self {
NetworkError::IoError(error)
}
} }
+6 -10
View File
@@ -1,6 +1,4 @@
use connectivity::providers::{Machine}; use connectivity::{providers::Machine, Network, NetworkError};
use connectivity::Network;
use std::io::{Error, ErrorKind};
#[derive(Debug)] #[derive(Debug)]
pub struct ProfileNetwork { pub struct ProfileNetwork {
@@ -9,18 +7,16 @@ pub struct ProfileNetwork {
/// Profile Network handler responsible to connect to a wireless network. /// Profile Network handler responsible to connect to a wireless network.
impl ProfileNetwork { impl ProfileNetwork {
pub fn new(name: &str) -> Result<Self, Error> { pub fn new(name: &str) -> Result<Self, NetworkError> {
if !(cfg!(target_os = "linux") || cfg!(target_os = "windows")) { if !(cfg!(target_os = "linux") || cfg!(target_os = "windows")) {
return Err(Error::new( return Err(NetworkError::OsNotSupported);
ErrorKind::Other,
"The Specified OS is not supported",
));
} }
let handler = Machine::new(name)?; let handler = Machine::new(name)?;
return Ok(ProfileNetwork {
Ok(ProfileNetwork {
handler: Box::new(handler), handler: Box::new(handler),
}); })
} }
pub fn connect(&self, password: &str) -> bool { pub fn connect(&self, password: &str) -> bool {
+72 -33
View File
@@ -1,71 +1,110 @@
use connectivity::{Network, NetworkType, NetworkTypeParseError}; extern crate tempfile;
use std::io;
use std::io::{Error, ErrorKind};
use std::process::{Command, Output};
use self::tempfile::NamedTempFile;
use connectivity::{Network, NetworkError, NetworkType};
use std::process::{Command, Output};
use std::{
fs::File, io::{Error, Read, Write},
};
#[derive(Debug)]
pub struct Linux { pub struct Linux {
pub name: String, pub name: String,
pub network_type: NetworkType, pub network_type: NetworkType,
} }
impl Linux { impl Linux {
pub fn new(name: String) -> Result<Self, io::Error> { pub fn new(name: &str) -> Result<Self, NetworkError> {
match Linux::check_if_web_or_wpa(name.clone()) { match Linux::check_if_web_or_wpa(name.into()) {
Ok(t) => match t { Ok(t) => match t {
NetworkType::WEP => Ok(Linux { NetworkType::WEP => Ok(Linux {
name: name.clone(), name: name.into(),
network_type: NetworkType::WEP, network_type: NetworkType::WEP,
}), }),
_ => Ok(Linux { _ => Ok(Linux {
name: name.clone(), name: name.into(),
network_type: NetworkType::WPA, network_type: NetworkType::WPA,
}), }),
}, },
Err(_) => Err(Error::new(ErrorKind::Other, "Failed to parse")), // use the NetworkTypeParseError::IoError here Err(err) => Err(err),
} }
} }
/// Detects the network type of a given network. /// Detects the network type of a given network.
fn check_if_web_or_wpa(name: String) -> Result<NetworkType, NetworkTypeParseError> { fn check_if_web_or_wpa(name: String) -> Result<NetworkType, NetworkError> {
Command::new("nmcli") Command::new("nmcli")
.args(&[ .args(&[
"-t",
"-f",
"802-11-wireless-security.key-mgmt",
"con", "con",
"list", "show",
"id",
"\"",
&name, &name,
"\"",
"|",
"awk",
"'/key-mgmt/ {{ print $2 }}'",
]) ])
.output() .output()
.map_err(|err| NetworkTypeParseError::IoError(err)) .map_err(|err| NetworkError::IoError(err))
.and_then(|output| { .and_then(|output| {
String::from_utf8(output.stdout) let output = String::from_utf8_lossy(&output.stdout);
.map_err(|err| NetworkTypeParseError::FromUtf8Error(err)) let psk = {
.and_then(|result| match result.as_ref() { let mut split = output.split(':');
"wpa-psk" => Ok(NetworkType::WPA), let _ = split.next();
_ => Ok(NetworkType::WEP), match split.next() {
}) Some(x) => x,
None => return Err(NetworkError::SsidNotFound),
}
};
match psk.trim() {
"wpa-psk" => Ok(NetworkType::WPA),
_ => Ok(NetworkType::WEP),
}
}) })
} }
pub fn connect_to_wep_network(&self, password: &str) -> Result<Output, io::Error> { pub fn connect_to_wep_network(&self, password: &str) -> Result<Output, NetworkError> {
Command::new("iwconfig") Ok(Command::new("iwconfig")
.args(&["wlan0", "essid", &self.name, "key", password]) .args(&["wlan0", "essid", &self.name, "key", password])
.output() .output()
.map_err(|err| NetworkError::FailedToConnect(format!("{:?}", err)))?)
} }
pub fn connect_to_wpa_network(&self, password: &str) -> Result<Output, io::Error> { pub fn connect_to_wpa_network(&self, password: &str) -> Result<Output, NetworkError> {
// Dynamically generate differennt version of file (if running sync) let passphrase = Command::new("wpa_passphrase")
Command::new("wpa_passphrase") .args(&[&self.name, password])
.args(&[&self.name, password, "wpa.conf"])
.output()?; .output()?;
Ok(Command::new("wpa_supplicant") let wpa_conf_file = self.create_conf_file(&String::from_utf8_lossy(&passphrase.stdout))?;
.args(&["-Dwext", "-i", "wlan0", "-c/root/wpa.conf"])
.output()?) let mut file = File::open(wpa_conf_file.path())?;
let mut new_content = String::new();
file.read_to_string(&mut new_content)?;
Command::new("wpa_supplicant")
.args(&[
"-D",
"wext",
"-B",
"-i",
"wlo1",
wpa_conf_file.path().to_str().unwrap(),
])
.output()
.map_err(|err| NetworkError::FailedToConnect(format!("{:?}", err)))?;
let a = Command::new("dhclient").args(&["wlo1"]).output()?;
println!("{:?}", String::from_utf8_lossy(&a.stdout));
Ok(Command::new("dhclient")
.args(&["wlo1"])
.output()
.map_err(|_| NetworkError::IpAssignFailed)?)
}
fn create_conf_file(&self, content: &str) -> Result<NamedTempFile, Error> {
let mut temp_file = NamedTempFile::new()?;
write!(temp_file, "{}", content)?;
Ok(temp_file)
} }
} }
+14 -10
View File
@@ -1,17 +1,16 @@
use connectivity::handlers::NetworkXmlProfileHandler; use connectivity::handlers::NetworkXmlProfileHandler;
use connectivity::Network; use connectivity::Network;
use std::io;
use std::process::Command; use std::process::Command;
const OUTPUT_XML_FILE_PATH: &str = "output.xml"; #[derive(Debug)]
#[cfg(target_os = "windows")]
pub(crate) struct Windows { pub(crate) struct Windows {
name: String, name: String,
pub output_xml_path: String, pub output_xml_path: String,
} }
impl Windows { impl Windows {
#[cfg(target_os = "windows")]
pub fn new(name: &str) -> Result<Self, io::Error> { pub fn new(name: &str) -> Result<Self, io::Error> {
Ok(Windows { Ok(Windows {
name: String::from(name), name: String::from(name),
@@ -33,12 +32,17 @@ impl Windows {
// Add the network profile // Add the network profile
if let Err(_) = Command::new("netsh") if let Err(_) = Command::new("netsh")
.args(&["wlan", "add", "profile", &format!("filename={}", self.output_xml_path)]) .args(&[
"wlan",
"add",
"profile",
&format!("filename={}", self.output_xml_path),
])
.output() .output()
{ {
return false; return false;
} }
true true
} }
} }
@@ -48,7 +52,7 @@ impl Network for Windows {
if self.add_profile(password) == false { if self.add_profile(password) == false {
return false; return false;
} }
let output = Command::new("netsh") let output = Command::new("netsh")
.args(&["wlan", "connect", &format!("name={}", self.name)]) .args(&["wlan", "connect", &format!("name={}", self.name)])
.output(); .output();
+1 -1
View File
@@ -1,7 +1,7 @@
#![allow(dead_code)] #![allow(dead_code)]
mod connectivity; mod connectivity;
pub use connectivity::profile_network::ProfileNetwork as WiFi; pub use connectivity::{profile_network::ProfileNetwork as WiFi, *};
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
+4 -7
View File
@@ -1,12 +1,9 @@
use std::io;
mod connectivity; mod connectivity;
pub use connectivity::profile_network::ProfileNetwork as WiFi; pub use connectivity::{profile_network::ProfileNetwork as WiFi, NetworkError};
fn main() -> Result<(), io::Error> {
let mut wifi = WiFi::new("AndroidAPS")?;
fn main() -> Result<(), NetworkError> {
let wifi = WiFi::new("AndroidAPSD")?;
println!("{}", wifi.connect("belm4235")); println!("{}", wifi.connect("belm4235"));
Ok(()) Ok(())
} }