1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
use super::Result;
use mullvad_types::settings::SettingsVersion;
/// This version introduces 2 new fields to the [mullvad_constraints::WireguardConstraints] struct:
/// pub entry_providers: Constraint<Providers>,
/// pub entry_ownership: Constraint<Ownership>,
/// When set, these filters apply to the entry relay when multihop is used.
/// A migration is needed to transfer the current providers and ownership to these new fields
/// so that the user's current filters don't change.
pub fn migrate(settings: &mut serde_json::Value) -> Result<()> {
if !version_matches(settings) {
return Ok(());
}
log::info!("Migrating settings format to V13");
migrate_filters_to_new_entry_only_filters(settings);
settings["settings_version"] = serde_json::json!(SettingsVersion::V13);
Ok(())
}
fn version_matches(settings: &serde_json::Value) -> bool {
settings
.get("settings_version")
.map(|version| version == SettingsVersion::V12 as u64)
.unwrap_or(false)
}
fn migrate_filters_to_new_entry_only_filters(settings: &mut serde_json::Value) -> Option<()> {
let normal = settings.get_mut("relay_settings")?.get_mut("normal")?;
let providers = normal.get("providers")?.clone();
let ownership = normal.get("ownership")?.clone();
let wireguard_constraints = normal.get_mut("wireguard_constraints")?.as_object_mut()?;
wireguard_constraints.insert("entry_providers".to_string(), providers);
wireguard_constraints.insert("entry_ownership".to_string(), ownership);
Some(())
}
#[cfg(test)]
mod test {
use super::{migrate, version_matches};
const V12_SETTINGS: &str = r#"
{
"relay_settings": {
"normal": {
"location": {
"only": {
"location": {
"country": "fr"
}
}
},
"providers": {
"only": {
"providers": [
"Blix",
"Creanova"
]
}
},
"ownership": {
"only": "MullvadOwned"
},
"tunnel_protocol": "wireguard",
"wireguard_constraints": {
"port": "any",
"ip_version": "any",
"allowed_ips": "any",
"use_multihop": true,
"entry_location": {
"only": {
"location": {
"country": "se"
}
}
}
},
"openvpn_constraints": {
"port": "any"
}
}
},
"settings_version": 12
}
"#;
#[test]
fn test_v12_to_v13_migration() {
let mut old_settings = serde_json::from_str(V12_SETTINGS).unwrap();
assert!(version_matches(&old_settings));
migrate(&mut old_settings).unwrap();
insta::assert_snapshot!(serde_json::to_string_pretty(&old_settings).unwrap());
}
}
|