diff --git a/client/src/data_store.rs b/client/src/data_store.rs index ea46a08..c69b590 100644 --- a/client/src/data_store.rs +++ b/client/src/data_store.rs @@ -5,7 +5,7 @@ use shared::{ensure_dirs_exist, Cidr, IoErrorContext, Peer, CLIENT_DATA_PATH}; use std::{ fs::{File, OpenOptions}, io::{Read, Seek, SeekFrom, Write}, - path::Path, + path::{Path, PathBuf}, }; use wgctrl::InterfaceName; @@ -33,7 +33,11 @@ impl DataStore { .with_path(path)?; if shared::chmod(&file, 0o600)? { - println!("{} updated permissions for {} to 0600.", "[!]".yellow(), path.display()); + println!( + "{} updated permissions for {} to 0600.", + "[!]".yellow(), + path.display() + ); } let mut json = String::new(); @@ -46,14 +50,15 @@ impl DataStore { Ok(Self { file, contents }) } + pub fn get_path(interface: &InterfaceName) -> PathBuf { + CLIENT_DATA_PATH + .join(interface.to_string()) + .with_extension("json") + } + fn _open(interface: &InterfaceName, create: bool) -> Result { ensure_dirs_exist(&[*CLIENT_DATA_PATH])?; - Self::open_with_path( - CLIENT_DATA_PATH - .join(interface.to_string()) - .with_extension("json"), - create, - ) + Self::open_with_path(Self::get_path(interface), create) } pub fn open(interface: &InterfaceName) -> Result { diff --git a/client/src/main.rs b/client/src/main.rs index 867782b..ab12ac1 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -96,6 +96,9 @@ enum Command { hosts: HostsOpt, }, + /// Uninstall an innernet network. + Uninstall { interface: Interface }, + /// Bring down the interface (equivalent to "wg-quick down [interface]") Down { interface: Interface }, @@ -416,6 +419,37 @@ fn fetch( Ok(()) } +fn uninstall(interface: &InterfaceName) -> Result<(), Error> { + let theme = ColorfulTheme::default(); + if Confirm::with_theme(&theme) + .with_prompt(&format!( + "Permanently delete network \"{}\"?", + interface.as_str_lossy().yellow() + )) + .default(false) + .interact()? + { + println!("{} bringing down interface (if up).", "[*]".dimmed()); + wg::down(interface).ok(); + let config = InterfaceConfig::get_path(interface); + let data = DataStore::get_path(interface); + std::fs::remove_file(&config) + .with_path(&config) + .map_err(|e| println!("[!] {}", e.to_string().yellow())) + .ok(); + std::fs::remove_file(&data) + .with_path(&data) + .map_err(|e| println!("[!] {}", e.to_string().yellow())) + .ok(); + println!( + "{} network {} is uninstalled.", + "[*]".dimmed(), + interface.as_str_lossy().yellow() + ); + } + Ok(()) +} + fn add_cidr(interface: &InterfaceName) -> Result<(), Error> { let InterfaceConfig { server, .. } = InterfaceConfig::from_interface(interface)?; println!("Fetching CIDRs"); @@ -790,6 +824,7 @@ fn run(opt: Opt) -> Result<(), Error> { hosts.into(), )?, Command::Down { interface } => wg::down(&interface)?, + Command::Uninstall { interface } => uninstall(&interface)?, Command::AddPeer { interface } => add_peer(&interface)?, Command::AddCidr { interface } => add_cidr(&interface)?, Command::DisablePeer { interface } => enable_or_disable_peer(&interface, false)?, diff --git a/shared/src/interface_config.rs b/shared/src/interface_config.rs index d0aaa2a..dd5b23c 100644 --- a/shared/src/interface_config.rs +++ b/shared/src/interface_config.rs @@ -67,7 +67,11 @@ impl InterfaceConfig { .with_path(path)?; if let Some(val) = mode { if crate::chmod(&target_file, 0o600)? { - println!("{} updated permissions for {} to 0600.", "[!]".yellow(), path.display()); + println!( + "{} updated permissions for {} to 0600.", + "[!]".yellow(), + path.display() + ); } let metadata = target_file.metadata()?; let mut permissions = metadata.permissions(); @@ -114,16 +118,24 @@ impl InterfaceConfig { let path = Self::build_config_file_path(interface)?; let file = File::open(&path).with_path(&path)?; if crate::chmod(&file, 0o600)? { - println!("{} updated permissions for {} to 0600.", "[!]".yellow(), path.display()); + println!( + "{} updated permissions for {} to 0600.", + "[!]".yellow(), + path.display() + ); } Self::from_file(path) } + pub fn get_path(interface: &InterfaceName) -> PathBuf { + CLIENT_CONFIG_PATH + .join(interface.to_string()) + .with_extension("conf") + } + fn build_config_file_path(interface: &InterfaceName) -> Result { ensure_dirs_exist(&[*CLIENT_CONFIG_PATH])?; - Ok(CLIENT_CONFIG_PATH - .join(interface.to_string()) - .with_extension("conf")) + Ok(Self::get_path(interface)) } }