* fix: Fix the missing wifi's still list.

* chore: Exclude the interface maybe

* chore: Don't add if already there, just modify

* chore: Minor changes

* no timeouts, regex on pw input (#1327)

Co-authored-by: Drew Ansbacher <drew@start9labs.com>

* fix: Allow more than 8

* Update wifi.page.ts

Co-authored-by: Drew Ansbacher <drew.ansbacher@gmail.com>
Co-authored-by: Drew Ansbacher <drew@start9labs.com>
This commit is contained in:
J M
2022-03-15 13:09:03 -06:00
committed by GitHub
parent 8942c29229
commit 227b7a03d7
2 changed files with 104 additions and 48 deletions

View File

@@ -1,4 +1,4 @@
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, BTreeSet, HashMap};
use std::path::Path; use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
@@ -79,6 +79,7 @@ pub async fn add(
.await .await
{ {
tracing::error!("Failed to add new WiFi network '{}': {}", ssid, err); tracing::error!("Failed to add new WiFi network '{}': {}", ssid, err);
tracing::debug!("{:?}", err);
return Err(Error::new( return Err(Error::new(
color_eyre::eyre::eyre!("Failed adding {}", ssid), color_eyre::eyre::eyre!("Failed adding {}", ssid),
ErrorKind::Wifi, ErrorKind::Wifi,
@@ -292,12 +293,12 @@ pub async fn get(
wpa_supplicant.list_wifi_low() wpa_supplicant.list_wifi_low()
); );
let signal_strengths = signal_strengths?; let signal_strengths = signal_strengths?;
let list_networks = list_networks?; let list_networks: BTreeSet<_> = list_networks?.into_iter().map(|(_, x)| x.ssid).collect();
let available_wifi = { let available_wifi = {
let mut wifi_list: Vec<WifiListOut> = signal_strengths let mut wifi_list: Vec<WifiListOut> = signal_strengths
.clone() .clone()
.into_iter() .into_iter()
.filter(|(ssid, _)| !list_networks.contains_key(ssid)) .filter(|(ssid, _)| !list_networks.contains(ssid))
.map(|(ssid, info)| WifiListOut { .map(|(ssid, info)| WifiListOut {
ssid, ssid,
strength: info.strength, strength: info.strength,
@@ -309,13 +310,13 @@ pub async fn get(
wifi_list wifi_list
}; };
let ssids: HashMap<Ssid, SignalStrength> = list_networks let ssids: HashMap<Ssid, SignalStrength> = list_networks
.into_keys() .into_iter()
.map(|x| { .map(|ssid| {
let signal_strength = signal_strengths let signal_strength = signal_strengths
.get(&x) .get(&ssid)
.map(|x| x.strength) .map(|x| x.strength)
.unwrap_or_default(); .unwrap_or_default();
(x, signal_strength) (ssid, signal_strength)
}) })
.collect(); .collect();
let current = current_res?; let current = current_res?;
@@ -341,10 +342,13 @@ pub async fn get_available(
wpa_supplicant.list_wifi_low(), wpa_supplicant.list_wifi_low(),
wpa_supplicant.list_networks_low() wpa_supplicant.list_networks_low()
); );
let network_list = network_list?; let network_list = network_list?
.into_iter()
.map(|(_, info)| info.ssid)
.collect::<BTreeSet<_>>();
let mut wifi_list: Vec<WifiListOut> = wifi_list? let mut wifi_list: Vec<WifiListOut> = wifi_list?
.into_iter() .into_iter()
.filter(|(ssid, _)| !network_list.contains_key(ssid)) .filter(|(ssid, _)| !network_list.contains(ssid))
.map(|(ssid, info)| WifiListOut { .map(|(ssid, info)| WifiListOut {
ssid, ssid,
strength: info.strength, strength: info.strength,
@@ -369,7 +373,7 @@ pub async fn set_country(
} }
let mut wpa_supplicant = ctx.wifi_manager.write().await; let mut wpa_supplicant = ctx.wifi_manager.write().await;
wpa_supplicant.set_country_low(country.alpha2()).await?; wpa_supplicant.set_country_low(country.alpha2()).await?;
for (_ssid, network_id) in wpa_supplicant.list_networks_low().await? { for (network_id, _wifi_info) in wpa_supplicant.list_networks_low().await? {
wpa_supplicant.remove_network_low(network_id).await?; wpa_supplicant.remove_network_low(network_id).await?;
} }
wpa_supplicant.remove_all_connections().await?; wpa_supplicant.remove_all_connections().await?;
@@ -421,6 +425,12 @@ impl SignalStrength {
} }
} }
#[derive(Debug, Clone)]
pub struct WifiInfo {
ssid: Ssid,
device: Option<String>,
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Psk(String); pub struct Psk(String);
impl WpaCli { impl WpaCli {
@@ -446,20 +456,20 @@ impl WpaCli {
} }
#[instrument(skip(self, psk))] #[instrument(skip(self, psk))]
pub async fn add_network_low(&mut self, ssid: &Ssid, psk: &Psk) -> Result<(), Error> { pub async fn add_network_low(&mut self, ssid: &Ssid, psk: &Psk) -> Result<(), Error> {
let _ = Command::new("nmcli") if self.find_networks(ssid).await?.is_empty() {
.arg("con") Command::new("nmcli")
.arg("add") .arg("con")
.arg("con-name") .arg("add")
.arg(&ssid.0) .arg("con-name")
.arg("ifname") .arg(&ssid.0)
.arg(&self.interface) .arg("type")
.arg("type") .arg("wifi")
.arg("wifi") .arg("ssid")
.arg("ssid") .arg(&ssid.0)
.arg(&ssid.0) .invoke(ErrorKind::Wifi)
.invoke(ErrorKind::Wifi) .await?;
.await?; }
let _ = Command::new("nmcli") Command::new("nmcli")
.arg("con") .arg("con")
.arg("modify") .arg("modify")
.arg(&ssid.0) .arg(&ssid.0)
@@ -467,7 +477,20 @@ impl WpaCli {
.arg("wpa-psk") .arg("wpa-psk")
.invoke(ErrorKind::Wifi) .invoke(ErrorKind::Wifi)
.await?; .await?;
let _ = Command::new("nmcli") Command::new("nmcli")
.arg("con")
.arg("modify")
.arg(&ssid.0)
.arg("ifname")
.arg(&self.interface)
.invoke(ErrorKind::Wifi)
.await
.map(|_| ())
.unwrap_or_else(|e| {
tracing::warn!("Failed to set interface {} for {}", self.interface, ssid.0);
tracing::debug!("{:?}", e);
});
Command::new("nmcli")
.arg("con") .arg("con")
.arg("modify") .arg("modify")
.arg(&ssid.0) .arg(&ssid.0)
@@ -526,27 +549,32 @@ impl WpaCli {
Ok(()) Ok(())
} }
#[instrument] #[instrument]
pub async fn list_networks_low(&self) -> Result<BTreeMap<Ssid, NetworkId>, Error> { pub async fn list_networks_low(&self) -> Result<BTreeMap<NetworkId, WifiInfo>, Error> {
let r = Command::new("nmcli") let r = Command::new("nmcli")
.arg("-t") .arg("-t")
.arg("c") .arg("c")
.arg("show") .arg("show")
.invoke(ErrorKind::Wifi) .invoke(ErrorKind::Wifi)
.await?; .await?;
Ok(String::from_utf8(r)? let r = String::from_utf8(r)?;
.lines() tracing::info!("JCWM: all the networks: {:?}", r);
Ok(r.lines()
.filter_map(|l| { .filter_map(|l| {
let mut cs = l.split(':'); let mut cs = l.split(':');
let name = Ssid(cs.next()?.to_owned()); let name = Ssid(cs.next()?.to_owned());
let uuid = NetworkId(cs.next()?.to_owned()); let uuid = NetworkId(cs.next()?.to_owned());
let connection_type = cs.next()?; let connection_type = cs.next()?;
let device = cs.next()?; let device = cs.next();
if !device.contains("wlan0") || !connection_type.contains("wireless") { if !connection_type.contains("wireless") {
return None; return None;
} }
Some((name, uuid)) let info = WifiInfo {
ssid: name,
device: device.map(|x| x.to_owned()),
};
Some((uuid, info))
}) })
.collect::<BTreeMap<Ssid, NetworkId>>()) .collect::<BTreeMap<NetworkId, WifiInfo>>())
} }
#[instrument] #[instrument]
@@ -606,12 +634,37 @@ impl WpaCli {
.await?; .await?;
Ok(()) Ok(())
} }
pub async fn check_network(&self, ssid: &Ssid) -> Result<Option<NetworkId>, Error> { async fn check_active_network(&self, ssid: &Ssid) -> Result<Option<NetworkId>, Error> {
Ok(self.list_networks_low().await?.remove(ssid)) Ok(self
.list_networks_low()
.await?
.iter()
.find_map(|(network_id, wifi_info)| {
wifi_info.device.as_ref()?;
if wifi_info.ssid == *ssid {
Some(network_id.clone())
} else {
None
}
}))
}
pub async fn find_networks(&self, ssid: &Ssid) -> Result<Vec<NetworkId>, Error> {
Ok(self
.list_networks_low()
.await?
.iter()
.filter_map(|(network_id, wifi_info)| {
if wifi_info.ssid == *ssid {
Some(network_id.clone())
} else {
None
}
})
.collect())
} }
#[instrument(skip(db))] #[instrument(skip(db))]
pub async fn select_network(&mut self, db: impl DbHandle, ssid: &Ssid) -> Result<bool, Error> { pub async fn select_network(&mut self, db: impl DbHandle, ssid: &Ssid) -> Result<bool, Error> {
let m_id = self.check_network(ssid).await?; let m_id = self.check_active_network(ssid).await?;
match m_id { match m_id {
None => Err(Error::new( None => Err(Error::new(
color_eyre::eyre::eyre!("SSID Not Found"), color_eyre::eyre::eyre!("SSID Not Found"),
@@ -663,14 +716,15 @@ impl WpaCli {
} }
#[instrument(skip(db))] #[instrument(skip(db))]
pub async fn remove_network(&mut self, db: impl DbHandle, ssid: &Ssid) -> Result<bool, Error> { pub async fn remove_network(&mut self, db: impl DbHandle, ssid: &Ssid) -> Result<bool, Error> {
match self.check_network(ssid).await? { let found_networks = self.find_networks(ssid).await?;
None => Ok(false), if found_networks.is_empty() {
Some(x) => { return Ok(true);
self.remove_network_low(x).await?;
self.save_config(db).await?;
Ok(true)
}
} }
for network_id in found_networks {
self.remove_network_low(network_id).await?;
}
self.save_config(db).await?;
Ok(true)
} }
#[instrument(skip(psk, db))] #[instrument(skip(psk, db))]
pub async fn set_add_network( pub async fn set_add_network(

View File

@@ -177,7 +177,7 @@ export class WifiPage {
try { try {
await this.api.setWifiCountry({ country }) await this.api.setWifiCountry({ country })
await this.getWifi(4000) await this.getWifi()
this.wifi.country = country this.wifi.country = country
} catch (e) { } catch (e) {
this.errToast.present(e) this.errToast.present(e)
@@ -190,7 +190,6 @@ export class WifiPage {
ssid: string, ssid: string,
deleteOnFailure = false, deleteOnFailure = false,
): Promise<void> { ): Promise<void> {
const timeout = 4000
const maxAttempts = 5 const maxAttempts = 5
let attempts = 0 let attempts = 0
@@ -205,7 +204,7 @@ export class WifiPage {
try { try {
const start = new Date().valueOf() const start = new Date().valueOf()
await this.getWifi(timeout) await this.getWifi()
const end = new Date().valueOf() const end = new Date().valueOf()
if (this.wifi.connected === ssid) { if (this.wifi.connected === ssid) {
this.presentAlertSuccess(ssid) this.presentAlertSuccess(ssid)
@@ -213,7 +212,8 @@ export class WifiPage {
} else { } else {
attempts++ attempts++
const diff = end - start const diff = end - start
await pauseFor(Math.max(1000, timeout - diff)) // depending on the response time, wait a min of 1000 ms, and a max of 4000 ms in between retries. Both 1000 and 4000 are arbitrary
await pauseFor(Math.max(1000, 4000 - diff))
} }
} catch (e) { } catch (e) {
attempts++ attempts++
@@ -288,7 +288,7 @@ export class WifiPage {
try { try {
await this.api.deleteWifi({ ssid }) await this.api.deleteWifi({ ssid })
await this.getWifi(4000) await this.getWifi()
delete this.wifi.ssids[ssid] delete this.wifi.ssids[ssid]
} catch (e) { } catch (e) {
this.errToast.present(e) this.errToast.present(e)
@@ -312,7 +312,7 @@ export class WifiPage {
priority: 0, priority: 0,
connect: false, connect: false,
}) })
await this.getWifi(4000) await this.getWifi()
} catch (e) { } catch (e) {
this.errToast.present(e) this.errToast.present(e)
} finally { } finally {
@@ -370,6 +370,8 @@ function getWifiValueSpec(
nullable: !needsPW, nullable: !needsPW,
masked: true, masked: true,
copyable: false, copyable: false,
pattern: '^.{8,}$',
'pattern-description': 'Must be longer than 8 characters',
}, },
}, },
} }