Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / supervised_user / supervised_user_site_list.cc
blobde3baaca1f0d005c5146c509526419d93a5469eb
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 "content/public/browser/browser_thread.h"
14 #include "url/gurl.h"
16 const int kSitelistFormatVersion = 1;
18 const char kHostnameHashesKey[] = "hostname_hashes";
19 const char kNameKey[] = "name";
20 const char kSitesKey[] = "sites";
21 const char kSitelistFormatVersionKey[] = "version";
22 const char kUrlKey[] = "url";
23 const char kWhitelistKey[] = "whitelist";
25 namespace {
27 scoped_ptr<base::Value> ReadFileOnBlockingThread(const base::FilePath& path) {
28 SCOPED_UMA_HISTOGRAM_TIMER("ManagedUsers.Whitelist.ReadDuration");
29 JSONFileValueDeserializer deserializer(path);
30 int error_code;
31 std::string error_msg;
32 scoped_ptr<base::Value> value(
33 deserializer.Deserialize(&error_code, &error_msg));
34 if (!value) {
35 LOG(ERROR) << "Couldn't load site list " << path.value() << ": "
36 << error_msg;
38 return value.Pass();
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 bool found = false;
48 const base::ListValue* whitelist = nullptr;
49 if (site_dict->GetList(kWhitelistKey, &whitelist)) {
50 found = true;
51 for (const base::Value* entry : *whitelist) {
52 std::string pattern;
53 if (!entry->GetAsString(&pattern)) {
54 LOG(ERROR) << "Invalid whitelist entry";
55 continue;
58 site->patterns.push_back(pattern);
62 const base::ListValue* hash_list = nullptr;
63 if (site_dict->GetList(kHostnameHashesKey, &hash_list)) {
64 found = true;
65 for (const base::Value* entry : *hash_list) {
66 std::string hash;
67 if (!entry->GetAsString(&hash)) {
68 LOG(ERROR) << "Invalid hostname_hashes entry";
69 continue;
71 // TODO(treib): Check that |hash| has exactly 40 (2*base::kSHA1Length)
72 // characters from [0-9a-fA-F]. Or just store the raw bytes (from
73 // base::HexStringToBytes).
75 site->hostname_hashes.push_back(hash);
79 if (found)
80 return;
82 // Fall back to using a whitelist based on the URL.
83 std::string url_str;
84 if (!site_dict->GetString(kUrlKey, &url_str)) {
85 LOG(ERROR) << "Whitelist is invalid";
86 return;
89 GURL url(url_str);
90 if (!url.is_valid()) {
91 LOG(ERROR) << "URL " << url_str << " is invalid";
92 return;
95 site->patterns.push_back(url.host());
98 } // namespace
100 SupervisedUserSiteList::Site::Site(const base::string16& name) : name(name) {
103 SupervisedUserSiteList::Site::~Site() {
106 void SupervisedUserSiteList::Load(const base::FilePath& path,
107 const LoadedCallback& callback) {
108 base::PostTaskAndReplyWithResult(
109 content::BrowserThread::GetBlockingPool()
110 ->GetTaskRunnerWithShutdownBehavior(
111 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)
112 .get(),
113 FROM_HERE, base::Bind(&ReadFileOnBlockingThread, path),
114 base::Bind(&SupervisedUserSiteList::OnJsonLoaded, path,
115 base::TimeTicks::Now(), callback));
118 SupervisedUserSiteList::SupervisedUserSiteList(const base::ListValue& sites) {
119 for (const base::Value* site : sites) {
120 const base::DictionaryValue* entry = nullptr;
121 if (!site->GetAsDictionary(&entry)) {
122 LOG(ERROR) << "Entry is invalid";
123 continue;
126 base::string16 name;
127 entry->GetString(kNameKey, &name);
128 sites_.push_back(Site(name));
129 AddWhitelistEntries(entry, &sites_.back());
133 SupervisedUserSiteList::~SupervisedUserSiteList() {
136 // static
137 void SupervisedUserSiteList::OnJsonLoaded(
138 const base::FilePath& path,
139 base::TimeTicks start_time,
140 const SupervisedUserSiteList::LoadedCallback& callback,
141 scoped_ptr<base::Value> value) {
142 if (!value)
143 return;
145 if (!start_time.is_null()) {
146 UMA_HISTOGRAM_TIMES("ManagedUsers.Whitelist.JsonParseDuration",
147 base::TimeTicks::Now() - start_time);
150 base::DictionaryValue* dict = nullptr;
151 if (!value->GetAsDictionary(&dict)) {
152 LOG(ERROR) << "Site list " << path.value() << " is invalid";
153 return;
156 int version = 0;
157 if (!dict->GetInteger(kSitelistFormatVersionKey, &version)) {
158 LOG(ERROR) << "Site list " << path.value() << " has invalid version";
159 return;
162 if (version > kSitelistFormatVersion) {
163 LOG(ERROR) << "Site list " << path.value() << " has a too new format";
164 return;
167 base::ListValue* sites = nullptr;
168 if (!dict->GetList(kSitesKey, &sites)) {
169 LOG(ERROR) << "Site list " << path.value() << " does not contain any sites";
170 return;
173 callback.Run(make_scoped_refptr(new SupervisedUserSiteList(*sites)));