diff options
| -rw-r--r-- | mullvad-daemon/src/access_method.rs | 35 | ||||
| -rw-r--r-- | mullvad-types/src/access_method.rs | 39 |
2 files changed, 54 insertions, 20 deletions
diff --git a/mullvad-daemon/src/access_method.rs b/mullvad-daemon/src/access_method.rs index 028e54f462..3bea2c4c7d 100644 --- a/mullvad-daemon/src/access_method.rs +++ b/mullvad-daemon/src/access_method.rs @@ -81,7 +81,7 @@ where ) -> Result<(), Error> { // Make sure that we are not trying to remove a built-in API access // method - let command = match self.settings.api_access_methods.find(&access_method) { + let command = match self.settings.api_access_methods.find_by_id(&access_method) { Some(api_access_method) => { if api_access_method.is_builtin() { Err(Error::RemoveBuiltIn) @@ -131,7 +131,7 @@ where ) -> Result<AccessMethodSetting, Error> { self.settings .api_access_methods - .find(&access_method) + .find_by_id(&access_method) .ok_or(Error::NoSuchMethod(access_method)) .cloned() } @@ -147,22 +147,37 @@ where &mut self, access_method_update: AccessMethodSetting, ) -> Result<(), Error> { - // We have to be a bit careful. If we are about to disable the last - // remaining enabled access method, we would cause an inconsistent state - // in the daemon's settings. Therefore, we have to safeguard against - // this by explicitly checking for & disallow any update which would - // cause the last enabled access method to become disabled. + // If the currently active access method is updated, we need to re-set + // it after updating the settings. let current = self.get_current_access_method().await?; let mut command = Command::Nothing; let settings_update = |settings: &mut Settings| { - if let Some(access_method) = settings - .api_access_methods - .find_mut(&access_method_update.get_id()) + let access_methods = &mut settings.api_access_methods; + if let Some(access_method) = + access_methods.find_by_id_mut(&access_method_update.get_id()) { *access_method = access_method_update; if access_method.get_id() == current.get_id() { command = Command::Set(access_method.get_id()) } + // We have to be a bit careful. If we are about to disable the last + // remaining enabled access method, we would cause an inconsistent state + // in the daemon's settings. Therefore, we have to safeguard against + // this by explicitly checking for any update which would cause the last + // enabled access method to become disabled. In that case, we should + // re-enable the `Direct` access method. + if access_methods.collect_enabled().is_empty() { + if let Some(direct) = access_methods.get_direct() { + direct.enabled = true; + } else { + // If the `Direct` access method does not exist within the + // settings for some reason, the settings are in an + // inconsistent state. We don't have much choice but to + // reset these settings to their default value. + log::warn!("The built-in access methods can not be found. This might be due to a corrupt settings file"); + *access_methods = access_method::Settings::default(); + } + } } }; diff --git a/mullvad-types/src/access_method.rs b/mullvad-types/src/access_method.rs index 7afaf94dfc..0c697acbbf 100644 --- a/mullvad-types/src/access_method.rs +++ b/mullvad-types/src/access_method.rs @@ -21,22 +21,34 @@ impl Settings { self.retain(|method| method.get_id() != *api_access_method) } - /// Search for a particular [`AccessMethod`] in `api_access_methods`. - pub fn find(&self, element: &Id) -> Option<&AccessMethodSetting> { + /// Search for any [`AccessMethod`] in `api_access_methods` which matches `predicate`. + pub fn find<P>(&self, predicate: P) -> Option<&AccessMethodSetting> + where + P: Fn(&AccessMethodSetting) -> bool, + { self.access_method_settings .iter() - .find(|api_access_method| *element == api_access_method.get_id()) + .find(|api_access_method| predicate(api_access_method)) } - /// Search for a particular [`AccessMethod`] in `api_access_methods`. - /// - /// If the [`AccessMethod`] is found to be part of `api_access_methods`, a - /// mutable reference to that inner element is returned. Otherwise, `None` - /// is returned. - pub fn find_mut(&mut self, element: &Id) -> Option<&mut AccessMethodSetting> { + /// Search for any [`AccessMethod`] in `api_access_methods`. + pub fn find_mut<P>(&mut self, predicate: P) -> Option<&mut AccessMethodSetting> + where + P: Fn(&AccessMethodSetting) -> bool, + { self.access_method_settings .iter_mut() - .find(|api_access_method| *element == api_access_method.get_id()) + .find(|api_access_method| predicate(api_access_method)) + } + + /// Search for a particular [`AccessMethod`] in `api_access_methods`. + pub fn find_by_id(&self, element: &Id) -> Option<&AccessMethodSetting> { + self.find(|api_access_method| *element == api_access_method.get_id()) + } + + /// Search for a particular [`AccessMethod`] in `api_access_methods`. + pub fn find_by_id_mut(&mut self, element: &Id) -> Option<&mut AccessMethodSetting> { + self.find_mut(|api_access_method| *element == api_access_method.get_id()) } /// Equivalent to [`Vec::retain`]. @@ -52,6 +64,13 @@ impl Settings { self.access_method_settings.clone() } + /// Get a reference to the `Direct` access method instance of this [`Settings`]. + pub fn get_direct(&mut self) -> Option<&mut AccessMethodSetting> { + self.find_mut(|access_method| { + access_method.access_method == BuiltInAccessMethod::Direct.into() + }) + } + pub fn direct() -> AccessMethodSetting { let method = BuiltInAccessMethod::Direct; AccessMethodSetting::new(method.canonical_name(), true, AccessMethod::from(method)) |
