1use anyhow::{format_err, Error};
6use fidl_fuchsia_wlan_policy as wlan_policy;
7use percent_encoding::{percent_decode_str, utf8_percent_encode, AsciiSet, CONTROLS};
8use serde::{Deserialize, Serialize};
9
10#[derive(Serialize, Deserialize)]
11struct WlanConfigDump {
12 version: u32,
13 data: Vec<SimplifiedNetworkConfig>,
14}
15#[derive(Serialize, Deserialize, Clone)]
16struct SimplifiedNetworkConfig {
17 ssid: Vec<u8>,
18 credential: Credential,
19 security_type: SecurityType,
20}
21
22#[derive(Serialize, Deserialize, Clone)]
23enum Credential {
24 None,
25 Password(Vec<u8>),
26 Psk(Vec<u8>),
27}
28
29#[derive(Serialize, Deserialize, Clone)]
30enum SecurityType {
31 None = 1,
32 Wep = 2,
33 Wpa = 3,
34 Wpa2 = 4,
35 Wpa3 = 5,
36}
37
38impl From<wlan_policy::SecurityType> for SecurityType {
39 fn from(security: wlan_policy::SecurityType) -> Self {
40 match security {
41 wlan_policy::SecurityType::None => SecurityType::None,
42 wlan_policy::SecurityType::Wep => SecurityType::Wep,
43 wlan_policy::SecurityType::Wpa => SecurityType::Wpa,
44 wlan_policy::SecurityType::Wpa2 => SecurityType::Wpa2,
45 wlan_policy::SecurityType::Wpa3 => SecurityType::Wpa3,
46 }
47 }
48}
49
50impl From<SecurityType> for wlan_policy::SecurityType {
51 fn from(security: SecurityType) -> Self {
52 match security {
53 SecurityType::None => wlan_policy::SecurityType::None,
54 SecurityType::Wep => wlan_policy::SecurityType::Wep,
55 SecurityType::Wpa => wlan_policy::SecurityType::Wpa,
56 SecurityType::Wpa2 => wlan_policy::SecurityType::Wpa2,
57 SecurityType::Wpa3 => wlan_policy::SecurityType::Wpa3,
58 }
59 }
60}
61
62impl TryFrom<wlan_policy::Credential> for Credential {
63 type Error = &'static str;
64
65 fn try_from(security: wlan_policy::Credential) -> Result<Self, Self::Error> {
66 match security {
67 wlan_policy::Credential::None(_) => Ok(Credential::None),
68 wlan_policy::Credential::Password(pass) => Ok(Credential::Password(pass)),
69 wlan_policy::Credential::Psk(psk) => Ok(Credential::Psk(psk)),
70 wlan_policy::CredentialUnknown!() => Err("Unrecognized credential"),
71 }
72 }
73}
74
75impl From<Credential> for wlan_policy::Credential {
76 fn from(security: Credential) -> Self {
77 match security {
78 Credential::None => wlan_policy::Credential::None(wlan_policy::Empty),
79 Credential::Password(pass) => wlan_policy::Credential::Password(pass),
80 Credential::Psk(psk) => wlan_policy::Credential::Psk(psk),
81 }
82 }
83}
84
85impl TryFrom<wlan_policy::NetworkConfig> for SimplifiedNetworkConfig {
86 type Error = &'static str;
87
88 fn try_from(config: wlan_policy::NetworkConfig) -> Result<Self, Self::Error> {
89 let id = match config.id {
90 Some(id) => id,
91 None => return Err("Network has no identifier"),
92 };
93
94 let credential = match config.credential {
95 Some(credential) => credential,
96 None => return Err("Network has no credential"),
97 };
98
99 let credential = credential.try_into()?;
100
101 Ok(SimplifiedNetworkConfig {
102 ssid: id.ssid,
103 credential: credential,
104 security_type: id.type_.into(),
105 })
106 }
107}
108
109impl From<SimplifiedNetworkConfig> for wlan_policy::NetworkConfig {
110 fn from(simplified_config: SimplifiedNetworkConfig) -> Self {
111 Self {
112 id: Some(wlan_policy::NetworkIdentifier {
113 ssid: simplified_config.ssid,
114 type_: simplified_config.security_type.into(),
115 }),
116 credential: Some(simplified_config.credential.into()),
117 ..Default::default()
118 }
119 }
120}
121
122pub fn serialize_saved_networks(
124 saved_networks: Vec<wlan_policy::NetworkConfig>,
125) -> Result<String, Error> {
126 let simplified_saved_networks = saved_networks
127 .iter()
128 .filter_map(|network| match SimplifiedNetworkConfig::try_from(network.clone()) {
129 Ok(network) => Some(network),
130 Err(_e) => None,
131 })
132 .collect();
133 let dump = WlanConfigDump { version: 1, data: simplified_saved_networks };
134 let json = serde_json::to_string(&dump)?;
135 const FRAGMENT: &AsciiSet = &CONTROLS.add(b' ').add(b'"').add(b'<').add(b'>').add(b'`');
137 let percent_encoded = utf8_percent_encode(&json, FRAGMENT).to_string();
138 Ok(percent_encoded)
139}
140
141pub fn deserialize_saved_networks(
142 raw_data: String,
143) -> Result<Vec<wlan_policy::NetworkConfig>, Error> {
144 let json = percent_decode_str(&raw_data).decode_utf8()?;
145 let data: WlanConfigDump =
146 serde_json::from_str(&json).map_err(|e| format_err!("Failed to parse config: {}", e))?;
147 let networks: Vec<wlan_policy::NetworkConfig> =
148 data.data.iter().map(|network| wlan_policy::NetworkConfig::from(network.clone())).collect();
149 Ok(networks)
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155 use ieee80211::Ssid;
156
157 fn generate_test_data() -> (String, Vec<wlan_policy::NetworkConfig>) {
158 let serialized = "{%22version%22:1,%22data%22:[{%22ssid%22:[84,101,115,116,87,76,65,78,49],%22credential%22:{%22Password%22:[49,50,51,52,53,54,55,56]},%22security_type%22:%22Wpa2%22}]}".to_string();
159
160 let deserialized: Vec<wlan_policy::NetworkConfig> = vec![wlan_policy::NetworkConfig {
161 id: Some(wlan_policy::NetworkIdentifier {
162 ssid: Ssid::try_from("TestWLAN1").unwrap().into(),
163 type_: wlan_policy::SecurityType::Wpa2,
164 }),
165 credential: Some(wlan_policy::Credential::Password("12345678".as_bytes().to_vec())),
166 ..Default::default()
167 }];
168
169 (serialized, deserialized)
170 }
171
172 #[fuchsia::test]
173 fn test_serialization() {
174 let (serialized, deserialized) = generate_test_data();
175 assert_eq!(serialized, serialize_saved_networks(deserialized).unwrap());
176 }
177
178 #[fuchsia::test]
179 fn test_serialization_with_malformed_network() {
180 let (serialized, mut deserialized) = generate_test_data();
181 let mut malformed = vec![wlan_policy::NetworkConfig {
183 id: Some(wlan_policy::NetworkIdentifier {
184 ssid: Ssid::try_from("MALFORMED - NO CREDENTIAL").unwrap().into(),
185 type_: wlan_policy::SecurityType::Wpa2,
186 }),
187 ..Default::default()
188 }];
189 deserialized.append(&mut malformed);
190 assert_eq!(serialized, serialize_saved_networks(deserialized).unwrap());
192 }
193
194 #[fuchsia::test]
195 fn test_deserialization() {
196 let (serialized, deserialized) = generate_test_data();
197 assert_eq!(deserialized, deserialize_saved_networks(serialized).unwrap());
198 }
199}