summaryrefslogtreecommitdiffhomepage
path: root/mullvad-daemon
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 /mullvad-daemon
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.
Diffstat (limited to 'mullvad-daemon')
-rw-r--r--mullvad-daemon/src/migrations/v7.rs313
1 files changed, 286 insertions, 27 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);
+ }
}