diff --git a/client/src/main.rs b/client/src/main.rs index ab12ac1..e29d36a 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -420,8 +420,7 @@ fn fetch( } fn uninstall(interface: &InterfaceName) -> Result<(), Error> { - let theme = ColorfulTheme::default(); - if Confirm::with_theme(&theme) + if Confirm::with_theme(&*prompts::THEME) .with_prompt(&format!( "Permanently delete network \"{}\"?", interface.as_str_lossy().yellow() diff --git a/server/src/main.rs b/server/src/main.rs index ddddd3a..2a1a5bc 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,4 +1,5 @@ use colored::*; +use dialoguer::Confirm; use error::handle_rejection; use hyper::{server::conn::AddrStream, Body, Request}; use indoc::printdoc; @@ -52,6 +53,9 @@ enum Command { #[structopt(alias = "init")] New, + /// Permanently uninstall a created network, rendering it unusable. Use with care. + Uninstall { interface: Interface }, + /// Serve the coordinating server for an existing network. Serve { interface: Interface }, @@ -125,7 +129,11 @@ impl ConfigFile { let path = path.as_ref(); let file = File::open(path).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() + ); } Ok(toml::from_slice(&std::fs::read(&path).with_path(path)?)?) } @@ -191,6 +199,7 @@ async fn main() -> Result<(), Box> { println!("{}: {}.", "creation failed".red(), e); } }, + Command::Uninstall { interface } => uninstall(&interface, &conf)?, Command::Serve { interface } => serve(&interface, &conf).await?, Command::AddPeer { interface } => add_peer(&interface, &conf)?, Command::AddCidr { interface } => add_cidr(&interface, &conf)?, @@ -337,6 +346,36 @@ async fn serve(interface: &InterfaceName, conf: &ServerConfig) -> Result<(), Err Ok(()) } +fn uninstall(interface: &InterfaceName, conf: &ServerConfig) -> Result<(), Error> { + if Confirm::with_theme(&*prompts::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 = conf.config_path(interface); + let data = conf.database_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(()) +} + /// This function differs per OS, because different operating systems have /// opposing characteristics when binding to a specific IP address. /// On Linux, binding to a specific local IP address does *not* bind it to diff --git a/shared/src/prompts.rs b/shared/src/prompts.rs index 5506793..650ae04 100644 --- a/shared/src/prompts.rs +++ b/shared/src/prompts.rs @@ -12,7 +12,7 @@ use std::net::{IpAddr, SocketAddr}; use wgctrl::{InterfaceName, KeyPair}; lazy_static! { - static ref THEME: ColorfulTheme = ColorfulTheme::default(); + pub static ref THEME: ColorfulTheme = ColorfulTheme::default(); /// Regex to match the requirements of hostname(7), needed to have peers also be reachable hostnames. /// Note that the full length also must be maximum 63 characters, which this regex does not check.