Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / chrome / browser / component_updater / supervised_user_whitelist_installer.cc
blobc41c144ddeb8d7bef102b7818c1ea25de654621d
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/command_line.h"
10 #include "base/files/file_enumerator.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.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_split.h"
24 #include "base/strings/string_util.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_switches.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"
34 namespace component_updater {
36 namespace {
38 // See the corresponding entries in extensions::manifest_keys.
39 const char kContentPack[] = "content_pack";
40 const char kContentPackSites[] = "sites";
42 const char kClients[] = "clients";
43 const char kName[] = "name";
45 base::FilePath GetWhitelistPath(const base::DictionaryValue& manifest,
46 const base::FilePath& install_dir) {
47 const base::DictionaryValue* content_pack_dict = nullptr;
48 if (!manifest.GetDictionary(kContentPack, &content_pack_dict))
49 return base::FilePath();
51 base::FilePath::StringType whitelist_file;
52 if (!content_pack_dict->GetString(kContentPackSites, &whitelist_file))
53 return base::FilePath();
55 return install_dir.Append(whitelist_file);
58 void RemoveUnregisteredWhitelistsOnTaskRunner(
59 const std::set<std::string>& registered_whitelists) {
60 base::FilePath base_dir;
61 PathService::Get(DIR_SUPERVISED_USER_WHITELISTS, &base_dir);
62 if (base_dir.empty())
63 return;
65 std::vector<base::FilePath> paths;
66 base::FileEnumerator file_enumerator(base_dir, false,
67 base::FileEnumerator::DIRECTORIES);
68 for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
69 path = file_enumerator.Next()) {
70 const std::string crx_id = path.BaseName().MaybeAsASCII();
72 // Ignore folders that don't have valid CRX ID names. These folders are not
73 // managed by the component installer, so do not try to remove them.
74 if (!crx_file::id_util::IdIsValid(crx_id))
75 continue;
77 // Ignore folders that correspond to registered whitelists.
78 if (registered_whitelists.count(crx_id) > 0)
79 continue;
81 base::RecordAction(
82 base::UserMetricsAction("ManagedUsers_Whitelist_UncleanUninstall"));
84 if (!base::DeleteFile(path, true))
85 DLOG(ERROR) << "Couldn't delete " << path.value();
89 class SupervisedUserWhitelistComponentInstallerTraits
90 : public ComponentInstallerTraits {
91 public:
92 SupervisedUserWhitelistComponentInstallerTraits(
93 const std::string& crx_id,
94 const std::string& name,
95 const base::Callback<void(const base::FilePath&)>& callback)
96 : crx_id_(crx_id), name_(name), callback_(callback) {}
97 ~SupervisedUserWhitelistComponentInstallerTraits() override {}
99 private:
100 // ComponentInstallerTraits overrides:
101 bool VerifyInstallation(const base::DictionaryValue& manifest,
102 const base::FilePath& install_dir) const override;
103 bool CanAutoUpdate() const override;
104 bool OnCustomInstall(const base::DictionaryValue& manifest,
105 const base::FilePath& install_dir) override;
106 void ComponentReady(const base::Version& version,
107 const base::FilePath& install_dir,
108 scoped_ptr<base::DictionaryValue> manifest) override;
109 base::FilePath GetBaseDirectory() const override;
110 void GetHash(std::vector<uint8_t>* hash) const override;
111 std::string GetName() const override;
113 std::string crx_id_;
114 std::string name_;
115 base::Callback<void(const base::FilePath&)> callback_;
117 DISALLOW_COPY_AND_ASSIGN(SupervisedUserWhitelistComponentInstallerTraits);
120 bool SupervisedUserWhitelistComponentInstallerTraits::VerifyInstallation(
121 const base::DictionaryValue& manifest,
122 const base::FilePath& install_dir) const {
123 // Check whether the whitelist exists at the path specified by the manifest.
124 // This does not check whether the whitelist is wellformed.
125 return base::PathExists(GetWhitelistPath(manifest, install_dir));
128 bool SupervisedUserWhitelistComponentInstallerTraits::CanAutoUpdate() const {
129 return true;
132 bool SupervisedUserWhitelistComponentInstallerTraits::OnCustomInstall(
133 const base::DictionaryValue& manifest,
134 const base::FilePath& install_dir) {
135 return true;
138 void SupervisedUserWhitelistComponentInstallerTraits::ComponentReady(
139 const base::Version& version,
140 const base::FilePath& install_dir,
141 scoped_ptr<base::DictionaryValue> manifest) {
142 callback_.Run(GetWhitelistPath(*manifest, install_dir));
145 base::FilePath
146 SupervisedUserWhitelistComponentInstallerTraits::GetBaseDirectory() const {
147 base::FilePath whitelist_directory;
148 PathService::Get(DIR_SUPERVISED_USER_WHITELISTS, &whitelist_directory);
149 return whitelist_directory.AppendASCII(crx_id_);
152 void SupervisedUserWhitelistComponentInstallerTraits::GetHash(
153 std::vector<uint8_t>* hash) const {
154 *hash = SupervisedUserWhitelistInstaller::GetHashFromCrxId(crx_id_);
157 std::string SupervisedUserWhitelistComponentInstallerTraits::GetName() const {
158 return name_;
161 class SupervisedUserWhitelistInstallerImpl
162 : public SupervisedUserWhitelistInstaller,
163 public ProfileInfoCacheObserver {
164 public:
165 SupervisedUserWhitelistInstallerImpl(ComponentUpdateService* cus,
166 ProfileInfoCache* profile_info_cache,
167 PrefService* local_state);
168 ~SupervisedUserWhitelistInstallerImpl() override {}
170 private:
171 void RegisterComponent(const std::string& crx_id,
172 const std::string& name,
173 const base::Closure& callback);
174 void RegisterNewComponent(const std::string& crx_id, const std::string& name);
175 bool UnregisterWhitelistInternal(base::DictionaryValue* pref_dict,
176 const std::string& client_id,
177 const std::string& crx_id);
179 void OnWhitelistReady(const std::string& crx_id,
180 const base::FilePath& whitelist_path);
182 // SupervisedUserWhitelistInstaller overrides:
183 void RegisterComponents() override;
184 void Subscribe(const WhitelistReadyCallback& callback) override;
185 void RegisterWhitelist(const std::string& client_id,
186 const std::string& crx_id,
187 const std::string& name) override;
188 void UnregisterWhitelist(const std::string& client_id,
189 const std::string& crx_id) override;
191 // ProfileInfoCacheObserver overrides:
192 void OnProfileWillBeRemoved(const base::FilePath& profile_path) override;
194 ComponentUpdateService* cus_;
195 PrefService* local_state_;
197 std::vector<WhitelistReadyCallback> callbacks_;
199 ScopedObserver<ProfileInfoCache, ProfileInfoCacheObserver> observer_;
201 base::WeakPtrFactory<SupervisedUserWhitelistInstallerImpl> weak_ptr_factory_;
203 DISALLOW_COPY_AND_ASSIGN(SupervisedUserWhitelistInstallerImpl);
206 SupervisedUserWhitelistInstallerImpl::SupervisedUserWhitelistInstallerImpl(
207 ComponentUpdateService* cus,
208 ProfileInfoCache* profile_info_cache,
209 PrefService* local_state)
210 : cus_(cus),
211 local_state_(local_state),
212 observer_(this),
213 weak_ptr_factory_(this) {
214 DCHECK(cus);
215 DCHECK(local_state);
216 // In unit tests, the profile info cache can be null.
217 if (profile_info_cache)
218 observer_.Add(profile_info_cache);
221 void SupervisedUserWhitelistInstallerImpl::RegisterComponent(
222 const std::string& crx_id,
223 const std::string& name,
224 const base::Closure& callback) {
225 scoped_ptr<ComponentInstallerTraits> traits(
226 new SupervisedUserWhitelistComponentInstallerTraits(
227 crx_id, name,
228 base::Bind(&SupervisedUserWhitelistInstallerImpl::OnWhitelistReady,
229 weak_ptr_factory_.GetWeakPtr(), crx_id)));
230 scoped_refptr<DefaultComponentInstaller> installer(
231 new DefaultComponentInstaller(traits.Pass()));
232 installer->Register(cus_, callback);
235 void SupervisedUserWhitelistInstallerImpl::RegisterNewComponent(
236 const std::string& crx_id,
237 const std::string& name) {
238 RegisterComponent(
239 crx_id, name,
240 base::Bind(&SupervisedUserWhitelistInstallerImpl::TriggerComponentUpdate,
241 &cus_->GetOnDemandUpdater(), crx_id));
244 bool SupervisedUserWhitelistInstallerImpl::UnregisterWhitelistInternal(
245 base::DictionaryValue* pref_dict,
246 const std::string& client_id,
247 const std::string& crx_id) {
248 base::DictionaryValue* whitelist_dict = nullptr;
249 bool success =
250 pref_dict->GetDictionaryWithoutPathExpansion(crx_id, &whitelist_dict);
251 DCHECK(success);
252 base::ListValue* clients = nullptr;
253 success = whitelist_dict->GetList(kClients, &clients);
255 const bool removed = clients->Remove(base::StringValue(client_id), nullptr);
257 if (!clients->empty())
258 return removed;
260 pref_dict->RemoveWithoutPathExpansion(crx_id, nullptr);
261 const bool result = cus_->UnregisterComponent(crx_id);
262 DCHECK(result);
264 return removed;
267 void SupervisedUserWhitelistInstallerImpl::OnWhitelistReady(
268 const std::string& crx_id,
269 const base::FilePath& whitelist_path) {
270 for (const auto& callback : callbacks_)
271 callback.Run(crx_id, whitelist_path);
274 void SupervisedUserWhitelistInstallerImpl::RegisterComponents() {
275 std::set<std::string> registered_whitelists;
276 const base::DictionaryValue* whitelists =
277 local_state_->GetDictionary(prefs::kRegisteredSupervisedUserWhitelists);
278 for (base::DictionaryValue::Iterator it(*whitelists); !it.IsAtEnd();
279 it.Advance()) {
280 const base::DictionaryValue* dict = nullptr;
281 it.value().GetAsDictionary(&dict);
282 std::string name;
283 bool result = dict->GetString(kName, &name);
284 DCHECK(result);
285 const std::string& id = it.key();
286 RegisterComponent(id, name, base::Closure());
288 registered_whitelists.insert(id);
291 // Register whitelists specified on the command line.
292 const base::CommandLine* command_line =
293 base::CommandLine::ForCurrentProcess();
294 std::string command_line_whitelists = command_line->GetSwitchValueASCII(
295 switches::kInstallSupervisedUserWhitelists);
296 std::vector<std::string> split_whitelists;
297 base::SplitString(command_line_whitelists, ',', &split_whitelists);
298 for (const std::string& whitelist : split_whitelists) {
299 std::string id;
300 std::string name;
301 size_t separator = whitelist.find(':');
302 if (separator != std::string::npos) {
303 id = whitelist.substr(0, separator);
304 name = whitelist.substr(separator + 1);
305 } else {
306 id = whitelist;
308 RegisterNewComponent(id, name);
310 registered_whitelists.insert(id);
313 cus_->GetSequencedTaskRunner()->PostTask(
314 FROM_HERE, base::Bind(&RemoveUnregisteredWhitelistsOnTaskRunner,
315 registered_whitelists));
318 void SupervisedUserWhitelistInstallerImpl::Subscribe(
319 const WhitelistReadyCallback& callback) {
320 return callbacks_.push_back(callback);
323 void SupervisedUserWhitelistInstallerImpl::RegisterWhitelist(
324 const std::string& client_id,
325 const std::string& crx_id,
326 const std::string& name) {
327 DictionaryPrefUpdate update(local_state_,
328 prefs::kRegisteredSupervisedUserWhitelists);
329 base::DictionaryValue* pref_dict = update.Get();
330 base::DictionaryValue* whitelist_dict = nullptr;
331 bool newly_added = false;
332 if (!pref_dict->GetDictionaryWithoutPathExpansion(crx_id, &whitelist_dict)) {
333 whitelist_dict = new base::DictionaryValue;
334 whitelist_dict->SetString(kName, name);
335 pref_dict->SetWithoutPathExpansion(crx_id, whitelist_dict);
336 newly_added = true;
339 base::ListValue* clients = nullptr;
340 if (!whitelist_dict->GetList(kClients, &clients)) {
341 DCHECK(newly_added);
342 clients = new base::ListValue;
343 whitelist_dict->Set(kClients, clients);
345 bool success = clients->AppendIfNotPresent(new base::StringValue(client_id));
346 DCHECK(success);
348 if (!newly_added) {
349 // Sanity-check that the stored name is equal to the name passed in.
350 // In release builds this is a no-op.
351 std::string stored_name;
352 DCHECK(whitelist_dict->GetString(kName, &stored_name));
353 DCHECK_EQ(stored_name, name);
354 return;
357 RegisterNewComponent(crx_id, name);
360 void SupervisedUserWhitelistInstallerImpl::UnregisterWhitelist(
361 const std::string& client_id,
362 const std::string& crx_id) {
363 DictionaryPrefUpdate update(local_state_,
364 prefs::kRegisteredSupervisedUserWhitelists);
365 bool removed = UnregisterWhitelistInternal(update.Get(), client_id, crx_id);
366 DCHECK(removed);
369 void SupervisedUserWhitelistInstallerImpl::OnProfileWillBeRemoved(
370 const base::FilePath& profile_path) {
371 std::string client_id = ClientIdForProfilePath(profile_path);
373 // Go through all registered whitelists and possibly unregister them for this
374 // client.
375 DictionaryPrefUpdate update(local_state_,
376 prefs::kRegisteredSupervisedUserWhitelists);
377 base::DictionaryValue* pref_dict = update.Get();
378 for (base::DictionaryValue::Iterator it(*pref_dict); !it.IsAtEnd();
379 it.Advance()) {
380 UnregisterWhitelistInternal(pref_dict, client_id, it.key());
384 } // namespace
386 // static
387 scoped_ptr<SupervisedUserWhitelistInstaller>
388 SupervisedUserWhitelistInstaller::Create(ComponentUpdateService* cus,
389 ProfileInfoCache* profile_info_cache,
390 PrefService* local_state) {
391 return make_scoped_ptr(new SupervisedUserWhitelistInstallerImpl(
392 cus, profile_info_cache, local_state));
395 // static
396 void SupervisedUserWhitelistInstaller::RegisterPrefs(
397 PrefRegistrySimple* registry) {
398 registry->RegisterDictionaryPref(prefs::kRegisteredSupervisedUserWhitelists);
401 // static
402 std::string SupervisedUserWhitelistInstaller::ClientIdForProfilePath(
403 const base::FilePath& profile_path) {
404 // See ProfileInfoCache::CacheKeyFromProfilePath().
405 return profile_path.BaseName().MaybeAsASCII();
408 // static
409 std::vector<uint8_t> SupervisedUserWhitelistInstaller::GetHashFromCrxId(
410 const std::string& crx_id) {
411 DCHECK(crx_file::id_util::IdIsValid(crx_id));
413 std::vector<uint8_t> hash;
414 uint8_t byte = 0;
415 for (size_t i = 0; i < crx_id.size(); ++i) {
416 // Uppercase characters in IDs are technically legal.
417 int val = base::ToLowerASCII(crx_id[i]) - 'a';
418 DCHECK_GE(val, 0);
419 DCHECK_LT(val, 16);
420 if (i % 2 == 0) {
421 byte = val;
422 } else {
423 hash.push_back(16 * byte + val);
424 byte = 0;
427 return hash;
430 // static
431 void SupervisedUserWhitelistInstaller::TriggerComponentUpdate(
432 OnDemandUpdater* updater,
433 const std::string& crx_id) {
434 const bool result = updater->OnDemandUpdate(crx_id);
435 DCHECK(result);
438 } // namespace component_updater