Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Side by Side Diff: chrome/browser/supervised_user/supervised_user_site_list.cc

Issue 1443033004: Supervised User whitelists: update to json format v2 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: title Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/supervised_user/supervised_user_site_list.h" 5 #include "chrome/browser/supervised_user/supervised_user_site_list.h"
6 6
7 #include "base/files/file_util.h" 7 #include "base/files/file_util.h"
8 #include "base/json/json_file_value_serializer.h" 8 #include "base/json/json_file_value_serializer.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/metrics/histogram_macros.h" 10 #include "base/metrics/histogram_macros.h"
11 #include "base/sha1.h"
11 #include "base/task_runner_util.h" 12 #include "base/task_runner_util.h"
12 #include "base/values.h" 13 #include "base/values.h"
13 #include "content/public/browser/browser_thread.h" 14 #include "content/public/browser/browser_thread.h"
14 #include "url/gurl.h" 15 #include "url/gurl.h"
15 16
16 const int kSitelistFormatVersion = 1; 17 const int kSitelistFormatVersion = 2;
17 18
19 const char kEntryPointUrlKey[] = "entry_point_url";
18 const char kHostnameHashesKey[] = "hostname_hashes"; 20 const char kHostnameHashesKey[] = "hostname_hashes";
19 const char kNameKey[] = "name";
20 const char kSitesKey[] = "sites";
21 const char kSitelistFormatVersionKey[] = "version"; 21 const char kSitelistFormatVersionKey[] = "version";
22 const char kUrlKey[] = "url";
23 const char kWhitelistKey[] = "whitelist"; 22 const char kWhitelistKey[] = "whitelist";
24 23
25 namespace { 24 namespace {
26 25
27 scoped_ptr<base::Value> ReadFileOnBlockingThread(const base::FilePath& path) { 26 scoped_ptr<base::Value> ReadFileOnBlockingThread(const base::FilePath& path) {
28 SCOPED_UMA_HISTOGRAM_TIMER("ManagedUsers.Whitelist.ReadDuration"); 27 SCOPED_UMA_HISTOGRAM_TIMER("ManagedUsers.Whitelist.ReadDuration");
29 JSONFileValueDeserializer deserializer(path); 28 JSONFileValueDeserializer deserializer(path);
30 int error_code; 29 int error_code;
31 std::string error_msg; 30 std::string error_msg;
32 scoped_ptr<base::Value> value = 31 scoped_ptr<base::Value> value =
33 deserializer.Deserialize(&error_code, &error_msg); 32 deserializer.Deserialize(&error_code, &error_msg);
34 if (!value) { 33 if (!value) {
35 LOG(ERROR) << "Couldn't load site list " << path.value() << ": " 34 LOG(ERROR) << "Couldn't load site list " << path.value() << ": "
36 << error_msg; 35 << error_msg;
37 } 36 }
38 return value.Pass(); 37 return value.Pass();
39 } 38 }
40 39
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;
47
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;
56 }
57
58 site->patterns.push_back(pattern);
59 }
60 }
61
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;
70 }
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).
74
75 site->hostname_hashes.push_back(hash);
76 }
77 }
78
79 if (found)
80 return;
81
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;
87 }
88
89 GURL url(url_str);
90 if (!url.is_valid()) {
91 LOG(ERROR) << "URL " << url_str << " is invalid";
92 return;
93 }
94
95 site->patterns.push_back(url.host());
96 }
97
98 } // namespace 40 } // namespace
99 41
100 SupervisedUserSiteList::Site::Site(const base::string16& name) : name(name) { 42 void SupervisedUserSiteList::Load(const base::string16& title,
101 } 43 const base::FilePath& path,
102
103 SupervisedUserSiteList::Site::~Site() {
104 }
105
106 void SupervisedUserSiteList::Load(const base::FilePath& path,
107 const LoadedCallback& callback) { 44 const LoadedCallback& callback) {
108 base::PostTaskAndReplyWithResult( 45 base::PostTaskAndReplyWithResult(
109 content::BrowserThread::GetBlockingPool() 46 content::BrowserThread::GetBlockingPool()
110 ->GetTaskRunnerWithShutdownBehavior( 47 ->GetTaskRunnerWithShutdownBehavior(
111 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN) 48 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)
112 .get(), 49 .get(),
113 FROM_HERE, base::Bind(&ReadFileOnBlockingThread, path), 50 FROM_HERE, base::Bind(&ReadFileOnBlockingThread, path),
114 base::Bind(&SupervisedUserSiteList::OnJsonLoaded, path, 51 base::Bind(&SupervisedUserSiteList::OnJsonLoaded, title, path,
115 base::TimeTicks::Now(), callback)); 52 base::TimeTicks::Now(), callback));
116 } 53 }
117 54
118 SupervisedUserSiteList::SupervisedUserSiteList(const base::ListValue& sites) { 55 SupervisedUserSiteList::SupervisedUserSiteList(
119 for (const base::Value* site : sites) { 56 const base::string16& title,
120 const base::DictionaryValue* entry = nullptr; 57 GURL entry_point,
121 if (!site->GetAsDictionary(&entry)) { 58 const base::ListValue* patterns,
122 LOG(ERROR) << "Entry is invalid"; 59 const base::ListValue* hostname_hashes)
123 continue; 60 : title_(title), entry_point_(entry_point) {
61 if (patterns) {
62 for (const base::Value* entry : *patterns) {
63 std::string pattern;
64 if (!entry->GetAsString(&pattern)) {
65 LOG(ERROR) << "Invalid whitelist entry";
66 continue;
67 }
68
69 patterns_.push_back(pattern);
124 } 70 }
71 }
125 72
126 base::string16 name; 73 if (hostname_hashes) {
127 entry->GetString(kNameKey, &name); 74 for (const base::Value* entry : *hostname_hashes) {
128 sites_.push_back(Site(name)); 75 // |hash| should be a hex-encoded SHA1 hash.
129 AddWhitelistEntries(entry, &sites_.back()); 76 std::string hash;
77 if (!entry->GetAsString(&hash) || hash.size() != 2 * base::kSHA1Length) {
78 LOG(ERROR) << "Invalid hostname_hashes entry";
79 continue;
80 }
81 // TODO(treib): Check that |hash| has only characters from [0-9a-fA-F].
82 // Or just store the raw bytes (from base::HexStringToBytes).
Bernhard Bauer 2015/11/18 12:10:40 Would now be a good time to do this? 😃
Marc Treib 2015/11/18 12:44:18 Hm. How about a follow-up CL, since it's really un
83 hostname_hashes_.push_back(hash);
84 }
130 } 85 }
86
87 if (patterns_.empty() && hostname_hashes_.empty())
88 LOG(WARNING) << "Site list is empty!";
131 } 89 }
132 90
133 SupervisedUserSiteList::~SupervisedUserSiteList() { 91 SupervisedUserSiteList::~SupervisedUserSiteList() {
134 } 92 }
135 93
136 // static 94 // static
137 void SupervisedUserSiteList::OnJsonLoaded( 95 void SupervisedUserSiteList::OnJsonLoaded(
96 const base::string16& title,
138 const base::FilePath& path, 97 const base::FilePath& path,
139 base::TimeTicks start_time, 98 base::TimeTicks start_time,
140 const SupervisedUserSiteList::LoadedCallback& callback, 99 const SupervisedUserSiteList::LoadedCallback& callback,
141 scoped_ptr<base::Value> value) { 100 scoped_ptr<base::Value> value) {
142 if (!value) 101 if (!value)
143 return; 102 return;
144 103
145 if (!start_time.is_null()) { 104 if (!start_time.is_null()) {
146 UMA_HISTOGRAM_TIMES("ManagedUsers.Whitelist.JsonParseDuration", 105 UMA_HISTOGRAM_TIMES("ManagedUsers.Whitelist.JsonParseDuration",
147 base::TimeTicks::Now() - start_time); 106 base::TimeTicks::Now() - start_time);
148 } 107 }
149 108
150 base::DictionaryValue* dict = nullptr; 109 base::DictionaryValue* dict = nullptr;
151 if (!value->GetAsDictionary(&dict)) { 110 if (!value->GetAsDictionary(&dict)) {
152 LOG(ERROR) << "Site list " << path.value() << " is invalid"; 111 LOG(ERROR) << "Site list " << path.value() << " is invalid";
153 return; 112 return;
154 } 113 }
155 114
156 int version = 0; 115 int version = 0;
157 if (!dict->GetInteger(kSitelistFormatVersionKey, &version)) { 116 if (!dict->GetInteger(kSitelistFormatVersionKey, &version)) {
158 LOG(ERROR) << "Site list " << path.value() << " has invalid version"; 117 LOG(ERROR) << "Site list " << path.value() << " has invalid version";
159 return; 118 return;
160 } 119 }
161 120 if (version != kSitelistFormatVersion) {
162 if (version > kSitelistFormatVersion) { 121 LOG(ERROR) << "Site list " << path.value() << " has wrong version "
163 LOG(ERROR) << "Site list " << path.value() << " has a too new format"; 122 << version << ", expected " << kSitelistFormatVersion;
164 return; 123 return;
165 } 124 }
166 125
167 base::ListValue* sites = nullptr; 126 std::string entry_point_url;
168 if (!dict->GetList(kSitesKey, &sites)) { 127 dict->GetString(kEntryPointUrlKey, &entry_point_url);
169 LOG(ERROR) << "Site list " << path.value() << " does not contain any sites";
170 return;
171 }
172 128
173 callback.Run(make_scoped_refptr(new SupervisedUserSiteList(*sites))); 129 base::ListValue* patterns = nullptr;
130 dict->GetList(kWhitelistKey, &patterns);
131
132 base::ListValue* hostname_hashes = nullptr;
133 dict->GetList(kHostnameHashesKey, &hostname_hashes);
134
135 callback.Run(make_scoped_refptr(new SupervisedUserSiteList(
136 title, GURL(entry_point_url), patterns, hostname_hashes)));
174 } 137 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698