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.
6 #include "base/callback.h"
7 #include "base/files/file_path.h"
8 #include "base/files/file_util.h"
9 #include "base/files/scoped_temp_dir.h"
10 #include "base/json/json_file_value_serializer.h"
11 #include "base/json/json_reader.h"
12 #include "base/json/json_writer.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/path_service.h"
15 #include "base/prefs/testing_pref_service.h"
16 #include "base/run_loop.h"
17 #include "base/sequenced_task_runner.h"
18 #include "base/strings/string_util.h"
19 #include "base/test/scoped_path_override.h"
20 #include "base/thread_task_runner_handle.h"
21 #include "base/values.h"
22 #include "chrome/browser/component_updater/supervised_user_whitelist_installer.h"
23 #include "chrome/common/chrome_paths.h"
24 #include "chrome/common/pref_names.h"
25 #include "components/component_updater/component_updater_paths.h"
26 #include "components/component_updater/component_updater_service.h"
27 #include "components/crx_file/id_util.h"
28 #include "components/safe_json/testing_json_parser.h"
29 #include "components/update_client/crx_update_item.h"
30 #include "components/update_client/update_client.h"
31 #include "components/update_client/utils.h"
32 #include "testing/gmock/include/gmock/gmock.h"
33 #include "testing/gtest/include/gtest/gtest.h"
35 using update_client::CrxComponent
;
36 using update_client::CrxUpdateItem
;
38 namespace component_updater
{
42 const char kClientId
[] = "client-id";
43 const char kCrxId
[] = "abcdefghijklmnopponmlkjihgfedcba";
44 const char kName
[] = "Some Whitelist";
45 const char kOtherClientId
[] = "other-client-id";
46 const char kVersion
[] = "1.2.3.4";
47 const char kWhitelistContents
[] = "{\"foo\": \"bar\"}";
48 const char kWhitelistFile
[] = "whitelist.json";
50 std::string
CrxIdToHashToCrxId(const std::string
& kCrxId
) {
51 CrxComponent component
;
53 SupervisedUserWhitelistInstaller::GetHashFromCrxId(kCrxId
);
54 EXPECT_EQ(16u, component
.pk_hash
.size());
55 return GetCrxComponentID(component
);
58 std::string
JsonToString(const base::DictionaryValue
& dict
) {
60 base::JSONWriter::Write(dict
, &json
);
64 class MockComponentUpdateService
: public ComponentUpdateService
,
65 public OnDemandUpdater
{
67 MockComponentUpdateService(
68 const scoped_refptr
<base::SequencedTaskRunner
>& task_runner
)
69 : task_runner_(task_runner
), on_demand_update_called_(false) {}
71 ~MockComponentUpdateService() override
{}
73 bool on_demand_update_called() const { return on_demand_update_called_
; }
75 const CrxComponent
* registered_component() { return component_
.get(); }
77 void set_registration_callback(const base::Closure
& registration_callback
) {
78 registration_callback_
= registration_callback
;
81 // ComponentUpdateService implementation:
82 void AddObserver(Observer
* observer
) override
{ ADD_FAILURE(); }
83 void RemoveObserver(Observer
* observer
) override
{ ADD_FAILURE(); }
85 std::vector
<std::string
> GetComponentIDs() const override
{
87 return std::vector
<std::string
>();
90 bool RegisterComponent(const CrxComponent
& component
) override
{
91 EXPECT_EQ(nullptr, component_
.get());
92 component_
.reset(new CrxComponent(component
));
93 if (!registration_callback_
.is_null())
94 registration_callback_
.Run();
99 bool UnregisterComponent(const std::string
& crx_id
) override
{
105 EXPECT_EQ(GetCrxComponentID(*component_
), crx_id
);
106 if (!component_
->installer
->Uninstall()) {
115 OnDemandUpdater
& GetOnDemandUpdater() override
{ return *this; }
117 void MaybeThrottle(const std::string
& kCrxId
,
118 const base::Closure
& callback
) override
{
122 scoped_refptr
<base::SequencedTaskRunner
> GetSequencedTaskRunner() override
{
126 bool GetComponentDetails(const std::string
& component_id
,
127 CrxUpdateItem
* item
) const override
{
132 // OnDemandUpdater implementation:
133 bool OnDemandUpdate(const std::string
& crx_id
) override
{
134 on_demand_update_called_
= true;
137 ADD_FAILURE() << "Trying to update unregistered component " << crx_id
;
141 EXPECT_EQ(GetCrxComponentID(*component_
), crx_id
);
146 scoped_refptr
<base::SequencedTaskRunner
> task_runner_
;
147 scoped_ptr
<CrxComponent
> component_
;
148 base::Closure registration_callback_
;
149 bool on_demand_update_called_
;
152 class WhitelistLoadObserver
{
154 explicit WhitelistLoadObserver(SupervisedUserWhitelistInstaller
* installer
)
155 : weak_ptr_factory_(this) {
156 installer
->Subscribe(base::Bind(&WhitelistLoadObserver::OnWhitelistReady
,
157 weak_ptr_factory_
.GetWeakPtr()));
160 void Wait() { run_loop_
.Run(); }
162 const base::FilePath
& whitelist_path() { return whitelist_path_
; }
165 void OnWhitelistReady(const std::string
& crx_id
,
166 const base::FilePath
& whitelist_path
) {
167 EXPECT_EQ(base::FilePath::StringType(), whitelist_path_
.value());
168 whitelist_path_
= whitelist_path
;
172 base::FilePath whitelist_path_
;
174 base::RunLoop run_loop_
;
175 base::WeakPtrFactory
<WhitelistLoadObserver
> weak_ptr_factory_
;
180 class SupervisedUserWhitelistInstallerTest
: public testing::Test
{
182 SupervisedUserWhitelistInstallerTest()
183 : raw_whitelists_path_override_(DIR_SUPERVISED_USER_WHITELISTS
),
184 installed_whitelists_path_override_(
185 chrome::DIR_SUPERVISED_USER_INSTALLED_WHITELISTS
),
186 component_update_service_(base::ThreadTaskRunnerHandle::Get()),
188 SupervisedUserWhitelistInstaller::Create(&component_update_service_
,
192 ~SupervisedUserWhitelistInstallerTest() override
{}
194 void SetUp() override
{
195 SupervisedUserWhitelistInstaller::RegisterPrefs(local_state_
.registry());
197 ASSERT_TRUE(PathService::Get(DIR_SUPERVISED_USER_WHITELISTS
,
198 &whitelist_base_directory_
));
199 whitelist_directory_
= whitelist_base_directory_
.AppendASCII(kCrxId
);
200 whitelist_version_directory_
= whitelist_directory_
.AppendASCII(kVersion
);
203 PathService::Get(chrome::DIR_SUPERVISED_USER_INSTALLED_WHITELISTS
,
204 &installed_whitelist_directory_
));
205 std::string
crx_id(kCrxId
);
207 installed_whitelist_directory_
.AppendASCII(crx_id
+ ".json");
209 scoped_ptr
<base::DictionaryValue
> whitelist_dict(
210 new base::DictionaryValue
);
211 whitelist_dict
->SetString("file", kWhitelistFile
);
212 manifest_
.Set("whitelist", whitelist_dict
.release());
213 manifest_
.SetString("version", kVersion
);
215 scoped_ptr
<base::DictionaryValue
> crx_dict(new base::DictionaryValue
);
216 crx_dict
->SetString("name", kName
);
217 scoped_ptr
<base::ListValue
> clients(new base::ListValue
);
218 clients
->AppendString(kClientId
);
219 clients
->AppendString(kOtherClientId
);
220 crx_dict
->Set("clients", clients
.release());
221 pref_
.Set(kCrxId
, crx_dict
.release());
225 void PrepareWhitelistFile(const base::FilePath
& whitelist_path
) {
226 size_t whitelist_contents_length
= sizeof(kWhitelistContents
) - 1;
227 ASSERT_EQ(static_cast<int>(whitelist_contents_length
),
228 base::WriteFile(whitelist_path
, kWhitelistContents
,
229 whitelist_contents_length
));
232 void PrepareWhitelistDirectory(const base::FilePath
& whitelist_directory
) {
233 PrepareWhitelistFile(whitelist_directory
.AppendASCII(kWhitelistFile
));
234 base::FilePath manifest_file
=
235 whitelist_directory
.AppendASCII("manifest.json");
236 ASSERT_TRUE(JSONFileValueSerializer(manifest_file
).Serialize(manifest_
));
239 void RegisterExistingComponents() {
240 local_state_
.Set(prefs::kRegisteredSupervisedUserWhitelists
, pref_
);
241 installer_
->RegisterComponents();
242 base::RunLoop().RunUntilIdle();
245 void CheckRegisteredComponent(const char* version
) {
246 const CrxComponent
* component
=
247 component_update_service_
.registered_component();
248 ASSERT_TRUE(component
);
249 EXPECT_EQ(kName
, component
->name
);
250 EXPECT_EQ(kCrxId
, GetCrxComponentID(*component
));
251 EXPECT_EQ(version
, component
->version
.GetString());
254 base::MessageLoop message_loop_
;
255 base::ScopedPathOverride raw_whitelists_path_override_
;
256 base::ScopedPathOverride installed_whitelists_path_override_
;
257 safe_json::TestingJsonParser::ScopedFactoryOverride json_parser_override_
;
258 MockComponentUpdateService component_update_service_
;
259 TestingPrefServiceSimple local_state_
;
260 scoped_ptr
<SupervisedUserWhitelistInstaller
> installer_
;
261 base::FilePath whitelist_base_directory_
;
262 base::FilePath whitelist_directory_
;
263 base::FilePath whitelist_version_directory_
;
264 base::FilePath installed_whitelist_directory_
;
265 base::FilePath whitelist_path_
;
266 base::DictionaryValue manifest_
;
267 base::DictionaryValue pref_
;
270 TEST_F(SupervisedUserWhitelistInstallerTest
, GetHashFromCrxId
) {
272 std::string extension_id
= "abcdefghijklmnopponmlkjihgfedcba";
273 ASSERT_EQ(extension_id
, CrxIdToHashToCrxId(extension_id
));
277 std::string extension_id
= "aBcDeFgHiJkLmNoPpOnMlKjIhGfEdCbA";
278 ASSERT_EQ(base::ToLowerASCII(extension_id
),
279 CrxIdToHashToCrxId(extension_id
));
283 std::string extension_id
= crx_file::id_util::GenerateId("Moose");
284 ASSERT_EQ(extension_id
, CrxIdToHashToCrxId(extension_id
));
288 TEST_F(SupervisedUserWhitelistInstallerTest
, InstallNewWhitelist
) {
289 base::RunLoop registration_run_loop
;
290 component_update_service_
.set_registration_callback(
291 registration_run_loop
.QuitClosure());
293 WhitelistLoadObserver
observer(installer_
.get());
294 installer_
->RegisterWhitelist(kClientId
, kCrxId
, kName
);
295 registration_run_loop
.Run();
297 ASSERT_NO_FATAL_FAILURE(CheckRegisteredComponent("0.0.0.0"));
298 EXPECT_TRUE(component_update_service_
.on_demand_update_called());
300 // Registering the same whitelist for another client should not do anything.
301 installer_
->RegisterWhitelist(kOtherClientId
, kCrxId
, kName
);
303 base::ScopedTempDir temp_dir
;
304 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
305 base::FilePath unpacked_path
= temp_dir
.path();
306 ASSERT_NO_FATAL_FAILURE(PrepareWhitelistDirectory(unpacked_path
));
308 const CrxComponent
* component
=
309 component_update_service_
.registered_component();
310 ASSERT_TRUE(component
);
311 EXPECT_TRUE(component
->installer
->Install(manifest_
, unpacked_path
));
314 EXPECT_EQ(whitelist_path_
.value(), observer
.whitelist_path().value());
316 std::string whitelist_contents
;
317 ASSERT_TRUE(base::ReadFileToString(whitelist_path_
, &whitelist_contents
));
319 // The actual file contents don't have to be equal, but the parsed values
321 EXPECT_TRUE(base::JSONReader::Read(kWhitelistContents
)
322 ->Equals(base::JSONReader::Read(whitelist_contents
).get()))
323 << kWhitelistContents
<< " vs. " << whitelist_contents
;
325 EXPECT_EQ(JsonToString(pref_
),
326 JsonToString(*local_state_
.GetDictionary(
327 prefs::kRegisteredSupervisedUserWhitelists
)));
330 TEST_F(SupervisedUserWhitelistInstallerTest
,
331 RegisterAndUninstallExistingWhitelist
) {
332 ASSERT_TRUE(base::CreateDirectory(whitelist_version_directory_
));
333 ASSERT_NO_FATAL_FAILURE(
334 PrepareWhitelistDirectory(whitelist_version_directory_
));
335 ASSERT_NO_FATAL_FAILURE(PrepareWhitelistFile(whitelist_path_
));
337 // Create another whitelist directory, with an ID that is not registered.
338 base::FilePath other_directory
=
339 whitelist_base_directory_
.AppendASCII("paobncmdlekfjgihhigjfkeldmcnboap");
340 ASSERT_TRUE(base::CreateDirectory(other_directory
));
341 ASSERT_NO_FATAL_FAILURE(PrepareWhitelistDirectory(other_directory
));
343 // Create a directory that is not a valid whitelist directory.
344 base::FilePath non_whitelist_directory
=
345 whitelist_base_directory_
.AppendASCII("Not a whitelist");
346 ASSERT_TRUE(base::CreateDirectory(non_whitelist_directory
));
348 RegisterExistingComponents();
350 ASSERT_NO_FATAL_FAILURE(CheckRegisteredComponent(kVersion
));
351 EXPECT_FALSE(component_update_service_
.on_demand_update_called());
353 // Check that unregistered whitelists have been removed:
354 // The registered whitelist directory should still exist.
355 EXPECT_TRUE(base::DirectoryExists(whitelist_directory_
));
357 // The other directory should be gone.
358 EXPECT_FALSE(base::DirectoryExists(other_directory
));
360 // The non-whitelist directory should still exist as well.
361 EXPECT_TRUE(base::DirectoryExists(non_whitelist_directory
));
363 // Unregistering for the first client should do nothing.
365 base::RunLoop run_loop
;
366 installer_
->UnregisterWhitelist(kClientId
, kCrxId
);
367 run_loop
.RunUntilIdle();
369 EXPECT_TRUE(component_update_service_
.registered_component());
370 EXPECT_TRUE(base::DirectoryExists(whitelist_version_directory_
));
371 EXPECT_TRUE(base::PathExists(whitelist_path_
));
373 // Unregistering for the second client should uninstall the whitelist.
375 base::RunLoop run_loop
;
376 installer_
->UnregisterWhitelist(kOtherClientId
, kCrxId
);
377 run_loop
.RunUntilIdle();
379 EXPECT_FALSE(component_update_service_
.registered_component());
380 EXPECT_FALSE(base::DirectoryExists(whitelist_directory_
));
381 EXPECT_FALSE(base::PathExists(whitelist_path_
));
384 } // namespace component_updater