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/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
{
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
);
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
))
77 // Ignore folders that correspond to registered whitelists.
78 if (registered_whitelists
.count(crx_id
) > 0)
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
{
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
{}
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
;
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 {
132 bool SupervisedUserWhitelistComponentInstallerTraits::OnCustomInstall(
133 const base::DictionaryValue
& manifest
,
134 const base::FilePath
& install_dir
) {
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
));
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 {
161 class SupervisedUserWhitelistInstallerImpl
162 : public SupervisedUserWhitelistInstaller
,
163 public ProfileInfoCacheObserver
{
165 SupervisedUserWhitelistInstallerImpl(ComponentUpdateService
* cus
,
166 ProfileInfoCache
* profile_info_cache
,
167 PrefService
* local_state
);
168 ~SupervisedUserWhitelistInstallerImpl() override
{}
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
)
211 local_state_(local_state
),
213 weak_ptr_factory_(this) {
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(
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
) {
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;
250 pref_dict
->GetDictionaryWithoutPathExpansion(crx_id
, &whitelist_dict
);
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())
260 pref_dict
->RemoveWithoutPathExpansion(crx_id
, nullptr);
261 const bool result
= cus_
->UnregisterComponent(crx_id
);
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();
280 const base::DictionaryValue
* dict
= nullptr;
281 it
.value().GetAsDictionary(&dict
);
283 bool result
= dict
->GetString(kName
, &name
);
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
) {
301 size_t separator
= whitelist
.find(':');
302 if (separator
!= std::string::npos
) {
303 id
= whitelist
.substr(0, separator
);
304 name
= whitelist
.substr(separator
+ 1);
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
);
339 base::ListValue
* clients
= nullptr;
340 if (!whitelist_dict
->GetList(kClients
, &clients
)) {
342 clients
= new base::ListValue
;
343 whitelist_dict
->Set(kClients
, clients
);
345 bool success
= clients
->AppendIfNotPresent(new base::StringValue(client_id
));
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
);
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
);
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
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();
380 UnregisterWhitelistInternal(pref_dict
, client_id
, it
.key());
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
));
396 void SupervisedUserWhitelistInstaller::RegisterPrefs(
397 PrefRegistrySimple
* registry
) {
398 registry
->RegisterDictionaryPref(prefs::kRegisteredSupervisedUserWhitelists
);
402 std::string
SupervisedUserWhitelistInstaller::ClientIdForProfilePath(
403 const base::FilePath
& profile_path
) {
404 // See ProfileInfoCache::CacheKeyFromProfilePath().
405 return profile_path
.BaseName().MaybeAsASCII();
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
;
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';
423 hash
.push_back(16 * byte
+ val
);
431 void SupervisedUserWhitelistInstaller::TriggerComponentUpdate(
432 OnDemandUpdater
* updater
,
433 const std::string
& crx_id
) {
434 const bool result
= updater
->OnDemandUpdate(crx_id
);
438 } // namespace component_updater