summaryrefslogtreecommitdiffhomepage
path: root/mullvad-daemon/src/migrations/v12.rs
blob: b396cbfdfa232ca84f3eaeb2e1e8c2745327efb1 (plain)
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());
    }
}