Chore(Stage): Initial Commit

This commit is contained in:
Tochukwu Nkemdilim
2018-06-13 18:41:24 +01:00
commit 1535d3d768
12 changed files with 305 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
**/target/*
**/*.rs.bk
Cargo.lock
*.xml
.env
rls
.vscode
.idea
**/.DS_Store
crossbeam-channel
+6
View File
@@ -0,0 +1,6 @@
[package]
name = "wifi-rs"
version = "0.1.0"
authors = ["Tochukwu Nkemdilim <nkemdilimtochukwu@gmail.com>"]
[dependencies]
+3
View File
@@ -0,0 +1,3 @@
mod xml_profile_handler;
pub(crate) use self::xml_profile_handler::NetworkXmlProfileHandler;
@@ -0,0 +1,24 @@
use std::fs;
use std::io;
use connectivity::stubs::windows_wifi_profile;
pub(crate) struct NetworkXmlProfileHandler {
pub(crate) content: String,
}
impl NetworkXmlProfileHandler {
pub fn new() -> Self {
NetworkXmlProfileHandler {
content: NetworkXmlProfileHandler::read_from_stub(),
}
}
pub fn read_from_stub() -> String {
windows_wifi_profile::get_wifi_profile()
}
/// Recreate the file and dump the processed contents to it
pub fn to_file(&mut self, file_path: &str) -> Result<(), io::Error> {
Ok(fs::write(&file_path, self.content.as_bytes())?)
}
}
+30
View File
@@ -0,0 +1,30 @@
pub mod profile_network;
mod handlers;
mod stubs;
mod providers;
use std::{fmt, io};
use std::string::FromUtf8Error;
pub trait Network {
/// Makes an attempt to connect to a selected wireless network with password specified.
fn connect(&self, password: &str) -> bool;
}
// Improve upon this.
impl fmt::Debug for Network {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Network")
}
}
pub enum NetworkType {
WEP,
WPA,
WPA2,
}
pub enum NetworkTypeParseError {
FromUtf8Error(FromUtf8Error),
IoError(io::Error),
}
+29
View File
@@ -0,0 +1,29 @@
use connectivity::providers::{Machine};
use connectivity::Network;
use std::io::{Error, ErrorKind};
#[derive(Debug)]
pub struct ProfileNetwork {
handler: Box<Network>,
}
/// Profile Network handler responsible to connect to a wireless network.
impl ProfileNetwork {
pub fn new(name: &str) -> Result<Self, Error> {
if !(cfg!(target_os = "linux") || cfg!(target_os = "windows")) {
return Err(Error::new(
ErrorKind::Other,
"The Specified OS is not supported",
));
}
let handler = Machine::new(name)?;
return Ok(ProfileNetwork {
handler: Box::new(handler),
});
}
pub fn connect(&self, password: &str) -> bool {
self.handler.connect(password)
}
}
+89
View File
@@ -0,0 +1,89 @@
use connectivity::{Network, NetworkType, NetworkTypeParseError};
use std::io;
use std::io::{Error, ErrorKind};
use std::process::{Command, Output};
pub struct Linux {
pub name: String,
pub network_type: NetworkType,
}
impl Linux {
pub fn new(name: String) -> Result<Self, io::Error> {
match Linux::check_if_web_or_wpa(name.clone()) {
Ok(t) => match t {
NetworkType::WEP => Ok(Linux {
name: name.clone(),
network_type: NetworkType::WEP,
}),
_ => Ok(Linux {
name: name.clone(),
network_type: NetworkType::WPA,
}),
},
Err(_) => Err(Error::new(ErrorKind::Other, "Failed to parse")), // use the NetworkTypeParseError::IoError here
}
}
/// Detects the network type of a given network.
fn check_if_web_or_wpa(name: String) -> Result<NetworkType, NetworkTypeParseError> {
Command::new("nmcli")
.args(&[
"con",
"list",
"id",
"\"",
&name,
"\"",
"|",
"awk",
"'/key-mgmt/ {{ print $2 }}'",
])
.output()
.map_err(|err| NetworkTypeParseError::IoError(err))
.and_then(|output| {
String::from_utf8(output.stdout)
.map_err(|err| NetworkTypeParseError::FromUtf8Error(err))
.and_then(|result| match result.as_ref() {
"wpa-psk" => Ok(NetworkType::WPA),
_ => Ok(NetworkType::WEP),
})
})
}
pub fn connect_to_wep_network(&self, password: &str) -> Result<Output, io::Error> {
Command::new("iwconfig")
.args(&["wlan0", "essid", &self.name, "key", password])
.output()
}
pub fn connect_to_wpa_network(&self, password: &str) -> Result<Output, io::Error> {
// Dynamically generate differennt version of file (if running sync)
Command::new("wpa_passphrase")
.args(&[&self.name, password, "wpa.conf"])
.output()?;
Ok(Command::new("wpa_supplicant")
.args(&["-Dwext", "-i", "wlan0", "-c/root/wpa.conf"])
.output()?)
}
}
impl Network for Linux {
fn connect(&self, password: &str) -> bool {
match self.network_type {
NetworkType::WEP => self
.connect_to_wep_network(password)
.map_err(|_err| false)
.unwrap()
.status
.success(),
_ => self
.connect_to_wpa_network(password)
.map_err(|_err| false)
.unwrap()
.status
.success(),
}
}
}
+8
View File
@@ -0,0 +1,8 @@
mod linux;
mod windows;
#[cfg(target_os = "windows")]
pub(crate) use self::windows::Windows as Machine;
#[cfg(target_os = "linux")]
pub(crate) use self::linux::Linux as Machine;
+54
View File
@@ -0,0 +1,54 @@
use connectivity::handlers::NetworkXmlProfileHandler;
use connectivity::Network;
use std::io;
use std::process::Command;
const OUTPUT_XML_FILE_PATH: &str = "output.xml";
#[cfg(target_os = "windows")]
pub(crate) struct Windows {
name: String,
pub output_xml_path: String,
}
impl Windows {
pub fn new(name: &str) -> Result<Self, io::Error> {
let profile_file_name = format!("netsh wlan add profile filename=\"{}\"", name);
Command::new("cmd")
.args(&["/C", &profile_file_name[..]])
.output()?;
Ok(Windows {
name: String::from(name),
output_xml_path: OUTPUT_XML_FILE_PATH.into(),
})
}
}
impl Network for Windows {
fn connect(&self, password: &str) -> bool {
{
let mut handler = NetworkXmlProfileHandler::new();
handler.content = handler
.content
.replace("{SSID}", &self.name)
.replace("{password}", password);
// Write details to new xml file
if let Err(err) = handler.to_file(&self.output_xml_path).map_err(|_err| false) {
return err;
}
}
let output = Command::new("netsh")
.args(&["wlan", "connect", &format!("name = \"{}\"", self.name)])
.output();
match output {
Ok(res) => res.status.success(),
Err(_) => false,
}
}
}
+1
View File
@@ -0,0 +1 @@
pub(crate) mod windows_wifi_profile;
@@ -0,0 +1,35 @@
pub fn get_wifi_profile() -> String {
String::from(
r#"
<?xml version="1.0"?>
<WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
<name>{SSID}</name>
<SSIDConfig>
<SSID>
<name>{SSID}</name>
</SSID>
</SSIDConfig>
<connectionType>ESS</connectionType>
<connectionMode>auto</connectionMode>
<MSM>
<security>
<authEncryption>
<authentication>WPA2PSK</authentication>
<encryption>AES</encryption>
<useOneX>false</useOneX>
</authEncryption>
<sharedKey>
<keyType>passPhrase</keyType>
<protected>false</protected>
<keyMaterial>{password}</keyMaterial>
</sharedKey>
</security>
</MSM>
<MacRandomization
xmlns="http://www.microsoft.com/networking/WLAN/profile/v3">
<enableRandomization>false</enableRandomization>
</MacRandomization>
</WLANProfile>
"#,
)
}
+15
View File
@@ -0,0 +1,15 @@
#![allow(dead_code)]
mod connectivity;
pub use connectivity::profile_network::ProfileNetwork as WiFi;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn connect_to_wifi_failed() {
let wifi = WiFi::new("hello").unwrap();
assert_eq!(wifi.connect("password"), false);
}
}