mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
Fix/wifi (#1326)
* 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:
@@ -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(
|
||||||
|
|||||||
@@ -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',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user