summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJonathan <jonathan@mullvad.net>2023-06-28 14:36:24 +0200
committerJonathan <jonathan@mullvad.net>2023-06-29 15:00:10 +0200
commit5f61ba4058337e6985cee99661a59a98ebff6dd0 (patch)
treeba94b7e0829f2fd57a9974b4590af59e9937e5be
parentb4bf8124fbc30bf891f70f120265f30c490d1244 (diff)
downloadmullvadvpn-5f61ba4058337e6985cee99661a59a98ebff6dd0.tar.xz
mullvadvpn-5f61ba4058337e6985cee99661a59a98ebff6dd0.zip
Add settings migration code, refactor and cleanup
Bump the settings version. Add code for migrating settings to new version since it is now not backwards compatible. Refactor LocationConstraint and related types to be more lean. Cleanup issues and fix formatting. Refactor LocationConstraint and add migration code
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/RelayListListener.kt1
-rw-r--r--mullvad-cli/src/cmds/bridge.rs2
-rw-r--r--mullvad-cli/src/cmds/relay.rs6
-rw-r--r--mullvad-cli/src/cmds/relay_constraints.rs2
-rw-r--r--mullvad-daemon/src/migrations/v6.rs303
-rw-r--r--mullvad-daemon/src/settings.rs4
-rw-r--r--mullvad-management-interface/src/types/conversions/relay_constraints.rs4
-rw-r--r--mullvad-relay-selector/src/lib.rs4
-rw-r--r--mullvad-types/src/relay_constraints.rs64
-rw-r--r--mullvad-types/src/settings/mod.rs16
10 files changed, 338 insertions, 68 deletions
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/RelayListListener.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/RelayListListener.kt
index 5efca2648c..c6142694b9 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/RelayListListener.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/RelayListListener.kt
@@ -6,7 +6,6 @@ import net.mullvad.mullvadvpn.ipc.EventDispatcher
import net.mullvad.mullvadvpn.ipc.Request
import net.mullvad.mullvadvpn.model.Constraint
import net.mullvad.mullvadvpn.model.GeographicLocationConstraint
-import net.mullvad.mullvadvpn.model.LocationConstraint
import net.mullvad.mullvadvpn.model.PortRange
import net.mullvad.mullvadvpn.model.RelayConstraints
import net.mullvad.mullvadvpn.model.RelaySettings
diff --git a/mullvad-cli/src/cmds/bridge.rs b/mullvad-cli/src/cmds/bridge.rs
index e43fce1b51..3cc1a95b37 100644
--- a/mullvad-cli/src/cmds/bridge.rs
+++ b/mullvad-cli/src/cmds/bridge.rs
@@ -168,7 +168,7 @@ impl Bridge {
} else {
Constraint::from(location)
};
- let location = location.map(|location| LocationConstraint::Location { location });
+ let location = location.map(LocationConstraint::Location);
Self::update_bridge_settings(&mut rpc, Some(location), None, None).await
}
SetCommands::CustomList { custom_list_name } => {
diff --git a/mullvad-cli/src/cmds/relay.rs b/mullvad-cli/src/cmds/relay.rs
index 1bb395c4e5..83f4ad4fdd 100644
--- a/mullvad-cli/src/cmds/relay.rs
+++ b/mullvad-cli/src/cmds/relay.rs
@@ -450,7 +450,7 @@ impl Relay {
// The country field is assumed to be hostname due to CLI argument parsing
find_relay_by_hostname(&countries, &location_constraint_args.country)
{
- Constraint::Only(LocationConstraint::Location { location: relay })
+ Constraint::Only(LocationConstraint::Location(relay))
} else {
let location_constraint: Constraint<GeographicLocationConstraint> =
Constraint::from(location_constraint_args);
@@ -468,7 +468,7 @@ impl Relay {
}
}
}
- location_constraint.map(|location| LocationConstraint::Location { location })
+ location_constraint.map(LocationConstraint::Location)
};
Self::update_constraints(RelaySettingsUpdate::Normal(RelayConstraintsUpdate {
@@ -576,7 +576,7 @@ impl Relay {
// The country field is assumed to be hostname due to CLI argument parsing
wireguard_constraints.entry_location =
if let Some(relay) = find_relay_by_hostname(&countries, &entry.country) {
- Constraint::Only(LocationConstraint::Location { location: relay })
+ Constraint::Only(LocationConstraint::Location(relay))
} else {
Constraint::from(entry)
};
diff --git a/mullvad-cli/src/cmds/relay_constraints.rs b/mullvad-cli/src/cmds/relay_constraints.rs
index dc79e79f0b..626754edcb 100644
--- a/mullvad-cli/src/cmds/relay_constraints.rs
+++ b/mullvad-cli/src/cmds/relay_constraints.rs
@@ -49,6 +49,6 @@ impl From<LocationArgs> for Constraint<LocationConstraint> {
}
_ => unreachable!("invalid location arguments"),
};
- Constraint::Only(LocationConstraint::Location { location })
+ Constraint::Only(LocationConstraint::Location(location))
}
}
diff --git a/mullvad-daemon/src/migrations/v6.rs b/mullvad-daemon/src/migrations/v6.rs
index 54dc2268e4..3a842923f0 100644
--- a/mullvad-daemon/src/migrations/v6.rs
+++ b/mullvad-daemon/src/migrations/v6.rs
@@ -36,16 +36,55 @@ pub fn migrate(settings: &mut serde_json::Value) -> Result<()> {
migrate_udp2tcp_port_443(settings);
- // TODO
- // log::info!("Migrating settings format to V7");
+ migrate_location_constraint(settings)?;
- // Note: Not incrementing the version number yet, since this migration is still open
- // for future modification.
- // settings["settings_version"] = serde_json::json!(SettingsVersion::V7);
+ log::info!("Migrating settings format to V7");
+
+ settings["settings_version"] = serde_json::json!(SettingsVersion::V7);
+
+ Ok(())
+}
+
+fn migrate_location_constraint(settings: &mut serde_json::Value) -> Result<()> {
+ if let Some(location) = settings
+ .get_mut("relay_settings")
+ .and_then(|relay_settings| relay_settings.get_mut("normal"))
+ .and_then(|normal_relay_settings| normal_relay_settings.get_mut("location"))
+ {
+ wrap_location(location)?;
+ }
+
+ if let Some(location) = settings
+ .get_mut("relay_settings")
+ .and_then(|relay_settings| relay_settings.get_mut("normal"))
+ .and_then(|normal_relay_settings| normal_relay_settings.get_mut("wireguard_constraints"))
+ .and_then(|normal_relay_settings| normal_relay_settings.get_mut("entry_location"))
+ {
+ wrap_location(location)?;
+ }
+
+ if let Some(location) = settings
+ .get_mut("bridge_settings")
+ .and_then(|relay_settings| relay_settings.get_mut("normal"))
+ .and_then(|normal_relay_settings| normal_relay_settings.get_mut("location"))
+ {
+ wrap_location(location)?;
+ }
Ok(())
}
+fn wrap_location(location: &mut serde_json::Value) -> Result<()> {
+ if let Some(only) = location.get_mut("only") {
+ only["location"] = only.clone();
+ let only = only.as_object_mut().ok_or(Error::InvalidSettingsContent)?;
+ only.remove("country");
+ only.remove("city");
+ only.remove("hostname");
+ }
+ Ok(())
+}
+
fn migrate_pq_setting(settings: &mut serde_json::Value) -> Result<()> {
if let Some(tunnel_options) = settings
.get_mut("tunnel_options")
@@ -89,7 +128,7 @@ fn version_matches(settings: &mut serde_json::Value) -> bool {
#[cfg(test)]
mod test {
- use super::{migrate, migrate_pq_setting, version_matches};
+ use super::{migrate, migrate_location_constraint, migrate_pq_setting, version_matches};
pub const V6_SETTINGS: &str = r#"
{
@@ -175,7 +214,9 @@ mod test {
"normal": {
"location": {
"only": {
- "country": "se"
+ "location": {
+ "country": "se"
+ }
}
},
"tunnel_protocol": "any",
@@ -241,7 +282,7 @@ mod test {
}
}
},
- "settings_version": 6
+ "settings_version": 7
}
"#;
@@ -256,6 +297,252 @@ mod test {
assert_eq!(&old_settings, &new_settings);
}
+ /// For relay settings
+ /// location: { only: { country : "se" } } should be replaced with
+ /// location: { only: { location: { country: "se" } } }
+ #[test]
+ fn test_from_relay_settings_location_constraint_country() {
+ let mut migrated_settings: serde_json::Value = serde_json::from_str(
+ r#"
+ {
+ "relay_settings": {
+ "normal": {
+ "location": {
+ "only": {
+ "country": "se"
+ }
+ }
+ }
+ }
+ }
+ "#,
+ )
+ .unwrap();
+ migrate_location_constraint(&mut migrated_settings).unwrap();
+
+ let expected_settings: serde_json::Value = serde_json::from_str(
+ r#"
+ {
+ "relay_settings": {
+ "normal": {
+ "location": {
+ "only": {
+ "location": {
+ "country": "se"
+ }
+ }
+ }
+ }
+ }
+ }
+ "#,
+ )
+ .unwrap();
+
+ assert_eq!(migrated_settings, expected_settings);
+ }
+
+ /// For relay settings
+ /// location: { only: { country : "se", city: "got" } } should be replaced with
+ /// location: { only: { location: { country: "se", city: "got" } } }
+ #[test]
+ fn test_from_relay_settings_location_constraint_city() {
+ let mut migrated_settings: serde_json::Value = serde_json::from_str(
+ r#"
+ {
+ "relay_settings": {
+ "normal": {
+ "location": {
+ "only": {
+ "country": "se",
+ "city": "got"
+ }
+ }
+ }
+ }
+ }
+ "#,
+ )
+ .unwrap();
+ migrate_location_constraint(&mut migrated_settings).unwrap();
+
+ let expected_settings: serde_json::Value = serde_json::from_str(
+ r#"
+ {
+ "relay_settings": {
+ "normal": {
+ "location": {
+ "only": {
+ "location": {
+ "country": "se",
+ "city": "got"
+ }
+ }
+ }
+ }
+ }
+ }
+ "#,
+ )
+ .unwrap();
+
+ assert_eq!(migrated_settings, expected_settings);
+ }
+
+ /// For relay settings
+ /// location: { only: { country : "se", city: "got", hostname: "se-got-wg-001" } } should be
+ /// replaced with location: { only: { location: { country: "se", city: "got", hostname:
+ /// "se-got-wg-001" } } }
+ #[test]
+ fn test_from_relay_settings_location_constraint_hostname() {
+ let mut migrated_settings: serde_json::Value = serde_json::from_str(
+ r#"
+ {
+ "relay_settings": {
+ "normal": {
+ "location": {
+ "only": {
+ "country": "se",
+ "city": "got",
+ "hostname": "se-got-wg-001"
+ }
+ }
+ }
+ }
+ }
+ "#,
+ )
+ .unwrap();
+ migrate_location_constraint(&mut migrated_settings).unwrap();
+
+ let expected_settings: serde_json::Value = serde_json::from_str(
+ r#"
+ {
+ "relay_settings": {
+ "normal": {
+ "location": {
+ "only": {
+ "location": {
+ "country": "se",
+ "city": "got",
+ "hostname": "se-got-wg-001"
+ }
+ }
+ }
+ }
+ }
+ }
+ "#,
+ )
+ .unwrap();
+
+ assert_eq!(migrated_settings, expected_settings);
+ }
+
+ /// For bridge settings
+ /// location: { only: { country : "se", city: "got", hostname: "se-got-wg-001" } } should be
+ /// replaced with location: { only: { location: { country: "se", city: "got", hostname:
+ /// "se-got-wg-001" } } }
+ #[test]
+ fn test_from_bridge_location_constraint_hostname() {
+ let mut migrated_settings: serde_json::Value = serde_json::from_str(
+ r#"
+ {
+ "bridge_settings": {
+ "normal": {
+ "location": {
+ "only": {
+ "country": "se",
+ "city": "got",
+ "hostname": "se-got-wg-001"
+ }
+ }
+ }
+ }
+ }
+ "#,
+ )
+ .unwrap();
+ migrate_location_constraint(&mut migrated_settings).unwrap();
+
+ let expected_settings: serde_json::Value = serde_json::from_str(
+ r#"
+ {
+ "bridge_settings": {
+ "normal": {
+ "location": {
+ "only": {
+ "location": {
+ "country": "se",
+ "city": "got",
+ "hostname": "se-got-wg-001"
+ }
+ }
+ }
+ }
+ }
+ }
+ "#,
+ )
+ .unwrap();
+
+ assert_eq!(migrated_settings, expected_settings);
+ }
+
+ /// For wireguard constraints
+ /// location: { only: { country : "se", city: "got", hostname: "se-got-wg-001" } } should be
+ /// replaced with location: { only: { location: { country: "se", city: "got", hostname:
+ /// "se-got-wg-001" } } }
+ #[test]
+ fn test_from_wireguard_constraint_location_constraint_hostname() {
+ let mut migrated_settings: serde_json::Value = serde_json::from_str(
+ r#"
+ {
+ "relay_settings": {
+ "normal": {
+ "wireguard_constraints": {
+ "entry_location": {
+ "only": {
+ "country": "se",
+ "city": "got",
+ "hostname": "se-got-wg-001"
+ }
+ }
+ }
+ }
+ }
+ }
+ "#,
+ )
+ .unwrap();
+ migrate_location_constraint(&mut migrated_settings).unwrap();
+
+ let expected_settings: serde_json::Value = serde_json::from_str(
+ r#"
+ {
+ "relay_settings": {
+ "normal": {
+ "wireguard_constraints": {
+ "entry_location": {
+ "only": {
+ "location": {
+ "country": "se",
+ "city": "got",
+ "hostname": "se-got-wg-001"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ "#,
+ )
+ .unwrap();
+
+ assert_eq!(migrated_settings, expected_settings);
+ }
+
/// use_pq_safe_psk=false should be replaced with quantum_resistant=null
#[test]
fn test_from_pq_safe_psk_false() {
diff --git a/mullvad-daemon/src/settings.rs b/mullvad-daemon/src/settings.rs
index ee3f355598..794b0381ca 100644
--- a/mullvad-daemon/src/settings.rs
+++ b/mullvad-daemon/src/settings.rs
@@ -378,9 +378,7 @@ mod test {
"location": {
"only": {
"location": {
- "location": {
- "country": "gb"
- }
+ "country": "gb"
}
}
},
diff --git a/mullvad-management-interface/src/types/conversions/relay_constraints.rs b/mullvad-management-interface/src/types/conversions/relay_constraints.rs
index 221c2140b2..e987ca102b 100644
--- a/mullvad-management-interface/src/types/conversions/relay_constraints.rs
+++ b/mullvad-management-interface/src/types/conversions/relay_constraints.rs
@@ -488,7 +488,7 @@ impl From<mullvad_types::relay_constraints::LocationConstraint> for proto::Locat
fn from(location: mullvad_types::relay_constraints::LocationConstraint) -> Self {
use mullvad_types::relay_constraints::LocationConstraint;
match location {
- LocationConstraint::Location { location } => Self {
+ LocationConstraint::Location(location) => Self {
r#type: Some(proto::location_constraint::Type::Location(
proto::RelayLocation::from(location),
)),
@@ -515,7 +515,7 @@ impl TryFrom<proto::LocationConstraint>
match location {
Constraint::Any => Ok(Constraint::Any),
Constraint::Only(location) => {
- Ok(Constraint::Only(LocationConstraint::Location { location }))
+ Ok(Constraint::Only(LocationConstraint::Location(location)))
}
}
}
diff --git a/mullvad-relay-selector/src/lib.rs b/mullvad-relay-selector/src/lib.rs
index 9fd6e3c6da..e62c63f3db 100644
--- a/mullvad-relay-selector/src/lib.rs
+++ b/mullvad-relay-selector/src/lib.rs
@@ -1564,7 +1564,7 @@ mod test {
BridgeState::Off,
attempt,
TunnelType::OpenVpn,
- &CustomListsSettings::default()
+ &CustomListsSettings::default(),
);
assert_eq!(
preferred.tunnel_protocol,
@@ -1575,7 +1575,7 @@ mod test {
BridgeState::Off,
attempt,
TunnelType::OpenVpn,
- &CustomListsSettings::default()
+ &CustomListsSettings::default(),
) {
Ok(result) if matches!(result.endpoint, MullvadEndpoint::OpenVpn(_)) => (),
_ => panic!("OpenVPN endpoint was not selected"),
diff --git a/mullvad-types/src/relay_constraints.rs b/mullvad-types/src/relay_constraints.rs
index 18ab4eef03..ab78ceca70 100644
--- a/mullvad-types/src/relay_constraints.rs
+++ b/mullvad-types/src/relay_constraints.rs
@@ -235,27 +235,19 @@ impl RelaySettings {
}
}
-#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
+#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(target_os = "android", derive(IntoJava, FromJava))]
#[cfg_attr(target_os = "android", jnix(package = "net.mullvad.mullvadvpn.model"))]
pub enum LocationConstraint {
- Location {
- location: GeographicLocationConstraint,
- },
- CustomList {
- list_id: Id,
- },
+ Location(GeographicLocationConstraint),
+ CustomList { list_id: Id },
}
#[derive(Debug, Clone)]
pub enum ResolvedLocationConstraint {
- Location {
- location: GeographicLocationConstraint,
- },
- Locations {
- locations: Vec<GeographicLocationConstraint>,
- },
+ Location(GeographicLocationConstraint),
+ Locations(Vec<GeographicLocationConstraint>),
}
impl ResolvedLocationConstraint {
@@ -265,18 +257,14 @@ impl ResolvedLocationConstraint {
) -> Constraint<ResolvedLocationConstraint> {
match location {
Constraint::Any => Constraint::Any,
- Constraint::Only(LocationConstraint::Location { location }) => {
- Constraint::Only(Self::Location { location })
+ Constraint::Only(LocationConstraint::Location(location)) => {
+ Constraint::Only(Self::Location(location))
}
Constraint::Only(LocationConstraint::CustomList { list_id }) => custom_lists
.custom_lists
.iter()
.find(|custom_list| custom_list.id == list_id)
- .map(|custom_list| {
- Constraint::Only(Self::Locations {
- locations: custom_list.locations.clone(),
- })
- })
+ .map(|custom_list| Constraint::Only(Self::Locations(custom_list.locations.clone())))
.unwrap_or(Constraint::Any),
}
}
@@ -284,7 +272,7 @@ impl ResolvedLocationConstraint {
impl From<GeographicLocationConstraint> for LocationConstraint {
fn from(location: GeographicLocationConstraint) -> Self {
- Self::Location { location }
+ Self::Location(location)
}
}
@@ -292,27 +280,23 @@ impl Set<Constraint<ResolvedLocationConstraint>> for Constraint<ResolvedLocation
fn is_subset(&self, other: &Self) -> bool {
match self {
Constraint::Any => other.is_any(),
- Constraint::Only(ResolvedLocationConstraint::Location { location }) => match other {
+ Constraint::Only(ResolvedLocationConstraint::Location(location)) => match other {
Constraint::Any => true,
- Constraint::Only(ResolvedLocationConstraint::Location {
- location: other_location,
- }) => location.is_subset(other_location),
- Constraint::Only(ResolvedLocationConstraint::Locations {
- locations: other_locations,
- }) => other_locations
- .iter()
- .any(|other_location| location.is_subset(other_location)),
+ Constraint::Only(ResolvedLocationConstraint::Location(other_location)) => {
+ location.is_subset(other_location)
+ }
+ Constraint::Only(ResolvedLocationConstraint::Locations(other_locations)) => {
+ other_locations
+ .iter()
+ .any(|other_location| location.is_subset(other_location))
+ }
},
- Constraint::Only(ResolvedLocationConstraint::Locations { locations }) => match other {
+ Constraint::Only(ResolvedLocationConstraint::Locations(locations)) => match other {
Constraint::Any => true,
- Constraint::Only(ResolvedLocationConstraint::Location {
- location: other_location,
- }) => locations
+ Constraint::Only(ResolvedLocationConstraint::Location(other_location)) => locations
.iter()
.all(|location| location.is_subset(other_location)),
- Constraint::Only(ResolvedLocationConstraint::Locations {
- locations: other_locations,
- }) => {
+ Constraint::Only(ResolvedLocationConstraint::Locations(other_locations)) => {
for location in locations {
if !other_locations
.iter()
@@ -332,10 +316,10 @@ impl Constraint<ResolvedLocationConstraint> {
pub fn matches_with_opts(&self, relay: &Relay, ignore_include_in_country: bool) -> bool {
match self {
Constraint::Any => true,
- Constraint::Only(ResolvedLocationConstraint::Location { location }) => {
+ Constraint::Only(ResolvedLocationConstraint::Location(location)) => {
location.matches_with_opts(relay, ignore_include_in_country)
}
- Constraint::Only(ResolvedLocationConstraint::Locations { locations }) => locations
+ Constraint::Only(ResolvedLocationConstraint::Locations(locations)) => locations
.iter()
.any(|loc| loc.matches_with_opts(relay, ignore_include_in_country)),
}
@@ -345,7 +329,7 @@ impl Constraint<ResolvedLocationConstraint> {
impl LocationConstraint {
fn format(&self, f: &mut String, custom_lists: &CustomListsSettings) -> Result<(), fmt::Error> {
match self {
- Self::Location { location } => writeln!(f, "location - {location}"),
+ Self::Location(location) => writeln!(f, "location - {location}"),
Self::CustomList { list_id } => match custom_lists
.custom_lists
.iter()
diff --git a/mullvad-types/src/settings/mod.rs b/mullvad-types/src/settings/mod.rs
index 5af6ecfe08..12f5d831e1 100644
--- a/mullvad-types/src/settings/mod.rs
+++ b/mullvad-types/src/settings/mod.rs
@@ -21,7 +21,7 @@ mod dns;
/// latest version that exists in `SettingsVersion`.
/// This should be bumped when a new version is introduced along with a migration
/// being added to `mullvad-daemon`.
-pub const CURRENT_SETTINGS_VERSION: SettingsVersion = SettingsVersion::V6;
+pub const CURRENT_SETTINGS_VERSION: SettingsVersion = SettingsVersion::V7;
#[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Copy)]
#[repr(u32)]
@@ -31,6 +31,7 @@ pub enum SettingsVersion {
V4 = 4,
V5 = 5,
V6 = 6,
+ V7 = 7,
}
impl<'de> Deserialize<'de> for SettingsVersion {
@@ -44,6 +45,7 @@ impl<'de> Deserialize<'de> for SettingsVersion {
v if v == SettingsVersion::V4 as u32 => Ok(SettingsVersion::V4),
v if v == SettingsVersion::V5 as u32 => Ok(SettingsVersion::V5),
v if v == SettingsVersion::V6 as u32 => Ok(SettingsVersion::V6),
+ v if v == SettingsVersion::V7 as u32 => Ok(SettingsVersion::V7),
v => Err(serde::de::Error::custom(format!(
"{v} is not a valid SettingsVersion"
))),
@@ -121,13 +123,13 @@ impl Default for Settings {
fn default() -> Self {
Settings {
relay_settings: RelaySettings::Normal(RelayConstraints {
- location: Constraint::Only(LocationConstraint::Location {
- location: GeographicLocationConstraint::Country("se".to_owned()),
- }),
+ location: Constraint::Only(LocationConstraint::Location(
+ GeographicLocationConstraint::Country("se".to_owned()),
+ )),
wireguard_constraints: WireguardConstraints {
- entry_location: Constraint::Only(LocationConstraint::Location {
- location: GeographicLocationConstraint::Country("se".to_owned()),
- }),
+ entry_location: Constraint::Only(LocationConstraint::Location(
+ GeographicLocationConstraint::Country("se".to_owned()),
+ )),
..Default::default()
},
..Default::default()