Check USB device path access when prompting users to select a device.
[chromium-blink-merge.git] / chrome / browser / supervised_user / supervised_user_site_list.cc
blob90c31e18500373166492ccbee5a5dd7cca0a22ee
1 // Copyright 2014 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 "chrome/browser/supervised_user/supervised_user_site_list.h"
7 #include "base/files/file_util.h"
8 #include "base/json/json_file_value_serializer.h"
9 #include "base/logging.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "base/task_runner_util.h"
12 #include "base/values.h"
13 #include "chrome/browser/safe_json_parser.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "url/gurl.h"
17 const int kSitelistFormatVersion = 1;
19 const char kHostnameHashesKey[] = "hostname_hashes";
20 const char kNameKey[] = "name";
21 const char kSitesKey[] = "sites";
22 const char kSitelistFormatVersionKey[] = "version";
23 const char kUrlKey[] = "url";
24 const char kWhitelistKey[] = "whitelist";
26 namespace {
28 bool g_load_in_process = false;
30 std::string ReadFileOnBlockingThread(const base::FilePath& path) {
31 SCOPED_UMA_HISTOGRAM_TIMER("ManagedUsers.Whitelist.ReadDuration");
32 std::string contents;
33 base::ReadFileToString(path, &contents);
34 return contents;
37 void HandleError(const base::FilePath& path, const std::string& error) {
38 LOG(ERROR) << "Couldn't load site list " << path.value() << ": " << error;
41 // Takes a DictionaryValue entry from the JSON file and fills the whitelist
42 // (via URL patterns or hostname hashes) and the URL in the corresponding Site
43 // struct.
44 void AddWhitelistEntries(const base::DictionaryValue* site_dict,
45 SupervisedUserSiteList::Site* site) {
46 std::vector<std::string>* patterns = &site->patterns;
48 bool found = false;
49 const base::ListValue* whitelist = nullptr;
50 if (site_dict->GetList(kWhitelistKey, &whitelist)) {
51 found = true;
52 for (const base::Value* entry : *whitelist) {
53 std::string pattern;
54 if (!entry->GetAsString(&pattern)) {
55 LOG(ERROR) << "Invalid whitelist entry";
56 continue;
59 patterns->push_back(pattern);
63 std::vector<std::string>* hashes = &site->hostname_hashes;
64 const base::ListValue* hash_list = nullptr;
65 if (site_dict->GetList(kHostnameHashesKey, &hash_list)) {
66 found = true;
67 for (const base::Value* entry : *hash_list) {
68 std::string hash;
69 if (!entry->GetAsString(&hash)) {
70 LOG(ERROR) << "Invalid whitelist entry";
71 continue;
74 hashes->push_back(hash);
78 if (found)
79 return;
81 // Fall back to using a whitelist based on the URL.
82 std::string url_str;
83 if (!site_dict->GetString(kUrlKey, &url_str)) {
84 LOG(ERROR) << "Whitelist is invalid";
85 return;
88 GURL url(url_str);
89 if (!url.is_valid()) {
90 LOG(ERROR) << "URL " << url_str << " is invalid";
91 return;
94 patterns->push_back(url.host());
97 } // namespace
99 SupervisedUserSiteList::Site::Site(const base::string16& name) : name(name) {
102 SupervisedUserSiteList::Site::~Site() {
105 void SupervisedUserSiteList::Load(const base::FilePath& path,
106 const LoadedCallback& callback) {
107 base::PostTaskAndReplyWithResult(
108 content::BrowserThread::GetBlockingPool(),
109 FROM_HERE,
110 base::Bind(&ReadFileOnBlockingThread, path),
111 base::Bind(&SupervisedUserSiteList::ParseJson, path, callback));
114 // static
115 void SupervisedUserSiteList::SetLoadInProcessForTesting(bool in_process) {
116 g_load_in_process = in_process;
119 SupervisedUserSiteList::SupervisedUserSiteList(const base::ListValue& sites) {
120 for (const base::Value* site : sites) {
121 const base::DictionaryValue* entry = nullptr;
122 if (!site->GetAsDictionary(&entry)) {
123 LOG(ERROR) << "Entry is invalid";
124 continue;
127 base::string16 name;
128 entry->GetString(kNameKey, &name);
129 sites_.push_back(Site(name));
130 AddWhitelistEntries(entry, &sites_.back());
134 SupervisedUserSiteList::~SupervisedUserSiteList() {
137 // static
138 void SupervisedUserSiteList::ParseJson(
139 const base::FilePath& path,
140 const SupervisedUserSiteList::LoadedCallback& callback,
141 const std::string& json) {
142 if (g_load_in_process) {
143 JSONFileValueDeserializer deserializer(path);
144 std::string error;
145 scoped_ptr<base::Value> value(deserializer.Deserialize(nullptr, &error));
146 if (!value) {
147 HandleError(path, error);
148 return;
151 OnJsonParseSucceeded(path, base::TimeTicks(), callback, value.Pass());
152 return;
155 // TODO(bauerb): Use batch mode to load multiple whitelists?
156 scoped_refptr<SafeJsonParser> parser(new SafeJsonParser(
157 json,
158 base::Bind(&SupervisedUserSiteList::OnJsonParseSucceeded, path,
159 base::TimeTicks::Now(), callback),
160 base::Bind(&HandleError, path)));
161 parser->Start();
164 // static
165 void SupervisedUserSiteList::OnJsonParseSucceeded(
166 const base::FilePath& path,
167 base::TimeTicks start_time,
168 const SupervisedUserSiteList::LoadedCallback& callback,
169 scoped_ptr<base::Value> value) {
170 if (!start_time.is_null()) {
171 UMA_HISTOGRAM_TIMES("ManagedUsers.Whitelist.JsonParseDuration",
172 base::TimeTicks::Now() - start_time);
175 base::DictionaryValue* dict = nullptr;
176 if (!value->GetAsDictionary(&dict)) {
177 LOG(ERROR) << "Site list " << path.value() << " is invalid";
178 return;
181 int version = 0;
182 if (!dict->GetInteger(kSitelistFormatVersionKey, &version)) {
183 LOG(ERROR) << "Site list " << path.value() << " has invalid version";
184 return;
187 if (version > kSitelistFormatVersion) {
188 LOG(ERROR) << "Site list " << path.value() << " has a too new format";
189 return;
192 base::ListValue* sites = nullptr;
193 if (!dict->GetList(kSitesKey, &sites)) {
194 LOG(ERROR) << "Site list " << path.value()
195 << " does not contain any sites";
196 return;
199 callback.Run(make_scoped_refptr(new SupervisedUserSiteList(*sites)));