From 2429ea8fdd3fad8c43ed29fa95a08fbdb92012e8 Mon Sep 17 00:00:00 2001 From: glyph Date: Thu, 25 Nov 2021 15:00:19 +0200 Subject: [PATCH 01/13] replace rand with nanorand and bump version --- Cargo.lock | 10 ++++++++-- peach-lib/Cargo.toml | 16 ++++++++-------- peach-lib/src/password_utils.rs | 15 +++++---------- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d7c1a12..6d39d43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2127,6 +2127,12 @@ dependencies = [ "version_check 0.9.3", ] +[[package]] +name = "nanorand" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "729eb334247daa1803e0a094d0a5c55711b85571179f5ec6e53eccfdf7008958" + [[package]] name = "native-tls" version = "0.2.8" @@ -2571,7 +2577,7 @@ dependencies = [ [[package]] name = "peach-lib" -version = "1.3.0" +version = "1.3.1" dependencies = [ "chrono", "env_logger 0.6.2", @@ -2580,7 +2586,7 @@ dependencies = [ "jsonrpc-client-http", "jsonrpc-core 8.0.1", "log 0.4.14", - "rand 0.8.4", + "nanorand", "regex", "rust-crypto", "serde 1.0.130", diff --git a/peach-lib/Cargo.toml b/peach-lib/Cargo.toml index af5aa51..31f8960 100644 --- a/peach-lib/Cargo.toml +++ b/peach-lib/Cargo.toml @@ -1,20 +1,20 @@ [package] name = "peach-lib" -version = "1.3.0" +version = "1.3.1" authors = ["Andrew Reid "] edition = "2018" [dependencies] -log = "0.4" +chrono = "0.4.19" +env_logger = "0.6" +fslock="0.1.6" jsonrpc-client-core = "0.5" jsonrpc-client-http = "0.5" jsonrpc-core = "8.0.1" -serde = { version = "1.0", features = ["derive"] } +log = "0.4" +nanorand = "0.6.1" +regex = "1" rust-crypto = "0.2.36" +serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_yaml = "0.8" -env_logger = "0.6" -regex = "1" -chrono = "0.4.19" -rand="0.8.4" -fslock="0.1.6" diff --git a/peach-lib/src/password_utils.rs b/peach-lib/src/password_utils.rs index 4223ff2..02a9b5c 100644 --- a/peach-lib/src/password_utils.rs +++ b/peach-lib/src/password_utils.rs @@ -1,7 +1,5 @@ -use std::iter; - use crypto::{digest::Digest, sha3::Sha3}; -use rand::{distributions::Alphanumeric, thread_rng, Rng}; +use nanorand::{Rng, WyRand}; use crate::{config_manager, error::PeachError, sbot_client}; @@ -68,13 +66,10 @@ pub fn verify_temporary_password(password: &str) -> Result<(), PeachError> { /// Generates a temporary password and sends it via ssb dm /// to the ssb id configured to be the admin of the peachcloud device pub fn send_password_reset() -> Result<(), PeachError> { - // first generate a new random password of ascii characters - let mut rng = thread_rng(); - let temporary_password: String = iter::repeat(()) - .map(|()| rng.sample(Alphanumeric)) - .map(char::from) - .take(10) - .collect(); + // initialise random number generator + let mut rng = WyRand::new(); + // generate a new password of random numbers + let temporary_password = rng.generate::().to_string(); // save this string as a new temporary password set_new_temporary_password(&temporary_password)?; let domain = config_manager::get_peachcloud_domain()?; From cd8e5737c4f4c9dc9647a6335125c31705e88ad1 Mon Sep 17 00:00:00 2001 From: glyph Date: Tue, 30 Nov 2021 13:48:16 +0200 Subject: [PATCH 02/13] implement custom error type --- Cargo.lock | 1 - peach-network/Cargo.toml | 1 - peach-network/src/error.rs | 349 ++++++++++++++++++++++++----------- peach-network/src/lib.rs | 2 +- peach-network/src/network.rs | 35 ++-- 5 files changed, 269 insertions(+), 119 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6d39d43..abad00b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2638,7 +2638,6 @@ dependencies = [ "regex", "serde 1.0.130", "serde_json", - "snafu 0.6.10", "wpactrl", ] diff --git a/peach-network/Cargo.toml b/peach-network/Cargo.toml index aa81ab9..cc2eead 100644 --- a/peach-network/Cargo.toml +++ b/peach-network/Cargo.toml @@ -36,7 +36,6 @@ log = "0.4" probes = "0.4" serde = { version = "1", features = ["derive"] } serde_json = "1" -snafu = "0.6" regex = "1" wpactrl = "0.3.1" diff --git a/peach-network/src/error.rs b/peach-network/src/error.rs index 808f208..c332b0f 100644 --- a/peach-network/src/error.rs +++ b/peach-network/src/error.rs @@ -1,150 +1,293 @@ use std::{error, io, str}; -use jsonrpc_core::{types::error::Error, ErrorCode}; +use jsonrpc_core::{types::error::Error as JsonRpcError, ErrorCode}; use probes::ProbeError; use serde_json::error::Error as SerdeError; -use snafu::Snafu; -pub type BoxError = Box; - -#[derive(Debug, Snafu)] -#[snafu(visibility(pub(crate)))] +#[derive(Debug)] pub enum NetworkError { - #[snafu(display("{}", err_msg))] - ActivateAp { err_msg: String }, + Add { + ssid: String, + }, - #[snafu(display("{}", err_msg))] - ActivateClient { err_msg: String }, + NoState { + iface: String, + source: io::Error, + }, - #[snafu(display("Failed to add network for {}", ssid))] - Add { ssid: String }, + Disable { + id: String, + iface: String, + }, - #[snafu(display("Failed to retrieve state for interface: {}", iface))] - NoState { iface: String, source: io::Error }, + Disconnect { + iface: String, + }, - #[snafu(display("Failed to disable network {} for interface: {}", id, iface))] - Disable { id: String, iface: String }, + GenWpaPassphrase { + ssid: String, + source: io::Error, + }, - #[snafu(display("Failed to disconnect {}", iface))] - Disconnect { iface: String }, + GenWpaPassphraseWarning { + ssid: String, + err_msg: String, + }, - #[snafu(display("Failed to generate wpa passphrase for {}: {}", ssid, source))] - GenWpaPassphrase { ssid: String, source: io::Error }, + Id { + ssid: String, + iface: String, + }, - #[snafu(display("Failed to generate wpa passphrase for {}: {}", ssid, err_msg))] - GenWpaPassphraseWarning { ssid: String, err_msg: String }, + NoIp { + iface: String, + source: io::Error, + }, - #[snafu(display("No ID found for {} on interface: {}", ssid, iface))] - Id { ssid: String, iface: String }, + Rssi { + iface: String, + }, - #[snafu(display("Could not access IP address for interface: {}", iface))] - NoIp { iface: String, source: io::Error }, + RssiPercent { + iface: String, + }, - #[snafu(display("Could not find RSSI for interface: {}", iface))] - Rssi { iface: String }, + Ssid { + iface: String, + }, - #[snafu(display("Could not find signal quality (%) for interface: {}", iface))] - RssiPercent { iface: String }, + State { + iface: String, + }, - #[snafu(display("Could not find SSID for interface: {}", iface))] - Ssid { iface: String }, + Status { + iface: String, + }, - #[snafu(display("No state found for interface: {}", iface))] - State { iface: String }, + Traffic { + iface: String, + }, - #[snafu(display("No status found for interface: {}", iface))] - Status { iface: String }, - - #[snafu(display("Could not find network traffic for interface: {}", iface))] - Traffic { iface: String }, - - #[snafu(display("No saved networks found for default interface"))] SavedNetworks, - #[snafu(display("No networks found in range of interface: {}", iface))] - AvailableNetworks { iface: String }, + AvailableNetworks { + iface: String, + }, - #[snafu(display("Missing expected parameters: {}", e))] - MissingParams { e: Error }, + MissingParams(JsonRpcError), - #[snafu(display("Failed to set new password for network {} on {}", id, iface))] - Modify { id: String, iface: String }, + Modify { + id: String, + iface: String, + }, - #[snafu(display("No IP found for interface: {}", iface))] - Ip { iface: String }, + Ip { + iface: String, + }, - #[snafu(display("Failed to parse integer from string for RSSI value: {}", source))] - ParseString { source: std::num::ParseIntError }, + ParseString(std::num::ParseIntError), - #[snafu(display( - "Failed to retrieve network traffic measurement for {}: {}", - iface, - source - ))] - NoTraffic { iface: String, source: ProbeError }, + NoTraffic { + iface: String, + source: ProbeError, + }, - #[snafu(display("Failed to reassociate with WiFi network for interface: {}", iface))] - Reassociate { iface: String }, + Reassociate { + iface: String, + }, - #[snafu(display("Failed to force reread of wpa_supplicant configuration file"))] Reconfigure, - #[snafu(display("Failed to reconnect with WiFi network for interface: {}", iface))] - Reconnect { iface: String }, + Reconnect { + iface: String, + }, - #[snafu(display("Regex command failed"))] - Regex { source: regex::Error }, + Regex(regex::Error), - #[snafu(display("Failed to delete network {} for interface: {}", id, iface))] - Delete { id: String, iface: String }, + Delete { + id: String, + iface: String, + }, - #[snafu(display("Failed to retrieve state of wlan0 service: {}", source))] - WlanState { source: io::Error }, + WlanState(io::Error), - #[snafu(display("Failed to retrieve connection state of wlan0 interface: {}", source))] - WlanOperstate { source: io::Error }, + WlanOperstate(io::Error), - #[snafu(display("Failed to save configuration changes to file"))] Save, - #[snafu(display("Failed to connect to network {} for interface: {}", id, iface))] - Connect { id: String, iface: String }, - - #[snafu(display("Failed to start ap0 service: {}", source))] - StartAp0 { source: io::Error }, - - #[snafu(display("Failed to start wlan0 service: {}", source))] - StartWlan0 { source: io::Error }, - - #[snafu(display("JSON serialization failed: {}", source))] - SerdeSerialize { source: SerdeError }, - - #[snafu(display("Failed to open control interface for wpasupplicant"))] - WpaCtrlOpen { - #[snafu(source(from(failure::Error, std::convert::Into::into)))] - source: BoxError, + Connect { + id: String, + iface: String, }, - #[snafu(display("Request to wpasupplicant via wpactrl failed"))] - WpaCtrlRequest { - #[snafu(source(from(failure::Error, std::convert::Into::into)))] - source: BoxError, - }, + StartAp0(io::Error), + + StartWlan0(io::Error), + + SerdeSerialize(SerdeError), + + WpaCtrlOpen(failure::Error), + + WpaCtrlRequest(failure::Error), +} + +impl std::error::Error for NetworkError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match *self { + NetworkError::Add { .. } => None, + NetworkError::NoState { .., ref source } => Some(source), + NetworkError::Disable { .. } => None, + NetworkError::Disconnect { .. } => None, + NetworkError::GenWpaPassphrase { .., ref source } => Some(source), + NetworkError::GenWpaPassphraseWarning { .. } => None, + NetworkError::Id { .. } => None, + NetworkError::NoIp { .., ref source } => Some(source), + NetworkError::Rssi { .. } => None, + NetworkError::RssiPercent { .. } => None, + NetworkError::Ssid { .. } => None, + NetworkError::State { .. } => None, + NetworkError::Status { .. } => None, + NetworkError::Traffic { .. } => None, + NetworkError::SavedNetworks => None, + NetworkError::AvailableNetworks { .. } => None, + NetworkError::MissingParams(ref source) => Some(source), + NetworkError::Modify { .. } => None, + NetworkError::Ip { .. } => None, + NetworkError::ParseString(ref source) => Some(source), + NetworkError::NoTraffic { .., ref source } => Some(source), + NetworkError::Reassociate { .. } => None, + NetworkError::Reconfigure { .. } => None, + NetworkError::Reconnect { .. } => None, + NetworkError::Regex(ref source) => Some(source), + NetworkError::Delete { .. } => None, + NetworkError::WpaState(ref source) => Some(source), + NetworkError::WpaOperstate(ref source) => Some(source), + NetworkError::Save => None, + NetworkError::Connect { .. } => None, + NetworkError::StartWlan0(ref source) => Some(source), + NetworkError::StartAp0(ref source) => Some(source), + NetworkError::SerdeSerialize(ref source) => Some(source), + NetworkError::WpaCtrlOpen(ref source) => Some(source), + NetworkError::WpaCtrlRequest(ref source) => Some(source), + } + } +} + +impl std::fmt::Display for NetworkError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match *self { + NetworkError::Add { ref ssid } => { + write!(f, "Failed to add network for {}", ssid) + }, + NetworkError::NoState { ref iface, .. } => { + write!(f, "Failed to retrieve state for interface: {}", iface) + }, + NetworkError::Disable { ref id, ref iface } => { + write!(f, "Failed to disable network {} for interface: {}", id, iface) + }, + NetworkError::Disconnect { ref iface } => { + write!(f, "Failed to disconnect {}", iface) + }, + NetworkError::GenWpaPassphrase { ref ssid, .. } => { + write!(f, "Failed to generate wpa passphrase for {}", ssid) + }, + NetworkError::GenWpaPassphraseWarning { ref ssid, ref err_msg } => { + write!(f, "Failed to generate wpa passphrase for {}: {}", ssid, err_msg) + }, + NetworkError::Id { ref ssid, ref iface } => { + write!(f, "No ID found for {} on interface: {}: {}", ssid, iface) + }, + NetworkError::NoIp { ref iface, .. } => { + write!(f, "Could not access IP address for interface: {}", iface) + }, + NetworkError::Rssi { ref iface } => { + write!(f, "Could not find RSSI for interface: {}", iface) + }, + NetworkError::RssiPercent { ref iface } => { + write!(f, "Could not find signal quality (%) for interface: {}", iface) + }, + NetworkError::Ssid { ref iface } => { + write!(f, "Could not find SSID for interface: {}", iface) + }, + NetworkError::State { ref iface } => { + write!(f, "No state found for interface: {}", iface) + }, + NetworkError::Status { ref iface } => { + write!(f, "No status found for interface: {}", iface) + }, + NetworkError::Traffic { ref iface } => { + write!(f, "Could not find network traffice for interface: {}", iface) + }, + NetworkError::SavedNetworks => { + write!("No saved networks found for default interface") + }, + NetworkError::AvailableNetworks { ref iface } => { + write!(f, "No networks found in range of interface: {}", iface) + }, + NetworkError::MissingParams(ref source) => { + write!(f, "Missing expected parameters: {}", source) + }, + NetworkError::Modify { ref id, ref iface } => { + write!(f, "Failed to set new password for network {} on {}", id, iface) + }, + NetworkError::Ip { ref iface } => { + write!(f, "No IP found for interface: {}", iface) + }, + NetworkError::ParseString(_) => { + write!("Failed to parse integer from string for RSSI value") + }, + NetworkError::NoTraffic { ref id, .. } => { + write!("Failed to retrieve network traffic measurement for {}", id) + }, + NetworkError::Reassociate { ref iface } => { + write!(f, "Failed to reassociate with WiFi network for interface: {}", iface) + }, + NetworkError::Reconfigure => { + write!("Failed to force reread of wpa_supplicant configuration file") + }, + NetworkError::Reconnect { ref iface } => { + write!(f, "Failed to reconnect with WiFi network for interface: {}", iface) + }, + NetworkError::Regex(_) => { + write!("Regex command failed") + }, + NetworkError::Delete { ref id, ref iface } => { + write!(f, "Failed to delete network {} for interface: {}", id, iface) + }, + NetworkError::WpaState(_) => { + write!("Failed to retrieve state of wlan0 service") + }, + NetworkError::WpaOperstate(_) => { + write!("Failed to retrieve connection state of wlan0 interface") + }, + NetworkError::Save => { + write!("Failed to save configuration changes to file") + }, + NetworkError::Connect { ref id, ref iface } => { + write!(f, "Failed to connect to network {} for interface: {}", id, iface) + }, + NetworkError::StartWlan0(_) => { + write!("Failed to start ap0 service") + }, + NetworkError::StartAp0(_) => { + write!("Failed to start wlan0 service") + }, + NetworkError::SerdeSerialize(_) => { + write!("JSON serialization failed") + }, + NetworkError::WpaCtrlOpen(_) => { + write!("Failed to open control interface for wpasupplicant") + }, + NetworkError::WpaCtrlRequest(_) => { + write!("Request to wpasupplicant via wpactrl failed") + }, + } + } } impl From for Error { fn from(err: NetworkError) -> Self { match &err { - NetworkError::ActivateAp { err_msg } => Error { - code: ErrorCode::ServerError(-32015), - message: err_msg.to_string(), - data: None, - }, - NetworkError::ActivateClient { err_msg } => Error { - code: ErrorCode::ServerError(-32017), - message: err_msg.to_string(), - data: None, - }, NetworkError::Add { ssid } => Error { code: ErrorCode::ServerError(-32000), message: format!("Failed to add network for {}", ssid), @@ -243,7 +386,7 @@ impl From for Error { message: format!("No networks found in range of {}", iface), data: None, }, - NetworkError::MissingParams { e } => e.clone(), + NetworkError::MissingParams(e) => e.clone(), NetworkError::Modify { id, iface } => Error { code: ErrorCode::ServerError(-32033), message: format!("Failed to set new password for network {} on {}", id, iface), diff --git a/peach-network/src/lib.rs b/peach-network/src/lib.rs index 2872b27..88155f0 100644 --- a/peach-network/src/lib.rs +++ b/peach-network/src/lib.rs @@ -317,7 +317,7 @@ pub fn run() -> Result<(), BoxError> { Err(_) => Err(Error::from(NetworkError::Connect { id, iface })), } } - Err(e) => Err(Error::from(NetworkError::MissingParams { e })), + Err(e) => Err(Error::from(NetworkError::MissingParams(e))), } }); diff --git a/peach-network/src/network.rs b/peach-network/src/network.rs index e52c1b2..6373a3b 100644 --- a/peach-network/src/network.rs +++ b/peach-network/src/network.rs @@ -21,13 +21,9 @@ use std::{ str, }; -use crate::error::{ - GenWpaPassphrase, NetworkError, NoIp, NoState, NoTraffic, ParseString, SerdeSerialize, - StartAp0, StartWlan0, WlanState, WpaCtrlOpen, WpaCtrlRequest, -}; +use crate::error::NetworkError; use probes::network; use serde::{Deserialize, Serialize}; -use snafu::ResultExt; use crate::utils; @@ -122,6 +118,14 @@ pub struct WiFi { pub pass: String, } +// TODO: wrap this into a helper function: +// +// let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); +// let mut wpa = wpactrl::WpaCtrl::new() +// .ctrl_path(wpa_path) +// .open() +// .map_err(|source| NetworkError::WpaCtrlOpen(source.compat()))?; + /* GET - Methods for retrieving data */ /// Retrieve list of available wireless access points for a given network @@ -145,8 +149,9 @@ pub fn available_networks(iface: &str) -> Result, NetworkError> { let mut wpa = wpactrl::WpaCtrl::new() .ctrl_path(wpa_path) .open() - .context(WpaCtrlOpen)?; - wpa.request("SCAN").context(WpaCtrlRequest)?; + .map_err(|source| NetworkError::WpaCtrlOpen(source.compat()))?; + wpa.request("SCAN") + .map_err(|source| NetworkError::WpaCtrlRequest(source.compat()))?; let networks = wpa.request("SCAN_RESULTS").context(WpaCtrlRequest)?; let mut scan = Vec::new(); for network in networks.lines() { @@ -204,8 +209,10 @@ pub fn id(iface: &str, ssid: &str) -> Result, NetworkError> { let mut wpa = wpactrl::WpaCtrl::new() .ctrl_path(wpa_path) .open() - .context(WpaCtrlOpen)?; - let networks = wpa.request("LIST_NETWORKS").context(WpaCtrlRequest)?; + .map_err(|source| NetworkError::WpaCtrlOpen(source.compat()))?; + let networks = wpa + .request("LIST_NETWORKS") + .map_err(|source| NetworkError::WpaCtrlRequest(source.compat()))?; let mut id = Vec::new(); for network in networks.lines() { let v: Vec<&str> = network.split('\t').collect(); @@ -239,7 +246,7 @@ pub fn id(iface: &str, ssid: &str) -> Result, NetworkError> { /// pub fn ip(iface: &str) -> Result, NetworkError> { let net_if: String = iface.to_string(); - let ifaces = get_if_addrs::get_if_addrs().context(NoIp { iface: net_if })?; + let ifaces = get_if_addrs::get_if_addrs().map_err(|_| NetworkError::NoIp { iface: net_if })?; let ip = ifaces .iter() .find(|&i| i.name == iface) @@ -268,7 +275,7 @@ pub fn rssi(iface: &str) -> Result, NetworkError> { let mut wpa = wpactrl::WpaCtrl::new() .ctrl_path(wpa_path) .open() - .context(WpaCtrlOpen)?; + .map_err(|source| NetworkError::WpaCtrlOpen(source.compat()))?; let status = wpa.request("SIGNAL_POLL").context(WpaCtrlRequest)?; let rssi = utils::regex_finder(r"RSSI=(.*)\n", &status)?; @@ -300,7 +307,7 @@ pub fn rssi_percent(iface: &str) -> Result, NetworkError> { let mut wpa = wpactrl::WpaCtrl::new() .ctrl_path(wpa_path) .open() - .context(WpaCtrlOpen)?; + .map_err(|source| NetworkError::WpaCtrlOpen(source.compat()))?; let status = wpa.request("SIGNAL_POLL").context(WpaCtrlRequest)?; let rssi = utils::regex_finder(r"RSSI=(.*)\n", &status)?; @@ -335,7 +342,9 @@ pub fn rssi_percent(iface: &str) -> Result, NetworkError> { /// sent to the caller. /// pub fn saved_networks() -> Result, NetworkError> { - let mut wpa = wpactrl::WpaCtrl::new().open().context(WpaCtrlOpen)?; + let mut wpa = wpactrl::WpaCtrl::new() + .open() + .map_err(|source| NetworkError::WpaCtrlOpen(source.compat()))?; let networks = wpa.request("LIST_NETWORKS").context(WpaCtrlRequest)?; let mut ssids = Vec::new(); for network in networks.lines() { From 79c94e6af0426c5bfaaed25747751cce375c2066 Mon Sep 17 00:00:00 2001 From: glyph Date: Wed, 1 Dec 2021 14:26:30 +0200 Subject: [PATCH 03/13] replace snafu with custom error type --- peach-network/src/error.rs | 439 +++++++++++++++++------------------ peach-network/src/lib.rs | 40 ++-- peach-network/src/network.rs | 151 +++++------- peach-network/src/utils.rs | 5 +- 4 files changed, 297 insertions(+), 338 deletions(-) diff --git a/peach-network/src/error.rs b/peach-network/src/error.rs index c332b0f..ebb4423 100644 --- a/peach-network/src/error.rs +++ b/peach-network/src/error.rs @@ -1,147 +1,95 @@ -use std::{error, io, str}; +use std::io; +use std::num::ParseIntError; +use io::Error as IoError; use jsonrpc_core::{types::error::Error as JsonRpcError, ErrorCode}; use probes::ProbeError; -use serde_json::error::Error as SerdeError; +use regex::Error as RegexError; +use serde_json::Error as SerdeError; +use wpactrl::WpaError; #[derive(Debug)] pub enum NetworkError { - Add { - ssid: String, - }, + Add { ssid: String }, - NoState { - iface: String, - source: io::Error, - }, + NoState { iface: String, source: IoError }, - Disable { - id: String, - iface: String, - }, + Disable { id: String, iface: String }, - Disconnect { - iface: String, - }, + Disconnect { iface: String }, - GenWpaPassphrase { - ssid: String, - source: io::Error, - }, + GenWpaPassphrase { ssid: String, source: IoError }, - GenWpaPassphraseWarning { - ssid: String, - err_msg: String, - }, + GenWpaPassphraseWarning { ssid: String, err_msg: String }, - Id { - ssid: String, - iface: String, - }, + Id { ssid: String, iface: String }, - NoIp { - iface: String, - source: io::Error, - }, + NoIp { iface: String, source: IoError }, - Rssi { - iface: String, - }, + Rssi { iface: String }, - RssiPercent { - iface: String, - }, + RssiPercent { iface: String }, - Ssid { - iface: String, - }, + Ssid { iface: String }, - State { - iface: String, - }, + State { iface: String }, - Status { - iface: String, - }, + Status { iface: String }, - Traffic { - iface: String, - }, + Traffic { iface: String }, SavedNetworks, - AvailableNetworks { - iface: String, - }, + AvailableNetworks { iface: String }, MissingParams(JsonRpcError), - Modify { - id: String, - iface: String, - }, + Modify { id: String, iface: String }, - Ip { - iface: String, - }, + Ip { iface: String }, - ParseString(std::num::ParseIntError), + ParseInt(ParseIntError), - NoTraffic { - iface: String, - source: ProbeError, - }, + NoTraffic { iface: String, source: ProbeError }, - Reassociate { - iface: String, - }, + Reassociate { iface: String }, Reconfigure, - Reconnect { - iface: String, - }, + Reconnect { iface: String }, - Regex(regex::Error), + Regex(RegexError), - Delete { - id: String, - iface: String, - }, + Delete { id: String, iface: String }, - WlanState(io::Error), + WlanState(IoError), - WlanOperstate(io::Error), + WlanOperstate(IoError), Save, - Connect { - id: String, - iface: String, - }, + Connect { id: String, iface: String }, - StartAp0(io::Error), + StartAp0(IoError), - StartWlan0(io::Error), + StartWlan0(IoError), SerdeSerialize(SerdeError), - WpaCtrlOpen(failure::Error), - - WpaCtrlRequest(failure::Error), + WpaCtrl(WpaError), } impl std::error::Error for NetworkError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match *self { NetworkError::Add { .. } => None, - NetworkError::NoState { .., ref source } => Some(source), + NetworkError::NoState { ref source, .. } => Some(source), NetworkError::Disable { .. } => None, NetworkError::Disconnect { .. } => None, - NetworkError::GenWpaPassphrase { .., ref source } => Some(source), + NetworkError::GenWpaPassphrase { ref source, .. } => Some(source), NetworkError::GenWpaPassphraseWarning { .. } => None, NetworkError::Id { .. } => None, - NetworkError::NoIp { .., ref source } => Some(source), + NetworkError::NoIp { ref source, .. } => Some(source), NetworkError::Rssi { .. } => None, NetworkError::RssiPercent { .. } => None, NetworkError::Ssid { .. } => None, @@ -153,22 +101,21 @@ impl std::error::Error for NetworkError { NetworkError::MissingParams(ref source) => Some(source), NetworkError::Modify { .. } => None, NetworkError::Ip { .. } => None, - NetworkError::ParseString(ref source) => Some(source), - NetworkError::NoTraffic { .., ref source } => Some(source), + NetworkError::ParseInt(ref source) => Some(source), + NetworkError::NoTraffic { ref source, .. } => Some(source), NetworkError::Reassociate { .. } => None, NetworkError::Reconfigure { .. } => None, NetworkError::Reconnect { .. } => None, NetworkError::Regex(ref source) => Some(source), NetworkError::Delete { .. } => None, - NetworkError::WpaState(ref source) => Some(source), - NetworkError::WpaOperstate(ref source) => Some(source), + NetworkError::WlanState(ref source) => Some(source), + NetworkError::WlanOperstate(ref source) => Some(source), NetworkError::Save => None, NetworkError::Connect { .. } => None, NetworkError::StartWlan0(ref source) => Some(source), NetworkError::StartAp0(ref source) => Some(source), NetworkError::SerdeSerialize(ref source) => Some(source), - NetworkError::WpaCtrlOpen(ref source) => Some(source), - NetworkError::WpaCtrlRequest(ref source) => Some(source), + NetworkError::WpaCtrl(ref source) => Some(source), } } } @@ -178,122 +125,178 @@ impl std::fmt::Display for NetworkError { match *self { NetworkError::Add { ref ssid } => { write!(f, "Failed to add network for {}", ssid) - }, + } NetworkError::NoState { ref iface, .. } => { write!(f, "Failed to retrieve state for interface: {}", iface) - }, + } NetworkError::Disable { ref id, ref iface } => { - write!(f, "Failed to disable network {} for interface: {}", id, iface) - }, + write!( + f, + "Failed to disable network {} for interface: {}", + id, iface + ) + } NetworkError::Disconnect { ref iface } => { write!(f, "Failed to disconnect {}", iface) - }, + } NetworkError::GenWpaPassphrase { ref ssid, .. } => { write!(f, "Failed to generate wpa passphrase for {}", ssid) - }, - NetworkError::GenWpaPassphraseWarning { ref ssid, ref err_msg } => { - write!(f, "Failed to generate wpa passphrase for {}: {}", ssid, err_msg) - }, - NetworkError::Id { ref ssid, ref iface } => { - write!(f, "No ID found for {} on interface: {}: {}", ssid, iface) - }, + } + NetworkError::GenWpaPassphraseWarning { + ref ssid, + ref err_msg, + } => { + write!( + f, + "Failed to generate wpa passphrase for {}: {}", + ssid, err_msg + ) + } + NetworkError::Id { + ref ssid, + ref iface, + } => { + write!(f, "No ID found for {} on interface: {}", ssid, iface) + } NetworkError::NoIp { ref iface, .. } => { write!(f, "Could not access IP address for interface: {}", iface) - }, + } NetworkError::Rssi { ref iface } => { write!(f, "Could not find RSSI for interface: {}", iface) - }, + } NetworkError::RssiPercent { ref iface } => { - write!(f, "Could not find signal quality (%) for interface: {}", iface) - }, - NetworkError::Ssid { ref iface } => { + write!( + f, + "Could not find signal quality (%) for interface: {}", + iface + ) + } + NetworkError::Ssid { ref iface } => { write!(f, "Could not find SSID for interface: {}", iface) - }, + } NetworkError::State { ref iface } => { write!(f, "No state found for interface: {}", iface) - }, + } NetworkError::Status { ref iface } => { write!(f, "No status found for interface: {}", iface) - }, - NetworkError::Traffic { ref iface } => { - write!(f, "Could not find network traffice for interface: {}", iface) - }, - NetworkError::SavedNetworks => { - write!("No saved networks found for default interface") - }, - NetworkError::AvailableNetworks { ref iface } => { + } + NetworkError::Traffic { ref iface } => { + write!( + f, + "Could not find network traffice for interface: {}", + iface + ) + } + NetworkError::SavedNetworks => { + write!(f, "No saved networks found for default interface") + } + NetworkError::AvailableNetworks { ref iface } => { write!(f, "No networks found in range of interface: {}", iface) - }, - NetworkError::MissingParams(ref source) => { + } + NetworkError::MissingParams(ref source) => { write!(f, "Missing expected parameters: {}", source) - }, - NetworkError::Modify { ref id, ref iface } => { - write!(f, "Failed to set new password for network {} on {}", id, iface) - }, - NetworkError::Ip { ref iface } => { + } + NetworkError::Modify { ref id, ref iface } => { + write!( + f, + "Failed to set new password for network {} on {}", + id, iface + ) + } + NetworkError::Ip { ref iface } => { write!(f, "No IP found for interface: {}", iface) - }, - NetworkError::ParseString(_) => { - write!("Failed to parse integer from string for RSSI value") - }, - NetworkError::NoTraffic { ref id, .. } => { - write!("Failed to retrieve network traffic measurement for {}", id) - }, - NetworkError::Reassociate { ref iface } => { - write!(f, "Failed to reassociate with WiFi network for interface: {}", iface) - }, - NetworkError::Reconfigure => { - write!("Failed to force reread of wpa_supplicant configuration file") - }, - NetworkError::Reconnect { ref iface } => { - write!(f, "Failed to reconnect with WiFi network for interface: {}", iface) - }, - NetworkError::Regex(_) => { - write!("Regex command failed") - }, - NetworkError::Delete { ref id, ref iface } => { - write!(f, "Failed to delete network {} for interface: {}", id, iface) - }, - NetworkError::WpaState(_) => { - write!("Failed to retrieve state of wlan0 service") - }, - NetworkError::WpaOperstate(_) => { - write!("Failed to retrieve connection state of wlan0 interface") - }, - NetworkError::Save => { - write!("Failed to save configuration changes to file") - }, - NetworkError::Connect { ref id, ref iface } => { - write!(f, "Failed to connect to network {} for interface: {}", id, iface) - }, - NetworkError::StartWlan0(_) => { - write!("Failed to start ap0 service") - }, - NetworkError::StartAp0(_) => { - write!("Failed to start wlan0 service") - }, - NetworkError::SerdeSerialize(_) => { - write!("JSON serialization failed") - }, - NetworkError::WpaCtrlOpen(_) => { - write!("Failed to open control interface for wpasupplicant") - }, - NetworkError::WpaCtrlRequest(_) => { - write!("Request to wpasupplicant via wpactrl failed") - }, + } + NetworkError::ParseInt(_) => { + write!(f, "Failed to parse integer from string for RSSI value") + } + NetworkError::NoTraffic { ref iface, .. } => { + write!( + f, + "Failed to retrieve network traffic measurement for {}", + iface + ) + } + NetworkError::Reassociate { ref iface } => { + write!( + f, + "Failed to reassociate with WiFi network for interface: {}", + iface + ) + } + NetworkError::Reconfigure => { + write!( + f, + "Failed to force reread of wpa_supplicant configuration file" + ) + } + NetworkError::Reconnect { ref iface } => { + write!( + f, + "Failed to reconnect with WiFi network for interface: {}", + iface + ) + } + NetworkError::Regex(_) => write!(f, "Regex command failed"), + NetworkError::Delete { ref id, ref iface } => { + write!( + f, + "Failed to delete network {} for interface: {}", + id, iface + ) + } + NetworkError::WlanState(_) => write!(f, "Failed to retrieve state of wlan0 service"), + NetworkError::WlanOperstate(_) => { + write!(f, "Failed to retrieve connection state of wlan0 interface") + } + NetworkError::Save => write!(f, "Failed to save configuration changes to file"), + NetworkError::Connect { ref id, ref iface } => { + write!( + f, + "Failed to connect to network {} for interface: {}", + id, iface + ) + } + NetworkError::StartWlan0(_) => write!(f, "Failed to start ap0 service"), + NetworkError::StartAp0(_) => write!(f, "Failed to start wlan0 service"), + NetworkError::SerdeSerialize(_) => write!(f, "JSON serialization failed"), + NetworkError::WpaCtrl(_) => write!(f, "WpaCtrl command failed"), } } } -impl From for Error { +impl From for NetworkError { + fn from(err: SerdeError) -> Self { + NetworkError::SerdeSerialize(err) + } +} + +impl From for NetworkError { + fn from(err: WpaError) -> Self { + NetworkError::WpaCtrl(err) + } +} + +impl From for NetworkError { + fn from(err: ParseIntError) -> Self { + NetworkError::ParseInt(err) + } +} + +impl From for NetworkError { + fn from(err: RegexError) -> Self { + NetworkError::Regex(err) + } +} + +impl From for JsonRpcError { fn from(err: NetworkError) -> Self { match &err { - NetworkError::Add { ssid } => Error { + NetworkError::Add { ssid } => JsonRpcError { code: ErrorCode::ServerError(-32000), message: format!("Failed to add network for {}", ssid), data: None, }, - NetworkError::NoState { iface, source } => Error { + NetworkError::NoState { iface, source } => JsonRpcError { code: ErrorCode::ServerError(-32022), message: format!( "Failed to retrieve interface state for {}: {}", @@ -301,22 +304,22 @@ impl From for Error { ), data: None, }, - NetworkError::Disable { id, iface } => Error { + NetworkError::Disable { id, iface } => JsonRpcError { code: ErrorCode::ServerError(-32029), message: format!("Failed to disable network {} for {}", id, iface), data: None, }, - NetworkError::Disconnect { iface } => Error { + NetworkError::Disconnect { iface } => JsonRpcError { code: ErrorCode::ServerError(-32032), message: format!("Failed to disconnect {}", iface), data: None, }, - NetworkError::GenWpaPassphrase { ssid, source } => Error { + NetworkError::GenWpaPassphrase { ssid, source } => JsonRpcError { code: ErrorCode::ServerError(-32025), message: format!("Failed to generate wpa passphrase for {}: {}", ssid, source), data: None, }, - NetworkError::GenWpaPassphraseWarning { ssid, err_msg } => Error { + NetworkError::GenWpaPassphraseWarning { ssid, err_msg } => JsonRpcError { code: ErrorCode::ServerError(-32036), message: format!( "Failed to generate wpa passphrase for {}: {}", @@ -324,17 +327,17 @@ impl From for Error { ), data: None, }, - NetworkError::Id { iface, ssid } => Error { + NetworkError::Id { iface, ssid } => JsonRpcError { code: ErrorCode::ServerError(-32026), message: format!("No ID found for {} on interface {}", ssid, iface), data: None, }, - NetworkError::NoIp { iface, source } => Error { + NetworkError::NoIp { iface, source } => JsonRpcError { code: ErrorCode::ServerError(-32001), message: format!("Failed to retrieve IP address for {}: {}", iface, source), data: None, }, - NetworkError::Rssi { iface } => Error { + NetworkError::Rssi { iface } => JsonRpcError { code: ErrorCode::ServerError(-32002), message: format!( "Failed to retrieve RSSI for {}. Interface may not be connected", @@ -342,7 +345,7 @@ impl From for Error { ), data: None, }, - NetworkError::RssiPercent { iface } => Error { + NetworkError::RssiPercent { iface } => JsonRpcError { code: ErrorCode::ServerError(-32034), message: format!( "Failed to retrieve signal quality (%) for {}. Interface may not be connected", @@ -350,7 +353,7 @@ impl From for Error { ), data: None, }, - NetworkError::Ssid { iface } => Error { + NetworkError::Ssid { iface } => JsonRpcError { code: ErrorCode::ServerError(-32003), message: format!( "Failed to retrieve SSID for {}. Interface may not be connected", @@ -358,17 +361,17 @@ impl From for Error { ), data: None, }, - NetworkError::State { iface } => Error { + NetworkError::State { iface } => JsonRpcError { code: ErrorCode::ServerError(-32023), message: format!("No state found for {}. Interface may not exist", iface), data: None, }, - NetworkError::Status { iface } => Error { + NetworkError::Status { iface } => JsonRpcError { code: ErrorCode::ServerError(-32024), message: format!("No status found for {}. Interface may not exist", iface), data: None, }, - NetworkError::Traffic { iface } => Error { + NetworkError::Traffic { iface } => JsonRpcError { code: ErrorCode::ServerError(-32004), message: format!( "No network traffic statistics found for {}. Interface may not exist", @@ -376,28 +379,28 @@ impl From for Error { ), data: None, }, - NetworkError::SavedNetworks => Error { + NetworkError::SavedNetworks => JsonRpcError { code: ErrorCode::ServerError(-32005), message: "No saved networks found".to_string(), data: None, }, - NetworkError::AvailableNetworks { iface } => Error { + NetworkError::AvailableNetworks { iface } => JsonRpcError { code: ErrorCode::ServerError(-32006), message: format!("No networks found in range of {}", iface), data: None, }, NetworkError::MissingParams(e) => e.clone(), - NetworkError::Modify { id, iface } => Error { + NetworkError::Modify { id, iface } => JsonRpcError { code: ErrorCode::ServerError(-32033), message: format!("Failed to set new password for network {} on {}", id, iface), data: None, }, - NetworkError::Ip { iface } => Error { + NetworkError::Ip { iface } => JsonRpcError { code: ErrorCode::ServerError(-32007), message: format!("No IP address found for {}", iface), data: None, }, - NetworkError::ParseString { source } => Error { + NetworkError::ParseInt(source) => JsonRpcError { code: ErrorCode::ServerError(-32035), message: format!( "Failed to parse integer from string for RSSI value: {}", @@ -405,7 +408,7 @@ impl From for Error { ), data: None, }, - NetworkError::NoTraffic { iface, source } => Error { + NetworkError::NoTraffic { iface, source } => JsonRpcError { code: ErrorCode::ServerError(-32015), message: format!( "Failed to retrieve network traffic statistics for {}: {}", @@ -413,37 +416,37 @@ impl From for Error { ), data: None, }, - NetworkError::Reassociate { iface } => Error { + NetworkError::Reassociate { iface } => JsonRpcError { code: ErrorCode::ServerError(-32008), message: format!("Failed to reassociate with WiFi network for {}", iface), data: None, }, - NetworkError::Reconfigure => Error { + NetworkError::Reconfigure => JsonRpcError { code: ErrorCode::ServerError(-32030), message: "Failed to force reread of wpa_supplicant configuration file".to_string(), data: None, }, - NetworkError::Reconnect { iface } => Error { + NetworkError::Reconnect { iface } => JsonRpcError { code: ErrorCode::ServerError(-32009), message: format!("Failed to reconnect with WiFi network for {}", iface), data: None, }, - NetworkError::Regex { source } => Error { + NetworkError::Regex(source) => JsonRpcError { code: ErrorCode::ServerError(-32010), message: format!("Regex command error: {}", source), data: None, }, - NetworkError::Delete { id, iface } => Error { + NetworkError::Delete { id, iface } => JsonRpcError { code: ErrorCode::ServerError(-32028), message: format!("Failed to delete network {} for {}", id, iface), data: None, }, - NetworkError::WlanState { source } => Error { + NetworkError::WlanState(source) => JsonRpcError { code: ErrorCode::ServerError(-32011), message: format!("Failed to retrieve state of wlan0 service: {}", source), data: None, }, - NetworkError::WlanOperstate { source } => Error { + NetworkError::WlanOperstate(source) => JsonRpcError { code: ErrorCode::ServerError(-32021), message: format!( "Failed to retrieve connection state of wlan0 interface: {}", @@ -451,42 +454,34 @@ impl From for Error { ), data: None, }, - NetworkError::Save => Error { + NetworkError::Save => JsonRpcError { code: ErrorCode::ServerError(-32031), message: "Failed to save configuration changes to file".to_string(), data: None, }, - NetworkError::Connect { id, iface } => Error { + NetworkError::Connect { id, iface } => JsonRpcError { code: ErrorCode::ServerError(-32027), message: format!("Failed to connect to network {} for {}", id, iface), data: None, }, - NetworkError::StartAp0 { source } => Error { + NetworkError::StartAp0(source) => JsonRpcError { code: ErrorCode::ServerError(-32016), message: format!("Failed to start ap0 service: {}", source), data: None, }, - NetworkError::StartWlan0 { source } => Error { + NetworkError::StartWlan0(source) => JsonRpcError { code: ErrorCode::ServerError(-32018), message: format!("Failed to start wlan0 service: {}", source), data: None, }, - NetworkError::SerdeSerialize { source } => Error { + NetworkError::SerdeSerialize(source) => JsonRpcError { code: ErrorCode::ServerError(-32012), message: format!("JSON serialization failed: {}", source), data: None, }, - NetworkError::WpaCtrlOpen { source } => Error { + NetworkError::WpaCtrl(source) => JsonRpcError { code: ErrorCode::ServerError(-32013), - message: format!( - "Failed to open control interface for wpasupplicant: {}", - source - ), - data: None, - }, - NetworkError::WpaCtrlRequest { source } => Error { - code: ErrorCode::ServerError(-32014), - message: format!("WPA supplicant request failed: {}", source), + message: format!("WPA control interface failure: {}", source), data: None, }, } diff --git a/peach-network/src/lib.rs b/peach-network/src/lib.rs index 88155f0..c4d0d3b 100644 --- a/peach-network/src/lib.rs +++ b/peach-network/src/lib.rs @@ -25,11 +25,11 @@ use jsonrpc_http_server::{AccessControlAllowOrigin, DomainsValidation, ServerBui use log::info; use serde_json::json; -use crate::error::{BoxError, NetworkError}; +use crate::error::NetworkError; use crate::network::{Iface, IfaceId, IfaceIdPass, IfaceSsid, WiFi}; /// Create JSON-RPC I/O handler, add RPC methods and launch HTTP server. -pub fn run() -> Result<(), BoxError> { +pub fn run() -> Result<(), NetworkError> { info!("Starting up."); info!("Creating JSON-RPC I/O handler."); @@ -47,7 +47,7 @@ pub fn run() -> Result<(), BoxError> { None => Err(Error::from(NetworkError::AvailableNetworks { iface })), } } - Err(e) => Err(Error::from(NetworkError::MissingParams { e })), + Err(e) => Err(Error::from(NetworkError::MissingParams(e))), } }); @@ -62,7 +62,7 @@ pub fn run() -> Result<(), BoxError> { None => Err(Error::from(NetworkError::Id { iface, ssid })), } } - Err(e) => Err(Error::from(NetworkError::MissingParams { e })), + Err(e) => Err(Error::from(NetworkError::MissingParams(e))), } }); @@ -76,7 +76,7 @@ pub fn run() -> Result<(), BoxError> { None => Err(Error::from(NetworkError::Ip { iface })), } } - Err(e) => Err(Error::from(NetworkError::MissingParams { e })), + Err(e) => Err(Error::from(NetworkError::MissingParams(e))), } }); @@ -92,7 +92,7 @@ pub fn run() -> Result<(), BoxError> { None => Err(Error::from(NetworkError::Rssi { iface })), } } - Err(e) => Err(Error::from(NetworkError::MissingParams { e })), + Err(e) => Err(Error::from(NetworkError::MissingParams(e))), } }); @@ -106,7 +106,7 @@ pub fn run() -> Result<(), BoxError> { None => Err(Error::from(NetworkError::RssiPercent { iface })), } } - Err(e) => Err(Error::from(NetworkError::MissingParams { e })), + Err(e) => Err(Error::from(NetworkError::MissingParams(e))), } }); @@ -128,7 +128,7 @@ pub fn run() -> Result<(), BoxError> { None => Err(Error::from(NetworkError::Ssid { iface })), } } - Err(e) => Err(Error::from(NetworkError::MissingParams { e })), + Err(e) => Err(Error::from(NetworkError::MissingParams(e))), } }); @@ -142,7 +142,7 @@ pub fn run() -> Result<(), BoxError> { None => Err(Error::from(NetworkError::State { iface })), } } - Err(e) => Err(Error::from(NetworkError::MissingParams { e })), + Err(e) => Err(Error::from(NetworkError::MissingParams(e))), } }); @@ -159,7 +159,7 @@ pub fn run() -> Result<(), BoxError> { None => Err(Error::from(NetworkError::Status { iface })), } } - Err(e) => Err(Error::from(NetworkError::MissingParams { e })), + Err(e) => Err(Error::from(NetworkError::MissingParams(e))), } }); @@ -173,7 +173,7 @@ pub fn run() -> Result<(), BoxError> { None => Err(Error::from(NetworkError::Traffic { iface })), } } - Err(e) => Err(Error::from(NetworkError::MissingParams { e })), + Err(e) => Err(Error::from(NetworkError::MissingParams(e))), } }); @@ -198,7 +198,7 @@ pub fn run() -> Result<(), BoxError> { Ok(_) => Ok(Value::String("success".to_string())), Err(e) => Err(Error::from(e)), }, - Err(e) => Err(Error::from(NetworkError::MissingParams { e })), + Err(e) => Err(Error::from(NetworkError::MissingParams(e))), } }); @@ -219,7 +219,7 @@ pub fn run() -> Result<(), BoxError> { Err(_) => Err(Error::from(NetworkError::Delete { id, iface })), } } - Err(e) => Err(Error::from(NetworkError::MissingParams { e })), + Err(e) => Err(Error::from(NetworkError::MissingParams(e))), } }); @@ -234,7 +234,7 @@ pub fn run() -> Result<(), BoxError> { Err(_) => Err(Error::from(NetworkError::Disable { id, iface })), } } - Err(e) => Err(Error::from(NetworkError::MissingParams { e })), + Err(e) => Err(Error::from(NetworkError::MissingParams(e))), } }); @@ -248,7 +248,7 @@ pub fn run() -> Result<(), BoxError> { Err(_) => Err(Error::from(NetworkError::Disconnect { iface })), } } - Err(e) => Err(Error::from(NetworkError::MissingParams { e })), + Err(e) => Err(Error::from(NetworkError::MissingParams(e))), } }); @@ -264,7 +264,7 @@ pub fn run() -> Result<(), BoxError> { Err(_) => Err(Error::from(NetworkError::Modify { iface, id })), } } - Err(e) => Err(Error::from(NetworkError::MissingParams { e })), + Err(e) => Err(Error::from(NetworkError::MissingParams(e))), } }); @@ -278,7 +278,7 @@ pub fn run() -> Result<(), BoxError> { Err(_) => Err(Error::from(NetworkError::Reassociate { iface })), } } - Err(e) => Err(Error::from(NetworkError::MissingParams { e })), + Err(e) => Err(Error::from(NetworkError::MissingParams(e))), } }); @@ -297,7 +297,7 @@ pub fn run() -> Result<(), BoxError> { Err(_) => Err(Error::from(NetworkError::Reconnect { iface })), } } - Err(e) => Err(Error::from(NetworkError::MissingParams { e })), + Err(e) => Err(Error::from(NetworkError::MissingParams(e))), } }); @@ -374,7 +374,7 @@ mod tests { message: String::from("Parse error"), data: None, }; - Err(Error::from(NetworkError::MissingParams { e })) + Err(Error::from(NetworkError::MissingParams(e))) }); test_rpc::Rpc::from(io) }; @@ -689,7 +689,7 @@ mod tests { ), data: None, }; - Err(Error::from(NetworkError::MissingParams { e })) + Err(Error::from(NetworkError::MissingParams(e))) }); test_rpc::Rpc::from(io) }; diff --git a/peach-network/src/network.rs b/peach-network/src/network.rs index 6373a3b..e579729 100644 --- a/peach-network/src/network.rs +++ b/peach-network/src/network.rs @@ -121,10 +121,7 @@ pub struct WiFi { // TODO: wrap this into a helper function: // // let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); -// let mut wpa = wpactrl::WpaCtrl::new() -// .ctrl_path(wpa_path) -// .open() -// .map_err(|source| NetworkError::WpaCtrlOpen(source.compat()))?; +// let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; /* GET - Methods for retrieving data */ @@ -146,13 +143,9 @@ pub struct WiFi { /// pub fn available_networks(iface: &str) -> Result, NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); - let mut wpa = wpactrl::WpaCtrl::new() - .ctrl_path(wpa_path) - .open() - .map_err(|source| NetworkError::WpaCtrlOpen(source.compat()))?; - wpa.request("SCAN") - .map_err(|source| NetworkError::WpaCtrlRequest(source.compat()))?; - let networks = wpa.request("SCAN_RESULTS").context(WpaCtrlRequest)?; + let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; + wpa.request("SCAN")?; + let networks = wpa.request("SCAN_RESULTS")?; let mut scan = Vec::new(); for network in networks.lines() { let v: Vec<&str> = network.split('\t').collect(); @@ -183,7 +176,7 @@ pub fn available_networks(iface: &str) -> Result, NetworkError> { if scan.is_empty() { Ok(None) } else { - let results = serde_json::to_string(&scan).context(SerdeSerialize)?; + let results = serde_json::to_string(&scan)?; Ok(Some(results)) } } @@ -206,13 +199,8 @@ pub fn available_networks(iface: &str) -> Result, NetworkError> { /// pub fn id(iface: &str, ssid: &str) -> Result, NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); - let mut wpa = wpactrl::WpaCtrl::new() - .ctrl_path(wpa_path) - .open() - .map_err(|source| NetworkError::WpaCtrlOpen(source.compat()))?; - let networks = wpa - .request("LIST_NETWORKS") - .map_err(|source| NetworkError::WpaCtrlRequest(source.compat()))?; + let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; + let networks = wpa.request("LIST_NETWORKS")?; let mut id = Vec::new(); for network in networks.lines() { let v: Vec<&str> = network.split('\t').collect(); @@ -246,7 +234,10 @@ pub fn id(iface: &str, ssid: &str) -> Result, NetworkError> { /// pub fn ip(iface: &str) -> Result, NetworkError> { let net_if: String = iface.to_string(); - let ifaces = get_if_addrs::get_if_addrs().map_err(|_| NetworkError::NoIp { iface: net_if })?; + let ifaces = get_if_addrs::get_if_addrs().map_err(|source| NetworkError::NoIp { + iface: net_if, + source, + })?; let ip = ifaces .iter() .find(|&i| i.name == iface) @@ -272,11 +263,8 @@ pub fn ip(iface: &str) -> Result, NetworkError> { /// pub fn rssi(iface: &str) -> Result, NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); - let mut wpa = wpactrl::WpaCtrl::new() - .ctrl_path(wpa_path) - .open() - .map_err(|source| NetworkError::WpaCtrlOpen(source.compat()))?; - let status = wpa.request("SIGNAL_POLL").context(WpaCtrlRequest)?; + let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; + let status = wpa.request("SIGNAL_POLL")?; let rssi = utils::regex_finder(r"RSSI=(.*)\n", &status)?; if rssi.is_none() { @@ -304,17 +292,14 @@ pub fn rssi(iface: &str) -> Result, NetworkError> { /// pub fn rssi_percent(iface: &str) -> Result, NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); - let mut wpa = wpactrl::WpaCtrl::new() - .ctrl_path(wpa_path) - .open() - .map_err(|source| NetworkError::WpaCtrlOpen(source.compat()))?; - let status = wpa.request("SIGNAL_POLL").context(WpaCtrlRequest)?; + let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; + let status = wpa.request("SIGNAL_POLL")?; let rssi = utils::regex_finder(r"RSSI=(.*)\n", &status)?; match rssi { Some(rssi) => { // parse the string to a signed integer (for math) - let rssi_parsed = rssi.parse::().context(ParseString)?; + let rssi_parsed = rssi.parse::()?; // perform rssi (dBm) to quality (%) conversion let quality_percent = 2 * (rssi_parsed + 100); // convert signal quality integer to string @@ -342,10 +327,8 @@ pub fn rssi_percent(iface: &str) -> Result, NetworkError> { /// sent to the caller. /// pub fn saved_networks() -> Result, NetworkError> { - let mut wpa = wpactrl::WpaCtrl::new() - .open() - .map_err(|source| NetworkError::WpaCtrlOpen(source.compat()))?; - let networks = wpa.request("LIST_NETWORKS").context(WpaCtrlRequest)?; + let mut wpa = wpactrl::WpaCtrl::builder().open()?; + let networks = wpa.request("LIST_NETWORKS")?; let mut ssids = Vec::new(); for network in networks.lines() { let v: Vec<&str> = network.split('\t').collect(); @@ -360,7 +343,7 @@ pub fn saved_networks() -> Result, NetworkError> { if ssids.is_empty() { Ok(None) } else { - let results = serde_json::to_string(&ssids).context(SerdeSerialize)?; + let results = serde_json::to_string(&ssids)?; Ok(Some(results)) } } @@ -381,11 +364,8 @@ pub fn saved_networks() -> Result, NetworkError> { /// pub fn ssid(iface: &str) -> Result, NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); - let mut wpa = wpactrl::WpaCtrl::new() - .ctrl_path(wpa_path) - .open() - .context(WpaCtrlOpen)?; - let status = wpa.request("STATUS").context(WpaCtrlRequest)?; + let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; + let status = wpa.request("STATUS")?; // pass the regex pattern and status output to the regex finder let ssid = utils::regex_finder(r"\nssid=(.*)\n", &status)?; @@ -413,7 +393,10 @@ pub fn state(iface: &str) -> Result, NetworkError> { let output = Command::new("cat") .arg(iface_path) .output() - .context(NoState { iface })?; + .map_err(|source| NetworkError::NoState { + iface: iface.to_string(), + source, + })?; if !output.stdout.is_empty() { // unwrap the command result and convert to String let mut state = String::from_utf8(output.stdout).unwrap(); @@ -442,11 +425,8 @@ pub fn state(iface: &str) -> Result, NetworkError> { /// pub fn status(iface: &str) -> Result, NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); - let mut wpa = wpactrl::WpaCtrl::new() - .ctrl_path(wpa_path) - .open() - .context(WpaCtrlOpen)?; - let wpa_status = wpa.request("STATUS").context(WpaCtrlRequest)?; + let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; + let wpa_status = wpa.request("STATUS")?; // pass the regex pattern and status output to the regex finder let state = utils::regex_finder(r"wpa_state=(.*)\n", &wpa_status)?; @@ -504,7 +484,10 @@ pub fn status(iface: &str) -> Result, NetworkError> { /// response is sent to the caller. /// pub fn traffic(iface: &str) -> Result, NetworkError> { - let network = network::read().context(NoTraffic { iface })?; + let network = network::read().map_err(|source| NetworkError::NoTraffic { + iface: iface.to_string(), + source, + })?; // iterate through interfaces returned in network data for (interface, traffic) in network.interfaces { if interface == iface { @@ -515,7 +498,7 @@ pub fn traffic(iface: &str) -> Result, NetworkError> { transmitted, }; // TODO: add test for SerdeSerialize error - let t = serde_json::to_string(&traffic).context(SerdeSerialize)?; + let t = serde_json::to_string(&traffic)?; return Ok(Some(t)); } } @@ -540,7 +523,7 @@ pub fn activate_ap() -> Result<(), NetworkError> { .arg("start") .arg("wpa_supplicant@ap0.service") .output() - .context(StartAp0)?; + .map_err(NetworkError::StartAp0)?; Ok(()) } @@ -560,7 +543,7 @@ pub fn activate_client() -> Result<(), NetworkError> { .arg("start") .arg("wpa_supplicant@wlan0.service") .output() - .context(StartWlan0)?; + .map_err(NetworkError::StartWlan0)?; Ok(()) } @@ -585,7 +568,10 @@ pub fn add(wifi: &WiFi) -> Result<(), NetworkError> { .arg(&wifi.pass) .stdout(Stdio::piped()) .output() - .context(GenWpaPassphrase { ssid: &wifi.ssid })?; + .map_err(|source| NetworkError::GenWpaPassphrase { + ssid: wifi.ssid.to_string(), + source, + })?; // prepend newline to wpa_details to safeguard against malformed supplicant let mut wpa_details = "\n".as_bytes().to_vec(); @@ -630,7 +616,7 @@ pub fn check_iface() -> Result<(), NetworkError> { .arg("is-active") .arg("wpa_supplicant@wlan0.service") .status() - .context(WlanState)?; + .map_err(NetworkError::WlanState)?; // returns the current state of the wlan0 interface let iface_state = state("wlan0")?; @@ -666,12 +652,9 @@ pub fn check_iface() -> Result<(), NetworkError> { /// pub fn connect(id: &str, iface: &str) -> Result<(), NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); - let mut wpa = wpactrl::WpaCtrl::new() - .ctrl_path(wpa_path) - .open() - .context(WpaCtrlOpen)?; + let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; let select = format!("SELECT {}", id); - wpa.request(&select).context(WpaCtrlRequest)?; + wpa.request(&select)?; Ok(()) } @@ -691,12 +674,9 @@ pub fn connect(id: &str, iface: &str) -> Result<(), NetworkError> { /// pub fn delete(id: &str, iface: &str) -> Result<(), NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); - let mut wpa = wpactrl::WpaCtrl::new() - .ctrl_path(wpa_path) - .open() - .context(WpaCtrlOpen)?; + let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; let remove = format!("REMOVE_NETWORK {}", id); - wpa.request(&remove).context(WpaCtrlRequest)?; + wpa.request(&remove)?; Ok(()) } @@ -715,12 +695,9 @@ pub fn delete(id: &str, iface: &str) -> Result<(), NetworkError> { /// pub fn disable(id: &str, iface: &str) -> Result<(), NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); - let mut wpa = wpactrl::WpaCtrl::new() - .ctrl_path(wpa_path) - .open() - .context(WpaCtrlOpen)?; + let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; let disable = format!("DISABLE_NETWORK {}", id); - wpa.request(&disable).context(WpaCtrlRequest)?; + wpa.request(&disable)?; Ok(()) } @@ -738,12 +715,9 @@ pub fn disable(id: &str, iface: &str) -> Result<(), NetworkError> { /// pub fn disconnect(iface: &str) -> Result<(), NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); - let mut wpa = wpactrl::WpaCtrl::new() - .ctrl_path(wpa_path) - .open() - .context(WpaCtrlOpen)?; + let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; let disconnect = "DISCONNECT".to_string(); - wpa.request(&disconnect).context(WpaCtrlRequest)?; + wpa.request(&disconnect)?; Ok(()) } @@ -763,12 +737,9 @@ pub fn disconnect(iface: &str) -> Result<(), NetworkError> { /// pub fn modify(id: &str, iface: &str, pass: &str) -> Result<(), NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); - let mut wpa = wpactrl::WpaCtrl::new() - .ctrl_path(wpa_path) - .open() - .context(WpaCtrlOpen)?; + let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; let new_pass = format!("NEW_PASSWORD {} {}", id, pass); - wpa.request(&new_pass).context(WpaCtrlRequest)?; + wpa.request(&new_pass)?; Ok(()) } @@ -786,11 +757,8 @@ pub fn modify(id: &str, iface: &str, pass: &str) -> Result<(), NetworkError> { /// pub fn reassociate(iface: &str) -> Result<(), NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); - let mut wpa = wpactrl::WpaCtrl::new() - .ctrl_path(wpa_path) - .open() - .context(WpaCtrlOpen)?; - wpa.request("REASSOCIATE").context(WpaCtrlRequest)?; + let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; + wpa.request("REASSOCIATE")?; Ok(()) } @@ -804,8 +772,8 @@ pub fn reassociate(iface: &str) -> Result<(), NetworkError> { /// caller. /// pub fn reconfigure() -> Result<(), NetworkError> { - let mut wpa = wpactrl::WpaCtrl::new().open().context(WpaCtrlOpen)?; - wpa.request("RECONFIGURE").context(WpaCtrlRequest)?; + let mut wpa = wpactrl::WpaCtrl::builder().open()?; + wpa.request("RECONFIGURE")?; Ok(()) } @@ -823,12 +791,9 @@ pub fn reconfigure() -> Result<(), NetworkError> { /// pub fn reconnect(iface: &str) -> Result<(), NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); - let mut wpa = wpactrl::WpaCtrl::new() - .ctrl_path(wpa_path) - .open() - .context(WpaCtrlOpen)?; - wpa.request("DISCONNECT").context(WpaCtrlRequest)?; - wpa.request("RECONNECT").context(WpaCtrlRequest)?; + let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; + wpa.request("DISCONNECT")?; + wpa.request("RECONNECT")?; Ok(()) } @@ -841,7 +806,7 @@ pub fn reconnect(iface: &str) -> Result<(), NetworkError> { /// appropriate JSON RPC response is sent to the caller. /// pub fn save() -> Result<(), NetworkError> { - let mut wpa = wpactrl::WpaCtrl::new().open().context(WpaCtrlOpen)?; - wpa.request("SAVE_CONFIG").context(WpaCtrlRequest)?; + let mut wpa = wpactrl::WpaCtrl::builder().open()?; + wpa.request("SAVE_CONFIG")?; Ok(()) } diff --git a/peach-network/src/utils.rs b/peach-network/src/utils.rs index e82b7aa..6c381eb 100644 --- a/peach-network/src/utils.rs +++ b/peach-network/src/utils.rs @@ -1,7 +1,6 @@ use regex::Regex; -use snafu::ResultExt; -use crate::error::*; +use crate::error::NetworkError; /// Return matches for a given Regex pattern and text /// @@ -11,7 +10,7 @@ use crate::error::*; /// * `text` - A string slice containing the text to be matched on /// pub fn regex_finder(pattern: &str, text: &str) -> Result, NetworkError> { - let re = Regex::new(pattern).context(Regex)?; + let re = Regex::new(pattern)?; let caps = re.captures(text); let result = caps.map(|caps| caps[1].to_string()); From c3fa18840051a63fb245a8a8742870a3ff9912a0 Mon Sep 17 00:00:00 2001 From: glyph Date: Tue, 7 Dec 2021 10:04:58 +0200 Subject: [PATCH 04/13] testing refactored wpactrl --- peach-network/Cargo.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/peach-network/Cargo.toml b/peach-network/Cargo.toml index cc2eead..efb33dd 100644 --- a/peach-network/Cargo.toml +++ b/peach-network/Cargo.toml @@ -28,7 +28,6 @@ maintenance = { status = "actively-developed" } [dependencies] env_logger = "0.6" -failure = "0.1" get_if_addrs = "0.5.3" jsonrpc-core = "11" jsonrpc-http-server = "11" @@ -37,7 +36,9 @@ probes = "0.4" serde = { version = "1", features = ["derive"] } serde_json = "1" regex = "1" -wpactrl = "0.3.1" +#wpactrl = "0.3.1" +#wpactrl = { git = "https://github.com/sauyon/wpa-ctrl-rs.git", branch = "master" } +wpactrl = { path = "../../../playground/rust/wpa-ctrl-rs" } [dev-dependencies] jsonrpc-test = "11" From 46b7c0fc2b0c98ea4fa7772c48e157cf8f5af65a Mon Sep 17 00:00:00 2001 From: glyph Date: Mon, 13 Dec 2021 08:19:25 +0200 Subject: [PATCH 05/13] update wpactrl tests --- peach-network/src/lib.rs | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/peach-network/src/lib.rs b/peach-network/src/lib.rs index c4d0d3b..97b011b 100644 --- a/peach-network/src/lib.rs +++ b/peach-network/src/lib.rs @@ -842,7 +842,7 @@ mod tests { let mut io = IoHandler::new(); io.add_method("rpc_regex_error", |_| { let source = regex::Error::Syntax("oh no!".to_string()); - Err(Error::from(NetworkError::Regex { source })) + Err(Error::from(NetworkError::Regex(source))) }); test_rpc::Rpc::from(io) }; @@ -886,7 +886,7 @@ mod tests { let mut io = IoHandler::new(); io.add_method("rpc_wlanstate_error", |_| { let source = IoError::new(ErrorKind::PermissionDenied, "oh no!"); - Err(Error::from(NetworkError::WlanState { source })) + Err(Error::from(NetworkError::WlanState(source))) }); test_rpc::Rpc::from(io) }; @@ -907,7 +907,7 @@ mod tests { let mut io = IoHandler::new(); io.add_method("rpc_wlanoperstate_error", |_| { let source = IoError::new(ErrorKind::PermissionDenied, "oh no!"); - Err(Error::from(NetworkError::WlanOperstate { source })) + Err(Error::from(NetworkError::WlanOperstate(source))) }); test_rpc::Rpc::from(io) }; @@ -945,9 +945,13 @@ mod tests { let rpc = { let mut io = IoHandler::new(); io.add_method("rpc_wpactrlopen_error", |_| { - let fail_err = failure::err_msg("Permission denied (os error 13)").compat(); - let source = Box::new(fail_err); - Err(Error::from(NetworkError::WpaCtrlOpen { source })) + let permission_error = IoError::new( + ErrorKind::PermissionDenied, + "Permission denied (os error 13)", + ); + Err(Error::from(NetworkError::WpaCtrl(wpactrl::WpaError::Io( + permission_error, + )))) }); test_rpc::Rpc::from(io) }; @@ -956,7 +960,7 @@ mod tests { rpc.request("rpc_wpactrlopen_error", &()), r#"{ "code": -32013, - "message": "Failed to open control interface for wpasupplicant: Permission denied (os error 13)" + "message": "WPA control interface failure: Failed to execute the specified command: Permission denied (os error 13)" }"# ); } @@ -967,9 +971,10 @@ mod tests { let rpc = { let mut io = IoHandler::new(); io.add_method("rpc_wpactrlrequest_error", |_| { - let fail_err = failure::err_msg("oh no!").compat(); - let source = Box::new(fail_err); - Err(Error::from(NetworkError::WpaCtrlRequest { source })) + let conn_refused_error = IoError::new(ErrorKind::ConnectionRefused, "oh no!"); + Err(Error::from(NetworkError::WpaCtrl(wpactrl::WpaError::Io( + conn_refused_error, + )))) }); test_rpc::Rpc::from(io) }; @@ -977,8 +982,8 @@ mod tests { assert_eq!( rpc.request("rpc_wpactrlrequest_error", &()), r#"{ - "code": -32014, - "message": "WPA supplicant request failed: oh no!" + "code": -32013, + "message": "WPA control interface failure: Failed to execute the specified command: oh no!" }"# ); } From 2f7c7aac8f2c6359d6ae5882632686aec09e1a82 Mon Sep 17 00:00:00 2001 From: glyph Date: Mon, 13 Dec 2021 08:19:55 +0200 Subject: [PATCH 06/13] bump version and fix wpactrl dep import --- peach-network/Cargo.toml | 7 +++---- peach-network/README.md | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/peach-network/Cargo.toml b/peach-network/Cargo.toml index efb33dd..66edf98 100644 --- a/peach-network/Cargo.toml +++ b/peach-network/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "peach-network" -version = "0.2.12" +version = "0.2.13" authors = ["Andrew Reid "] edition = "2018" description = "Query and configure network interfaces using JSON-RPC over HTTP." @@ -36,9 +36,8 @@ probes = "0.4" serde = { version = "1", features = ["derive"] } serde_json = "1" regex = "1" -#wpactrl = "0.3.1" -#wpactrl = { git = "https://github.com/sauyon/wpa-ctrl-rs.git", branch = "master" } -wpactrl = { path = "../../../playground/rust/wpa-ctrl-rs" } +# replace this with crate import once latest changes have been published +wpactrl = { git = "https://github.com/sauyon/wpa-ctrl-rs.git", branch = "master" } [dev-dependencies] jsonrpc-test = "11" diff --git a/peach-network/README.md b/peach-network/README.md index 1642d93..c8babd0 100644 --- a/peach-network/README.md +++ b/peach-network/README.md @@ -1,6 +1,6 @@ # peach-network -[![Build Status](https://travis-ci.com/peachcloud/peach-network.svg?branch=master)](https://travis-ci.com/peachcloud/peach-network) ![Generic badge](https://img.shields.io/badge/version-0.2.12-.svg) +[![Build Status](https://travis-ci.com/peachcloud/peach-network.svg?branch=master)](https://travis-ci.com/peachcloud/peach-network) ![Generic badge](https://img.shields.io/badge/version-0.2.13-.svg) Networking microservice module for PeachCloud. Query and configure device interfaces using [JSON-RPC](https://www.jsonrpc.org/specification) over http. From dfa1306b2d96791c06d71f853d483eda6099988f Mon Sep 17 00:00:00 2001 From: glyph Date: Mon, 13 Dec 2021 08:20:03 +0200 Subject: [PATCH 07/13] update lockfile --- Cargo.lock | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index abad00b..1e295c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2210,20 +2210,6 @@ dependencies = [ "void", ] -[[package]] -name = "nix" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7fd5681d13fda646462cfbd4e5f2051279a89a544d50eb98c365b507246839f" -dependencies = [ - "bitflags 1.3.2", - "bytes 0.4.12", - "cfg-if 0.1.10", - "gcc", - "libc", - "void", -] - [[package]] name = "nix" version = "0.11.1" @@ -2625,10 +2611,9 @@ dependencies = [ [[package]] name = "peach-network" -version = "0.2.12" +version = "0.2.13" dependencies = [ "env_logger 0.6.2", - "failure", "get_if_addrs", "jsonrpc-core 11.0.0", "jsonrpc-http-server 11.0.0", @@ -5010,12 +4995,10 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "wpactrl" version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f487ac0a84d67974aa9ca3a7a284cb4821869d677376768f5c303fa786635c13" +source = "git+https://github.com/sauyon/wpa-ctrl-rs.git?branch=master#e37eeb0a9b58cde12bc9825515caaaadcbf49fa6" dependencies = [ - "failure", + "libc", "log 0.4.14", - "nix 0.10.0", ] [[package]] From f4113f0632fcc6eec54286c31dfcd63e39b25f55 Mon Sep 17 00:00:00 2001 From: glyph Date: Mon, 13 Dec 2021 10:54:24 +0200 Subject: [PATCH 08/13] remove debian files and main --- peach-network/debian/peach-network.service | 13 ------------- peach-network/src/main.rs | 14 -------------- 2 files changed, 27 deletions(-) delete mode 100644 peach-network/debian/peach-network.service delete mode 100644 peach-network/src/main.rs diff --git a/peach-network/debian/peach-network.service b/peach-network/debian/peach-network.service deleted file mode 100644 index d81099c..0000000 --- a/peach-network/debian/peach-network.service +++ /dev/null @@ -1,13 +0,0 @@ -[Unit] -Description=Query and configure network interfaces using JSON-RPC over HTTP. - -[Service] -Type=simple -User=root -Group=netdev -Environment="RUST_LOG=error" -ExecStart=/usr/bin/peach-network -Restart=always - -[Install] -WantedBy=multi-user.target diff --git a/peach-network/src/main.rs b/peach-network/src/main.rs deleted file mode 100644 index b54cc87..0000000 --- a/peach-network/src/main.rs +++ /dev/null @@ -1,14 +0,0 @@ -use std::process; - -use log::error; - -fn main() { - // initalize the logger - env_logger::init(); - - // handle errors returned from `run` - if let Err(e) = peach_network::run() { - error!("Application error: {}", e); - process::exit(1); - } -} From 4f5eb3aa04659d7cf231e13519639cacdee3d30c Mon Sep 17 00:00:00 2001 From: glyph Date: Mon, 13 Dec 2021 10:54:38 +0200 Subject: [PATCH 09/13] update dependencies and version --- Cargo.lock | 9 ++------- peach-network/Cargo.toml | 41 +++++++++++++++------------------------- 2 files changed, 17 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 35610f6..c48e7d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2532,18 +2532,13 @@ dependencies = [ [[package]] name = "peach-network" -version = "0.2.13" +version = "0.3.0" dependencies = [ - "env_logger 0.6.2", "get_if_addrs", - "jsonrpc-core 11.0.0", - "jsonrpc-http-server 11.0.0", - "jsonrpc-test 11.0.0", - "log 0.4.14", + "miniserde", "probes 0.4.1", "regex", "serde 1.0.130", - "serde_json", "wpactrl", ] diff --git a/peach-network/Cargo.toml b/peach-network/Cargo.toml index 66edf98..502a719 100644 --- a/peach-network/Cargo.toml +++ b/peach-network/Cargo.toml @@ -1,43 +1,32 @@ [package] name = "peach-network" -version = "0.2.13" -authors = ["Andrew Reid "] +version = "0.3.0" +authors = ["Andrew Reid "] edition = "2018" -description = "Query and configure network interfaces using JSON-RPC over HTTP." +description = "Query and configure network interfaces." homepage = "https://opencollective.com/peachcloud" -repository = "https://github.com/peachcloud/peach-network" +repository = "ihttps://git.coopcloud.tech/PeachCloud/peach-workspace/src/branch/main/peach-network" readme = "README.md" license = "AGPL-3.0-only" publish = false -[package.metadata.deb] -depends = "$auto" -extended-description = """\ -peach-network is a microservice to query and configure network interfaces \ -using JSON-RPC over HTTP.""" -maintainer-scripts="debian" -systemd-units = { unit-name = "peach-network" } -assets = [ - ["target/release/peach-network", "usr/bin/", "755"], - ["README.md", "usr/share/doc/peach-network/README", "644"], -] - [badges] -travis-ci = { repository = "peachcloud/peach-network", branch = "master" } maintenance = { status = "actively-developed" } [dependencies] -env_logger = "0.6" get_if_addrs = "0.5.3" -jsonrpc-core = "11" -jsonrpc-http-server = "11" -log = "0.4" -probes = "0.4" -serde = { version = "1", features = ["derive"] } -serde_json = "1" +miniserde = { version = "0.1.15", optional = true } +probes = "0.4.1" +serde = { version = "1.0.130", features = ["derive"], optional = true } regex = "1" # replace this with crate import once latest changes have been published wpactrl = { git = "https://github.com/sauyon/wpa-ctrl-rs.git", branch = "master" } -[dev-dependencies] -jsonrpc-test = "11" +[features] +default = [] + +# Provide `Serialize` and `Deserialize` traits for library structs using `miniserde` +miniserde_support = ["miniserde"] + +# Provide `Serialize` and `Deserialize` traits for library structs using `serde` +serde_support = ["serde"] From 9f40378fce0818c71632fe733c592d82913fbab7 Mon Sep 17 00:00:00 2001 From: glyph Date: Mon, 13 Dec 2021 10:54:51 +0200 Subject: [PATCH 10/13] remove json-rpc error code and improve docs --- peach-network/src/error.rs | 423 +++++++++++++------------------------ 1 file changed, 146 insertions(+), 277 deletions(-) diff --git a/peach-network/src/error.rs b/peach-network/src/error.rs index ebb4423..f66db36 100644 --- a/peach-network/src/error.rs +++ b/peach-network/src/error.rs @@ -1,81 +1,166 @@ +//! Custom error type for `peach-network`. + use std::io; use std::num::ParseIntError; use io::Error as IoError; -use jsonrpc_core::{types::error::Error as JsonRpcError, ErrorCode}; use probes::ProbeError; use regex::Error as RegexError; -use serde_json::Error as SerdeError; use wpactrl::WpaError; +/// Custom error type encapsulating all possible errors when querying +/// network interfaces and modifying their state. #[derive(Debug)] pub enum NetworkError { - Add { ssid: String }, - - NoState { iface: String, source: IoError }, - - Disable { id: String, iface: String }, - - Disconnect { iface: String }, - - GenWpaPassphrase { ssid: String, source: IoError }, - - GenWpaPassphraseWarning { ssid: String, err_msg: String }, - - Id { ssid: String, iface: String }, - - NoIp { iface: String, source: IoError }, - - Rssi { iface: String }, - - RssiPercent { iface: String }, - - Ssid { iface: String }, - - State { iface: String }, - - Status { iface: String }, - - Traffic { iface: String }, - + /// Failed to add network. + Add { + /// SSID. + ssid: String, + }, + /// Failed to retrieve network state. + NoState { + /// Interface. + iface: String, + /// Underlying error source. + source: IoError, + }, + /// Failed to disable network. + Disable { + /// ID. + id: String, + /// Interface. + iface: String, + }, + /// Failed to disconnect interface. + Disconnect { + /// Interface. + iface: String, + }, + /// Failed to execute wpa_passphrase command. + GenWpaPassphrase { + /// SSID. + ssid: String, + /// Underlying error source. + source: IoError, + }, + /// Failed to successfully generate wpa passphrase. + GenWpaPassphraseWarning { + /// SSID. + ssid: String, + /// Error message describing context. + err_msg: String, + }, + /// Failed to retrieve ID for the given SSID and interface. + Id { + /// SSID. + ssid: String, + /// Interface. + iface: String, + }, + /// Failed to retrieve IP address. + NoIp { + /// Inteface. + iface: String, + /// Underlying error source. + source: IoError, + }, + /// Failed to retrieve RSSI. + Rssi { + /// Interface. + iface: String, + }, + /// Failed to retrieve signal quality (%). + RssiPercent { + /// Interface. + iface: String, + }, + /// Failed to retrieve SSID. + Ssid { + /// Interface. + iface: String, + }, + /// Failed to retrieve state. + State { + /// Interface. + iface: String, + }, + /// Failed to retrieve status. + Status { + /// Interface. + iface: String, + }, + /// Failed to retieve network traffic. + Traffic { + /// Interface. + iface: String, + }, + /// No saved network found for the default interface. SavedNetworks, - - AvailableNetworks { iface: String }, - - MissingParams(JsonRpcError), - - Modify { id: String, iface: String }, - - Ip { iface: String }, - + /// No networks found in range. + AvailableNetworks { + /// Interface. + iface: String, + }, + /// Failed to set new password. + Modify { + /// ID. + id: String, + /// Interface. + iface: String, + }, + /// Failed to retrieve IP address. + Ip { + /// Interface. + iface: String, + }, + /// Failed to parse integer from string. ParseInt(ParseIntError), - - NoTraffic { iface: String, source: ProbeError }, - - Reassociate { iface: String }, - + /// Failed to retrieve network traffic measurement. + NoTraffic { + /// Interface. + iface: String, + /// Underlying error source. + source: ProbeError, + }, + /// Failed to reassociate with WiFi network. + Reassociate { + /// Interface. + iface: String, + }, + /// Failed to force reread of wpa_supplicant configuration file. Reconfigure, - - Reconnect { iface: String }, - + /// Failed to reconnect with WiFi network. + Reconnect { + /// Interface. + iface: String, + }, + /// Failed to execute Regex command. Regex(RegexError), - - Delete { id: String, iface: String }, - + /// Failed to delete network. + Delete { + /// ID. + id: String, + /// Interface. + iface: String, + }, + /// Failed to retrieve state of wlan0 service. WlanState(IoError), - + /// Failed to retrieve connection state of wlan0 interface. WlanOperstate(IoError), - + /// Failed to save wpa_supplicant configuration changes to file. Save, - - Connect { id: String, iface: String }, - + /// Failed to connect to network. + Connect { + /// ID. + id: String, + /// Interface. + iface: String, + }, + /// Failed to start ap0 service. StartAp0(IoError), - + /// Failed to start wlan0 service. StartWlan0(IoError), - - SerdeSerialize(SerdeError), - + /// Failed to execute wpa-ctrl command. WpaCtrl(WpaError), } @@ -98,7 +183,6 @@ impl std::error::Error for NetworkError { NetworkError::Traffic { .. } => None, NetworkError::SavedNetworks => None, NetworkError::AvailableNetworks { .. } => None, - NetworkError::MissingParams(ref source) => Some(source), NetworkError::Modify { .. } => None, NetworkError::Ip { .. } => None, NetworkError::ParseInt(ref source) => Some(source), @@ -114,7 +198,6 @@ impl std::error::Error for NetworkError { NetworkError::Connect { .. } => None, NetworkError::StartWlan0(ref source) => Some(source), NetworkError::StartAp0(ref source) => Some(source), - NetworkError::SerdeSerialize(ref source) => Some(source), NetworkError::WpaCtrl(ref source) => Some(source), } } @@ -181,20 +264,13 @@ impl std::fmt::Display for NetworkError { write!(f, "No status found for interface: {}", iface) } NetworkError::Traffic { ref iface } => { - write!( - f, - "Could not find network traffice for interface: {}", - iface - ) + write!(f, "Could not find network traffic for interface: {}", iface) } NetworkError::SavedNetworks => { write!(f, "No saved networks found for default interface") } NetworkError::AvailableNetworks { ref iface } => { - write!(f, "No networks found in range of interface: {}", iface) - } - NetworkError::MissingParams(ref source) => { - write!(f, "Missing expected parameters: {}", source) + write!(f, "No networks found in range of interface: {}", iface) } NetworkError::Modify { ref id, ref iface } => { write!( @@ -258,18 +334,11 @@ impl std::fmt::Display for NetworkError { } NetworkError::StartWlan0(_) => write!(f, "Failed to start ap0 service"), NetworkError::StartAp0(_) => write!(f, "Failed to start wlan0 service"), - NetworkError::SerdeSerialize(_) => write!(f, "JSON serialization failed"), NetworkError::WpaCtrl(_) => write!(f, "WpaCtrl command failed"), } } } -impl From for NetworkError { - fn from(err: SerdeError) -> Self { - NetworkError::SerdeSerialize(err) - } -} - impl From for NetworkError { fn from(err: WpaError) -> Self { NetworkError::WpaCtrl(err) @@ -287,203 +356,3 @@ impl From for NetworkError { NetworkError::Regex(err) } } - -impl From for JsonRpcError { - fn from(err: NetworkError) -> Self { - match &err { - NetworkError::Add { ssid } => JsonRpcError { - code: ErrorCode::ServerError(-32000), - message: format!("Failed to add network for {}", ssid), - data: None, - }, - NetworkError::NoState { iface, source } => JsonRpcError { - code: ErrorCode::ServerError(-32022), - message: format!( - "Failed to retrieve interface state for {}: {}", - iface, source - ), - data: None, - }, - NetworkError::Disable { id, iface } => JsonRpcError { - code: ErrorCode::ServerError(-32029), - message: format!("Failed to disable network {} for {}", id, iface), - data: None, - }, - NetworkError::Disconnect { iface } => JsonRpcError { - code: ErrorCode::ServerError(-32032), - message: format!("Failed to disconnect {}", iface), - data: None, - }, - NetworkError::GenWpaPassphrase { ssid, source } => JsonRpcError { - code: ErrorCode::ServerError(-32025), - message: format!("Failed to generate wpa passphrase for {}: {}", ssid, source), - data: None, - }, - NetworkError::GenWpaPassphraseWarning { ssid, err_msg } => JsonRpcError { - code: ErrorCode::ServerError(-32036), - message: format!( - "Failed to generate wpa passphrase for {}: {}", - ssid, err_msg - ), - data: None, - }, - NetworkError::Id { iface, ssid } => JsonRpcError { - code: ErrorCode::ServerError(-32026), - message: format!("No ID found for {} on interface {}", ssid, iface), - data: None, - }, - NetworkError::NoIp { iface, source } => JsonRpcError { - code: ErrorCode::ServerError(-32001), - message: format!("Failed to retrieve IP address for {}: {}", iface, source), - data: None, - }, - NetworkError::Rssi { iface } => JsonRpcError { - code: ErrorCode::ServerError(-32002), - message: format!( - "Failed to retrieve RSSI for {}. Interface may not be connected", - iface - ), - data: None, - }, - NetworkError::RssiPercent { iface } => JsonRpcError { - code: ErrorCode::ServerError(-32034), - message: format!( - "Failed to retrieve signal quality (%) for {}. Interface may not be connected", - iface - ), - data: None, - }, - NetworkError::Ssid { iface } => JsonRpcError { - code: ErrorCode::ServerError(-32003), - message: format!( - "Failed to retrieve SSID for {}. Interface may not be connected", - iface - ), - data: None, - }, - NetworkError::State { iface } => JsonRpcError { - code: ErrorCode::ServerError(-32023), - message: format!("No state found for {}. Interface may not exist", iface), - data: None, - }, - NetworkError::Status { iface } => JsonRpcError { - code: ErrorCode::ServerError(-32024), - message: format!("No status found for {}. Interface may not exist", iface), - data: None, - }, - NetworkError::Traffic { iface } => JsonRpcError { - code: ErrorCode::ServerError(-32004), - message: format!( - "No network traffic statistics found for {}. Interface may not exist", - iface - ), - data: None, - }, - NetworkError::SavedNetworks => JsonRpcError { - code: ErrorCode::ServerError(-32005), - message: "No saved networks found".to_string(), - data: None, - }, - NetworkError::AvailableNetworks { iface } => JsonRpcError { - code: ErrorCode::ServerError(-32006), - message: format!("No networks found in range of {}", iface), - data: None, - }, - NetworkError::MissingParams(e) => e.clone(), - NetworkError::Modify { id, iface } => JsonRpcError { - code: ErrorCode::ServerError(-32033), - message: format!("Failed to set new password for network {} on {}", id, iface), - data: None, - }, - NetworkError::Ip { iface } => JsonRpcError { - code: ErrorCode::ServerError(-32007), - message: format!("No IP address found for {}", iface), - data: None, - }, - NetworkError::ParseInt(source) => JsonRpcError { - code: ErrorCode::ServerError(-32035), - message: format!( - "Failed to parse integer from string for RSSI value: {}", - source - ), - data: None, - }, - NetworkError::NoTraffic { iface, source } => JsonRpcError { - code: ErrorCode::ServerError(-32015), - message: format!( - "Failed to retrieve network traffic statistics for {}: {}", - iface, source - ), - data: None, - }, - NetworkError::Reassociate { iface } => JsonRpcError { - code: ErrorCode::ServerError(-32008), - message: format!("Failed to reassociate with WiFi network for {}", iface), - data: None, - }, - NetworkError::Reconfigure => JsonRpcError { - code: ErrorCode::ServerError(-32030), - message: "Failed to force reread of wpa_supplicant configuration file".to_string(), - data: None, - }, - NetworkError::Reconnect { iface } => JsonRpcError { - code: ErrorCode::ServerError(-32009), - message: format!("Failed to reconnect with WiFi network for {}", iface), - data: None, - }, - NetworkError::Regex(source) => JsonRpcError { - code: ErrorCode::ServerError(-32010), - message: format!("Regex command error: {}", source), - data: None, - }, - NetworkError::Delete { id, iface } => JsonRpcError { - code: ErrorCode::ServerError(-32028), - message: format!("Failed to delete network {} for {}", id, iface), - data: None, - }, - NetworkError::WlanState(source) => JsonRpcError { - code: ErrorCode::ServerError(-32011), - message: format!("Failed to retrieve state of wlan0 service: {}", source), - data: None, - }, - NetworkError::WlanOperstate(source) => JsonRpcError { - code: ErrorCode::ServerError(-32021), - message: format!( - "Failed to retrieve connection state of wlan0 interface: {}", - source - ), - data: None, - }, - NetworkError::Save => JsonRpcError { - code: ErrorCode::ServerError(-32031), - message: "Failed to save configuration changes to file".to_string(), - data: None, - }, - NetworkError::Connect { id, iface } => JsonRpcError { - code: ErrorCode::ServerError(-32027), - message: format!("Failed to connect to network {} for {}", id, iface), - data: None, - }, - NetworkError::StartAp0(source) => JsonRpcError { - code: ErrorCode::ServerError(-32016), - message: format!("Failed to start ap0 service: {}", source), - data: None, - }, - NetworkError::StartWlan0(source) => JsonRpcError { - code: ErrorCode::ServerError(-32018), - message: format!("Failed to start wlan0 service: {}", source), - data: None, - }, - NetworkError::SerdeSerialize(source) => JsonRpcError { - code: ErrorCode::ServerError(-32012), - message: format!("JSON serialization failed: {}", source), - data: None, - }, - NetworkError::WpaCtrl(source) => JsonRpcError { - code: ErrorCode::ServerError(-32013), - message: format!("WPA control interface failure: {}", source), - data: None, - }, - } - } -} From 287082381ee2754653c0619e773bcb01bd81fc1f Mon Sep 17 00:00:00 2001 From: glyph Date: Mon, 13 Dec 2021 10:55:04 +0200 Subject: [PATCH 11/13] remove json-rpc methods --- peach-network/src/lib.rs | 1013 ++------------------------------------ 1 file changed, 35 insertions(+), 978 deletions(-) diff --git a/peach-network/src/lib.rs b/peach-network/src/lib.rs index 97b011b..b6ff630 100644 --- a/peach-network/src/lib.rs +++ b/peach-network/src/lib.rs @@ -1,990 +1,47 @@ +#![warn(missing_docs)] + //! # peach-network //! -//! `peach-network` is a networking microservice module for PeachCloud. It -//! exposes a JSON-RPC API over HTTP which allows querying of network interface -//! data and modification of interface state. +//! Network interface state query and modification library; designed for use +//! with the PeachCloud platform. //! //! The `src/network.rs` module contains the core networking logic and data //! types for interacting with the `wpa_supplicant` process and related parts of //! the operating system, while the `src/error.rs` module contains //! error-handling data types and methods. //! -//! `src/main.rs` initializes the logger, starts the application and catches -//! application errors, while `src/lib.rs` contains the JSON-RPC server, RPC -//! methods, HTTP server and tests. +//! ## Example Usage //! -mod error; +//! ```rust +//! use peach_network::{network, NetworkError, network::WiFi}; +//! +//! fn main() -> Result<(), NetworkError> { +//! let ip = network::ip("wlan0"); +//! let ssid = network::ssid("wlan0"); +//! +//! let new_ap = WiFi { ssid: "Home".to_string(), pass: "SuperSecret".to_string() }; +//! +//! //network::add(&new_ap)?; +//! //network::save()?; +//! +//! Ok(()) +//! } +//! ``` +//! +//! ## Feature Flags +//! +//! Feature flags are used to offer `Serialize` and `Deserialize` implementations +//! for all `struct` data types provided by this library. These traits are not +//! provided by default. A choice of `miniserde` and `serde` is provided. +//! +//! Define the desired feature in the `Cargo.toml` manifest of your project: +//! +//! ```toml +//! peach-network = { version = "0.3.0", features = ["miniserde_support"] } +//! ``` + +pub mod error; pub mod network; mod utils; -use std::env; -use std::result::Result; - -use jsonrpc_core::{types::error::Error, IoHandler, Params, Value}; -use jsonrpc_http_server::{AccessControlAllowOrigin, DomainsValidation, ServerBuilder}; -use log::info; -use serde_json::json; - -use crate::error::NetworkError; -use crate::network::{Iface, IfaceId, IfaceIdPass, IfaceSsid, WiFi}; - -/// Create JSON-RPC I/O handler, add RPC methods and launch HTTP server. -pub fn run() -> Result<(), NetworkError> { - info!("Starting up."); - - info!("Creating JSON-RPC I/O handler."); - let mut io = IoHandler::default(); - - /* GET - All RPC methods for retrieving data */ - - io.add_method("available_networks", move |params: Params| { - let i: Result = params.parse(); - match i { - Ok(i) => { - let iface = i.iface; - match network::available_networks(&iface)? { - Some(list) => Ok(Value::String(list)), - None => Err(Error::from(NetworkError::AvailableNetworks { iface })), - } - } - Err(e) => Err(Error::from(NetworkError::MissingParams(e))), - } - }); - - io.add_method("id", move |params: Params| { - let i: Result = params.parse(); - match i { - Ok(i) => { - let iface = i.iface; - let ssid = i.ssid; - match network::id(&iface, &ssid)? { - Some(id) => Ok(Value::String(id)), - None => Err(Error::from(NetworkError::Id { iface, ssid })), - } - } - Err(e) => Err(Error::from(NetworkError::MissingParams(e))), - } - }); - - io.add_method("ip", move |params: Params| { - let i: Result = params.parse(); - match i { - Ok(i) => { - let iface = i.iface; - match network::ip(&iface)? { - Some(ip) => Ok(Value::String(ip)), - None => Err(Error::from(NetworkError::Ip { iface })), - } - } - Err(e) => Err(Error::from(NetworkError::MissingParams(e))), - } - }); - - io.add_method("ping", |_| Ok(Value::String("success".to_string()))); - - io.add_method("rssi", move |params: Params| { - let i: Result = params.parse(); - match i { - Ok(i) => { - let iface = i.iface; - match network::rssi(&iface)? { - Some(rssi) => Ok(Value::String(rssi)), - None => Err(Error::from(NetworkError::Rssi { iface })), - } - } - Err(e) => Err(Error::from(NetworkError::MissingParams(e))), - } - }); - - io.add_method("rssi_percent", move |params: Params| { - let i: Result = params.parse(); - match i { - Ok(i) => { - let iface = i.iface; - match network::rssi_percent(&iface)? { - Some(rssi) => Ok(Value::String(rssi)), - None => Err(Error::from(NetworkError::RssiPercent { iface })), - } - } - Err(e) => Err(Error::from(NetworkError::MissingParams(e))), - } - }); - - io.add_method("saved_networks", move |_| { - let list = network::saved_networks()?; - match list { - Some(list) => Ok(Value::String(list)), - None => Err(Error::from(NetworkError::SavedNetworks)), - } - }); - - io.add_method("ssid", move |params: Params| { - let i: Result = params.parse(); - match i { - Ok(i) => { - let iface = i.iface; - match network::ssid(&iface)? { - Some(ip) => Ok(Value::String(ip)), - None => Err(Error::from(NetworkError::Ssid { iface })), - } - } - Err(e) => Err(Error::from(NetworkError::MissingParams(e))), - } - }); - - io.add_method("state", move |params: Params| { - let i: Result = params.parse(); - match i { - Ok(i) => { - let iface = i.iface; - match network::state(&iface)? { - Some(state) => Ok(Value::String(state)), - None => Err(Error::from(NetworkError::State { iface })), - } - } - Err(e) => Err(Error::from(NetworkError::MissingParams(e))), - } - }); - - io.add_method("status", move |params: Params| { - let i: Result = params.parse(); - match i { - Ok(i) => { - let iface = i.iface; - match network::status(&iface)? { - Some(status) => { - let json_status = json!(status); - Ok(Value::String(json_status.to_string())) - } - None => Err(Error::from(NetworkError::Status { iface })), - } - } - Err(e) => Err(Error::from(NetworkError::MissingParams(e))), - } - }); - - io.add_method("traffic", move |params: Params| { - let i: Result = params.parse(); - match i { - Ok(i) => { - let iface = i.iface; - match network::traffic(&iface)? { - Some(traffic) => Ok(Value::String(traffic)), - None => Err(Error::from(NetworkError::Traffic { iface })), - } - } - Err(e) => Err(Error::from(NetworkError::MissingParams(e))), - } - }); - - /* SET - All RPC methods for modifying state */ - - io.add_method("activate_ap", move |_| { - network::activate_ap()?; - - Ok(Value::String("success".to_string())) - }); - - io.add_method("activate_client", move |_| { - network::activate_client()?; - - Ok(Value::String("success".to_string())) - }); - - io.add_method("add", move |params: Params| { - let w: Result = params.parse(); - match w { - Ok(w) => match network::add(&w) { - Ok(_) => Ok(Value::String("success".to_string())), - Err(e) => Err(Error::from(e)), - }, - Err(e) => Err(Error::from(NetworkError::MissingParams(e))), - } - }); - - io.add_method("check_iface", move |_| { - network::check_iface()?; - - Ok(Value::String("success".to_string())) - }); - - io.add_method("delete", move |params: Params| { - let i: Result = params.parse(); - match i { - Ok(i) => { - let id = i.id; - let iface = i.iface; - match network::delete(&id, &iface) { - Ok(_) => Ok(Value::String("success".to_string())), - Err(_) => Err(Error::from(NetworkError::Delete { id, iface })), - } - } - Err(e) => Err(Error::from(NetworkError::MissingParams(e))), - } - }); - - io.add_method("disable", move |params: Params| { - let i: Result = params.parse(); - match i { - Ok(i) => { - let id = i.id; - let iface = i.iface; - match network::disable(&id, &iface) { - Ok(_) => Ok(Value::String("success".to_string())), - Err(_) => Err(Error::from(NetworkError::Disable { id, iface })), - } - } - Err(e) => Err(Error::from(NetworkError::MissingParams(e))), - } - }); - - io.add_method("disconnect", move |params: Params| { - let i: Result = params.parse(); - match i { - Ok(i) => { - let iface = i.iface; - match network::disconnect(&iface) { - Ok(_) => Ok(Value::String("success".to_string())), - Err(_) => Err(Error::from(NetworkError::Disconnect { iface })), - } - } - Err(e) => Err(Error::from(NetworkError::MissingParams(e))), - } - }); - - io.add_method("modify", move |params: Params| { - let i: Result = params.parse(); - match i { - Ok(i) => { - let iface = i.iface; - let id = i.id; - let pass = i.pass; - match network::modify(&iface, &id, &pass) { - Ok(_) => Ok(Value::String("success".to_string())), - Err(_) => Err(Error::from(NetworkError::Modify { iface, id })), - } - } - Err(e) => Err(Error::from(NetworkError::MissingParams(e))), - } - }); - - io.add_method("reassociate", move |params: Params| { - let i: Result = params.parse(); - match i { - Ok(i) => { - let iface = i.iface; - match network::reassociate(&iface) { - Ok(_) => Ok(Value::String("success".to_string())), - Err(_) => Err(Error::from(NetworkError::Reassociate { iface })), - } - } - Err(e) => Err(Error::from(NetworkError::MissingParams(e))), - } - }); - - io.add_method("reconfigure", move |_| match network::reconfigure() { - Ok(_) => Ok(Value::String("success".to_string())), - Err(_) => Err(Error::from(NetworkError::Reconfigure)), - }); - - io.add_method("reconnect", move |params: Params| { - let i: Result = params.parse(); - match i { - Ok(i) => { - let iface = i.iface; - match network::reconnect(&iface) { - Ok(_) => Ok(Value::String("success".to_string())), - Err(_) => Err(Error::from(NetworkError::Reconnect { iface })), - } - } - Err(e) => Err(Error::from(NetworkError::MissingParams(e))), - } - }); - - io.add_method("save", move |_| match network::save() { - Ok(_) => Ok(Value::String("success".to_string())), - Err(_) => Err(Error::from(NetworkError::Save)), - }); - - io.add_method("connect", move |params: Params| { - let i: Result = params.parse(); - match i { - Ok(i) => { - let id = i.id; - let iface = i.iface; - match network::connect(&id, &iface) { - Ok(_) => Ok(Value::String("success".to_string())), - Err(_) => Err(Error::from(NetworkError::Connect { id, iface })), - } - } - Err(e) => Err(Error::from(NetworkError::MissingParams(e))), - } - }); - - let http_server = - env::var("PEACH_NETWORK_SERVER").unwrap_or_else(|_| "127.0.0.1:5110".to_string()); - - info!("Starting JSON-RPC server on {}.", http_server); - let server = ServerBuilder::new(io) - .cors(DomainsValidation::AllowOnly(vec![ - AccessControlAllowOrigin::Null, - ])) - .start_http( - &http_server - .parse() - .expect("Invalid HTTP address and port combination"), - ) - .expect("Unable to start RPC server"); - - server.wait(); - - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - - use jsonrpc_core::ErrorCode; - use jsonrpc_test as test_rpc; - use std::io::Error as IoError; - use std::io::ErrorKind; - - #[test] - fn rpc_success() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_success_response", |_| { - Ok(Value::String("success".into())) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!(rpc.request("rpc_success_response", &()), r#""success""#); - } - - // test to ensure correct MissingParams parse error - #[test] - fn rpc_parse_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_parse_error", |_| { - let e = Error { - code: ErrorCode::ParseError, - message: String::from("Parse error"), - data: None, - }; - Err(Error::from(NetworkError::MissingParams(e))) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_parse_error", &()), - r#"{ - "code": -32700, - "message": "Parse error" -}"# - ); - } - - // test to ensure correct Add error response - #[test] - fn rpc_add_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_add_error", |_| { - Err(Error::from(NetworkError::Add { - ssid: "Home".to_string(), - })) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_add_error", &()), - r#"{ - "code": -32000, - "message": "Failed to add network for Home" -}"# - ); - } - - // test to ensure correct Disable error response - #[test] - fn rpc_disable_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_disable_error", |_| { - Err(Error::from(NetworkError::Disable { - id: "0".to_string(), - iface: "wlan0".to_string(), - })) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_disable_error", &()), - r#"{ - "code": -32029, - "message": "Failed to disable network 0 for wlan0" -}"# - ); - } - - // test to ensure correct Disconnect error response - #[test] - fn rpc_disconnect_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_disconnect_error", |_| { - Err(Error::from(NetworkError::Disconnect { - iface: "wlan0".to_string(), - })) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_disconnect_error", &()), - r#"{ - "code": -32032, - "message": "Failed to disconnect wlan0" -}"# - ); - } - - // test to ensure correct GenWpaPassphrase error response - #[test] - fn rpc_genwpapassphrase_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_genwpapassphrase_error", |_| { - Err(Error::from(NetworkError::GenWpaPassphrase { - ssid: "HomeWifi".to_string(), - source: IoError::new(ErrorKind::NotFound, "oh no!"), - })) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_genwpapassphrase_error", &()), - r#"{ - "code": -32025, - "message": "Failed to generate wpa passphrase for HomeWifi: oh no!" -}"# - ); - } - - // test to ensure correct Id error response - #[test] - fn rpc_id_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_id_error", |_| { - Err(Error::from(NetworkError::Id { - iface: "wlan0".to_string(), - ssid: "Home".to_string(), - })) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_id_error", &()), - r#"{ - "code": -32026, - "message": "No ID found for Home on interface wlan0" -}"# - ); - } - - // test to ensure correct NoIp error response - #[test] - fn rpc_noip_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_noip_error", |_| { - Err(Error::from(NetworkError::NoIp { - iface: "wlan7".to_string(), - source: IoError::new(ErrorKind::AddrNotAvailable, "oh no!"), - })) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_noip_error", &()), - r#"{ - "code": -32001, - "message": "Failed to retrieve IP address for wlan7: oh no!" -}"# - ); - } - - // test to ensure correct Rssi error response - #[test] - fn rpc_rssi_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_rssi_error", |_| { - Err(Error::from(NetworkError::Rssi { - iface: "wlan0".to_string(), - })) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_rssi_error", &()), - r#"{ - "code": -32002, - "message": "Failed to retrieve RSSI for wlan0. Interface may not be connected" -}"# - ); - } - - // test to ensure correct RssiPercent error response - #[test] - fn rpc_rssipercent_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_rssipercent_error", |_| { - Err(Error::from(NetworkError::RssiPercent { - iface: "wlan0".to_string(), - })) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_rssipercent_error", &()), - r#"{ - "code": -32034, - "message": "Failed to retrieve signal quality (%) for wlan0. Interface may not be connected" -}"# - ); - } - - // test to ensure correct Ssid error response - #[test] - fn rpc_ssid_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_ssid_error", |_| { - Err(Error::from(NetworkError::Ssid { - iface: "wlan0".to_string(), - })) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_ssid_error", &()), - r#"{ - "code": -32003, - "message": "Failed to retrieve SSID for wlan0. Interface may not be connected" -}"# - ); - } - - // test to ensure correct State error response - #[test] - fn rpc_state_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_state_error", |_| { - Err(Error::from(NetworkError::State { - iface: "wlan1".to_string(), - })) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_state_error", &()), - r#"{ - "code": -32023, - "message": "No state found for wlan1. Interface may not exist" -}"# - ); - } - - // test to ensure correct Traffic error response - #[test] - fn rpc_traffic_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_traffic_error", |_| { - Err(Error::from(NetworkError::Traffic { - iface: "wlan0".to_string(), - })) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_traffic_error", &()), - r#"{ - "code": -32004, - "message": "No network traffic statistics found for wlan0. Interface may not exist" -}"# - ); - } - - // test to ensure correct SavedNetworks error response - #[test] - fn rpc_savednetworks_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_savednetworks_error", |_| { - Err(Error::from(NetworkError::SavedNetworks)) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_savednetworks_error", &()), - r#"{ - "code": -32005, - "message": "No saved networks found" -}"# - ); - } - - // test to ensure correct AvailableNetworks error response - #[test] - fn rpc_availablenetworks_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_availablenetworks_error", |_| { - Err(Error::from(NetworkError::AvailableNetworks { - iface: "wlan0".to_string(), - })) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_availablenetworks_error", &()), - r#"{ - "code": -32006, - "message": "No networks found in range of wlan0" -}"# - ); - } - - // test to ensure correct MissingParams error response - #[test] - fn rpc_missingparams_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_missingparams_error", |_| { - let e = Error { - code: ErrorCode::InvalidParams, - message: String::from( - "Invalid params: invalid type: null, expected struct Iface.", - ), - data: None, - }; - Err(Error::from(NetworkError::MissingParams(e))) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_missingparams_error", &()), - r#"{ - "code": -32602, - "message": "Invalid params: invalid type: null, expected struct Iface." -}"# - ); - } - - // test to ensure correct Modify error response - #[test] - fn rpc_modify_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_modify_error", |_| { - Err(Error::from(NetworkError::Modify { - id: "1".to_string(), - iface: "wlan0".to_string(), - })) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_modify_error", &()), - r#"{ - "code": -32033, - "message": "Failed to set new password for network 1 on wlan0" -}"# - ); - } - - // test to ensure correct Ip error response - #[test] - fn rpc_ip_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_ip_error", |_| { - Err(Error::from(NetworkError::Ip { - iface: "wlan0".to_string(), - })) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_ip_error", &()), - r#"{ - "code": -32007, - "message": "No IP address found for wlan0" -}"# - ); - } - - // test to ensure correct Reassociate error response - #[test] - fn rpc_reassociate_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_reassociate_error", |_| { - Err(Error::from(NetworkError::Reassociate { - iface: "wlan0".to_string(), - })) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_reassociate_error", &()), - r#"{ - "code": -32008, - "message": "Failed to reassociate with WiFi network for wlan0" -}"# - ); - } - - // test to ensure correct Reconfigure error response - #[test] - fn rpc_reconfigure_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_reconfigure_error", |_| { - Err(Error::from(NetworkError::Reconfigure)) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_reconfigure_error", &()), - r#"{ - "code": -32030, - "message": "Failed to force reread of wpa_supplicant configuration file" -}"# - ); - } - - // test to ensure correct Connect error response - #[test] - fn rpc_connect_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_connect_error", |_| { - Err(Error::from(NetworkError::Connect { - id: "0".to_string(), - iface: "wlan0".to_string(), - })) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_connect_error", &()), - r#"{ - "code": -32027, - "message": "Failed to connect to network 0 for wlan0" -}"# - ); - } - - // test to ensure correct Reconnect error response - #[test] - fn rpc_reconnect_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_reconnect_error", |_| { - Err(Error::from(NetworkError::Reconnect { - iface: "wlan0".to_string(), - })) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_reconnect_error", &()), - r#"{ - "code": -32009, - "message": "Failed to reconnect with WiFi network for wlan0" -}"# - ); - } - - // test to ensure correct Regex error response - #[test] - fn rpc_regex_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_regex_error", |_| { - let source = regex::Error::Syntax("oh no!".to_string()); - Err(Error::from(NetworkError::Regex(source))) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_regex_error", &()), - r#"{ - "code": -32010, - "message": "Regex command error: oh no!" -}"# - ); - } - - // test to ensure correct Delete error response - #[test] - fn rpc_delete_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_delete_error", |_| { - Err(Error::from(NetworkError::Delete { - id: "0".to_string(), - iface: "wlan0".to_string(), - })) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_delete_error", &()), - r#"{ - "code": -32028, - "message": "Failed to delete network 0 for wlan0" -}"# - ); - } - - // test to ensure correct WlanState error response - #[test] - fn rpc_wlanstate_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_wlanstate_error", |_| { - let source = IoError::new(ErrorKind::PermissionDenied, "oh no!"); - Err(Error::from(NetworkError::WlanState(source))) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_wlanstate_error", &()), - r#"{ - "code": -32011, - "message": "Failed to retrieve state of wlan0 service: oh no!" -}"# - ); - } - - // test to ensure correct WlanOperstate error response - #[test] - fn rpc_wlanoperstate_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_wlanoperstate_error", |_| { - let source = IoError::new(ErrorKind::PermissionDenied, "oh no!"); - Err(Error::from(NetworkError::WlanOperstate(source))) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_wlanoperstate_error", &()), - r#"{ - "code": -32021, - "message": "Failed to retrieve connection state of wlan0 interface: oh no!" -}"# - ); - } - - // test to ensure correct Save error response - #[test] - fn rpc_save_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_save_error", |_| Err(Error::from(NetworkError::Save))); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_save_error", &()), - r#"{ - "code": -32031, - "message": "Failed to save configuration changes to file" -}"# - ); - } - - // test to ensure correct WpaCtrlOpen error response - #[test] - fn rpc_wpactrlopen_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_wpactrlopen_error", |_| { - let permission_error = IoError::new( - ErrorKind::PermissionDenied, - "Permission denied (os error 13)", - ); - Err(Error::from(NetworkError::WpaCtrl(wpactrl::WpaError::Io( - permission_error, - )))) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_wpactrlopen_error", &()), - r#"{ - "code": -32013, - "message": "WPA control interface failure: Failed to execute the specified command: Permission denied (os error 13)" -}"# - ); - } - - // test to ensure correct WpaCtrlRequest error response - #[test] - fn rpc_wpactrlrequest_error() { - let rpc = { - let mut io = IoHandler::new(); - io.add_method("rpc_wpactrlrequest_error", |_| { - let conn_refused_error = IoError::new(ErrorKind::ConnectionRefused, "oh no!"); - Err(Error::from(NetworkError::WpaCtrl(wpactrl::WpaError::Io( - conn_refused_error, - )))) - }); - test_rpc::Rpc::from(io) - }; - - assert_eq!( - rpc.request("rpc_wpactrlrequest_error", &()), - r#"{ - "code": -32013, - "message": "WPA control interface failure: Failed to execute the specified command: oh no!" -}"# - ); - } -} +pub use crate::error::NetworkError; From a824be53b953021042bd6a2c2882e05b7e13c4d5 Mon Sep 17 00:00:00 2001 From: glyph Date: Mon, 13 Dec 2021 10:55:27 +0200 Subject: [PATCH 12/13] update docs and remove unnecessary structs --- peach-network/README.md | 180 +++------------------------- peach-network/src/network.rs | 224 ++++++++++++----------------------- 2 files changed, 96 insertions(+), 308 deletions(-) diff --git a/peach-network/README.md b/peach-network/README.md index c8babd0..2959f20 100644 --- a/peach-network/README.md +++ b/peach-network/README.md @@ -1,178 +1,32 @@ # peach-network -[![Build Status](https://travis-ci.com/peachcloud/peach-network.svg?branch=master)](https://travis-ci.com/peachcloud/peach-network) ![Generic badge](https://img.shields.io/badge/version-0.2.13-.svg) +![Generic badge](https://img.shields.io/badge/version-0.3.0-.svg) -Networking microservice module for PeachCloud. Query and configure device interfaces using [JSON-RPC](https://www.jsonrpc.org/specification) over http. +Network interface state query and modification library. Interaction with wireless interfaces occurs primarily through the [wpactrl crate](https://docs.rs/wpactrl/0.3.1/wpactrl/) which provides "a pure-Rust lowlevel library for controlling wpasupplicant remotely". This approach is akin to using `wpa_cli` (a WPA command line client). -_Note: This module is a work-in-progress._ +## API Documentation -### JSON-RPC API +API documentation can be built and served with `cargo doc --no-deps --open`. The full set of available data structures and functions is listed in the `peach_network::network` module. A custom error type (`NetworkError`) is also publically exposed for library users; it encapsulates all possible error variants. -Methods for **retrieving data**: +## Example Usage -| Method | Parameters | Description | -| --- | --- | --- | -| `available_networks` | `iface` | List SSID, flags (security), frequency and signal level for all networks in range of given interface | -| `id` | `iface`, `ssid` | Return ID of given SSID | -| `ip` | `iface` | Return IP of given network interface | -| `ping` | | Respond with `success` if microservice is running | -| `rssi` | `iface` | Return average signal strength (dBm) for given interface | -| `rssi_percent` | `iface` | Return average signal strength (%) for given interface | -| `saved_networks` | | List all networks saved in wpasupplicant config | -| `ssid` | `iface` | Return SSID of currently-connected network for given interface | -| `state` | `iface` | Return state of given interface | -| `status` | `iface` | Return status parameters for given interface | -| `traffic` | `iface` | Return network traffic for given interface | +```rust +use peach_network::{network, NetworkError}; -Methods for **modifying state**: +fn main() -> Result<(), NetworkError> { + let ip = network::ip("wlan0")?; + let ssid = network::ssid("wlan0")?; -| Method | Parameters | Description | -| --- | --- | --- | -| `activate_ap` | | Activate WiFi access point (start `wpa_supplicant@ap0.service`) | -| `activate_client` | | Activate WiFi client connection (start `wpa_supplicant@wlan0.service`) | -| `add` | `ssid`, `pass` | Add WiFi credentials to `wpa_supplicant-wlan0.conf` | -| `check_iface` | | Activate WiFi access point if client mode is active without a connection | -| `connect` | `id`, `iface` | Disable other networks and attempt connection with AP represented by given id | -| `delete` | `id`, `iface` | Remove WiFi credentials for given network id and interface | -| `disable` | `id`, `iface` | Disable connection with AP represented by given id | -| `disconnect` | `iface` | Disconnect given interface | -| `modify` | `id`, `iface`, `password` | Set a new password for given network id and interface | -| `reassociate` | `iface` | Reassociate with current AP for given interface | -| `reconfigure` | | Force wpa_supplicant to re-read its configuration file | -| `reconnect` | `iface` | Disconnect and reconnect given interface | -| `save` | | Save configuration changes to `wpa_supplicant-wlan0.conf` | + let new_ap = Wifi { ssid: "Home".to_string(), pass: "SuperSecret".to_string() }; + network::add(new_ap)?; + network::save()?; -### API Documentation + Ok(()) +} +``` -API documentation can be built and served with `cargo doc --no-deps --open`. This set of documentation is intended for developers who wish to work on the project or better understand the API of the `src/network.rs` module. - -### Environment - -The JSON-RPC HTTP server address and port can be configured with the `PEACH_NETWORK_SERVER` environment variable: - -`export PEACH_NETWORK_SERVER=127.0.0.1:5000` - -When not set, the value defaults to `127.0.0.1:5110`. - -Logging is made available with `env_logger`: - -`export RUST_LOG=info` - -Other logging levels include `debug`, `warn` and `error`. - -### Setup - -Clone this repo: - -`git clone https://github.com/peachcloud/peach-network.git` - -Move into the repo and compile: - -`cd peach-network` -`cargo build --release` - -Run the binary (sudo needed to satisfy permission requirements): - -`sudo ./target/release/peach-network` - -### Debian Packaging - -A `systemd` service file and Debian maintainer scripts are included in the `debian` directory, allowing `peach-network` to be easily bundled as a Debian package (`.deb`). The `cargo-deb` [crate](https://crates.io/crates/cargo-deb) can be used to achieve this. - -Install `cargo-deb`: - -`cargo install cargo-deb` - -Move into the repo: - -`cd peach-network` - -Build the package: - -`cargo deb` - -The output will be written to `target/debian/peach-network_0.2.4_arm64.deb` (or similar). - -Build the package (aarch64): - -`cargo deb --target aarch64-unknown-linux-gnu` - -Install the package as follows: - -`sudo dpkg -i target/debian/peach-network_0.2.4_arm64.deb` - -The service will be automatically enabled and started. - -Uninstall the service: - -`sudo apt-get remove peach-network` - -Remove configuration files (not removed with `apt-get remove`): - -`sudo apt-get purge peach-network` - -### Example Usage - -**Retrieve IP address for wlan0** - -With microservice running, open a second terminal window and use `curl` to call server methods: - -`curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "ip", "params" : {"iface": "wlan0" }, "id":1 }' 127.0.0.1:5110` - -Server responds with: - -`{"jsonrpc":"2.0","result":"192.168.1.21","id":1}` - -**Retrieve SSID of connected access point for wlan1** - -`curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "ssid", "params" : {"iface": "wlan1" }, "id":1 }' 127.0.0.1:5110` - -Server response when interface is connected: - -`{"jsonrpc":"2.0","result":"Home","id":1}` - -Server response when interface is not connected: - -`{"jsonrpc":"2.0","error":{"code":-32003,"message":"Failed to retrieve SSID for wlan1. Interface may not be connected."},"id":1}` - -**Retrieve list of SSIDs for all networks in range of wlan0** - -`curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "available_networks", "params" : {"iface": "wlan0" }, "id":1 }' 127.0.0.1:5110` - -Server response when interface is connected: - -`{"jsonrpc":"2.0","result":"[{\"frequency\":\"2412\",\"signal_level\":\"-72\",\"ssid\":\"Home\",\"flags\":\"[WPA2-PSK-CCMP][ESS]\"},{\"frequency\":\"2472\",\"signal_level\":\"-56\",\"ssid\":\"podetium\",\"flags\":\"[WPA2-PSK-CCMP+TKIP][ESS]\"}]","id":1}` - -Server response when interface is not connected: - -`{"jsonrpc":"2.0","error":{"code":-32006,"message":"No networks found in range of wlan0"},"id":1}` - -**Retrieve network traffic statistics for wlan1** - -`curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "traffic", "params" : {"iface": "wlan1" }, "id":1 }' 127.0.0.1:5110` - -Server response if interface exists: - -`{"jsonrpc":"2.0","result":"{\"received\":26396361,\"transmitted\":22352530}","id":1}` - -Server response when interface is not found: - -`{"jsonrpc":"2.0","error":{"code":-32004,"message":"Failed to retrieve network traffic for wlan3. Interface may not be connected"},"id":1}` - -**Retrieve status information for wlan0** - -`curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "status", "params" : {"iface": "wlan0" }, "id":1 }' 127.0.0.1:5110` - -Server response if interface exists: - -`{"jsonrpc":"2.0","result":"{\"address\":\"b8:27:eb:9b:5d:5f\",\"bssid\":\"f4:8c:eb:cd:31:81\",\"freq\":\"2412\",\"group_cipher\":\"CCMP\",\"id\":\"0\",\"ip_address\":\"192.168.0.162\",\"key_mgmt\":\"WPA2-PSK\",\"mode\":\"station\",\"pairwise_cipher\":\"CCMP\",\"ssid\":\"Home\",\"wpa_state\":\"COMPLETED\"}","id":1}` - -Server response when interface is not found: - -`{"jsonrpc":"2.0","error":{"code":-32013,"message":"Failed to open control interface for wpasupplicant: No such file or directory (os error 2)"},"id":1}` - -### Licensing +## Licensing AGPL-3.0 diff --git a/peach-network/src/network.rs b/peach-network/src/network.rs index e579729..1a0874d 100644 --- a/peach-network/src/network.rs +++ b/peach-network/src/network.rs @@ -1,6 +1,6 @@ //! Retrieve network data and modify interface state. //! -//! This module contains the core logic of the `peach-network` microservice and +//! This module contains the core logic of the `peach-network` and //! provides convenience wrappers for a range of `wpasupplicant` commands, //! many of which are ordinarily executed using `wpa_cli` (a WPA command line //! client). @@ -12,7 +12,7 @@ //! system calls to systemd (via `systemctl`). Further networking functionality //! is provided by making system calls to retrieve interface state and write //! access point credentials to `wpa_supplicant-wlan0.conf`. -//! + use std::{ fs::OpenOptions, io::prelude::*, @@ -21,68 +21,67 @@ use std::{ str, }; -use crate::error::NetworkError; use probes::network; + +#[cfg(feature = "miniserde_support")] +use miniserde::{Deserialize, Serialize}; + +#[cfg(feature = "serde_support")] use serde::{Deserialize, Serialize}; +use crate::error::NetworkError; use crate::utils; -/// Network interface name. -#[derive(Debug, Deserialize)] -pub struct Iface { - pub iface: String, -} - -/// Network interface name and network identifier. -#[derive(Debug, Deserialize)] -pub struct IfaceId { - pub iface: String, - pub id: String, -} - -/// Network interface name, network identifier and password. -#[derive(Debug, Deserialize)] -pub struct IfaceIdPass { - pub iface: String, - pub id: String, - pub pass: String, -} - -/// Network interface name and network SSID. -#[derive(Debug, Deserialize)] -pub struct IfaceSsid { - pub iface: String, - pub ssid: String, -} - /// Network SSID. -#[derive(Debug, Serialize)] +#[derive(Debug)] +#[cfg_attr(feature = "miniserde_support", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] pub struct Network { + /// Service Set Identifier (SSID). pub ssid: String, } /// Access point data retrieved via scan. -#[derive(Debug, Serialize)] +#[derive(Debug)] +#[cfg_attr(feature = "miniserde_support", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] pub struct Scan { + /// Frequency. pub frequency: String, + /// Protocol. pub protocol: String, + /// Signal strength. pub signal_level: String, + /// SSID. pub ssid: String, } /// Status data for a network interface. -#[derive(Debug, Serialize)] +#[derive(Debug)] +#[cfg_attr(feature = "miniserde_support", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] pub struct Status { + /// MAC address. pub address: Option, + /// Basic Service Set Identifier (BSSID). pub bssid: Option, + /// Frequency. pub freq: Option, + /// Group cipher. pub group_cipher: Option, + /// Local ID. pub id: Option, + /// IP address. pub ip_address: Option, + /// Key management. pub key_mgmt: Option, + /// Mode. pub mode: Option, + /// Pairwise cipher. pub pairwise_cipher: Option, + /// SSID. pub ssid: Option, + /// WPA state. pub wpa_state: Option, } @@ -105,24 +104,27 @@ impl Status { } /// Received and transmitted network traffic (bytes). -#[derive(Debug, Serialize)] +#[derive(Debug)] +#[cfg_attr(feature = "miniserde_support", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] pub struct Traffic { + /// Total bytes received. pub received: u64, + /// Total bytes transmitted. pub transmitted: u64, } /// SSID and password for a wireless access point. -#[derive(Debug, Deserialize)] +#[derive(Debug)] +#[cfg_attr(feature = "miniserde_support", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] pub struct WiFi { + /// SSID. pub ssid: String, + /// Password. pub pass: String, } -// TODO: wrap this into a helper function: -// -// let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); -// let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; - /* GET - Methods for retrieving data */ /// Retrieve list of available wireless access points for a given network @@ -133,15 +135,11 @@ pub struct WiFi { /// * `iface` - A string slice holding the name of a wireless network interface /// /// If the scan results include one or more access points for the given network -/// interface, an `Ok` `Result` type is returned containing `Some(String)` - -/// where `String` is a serialized vector of `Scan` structs containing -/// data for the in-range access points. If no access points are found, -/// a `None` type is returned in the `Result`. In the event of an error, a -/// `NetworkError` is returned in the `Result`. The `NetworkError` is then -/// enumerated to a specific error type and an appropriate JSON RPC response is -/// sent to the caller. -/// -pub fn available_networks(iface: &str) -> Result, NetworkError> { +/// interface, an `Ok` `Result` type is returned containing `Some(Vec)`. +/// The vector of `Scan` structs contains data for the in-range access points. +/// If no access points are found, a `None` type is returned in the `Result`. +/// In the event of an error, a `NetworkError` is returned in the `Result`. +pub fn available_networks(iface: &str) -> Result>, NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; wpa.request("SCAN")?; @@ -176,8 +174,7 @@ pub fn available_networks(iface: &str) -> Result, NetworkError> { if scan.is_empty() { Ok(None) } else { - let results = serde_json::to_string(&scan)?; - Ok(Some(results)) + Ok(Some(scan)) } } @@ -193,10 +190,7 @@ pub fn available_networks(iface: &str) -> Result, NetworkError> { /// found in the list of saved networks, an `Ok` `Result` type is returned /// containing `Some(String)` - where `String` is the network identifier. /// If no match is found, a `None` type is returned in the `Result`. In the -/// event of an error, a `NetworkError` is returned in the `Result`. The -/// `NetworkError` is then enumerated to a specific error type and an -/// appropriate JSON RPC response is sent to the caller. -/// +/// event of an error, a `NetworkError` is returned in the `Result`. pub fn id(iface: &str, ssid: &str) -> Result, NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; @@ -228,10 +222,7 @@ pub fn id(iface: &str, ssid: &str) -> Result, NetworkError> { /// an `Ok` `Result` type is returned containing `Some(String)` - where `String` /// is the IP address of the interface. If no match is found, a `None` type is /// returned in the `Result`. In the event of an error, a `NetworkError` is -/// returned in the `Result`. The `NetworkError` is then enumerated to a -/// specific error type and an appropriate JSON RPC response is sent to the -/// caller. -/// +/// returned in the `Result`. pub fn ip(iface: &str) -> Result, NetworkError> { let net_if: String = iface.to_string(); let ifaces = get_if_addrs::get_if_addrs().map_err(|source| NetworkError::NoIp { @@ -258,9 +249,7 @@ pub fn ip(iface: &str) -> Result, NetworkError> { /// is the RSSI (Received Signal Strength Indicator) of the connection measured /// in dBm. If signal strength is not found, a `None` type is returned in the /// `Result`. In the event of an error, a `NetworkError` is returned in the -/// `Result`. The `NetworkError` is then enumerated to a specific error type and -/// an appropriate JSON RPC response is sent to the caller. -/// +/// `Result`. pub fn rssi(iface: &str) -> Result, NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; @@ -287,9 +276,7 @@ pub fn rssi(iface: &str) -> Result, NetworkError> { /// is the RSSI (Received Signal Strength Indicator) of the connection measured /// as a percentage. If signal strength is not found, a `None` type is returned /// in the `Result`. In the event of an error, a `NetworkError` is returned in -/// the `Result`. The `NetworkError` is then enumerated to a specific error type -/// and an appropriate JSON RPC response is sent to the caller. -/// +/// the `Result`. pub fn rssi_percent(iface: &str) -> Result, NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; @@ -319,14 +306,11 @@ pub fn rssi_percent(iface: &str) -> Result, NetworkError> { /// /// If the wpasupplicant configuration file contains credentials for one or /// more access points, an `Ok` `Result` type is returned containing -/// `Some(String)` - where `String` is a serialized vector of `Network` structs -/// containing the SSIDs of all saved networks. If no network credentials are -/// found, a `None` type is returned in the `Result`. In the event of an error, -/// a `NetworkError` is returned in the `Result`. The `NetworkError` is then -/// enumerated to a specific error type and an appropriate JSON RPC response is -/// sent to the caller. -/// -pub fn saved_networks() -> Result, NetworkError> { +/// `Some(Vec)`. The vector of `Network` structs contains the SSIDs +/// of all saved networks. If no network credentials are found, a `None` type +/// is returned in the `Result`. In the event of an error, a `NetworkError` is +/// returned in the `Result`. +pub fn saved_networks() -> Result>, NetworkError> { let mut wpa = wpactrl::WpaCtrl::builder().open()?; let networks = wpa.request("LIST_NETWORKS")?; let mut ssids = Vec::new(); @@ -343,8 +327,7 @@ pub fn saved_networks() -> Result, NetworkError> { if ssids.is_empty() { Ok(None) } else { - let results = serde_json::to_string(&ssids)?; - Ok(Some(results)) + Ok(Some(ssids)) } } @@ -358,10 +341,7 @@ pub fn saved_networks() -> Result, NetworkError> { /// an `Ok` `Result` type is returned containing `Some(String)` - where `String` /// is the SSID of the associated network. If SSID is not found, a `None` type /// is returned in the `Result`. In the event of an error, a `NetworkError` is -/// returned in the `Result`. The `NetworkError` is then enumerated to a -/// specific error type and an appropriate JSON RPC response is sent to the -/// caller. -/// +/// returned in the `Result`. pub fn ssid(iface: &str) -> Result, NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; @@ -383,9 +363,7 @@ pub fn ssid(iface: &str) -> Result, NetworkError> { /// returned containing `Some(String)` - where `String` is the state of the /// network interface. If state is not found, a `None` type is returned in the /// `Result`. In the event of an error, a `NetworkError` is returned in the -/// `Result`. The `NetworkError` is then enumerated to a specific error type and -/// an appropriate JSON RPC response is sent to the caller. -/// +/// `Result`. pub fn state(iface: &str) -> Result, NetworkError> { // construct the interface operstate path let iface_path: String = format!("/sys/class/net/{}/operstate", iface); @@ -419,10 +397,7 @@ pub fn state(iface: &str) -> Result, NetworkError> { /// returned containing `Some(Status)` - where `Status` is a `struct` /// containing the aggregated interface data in named fields. If status is not /// found, a `None` type is returned in the `Result`. In the event of an error, -/// a `NetworkError` is returned in the `Result`. The `NetworkError` is then -/// enumerated to a specific error type and an appropriate JSON RPC response is -/// sent to the caller. -/// +/// a `NetworkError` is returned in the `Result`. pub fn status(iface: &str) -> Result, NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; @@ -475,15 +450,12 @@ pub fn status(iface: &str) -> Result, NetworkError> { /// * `iface` - A string slice holding the name of a wireless network interface /// /// If the network traffic statistics are found for the given interface, an `Ok` -/// `Result` type is returned containing `Some(String)` - where `String` is a -/// serialized `Traffic` `struct` with fields for received and transmitted -/// network data statistics. If network traffic statistics are not found for the -/// given interface, a `None` type is returned in the `Result`. In the event of -/// an error, a `NetworkError` is returned in the `Result`. The `NetworkError` -/// is then enumerated to a specific error type and an appropriate JSON RPC -/// response is sent to the caller. -/// -pub fn traffic(iface: &str) -> Result, NetworkError> { +/// `Result` type is returned containing `Some(Traffic)`. The `Traffic` `struct` +/// includes fields for received and transmitted network data statistics. If +/// network traffic statistics are not found for the given interface, a `None` +/// type is returned in the `Result`. In the event of an error, a `NetworkError` +/// is returned in the `Result`. +pub fn traffic(iface: &str) -> Result, NetworkError> { let network = network::read().map_err(|source| NetworkError::NoTraffic { iface: iface.to_string(), source, @@ -497,9 +469,7 @@ pub fn traffic(iface: &str) -> Result, NetworkError> { received, transmitted, }; - // TODO: add test for SerdeSerialize error - let t = serde_json::to_string(&traffic)?; - return Ok(Some(t)); + return Ok(Some(traffic)); } } @@ -513,9 +483,6 @@ pub fn traffic(iface: &str) -> Result, NetworkError> { /// A `systemctl `command is invoked which starts the `ap0` interface service. /// If the command executes successfully, an `Ok` `Result` type is returned. /// In the event of an error, a `NetworkError` is returned in the `Result`. -/// The `NetworkError` is then enumerated to a specific error type and an -/// appropriate JSON RPC response is sent to the caller. -/// pub fn activate_ap() -> Result<(), NetworkError> { // start the ap0 interface service Command::new("sudo") @@ -533,9 +500,6 @@ pub fn activate_ap() -> Result<(), NetworkError> { /// A `systemctl` command is invoked which starts the `wlan0` interface service. /// If the command executes successfully, an `Ok` `Result` type is returned. /// In the event of an error, a `NetworkError` is returned in the `Result`. -/// The `NetworkError` is then enumerated to a specific error type and an -/// appropriate JSON RPC response is sent to the caller. -/// pub fn activate_client() -> Result<(), NetworkError> { // start the wlan0 interface service Command::new("sudo") @@ -557,10 +521,7 @@ pub fn activate_client() -> Result<(), NetworkError> { /// If configuration parameters are successfully generated from the provided /// SSID and password and appended to `wpa_supplicant-wlan0.conf`, an `Ok` /// `Result` type is returned. In the event of an error, a `NetworkError` is -/// returned in the `Result`. The `NetworkError` is then enumerated to a -/// specific error type and an appropriate JSON RPC response is sent to the -/// caller. -/// +/// returned in the `Result`. pub fn add(wifi: &WiFi) -> Result<(), NetworkError> { // generate configuration based on provided ssid & password let output = Command::new("wpa_passphrase") @@ -609,7 +570,6 @@ pub fn add(wifi: &WiFi) -> Result<(), NetworkError> { /// are checked. If the service is active but the interface is down (ie. not /// currently connected to an access point), then the access point is activated /// by calling the `activate_ap()` function. -/// pub fn check_iface() -> Result<(), NetworkError> { // returns 0 if the service is currently active let wlan0_status = Command::new("/usr/bin/systemctl") @@ -646,10 +606,7 @@ pub fn check_iface() -> Result<(), NetworkError> { /// If the network connection is successfully activated for the access point /// represented by the given network identifier on the given wireless interface, /// an `Ok` `Result`type is returned. In the event of an error, a `NetworkError` -/// is returned in the `Result`. The `NetworkError` is then enumerated to a -/// specific error type and an appropriate JSON RPC response is sent to the -/// caller. -/// +/// is returned in the `Result`. pub fn connect(id: &str, iface: &str) -> Result<(), NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; @@ -668,10 +625,7 @@ pub fn connect(id: &str, iface: &str) -> Result<(), NetworkError> { /// If the network configuration parameters are successfully deleted for /// the access point represented by the given network identifier, an `Ok` /// `Result`type is returned. In the event of an error, a `NetworkError` is -/// returned in the `Result`. The `NetworkError` is then enumerated to a -/// specific error type and an appropriate JSON RPC response is sent to the -/// caller. -/// +/// returned in the `Result`. pub fn delete(id: &str, iface: &str) -> Result<(), NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; @@ -690,9 +644,7 @@ pub fn delete(id: &str, iface: &str) -> Result<(), NetworkError> { /// If the network connection is successfully disabled for the access point /// represented by the given network identifier, an `Ok` `Result`type is /// returned. In the event of an error, a `NetworkError` is returned in the -/// `Result`. The `NetworkError` is then enumerated to a specific error type and -/// an appropriate JSON RPC response is sent to the caller. -/// +/// `Result`. pub fn disable(id: &str, iface: &str) -> Result<(), NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; @@ -709,10 +661,7 @@ pub fn disable(id: &str, iface: &str) -> Result<(), NetworkError> { /// /// If the network connection is successfully disconnected for the given /// wireless interface, an `Ok` `Result` type is returned. In the event of an -/// error, a `NetworkError` is returned in the `Result`. The `NetworkError` is -/// then enumerated to a specific error type and an appropriate JSON RPC -/// response is sent to the caller. -/// +/// error, a `NetworkError` is returned in the `Result`. pub fn disconnect(iface: &str) -> Result<(), NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; @@ -731,10 +680,7 @@ pub fn disconnect(iface: &str) -> Result<(), NetworkError> { /// /// If the password is successfully updated for the access point represented by /// the given network identifier, an `Ok` `Result` type is returned. In the -/// event of an error, a `NetworkError` is returned in the `Result`. The -/// `NetworkError` is then enumerated to a specific error type and an -/// appropriate JSON RPC response is sent to the caller. -/// +/// event of an error, a `NetworkError` is returned in the `Result`. pub fn modify(id: &str, iface: &str, pass: &str) -> Result<(), NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; @@ -751,10 +697,7 @@ pub fn modify(id: &str, iface: &str, pass: &str) -> Result<(), NetworkError> { /// /// If the network connection is successfully reassociated for the given /// wireless interface, an `Ok` `Result` type is returned. In the event of an -/// error, a `NetworkError` is returned in the `Result`. The `NetworkError` is -/// then enumerated to a specific error type and an appropriate JSON RPC -/// response is sent to the caller. -/// +/// error, a `NetworkError` is returned in the `Result`. pub fn reassociate(iface: &str) -> Result<(), NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; @@ -767,10 +710,7 @@ pub fn reassociate(iface: &str) -> Result<(), NetworkError> { /// If the reconfigure command is successfully executed, indicating a reread /// of the `wpa_supplicant.conf` file by the `wpa_supplicant` process, an `Ok` /// `Result` type is returned. In the event of an error, a `NetworkError` is -/// returned in the `Result`. The `NetworkError` is then enumerated to a -/// specific error type and an appropriate JSON RPC response is sent to the -/// caller. -/// +/// returned in the `Result`. pub fn reconfigure() -> Result<(), NetworkError> { let mut wpa = wpactrl::WpaCtrl::builder().open()?; wpa.request("RECONFIGURE")?; @@ -785,10 +725,7 @@ pub fn reconfigure() -> Result<(), NetworkError> { /// /// If the network connection is successfully disconnected and reconnected for /// the given wireless interface, an `Ok` `Result` type is returned. In the -/// event of an error, a `NetworkError` is returned in the `Result`. The -/// `NetworkError` is then enumerated to a specific error type and an -/// appropriate JSON RPC response is sent to the caller. -/// +/// event of an error, a `NetworkError` is returned in the `Result`. pub fn reconnect(iface: &str) -> Result<(), NetworkError> { let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?; @@ -801,10 +738,7 @@ pub fn reconnect(iface: &str) -> Result<(), NetworkError> { /// /// If wireless network configuration updates are successfully save to the /// `wpa_supplicant.conf` file, an `Ok` `Result` type is returned. In the -/// event of an error, a `NetworkError` is returned in the `Result`. The -/// `NetworkError` is then enumerated to a specific error type and an -/// appropriate JSON RPC response is sent to the caller. -/// +/// event of an error, a `NetworkError` is returned in the `Result`. pub fn save() -> Result<(), NetworkError> { let mut wpa = wpactrl::WpaCtrl::builder().open()?; wpa.request("SAVE_CONFIG")?; From 1986d31461d02716b7fea7667c65b983d93e33a9 Mon Sep 17 00:00:00 2001 From: glyph Date: Mon, 13 Dec 2021 11:00:16 +0200 Subject: [PATCH 13/13] feature flag docs and license --- peach-network/Cargo.toml | 2 +- peach-network/README.md | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/peach-network/Cargo.toml b/peach-network/Cargo.toml index 502a719..44987c7 100644 --- a/peach-network/Cargo.toml +++ b/peach-network/Cargo.toml @@ -7,7 +7,7 @@ description = "Query and configure network interfaces." homepage = "https://opencollective.com/peachcloud" repository = "ihttps://git.coopcloud.tech/PeachCloud/peach-workspace/src/branch/main/peach-network" readme = "README.md" -license = "AGPL-3.0-only" +license = "LGPL-3.0-only" publish = false [badges] diff --git a/peach-network/README.md b/peach-network/README.md index 2959f20..4b2ea7c 100644 --- a/peach-network/README.md +++ b/peach-network/README.md @@ -27,6 +27,16 @@ fn main() -> Result<(), NetworkError> { } ``` -## Licensing +## Feature Flags -AGPL-3.0 +Feature flags are used to offer `Serialize` and `Deserialize` implementations for all `struct` data types provided by this library. These traits are not provided by default. A choice of `miniserde` and `serde` is provided. + +Define the desired feature in the `Cargo.toml` manifest of your project: + +```toml +peach-network = { version = "0.3.0", features = ["miniserde_support"] } +``` + +## License + +LGPL-3.0.