158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// found in the LICENSE file.
458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chromeos/network/shill_property_util.h"
658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/i18n/icu_encoding_detection.h"
858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/i18n/icu_string_conversions.h"
958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/json/json_writer.h"
1058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
1158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/strings/string_util.h"
1258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/strings/stringprintf.h"
1358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/strings/utf_string_conversion_utils.h"
1458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/values.h"
1558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chromeos/network/network_event_log.h"
1658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chromeos/network/network_ui_data.h"
1758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chromeos/network/onc/onc_utils.h"
1858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "third_party/cros_system_api/dbus/service_constants.h"
1958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)namespace chromeos {
2158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)namespace shill_property_util {
2358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)namespace {
2558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Replace non UTF8 characters in |str| with a replacement character.
2758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)std::string ValidateUTF8(const std::string& str) {
2858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string result;
2958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  for (int32 index = 0; index < static_cast<int32>(str.size()); ++index) {
3058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    uint32 code_point_out;
3158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    bool is_unicode_char = base::ReadUnicodeCharacter(
3258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        str.c_str(), str.size(), &index, &code_point_out);
3358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const uint32 kFirstNonControlChar = 0x20;
3458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (is_unicode_char && (code_point_out >= kFirstNonControlChar)) {
3558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      base::WriteUnicodeCharacter(code_point_out, &result);
3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    } else {
3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      const uint32 kReplacementChar = 0xFFFD;
3858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      // Puts kReplacementChar if character is a control character [0,0x20)
3958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      // or is not readable UTF8.
4058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      base::WriteUnicodeCharacter(kReplacementChar, &result);
4158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
4258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
4358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return result;
4458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
4558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// If existent and non-empty, copies the string at |key| from |source| to
4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// |dest|. Returns true if the string was copied.
4858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool CopyStringFromDictionary(const base::DictionaryValue& source,
4958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                              const std::string& key,
5058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                              base::DictionaryValue* dest) {
5158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string string_value;
5258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!source.GetStringWithoutPathExpansion(key, &string_value) ||
53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      string_value.empty()) {
5458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return false;
55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
5658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  dest->SetStringWithoutPathExpansion(key, string_value);
5758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return true;
5858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
5958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// This is the same normalization that Shill applies to security types for the
61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// sake of comparing/identifying WiFi networks. See Shill's
62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// WiFiService::GetSecurityClass.
63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)std::string GetSecurityClass(const std::string& security) {
64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (security == shill::kSecurityRsn || security == shill::kSecurityWpa)
65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return shill::kSecurityPsk;
66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  else
67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return security;
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
7058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}  // namespace
7158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void SetSSID(const std::string ssid, base::DictionaryValue* properties) {
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string hex_ssid = base::HexEncode(ssid.c_str(), ssid.size());
744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  properties->SetStringWithoutPathExpansion(shill::kWifiHexSsid, hex_ssid);
754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)std::string GetSSIDFromProperties(const base::DictionaryValue& properties,
784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                  bool* unknown_encoding) {
79116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool verbose_logging = false;
80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (unknown_encoding) {
814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    *unknown_encoding = false;
82116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    verbose_logging = true;
83116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Get name for debugging.
86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::string name;
87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  properties.GetStringWithoutPathExpansion(shill::kNameProperty, &name);
88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string hex_ssid;
9068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  properties.GetStringWithoutPathExpansion(shill::kWifiHexSsid, &hex_ssid);
9158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
9258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (hex_ssid.empty()) {
93116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (verbose_logging)
94116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      NET_LOG_DEBUG("GetSSIDFromProperties: No HexSSID set.", name);
954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return std::string();
9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
9758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
9858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string ssid;
9958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::vector<uint8> raw_ssid_bytes;
10058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (base::HexStringToBytes(hex_ssid, &raw_ssid_bytes)) {
10158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    ssid = std::string(raw_ssid_bytes.begin(), raw_ssid_bytes.end());
102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (verbose_logging) {
103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      NET_LOG_DEBUG(base::StringPrintf("GetSSIDFromProperties: %s, SSID: %s",
104116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                       hex_ssid.c_str(), ssid.c_str()), name);
105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
10658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  } else {
107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    NET_LOG_ERROR(
108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        base::StringPrintf("GetSSIDFromProperties: Error processing: %s",
109116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           hex_ssid.c_str()), name);
1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return std::string();
11158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
11258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
113010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (base::IsStringUTF8(ssid))
11458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return ssid;
11558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
11658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Detect encoding and convert to UTF-8.
11758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string encoding;
11858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!base::DetectEncoding(ssid, &encoding)) {
11958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // TODO(stevenjb): This is currently experimental. If we find a case where
12058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // base::DetectEncoding() fails, we need to figure out whether we can use
12158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // country_code with ConvertToUtf8(). crbug.com/233267.
1224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    properties.GetStringWithoutPathExpansion(shill::kCountryProperty,
1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                             &encoding);
12458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string utf8_ssid;
1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!encoding.empty() &&
1274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      base::ConvertToUtf8AndNormalize(ssid, encoding, &utf8_ssid)) {
1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (utf8_ssid != ssid) {
129116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (verbose_logging) {
130116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        NET_LOG_DEBUG(
131116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            base::StringPrintf("GetSSIDFromProperties: Encoding=%s: %s",
132116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                               encoding.c_str(), utf8_ssid.c_str()), name);
133116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      }
13458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return utf8_ssid;
13658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
13758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (unknown_encoding)
1394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    *unknown_encoding = true;
140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (verbose_logging) {
141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    NET_LOG_DEBUG(
142116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        base::StringPrintf("GetSSIDFromProperties: Unrecognized Encoding=%s",
143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           encoding.c_str()), name);
144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
1454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return ssid;
1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
148effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstd::string GetNetworkIdFromProperties(
149effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const base::DictionaryValue& properties) {
150effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (properties.empty())
151effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return "EmptyProperties";
152effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::string result;
153effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (properties.GetStringWithoutPathExpansion(shill::kGuidProperty, &result))
154effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return result;
155effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (properties.GetStringWithoutPathExpansion(shill::kSSIDProperty, &result))
156effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return result;
157effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (properties.GetStringWithoutPathExpansion(shill::kNameProperty, &result))
158effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return result;
159effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::string type = "UnknownType";
160effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
161effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return "Unidentified " + type;
162effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
163effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
1644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)std::string GetNameFromProperties(const std::string& service_path,
1654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                  const base::DictionaryValue& properties) {
1664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string name;
1674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  properties.GetStringWithoutPathExpansion(shill::kNameProperty, &name);
1684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string validated_name = ValidateUTF8(name);
1704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (validated_name != name) {
1714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    NET_LOG_DEBUG("GetNameFromProperties",
1724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                  base::StringPrintf("Validated name %s: UTF8: %s",
1734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                     service_path.c_str(),
1744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                     validated_name.c_str()));
1754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string type;
1784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
179effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (type.empty()) {
180effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    NET_LOG_ERROR("GetNameFromProperties: No type", service_path);
181effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return validated_name;
182effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
1834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!NetworkTypePattern::WiFi().MatchesType(type))
1844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return validated_name;
1854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  bool unknown_ssid_encoding = false;
1874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string ssid = GetSSIDFromProperties(properties, &unknown_ssid_encoding);
1884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (ssid.empty())
1894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    NET_LOG_ERROR("GetNameFromProperties", "No SSID set: " + service_path);
1904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Use |validated_name| if |ssid| is empty.
1924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // And if the encoding of the SSID is unknown, use |ssid|, which contains raw
1934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // bytes in that case, only if |validated_name| is empty.
1944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (ssid.empty() || (unknown_ssid_encoding && !validated_name.empty()))
1954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return validated_name;
1964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (ssid != validated_name) {
1984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    NET_LOG_DEBUG("GetNameFromProperties",
1994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                  base::StringPrintf("%s: SSID: %s, Name: %s",
2004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                     service_path.c_str(),
2014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                     ssid.c_str(),
2024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                     validated_name.c_str()));
2034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
2044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return ssid;
20558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
20658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
20758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)scoped_ptr<NetworkUIData> GetUIDataFromValue(const base::Value& ui_data_value) {
20858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string ui_data_str;
20958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!ui_data_value.GetAsString(&ui_data_str))
21058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return scoped_ptr<NetworkUIData>();
21158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (ui_data_str.empty())
21258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return make_scoped_ptr(new NetworkUIData());
21358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> ui_data_dict(
21458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      chromeos::onc::ReadDictionaryFromJson(ui_data_str));
21558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!ui_data_dict)
21658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return scoped_ptr<NetworkUIData>();
21758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return make_scoped_ptr(new NetworkUIData(*ui_data_dict));
21858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
21958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
22058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)scoped_ptr<NetworkUIData> GetUIDataFromProperties(
22158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const base::DictionaryValue& shill_dictionary) {
22258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const base::Value* ui_data_value = NULL;
22368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  shill_dictionary.GetWithoutPathExpansion(shill::kUIDataProperty,
22458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                           &ui_data_value);
22558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!ui_data_value) {
22658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    VLOG(2) << "Dictionary has no UIData entry.";
22758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return scoped_ptr<NetworkUIData>();
22858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
22958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  scoped_ptr<NetworkUIData> ui_data = GetUIDataFromValue(*ui_data_value);
23058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!ui_data)
23158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    LOG(ERROR) << "UIData is not a valid JSON dictionary.";
23258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return ui_data.Pass();
23358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
23458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
23558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void SetUIData(const NetworkUIData& ui_data,
23658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)               base::DictionaryValue* shill_dictionary) {
23758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  base::DictionaryValue ui_data_dict;
23858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  ui_data.FillDictionary(&ui_data_dict);
23958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string ui_data_blob;
24058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  base::JSONWriter::Write(&ui_data_dict, &ui_data_blob);
24168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  shill_dictionary->SetStringWithoutPathExpansion(shill::kUIDataProperty,
24258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                                  ui_data_blob);
24358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
24458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
24558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool CopyIdentifyingProperties(const base::DictionaryValue& service_properties,
246f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                               const bool properties_read_from_shill,
24758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                               base::DictionaryValue* dest) {
24858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  bool success = true;
24958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
25058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // GUID is optional.
25168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  CopyStringFromDictionary(service_properties, shill::kGuidProperty, dest);
25258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
25358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string type;
25468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  service_properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
25558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  success &= !type.empty();
25668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  dest->SetStringWithoutPathExpansion(shill::kTypeProperty, type);
25768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (type == shill::kTypeWifi) {
258cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    std::string security;
259cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    service_properties.GetStringWithoutPathExpansion(shill::kSecurityProperty,
260cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                                     &security);
261cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (security.empty()) {
262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      success = false;
263cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    } else {
264cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      dest->SetStringWithoutPathExpansion(shill::kSecurityProperty,
265cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                          GetSecurityClass(security));
266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
2674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    success &=
2684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        CopyStringFromDictionary(service_properties, shill::kWifiHexSsid, dest);
26958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    success &= CopyStringFromDictionary(
27068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        service_properties, shill::kModeProperty, dest);
27168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  } else if (type == shill::kTypeVPN) {
27258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    success &= CopyStringFromDictionary(
27368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        service_properties, shill::kNameProperty, dest);
274f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
27558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // VPN Provider values are read from the "Provider" dictionary, but written
27658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // with the keys "Provider.Type" and "Provider.Host".
277f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // TODO(pneubeck): Simplify this once http://crbug.com/381135 is fixed.
27858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    std::string vpn_provider_type;
279f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::string vpn_provider_host;
280f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (properties_read_from_shill) {
281f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      const base::DictionaryValue* provider_properties = NULL;
282f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (!service_properties.GetDictionaryWithoutPathExpansion(
283f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)              shill::kProviderProperty, &provider_properties)) {
284f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        NET_LOG_ERROR("Missing VPN provider dict",
285f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                      GetNetworkIdFromProperties(service_properties));
286f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      }
287f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      provider_properties->GetStringWithoutPathExpansion(shill::kTypeProperty,
288f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                                         &vpn_provider_type);
289f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      provider_properties->GetStringWithoutPathExpansion(shill::kHostProperty,
290f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                                         &vpn_provider_host);
291f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    } else {
292f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      service_properties.GetStringWithoutPathExpansion(
293f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          shill::kProviderTypeProperty, &vpn_provider_type);
294f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      service_properties.GetStringWithoutPathExpansion(
295f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          shill::kProviderHostProperty, &vpn_provider_host);
296f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
29758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    success &= !vpn_provider_type.empty();
29868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    dest->SetStringWithoutPathExpansion(shill::kProviderTypeProperty,
29958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                        vpn_provider_type);
30058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
30158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    success &= !vpn_provider_host.empty();
30268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    dest->SetStringWithoutPathExpansion(shill::kProviderHostProperty,
30358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                        vpn_provider_host);
30468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  } else if (type == shill::kTypeEthernet || type == shill::kTypeEthernetEap) {
30558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Ethernet and EthernetEAP don't have any additional identifying
30658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // properties.
30758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  } else {
30858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    NOTREACHED() << "Unsupported network type " << type;
30958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    success = false;
31058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
311effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!success) {
312effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    NET_LOG_ERROR("Missing required properties",
313effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                  GetNetworkIdFromProperties(service_properties));
314effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
31558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return success;
31658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
31758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
318f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool DoIdentifyingPropertiesMatch(const base::DictionaryValue& new_properties,
319f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                  const base::DictionaryValue& old_properties) {
320f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  base::DictionaryValue new_identifying;
321f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!CopyIdentifyingProperties(
322f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          new_properties,
323f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          false /* properties were not read from Shill */,
324f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          &new_identifying)) {
325f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
326f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
327f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  base::DictionaryValue old_identifying;
328f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!CopyIdentifyingProperties(old_properties,
329f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                 true /* properties were read from Shill */,
330f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                 &old_identifying)) {
331f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
332f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
333f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
334f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return new_identifying.Equals(&old_identifying);
335f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
336f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
337effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool IsPassphraseKey(const std::string& key) {
338effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return key == shill::kEapPrivateKeyPasswordProperty ||
339effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      key == shill::kEapPasswordProperty ||
340effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      key == shill::kL2tpIpsecPasswordProperty ||
341effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      key == shill::kOpenVPNPasswordProperty ||
342effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      key == shill::kOpenVPNAuthUserPassProperty ||
343effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      key == shill::kOpenVPNTLSAuthContentsProperty ||
344effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      key == shill::kPassphraseProperty ||
345effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      key == shill::kOpenVPNOTPProperty ||
346effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      key == shill::kEapPrivateKeyProperty ||
347effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      key == shill::kEapPinProperty ||
348effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      key == shill::kApnPasswordProperty;
349effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
350effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
351cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool GetHomeProviderFromProperty(const base::Value& value,
352cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                 std::string* home_provider_id) {
353cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const base::DictionaryValue* dict = NULL;
354cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!value.GetAsDictionary(&dict))
355cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return false;
356cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string home_provider_country;
357cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string home_provider_name;
358cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  dict->GetStringWithoutPathExpansion(shill::kOperatorCountryKey,
359cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                      &home_provider_country);
360cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  dict->GetStringWithoutPathExpansion(shill::kOperatorNameKey,
361cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                      &home_provider_name);
362cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Set home_provider_id
363cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!home_provider_name.empty() && !home_provider_country.empty()) {
364cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    *home_provider_id = base::StringPrintf(
365cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        "%s (%s)", home_provider_name.c_str(), home_provider_country.c_str());
366cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else {
367cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!dict->GetStringWithoutPathExpansion(shill::kOperatorCodeKey,
368cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                             home_provider_id)) {
369cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return false;
370cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
371cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    LOG(WARNING)
372cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        << "Provider name and country not defined, using code instead: "
373cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        << *home_provider_id;
37458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
375cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return true;
37658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
37758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
378cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}  // namespace shill_property_util
37958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
38058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}  // namespace chromeos
381