Add ICU message format support
[chromium-blink-merge.git] / chrome / browser / component_updater / supervised_user_whitelist_installer.cc
blob52723c5136a7542cc26bdd002fa4bb1592fd534c
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/location.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/metrics/user_metrics.h"
15 #include "base/metrics/user_metrics_action.h"
16 #include "base/path_service.h"
17 #include "base/prefs/pref_registry_simple.h"
18 #include "base/prefs/pref_service.h"
19 #include "base/prefs/scoped_user_pref_update.h"
20 #include "base/scoped_observer.h"
21 #include "base/sequenced_task_runner.h"
22 #include "base/strings/string_util.h"
23 #include "chrome/browser/profiles/profile_info_cache.h"
24 #include "chrome/browser/profiles/profile_info_cache_observer.h"
25 #include "chrome/common/pref_names.h"
26 #include "components/component_updater/component_updater_paths.h"
27 #include "components/component_updater/component_updater_service.h"
28 #include "components/component_updater/default_component_installer.h"
29 #include "components/crx_file/id_util.h"
31 namespace component_updater {
33 namespace {
35 const char kWhitelist[] = "whitelist";
36 const char kFile[] = "file";
38 const char kClients[] = "clients";
39 const char kName[] = "name";
41 base::FilePath GetWhitelistPath(const base::DictionaryValue& manifest,
42 const base::FilePath& install_dir) {
43 const base::DictionaryValue* whitelist_dict = nullptr;
44 if (!manifest.GetDictionary(kWhitelist, &whitelist_dict))
45 return base::FilePath();
47 base::FilePath::StringType whitelist_file;
48 if (!whitelist_dict->GetString(kFile, &whitelist_file))
49 return base::FilePath();
51 return install_dir.Append(whitelist_file);
54 void RemoveUnregisteredWhitelistsOnTaskRunner(
55 const std::set<std::string>& registered_whitelists) {
56 base::FilePath base_dir;
57 PathService::Get(DIR_SUPERVISED_USER_WHITELISTS, &base_dir);
58 if (base_dir.empty())
59 return;
61 std::vector<base::FilePath> paths;
62 base::FileEnumerator file_enumerator(base_dir, false,
63 base::FileEnumerator::DIRECTORIES);
64 for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
65 path = file_enumerator.Next()) {
66 const std::string crx_id = path.BaseName().MaybeAsASCII();
68 // Ignore folders that don't have valid CRX ID names. These folders are not
69 // managed by the component installer, so do not try to remove them.
70 if (!crx_file::id_util::IdIsValid(crx_id))
71 continue;
73 // Ignore folders that correspond to registered whitelists.
74 if (registered_whitelists.count(crx_id) > 0)
75 continue;
77 base::RecordAction(
78 base::UserMetricsAction("ManagedUsers_Whitelist_UncleanUninstall"));
80 if (!base::DeleteFile(path, true))
81 DLOG(ERROR) << "Couldn't delete " << path.value();
85 class SupervisedUserWhitelistComponentInstallerTraits
86 : public ComponentInstallerTraits {
87 public:
88 SupervisedUserWhitelistComponentInstallerTraits(
89 const std::string& crx_id,
90 const std::string& name,
91 const base::Callback<void(const base::FilePath&)>& callback)
92 : crx_id_(crx_id), name_(name), callback_(callback) {}
93 ~SupervisedUserWhitelistComponentInstallerTraits() override {}
95 private:
96 // ComponentInstallerTraits overrides:
97 bool VerifyInstallation(const base::DictionaryValue& manifest,
98 const base::FilePath& install_dir) const override;
99 bool CanAutoUpdate() const override;
100 bool OnCustomInstall(const base::DictionaryValue& manifest,
101 const base::FilePath& install_dir) override;
102 void ComponentReady(const base::Version& version,
103 const base::FilePath& install_dir,
104 scoped_ptr<base::DictionaryValue> manifest) override;
105 base::FilePath GetBaseDirectory() const override;
106 void GetHash(std::vector<uint8_t>* hash) const override;
107 std::string GetName() const override;
109 std::string crx_id_;
110 std::string name_;
111 base::Callback<void(const base::FilePath&)> callback_;
113 DISALLOW_COPY_AND_ASSIGN(SupervisedUserWhitelistComponentInstallerTraits);
116 bool SupervisedUserWhitelistComponentInstallerTraits::VerifyInstallation(
117 const base::DictionaryValue& manifest,
118 const base::FilePath& install_dir) const {
119 // Check whether the whitelist exists at the path specified by the manifest.
120 // This does not check whether the whitelist is wellformed.
121 return base::PathExists(GetWhitelistPath(manifest, install_dir));
124 bool SupervisedUserWhitelistComponentInstallerTraits::CanAutoUpdate() const {
125 return true;
128 bool SupervisedUserWhitelistComponentInstallerTraits::OnCustomInstall(
129 const base::DictionaryValue& manifest,
130 const base::FilePath& install_dir) {
131 return true;
134 void SupervisedUserWhitelistComponentInstallerTraits::ComponentReady(
135 const base::Version& version,
136 const base::FilePath& install_dir,
137 scoped_ptr<base::DictionaryValue> manifest) {
138 callback_.Run(GetWhitelistPath(*manifest, install_dir));
141 base::FilePath
142 SupervisedUserWhitelistComponentInstallerTraits::GetBaseDirectory() const {
143 base::FilePath whitelist_directory;
144 PathService::Get(DIR_SUPERVISED_USER_WHITELISTS, &whitelist_directory);
145 return whitelist_directory.AppendASCII(crx_id_);
148 void SupervisedUserWhitelistComponentInstallerTraits::GetHash(
149 std::vector<uint8_t>* hash) const {
150 *hash = SupervisedUserWhitelistInstaller::GetHashFromCrxId(crx_id_);
153 std::string SupervisedUserWhitelistComponentInstallerTraits::GetName() const {
154 return name_;
157 class SupervisedUserWhitelistInstallerImpl
158 : public SupervisedUserWhitelistInstaller,
159 public ProfileInfoCacheObserver {
160 public:
161 SupervisedUserWhitelistInstallerImpl(ComponentUpdateService* cus,
162 ProfileInfoCache* profile_info_cache,
163 PrefService* local_state);
164 ~SupervisedUserWhitelistInstallerImpl() override {}
166 private:
167 void RegisterComponent(const std::string& crx_id,
168 const std::string& name,
169 const base::Closure& callback);
170 void RegisterNewComponent(const std::string& crx_id, const std::string& name);
171 bool UnregisterWhitelistInternal(base::DictionaryValue* pref_dict,
172 const std::string& client_id,
173 const std::string& crx_id);
175 void OnWhitelistReady(const std::string& crx_id,
176 const base::FilePath& whitelist_path);
178 // SupervisedUserWhitelistInstaller overrides:
179 void RegisterComponents() override;
180 void Subscribe(const WhitelistReadyCallback& callback) override;
181 void RegisterWhitelist(const std::string& client_id,
182 const std::string& crx_id,
183 const std::string& name) override;
184 void UnregisterWhitelist(const std::string& client_id,
185 const std::string& crx_id) override;
187 // ProfileInfoCacheObserver overrides:
188 void OnProfileWillBeRemoved(const base::FilePath& profile_path) override;
190 ComponentUpdateService* cus_;
191 PrefService* local_state_;
193 std::vector<WhitelistReadyCallback> callbacks_;
195 ScopedObserver<ProfileInfoCache, ProfileInfoCacheObserver> observer_;
197 base::WeakPtrFactory<SupervisedUserWhitelistInstallerImpl> weak_ptr_factory_;
199 DISALLOW_COPY_AND_ASSIGN(SupervisedUserWhitelistInstallerImpl);
202 SupervisedUserWhitelistInstallerImpl::SupervisedUserWhitelistInstallerImpl(
203 ComponentUpdateService* cus,
204 ProfileInfoCache* profile_info_cache,
205 PrefService* local_state)
206 : cus_(cus),
207 local_state_(local_state),
208 observer_(this),
209 weak_ptr_factory_(this) {
210 DCHECK(cus);
211 DCHECK(local_state);
212 // In unit tests, the profile info cache can be null.
213 if (profile_info_cache)
214 observer_.Add(profile_info_cache);
217 void SupervisedUserWhitelistInstallerImpl::RegisterComponent(
218 const std::string& crx_id,
219 const std::string& name,
220 const base::Closure& callback) {
221 scoped_ptr<ComponentInstallerTraits> traits(
222 new SupervisedUserWhitelistComponentInstallerTraits(
223 crx_id, name,
224 base::Bind(&SupervisedUserWhitelistInstallerImpl::OnWhitelistReady,
225 weak_ptr_factory_.GetWeakPtr(), crx_id)));
226 scoped_refptr<DefaultComponentInstaller> installer(
227 new DefaultComponentInstaller(traits.Pass()));
228 installer->Register(cus_, callback);
231 void SupervisedUserWhitelistInstallerImpl::RegisterNewComponent(
232 const std::string& crx_id,
233 const std::string& name) {
234 RegisterComponent(
235 crx_id, name,
236 base::Bind(&SupervisedUserWhitelistInstallerImpl::TriggerComponentUpdate,
237 &cus_->GetOnDemandUpdater(), crx_id));
240 bool SupervisedUserWhitelistInstallerImpl::UnregisterWhitelistInternal(
241 base::DictionaryValue* pref_dict,
242 const std::string& client_id,
243 const std::string& crx_id) {
244 base::DictionaryValue* whitelist_dict = nullptr;
245 bool success =
246 pref_dict->GetDictionaryWithoutPathExpansion(crx_id, &whitelist_dict);
247 DCHECK(success);
248 base::ListValue* clients = nullptr;
249 success = whitelist_dict->GetList(kClients, &clients);
251 const bool removed = clients->Remove(base::StringValue(client_id), nullptr);
253 if (!clients->empty())
254 return removed;
256 pref_dict->RemoveWithoutPathExpansion(crx_id, nullptr);
257 const bool result = cus_->UnregisterComponent(crx_id);
258 DCHECK(result);
260 return removed;
263 void SupervisedUserWhitelistInstallerImpl::OnWhitelistReady(
264 const std::string& crx_id,
265 const base::FilePath& whitelist_path) {
266 for (const auto& callback : callbacks_)
267 callback.Run(crx_id, whitelist_path);
270 void SupervisedUserWhitelistInstallerImpl::RegisterComponents() {
271 std::set<std::string> registered_whitelists;
272 const base::DictionaryValue* whitelists =
273 local_state_->GetDictionary(prefs::kRegisteredSupervisedUserWhitelists);
274 for (base::DictionaryValue::Iterator it(*whitelists); !it.IsAtEnd();
275 it.Advance()) {
276 const base::DictionaryValue* dict = nullptr;
277 it.value().GetAsDictionary(&dict);
278 std::string name;
279 bool result = dict->GetString(kName, &name);
280 DCHECK(result);
281 const std::string& id = it.key();
282 RegisterComponent(id, name, base::Closure());
284 registered_whitelists.insert(id);
287 cus_->GetSequencedTaskRunner()->PostTask(
288 FROM_HERE, base::Bind(&RemoveUnregisteredWhitelistsOnTaskRunner,
289 registered_whitelists));
292 void SupervisedUserWhitelistInstallerImpl::Subscribe(
293 const WhitelistReadyCallback& callback) {
294 return callbacks_.push_back(callback);
297 void SupervisedUserWhitelistInstallerImpl::RegisterWhitelist(
298 const std::string& client_id,
299 const std::string& crx_id,
300 const std::string& name) {
301 DictionaryPrefUpdate update(local_state_,
302 prefs::kRegisteredSupervisedUserWhitelists);
303 base::DictionaryValue* pref_dict = update.Get();
304 base::DictionaryValue* whitelist_dict = nullptr;
305 bool newly_added = false;
306 if (!pref_dict->GetDictionaryWithoutPathExpansion(crx_id, &whitelist_dict)) {
307 whitelist_dict = new base::DictionaryValue;
308 whitelist_dict->SetString(kName, name);
309 pref_dict->SetWithoutPathExpansion(crx_id, whitelist_dict);
310 newly_added = true;
313 base::ListValue* clients = nullptr;
314 if (!whitelist_dict->GetList(kClients, &clients)) {
315 DCHECK(newly_added);
316 clients = new base::ListValue;
317 whitelist_dict->Set(kClients, clients);
319 bool success = clients->AppendIfNotPresent(new base::StringValue(client_id));
320 DCHECK(success);
322 if (!newly_added) {
323 // Sanity-check that the stored name is equal to the name passed in.
324 // In release builds this is a no-op.
325 std::string stored_name;
326 DCHECK(whitelist_dict->GetString(kName, &stored_name));
327 DCHECK_EQ(stored_name, name);
328 return;
331 RegisterNewComponent(crx_id, name);
334 void SupervisedUserWhitelistInstallerImpl::UnregisterWhitelist(
335 const std::string& client_id,
336 const std::string& crx_id) {
337 DictionaryPrefUpdate update(local_state_,
338 prefs::kRegisteredSupervisedUserWhitelists);
339 bool removed = UnregisterWhitelistInternal(update.Get(), client_id, crx_id);
340 DCHECK(removed);
343 void SupervisedUserWhitelistInstallerImpl::OnProfileWillBeRemoved(
344 const base::FilePath& profile_path) {
345 std::string client_id = ClientIdForProfilePath(profile_path);
347 // Go through all registered whitelists and possibly unregister them for this
348 // client.
349 DictionaryPrefUpdate update(local_state_,
350 prefs::kRegisteredSupervisedUserWhitelists);
351 base::DictionaryValue* pref_dict = update.Get();
352 for (base::DictionaryValue::Iterator it(*pref_dict); !it.IsAtEnd();
353 it.Advance()) {
354 UnregisterWhitelistInternal(pref_dict, client_id, it.key());
358 } // namespace
360 // static
361 scoped_ptr<SupervisedUserWhitelistInstaller>
362 SupervisedUserWhitelistInstaller::Create(ComponentUpdateService* cus,
363 ProfileInfoCache* profile_info_cache,
364 PrefService* local_state) {
365 return make_scoped_ptr(new SupervisedUserWhitelistInstallerImpl(
366 cus, profile_info_cache, local_state));
369 // static
370 void SupervisedUserWhitelistInstaller::RegisterPrefs(
371 PrefRegistrySimple* registry) {
372 registry->RegisterDictionaryPref(prefs::kRegisteredSupervisedUserWhitelists);
375 // static
376 std::string SupervisedUserWhitelistInstaller::ClientIdForProfilePath(
377 const base::FilePath& profile_path) {
378 // See ProfileInfoCache::CacheKeyFromProfilePath().
379 return profile_path.BaseName().MaybeAsASCII();
382 // static
383 std::vector<uint8_t> SupervisedUserWhitelistInstaller::GetHashFromCrxId(
384 const std::string& crx_id) {
385 DCHECK(crx_file::id_util::IdIsValid(crx_id));
387 std::vector<uint8_t> hash;
388 uint8_t byte = 0;
389 for (size_t i = 0; i < crx_id.size(); ++i) {
390 // Uppercase characters in IDs are technically legal.
391 int val = base::ToLowerASCII(crx_id[i]) - 'a';
392 DCHECK_GE(val, 0);
393 DCHECK_LT(val, 16);
394 if (i % 2 == 0) {
395 byte = val;
396 } else {
397 hash.push_back(16 * byte + val);
398 byte = 0;
401 return hash;
404 // static
405 void SupervisedUserWhitelistInstaller::TriggerComponentUpdate(
406 OnDemandUpdater* updater,
407 const std::string& crx_id) {
408 const bool result = updater->OnDemandUpdate(crx_id);
409 DCHECK(result);
412 } // namespace component_updater