diff options
| author | Emīls Piņķis <emils@mullvad.net> | 2019-07-22 19:00:12 +0100 |
|---|---|---|
| committer | Emīls Piņķis <emils@mullvad.net> | 2019-07-22 19:00:12 +0100 |
| commit | 81e8f3ca90749d6dc202bdf6b399ec377dfed6fb (patch) | |
| tree | d2e89ceee050072dcd2dc886b2a38c9a93b5909b | |
| parent | 227fc1d94d84ec3665965f5e94abcae1537f7462 (diff) | |
| parent | 63447330e70bc685b3919b9bad5238a6f0030907 (diff) | |
| download | mullvadvpn-81e8f3ca90749d6dc202bdf6b399ec377dfed6fb.tar.xz mullvadvpn-81e8f3ca90749d6dc202bdf6b399ec377dfed6fb.zip | |
Merge branch 'add-reset-command'
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/mod.rs | 4 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/reset.rs | 44 | ||||
| -rw-r--r-- | mullvad-daemon/src/account_history.rs | 6 | ||||
| -rw-r--r-- | mullvad-daemon/src/lib.rs | 53 | ||||
| -rw-r--r-- | mullvad-daemon/src/management_interface.rs | 17 | ||||
| -rw-r--r-- | mullvad-ipc-client/src/lib.rs | 4 | ||||
| -rw-r--r-- | mullvad-types/src/settings.rs | 30 |
8 files changed, 156 insertions, 3 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 6de581ecd3..008daea001 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ Line wrap the file at 100 chars. Th ## [Unreleased] ### Added - Add new settings page for generating and verifying wireguard keys. +- Add `factory-reset` CLI command for removing settings, logs and clearing the cache. ### Changed - Upgrade OpenVPN from 2.4.6 to 2.4.7. diff --git a/mullvad-cli/src/cmds/mod.rs b/mullvad-cli/src/cmds/mod.rs index 83bfd47883..8caf26eac5 100644 --- a/mullvad-cli/src/cmds/mod.rs +++ b/mullvad-cli/src/cmds/mod.rs @@ -28,6 +28,9 @@ pub use self::relay::Relay; mod lan; pub use self::lan::Lan; +mod reset; +pub use self::reset::Reset; + mod tunnel; pub use self::tunnel::Tunnel; @@ -45,6 +48,7 @@ pub fn get_commands() -> HashMap<&'static str, Box<dyn Command>> { Box::new(Disconnect), Box::new(Lan), Box::new(Relay), + Box::new(Reset), Box::new(Status), Box::new(Tunnel), Box::new(Version), diff --git a/mullvad-cli/src/cmds/reset.rs b/mullvad-cli/src/cmds/reset.rs new file mode 100644 index 0000000000..d859d1e436 --- /dev/null +++ b/mullvad-cli/src/cmds/reset.rs @@ -0,0 +1,44 @@ +use crate::{new_rpc_client, Command, Result}; +use std::io::stdin; + +pub struct Reset; +impl Command for Reset { + fn name(&self) -> &'static str { + "factory-reset" + } + + fn clap_subcommand(&self) -> clap::App<'static, 'static> { + clap::SubCommand::with_name(self.name()).about("Reset settings, caches and logs") + } + + fn run(&self, _matches: &clap::ArgMatches<'_>) -> Result<()> { + let mut rpc = new_rpc_client()?; + if Self::receive_confirmation() { + if rpc.factory_reset().is_err() { + eprintln!("FAILED TO PERFORM FACTORY RESET"); + } else { + #[cfg(target_os = "linux")] + println!("If you're running systemd, to remove all logs, you must use journalctl"); + } + } + Ok(()) + } +} + +impl Reset { + fn receive_confirmation() -> bool { + println!("Are you sure you want to disconnect, log out, delete all settings, logs and cache files for the Mullvad VPN system service? [Yes/No (default)]"); + loop { + let mut buf = String::new(); + if let Err(e) = stdin().read_line(&mut buf) { + eprintln!("Couldn't read from STDIN - {}", e); + return false; + } + match buf.trim() { + "Yes" => return true, + "No" | "no" | "" => return false, + _ => println!("Unexpected response. Please enter \"Yes\" or \"No\""), + } + } + } +} diff --git a/mullvad-daemon/src/account_history.rs b/mullvad-daemon/src/account_history.rs index c8bb92c7a9..faecc5b5e7 100644 --- a/mullvad-daemon/src/account_history.rs +++ b/mullvad-daemon/src/account_history.rs @@ -147,6 +147,12 @@ impl AccountHistory { self.save_to_disk() } + /// Remove account history + pub fn clear(&mut self) -> Result<()> { + self.accounts = VecDeque::new(); + self.save_to_disk() + } + fn save_to_disk(&mut self) -> Result<()> { self.file.get_mut().set_len(0).map_err(Error::Write)?; self.file diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs index 8309f42e81..5fb1f11a89 100644 --- a/mullvad-daemon/src/lib.rs +++ b/mullvad-daemon/src/lib.rs @@ -46,7 +46,7 @@ use mullvad_types::{ wireguard::KeygenEvent, }; use settings::Settings; -use std::{io, mem, path::PathBuf, sync::mpsc, thread, time::Duration}; +use std::{fs, io, mem, path::PathBuf, sync::mpsc, thread, time::Duration}; use talpid_core::{ mpsc::IntoSender, tunnel::tun_provider::{PlatformTunProvider, TunProvider}, @@ -101,6 +101,15 @@ pub enum Error { #[error(display = "Tunnel state machine error")] TunnelError(#[error(cause)] tunnel_state_machine::Error), + + #[error(display = "Failed to remove a directory")] + RemovalError(#[error(cause)] io::Error), + + #[error(display = "Failed to create a directory")] + CreateDirError(#[error(cause)] io::Error), + + #[error(display = "Failed to get path")] + PathError(#[error(cause)] mullvad_paths::Error), } type SyncUnboundedSender<T> = ::futures::sink::Wait<UnboundedSender<T>>; @@ -699,6 +708,7 @@ where VerifyWireguardKey(tx) => self.on_verify_wireguard_key(tx), GetVersionInfo(tx) => self.on_get_version_info(tx), GetCurrentVersion(tx) => self.on_get_current_version(tx), + FactoryReset(tx) => self.on_factory_reset(tx), Shutdown => self.handle_trigger_shutdown_event(), } } @@ -932,6 +942,35 @@ where Self::oneshot_send(tx, self.version.clone(), "get_current_version response"); } + fn on_factory_reset(&mut self, tx: oneshot::Sender<()>) { + self.set_target_state(TargetState::Unsecured); + let mut failed = false; + + if let Err(e) = self.clear_cache_directory() { + log::error!("Failed to clear cache directory - {}", e); + failed = true; + } + + if let Err(e) = self.clear_log_directory() { + log::error!("Failed to clear log directory - {}", e); + failed = true; + } + + if let Err(e) = self.settings.reset() { + log::error!("Failed to reset settings - {}", e); + failed = true; + } + + if let Err(e) = self.account_history.clear() { + log::error!("Failed to clear account history - {}", e); + failed = true; + } + + if !failed { + Self::oneshot_send(tx, (), "factory_reset response"); + } + } + fn on_update_relay_settings(&mut self, tx: oneshot::Sender<()>, update: RelaySettingsUpdate) { let save_result = self.settings.update_relay_settings(update); match save_result { @@ -1293,6 +1332,18 @@ where .expect("Tunnel state machine has stopped"); } + fn clear_log_directory(&self) -> Result<()> { + let log_dir = mullvad_paths::get_log_dir().map_err(Error::PathError)?; + fs::remove_dir_all(&log_dir).map_err(Error::RemovalError)?; + fs::create_dir_all(&log_dir).map_err(Error::CreateDirError) + } + + fn clear_cache_directory(&self) -> Result<()> { + let cache_dir = mullvad_paths::cache_dir().map_err(Error::PathError)?; + fs::remove_dir_all(&cache_dir).map_err(Error::RemovalError)?; + fs::create_dir_all(&cache_dir).map_err(Error::CreateDirError) + } + pub fn shutdown_handle(&self) -> DaemonShutdownHandle { DaemonShutdownHandle { tx: self.tx.clone(), diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs index a2eae7830d..04193ca9b5 100644 --- a/mullvad-daemon/src/management_interface.rs +++ b/mullvad-daemon/src/management_interface.rs @@ -151,6 +151,10 @@ build_rpc_trait! { #[rpc(meta, name = "get_version_info")] fn get_version_info(&self, Self::Metadata) -> BoxFuture<version::AppVersionInfo, Error>; + /// Remove all configuration and cache files + #[rpc(meta, name = "factory_reset")] + fn factory_reset(&self, Self::Metadata) -> BoxFuture<(), Error>; + #[pubsub(name = "daemon_event")] { /// Subscribes to events from the daemon. #[rpc(name = "daemon_event_subscribe")] @@ -222,6 +226,8 @@ pub enum ManagementCommand { GetVersionInfo(OneshotSender<BoxFuture<version::AppVersionInfo, mullvad_rpc::Error>>), /// Get current version of the app GetCurrentVersion(OneshotSender<version::AppVersion>), + /// Remove settings and clear the cache + FactoryReset(OneshotSender<()>), /// Makes the daemon exit the main loop and quit. Shutdown, } @@ -679,6 +685,17 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi Box::new(future) } + fn factory_reset(&self, _: Self::Metadata) -> BoxFuture<(), Error> { + log::debug!("factory_reset"); + let (tx, rx) = sync::oneshot::channel(); + let future = self + .send_command_to_daemon(ManagementCommand::FactoryReset(tx)) + .and_then(|_| rx.map_err(|_| Error::internal_error())); + + Box::new(future) + } + + fn daemon_event_subscribe( &self, _: Self::Metadata, diff --git a/mullvad-ipc-client/src/lib.rs b/mullvad-ipc-client/src/lib.rs index 98b6206ba4..bf6ea760a7 100644 --- a/mullvad-ipc-client/src/lib.rs +++ b/mullvad-ipc-client/src/lib.rs @@ -204,6 +204,10 @@ impl DaemonRpcClient { self.call("shutdown", &NO_ARGS) } + pub fn factory_reset(&mut self) -> Result<()> { + self.call("factory_reset", &NO_ARGS) + } + pub fn update_relay_settings(&mut self, update: RelaySettingsUpdate) -> Result<()> { self.call("update_relay_settings", &[update]) } diff --git a/mullvad-types/src/settings.rs b/mullvad-types/src/settings.rs index 41f280c973..dab81bf43a 100644 --- a/mullvad-types/src/settings.rs +++ b/mullvad-types/src/settings.rs @@ -5,8 +5,15 @@ use crate::relay_constraints::{ use log::{debug, info}; use serde::{Deserialize, Serialize}; use serde_json; -use std::{fs::File, io, path::PathBuf}; -use talpid_types::net::{openvpn, wireguard, GenericTunnelOptions}; +use std::{ + fs::{self, File}, + io, + path::PathBuf, +}; +use talpid_types::{ + net::{openvpn, wireguard, GenericTunnelOptions}, + ErrorExt, +}; pub type Result<T> = std::result::Result<T, Error>; @@ -19,6 +26,9 @@ pub enum Error { #[error(display = "Unable to read settings from {}", _0)] ReadError(String, #[error(cause)] io::Error), + #[error(display = "Unable to remove settings file {}", _0)] + DeleteError(String, #[error(cause)] io::Error), + #[error(display = "Malformed settings")] ParseError(#[error(cause)] serde_json::Error), @@ -101,6 +111,22 @@ impl Settings { .map_err(|e| Error::WriteError(path.display().to_string(), e)) } + /// Resets default settings + pub fn reset(&mut self) -> Result<()> { + *self = Default::default(); + self.save().or_else(|e| { + log::error!( + "{}", + e.display_chain_with_msg("Unable to save default settings") + ); + log::error!("Will attempt to remove settings file"); + Self::get_settings_path().and_then(|path| { + fs::remove_file(&path) + .map_err(|e| Error::DeleteError(path.display().to_string(), e)) + }) + }) + } + fn get_settings_path() -> Result<PathBuf> { let dir = ::mullvad_paths::settings_dir().map_err(Error::DirectoryError)?; Ok(dir.join(SETTINGS_FILE)) |
