summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMarkus Pettersson <markus.pettersson@mullvad.net>2024-01-31 11:03:55 +0100
committerMarkus Pettersson <markus.pettersson@mullvad.net>2024-01-31 12:46:16 +0100
commit7cd49c0bb24ad7c104f2f244b9e9258f5663d656 (patch)
treef38d1a6689d037a0f93157732468a5a04fb7a933
parent8dbdc97b7dafaab15dc877538e5ff48af007b46e (diff)
downloadmullvadvpn-7cd49c0bb24ad7c104f2f244b9e9258f5663d656.tar.xz
mullvadvpn-7cd49c0bb24ad7c104f2f244b9e9258f5663d656.zip
Change API access methods settings format
Change API access methods settings format to encode that built-in access methods always exist by making them distinct values of the `AccessMethod` settings. This change was also propagated to the corresponding protobuf definition, such that any client may make use of this fact as well. The appropriate settings migration was added.
-rw-r--r--mullvad-daemon/src/migrations/v7.rs313
-rw-r--r--mullvad-management-interface/proto/management_interface.proto6
-rw-r--r--mullvad-management-interface/src/client.rs17
-rw-r--r--mullvad-management-interface/src/types/conversions/access_method.rs52
-rw-r--r--mullvad-management-interface/src/types/conversions/settings.rs2
-rw-r--r--mullvad-types/src/access_method.rs179
-rw-r--r--mullvad-types/src/settings/mod.rs2
7 files changed, 460 insertions, 111 deletions
diff --git a/mullvad-daemon/src/migrations/v7.rs b/mullvad-daemon/src/migrations/v7.rs
index efd3193624..4614cedce9 100644
--- a/mullvad-daemon/src/migrations/v7.rs
+++ b/mullvad-daemon/src/migrations/v7.rs
@@ -75,6 +75,10 @@ pub struct ShadowsocksProxySettings {
/// that instead of having a Socks5 and Shadowsocks variant instead has a Socks5Local, Socks5Remote
/// and Shadowsocks variant.
///
+/// The predefined access methods "Direct" and "Mullvad Bridges" are now stored as distinct keys in
+/// the api_access_methods settings, separating them from user-defined access methods in the settings
+/// datastructure.
+///
/// We also take the oppertunity to rename a couple of fields that relate to proxy types.
/// We rename
/// - shadowsocks.peer to shadowsocks.endpoint
@@ -141,6 +145,62 @@ fn migrate_api_access_settings(settings: &mut serde_json::Value) -> Result<()> {
}
}
+ // Step 1. Rename { "api_access_methods": { "access_method_settings": .. } } to { "api_access_methods": { "custom": .. } }.
+ // Step 2. Collect all of the built-in methods from { "api_access_methods": { "custom": [ .. ] } }.
+ // Step 3. Remove all of the built-in methods from { "api_access_methods": { "custom": [ .. ] } }.
+ // Step 4. Add the collected built-in methods from step 2 to { "api_access_methods": { .. } } under some appropriate key.
+ if let Some(access_method_settings) = settings
+ .get_mut("api_access_methods")
+ .and_then(serde_json::value::Value::as_object_mut)
+ {
+ // Step 1.
+ rename_map_field(access_method_settings, "access_method_settings", "custom")?;
+
+ if let Some(access_method_settings_list) = access_method_settings
+ .get_mut("custom")
+ .and_then(serde_json::value::Value::as_array_mut)
+ {
+ // Step 2.
+ let built_ins: Vec<_> = access_method_settings_list
+ .iter()
+ .filter(|value| {
+ value
+ .get("access_method")
+ .and_then(|value| value.get("built_in"))
+ .is_some()
+ })
+ .cloned()
+ .collect();
+
+ // Step 3.
+ for built_in in built_ins.iter() {
+ access_method_settings_list
+ .retain(|access_method| access_method.get("id") != built_in.get("id"));
+ }
+
+ // Step 4.
+ // Note that the only supported built-in access methods at this time
+ // are "Direct" and "Mullvad Bridges", so we may discard anything
+ // else.
+ let built_ins: Vec<_> = built_ins
+ .into_iter()
+ .filter_map(|built_in| {
+ match built_in
+ .get("access_method")
+ .and_then(|value| value.get("built_in"))
+ .and_then(|value| value.as_str())
+ {
+ Some("direct") => Some(("direct".to_string(), built_in)),
+ Some("bridge") => Some(("mullvad_bridges".to_string(), built_in)),
+ Some(_) | None => None,
+ }
+ })
+ .collect();
+
+ access_method_settings.extend(built_ins);
+ }
+ }
+
Ok(())
}
@@ -228,15 +288,24 @@ fn extract_str(opt: Option<&serde_json::Value>) -> Result<&str> {
.ok_or(Error::InvalidSettingsContent)
}
-fn rename_field(object: &mut serde_json::Value, old_name: &str, new_name: &str) -> Result<()> {
- object[new_name] = object
+fn rename_field(value: &mut serde_json::Value, old_name: &str, new_name: &str) -> Result<()> {
+ value
+ .as_object_mut()
+ .ok_or(Error::InvalidSettingsContent)
+ .and_then(|object| rename_map_field(object, old_name, new_name))
+}
+
+fn rename_map_field(
+ object: &mut serde_json::Map<String, serde_json::Value>,
+ old_name: &str,
+ new_name: &str,
+) -> Result<()> {
+ let old_value = object
.get(old_name)
.ok_or(Error::InvalidSettingsContent)?
.clone();
- object
- .as_object_mut()
- .ok_or(Error::InvalidSettingsContent)?
- .remove(old_name);
+ let _ = object.insert(new_name.to_string(), old_value);
+ object.remove(old_name);
Ok(())
}
@@ -475,23 +544,23 @@ mod test {
}
},
"api_access_methods": {
- "access_method_settings": [
- {
- "id": "8cbdcfc8-fa7b-41de-8d12-26fa37439f89",
- "name": "Direct",
- "enabled": true,
- "access_method": {
- "built_in": "direct"
- }
- },
- {
- "id": "1d0d8891-dbb3-4439-a8f7-0e7d742ddbe4",
- "name": "Mullvad Bridges",
- "enabled": true,
- "access_method": {
- "built_in": "bridge"
- }
- },
+ "direct": {
+ "id": "8cbdcfc8-fa7b-41de-8d12-26fa37439f89",
+ "name": "Direct",
+ "enabled": true,
+ "access_method": {
+ "built_in": "direct"
+ }
+ },
+ "mullvad_bridges": {
+ "id": "1d0d8891-dbb3-4439-a8f7-0e7d742ddbe4",
+ "name": "Mullvad Bridges",
+ "enabled": true,
+ "access_method": {
+ "built_in": "bridge"
+ }
+ },
+ "custom": [
{
"id": "1aaff7ab-e09f-4c03-af02-765e41943a7b",
"name": "localsox",
@@ -851,7 +920,7 @@ mod test {
r#"
{
"api_access_methods": {
- "access_method_settings": [
+ "custom": [
{
"id": "5eb9b2ee-f764-47c8-8111-ee95910d0099",
"name": "mysocks",
@@ -880,7 +949,6 @@ mod test {
#[test]
fn test_api_access_methods_custom_socks5_remote() {
- println!("wew");
let mut pre: serde_json::Value = serde_json::from_str(
r#"
{
@@ -910,7 +978,7 @@ mod test {
r#"
{
"api_access_methods": {
- "access_method_settings": [
+ "custom": [
{
"id": "8e377232-8a53-4414-8b8f-f487227aaedb",
"name": "remotesox",
@@ -965,7 +1033,7 @@ mod test {
r#"
{
"api_access_methods": {
- "access_method_settings": [
+ "custom": [
{
"id": "74e5c659-acdd-4cad-a632-a25bf63c20e2",
"name": "remotess",
@@ -989,4 +1057,195 @@ mod test {
migrate_api_access_settings(&mut pre).unwrap();
assert_eq!(pre, post);
}
+
+ #[test]
+ fn test_api_access_methods_extract_direct() {
+ let mut pre: serde_json::Value = serde_json::from_str(
+ r#"
+{
+ "api_access_methods": {
+ "access_method_settings": [
+ {
+ "id": "8cbdcfc8-fa7b-41de-8d12-26fa37439f89",
+ "name": "Direct",
+ "enabled": true,
+ "access_method": {
+ "built_in": "direct"
+ }
+ }
+ ]
+ }
+}
+"#,
+ )
+ .unwrap();
+
+ let post: serde_json::Value = serde_json::from_str(
+ r#"
+{
+ "api_access_methods": {
+ "direct": {
+ "id": "8cbdcfc8-fa7b-41de-8d12-26fa37439f89",
+ "name": "Direct",
+ "enabled": true,
+ "access_method": {
+ "built_in": "direct"
+ }
+ },
+ "custom": []
+ }
+}
+"#,
+ )
+ .unwrap();
+
+ migrate_api_access_settings(&mut pre).unwrap();
+ assert_eq!(pre, post);
+ }
+
+ #[test]
+ fn test_api_access_methods_extract_mullvad_bridges() {
+ let mut pre: serde_json::Value = serde_json::from_str(
+ r#"
+{
+ "api_access_methods": {
+ "access_method_settings": [
+ {
+ "id": "1d0d8891-dbb3-4439-a8f7-0e7d742ddbe4",
+ "name": "Mullvad Bridges",
+ "enabled": true,
+ "access_method": {
+ "built_in": "bridge"
+ }
+ }
+ ]
+ }
+}
+"#,
+ )
+ .unwrap();
+
+ let post: serde_json::Value = serde_json::from_str(
+ r#"
+{
+ "api_access_methods": {
+ "mullvad_bridges": {
+ "id": "1d0d8891-dbb3-4439-a8f7-0e7d742ddbe4",
+ "name": "Mullvad Bridges",
+ "enabled": true,
+ "access_method": {
+ "built_in": "bridge"
+ }
+ },
+ "custom": []
+ }
+}
+"#,
+ )
+ .unwrap();
+
+ migrate_api_access_settings(&mut pre).unwrap();
+ assert_eq!(pre, post);
+ }
+
+ #[test]
+ fn test_api_access_methods_do_not_extract_custom_methods() {
+ let mut pre: serde_json::Value = serde_json::from_str(
+ r#"
+{
+ "api_access_methods": {
+ "access_method_settings": [
+ {
+ "id": "1aaff7ab-e09f-4c03-af02-765e41943a7b",
+ "name": "localsox",
+ "enabled": false,
+ "access_method": {
+ "custom": {
+ "socks5": {
+ "local": {
+ "remote_endpoint": {
+ "address": "1.3.3.7:1080",
+ "protocol": "tcp"
+ },
+ "local_port": 1079
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+}
+"#,
+ )
+ .unwrap();
+
+ let post: serde_json::Value = serde_json::from_str(
+ r#"
+{
+ "api_access_methods": {
+ "custom": [
+ {
+ "id": "1aaff7ab-e09f-4c03-af02-765e41943a7b",
+ "name": "localsox",
+ "enabled": false,
+ "access_method": {
+ "custom": {
+ "socks5_local": {
+ "remote_endpoint": {
+ "address": "1.3.3.7:1080",
+ "protocol": "tcp"
+ },
+ "local_port": 1079
+ }
+ }
+ }
+ }
+ ]
+ }
+}
+"#,
+ )
+ .unwrap();
+
+ migrate_api_access_settings(&mut pre).unwrap();
+ assert_eq!(pre, post);
+ }
+
+ #[test]
+ fn test_api_access_methods_extract_corrupt_built_in() {
+ let mut pre: serde_json::Value = serde_json::from_str(
+ r#"
+{
+ "api_access_methods": {
+ "access_method_settings": [
+ {
+ "id": "1d0d8891-dbb3-4439-a8f7-0e7d742ddbe4",
+ "name": "Mullvad Bridges",
+ "enabled": true,
+ "access_method": {
+ "built_in": "some_other_alternative"
+ }
+ }
+ ]
+ }
+}
+"#,
+ )
+ .unwrap();
+
+ let post: serde_json::Value = serde_json::from_str(
+ r#"
+{
+ "api_access_methods": {
+ "custom": []
+ }
+}
+"#,
+ )
+ .unwrap();
+
+ migrate_api_access_settings(&mut pre).unwrap();
+ assert_eq!(pre, post);
+ }
}
diff --git a/mullvad-management-interface/proto/management_interface.proto b/mullvad-management-interface/proto/management_interface.proto
index 21de18df8e..7fbdb6eba6 100644
--- a/mullvad-management-interface/proto/management_interface.proto
+++ b/mullvad-management-interface/proto/management_interface.proto
@@ -380,7 +380,11 @@ message NewAccessMethodSetting {
AccessMethod access_method = 3;
}
-message ApiAccessMethodSettings { repeated AccessMethodSetting access_method_settings = 1; }
+message ApiAccessMethodSettings {
+ AccessMethodSetting direct = 1;
+ AccessMethodSetting mullvad_bridges = 2;
+ repeated AccessMethodSetting custom = 3;
+}
message Settings {
RelaySettings relay_settings = 1;
diff --git a/mullvad-management-interface/src/client.rs b/mullvad-management-interface/src/client.rs
index 52dbd72b47..f30b613171 100644
--- a/mullvad-management-interface/src/client.rs
+++ b/mullvad-management-interface/src/client.rs
@@ -176,19 +176,20 @@ impl MullvadProxyClient {
}
pub async fn get_api_access_methods(&mut self) -> Result<Vec<AccessMethodSetting>> {
- self.0
+ let access_method_settings = self
+ .0
.get_settings(())
.await
.map_err(Error::Rpc)?
.into_inner()
.api_access_methods
- .ok_or(Error::ApiAccessMethodSettingsNotFound)?
- .access_method_settings
- .into_iter()
- .map(|api_access_method| {
- AccessMethodSetting::try_from(api_access_method).map_err(Error::InvalidResponse)
- })
- .collect()
+ .ok_or(Error::ApiAccessMethodSettingsNotFound)
+ .and_then(|access_method_settings| {
+ access_method::Settings::try_from(access_method_settings)
+ .map_err(Error::InvalidResponse)
+ })?;
+
+ Ok(access_method_settings.iter().cloned().collect())
}
pub async fn get_api_access_method(
diff --git a/mullvad-management-interface/src/types/conversions/access_method.rs b/mullvad-management-interface/src/types/conversions/access_method.rs
index ec5681d74d..d9758a571c 100644
--- a/mullvad-management-interface/src/types/conversions/access_method.rs
+++ b/mullvad-management-interface/src/types/conversions/access_method.rs
@@ -5,35 +5,49 @@ mod settings {
use crate::types::{proto, FromProtobufTypeError};
use mullvad_types::access_method;
- impl From<&access_method::Settings> for proto::ApiAccessMethodSettings {
- fn from(settings: &access_method::Settings) -> Self {
+ impl From<access_method::Settings> for proto::ApiAccessMethodSettings {
+ fn from(settings: access_method::Settings) -> Self {
Self {
- access_method_settings: settings
- .access_method_settings
- .iter()
- .map(|method| method.clone().into())
+ direct: Some(settings.direct().clone().into()),
+ mullvad_bridges: Some(settings.mullvad_bridges().clone().into()),
+ custom: settings
+ .iter_custom()
+ .cloned()
+ .map(|method| method.into())
.collect(),
}
}
}
- impl From<access_method::Settings> for proto::ApiAccessMethodSettings {
- fn from(settings: access_method::Settings) -> Self {
- proto::ApiAccessMethodSettings::from(&settings)
- }
- }
-
impl TryFrom<proto::ApiAccessMethodSettings> for access_method::Settings {
type Error = FromProtobufTypeError;
fn try_from(settings: proto::ApiAccessMethodSettings) -> Result<Self, Self::Error> {
- Ok(Self {
- access_method_settings: settings
- .access_method_settings
- .iter()
- .map(access_method::AccessMethodSetting::try_from)
- .collect::<Result<Vec<access_method::AccessMethodSetting>, _>>()?,
- })
+ let direct = settings
+ .direct
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "Could not deserialize Direct Access Method from protobuf",
+ ))
+ .and_then(access_method::AccessMethodSetting::try_from)?;
+
+ let mullvad_bridges = settings
+ .mullvad_bridges
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "Could not deserialize Mullvad Bridges Access Method from protobuf",
+ ))
+ .and_then(access_method::AccessMethodSetting::try_from)?;
+
+ let custom = settings
+ .custom
+ .iter()
+ .map(access_method::AccessMethodSetting::try_from)
+ .collect::<Result<Vec<_>, _>>()?;
+
+ Ok(access_method::Settings::new(
+ direct,
+ mullvad_bridges,
+ custom,
+ ))
}
}
}
diff --git a/mullvad-management-interface/src/types/conversions/settings.rs b/mullvad-management-interface/src/types/conversions/settings.rs
index a7c4bcd78c..a4d6313158 100644
--- a/mullvad-management-interface/src/types/conversions/settings.rs
+++ b/mullvad-management-interface/src/types/conversions/settings.rs
@@ -43,7 +43,7 @@ impl From<&mullvad_types::settings::Settings> for proto::Settings {
settings.custom_lists.clone(),
)),
api_access_methods: Some(proto::ApiAccessMethodSettings::from(
- &settings.api_access_methods,
+ settings.api_access_methods.clone(),
)),
relay_overrides: settings
.relay_overrides
diff --git a/mullvad-types/src/access_method.rs b/mullvad-types/src/access_method.rs
index 73ab671c9c..80ba7ab69c 100644
--- a/mullvad-types/src/access_method.rs
+++ b/mullvad-types/src/access_method.rs
@@ -1,102 +1,162 @@
-use std::str::FromStr;
-
use serde::{Deserialize, Serialize};
use talpid_types::net::proxy::{CustomProxy, Shadowsocks, Socks5Local, Socks5Remote};
-/// Dttings for API access methods.
+/// Settings for API access methods.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Settings {
- pub access_method_settings: Vec<AccessMethodSetting>,
+ direct: AccessMethodSetting,
+ mullvad_bridges: AccessMethodSetting,
+ /// Custom API access methods.
+ custom: Vec<AccessMethodSetting>,
}
impl Settings {
+ pub fn new(
+ direct: AccessMethodSetting,
+ mullvad_bridges: AccessMethodSetting,
+ custom: Vec<AccessMethodSetting>,
+ ) -> Settings {
+ Settings {
+ direct,
+ mullvad_bridges,
+ custom,
+ }
+ }
+
/// Append an [`AccessMethod`] to the end of `api_access_methods`.
pub fn append(&mut self, api_access_method: AccessMethodSetting) {
- self.access_method_settings.push(api_access_method)
+ self.custom.push(api_access_method)
}
/// Remove an [`ApiAccessMethod`] from `api_access_methods`.
- pub fn remove(&mut self, api_access_method: &Id) {
- self.retain(|method| method.get_id() != *api_access_method)
+ ///
+ /// This function will return an error if a built-in API access is about to
+ /// be removed.
+ pub fn remove(&mut self, api_access_method: &Id) -> Result<(), Error> {
+ let maybe_setting = self
+ .custom
+ .iter()
+ .find(|setting| setting.get_id() == *api_access_method);
+
+ match maybe_setting {
+ Some(x) => match x.access_method {
+ AccessMethod::BuiltIn(ref built_in) => Err(Error::RemoveBuiltin {
+ attempted: built_in.clone(),
+ }),
+ AccessMethod::Custom(_) => {
+ self.custom
+ .retain(|method| method.get_id() != *api_access_method);
+ self.ensure_consistent_state();
+ Ok(())
+ }
+ },
+ None => Ok(()),
+ }
}
- /// 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| predicate(api_access_method))
+ /// Update an existing [`AccessMethodSetting`] chosen by `predicate`, in a
+ /// closure `f`, saving the result to `self`.
+ ///
+ /// Returns a bool to indicate whether some [`AccessMethodSetting`] was
+ /// updated.
+ pub fn update(
+ &mut self,
+ predicate: impl Fn(&AccessMethodSetting) -> bool,
+ f: impl FnOnce(&AccessMethodSetting) -> AccessMethodSetting,
+ ) -> bool {
+ let mut updated = false;
+ if let Some(access_method) = self.iter_mut().find(|setting| predicate(setting)) {
+ *access_method = f(access_method);
+ updated = true;
+ }
+ self.ensure_consistent_state();
+
+ updated
}
- /// 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| predicate(api_access_method))
+ /// Check that `self` contains atleast one enabled access methods. If not,
+ /// the `Direct` access method is re-enabled.
+ fn ensure_consistent_state(&mut self) {
+ if self.collect_enabled().is_empty() {
+ self.direct.enable();
+ }
}
- /// 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())
+ // TODO(markus): This can surely be removed.
+ /// Retrieve all [`AccessMethodSetting`]s which are enabled.
+ pub fn collect_enabled(&self) -> Vec<AccessMethodSetting> {
+ self.iter()
+ .filter(|access_method| access_method.enabled)
+ .cloned()
+ .collect()
}
- /// 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())
+ /// Iterate over references of built-in & custom access methods.
+ pub fn iter(&self) -> impl Iterator<Item = &AccessMethodSetting> {
+ use std::iter::once;
+ once(&self.direct)
+ .chain(once(&self.mullvad_bridges))
+ .chain(&self.custom)
}
- /// Equivalent to [`Vec::retain`].
- pub fn retain<F>(&mut self, f: F)
- where
- F: FnMut(&AccessMethodSetting) -> bool,
- {
- self.access_method_settings.retain(f)
+ /// Iterate over mutable references of built-in & custom access methods.
+ fn iter_mut(&mut self) -> impl Iterator<Item = &mut AccessMethodSetting> {
+ use std::iter::once;
+ once(&mut self.direct)
+ .chain(once(&mut self.mullvad_bridges))
+ .chain(&mut self.custom)
}
- /// Clone the content of `api_access_methods`.
- pub fn cloned(&self) -> Vec<AccessMethodSetting> {
- self.access_method_settings.clone()
+ /// Iterate over references of custom access methods.
+ pub fn iter_custom(&self) -> impl Iterator<Item = &AccessMethodSetting> {
+ self.custom.iter()
}
- /// 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()
- })
+ /// Return the total number of access methods.
+ /// This counts both enabled and disabled [`AccessMethodSetting`]s.
+ pub fn cardinality(&self) -> usize {
+ 1 + // 'Direct'
+ 1 + // 'Mullvad bridges'
+ self.custom.len()
}
- pub fn direct() -> AccessMethodSetting {
+ pub fn direct(&self) -> &AccessMethodSetting {
+ &self.direct
+ }
+
+ pub fn mullvad_bridges(&self) -> &AccessMethodSetting {
+ &self.mullvad_bridges
+ }
+
+ // TODO(markus): This can probably be made private
+ pub fn create_direct() -> AccessMethodSetting {
let method = BuiltInAccessMethod::Direct;
AccessMethodSetting::new(method.canonical_name(), true, AccessMethod::from(method))
}
- pub fn mullvad_bridges() -> AccessMethodSetting {
+ fn create_mullvad_bridges() -> AccessMethodSetting {
let method = BuiltInAccessMethod::Bridge;
AccessMethodSetting::new(method.canonical_name(), true, AccessMethod::from(method))
}
-
- /// Retrieve all [`AccessMethodSetting`]s which are enabled.
- pub fn collect_enabled(&self) -> Vec<AccessMethodSetting> {
- self.cloned()
- .into_iter()
- .filter(|access_method| access_method.enabled)
- .collect()
- }
}
impl Default for Settings {
fn default() -> Self {
Self {
- access_method_settings: vec![Settings::direct(), Settings::mullvad_bridges()],
+ direct: Settings::create_direct(),
+ mullvad_bridges: Settings::create_mullvad_bridges(),
+ custom: vec![],
}
}
}
+#[derive(err_derive::Error, Debug)]
+pub enum Error {
+ /// Built-in access methods can not be removed
+ #[error(display = "Cannot remove built-in access method {}", attempted)]
+ RemoveBuiltin { attempted: BuiltInAccessMethod },
+}
+
/// API Access Method datastructure
///
/// Mirrors the protobuf definition
@@ -120,6 +180,7 @@ impl Id {
/// Tries to parse a UUID from a raw String. If it is successful, an
/// [`Id`] is instantiated.
pub fn from_string(id: String) -> Option<Self> {
+ use std::str::FromStr;
uuid::Uuid::from_str(&id).ok().map(Self)
}
}
@@ -178,6 +239,10 @@ impl AccessMethodSetting {
self.enabled
}
+ pub fn disabled(&self) -> bool {
+ !self.enabled
+ }
+
pub fn as_custom(&self) -> Option<&CustomProxy> {
self.access_method.as_custom()
}
@@ -223,6 +288,12 @@ impl BuiltInAccessMethod {
}
}
+impl std::fmt::Display for BuiltInAccessMethod {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_str(&self.canonical_name())
+ }
+}
+
impl From<BuiltInAccessMethod> for AccessMethod {
fn from(value: BuiltInAccessMethod) -> Self {
AccessMethod::BuiltIn(value)
diff --git a/mullvad-types/src/settings/mod.rs b/mullvad-types/src/settings/mod.rs
index e6886c9e3c..af8c11e8d7 100644
--- a/mullvad-types/src/settings/mod.rs
+++ b/mullvad-types/src/settings/mod.rs
@@ -79,7 +79,7 @@ pub struct Settings {
/// All of the custom relay lists
#[cfg_attr(target_os = "android", jnix(skip))]
pub custom_lists: CustomListsSettings,
- /// API access methods.
+ /// API access methods
#[cfg_attr(target_os = "android", jnix(skip))]
pub api_access_methods: access_method::Settings,
/// If the daemon should allow communication with private (LAN) networks.