Roll WebRTC 9745:9761, Libjingle 9742:9761
[chromium-blink-merge.git] / chromeos / network / shill_property_util.cc
blob30a6925bb6af2f6696d18904a9c0b17186123bf1
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chromeos/network/shill_property_util.h"
7 #include <set>
9 #include "base/i18n/icu_encoding_detection.h"
10 #include "base/i18n/icu_string_conversions.h"
11 #include "base/json/json_writer.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/strings/utf_string_conversion_utils.h"
16 #include "base/values.h"
17 #include "chromeos/network/network_ui_data.h"
18 #include "chromeos/network/onc/onc_utils.h"
19 #include "components/device_event_log/device_event_log.h"
20 #include "third_party/cros_system_api/dbus/service_constants.h"
22 namespace chromeos {
24 namespace shill_property_util {
26 namespace {
28 // Replace non UTF8 characters in |str| with a replacement character.
29 std::string ValidateUTF8(const std::string& str) {
30 std::string result;
31 for (int32 index = 0; index < static_cast<int32>(str.size()); ++index) {
32 uint32 code_point_out;
33 bool is_unicode_char = base::ReadUnicodeCharacter(
34 str.c_str(), str.size(), &index, &code_point_out);
35 const uint32 kFirstNonControlChar = 0x20;
36 if (is_unicode_char && (code_point_out >= kFirstNonControlChar)) {
37 base::WriteUnicodeCharacter(code_point_out, &result);
38 } else {
39 const uint32 kReplacementChar = 0xFFFD;
40 // Puts kReplacementChar if character is a control character [0,0x20)
41 // or is not readable UTF8.
42 base::WriteUnicodeCharacter(kReplacementChar, &result);
45 return result;
48 // If existent and non-empty, copies the string at |key| from |source| to
49 // |dest|. Returns true if the string was copied.
50 bool CopyStringFromDictionary(const base::DictionaryValue& source,
51 const std::string& key,
52 base::DictionaryValue* dest) {
53 std::string string_value;
54 if (!source.GetStringWithoutPathExpansion(key, &string_value) ||
55 string_value.empty()) {
56 return false;
58 dest->SetStringWithoutPathExpansion(key, string_value);
59 return true;
62 } // namespace
64 void SetSSID(const std::string ssid, base::DictionaryValue* properties) {
65 std::string hex_ssid = base::HexEncode(ssid.c_str(), ssid.size());
66 properties->SetStringWithoutPathExpansion(shill::kWifiHexSsid, hex_ssid);
69 std::string GetSSIDFromProperties(const base::DictionaryValue& properties,
70 bool verbose_logging,
71 bool* unknown_encoding) {
72 if (unknown_encoding)
73 *unknown_encoding = false;
75 // Get name for debugging.
76 std::string name;
77 properties.GetStringWithoutPathExpansion(shill::kNameProperty, &name);
79 std::string hex_ssid;
80 properties.GetStringWithoutPathExpansion(shill::kWifiHexSsid, &hex_ssid);
82 if (hex_ssid.empty()) {
83 if (verbose_logging)
84 NET_LOG(DEBUG) << "GetSSIDFromProperties: No HexSSID set: " << name;
85 return std::string();
88 std::string ssid;
89 std::vector<uint8> raw_ssid_bytes;
90 if (base::HexStringToBytes(hex_ssid, &raw_ssid_bytes)) {
91 ssid = std::string(raw_ssid_bytes.begin(), raw_ssid_bytes.end());
92 VLOG(2) << "GetSSIDFromProperties: " << name << " HexSsid=" << hex_ssid
93 << " SSID=" << ssid;
94 } else {
95 NET_LOG(ERROR) << "GetSSIDFromProperties: " << name
96 << " Error processing HexSsid: " << hex_ssid;
97 return std::string();
100 if (base::IsStringUTF8(ssid))
101 return ssid;
103 // Detect encoding and convert to UTF-8.
104 std::string encoding;
105 if (!base::DetectEncoding(ssid, &encoding)) {
106 // TODO(stevenjb): This is currently experimental. If we find a case where
107 // base::DetectEncoding() fails, we need to figure out whether we can use
108 // country_code with ConvertToUtf8(). crbug.com/233267.
109 properties.GetStringWithoutPathExpansion(shill::kCountryProperty,
110 &encoding);
112 std::string utf8_ssid;
113 if (!encoding.empty() &&
114 base::ConvertToUtf8AndNormalize(ssid, encoding, &utf8_ssid)) {
115 if (utf8_ssid != ssid) {
116 if (verbose_logging) {
117 NET_LOG(DEBUG) << "GetSSIDFromProperties: " << name
118 << " Encoding=" << encoding << " SSID=" << ssid
119 << " UTF8 SSID=" << utf8_ssid;
122 return utf8_ssid;
125 if (unknown_encoding)
126 *unknown_encoding = true;
127 if (verbose_logging) {
128 NET_LOG(DEBUG) << "GetSSIDFromProperties: " << name
129 << " Unrecognized Encoding=" << encoding;
131 return ssid;
134 std::string GetNetworkIdFromProperties(
135 const base::DictionaryValue& properties) {
136 if (properties.empty())
137 return "EmptyProperties";
138 std::string result;
139 if (properties.GetStringWithoutPathExpansion(shill::kGuidProperty, &result))
140 return result;
141 if (properties.GetStringWithoutPathExpansion(shill::kSSIDProperty, &result))
142 return result;
143 if (properties.GetStringWithoutPathExpansion(shill::kNameProperty, &result))
144 return result;
145 std::string type = "UnknownType";
146 properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
147 return "Unidentified " + type;
150 std::string GetNameFromProperties(const std::string& service_path,
151 const base::DictionaryValue& properties) {
152 std::string name;
153 properties.GetStringWithoutPathExpansion(shill::kNameProperty, &name);
155 std::string validated_name = ValidateUTF8(name);
156 if (validated_name != name) {
157 NET_LOG(DEBUG) << "GetNameFromProperties: " << service_path
158 << " Validated name=" << validated_name << " name=" << name;
161 std::string type;
162 properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
163 if (type.empty()) {
164 NET_LOG(ERROR) << "GetNameFromProperties: " << service_path << " No type.";
165 return validated_name;
167 if (!NetworkTypePattern::WiFi().MatchesType(type))
168 return validated_name;
170 bool unknown_ssid_encoding = false;
171 std::string ssid = GetSSIDFromProperties(
172 properties, true /* verbose_logging */, &unknown_ssid_encoding);
173 if (ssid.empty()) {
174 NET_LOG(ERROR) << "GetNameFromProperties: " << service_path
175 << " No SSID set";
178 // Use |validated_name| if |ssid| is empty.
179 // And if the encoding of the SSID is unknown, use |ssid|, which contains raw
180 // bytes in that case, only if |validated_name| is empty.
181 if (ssid.empty() || (unknown_ssid_encoding && !validated_name.empty()))
182 return validated_name;
184 if (ssid != validated_name) {
185 NET_LOG(DEBUG) << "GetNameFromProperties: " << service_path
186 << " SSID=" << ssid << " Validated name=" << validated_name;
188 return ssid;
191 scoped_ptr<NetworkUIData> GetUIDataFromValue(const base::Value& ui_data_value) {
192 std::string ui_data_str;
193 if (!ui_data_value.GetAsString(&ui_data_str))
194 return scoped_ptr<NetworkUIData>();
195 if (ui_data_str.empty())
196 return make_scoped_ptr(new NetworkUIData());
197 scoped_ptr<base::DictionaryValue> ui_data_dict(
198 chromeos::onc::ReadDictionaryFromJson(ui_data_str));
199 if (!ui_data_dict)
200 return scoped_ptr<NetworkUIData>();
201 return make_scoped_ptr(new NetworkUIData(*ui_data_dict));
204 scoped_ptr<NetworkUIData> GetUIDataFromProperties(
205 const base::DictionaryValue& shill_dictionary) {
206 const base::Value* ui_data_value = NULL;
207 shill_dictionary.GetWithoutPathExpansion(shill::kUIDataProperty,
208 &ui_data_value);
209 if (!ui_data_value) {
210 VLOG(2) << "Dictionary has no UIData entry.";
211 return scoped_ptr<NetworkUIData>();
213 scoped_ptr<NetworkUIData> ui_data = GetUIDataFromValue(*ui_data_value);
214 if (!ui_data)
215 LOG(ERROR) << "UIData is not a valid JSON dictionary.";
216 return ui_data.Pass();
219 void SetUIData(const NetworkUIData& ui_data,
220 base::DictionaryValue* shill_dictionary) {
221 base::DictionaryValue ui_data_dict;
222 ui_data.FillDictionary(&ui_data_dict);
223 std::string ui_data_blob;
224 base::JSONWriter::Write(ui_data_dict, &ui_data_blob);
225 shill_dictionary->SetStringWithoutPathExpansion(shill::kUIDataProperty,
226 ui_data_blob);
229 bool CopyIdentifyingProperties(const base::DictionaryValue& service_properties,
230 const bool properties_read_from_shill,
231 base::DictionaryValue* dest) {
232 bool success = true;
234 // GUID is optional.
235 CopyStringFromDictionary(service_properties, shill::kGuidProperty, dest);
237 std::string type;
238 service_properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
239 success &= !type.empty();
240 dest->SetStringWithoutPathExpansion(shill::kTypeProperty, type);
241 if (type == shill::kTypeWifi) {
242 success &=
243 CopyStringFromDictionary(
244 service_properties, shill::kSecurityClassProperty, dest);
245 success &=
246 CopyStringFromDictionary(service_properties, shill::kWifiHexSsid, dest);
247 success &= CopyStringFromDictionary(
248 service_properties, shill::kModeProperty, dest);
249 } else if (type == shill::kTypeCellular) {
250 success &= CopyStringFromDictionary(
251 service_properties, shill::kNetworkTechnologyProperty, dest);
252 } else if (type == shill::kTypeVPN) {
253 success &= CopyStringFromDictionary(
254 service_properties, shill::kNameProperty, dest);
256 // VPN Provider values are read from the "Provider" dictionary, but written
257 // with the keys "Provider.Type" and "Provider.Host".
258 // TODO(pneubeck): Simplify this once http://crbug.com/381135 is fixed.
259 std::string vpn_provider_type;
260 std::string vpn_provider_host;
261 if (properties_read_from_shill) {
262 const base::DictionaryValue* provider_properties = NULL;
263 if (!service_properties.GetDictionaryWithoutPathExpansion(
264 shill::kProviderProperty, &provider_properties)) {
265 NET_LOG(ERROR) << "Missing VPN provider dict: "
266 << GetNetworkIdFromProperties(service_properties);
268 provider_properties->GetStringWithoutPathExpansion(shill::kTypeProperty,
269 &vpn_provider_type);
270 provider_properties->GetStringWithoutPathExpansion(shill::kHostProperty,
271 &vpn_provider_host);
272 } else {
273 service_properties.GetStringWithoutPathExpansion(
274 shill::kProviderTypeProperty, &vpn_provider_type);
275 service_properties.GetStringWithoutPathExpansion(
276 shill::kProviderHostProperty, &vpn_provider_host);
278 success &= !vpn_provider_type.empty();
279 dest->SetStringWithoutPathExpansion(shill::kProviderTypeProperty,
280 vpn_provider_type);
282 success &= !vpn_provider_host.empty();
283 dest->SetStringWithoutPathExpansion(shill::kProviderHostProperty,
284 vpn_provider_host);
285 } else if (type == shill::kTypeEthernet || type == shill::kTypeEthernetEap) {
286 // Ethernet and EthernetEAP don't have any additional identifying
287 // properties.
288 } else {
289 NOTREACHED() << "Unsupported network type " << type;
290 success = false;
292 if (!success) {
293 NET_LOG(ERROR) << "Missing required properties: "
294 << GetNetworkIdFromProperties(service_properties);
296 return success;
299 bool DoIdentifyingPropertiesMatch(const base::DictionaryValue& new_properties,
300 const base::DictionaryValue& old_properties) {
301 base::DictionaryValue new_identifying;
302 if (!CopyIdentifyingProperties(
303 new_properties,
304 false /* properties were not read from Shill */,
305 &new_identifying)) {
306 return false;
308 base::DictionaryValue old_identifying;
309 if (!CopyIdentifyingProperties(old_properties,
310 true /* properties were read from Shill */,
311 &old_identifying)) {
312 return false;
315 return new_identifying.Equals(&old_identifying);
318 bool IsLoggableShillProperty(const std::string& key) {
319 static std::set<std::string>* s_skip_properties = nullptr;
320 if (!s_skip_properties) {
321 s_skip_properties = new std::set<std::string>;
322 s_skip_properties->insert(shill::kApnPasswordProperty);
323 s_skip_properties->insert(shill::kEapCaCertNssProperty);
324 s_skip_properties->insert(shill::kEapCaCertPemProperty);
325 s_skip_properties->insert(shill::kEapCaCertProperty);
326 s_skip_properties->insert(shill::kEapClientCertNssProperty);
327 s_skip_properties->insert(shill::kEapClientCertProperty);
328 s_skip_properties->insert(shill::kEapPasswordProperty);
329 s_skip_properties->insert(shill::kEapPinProperty);
330 s_skip_properties->insert(shill::kEapPrivateKeyPasswordProperty);
331 s_skip_properties->insert(shill::kEapPrivateKeyProperty);
332 s_skip_properties->insert(shill::kL2tpIpsecCaCertPemProperty);
333 s_skip_properties->insert(shill::kL2tpIpsecPasswordProperty);
334 s_skip_properties->insert(shill::kL2tpIpsecPinProperty);
335 s_skip_properties->insert(shill::kL2tpIpsecPskProperty);
336 s_skip_properties->insert(shill::kOpenVPNAuthUserPassProperty);
337 s_skip_properties->insert(shill::kOpenVPNCaCertNSSProperty);
338 s_skip_properties->insert(shill::kOpenVPNCaCertPemProperty);
339 s_skip_properties->insert(shill::kOpenVPNCaCertProperty);
340 s_skip_properties->insert(shill::kOpenVPNCertProperty);
341 s_skip_properties->insert(shill::kOpenVPNExtraCertPemProperty);
342 s_skip_properties->insert(shill::kOpenVPNOTPProperty);
343 s_skip_properties->insert(shill::kOpenVPNPasswordProperty);
344 s_skip_properties->insert(shill::kOpenVPNPinProperty);
345 s_skip_properties->insert(shill::kOpenVPNTLSAuthContentsProperty);
346 s_skip_properties->insert(shill::kPPPoEPasswordProperty);
347 s_skip_properties->insert(shill::kPassphraseProperty);
349 return s_skip_properties->count(key) == 0;
352 bool GetHomeProviderFromProperty(const base::Value& value,
353 std::string* home_provider_id) {
354 const base::DictionaryValue* dict = NULL;
355 if (!value.GetAsDictionary(&dict))
356 return false;
357 std::string home_provider_country;
358 std::string home_provider_name;
359 dict->GetStringWithoutPathExpansion(shill::kOperatorCountryKey,
360 &home_provider_country);
361 dict->GetStringWithoutPathExpansion(shill::kOperatorNameKey,
362 &home_provider_name);
363 // Set home_provider_id
364 if (!home_provider_name.empty() && !home_provider_country.empty()) {
365 *home_provider_id = base::StringPrintf(
366 "%s (%s)", home_provider_name.c_str(), home_provider_country.c_str());
367 } else {
368 if (!dict->GetStringWithoutPathExpansion(shill::kOperatorCodeKey,
369 home_provider_id)) {
370 return false;
372 LOG(WARNING)
373 << "Provider name and country not defined, using code instead: "
374 << *home_provider_id;
376 return true;
379 } // namespace shill_property_util
381 } // namespace chromeos