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"
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
{
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
);
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
))
73 // Ignore folders that correspond to registered whitelists.
74 if (registered_whitelists
.count(crx_id
) > 0)
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
{
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
{}
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
;
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 {
128 bool SupervisedUserWhitelistComponentInstallerTraits::OnCustomInstall(
129 const base::DictionaryValue
& manifest
,
130 const base::FilePath
& install_dir
) {
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
));
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 {
157 class SupervisedUserWhitelistInstallerImpl
158 : public SupervisedUserWhitelistInstaller
,
159 public ProfileInfoCacheObserver
{
161 SupervisedUserWhitelistInstallerImpl(ComponentUpdateService
* cus
,
162 ProfileInfoCache
* profile_info_cache
,
163 PrefService
* local_state
);
164 ~SupervisedUserWhitelistInstallerImpl() override
{}
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
)
207 local_state_(local_state
),
209 weak_ptr_factory_(this) {
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(
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
) {
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;
246 pref_dict
->GetDictionaryWithoutPathExpansion(crx_id
, &whitelist_dict
);
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())
256 pref_dict
->RemoveWithoutPathExpansion(crx_id
, nullptr);
257 const bool result
= cus_
->UnregisterComponent(crx_id
);
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();
276 const base::DictionaryValue
* dict
= nullptr;
277 it
.value().GetAsDictionary(&dict
);
279 bool result
= dict
->GetString(kName
, &name
);
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
);
313 base::ListValue
* clients
= nullptr;
314 if (!whitelist_dict
->GetList(kClients
, &clients
)) {
316 clients
= new base::ListValue
;
317 whitelist_dict
->Set(kClients
, clients
);
319 bool success
= clients
->AppendIfNotPresent(new base::StringValue(client_id
));
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
);
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
);
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
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();
354 UnregisterWhitelistInternal(pref_dict
, client_id
, it
.key());
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
));
370 void SupervisedUserWhitelistInstaller::RegisterPrefs(
371 PrefRegistrySimple
* registry
) {
372 registry
->RegisterDictionaryPref(prefs::kRegisteredSupervisedUserWhitelists
);
376 std::string
SupervisedUserWhitelistInstaller::ClientIdForProfilePath(
377 const base::FilePath
& profile_path
) {
378 // See ProfileInfoCache::CacheKeyFromProfilePath().
379 return profile_path
.BaseName().MaybeAsASCII();
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
;
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';
397 hash
.push_back(16 * byte
+ val
);
405 void SupervisedUserWhitelistInstaller::TriggerComponentUpdate(
406 OnDemandUpdater
* updater
,
407 const std::string
& crx_id
) {
408 const bool result
= updater
->OnDemandUpdate(crx_id
);
412 } // namespace component_updater