use super::Result; use mullvad_types::{constraints::Constraint, settings::SettingsVersion}; use serde::{Deserialize, Serialize}; // ====================================================== // Section for vendoring types and values that // this settings version depend on. See `mod.rs`. /// The tunnel protocol used by a [`TunnelEndpoint`][talpid_types::net::TunnelEndpoint]. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename = "tunnel_type")] pub enum TunnelType { #[serde(rename = "openvpn")] OpenVpn, #[serde(rename = "wireguard")] Wireguard, } // ====================================================== pub fn migrate(settings: &mut serde_json::Value) -> Result<()> { if !version_matches(settings) { return Ok(()); } log::info!("Migrating settings format to V2"); let openvpn_constraints = || -> Option { settings .get("relay_settings")? .get("normal")? .get("tunnel")? .get("only")? .get("openvpn") .cloned() }(); let wireguard_constraints = || -> Option { settings .get("relay_settings")? .get("normal")? .get("tunnel")? .get("only")? .get("wireguard") .cloned() }(); if let Some(relay_settings) = settings.get_mut("relay_settings") && let Some(normal_settings) = relay_settings.get_mut("normal") { if let Some(openvpn_constraints) = openvpn_constraints { normal_settings["openvpn_constraints"] = openvpn_constraints; normal_settings["tunnel_protocol"] = serde_json::json!(Constraint::::Any); } else if let Some(wireguard_constraints) = wireguard_constraints { normal_settings["wireguard_constraints"] = wireguard_constraints; normal_settings["tunnel_protocol"] = serde_json::json!(Constraint::Only(TunnelType::Wireguard)); } else { normal_settings["tunnel_protocol"] = serde_json::json!(Constraint::::Any); } if let Some(object) = normal_settings.as_object_mut() { object.remove("tunnel"); } } settings["show_beta_releases"] = serde_json::json!(false); settings["settings_version"] = serde_json::json!(SettingsVersion::V2); Ok(()) } fn version_matches(settings: &serde_json::Value) -> bool { settings.get("settings_version").is_none() } #[cfg(test)] mod test { use super::{migrate, version_matches}; pub const V2_SETTINGS: &str = r#" { "account_token": "1234", "relay_settings": { "normal": { "location": { "only": { "country": "se" } }, "tunnel_protocol": "any", "openvpn_constraints": { "port": { "only": 53 }, "protocol": { "only": "udp" } } } }, "allow_lan": true, "block_when_disconnected": false, "auto_connect": false, "tunnel_options": { "openvpn": { "mssfix": null }, "wireguard": { "mtu": null }, "generic": { "enable_ipv6": false } }, "show_beta_releases": false, "settings_version": 2 } "#; const V1_SETTINGS: &str = include_str!("v1_settings.json"); const V1_SETTINGS_2019V3: &str = r#" { "account_token": "1234", "relay_settings": { "normal": { "location": { "only": { "country": "se" } }, "tunnel": { "only": { "openvpn": { "port": { "only": 53 }, "protocol": { "only": "udp" } } } } } }, "allow_lan": true, "block_when_disconnected": false, "auto_connect": false, "tunnel_options": { "openvpn": { "mssfix": null }, "wireguard": { "mtu": null }, "generic": { "enable_ipv6": false } } } "#; #[test] fn test_v1_migration() { let mut old_settings = serde_json::from_str(V1_SETTINGS).unwrap(); assert!(version_matches(&old_settings)); migrate(&mut old_settings).unwrap(); let new_settings: serde_json::Value = serde_json::from_str(V2_SETTINGS).unwrap(); assert_eq!(&old_settings, &new_settings); } #[test] fn test_v1_2019v3_migration() { let mut old_settings = serde_json::from_str(V1_SETTINGS_2019V3).unwrap(); assert!(version_matches(&old_settings)); migrate(&mut old_settings).unwrap(); let new_settings: serde_json::Value = serde_json::from_str(V2_SETTINGS).unwrap(); assert_eq!(&old_settings, &new_settings); } }