forked from PeachCloud/peach-workspace
1071 lines
38 KiB
Rust
1071 lines
38 KiB
Rust
use log::{debug, warn};
|
|
|
|
use rocket::{
|
|
form::{Form, FromForm},
|
|
get, post,
|
|
request::FlashMessage,
|
|
response::{Flash, Redirect},
|
|
serde::{
|
|
json::{json, Json, Value},
|
|
Deserialize, Serialize,
|
|
},
|
|
uri, UriDisplayQuery,
|
|
};
|
|
use rocket_dyn_templates::Template;
|
|
use std::collections::HashMap;
|
|
|
|
use peach_lib::network_client;
|
|
use peach_lib::network_client::{AccessPoint, Networks, Scan};
|
|
use peach_lib::stats_client::Traffic;
|
|
|
|
use crate::routes::authentication::Authenticated;
|
|
use crate::utils::build_json_response;
|
|
use crate::utils::monitor;
|
|
use crate::utils::monitor::{Alert, Data, Threshold};
|
|
|
|
// STRUCTS USED BY NETWORK ROUTES
|
|
|
|
#[derive(Debug, Deserialize, FromForm, UriDisplayQuery)]
|
|
pub struct Ssid {
|
|
pub ssid: String,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, FromForm)]
|
|
pub struct WiFi {
|
|
pub ssid: String,
|
|
pub pass: String,
|
|
}
|
|
|
|
// HELPERS AND ROUTES FOR /settings/network/wifi/usage/reset
|
|
|
|
#[get("/wifi/usage/reset")]
|
|
pub fn wifi_usage_reset(_auth: Authenticated) -> Flash<Redirect> {
|
|
let url = uri!(wifi_usage);
|
|
match monitor::reset_data() {
|
|
Ok(_) => Flash::success(Redirect::to(url), "Reset stored network traffic total"),
|
|
Err(_) => Flash::error(
|
|
Redirect::to(url),
|
|
"Failed to reset stored network traffic total",
|
|
),
|
|
}
|
|
}
|
|
|
|
#[post("/wifi/connect", data = "<network>")]
|
|
pub fn connect_wifi(network: Form<Ssid>, _auth: Authenticated) -> Flash<Redirect> {
|
|
let ssid = &network.ssid;
|
|
let url = uri!(network_detail(ssid = ssid));
|
|
match network_client::id("wlan0", ssid) {
|
|
Ok(id) => match network_client::connect(&id, "wlan0") {
|
|
Ok(_) => Flash::success(Redirect::to(url), "Connected to chosen network"),
|
|
Err(_) => Flash::error(Redirect::to(url), "Failed to connect to chosen network"),
|
|
},
|
|
Err(_) => Flash::error(Redirect::to(url), "Failed to retrieve the network ID"),
|
|
}
|
|
}
|
|
|
|
#[post("/wifi/disconnect", data = "<network>")]
|
|
pub fn disconnect_wifi(network: Form<Ssid>, _auth: Authenticated) -> Flash<Redirect> {
|
|
let ssid = &network.ssid;
|
|
let url = uri!(network_home);
|
|
match network_client::disable("wlan0", ssid) {
|
|
Ok(_) => Flash::success(Redirect::to(url), "Disconnected from WiFi network"),
|
|
Err(_) => Flash::error(Redirect::to(url), "Failed to disconnect from WiFi network"),
|
|
}
|
|
}
|
|
|
|
#[post("/wifi/forget", data = "<network>")]
|
|
pub fn forget_wifi(network: Form<Ssid>, _auth: Authenticated) -> Flash<Redirect> {
|
|
let ssid = &network.ssid;
|
|
let url = uri!(network_home);
|
|
match network_client::forget("wlan0", ssid) {
|
|
Ok(_) => Flash::success(Redirect::to(url), "WiFi credentials removed"),
|
|
Err(_) => Flash::error(
|
|
Redirect::to(url),
|
|
"Failed to remove WiFi credentials".to_string(),
|
|
),
|
|
}
|
|
}
|
|
|
|
#[get("/wifi/modify?<ssid>")]
|
|
pub fn wifi_password(ssid: &str, flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
|
|
let mut context = NetworkAddContext {
|
|
back: Some("/settings/network/wifi".to_string()),
|
|
flash_name: None,
|
|
flash_msg: None,
|
|
selected: Some(ssid.to_string()),
|
|
title: Some("Update WiFi Password".to_string()),
|
|
};
|
|
// check to see if there is a flash message to display
|
|
if let Some(flash) = flash {
|
|
// add flash message contents to the context object
|
|
context.flash_name = Some(flash.kind().to_string());
|
|
context.flash_msg = Some(flash.message().to_string());
|
|
};
|
|
// template_dir is set in Rocket.toml
|
|
Template::render("settings/network/modify_ap", &context)
|
|
}
|
|
|
|
#[post("/wifi/modify", data = "<wifi>")]
|
|
pub fn wifi_set_password(wifi: Form<WiFi>, _auth: Authenticated) -> Flash<Redirect> {
|
|
let ssid = &wifi.ssid;
|
|
let pass = &wifi.pass;
|
|
let url = uri!(network_detail(ssid = ssid));
|
|
match network_client::update("wlan0", ssid, pass) {
|
|
Ok(_) => Flash::success(Redirect::to(url), "WiFi password updated".to_string()),
|
|
Err(_) => Flash::error(
|
|
Redirect::to(url),
|
|
"Failed to update WiFi password".to_string(),
|
|
),
|
|
}
|
|
}
|
|
|
|
// HELPERS AND ROUTES FOR /settings/network
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct NetworkContext {
|
|
pub ap_ip: String,
|
|
pub ap_ssid: String,
|
|
pub ap_state: String,
|
|
pub ap_traffic: Option<Traffic>,
|
|
pub wlan_ip: String,
|
|
pub wlan_rssi: Option<String>,
|
|
pub wlan_scan: Option<Vec<Scan>>,
|
|
pub wlan_ssid: String,
|
|
pub wlan_state: String,
|
|
pub wlan_status: String,
|
|
pub wlan_traffic: Option<Traffic>,
|
|
pub flash_name: Option<String>,
|
|
pub flash_msg: Option<String>,
|
|
// allows for passing in the ssid of a chosen access point
|
|
// this is used in the network_detail template
|
|
pub selected: Option<String>,
|
|
// page title for header in navbar
|
|
pub title: Option<String>,
|
|
// url for back-arrow link
|
|
pub back: Option<String>,
|
|
}
|
|
|
|
impl NetworkContext {
|
|
pub fn build() -> NetworkContext {
|
|
let ap_ip = match network_client::ip("ap0") {
|
|
Ok(ip) => ip,
|
|
Err(_) => "x.x.x.x".to_string(),
|
|
};
|
|
let ap_ssid = match network_client::ssid("ap0") {
|
|
Ok(ssid) => ssid,
|
|
Err(_) => "Not currently activated".to_string(),
|
|
};
|
|
let ap_state = match network_client::state("ap0") {
|
|
Ok(state) => state,
|
|
Err(_) => "Interface unavailable".to_string(),
|
|
};
|
|
let ap_traffic = match network_client::traffic("ap0") {
|
|
Ok(traffic) => {
|
|
let mut t = traffic;
|
|
// modify traffic values & assign measurement unit
|
|
// based on received and transmitted values
|
|
// if received > 999 MB, convert it to GB
|
|
if t.received > 1_047_527_424 {
|
|
t.received /= 1_073_741_824;
|
|
t.rx_unit = Some("GB".to_string());
|
|
} else if t.received > 0 {
|
|
// otherwise, convert it to MB
|
|
t.received = (t.received / 1024) / 1024;
|
|
t.rx_unit = Some("MB".to_string());
|
|
} else {
|
|
t.received = 0;
|
|
t.rx_unit = Some("MB".to_string());
|
|
}
|
|
|
|
if t.transmitted > 1_047_527_424 {
|
|
t.transmitted /= 1_073_741_824;
|
|
t.tx_unit = Some("GB".to_string());
|
|
} else if t.transmitted > 0 {
|
|
t.transmitted = (t.transmitted / 1024) / 1024;
|
|
t.tx_unit = Some("MB".to_string());
|
|
} else {
|
|
t.transmitted = 0;
|
|
t.tx_unit = Some("MB".to_string());
|
|
}
|
|
Some(t)
|
|
}
|
|
Err(_) => None,
|
|
};
|
|
let wlan_ip = match network_client::ip("wlan0") {
|
|
Ok(ip) => ip,
|
|
Err(_) => "x.x.x.x".to_string(),
|
|
};
|
|
let wlan_rssi = match network_client::rssi_percent("wlan0") {
|
|
Ok(rssi) => Some(rssi),
|
|
Err(_) => None,
|
|
};
|
|
let wlan_scan = match network_client::available_networks("wlan0") {
|
|
Ok(networks) => {
|
|
let scan: Vec<Scan> = serde_json::from_str(networks.as_str())
|
|
.expect("Failed to deserialize scan_networks response");
|
|
Some(scan)
|
|
}
|
|
Err(_) => None,
|
|
};
|
|
let wlan_ssid = match network_client::ssid("wlan0") {
|
|
Ok(ssid) => ssid,
|
|
Err(_) => "Not connected".to_string(),
|
|
};
|
|
let wlan_state = match network_client::state("wlan0") {
|
|
Ok(state) => state,
|
|
Err(_) => "Interface unavailable".to_string(),
|
|
};
|
|
let wlan_status = match network_client::status("wlan0") {
|
|
Ok(status) => status,
|
|
Err(_) => "Interface unavailable".to_string(),
|
|
};
|
|
let wlan_traffic = match network_client::traffic("wlan0") {
|
|
Ok(traffic) => {
|
|
let mut t = traffic;
|
|
// modify traffic values & assign measurement unit
|
|
// based on received and transmitted values
|
|
// if received > 999 MB, convert it to GB
|
|
if t.received > 1_047_527_424 {
|
|
t.received /= 1_073_741_824;
|
|
t.rx_unit = Some("GB".to_string());
|
|
} else if t.received > 0 {
|
|
// otherwise, convert it to MB
|
|
t.received = (t.received / 1024) / 1024;
|
|
t.rx_unit = Some("MB".to_string());
|
|
} else {
|
|
t.received = 0;
|
|
t.rx_unit = Some("MB".to_string());
|
|
}
|
|
|
|
if t.transmitted > 1_047_527_424 {
|
|
t.transmitted /= 1_073_741_824;
|
|
t.tx_unit = Some("GB".to_string());
|
|
} else if t.transmitted > 0 {
|
|
t.transmitted = (t.transmitted / 1024) / 1024;
|
|
t.tx_unit = Some("MB".to_string());
|
|
} else {
|
|
t.transmitted = 0;
|
|
t.tx_unit = Some("MB".to_string());
|
|
}
|
|
Some(t)
|
|
}
|
|
Err(_) => None,
|
|
};
|
|
|
|
NetworkContext {
|
|
ap_ip,
|
|
ap_ssid,
|
|
ap_state,
|
|
ap_traffic,
|
|
wlan_ip,
|
|
wlan_rssi,
|
|
wlan_scan,
|
|
wlan_ssid,
|
|
wlan_state,
|
|
wlan_status,
|
|
wlan_traffic,
|
|
flash_name: None,
|
|
flash_msg: None,
|
|
selected: None,
|
|
title: None,
|
|
back: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[get("/")]
|
|
pub fn network_home(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
|
|
// assign context through context_builder call
|
|
let mut context = NetworkContext::build();
|
|
// set back button (nav) url
|
|
context.back = Some("/settings".to_string());
|
|
// set page title
|
|
context.title = Some("Network Configuration".to_string());
|
|
// check to see if there is a flash message to display
|
|
if let Some(flash) = flash {
|
|
// add flash message contents to the context object
|
|
context.flash_name = Some(flash.kind().to_string());
|
|
context.flash_msg = Some(flash.message().to_string());
|
|
};
|
|
// template_dir is set in Rocket.toml
|
|
Template::render("settings/network/menu", &context)
|
|
}
|
|
|
|
// HELPERS AND ROUTES FOR /settings/network/ap/activate
|
|
|
|
#[get("/ap/activate")]
|
|
pub fn deploy_ap(_auth: Authenticated) -> Flash<Redirect> {
|
|
// activate the wireless access point
|
|
debug!("Activating WiFi access point.");
|
|
match network_client::activate_ap() {
|
|
Ok(_) => Flash::success(
|
|
Redirect::to("/settings/network"),
|
|
"Activated WiFi access point",
|
|
),
|
|
Err(_) => Flash::error(
|
|
Redirect::to("/settings/network"),
|
|
"Failed to activate WiFi access point",
|
|
),
|
|
}
|
|
}
|
|
|
|
// HELPERS AND ROUTES FOR /settings/network/wifi
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct NetworkListContext {
|
|
pub ap_state: String,
|
|
pub back: Option<String>,
|
|
pub flash_name: Option<String>,
|
|
pub flash_msg: Option<String>,
|
|
pub title: Option<String>,
|
|
pub wlan_networks: HashMap<String, String>,
|
|
pub wlan_ssid: String,
|
|
}
|
|
|
|
impl NetworkListContext {
|
|
pub fn build() -> NetworkListContext {
|
|
// list of networks saved in the wpa_supplicant.conf
|
|
let wlan_list = match network_client::saved_networks() {
|
|
Ok(ssids) => {
|
|
let networks: Vec<Networks> = serde_json::from_str(ssids.as_str())
|
|
.expect("Failed to deserialize scan_list response");
|
|
networks
|
|
}
|
|
Err(_) => Vec::new(),
|
|
};
|
|
|
|
// list of networks currently in range (online & accessible)
|
|
let wlan_scan = match network_client::available_networks("wlan0") {
|
|
Ok(networks) => {
|
|
let scan: Vec<Networks> = serde_json::from_str(networks.as_str())
|
|
.expect("Failed to deserialize scan_networks response");
|
|
scan
|
|
}
|
|
Err(_) => Vec::new(),
|
|
};
|
|
|
|
let wlan_ssid = match network_client::ssid("wlan0") {
|
|
Ok(ssid) => ssid,
|
|
Err(_) => "Not connected".to_string(),
|
|
};
|
|
|
|
// create a hashmap to combine wlan_list & wlan_scan without repetition
|
|
let mut wlan_networks = HashMap::new();
|
|
for ap in wlan_scan {
|
|
wlan_networks.insert(ap.ssid, "Available".to_string());
|
|
}
|
|
for network in wlan_list {
|
|
// insert ssid (with state) only if it doesn't already exist
|
|
wlan_networks
|
|
.entry(network.ssid)
|
|
.or_insert_with(|| "Not in range".to_string());
|
|
}
|
|
|
|
let ap_state = match network_client::state("ap0") {
|
|
Ok(state) => state,
|
|
Err(_) => "Interface unavailable".to_string(),
|
|
};
|
|
|
|
NetworkListContext {
|
|
ap_state,
|
|
back: None,
|
|
flash_msg: None,
|
|
flash_name: None,
|
|
title: None,
|
|
wlan_networks,
|
|
wlan_ssid,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[get("/wifi")]
|
|
pub fn wifi_list(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
|
|
// assign context through context_builder call
|
|
let mut context = NetworkListContext::build();
|
|
context.back = Some("/settings/network".to_string());
|
|
context.title = Some("WiFi Networks".to_string());
|
|
// check to see if there is a flash message to display
|
|
if let Some(flash) = flash {
|
|
// add flash message contents to the context object
|
|
context.flash_name = Some(flash.kind().to_string());
|
|
context.flash_msg = Some(flash.message().to_string());
|
|
};
|
|
// template_dir is set in Rocket.toml
|
|
Template::render("settings/network/list_aps", &context)
|
|
}
|
|
|
|
// HELPERS AND ROUTES FOR /settings/network/wifi<ssid>
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct NetworkDetailContext {
|
|
pub back: Option<String>,
|
|
pub flash_name: Option<String>,
|
|
pub flash_msg: Option<String>,
|
|
pub saved_aps: Vec<Networks>,
|
|
pub selected: Option<String>,
|
|
pub title: Option<String>,
|
|
pub wlan_ip: String,
|
|
pub wlan_networks: HashMap<String, AccessPoint>,
|
|
pub wlan_rssi: Option<String>,
|
|
pub wlan_ssid: String,
|
|
pub wlan_state: String,
|
|
pub wlan_status: String,
|
|
pub wlan_traffic: Option<Traffic>,
|
|
}
|
|
|
|
impl NetworkDetailContext {
|
|
pub fn build() -> NetworkDetailContext {
|
|
let wlan_ip = match network_client::ip("wlan0") {
|
|
Ok(ip) => ip,
|
|
Err(_) => "x.x.x.x".to_string(),
|
|
};
|
|
// list of networks saved in wpa_supplicant.conf
|
|
let wlan_list = match network_client::saved_networks() {
|
|
Ok(ssids) => {
|
|
let networks: Vec<Networks> = serde_json::from_str(ssids.as_str())
|
|
.expect("Failed to deserialize scan_list response");
|
|
networks
|
|
}
|
|
Err(_) => Vec::new(),
|
|
};
|
|
// list of networks saved in wpa_supplicant.conf
|
|
// HACK: we're running the same function twice (wlan_list)
|
|
// see if we can implement clone for Vec<Networks> instead
|
|
let saved_aps = match network_client::saved_networks() {
|
|
Ok(ssids) => {
|
|
let networks: Vec<Networks> = serde_json::from_str(ssids.as_str())
|
|
.expect("Failed to deserialize scan_list response");
|
|
networks
|
|
}
|
|
Err(_) => Vec::new(),
|
|
};
|
|
let wlan_rssi = match network_client::rssi_percent("wlan0") {
|
|
Ok(rssi) => Some(rssi),
|
|
Err(_) => None,
|
|
};
|
|
// list of networks currently in range (online & accessible)
|
|
let wlan_scan = match network_client::available_networks("wlan0") {
|
|
Ok(networks) => {
|
|
let scan: Vec<Scan> = serde_json::from_str(networks.as_str())
|
|
.expect("Failed to deserialize scan_networks response");
|
|
scan
|
|
}
|
|
Err(_) => Vec::new(),
|
|
};
|
|
let wlan_ssid = match network_client::ssid("wlan0") {
|
|
Ok(ssid) => ssid,
|
|
Err(_) => "Not connected".to_string(),
|
|
};
|
|
let wlan_state = match network_client::state("wlan0") {
|
|
Ok(state) => state,
|
|
Err(_) => "Interface unavailable".to_string(),
|
|
};
|
|
let wlan_status = match network_client::status("wlan0") {
|
|
Ok(status) => status,
|
|
Err(_) => "Interface unavailable".to_string(),
|
|
};
|
|
let wlan_traffic = match network_client::traffic("wlan0") {
|
|
Ok(traffic) => {
|
|
let mut t = traffic;
|
|
// modify traffic values & assign measurement unit
|
|
// based on received and transmitted values
|
|
// if received > 999 MB, convert it to GB
|
|
if t.received > 1_047_527_424 {
|
|
t.received /= 1_073_741_824;
|
|
t.rx_unit = Some("GB".to_string());
|
|
} else if t.received > 0 {
|
|
// otherwise, convert it to MB
|
|
t.received = (t.received / 1024) / 1024;
|
|
t.rx_unit = Some("MB".to_string());
|
|
} else {
|
|
t.received = 0;
|
|
t.rx_unit = Some("MB".to_string());
|
|
}
|
|
|
|
if t.transmitted > 1_047_527_424 {
|
|
t.transmitted /= 1_073_741_824;
|
|
t.tx_unit = Some("GB".to_string());
|
|
} else if t.transmitted > 0 {
|
|
t.transmitted = (t.transmitted / 1024) / 1024;
|
|
t.tx_unit = Some("MB".to_string());
|
|
} else {
|
|
t.transmitted = 0;
|
|
t.tx_unit = Some("MB".to_string());
|
|
}
|
|
Some(t)
|
|
}
|
|
Err(_) => None,
|
|
};
|
|
// create a hashmap to combine wlan_list & wlan_scan without repetition
|
|
let mut wlan_networks = HashMap::new();
|
|
for ap in wlan_scan {
|
|
let ssid = ap.ssid.clone();
|
|
let rssi = ap.signal_level.clone();
|
|
// parse the string to a signed integer (for math)
|
|
let rssi_parsed = rssi.parse::<i32>().unwrap();
|
|
// perform rssi (dBm) to quality (%) conversion
|
|
let quality_percent = 2 * (rssi_parsed + 100);
|
|
let ap_detail = AccessPoint {
|
|
detail: Some(ap),
|
|
state: "Available".to_string(),
|
|
signal: Some(quality_percent),
|
|
};
|
|
wlan_networks.insert(ssid, ap_detail);
|
|
}
|
|
for network in wlan_list {
|
|
// avoid repetition by checking that ssid is not already in list
|
|
if !wlan_networks.contains_key(&network.ssid) {
|
|
let ssid = network.ssid.clone();
|
|
let net_detail = AccessPoint {
|
|
detail: None,
|
|
state: "Not in range".to_string(),
|
|
signal: None,
|
|
};
|
|
wlan_networks.insert(ssid, net_detail);
|
|
}
|
|
}
|
|
|
|
NetworkDetailContext {
|
|
back: None,
|
|
flash_name: None,
|
|
flash_msg: None,
|
|
saved_aps,
|
|
selected: None,
|
|
title: None,
|
|
wlan_ip,
|
|
wlan_networks,
|
|
wlan_rssi,
|
|
wlan_ssid,
|
|
wlan_state,
|
|
wlan_status,
|
|
wlan_traffic,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[get("/wifi?<ssid>")]
|
|
pub fn network_detail(ssid: &str, flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
|
|
// assign context through context_builder call
|
|
let mut context = NetworkDetailContext::build();
|
|
context.back = Some("/settings/network/wifi".to_string());
|
|
context.title = Some("WiFi Network".to_string());
|
|
context.selected = Some(ssid.to_string());
|
|
// check to see if there is a flash message to display
|
|
if let Some(flash) = flash {
|
|
// add flash message contents to the context object
|
|
context.flash_name = Some(flash.kind().to_string());
|
|
context.flash_msg = Some(flash.message().to_string());
|
|
};
|
|
// template_dir is set in Rocket.toml
|
|
Template::render("settings/network/ap_details", &context)
|
|
}
|
|
|
|
// HELPERS AND ROUTES FOR /settings/network/wifi/activate
|
|
|
|
#[get("/wifi/activate")]
|
|
pub fn deploy_client(_auth: Authenticated) -> Flash<Redirect> {
|
|
// activate the wireless client
|
|
debug!("Activating WiFi client mode.");
|
|
match network_client::activate_client() {
|
|
Ok(_) => Flash::success(Redirect::to("/settings/network"), "Activated WiFi client"),
|
|
Err(_) => Flash::error(
|
|
Redirect::to("/settings/network"),
|
|
"Failed to activate WiFi client",
|
|
),
|
|
}
|
|
}
|
|
|
|
// HELPERS AND ROUTES FOR /settings/network/wifi/add
|
|
|
|
#[get("/wifi/add")]
|
|
pub fn add_wifi(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
|
|
let mut context = NetworkContext::build();
|
|
// set back icon link to network route
|
|
context.back = Some("/settings/network".to_string());
|
|
context.title = Some("Add WiFi Network".to_string());
|
|
// check to see if there is a flash message to display
|
|
if let Some(flash) = flash {
|
|
// add flash message contents to the context object
|
|
context.flash_name = Some(flash.kind().to_string());
|
|
context.flash_msg = Some(flash.message().to_string());
|
|
};
|
|
// template_dir is set in Rocket.toml
|
|
Template::render("settings/network/add_ap", &context)
|
|
}
|
|
|
|
// used in /settings/network/wifi/add?<ssid>
|
|
#[derive(Debug, Serialize)]
|
|
pub struct NetworkAddContext {
|
|
pub back: Option<String>,
|
|
pub flash_name: Option<String>,
|
|
pub flash_msg: Option<String>,
|
|
pub selected: Option<String>,
|
|
pub title: Option<String>,
|
|
}
|
|
|
|
impl NetworkAddContext {
|
|
pub fn build() -> NetworkAddContext {
|
|
NetworkAddContext {
|
|
back: None,
|
|
flash_name: None,
|
|
flash_msg: None,
|
|
selected: None,
|
|
title: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[get("/wifi/add?<ssid>")]
|
|
pub fn add_ssid(ssid: &str, flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
|
|
let mut context = NetworkAddContext::build();
|
|
context.back = Some("/settings/network/wifi".to_string());
|
|
context.selected = Some(ssid.to_string());
|
|
context.title = Some("Add WiFi Network".to_string());
|
|
// check to see if there is a flash message to display
|
|
if let Some(flash) = flash {
|
|
// add flash message contents to the context object
|
|
context.flash_name = Some(flash.kind().to_string());
|
|
context.flash_msg = Some(flash.message().to_string());
|
|
};
|
|
// template_dir is set in Rocket.toml
|
|
Template::render("settings/network/add_ap", &context)
|
|
}
|
|
|
|
#[post("/wifi/add", data = "<wifi>")]
|
|
pub fn add_credentials(wifi: Form<WiFi>, _auth: Authenticated) -> Template {
|
|
// check if the credentials already exist for this access point
|
|
// note: this is nicer but it's an unstable feature:
|
|
// if check_saved_aps(&wifi.ssid).contains(true)
|
|
// use unwrap_or instead, set value to false if err is returned
|
|
let creds_exist = network_client::saved_ap(&wifi.ssid).unwrap_or(false);
|
|
if creds_exist {
|
|
let mut context = NetworkAddContext::build();
|
|
context.back = Some("/settings/network".to_string());
|
|
context.flash_name = Some("error".to_string());
|
|
context.flash_msg =
|
|
Some("Network credentials already exist for this access point".to_string());
|
|
context.title = Some("Add WiFi Network".to_string());
|
|
// return early from handler with "creds already exist" message
|
|
return Template::render("settings/network/add_ap", &context);
|
|
};
|
|
|
|
// if credentials not found, generate and write wifi config to wpa_supplicant
|
|
match network_client::add(&wifi.ssid, &wifi.pass) {
|
|
Ok(_) => {
|
|
debug!("Added WiFi credentials.");
|
|
// force reread of wpa_supplicant.conf file with new credentials
|
|
match network_client::reconfigure() {
|
|
Ok(_) => debug!("Successfully reconfigured wpa_supplicant"),
|
|
Err(_) => warn!("Failed to reconfigure wpa_supplicant"),
|
|
}
|
|
let mut context = NetworkAddContext::build();
|
|
context.back = Some("/settings/network".to_string());
|
|
context.flash_name = Some("success".to_string());
|
|
context.flash_msg = Some("Added WiFi credentials".to_string());
|
|
context.title = Some("Add WiFi Network".to_string());
|
|
Template::render("settings/network/add_ap", &context)
|
|
}
|
|
Err(_) => {
|
|
debug!("Failed to add WiFi credentials.");
|
|
let mut context = NetworkAddContext::build();
|
|
context.back = Some("/settings/network".to_string());
|
|
context.flash_name = Some("error".to_string());
|
|
context.flash_msg = Some("Failed to add WiFi credentials".to_string());
|
|
context.title = Some("Add WiFi Network".to_string());
|
|
Template::render("settings/network/add_ap", &context)
|
|
}
|
|
}
|
|
}
|
|
|
|
// HELPERS AND ROUTES FOR WIFI USAGE
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct NetworkAlertContext {
|
|
pub alert: Alert,
|
|
pub back: Option<String>,
|
|
pub data_total: Data, // combined stored and current wifi traffic in bytes
|
|
pub flash_name: Option<String>,
|
|
pub flash_msg: Option<String>,
|
|
pub threshold: Threshold,
|
|
pub title: Option<String>,
|
|
pub traffic: Traffic, // current wifi traffic in bytes (since boot)
|
|
}
|
|
|
|
impl NetworkAlertContext {
|
|
pub fn build() -> NetworkAlertContext {
|
|
let alert = monitor::get_alerts().unwrap();
|
|
// stored wifi data values as bytes
|
|
let stored_traffic = monitor::get_data().unwrap();
|
|
let threshold = monitor::get_thresholds().unwrap();
|
|
// current wifi traffic values as bytes
|
|
let traffic = match network_client::traffic("wlan0") {
|
|
Ok(t) => t,
|
|
Err(_) => Traffic {
|
|
received: 0,
|
|
transmitted: 0,
|
|
rx_unit: None,
|
|
tx_unit: None,
|
|
},
|
|
};
|
|
|
|
let current_traffic = traffic.received + traffic.transmitted;
|
|
let total = stored_traffic.total + current_traffic;
|
|
let data_total = Data { total };
|
|
|
|
NetworkAlertContext {
|
|
alert,
|
|
back: None,
|
|
data_total,
|
|
flash_name: None,
|
|
flash_msg: None,
|
|
threshold,
|
|
title: None,
|
|
traffic,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[get("/wifi/usage")]
|
|
pub fn wifi_usage(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
|
|
let mut context = NetworkAlertContext::build();
|
|
// set back icon link to network route
|
|
context.back = Some("/settings/network".to_string());
|
|
context.title = Some("Network Data Usage".to_string());
|
|
// check to see if there is a flash message to display
|
|
if let Some(flash) = flash {
|
|
// add flash message contents to the context object
|
|
context.flash_name = Some(flash.kind().to_string());
|
|
context.flash_msg = Some(flash.message().to_string());
|
|
};
|
|
// template_dir is set in Rocket.toml
|
|
Template::render("settings/network/data_usage_limits", &context)
|
|
}
|
|
|
|
#[post("/wifi/usage", data = "<thresholds>")]
|
|
pub fn wifi_usage_alerts(thresholds: Form<Threshold>, _auth: Authenticated) -> Flash<Redirect> {
|
|
match monitor::update_store(thresholds.into_inner()) {
|
|
Ok(_) => {
|
|
debug!("WiFi data usage thresholds updated.");
|
|
Flash::success(
|
|
Redirect::to("/settings/network/wifi/usage"),
|
|
"Updated alert thresholds and flags",
|
|
)
|
|
}
|
|
Err(_) => {
|
|
warn!("Failed to update WiFi data usage thresholds.");
|
|
Flash::error(
|
|
Redirect::to("/settings/network/wifi/usage"),
|
|
"Failed to update alert thresholds and flags",
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
// JSON ROUTES FOR NETWORK SETTINGS
|
|
|
|
#[post("/wifi/usage", data = "<thresholds>")]
|
|
pub fn update_wifi_alerts(thresholds: Json<Threshold>, _auth: Authenticated) -> Value {
|
|
match monitor::update_store(thresholds.into_inner()) {
|
|
Ok(_) => {
|
|
debug!("WiFi data usage thresholds updated.");
|
|
let status = "success".to_string();
|
|
let msg = "Updated alert threshold and flags.".to_string();
|
|
build_json_response(status, None, Some(msg))
|
|
}
|
|
Err(_) => {
|
|
warn!("Failed to update WiFi data usage thresholds.");
|
|
let status = "error".to_string();
|
|
let msg = "Failed to update WiFi data usage thresholds.".to_string();
|
|
build_json_response(status, None, Some(msg))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[post("/wifi/usage/reset")]
|
|
pub fn reset_data_total(_auth: Authenticated) -> Value {
|
|
match monitor::reset_data() {
|
|
Ok(_) => {
|
|
debug!("Reset network data usage total.");
|
|
let traffic = match network_client::traffic("wlan0") {
|
|
Ok(t) => t,
|
|
Err(_) => Traffic {
|
|
received: 0,
|
|
transmitted: 0,
|
|
rx_unit: None,
|
|
tx_unit: None,
|
|
},
|
|
};
|
|
// current wifi traffic values as bytes
|
|
let current_traffic = traffic.received + traffic.transmitted;
|
|
let data = json!(current_traffic);
|
|
let status = "success".to_string();
|
|
let msg = "Reset network data usage total.".to_string();
|
|
build_json_response(status, Some(data), Some(msg))
|
|
}
|
|
Err(_) => {
|
|
warn!("Failed to reset network data usage total.");
|
|
let status = "error".to_string();
|
|
let msg = "Failed to reset network data usage total.".to_string();
|
|
build_json_response(status, None, Some(msg))
|
|
}
|
|
}
|
|
}
|
|
|
|
// HELPERS AND ROUTES FOR ACCESS POINT ACTIVATION
|
|
|
|
#[post("/activate_ap")]
|
|
pub fn activate_ap(_auth: Authenticated) -> Value {
|
|
// activate the wireless access point
|
|
debug!("Activating WiFi access point.");
|
|
match network_client::activate_ap() {
|
|
Ok(_) => {
|
|
let status = "success".to_string();
|
|
build_json_response(status, None, None)
|
|
}
|
|
Err(_) => {
|
|
let status = "error".to_string();
|
|
let msg = "Failed to activate WiFi access point.".to_string();
|
|
build_json_response(status, None, Some(msg))
|
|
}
|
|
}
|
|
}
|
|
|
|
// HELPERS AND ROUTES FOR WIFI CLIENT MANAGEMENT
|
|
|
|
#[post("/activate_client")]
|
|
pub fn activate_client(_auth: Authenticated) -> Value {
|
|
// activate the wireless client
|
|
debug!("Activating WiFi client mode.");
|
|
match network_client::activate_client() {
|
|
Ok(_) => {
|
|
let status = "success".to_string();
|
|
build_json_response(status, None, None)
|
|
}
|
|
Err(_) => {
|
|
let status = "error".to_string();
|
|
let msg = "Failed to activate WiFi client mode.".to_string();
|
|
build_json_response(status, None, Some(msg))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[post("/wifi", data = "<wifi>")]
|
|
pub fn add_wifi_credentials(wifi: Json<WiFi>, _auth: Authenticated) -> Value {
|
|
// generate and write wifi config to wpa_supplicant
|
|
match network_client::add(&wifi.ssid, &wifi.pass) {
|
|
Ok(_) => {
|
|
debug!("Added WiFi credentials.");
|
|
// force reread of wpa_supplicant.conf file with new credentials
|
|
match network_client::reconfigure() {
|
|
Ok(_) => debug!("Successfully reconfigured wpa_supplicant."),
|
|
Err(_) => warn!("Failed to reconfigure wpa_supplicant."),
|
|
}
|
|
// json response for successful update
|
|
let status = "success".to_string();
|
|
let msg = "WiFi credentials added.".to_string();
|
|
build_json_response(status, None, Some(msg))
|
|
}
|
|
Err(_) => {
|
|
debug!("Failed to add WiFi credentials.");
|
|
// json response for failed update
|
|
let status = "error".to_string();
|
|
let msg = "Failed to add WiFi credentials.".to_string();
|
|
build_json_response(status, None, Some(msg))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[post("/wifi/connect", data = "<ssid>")]
|
|
pub fn connect_ap(ssid: Json<Ssid>, _auth: Authenticated) -> Value {
|
|
// retrieve the id for the given network ssid
|
|
match network_client::id("wlan0", &ssid.ssid) {
|
|
// attempt connection with the given network
|
|
Ok(id) => match network_client::connect(&id, "wlan0") {
|
|
Ok(_) => {
|
|
let status = "success".to_string();
|
|
let msg = "Connected to chosen network.".to_string();
|
|
build_json_response(status, None, Some(msg))
|
|
}
|
|
Err(_) => {
|
|
let status = "error".to_string();
|
|
let msg = "Failed to connect to chosen network.".to_string();
|
|
build_json_response(status, None, Some(msg))
|
|
}
|
|
},
|
|
Err(_) => {
|
|
let status = "error".to_string();
|
|
let msg = "Failed to retrieve the network ID.".to_string();
|
|
build_json_response(status, None, Some(msg))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[post("/wifi/disconnect", data = "<ssid>")]
|
|
pub fn disconnect_ap(ssid: Json<Ssid>, _auth: Authenticated) -> Value {
|
|
// attempt to disable the current network for wlan0 interface
|
|
match network_client::disable("wlan0", &ssid.ssid) {
|
|
Ok(_) => {
|
|
let status = "success".to_string();
|
|
let msg = "Disconnected from WiFi network.".to_string();
|
|
build_json_response(status, None, Some(msg))
|
|
}
|
|
Err(_) => {
|
|
let status = "error".to_string();
|
|
let msg = "Failed to disconnect from WiFi network.".to_string();
|
|
build_json_response(status, None, Some(msg))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[post("/wifi/forget", data = "<network>")]
|
|
pub fn forget_ap(network: Json<Ssid>, _auth: Authenticated) -> Value {
|
|
let ssid = &network.ssid;
|
|
match network_client::forget("wlan0", ssid) {
|
|
Ok(_) => {
|
|
debug!("Removed WiFi credentials for chosen network.");
|
|
let status = "success".to_string();
|
|
let msg = "WiFi network credentials removed.".to_string();
|
|
build_json_response(status, None, Some(msg))
|
|
}
|
|
Err(_) => {
|
|
warn!("Failed to remove WiFi credentials.");
|
|
let status = "error".to_string();
|
|
let msg = "Failed to remove WiFi network credentials.".to_string();
|
|
build_json_response(status, None, Some(msg))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[post("/wifi/modify", data = "<wifi>")]
|
|
pub fn modify_password(wifi: Json<WiFi>, _auth: Authenticated) -> Value {
|
|
let ssid = &wifi.ssid;
|
|
let pass = &wifi.pass;
|
|
// we are using a helper function (`update`) to delete the old
|
|
// credentials and add the new ones. this is because the wpa_cli method
|
|
// for updating the password does not work.
|
|
match network_client::update("wlan0", ssid, pass) {
|
|
Ok(_) => {
|
|
debug!("WiFi password updated for chosen network.");
|
|
let status = "success".to_string();
|
|
let msg = "WiFi password updated.".to_string();
|
|
build_json_response(status, None, Some(msg))
|
|
}
|
|
Err(_) => {
|
|
warn!("Failed to update WiFi password.");
|
|
let status = "error".to_string();
|
|
let msg = "Failed to update WiFi password.".to_string();
|
|
build_json_response(status, None, Some(msg))
|
|
}
|
|
}
|
|
}
|
|
|
|
// HELPERS AND ROUTES FOR NETWORK STATE QUERIES
|
|
|
|
#[get("/ip")]
|
|
pub fn return_ip(_auth: Authenticated) -> Value {
|
|
// retrieve ip for wlan0 or set to x.x.x.x if not found
|
|
let wlan_ip = match network_client::ip("wlan0") {
|
|
Ok(ip) => ip,
|
|
Err(_) => "x.x.x.x".to_string(),
|
|
};
|
|
// retrieve ip for ap0 or set to x.x.x.x if not found
|
|
let ap_ip = match network_client::ip("ap0") {
|
|
Ok(ip) => ip,
|
|
Err(_) => "x.x.x.x".to_string(),
|
|
};
|
|
let data = json!({
|
|
"wlan0": wlan_ip,
|
|
"ap0": ap_ip
|
|
});
|
|
let status = "success".to_string();
|
|
build_json_response(status, Some(data), None)
|
|
}
|
|
|
|
#[get("/rssi")]
|
|
pub fn return_rssi(_auth: Authenticated) -> Value {
|
|
// retrieve rssi for connected network
|
|
match network_client::rssi("wlan0") {
|
|
Ok(rssi) => {
|
|
let status = "success".to_string();
|
|
let data = json!(rssi);
|
|
build_json_response(status, Some(data), None)
|
|
}
|
|
Err(_) => {
|
|
let status = "success".to_string();
|
|
let msg = "Not currently connected to an access point.".to_string();
|
|
build_json_response(status, None, Some(msg))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[get("/ssid")]
|
|
pub fn return_ssid(_auth: Authenticated) -> Value {
|
|
// retrieve ssid for connected network
|
|
match network_client::ssid("wlan0") {
|
|
Ok(network) => {
|
|
let status = "success".to_string();
|
|
let data = json!(network);
|
|
build_json_response(status, Some(data), None)
|
|
}
|
|
Err(_) => {
|
|
let status = "success".to_string();
|
|
let msg = "Not currently connected to an access point.".to_string();
|
|
build_json_response(status, None, Some(msg))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[get("/state")]
|
|
pub fn return_state(_auth: Authenticated) -> Value {
|
|
// retrieve state of wlan0 or set to x.x.x.x if not found
|
|
let wlan_state = match network_client::state("wlan0") {
|
|
Ok(state) => state,
|
|
Err(_) => "unavailable".to_string(),
|
|
};
|
|
// retrieve state for ap0 or set to x.x.x.x if not found
|
|
let ap_state = match network_client::state("ap0") {
|
|
Ok(state) => state,
|
|
Err(_) => "unavailable".to_string(),
|
|
};
|
|
let data = json!({
|
|
"wlan0": wlan_state,
|
|
"ap0": ap_state
|
|
});
|
|
let status = "success".to_string();
|
|
build_json_response(status, Some(data), None)
|
|
}
|
|
|
|
#[get("/status")]
|
|
pub fn return_status(_auth: Authenticated) -> Value {
|
|
// retrieve status info for wlan0 interface
|
|
match network_client::status("wlan0") {
|
|
Ok(network) => {
|
|
let status = "success".to_string();
|
|
let data = json!(network);
|
|
build_json_response(status, Some(data), None)
|
|
}
|
|
Err(_) => {
|
|
let status = "success".to_string();
|
|
let msg = "Not currently connected to an access point.".to_string();
|
|
build_json_response(status, None, Some(msg))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[get("/wifi")]
|
|
pub fn scan_networks(_auth: Authenticated) -> Value {
|
|
// retrieve scan results for access-points within range of wlan0
|
|
match network_client::available_networks("wlan0") {
|
|
Ok(networks) => {
|
|
let status = "success".to_string();
|
|
let data = json!(networks);
|
|
build_json_response(status, Some(data), None)
|
|
}
|
|
Err(_) => {
|
|
let status = "success".to_string();
|
|
let msg = "Unable to scan for networks. Interface may be deactivated.".to_string();
|
|
build_json_response(status, None, Some(msg))
|
|
}
|
|
}
|
|
}
|