diff options
| -rw-r--r-- | mullvad-management-interface/src/types/conversions/features.rs | 2 | ||||
| -rw-r--r-- | mullvad-types/src/features.rs | 196 |
2 files changed, 196 insertions, 2 deletions
diff --git a/mullvad-management-interface/src/types/conversions/features.rs b/mullvad-management-interface/src/types/conversions/features.rs index d21441a610..ac235d8163 100644 --- a/mullvad-management-interface/src/types/conversions/features.rs +++ b/mullvad-management-interface/src/types/conversions/features.rs @@ -57,7 +57,7 @@ impl From<mullvad_types::features::FeatureIndicators> for proto::FeatureIndicato let mut proto_features = Self::default(); features - .active_features() + .into_iter() .map(proto::FeatureIndicator::from) .for_each(|feature| proto_features.push_active_features(feature)); diff --git a/mullvad-types/src/features.rs b/mullvad-types/src/features.rs index b2205272c7..95caade0f8 100644 --- a/mullvad-types/src/features.rs +++ b/mullvad-types/src/features.rs @@ -11,6 +11,15 @@ use talpid_types::net::{ObfuscationType, TunnelEndpoint, TunnelType}; #[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct FeatureIndicators(HashSet<FeatureIndicator>); +impl IntoIterator for FeatureIndicators { + type Item = FeatureIndicator; + type IntoIter = std::collections::hash_set::IntoIter<Self::Item>; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + impl FeatureIndicators { pub fn active_features(&self) -> impl Iterator<Item = FeatureIndicator> { self.0.clone().into_iter() @@ -86,7 +95,7 @@ pub fn compute_feature_indicators( .default_options .any_blockers_enabled(); let custom_dns = settings.tunnel_options.dns_options.state == DnsState::Custom; - let server_ip_override = !settings.relay_overrides.is_empty(); + let server_ip_override = !settings.relay_overrides.is_empty(); // TODO: Should check if actually used let generic_features = [ (split_tunneling, FeatureIndicator::SplitTunneling), @@ -146,3 +155,188 @@ pub fn compute_feature_indicators( .filter_map(|(active, feature)| active.then_some(feature)) .collect() } + +#[cfg(test)] +mod tests { + use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + + use talpid_types::net::{ + proxy::{ProxyEndpoint, ProxyType}, + Endpoint, ObfuscationEndpoint, TransportProtocol, + }; + + use super::*; + + #[test] + fn test_one_indicator_at_a_time() { + let mut settings = Settings::default(); + let mut endpoint = TunnelEndpoint { + endpoint: Endpoint { + address: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080), + protocol: TransportProtocol::Udp, + }, + tunnel_type: TunnelType::Wireguard, + quantum_resistant: Default::default(), + proxy: Default::default(), + obfuscation: Default::default(), + entry_endpoint: Default::default(), + tunnel_interface: Default::default(), + daita: Default::default(), + }; + + let mut expected_indicators: FeatureIndicators = [].into_iter().collect(); + + assert_eq!( + compute_feature_indicators(&settings, &endpoint), + expected_indicators, + "The default settings and TunnelEndpoint should not have any feature indicators. \ + If this is not true anymore, please update this test." + ); + + settings.block_when_disconnected = true; + expected_indicators.0.insert(FeatureIndicator::LockdownMode); + + assert_eq!( + compute_feature_indicators(&settings, &endpoint), + expected_indicators + ); + + settings + .tunnel_options + .dns_options + .default_options + .block_ads = true; + + expected_indicators + .0 + .insert(FeatureIndicator::DnsContentBlockers); + + assert_eq!( + compute_feature_indicators(&settings, &endpoint), + expected_indicators + ); + + settings.allow_lan = true; + + expected_indicators.0.insert(FeatureIndicator::LanSharing); + + assert_eq!( + compute_feature_indicators(&settings, &endpoint), + expected_indicators + ); + + settings.tunnel_options.openvpn.mssfix = Some(1300); + assert_eq!( + compute_feature_indicators(&settings, &endpoint), + expected_indicators, + "Setting mssfix without having an openVPN endpoint should not result in an indicator" + ); + + endpoint.tunnel_type = TunnelType::OpenVpn; + expected_indicators.0.insert(FeatureIndicator::CustomMssFix); + + assert_eq!( + compute_feature_indicators(&settings, &endpoint), + expected_indicators + ); + + endpoint.proxy = Some(ProxyEndpoint { + endpoint: Endpoint { + address: SocketAddr::from(([1, 2, 3, 4], 443)), + protocol: TransportProtocol::Tcp, + }, + proxy_type: ProxyType::Shadowsocks, + }); + + expected_indicators.0.insert(FeatureIndicator::BridgeMode); + assert_eq!( + compute_feature_indicators(&settings, &endpoint), + expected_indicators + ); + + endpoint.tunnel_type = TunnelType::Wireguard; + expected_indicators + .0 + .remove(&FeatureIndicator::CustomMssFix); + expected_indicators.0.remove(&FeatureIndicator::BridgeMode); + assert_eq!( + compute_feature_indicators(&settings, &endpoint), + expected_indicators + ); + + endpoint.quantum_resistant = true; + expected_indicators + .0 + .insert(FeatureIndicator::QuantumResistance); + assert_eq!( + compute_feature_indicators(&settings, &endpoint), + expected_indicators + ); + + endpoint.entry_endpoint = Some(Endpoint { + address: SocketAddr::from(([1, 2, 3, 4], 443)), + protocol: TransportProtocol::Tcp, + }); + expected_indicators.0.insert(FeatureIndicator::Multihop); + assert_eq!( + compute_feature_indicators(&settings, &endpoint), + expected_indicators + ); + + endpoint.obfuscation = Some(ObfuscationEndpoint { + endpoint: Endpoint { + address: SocketAddr::from(([1, 2, 3, 4], 443)), + protocol: TransportProtocol::Tcp, + }, + obfuscation_type: ObfuscationType::Udp2Tcp, + }); + expected_indicators.0.insert(FeatureIndicator::Udp2Tcp); + assert_eq!( + compute_feature_indicators(&settings, &endpoint), + expected_indicators + ); + endpoint.obfuscation.as_mut().unwrap().obfuscation_type = ObfuscationType::Shadowsocks; + expected_indicators.0.remove(&FeatureIndicator::Udp2Tcp); + expected_indicators.0.insert(FeatureIndicator::Shadowsocks); + assert_eq!( + compute_feature_indicators(&settings, &endpoint), + expected_indicators + ); + + settings.tunnel_options.wireguard.mtu = Some(1300); + expected_indicators.0.insert(FeatureIndicator::CustomMtu); + assert_eq!( + compute_feature_indicators(&settings, &endpoint), + expected_indicators + ); + + #[cfg(daita)] + { + endpoint.daita = true; + expected_indicators.0.insert(FeatureIndicator::Daita); + assert_eq!( + compute_feature_indicators(&settings, &endpoint), + expected_indicators + ); + } + + // NOTE: If this match statement fails to compile, it means that a new feature indicator has + // been added. Please update this test to include the new feature indicator. + match FeatureIndicator::QuantumResistance { + FeatureIndicator::QuantumResistance => {} + FeatureIndicator::Multihop => {} + FeatureIndicator::BridgeMode => {} + FeatureIndicator::SplitTunneling => {} + FeatureIndicator::LockdownMode => {} + FeatureIndicator::Udp2Tcp => {} + FeatureIndicator::Shadowsocks => {} + FeatureIndicator::LanSharing => {} + FeatureIndicator::DnsContentBlockers => {} + FeatureIndicator::CustomDns => {} + FeatureIndicator::ServerIpOverride => {} + FeatureIndicator::CustomMtu => {} + FeatureIndicator::CustomMssFix => {} + FeatureIndicator::Daita => {} + } + } +} |
