Chore(Stage): Initial Commit
This commit is contained in:
+11
@@ -0,0 +1,11 @@
|
||||
|
||||
**/target/*
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
*.xml
|
||||
.env
|
||||
rls
|
||||
.vscode
|
||||
.idea
|
||||
**/.DS_Store
|
||||
crossbeam-channel
|
||||
@@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "wifi-rs"
|
||||
version = "0.1.0"
|
||||
authors = ["Tochukwu Nkemdilim <nkemdilimtochukwu@gmail.com>"]
|
||||
|
||||
[dependencies]
|
||||
@@ -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())?)
|
||||
}
|
||||
}
|
||||
@@ -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),
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user