Popular sites on the NTP: re-download popular suggestions once per Chrome run
[chromium-blink-merge.git] / chrome / browser / component_updater / supervised_user_whitelist_installer.cc
blobcc8d4c10dda363b5df4baf78e34931630adbaea7
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/component_updater/supervised_user_whitelist_installer.h"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/files/file_enumerator.h"
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
12 #include "base/files/important_file_writer.h"
13 #include "base/location.h"
14 #include "base/memory/weak_ptr.h"
15 #include "base/metrics/user_metrics.h"
16 #include "base/metrics/user_metrics_action.h"
17 #include "base/path_service.h"
18 #include "base/prefs/pref_registry_simple.h"
19 #include "base/prefs/pref_service.h"
20 #include "base/prefs/scoped_user_pref_update.h"
21 #include "base/scoped_observer.h"
22 #include "base/sequenced_task_runner.h"
23 #include "base/strings/string_util.h"
24 #include "base/thread_task_runner_handle.h"
25 #include "chrome/browser/profiles/profile_info_cache.h"
26 #include "chrome/browser/profiles/profile_info_cache_observer.h"
27 #include "chrome/common/chrome_paths.h"
28 #include "chrome/common/pref_names.h"
29 #include "components/component_updater/component_updater_paths.h"
30 #include "components/component_updater/component_updater_service.h"
31 #include "components/component_updater/default_component_installer.h"
32 #include "components/crx_file/id_util.h"
33 #include "components/safe_json/json_sanitizer.h"
35 namespace component_updater {
37 namespace {
39 const char kSanitizedWhitelistExtension[] = ".json";
41 const char kWhitelist[] = "whitelist";
42 const char kFile[] = "file";
44 const char kClients[] = "clients";
45 const char kName[] = "name";
47 base::FilePath GetRawWhitelistPath(const base::DictionaryValue& manifest,
48 const base::FilePath& install_dir) {
49 const base::DictionaryValue* whitelist_dict = nullptr;
50 if (!manifest.GetDictionary(kWhitelist, &whitelist_dict))
51 return base::FilePath();
53 base::FilePath::StringType whitelist_file;
54 if (!whitelist_dict->GetString(kFile, &whitelist_file))
55 return base::FilePath();
57 return install_dir.Append(whitelist_file);
60 base::FilePath GetSanitizedWhitelistPath(const std::string& crx_id) {
61 base::FilePath base_dir;
62 PathService::Get(chrome::DIR_SUPERVISED_USER_INSTALLED_WHITELISTS, &base_dir);
63 return base_dir.empty()
64 ? base::FilePath()
65 : base_dir.AppendASCII(crx_id + kSanitizedWhitelistExtension);
68 void OnWhitelistSanitizationError(const base::FilePath& whitelist,
69 const std::string& error) {
70 LOG(WARNING) << "Invalid whitelist " << whitelist.value() << ": " << error;
73 void OnWhitelistSanitizationResult(
74 const std::string& crx_id,
75 const scoped_refptr<base::SequencedTaskRunner>& task_runner,
76 const base::Closure& callback,
77 const std::string& result) {
78 const base::FilePath sanitized_whitelist_path =
79 GetSanitizedWhitelistPath(crx_id);
80 const base::FilePath install_directory = sanitized_whitelist_path.DirName();
81 if (!base::DirectoryExists(install_directory)) {
82 if (!base::CreateDirectory(install_directory)) {
83 PLOG(ERROR) << "Could't create directory " << install_directory.value();
84 return;
88 const int size = result.size();
89 if (base::WriteFile(sanitized_whitelist_path, result.data(), size) != size) {
90 PLOG(ERROR) << "Couldn't write file " << sanitized_whitelist_path.value();
91 return;
93 task_runner->PostTask(FROM_HERE, callback);
96 void CheckForSanitizedWhitelistOnTaskRunner(
97 const std::string& crx_id,
98 const base::FilePath& whitelist_path,
99 const scoped_refptr<base::SequencedTaskRunner>& task_runner,
100 const base::Closure& callback) {
101 if (base::PathExists(GetSanitizedWhitelistPath(crx_id))) {
102 task_runner->PostTask(FROM_HERE, callback);
103 return;
106 std::string unsafe_json;
107 if (!base::ReadFileToString(whitelist_path, &unsafe_json)) {
108 PLOG(ERROR) << "Couldn't read file " << whitelist_path.value();
109 return;
112 safe_json::JsonSanitizer::Sanitize(
113 unsafe_json,
114 base::Bind(&OnWhitelistSanitizationResult, crx_id, task_runner, callback),
115 base::Bind(&OnWhitelistSanitizationError, whitelist_path));
118 void RemoveUnregisteredWhitelistsOnTaskRunner(
119 const std::set<std::string>& registered_whitelists) {
120 base::FilePath base_dir;
121 PathService::Get(DIR_SUPERVISED_USER_WHITELISTS, &base_dir);
122 if (!base_dir.empty()) {
123 base::FileEnumerator file_enumerator(base_dir, false,
124 base::FileEnumerator::DIRECTORIES);
125 for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
126 path = file_enumerator.Next()) {
127 const std::string crx_id = path.BaseName().MaybeAsASCII();
129 // Ignore folders that don't have valid CRX ID names. These folders are
130 // not managed by the component installer, so do not try to remove them.
131 if (!crx_file::id_util::IdIsValid(crx_id))
132 continue;
134 // Ignore folders that correspond to registered whitelists.
135 if (registered_whitelists.count(crx_id) > 0)
136 continue;
138 base::RecordAction(
139 base::UserMetricsAction("ManagedUsers_Whitelist_UncleanUninstall"));
141 if (!base::DeleteFile(path, true))
142 DPLOG(ERROR) << "Couldn't delete " << path.value();
146 PathService::Get(chrome::DIR_SUPERVISED_USER_INSTALLED_WHITELISTS, &base_dir);
147 if (!base_dir.empty()) {
148 base::FilePath pattern(FILE_PATH_LITERAL("*"));
149 pattern = pattern.AppendASCII(kSanitizedWhitelistExtension);
150 base::FileEnumerator file_enumerator(
151 base_dir, false, base::FileEnumerator::FILES, pattern.value());
152 for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
153 path = file_enumerator.Next()) {
154 // Ignore files that don't have valid CRX ID names. These files are not
155 // managed by the component installer, so do not try to remove them.
156 const std::string filename = path.BaseName().MaybeAsASCII();
157 DCHECK(base::EndsWith(filename, kSanitizedWhitelistExtension,
158 base::CompareCase::SENSITIVE));
160 const std::string crx_id = filename.substr(
161 filename.size() - strlen(kSanitizedWhitelistExtension));
163 if (!crx_file::id_util::IdIsValid(crx_id))
164 continue;
166 // Ignore files that correspond to registered whitelists.
167 if (registered_whitelists.count(crx_id) > 0)
168 continue;
170 base::RecordAction(
171 base::UserMetricsAction("ManagedUsers_Whitelist_UncleanUninstall"));
173 if (!base::DeleteFile(path, true))
174 DPLOG(ERROR) << "Couldn't delete " << path.value();
179 class SupervisedUserWhitelistComponentInstallerTraits
180 : public ComponentInstallerTraits {
181 public:
182 SupervisedUserWhitelistComponentInstallerTraits(
183 const std::string& crx_id,
184 const std::string& name,
185 const base::Callback<void(const base::FilePath&)>& callback)
186 : crx_id_(crx_id), name_(name), callback_(callback) {}
187 ~SupervisedUserWhitelistComponentInstallerTraits() override {}
189 private:
190 // ComponentInstallerTraits overrides:
191 bool VerifyInstallation(const base::DictionaryValue& manifest,
192 const base::FilePath& install_dir) const override;
193 bool CanAutoUpdate() const override;
194 bool OnCustomInstall(const base::DictionaryValue& manifest,
195 const base::FilePath& install_dir) override;
196 void ComponentReady(const base::Version& version,
197 const base::FilePath& install_dir,
198 scoped_ptr<base::DictionaryValue> manifest) override;
199 base::FilePath GetBaseDirectory() const override;
200 void GetHash(std::vector<uint8_t>* hash) const override;
201 std::string GetName() const override;
203 std::string crx_id_;
204 std::string name_;
205 base::Callback<void(const base::FilePath&)> callback_;
207 DISALLOW_COPY_AND_ASSIGN(SupervisedUserWhitelistComponentInstallerTraits);
210 bool SupervisedUserWhitelistComponentInstallerTraits::VerifyInstallation(
211 const base::DictionaryValue& manifest,
212 const base::FilePath& install_dir) const {
213 // Check whether the whitelist exists at the path specified by the manifest.
214 // This does not check whether the whitelist is wellformed.
215 return base::PathExists(GetRawWhitelistPath(manifest, install_dir));
218 bool SupervisedUserWhitelistComponentInstallerTraits::CanAutoUpdate() const {
219 return true;
222 bool SupervisedUserWhitelistComponentInstallerTraits::OnCustomInstall(
223 const base::DictionaryValue& manifest,
224 const base::FilePath& install_dir) {
225 // Delete the existing sanitized whitelist.
226 return base::DeleteFile(GetSanitizedWhitelistPath(crx_id_), false);
229 void SupervisedUserWhitelistComponentInstallerTraits::ComponentReady(
230 const base::Version& version,
231 const base::FilePath& install_dir,
232 scoped_ptr<base::DictionaryValue> manifest) {
233 callback_.Run(GetRawWhitelistPath(*manifest, install_dir));
236 base::FilePath
237 SupervisedUserWhitelistComponentInstallerTraits::GetBaseDirectory() const {
238 base::FilePath whitelist_directory;
239 PathService::Get(DIR_SUPERVISED_USER_WHITELISTS, &whitelist_directory);
240 return whitelist_directory.AppendASCII(crx_id_);
243 void SupervisedUserWhitelistComponentInstallerTraits::GetHash(
244 std::vector<uint8_t>* hash) const {
245 *hash = SupervisedUserWhitelistInstaller::GetHashFromCrxId(crx_id_);
248 std::string SupervisedUserWhitelistComponentInstallerTraits::GetName() const {
249 return name_;
252 class SupervisedUserWhitelistInstallerImpl
253 : public SupervisedUserWhitelistInstaller,
254 public ProfileInfoCacheObserver {
255 public:
256 SupervisedUserWhitelistInstallerImpl(ComponentUpdateService* cus,
257 ProfileInfoCache* profile_info_cache,
258 PrefService* local_state);
259 ~SupervisedUserWhitelistInstallerImpl() override {}
261 private:
262 void RegisterComponent(const std::string& crx_id,
263 const std::string& name,
264 const base::Closure& callback);
265 void RegisterNewComponent(const std::string& crx_id, const std::string& name);
266 bool UnregisterWhitelistInternal(base::DictionaryValue* pref_dict,
267 const std::string& client_id,
268 const std::string& crx_id);
270 void OnRawWhitelistReady(const std::string& crx_id,
271 const base::FilePath& whitelist_path);
272 void OnSanitizedWhitelistReady(const std::string& crx_id);
274 // SupervisedUserWhitelistInstaller overrides:
275 void RegisterComponents() override;
276 void Subscribe(const WhitelistReadyCallback& callback) override;
277 void RegisterWhitelist(const std::string& client_id,
278 const std::string& crx_id,
279 const std::string& name) override;
280 void UnregisterWhitelist(const std::string& client_id,
281 const std::string& crx_id) override;
283 // ProfileInfoCacheObserver overrides:
284 void OnProfileWillBeRemoved(const base::FilePath& profile_path) override;
286 ComponentUpdateService* cus_;
287 PrefService* local_state_;
289 std::vector<WhitelistReadyCallback> callbacks_;
291 ScopedObserver<ProfileInfoCache, ProfileInfoCacheObserver> observer_;
293 base::WeakPtrFactory<SupervisedUserWhitelistInstallerImpl> weak_ptr_factory_;
295 DISALLOW_COPY_AND_ASSIGN(SupervisedUserWhitelistInstallerImpl);
298 SupervisedUserWhitelistInstallerImpl::SupervisedUserWhitelistInstallerImpl(
299 ComponentUpdateService* cus,
300 ProfileInfoCache* profile_info_cache,
301 PrefService* local_state)
302 : cus_(cus),
303 local_state_(local_state),
304 observer_(this),
305 weak_ptr_factory_(this) {
306 DCHECK(cus);
307 DCHECK(local_state);
308 // In unit tests, the profile info cache can be null.
309 if (profile_info_cache)
310 observer_.Add(profile_info_cache);
313 void SupervisedUserWhitelistInstallerImpl::RegisterComponent(
314 const std::string& crx_id,
315 const std::string& name,
316 const base::Closure& callback) {
317 scoped_ptr<ComponentInstallerTraits> traits(
318 new SupervisedUserWhitelistComponentInstallerTraits(
319 crx_id, name,
320 base::Bind(&SupervisedUserWhitelistInstallerImpl::OnRawWhitelistReady,
321 weak_ptr_factory_.GetWeakPtr(), crx_id)));
322 scoped_refptr<DefaultComponentInstaller> installer(
323 new DefaultComponentInstaller(traits.Pass()));
324 installer->Register(cus_, callback);
327 void SupervisedUserWhitelistInstallerImpl::RegisterNewComponent(
328 const std::string& crx_id,
329 const std::string& name) {
330 RegisterComponent(
331 crx_id, name,
332 base::Bind(&SupervisedUserWhitelistInstaller::TriggerComponentUpdate,
333 &cus_->GetOnDemandUpdater(), crx_id));
336 bool SupervisedUserWhitelistInstallerImpl::UnregisterWhitelistInternal(
337 base::DictionaryValue* pref_dict,
338 const std::string& client_id,
339 const std::string& crx_id) {
340 base::DictionaryValue* whitelist_dict = nullptr;
341 bool success =
342 pref_dict->GetDictionaryWithoutPathExpansion(crx_id, &whitelist_dict);
343 DCHECK(success);
344 base::ListValue* clients = nullptr;
345 success = whitelist_dict->GetList(kClients, &clients);
347 const bool removed = clients->Remove(base::StringValue(client_id), nullptr);
349 if (!clients->empty())
350 return removed;
352 pref_dict->RemoveWithoutPathExpansion(crx_id, nullptr);
353 bool result = cus_->UnregisterComponent(crx_id);
354 DCHECK(result);
356 result = base::DeleteFile(GetSanitizedWhitelistPath(crx_id), false);
357 DCHECK(result);
359 return removed;
362 void SupervisedUserWhitelistInstallerImpl::OnRawWhitelistReady(
363 const std::string& crx_id,
364 const base::FilePath& whitelist_path) {
365 cus_->GetSequencedTaskRunner()->PostTask(
366 FROM_HERE,
367 base::Bind(
368 &CheckForSanitizedWhitelistOnTaskRunner, crx_id, whitelist_path,
369 base::ThreadTaskRunnerHandle::Get(),
370 base::Bind(
371 &SupervisedUserWhitelistInstallerImpl::OnSanitizedWhitelistReady,
372 weak_ptr_factory_.GetWeakPtr(), crx_id)));
375 void SupervisedUserWhitelistInstallerImpl::OnSanitizedWhitelistReady(
376 const std::string& crx_id) {
377 for (const WhitelistReadyCallback& callback : callbacks_)
378 callback.Run(crx_id, GetSanitizedWhitelistPath(crx_id));
381 void SupervisedUserWhitelistInstallerImpl::RegisterComponents() {
382 std::set<std::string> registered_whitelists;
383 const base::DictionaryValue* whitelists =
384 local_state_->GetDictionary(prefs::kRegisteredSupervisedUserWhitelists);
385 for (base::DictionaryValue::Iterator it(*whitelists); !it.IsAtEnd();
386 it.Advance()) {
387 const base::DictionaryValue* dict = nullptr;
388 it.value().GetAsDictionary(&dict);
389 std::string name;
390 bool result = dict->GetString(kName, &name);
391 DCHECK(result);
392 const std::string& id = it.key();
393 RegisterComponent(id, name, base::Closure());
395 registered_whitelists.insert(id);
398 cus_->GetSequencedTaskRunner()->PostTask(
399 FROM_HERE, base::Bind(&RemoveUnregisteredWhitelistsOnTaskRunner,
400 registered_whitelists));
403 void SupervisedUserWhitelistInstallerImpl::Subscribe(
404 const WhitelistReadyCallback& callback) {
405 return callbacks_.push_back(callback);
408 void SupervisedUserWhitelistInstallerImpl::RegisterWhitelist(
409 const std::string& client_id,
410 const std::string& crx_id,
411 const std::string& name) {
412 DictionaryPrefUpdate update(local_state_,
413 prefs::kRegisteredSupervisedUserWhitelists);
414 base::DictionaryValue* pref_dict = update.Get();
415 base::DictionaryValue* whitelist_dict = nullptr;
416 bool newly_added = false;
417 if (!pref_dict->GetDictionaryWithoutPathExpansion(crx_id, &whitelist_dict)) {
418 whitelist_dict = new base::DictionaryValue;
419 whitelist_dict->SetString(kName, name);
420 pref_dict->SetWithoutPathExpansion(crx_id, whitelist_dict);
421 newly_added = true;
424 base::ListValue* clients = nullptr;
425 if (!whitelist_dict->GetList(kClients, &clients)) {
426 DCHECK(newly_added);
427 clients = new base::ListValue;
428 whitelist_dict->Set(kClients, clients);
430 bool success = clients->AppendIfNotPresent(new base::StringValue(client_id));
431 DCHECK(success);
433 if (!newly_added) {
434 // Sanity-check that the stored name is equal to the name passed in.
435 // In release builds this is a no-op.
436 std::string stored_name;
437 DCHECK(whitelist_dict->GetString(kName, &stored_name));
438 DCHECK_EQ(stored_name, name);
439 return;
442 RegisterNewComponent(crx_id, name);
445 void SupervisedUserWhitelistInstallerImpl::UnregisterWhitelist(
446 const std::string& client_id,
447 const std::string& crx_id) {
448 DictionaryPrefUpdate update(local_state_,
449 prefs::kRegisteredSupervisedUserWhitelists);
450 bool removed = UnregisterWhitelistInternal(update.Get(), client_id, crx_id);
451 DCHECK(removed);
454 void SupervisedUserWhitelistInstallerImpl::OnProfileWillBeRemoved(
455 const base::FilePath& profile_path) {
456 std::string client_id = ClientIdForProfilePath(profile_path);
458 // Go through all registered whitelists and possibly unregister them for this
459 // client.
460 DictionaryPrefUpdate update(local_state_,
461 prefs::kRegisteredSupervisedUserWhitelists);
462 base::DictionaryValue* pref_dict = update.Get();
463 for (base::DictionaryValue::Iterator it(*pref_dict); !it.IsAtEnd();
464 it.Advance()) {
465 UnregisterWhitelistInternal(pref_dict, client_id, it.key());
469 } // namespace
471 // static
472 scoped_ptr<SupervisedUserWhitelistInstaller>
473 SupervisedUserWhitelistInstaller::Create(ComponentUpdateService* cus,
474 ProfileInfoCache* profile_info_cache,
475 PrefService* local_state) {
476 return make_scoped_ptr(new SupervisedUserWhitelistInstallerImpl(
477 cus, profile_info_cache, local_state));
480 // static
481 void SupervisedUserWhitelistInstaller::RegisterPrefs(
482 PrefRegistrySimple* registry) {
483 registry->RegisterDictionaryPref(prefs::kRegisteredSupervisedUserWhitelists);
486 // static
487 std::string SupervisedUserWhitelistInstaller::ClientIdForProfilePath(
488 const base::FilePath& profile_path) {
489 // See ProfileInfoCache::CacheKeyFromProfilePath().
490 return profile_path.BaseName().MaybeAsASCII();
493 // static
494 std::vector<uint8_t> SupervisedUserWhitelistInstaller::GetHashFromCrxId(
495 const std::string& crx_id) {
496 DCHECK(crx_file::id_util::IdIsValid(crx_id));
498 std::vector<uint8_t> hash;
499 uint8_t byte = 0;
500 for (size_t i = 0; i < crx_id.size(); ++i) {
501 // Uppercase characters in IDs are technically legal.
502 int val = base::ToLowerASCII(crx_id[i]) - 'a';
503 DCHECK_GE(val, 0);
504 DCHECK_LT(val, 16);
505 if (i % 2 == 0) {
506 byte = val;
507 } else {
508 hash.push_back(16 * byte + val);
509 byte = 0;
512 return hash;
515 // static
516 void SupervisedUserWhitelistInstaller::TriggerComponentUpdate(
517 OnDemandUpdater* updater,
518 const std::string& crx_id) {
519 const bool result = updater->OnDemandUpdate(crx_id);
520 DCHECK(result);
523 } // namespace component_updater