From e9166c4a7dd20c9a8ed27c6194b8e35a73eabe48 Mon Sep 17 00:00:00 2001 From: Aiden McClelland Date: Tue, 9 Apr 2024 15:24:05 -0600 Subject: [PATCH] fix wifi types --- core/startos/bindings/ServerInfo.ts | 6 +- core/startos/bindings/WifiInfo.ts | 4 +- core/startos/src/backup/restore.rs | 6 +- core/startos/src/context/config.rs | 3 - core/startos/src/context/rpc.rs | 9 +-- core/startos/src/db/model/mod.rs | 4 +- core/startos/src/db/model/public.rs | 26 +++---- core/startos/src/init.rs | 15 ++-- core/startos/src/net/wifi.rs | 71 +++++++++++++++---- core/startos/src/os_install/mod.rs | 4 +- core/startos/src/setup.rs | 6 +- .../ui/src/app/services/api/mock-patch.ts | 3 +- 12 files changed, 85 insertions(+), 72 deletions(-) diff --git a/core/startos/bindings/ServerInfo.ts b/core/startos/bindings/ServerInfo.ts index 130a5bafe..618d396fd 100644 --- a/core/startos/bindings/ServerInfo.ts +++ b/core/startos/bindings/ServerInfo.ts @@ -11,10 +11,6 @@ export type ServerInfo = { hostname: string; version: string; lastBackup: string | null; - /** - * Used in the wifi to determine the region to set the system to - */ - lastWifiRegion: string | null; eosVersionCompat: string; lanAddress: string; onionAddress: string; @@ -24,7 +20,7 @@ export type ServerInfo = { torAddress: string; ipInfo: { [key: string]: IpInfo }; statusInfo: ServerStatus; - wifi: WifiInfo | null; + wifi: WifiInfo; unreadNotificationCount: number; passwordHash: string; pubkey: string; diff --git a/core/startos/bindings/WifiInfo.ts b/core/startos/bindings/WifiInfo.ts index 59b1b901d..812cc431f 100644 --- a/core/startos/bindings/WifiInfo.ts +++ b/core/startos/bindings/WifiInfo.ts @@ -1,8 +1,8 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. export type WifiInfo = { - interface: string; + interface: string | null; ssids: Array; selected: string | null; - connected: string | null; + lastRegion: string | null; }; diff --git a/core/startos/src/backup/restore.rs b/core/startos/src/backup/restore.rs index 41aaeca7b..4753a4290 100644 --- a/core/startos/src/backup/restore.rs +++ b/core/startos/src/backup/restore.rs @@ -96,11 +96,7 @@ pub async fn recover_full_embassy( .with_kind(ErrorKind::PasswordHashGeneration)?; let db = ctx.db().await?; - db.put( - &ROOT, - &Database::init(&os_backup.account, ctx.config.wifi_interface.clone())?, - ) - .await?; + db.put(&ROOT, &Database::init(&os_backup.account)?).await?; drop(db); init(&ctx.config).await?; diff --git a/core/startos/src/context/config.rs b/core/startos/src/context/config.rs index 55065e816..0e6d9feff 100644 --- a/core/startos/src/context/config.rs +++ b/core/startos/src/context/config.rs @@ -91,8 +91,6 @@ impl ClientConfig { pub struct ServerConfig { #[arg(short = 'c', long = "config")] pub config: Option, - #[arg(long = "wifi-interface")] - pub wifi_interface: Option, #[arg(long = "ethernet-interface")] pub ethernet_interface: Option, #[arg(skip)] @@ -117,7 +115,6 @@ impl ContextConfig for ServerConfig { self.config.take() } fn merge_with(&mut self, other: Self) { - self.wifi_interface = self.wifi_interface.take().or(other.wifi_interface); self.ethernet_interface = self.ethernet_interface.take().or(other.ethernet_interface); self.os_partitions = self.os_partitions.take().or(other.os_partitions); self.bind_rpc = self.bind_rpc.take().or(other.bind_rpc); diff --git a/core/startos/src/context/rpc.rs b/core/startos/src/context/rpc.rs index a51e23b08..5adab5e58 100644 --- a/core/startos/src/context/rpc.rs +++ b/core/startos/src/context/rpc.rs @@ -26,7 +26,7 @@ use crate::init::check_time_is_synchronized; use crate::lxc::{LxcContainer, LxcManager}; use crate::middleware::auth::HashSessionToken; use crate::net::net_controller::NetController; -use crate::net::utils::find_eth_iface; +use crate::net::utils::{find_eth_iface, find_wifi_iface}; use crate::net::wifi::WpaCli; use crate::prelude::*; use crate::service::ServiceMap; @@ -132,6 +132,8 @@ impl RpcContext { }); } + let wifi_interface = find_wifi_iface().await?; + let seed = Arc::new(RpcContextSeed { is_closed: AtomicBool::new(false), datadir: config.datadir().to_path_buf(), @@ -141,7 +143,7 @@ impl RpcContext { ErrorKind::Filesystem, ) })?, - wifi_interface: config.wifi_interface.clone(), + wifi_interface: wifi_interface.clone(), ethernet_interface: if let Some(eth) = config.ethernet_interface.clone() { eth } else { @@ -158,8 +160,7 @@ impl RpcContext { lxc_manager: Arc::new(LxcManager::new()), open_authed_websockets: Mutex::new(BTreeMap::new()), rpc_stream_continuations: Mutex::new(BTreeMap::new()), - wifi_manager: config - .wifi_interface + wifi_manager: wifi_interface .clone() .map(|i| Arc::new(RwLock::new(WpaCli::init(i)))), current_secret: Arc::new( diff --git a/core/startos/src/db/model/mod.rs b/core/startos/src/db/model/mod.rs index 8b959cdfd..cae1bfe51 100644 --- a/core/startos/src/db/model/mod.rs +++ b/core/startos/src/db/model/mod.rs @@ -27,9 +27,9 @@ pub struct Database { pub private: Private, } impl Database { - pub fn init(account: &AccountInfo, wifi_interface: Option) -> Result { + pub fn init(account: &AccountInfo) -> Result { Ok(Self { - public: Public::init(account, wifi_interface)?, + public: Public::init(account)?, private: Private { key_store: KeyStore::new(account)?, password: account.password.clone(), diff --git a/core/startos/src/db/model/public.rs b/core/startos/src/db/model/public.rs index 5b83eb74d..a51303cf4 100644 --- a/core/startos/src/db/model/public.rs +++ b/core/startos/src/db/model/public.rs @@ -1,4 +1,4 @@ -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet}; use std::net::{Ipv4Addr, Ipv6Addr}; use chrono::{DateTime, Utc}; @@ -35,7 +35,7 @@ pub struct Public { pub ui: Value, } impl Public { - pub fn init(account: &AccountInfo, wifi_interface: Option) -> Result { + pub fn init(account: &AccountInfo) -> Result { let lan_address = account.hostname.lan_address().parse().unwrap(); Ok(Self { server_info: ServerInfo { @@ -45,7 +45,6 @@ impl Public { version: Current::new().semver().into(), hostname: account.hostname.no_dot_host_name(), last_backup: None, - last_wifi_region: None, eos_version_compat: Current::new().compat().clone(), lan_address, onion_address: account.tor_key.public().get_onion_address(), @@ -60,12 +59,7 @@ impl Public { shutting_down: false, restarting: false, }, - wifi: wifi_interface.map(|interface| WifiInfo { - interface, - ssids: Vec::new(), - connected: None, - selected: None, - }), + wifi: WifiInfo::default(), unread_notification_count: 0, password_hash: account.password.clone(), pubkey: ssh_key::PublicKey::from(&account.ssh_key) @@ -117,9 +111,6 @@ pub struct ServerInfo { pub version: Version, #[ts(type = "string | null")] pub last_backup: Option>, - /// Used in the wifi to determine the region to set the system to - #[ts(type = "string | null")] - pub last_wifi_region: Option, #[ts(type = "string")] pub eos_version_compat: VersionRange, #[ts(type = "string")] @@ -132,7 +123,7 @@ pub struct ServerInfo { pub ip_info: BTreeMap, #[serde(default)] pub status_info: ServerStatus, - pub wifi: Option, + pub wifi: WifiInfo, #[ts(type = "number")] pub unread_notification_count: u64, pub password_hash: String, @@ -202,15 +193,16 @@ pub struct UpdateProgress { pub downloaded: u64, } -#[derive(Debug, Deserialize, Serialize, HasModel, TS)] +#[derive(Debug, Default, Deserialize, Serialize, HasModel, TS)] #[serde(rename_all = "camelCase")] #[model = "Model"] #[ts(export)] pub struct WifiInfo { - pub interface: String, - pub ssids: Vec, + pub interface: Option, + pub ssids: BTreeSet, pub selected: Option, - pub connected: Option, + #[ts(type = "string | null")] + pub last_region: Option, } #[derive(Debug, Deserialize, Serialize, TS)] diff --git a/core/startos/src/init.rs b/core/startos/src/init.rs index d1d5a9943..3f7d7f1bc 100644 --- a/core/startos/src/init.rs +++ b/core/startos/src/init.rs @@ -232,15 +232,12 @@ pub async fn init(cfg: &ServerConfig) -> Result { .invoke(crate::ErrorKind::OpenSsl) .await?; - if let Some(wifi_interface) = &cfg.wifi_interface { - crate::net::wifi::synchronize_wpa_supplicant_conf( - &cfg.datadir().join("main"), - wifi_interface, - &server_info.last_wifi_region, - ) - .await?; - tracing::info!("Synchronized WiFi"); - } + crate::net::wifi::synchronize_wpa_supplicant_conf( + &cfg.datadir().join("main"), + &mut server_info.wifi, + ) + .await?; + tracing::info!("Synchronized WiFi"); let should_rebuild = tokio::fs::metadata(SYSTEM_REBUILD_PATH).await.is_ok() || &*server_info.version < &emver::Version::new(0, 3, 2, 0) diff --git a/core/startos/src/net/wifi.rs b/core/startos/src/net/wifi.rs index 9de177bfe..93f610a42 100644 --- a/core/startos/src/net/wifi.rs +++ b/core/startos/src/net/wifi.rs @@ -16,6 +16,8 @@ use tracing::instrument; use ts_rs::TS; use crate::context::{CliContext, RpcContext}; +use crate::db::model::public::WifiInfo; +use crate::net::utils::find_wifi_iface; use crate::prelude::*; use crate::util::serde::{display_serializable, HandlerExtSerde, WithIoFormat}; use crate::util::Invoke; @@ -137,6 +139,18 @@ pub async fn add(ctx: RpcContext, AddParams { ssid, password }: AddParams) -> Re ErrorKind::Wifi, )); } + ctx.db + .mutate(|db| { + db.as_public_mut() + .as_server_info_mut() + .as_wifi_mut() + .as_ssids_mut() + .mutate(|s| { + s.insert(ssid); + Ok(()) + }) + }) + .await?; Ok(()) } #[derive(Deserialize, Serialize, Parser, TS)] @@ -190,6 +204,17 @@ pub async fn connect(ctx: RpcContext, SsidParams { ssid }: SsidParams) -> Result ErrorKind::Wifi, )); } + + ctx.db + .mutate(|db| { + let wifi = db.as_public_mut().as_server_info_mut().as_wifi_mut(); + wifi.as_ssids_mut().mutate(|s| { + s.insert(ssid.clone()); + Ok(()) + })?; + wifi.as_selected_mut().ser(&Some(ssid)) + }) + .await?; Ok(()) } @@ -215,11 +240,23 @@ pub async fn delete(ctx: RpcContext, SsidParams { ssid }: SsidParams) -> Result< } wpa_supplicant.remove_network(ctx.db.clone(), &ssid).await?; + + ctx.db + .mutate(|db| { + let wifi = db.as_public_mut().as_server_info_mut().as_wifi_mut(); + wifi.as_ssids_mut().mutate(|s| { + s.remove(&ssid.0); + Ok(()) + })?; + wifi.as_selected_mut() + .map_mutate(|s| Ok(s.filter(|s| s == &ssid.0))) + }) + .await?; Ok(()) } #[derive(serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] -pub struct WiFiInfo { +pub struct WifiListInfo { ssids: HashMap, connected: Option, country: Option, @@ -228,7 +265,7 @@ pub struct WiFiInfo { } #[derive(serde::Serialize, serde::Deserialize, Clone)] #[serde(rename_all = "camelCase")] -pub struct WifiListInfo { +pub struct WifiListInfoLow { strength: SignalStrength, security: Vec, } @@ -239,8 +276,8 @@ pub struct WifiListOut { strength: SignalStrength, security: Vec, } -pub type WifiList = HashMap; -fn display_wifi_info(params: WithIoFormat, info: WiFiInfo) { +pub type WifiList = HashMap; +fn display_wifi_info(params: WithIoFormat, info: WifiListInfo) { use prettytable::*; if let Some(format) = params.format { @@ -330,7 +367,7 @@ fn display_wifi_list(params: WithIoFormat, info: Vec) { // #[command(display(display_wifi_info))] #[instrument(skip_all)] -pub async fn get(ctx: RpcContext, _: Empty) -> Result { +pub async fn get(ctx: RpcContext, _: Empty) -> Result { let wifi_manager = wifi_manager(&ctx)?; let wpa_supplicant = wifi_manager.read().await; let (list_networks, current_res, country_res, ethernet_res, signal_strengths) = tokio::join!( @@ -368,7 +405,7 @@ pub async fn get(ctx: RpcContext, _: Empty) -> Result { }) .collect(); let current = current_res?; - Ok(WiFiInfo { + Ok(WifiListInfo { ssids, connected: current, country: country_res?, @@ -477,7 +514,7 @@ impl SignalStrength { } #[derive(Debug, Clone)] -pub struct WifiInfo { +pub struct WifiInfoLow { ssid: Ssid, device: Option, } @@ -604,7 +641,7 @@ impl WpaCli { Ok(()) } #[instrument(skip_all)] - pub async fn list_networks_low(&self) -> Result, Error> { + pub async fn list_networks_low(&self) -> Result, Error> { let r = Command::new("nmcli") .arg("-t") .arg("c") @@ -623,13 +660,13 @@ impl WpaCli { if !connection_type.contains("wireless") { return None; } - let info = WifiInfo { + let info = WifiInfoLow { ssid: name, device: device.map(|x| x.to_owned()), }; Some((uuid, info)) }) - .collect::>()) + .collect::>()) } #[instrument(skip_all)] @@ -652,7 +689,7 @@ impl WpaCli { values.next()?.split(' ').map(|x| x.to_owned()).collect(); Some(( ssid, - WifiListInfo { + WifiListInfoLow { strength: signal, security, }, @@ -686,7 +723,8 @@ impl WpaCli { db.mutate(|d| { d.as_public_mut() .as_server_info_mut() - .as_last_wifi_region_mut() + .as_wifi_mut() + .as_last_region_mut() .ser(&new_country) }) .await @@ -837,9 +875,12 @@ impl TypedValueParser for CountryCodeParser { #[instrument(skip_all)] pub async fn synchronize_wpa_supplicant_conf>( main_datadir: P, - wifi_iface: &str, - last_country_code: &Option, + wifi: &mut WifiInfo, ) -> Result<(), Error> { + wifi.interface = find_wifi_iface().await?; + let Some(wifi_iface) = &wifi.interface else { + return Ok(()); + }; let persistent = main_datadir.as_ref().join("system-connections"); tracing::debug!("persistent: {:?}", persistent); // let supplicant = Path::new("/etc/wpa_supplicant.conf"); @@ -863,7 +904,7 @@ pub async fn synchronize_wpa_supplicant_conf>( .arg("up") .invoke(ErrorKind::Wifi) .await?; - if let Some(last_country_code) = last_country_code { + if let Some(last_country_code) = wifi.last_region { tracing::info!("Setting the region"); let _ = Command::new("iw") .arg("reg") diff --git a/core/startos/src/os_install/mod.rs b/core/startos/src/os_install/mod.rs index 0abd1d23e..4bbbe70a6 100644 --- a/core/startos/src/os_install/mod.rs +++ b/core/startos/src/os_install/mod.rs @@ -17,7 +17,7 @@ use crate::disk::mount::filesystem::{MountType, ReadWrite}; use crate::disk::mount::guard::{GenericMountGuard, MountGuard, TmpMountGuard}; use crate::disk::util::{DiskInfo, PartitionTable}; use crate::disk::OsPartitionInfo; -use crate::net::utils::{find_eth_iface, find_wifi_iface}; +use crate::net::utils::find_eth_iface; use crate::util::serde::IoFormat; use crate::util::Invoke; use crate::ARCH; @@ -140,7 +140,6 @@ pub async fn execute( ) })?; let eth_iface = find_eth_iface().await?; - let wifi_iface = find_wifi_iface().await?; overwrite |= disk.guid.is_none() && disk.partitions.iter().all(|p| p.guid.is_none()); @@ -260,7 +259,6 @@ pub async fn execute( IoFormat::Yaml.to_vec(&ServerConfig { os_partitions: Some(part_info.clone()), ethernet_interface: Some(eth_iface), - wifi_interface: wifi_iface, ..Default::default() })?, ) diff --git a/core/startos/src/setup.rs b/core/startos/src/setup.rs index b8b761e69..9120544e3 100644 --- a/core/startos/src/setup.rs +++ b/core/startos/src/setup.rs @@ -419,11 +419,7 @@ async fn fresh_setup( ) -> Result<(Hostname, OnionAddressV3, X509), Error> { let account = AccountInfo::new(start_os_password, root_ca_start_time().await?)?; let db = ctx.db().await?; - db.put( - &ROOT, - &Database::init(&account, ctx.config.wifi_interface.clone())?, - ) - .await?; + db.put(&ROOT, &Database::init(&account)?).await?; drop(db); init(&ctx.config).await?; Ok(( diff --git a/web/projects/ui/src/app/services/api/mock-patch.ts b/web/projects/ui/src/app/services/api/mock-patch.ts index 446bf2424..ed0edacbe 100644 --- a/web/projects/ui/src/app/services/api/mock-patch.ts +++ b/web/projects/ui/src/app/services/api/mock-patch.ts @@ -55,7 +55,6 @@ export const mockPatchData: DataModel = { ipv6Range: 'FE80:CD00:0000:0CDE:1257:0000:211E:729CD/64', }, }, - lastWifiRegion: null, unreadNotificationCount: 4, // password is asdfasdf passwordHash: @@ -79,7 +78,7 @@ export const mockPatchData: DataModel = { interface: 'wlan0', ssids: [], selected: null, - connected: null, + lastRegion: null, }, }, packageData: {