Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/prefs/profile_pref_store_manager.h" | 5 #include "chrome/browser/prefs/profile_pref_store_manager.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
| 10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
| 11 #include "base/files/file_enumerator.h" | |
| 11 #include "base/files/scoped_temp_dir.h" | 12 #include "base/files/scoped_temp_dir.h" |
| 12 #include "base/memory/ref_counted.h" | 13 #include "base/memory/ref_counted.h" |
| 13 #include "base/memory/scoped_ptr.h" | 14 #include "base/memory/scoped_ptr.h" |
| 14 #include "base/message_loop/message_loop.h" | 15 #include "base/message_loop/message_loop.h" |
| 15 #include "base/prefs/json_pref_store.h" | 16 #include "base/prefs/json_pref_store.h" |
| 16 #include "base/prefs/persistent_pref_store.h" | 17 #include "base/prefs/persistent_pref_store.h" |
| 17 #include "base/prefs/pref_service.h" | 18 #include "base/prefs/pref_service.h" |
| 18 #include "base/prefs/pref_store.h" | 19 #include "base/prefs/pref_store.h" |
| 19 #include "base/prefs/testing_pref_service.h" | 20 #include "base/prefs/testing_pref_service.h" |
| 20 #include "base/run_loop.h" | 21 #include "base/run_loop.h" |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 52 pref_registry_->end(), | 53 pref_registry_->end(), |
| 53 FirstEqualsPredicate(key))); | 54 FirstEqualsPredicate(key))); |
| 54 } | 55 } |
| 55 | 56 |
| 56 virtual void OnInitializationCompleted(bool succeeded) OVERRIDE {} | 57 virtual void OnInitializationCompleted(bool succeeded) OVERRIDE {} |
| 57 | 58 |
| 58 private: | 59 private: |
| 59 scoped_refptr<PrefRegistry> pref_registry_; | 60 scoped_refptr<PrefRegistry> pref_registry_; |
| 60 }; | 61 }; |
| 61 | 62 |
| 63 const char kUnprotectedAtomic[] = "unprotected_atomic"; | |
| 62 const char kTrackedAtomic[] = "tracked_atomic"; | 64 const char kTrackedAtomic[] = "tracked_atomic"; |
| 63 const char kProtectedAtomic[] = "protected_atomic"; | 65 const char kProtectedAtomic[] = "protected_atomic"; |
| 64 const char kProtectedSplit[] = "protected_split"; | 66 const char kProtectedSplit[] = "protected_split"; |
| 65 | 67 |
| 66 const char kFoobar[] = "FOOBAR"; | 68 const char kFoobar[] = "FOOBAR"; |
| 67 const char kBarfoo[] = "BARFOO"; | 69 const char kBarfoo[] = "BARFOO"; |
| 68 const char kHelloWorld[] = "HELLOWORLD"; | 70 const char kHelloWorld[] = "HELLOWORLD"; |
| 69 const char kGoodbyeWorld[] = "GOODBYEWORLD"; | 71 const char kGoodbyeWorld[] = "GOODBYEWORLD"; |
| 70 | 72 |
| 71 const PrefHashFilter::TrackedPreferenceMetadata kConfiguration[] = { | 73 const PrefHashFilter::TrackedPreferenceMetadata kConfiguration[] = { |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 93 it != kConfiguration + arraysize(kConfiguration); | 95 it != kConfiguration + arraysize(kConfiguration); |
| 94 ++it) { | 96 ++it) { |
| 95 if (it->strategy == PrefHashFilter::TRACKING_STRATEGY_ATOMIC) { | 97 if (it->strategy == PrefHashFilter::TRACKING_STRATEGY_ATOMIC) { |
| 96 profile_pref_registry_->RegisterStringPref( | 98 profile_pref_registry_->RegisterStringPref( |
| 97 it->name, "", user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | 99 it->name, "", user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| 98 } else { | 100 } else { |
| 99 profile_pref_registry_->RegisterDictionaryPref( | 101 profile_pref_registry_->RegisterDictionaryPref( |
| 100 it->name, user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | 102 it->name, user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| 101 } | 103 } |
| 102 } | 104 } |
| 105 profile_pref_registry_->RegisterStringPref( | |
| 106 kUnprotectedAtomic, | |
| 107 "", | |
| 108 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | |
| 109 | |
| 103 ASSERT_TRUE(profile_dir_.CreateUniqueTempDir()); | 110 ASSERT_TRUE(profile_dir_.CreateUniqueTempDir()); |
| 111 ReloadConfiguration(); | |
| 112 } | |
| 104 | 113 |
| 114 void ReloadConfiguration() { | |
| 105 manager_.reset(new ProfilePrefStoreManager(profile_dir_.path(), | 115 manager_.reset(new ProfilePrefStoreManager(profile_dir_.path(), |
| 106 configuration_, | 116 configuration_, |
| 107 configuration_.size(), | 117 configuration_.size(), |
| 108 "seed", | 118 "seed", |
| 109 "device_id", | 119 "device_id", |
| 110 &local_state_)); | 120 &local_state_)); |
| 111 } | 121 } |
| 112 | 122 |
| 113 virtual void TearDown() OVERRIDE { | 123 virtual void TearDown() OVERRIDE { DestroyPrefStore(); } |
| 124 | |
| 125 protected: | |
| 126 void InitializePrefs() { | |
| 127 scoped_refptr<PersistentPrefStore> pref_store = | |
| 128 manager_->CreateProfilePrefStore( | |
| 129 main_message_loop_.message_loop_proxy()); | |
| 130 InitializePrefStore(pref_store); | |
| 131 pref_store = NULL; | |
| 132 base::RunLoop().RunUntilIdle(); | |
| 133 } | |
| 134 void DestroyPrefStore() { | |
| 114 if (pref_store_) { | 135 if (pref_store_) { |
| 115 // Force everything to be written to disk, triggering the PrefHashFilter | 136 // Force everything to be written to disk, triggering the PrefHashFilter |
| 116 // while our RegistryVerifier is watching. | 137 // while our RegistryVerifier is watching. |
| 117 pref_store_->CommitPendingWrite(); | 138 pref_store_->CommitPendingWrite(); |
| 118 base::RunLoop().RunUntilIdle(); | 139 base::RunLoop().RunUntilIdle(); |
| 119 | 140 |
| 120 pref_store_->RemoveObserver(®istry_verifier_); | 141 pref_store_->RemoveObserver(®istry_verifier_); |
| 121 pref_store_ = NULL; | 142 pref_store_ = NULL; |
| 122 // Nothing should have to happen on the background threads, but just in | 143 // Nothing should have to happen on the background threads, but just in |
| 123 // case... | 144 // case... |
| 124 base::RunLoop().RunUntilIdle(); | 145 base::RunLoop().RunUntilIdle(); |
| 125 } | 146 } |
| 126 } | 147 } |
| 127 | 148 |
| 128 protected: | 149 void InitializeDeprecatedCombinedProfilePrefStore() { |
| 129 void InitializePrefs() { | |
| 130 scoped_refptr<PersistentPrefStore> pref_store = | 150 scoped_refptr<PersistentPrefStore> pref_store = |
| 131 manager_->CreateProfilePrefStore( | 151 manager_->CreateDeprecatedCombinedProfilePrefStore( |
| 132 main_message_loop_.message_loop_proxy()); | 152 main_message_loop_.message_loop_proxy()); |
| 153 InitializePrefStore(pref_store); | |
| 154 pref_store = NULL; | |
| 155 base::RunLoop().RunUntilIdle(); | |
| 156 } | |
| 157 | |
| 158 void InitializePrefStore(PersistentPrefStore* pref_store) { | |
| 133 pref_store->AddObserver(®istry_verifier_); | 159 pref_store->AddObserver(®istry_verifier_); |
| 134 PersistentPrefStore::PrefReadError error = pref_store->ReadPrefs(); | 160 PersistentPrefStore::PrefReadError error = pref_store->ReadPrefs(); |
| 135 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE, error); | 161 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE, error); |
| 136 pref_store->SetValue(kTrackedAtomic, new base::StringValue(kFoobar)); | 162 pref_store->SetValue(kTrackedAtomic, new base::StringValue(kFoobar)); |
| 137 pref_store->SetValue(kProtectedAtomic, new base::StringValue(kHelloWorld)); | 163 pref_store->SetValue(kProtectedAtomic, new base::StringValue(kHelloWorld)); |
| 164 pref_store->SetValue(kUnprotectedAtomic, new base::StringValue(kFoobar)); | |
| 138 pref_store->RemoveObserver(®istry_verifier_); | 165 pref_store->RemoveObserver(®istry_verifier_); |
| 139 pref_store = NULL; | 166 pref_store->CommitPendingWrite(); |
| 140 base::RunLoop().RunUntilIdle(); | 167 base::RunLoop().RunUntilIdle(); |
| 141 } | 168 } |
| 142 | 169 |
| 143 void LoadExistingPrefs() { | 170 void LoadExistingPrefs() { |
| 171 DestroyPrefStore(); | |
| 144 pref_store_ = manager_->CreateProfilePrefStore( | 172 pref_store_ = manager_->CreateProfilePrefStore( |
| 145 main_message_loop_.message_loop_proxy()); | 173 main_message_loop_.message_loop_proxy()); |
| 146 pref_store_->AddObserver(®istry_verifier_); | 174 pref_store_->AddObserver(®istry_verifier_); |
| 147 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, | 175 pref_store_->ReadPrefs(); |
| 148 pref_store_->ReadPrefs()); | |
| 149 } | 176 } |
| 150 | 177 |
| 151 void ReplaceStringInPrefs(const std::string& find, | 178 void ReplaceStringInPrefs(const std::string& find, |
| 152 const std::string& replace) { | 179 const std::string& replace) { |
| 153 // Tamper with the file's contents | 180 base::FileEnumerator file_enumerator( |
| 154 base::FilePath pref_file_path = | 181 profile_dir_.path(), true, base::FileEnumerator::FILES); |
| 155 ProfilePrefStoreManager::GetPrefFilePathFromProfilePath( | 182 |
| 156 profile_dir_.path()); | 183 base::FilePath pref_file_path; |
| 157 std::string pref_file_contents; | 184 while (!(pref_file_path = file_enumerator.Next()).empty()) { |
| 158 EXPECT_TRUE(base::ReadFileToString(pref_file_path, &pref_file_contents)); | 185 // Tamper with the file's contents |
| 159 ReplaceSubstringsAfterOffset(&pref_file_contents, 0u, find, replace); | 186 std::string pref_file_contents; |
| 160 EXPECT_EQ(static_cast<int>(pref_file_contents.length()), | 187 EXPECT_TRUE(base::ReadFileToString(pref_file_path, &pref_file_contents)); |
| 161 base::WriteFile(pref_file_path, | 188 ReplaceSubstringsAfterOffset(&pref_file_contents, 0u, find, replace); |
| 162 pref_file_contents.c_str(), | 189 EXPECT_EQ((int)pref_file_contents.length(), |
| 163 pref_file_contents.length())); | 190 base::WriteFile(pref_file_path, |
| 191 pref_file_contents.c_str(), | |
| 192 pref_file_contents.length())); | |
| 193 } | |
| 164 } | 194 } |
| 165 | 195 |
| 166 void ExpectStringValueEquals(const std::string& name, | 196 void ExpectStringValueEquals(const std::string& name, |
| 167 const std::string& expected) { | 197 const std::string& expected) { |
| 168 const base::Value* value = NULL; | 198 const base::Value* value = NULL; |
| 169 std::string as_string; | 199 std::string as_string; |
| 170 if (!pref_store_->GetValue(name, &value)) { | 200 if (!pref_store_->GetValue(name, &value)) { |
| 171 ADD_FAILURE() << name << " is not a defined value."; | 201 ADD_FAILURE() << name << " is not a defined value."; |
| 172 } else if (!value->GetAsString(&as_string)) { | 202 } else if (!value->GetAsString(&as_string)) { |
| 173 ADD_FAILURE() << name << " could not be coerced to a string."; | 203 ADD_FAILURE() << name << " could not be coerced to a string."; |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 248 LoadExistingPrefs(); | 278 LoadExistingPrefs(); |
| 249 | 279 |
| 250 // kTrackedAtomic is loaded as it appears on disk. | 280 // kTrackedAtomic is loaded as it appears on disk. |
| 251 ExpectStringValueEquals(kTrackedAtomic, kFoobar); | 281 ExpectStringValueEquals(kTrackedAtomic, kFoobar); |
| 252 // If preference tracking is supported, kProtectedAtomic will be undefined | 282 // If preference tracking is supported, kProtectedAtomic will be undefined |
| 253 // because the value was discarded due to loss of the hash store contents. | 283 // because the value was discarded due to loss of the hash store contents. |
| 254 EXPECT_EQ(!ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, | 284 EXPECT_EQ(!ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, |
| 255 pref_store_->GetValue(kProtectedAtomic, NULL)); | 285 pref_store_->GetValue(kProtectedAtomic, NULL)); |
| 256 } | 286 } |
| 257 | 287 |
| 288 TEST_F(ProfilePrefStoreManagerTest, MigrateFromOneFile) { | |
| 289 InitializeDeprecatedCombinedProfilePrefStore(); | |
| 290 | |
| 291 LoadExistingPrefs(); | |
| 292 | |
| 293 ExpectStringValueEquals(kTrackedAtomic, kFoobar); | |
| 294 ExpectStringValueEquals(kProtectedAtomic, kHelloWorld); | |
| 295 } | |
| 296 | |
| 258 TEST_F(ProfilePrefStoreManagerTest, UpdateProfileHashStoreIfRequired) { | 297 TEST_F(ProfilePrefStoreManagerTest, UpdateProfileHashStoreIfRequired) { |
| 259 InitializePrefs(); | 298 scoped_refptr<JsonPrefStore> legacy_prefs( |
| 260 | 299 new JsonPrefStore(ProfilePrefStoreManager::GetPrefFilePathFromProfilePath( |
| 261 manager_->ResetPrefHashStore(); | 300 profile_dir_.path()), |
| 301 main_message_loop_.message_loop_proxy(), | |
| 302 scoped_ptr<PrefFilter>())); | |
| 303 legacy_prefs->SetValue(kTrackedAtomic, new base::StringValue(kFoobar)); | |
| 304 legacy_prefs->SetValue(kProtectedAtomic, new base::StringValue(kHelloWorld)); | |
| 305 legacy_prefs = NULL; | |
| 306 base::RunLoop().RunUntilIdle(); | |
| 262 | 307 |
| 263 // This is a no-op if !kPlatformSupportsPreferenceTracking. | 308 // This is a no-op if !kPlatformSupportsPreferenceTracking. |
| 264 manager_->UpdateProfileHashStoreIfRequired( | 309 manager_->UpdateProfileHashStoreIfRequired( |
| 265 main_message_loop_.message_loop_proxy()); | 310 main_message_loop_.message_loop_proxy()); |
| 266 base::RunLoop().RunUntilIdle(); | 311 base::RunLoop().RunUntilIdle(); |
| 267 | 312 |
| 268 // At the moment, UpdateProfileHashStoreIfRequired will accept existing | 313 // At the moment, UpdateProfileHashStoreIfRequired will accept existing |
| 269 // values. | 314 // values. |
| 270 LoadExistingPrefs(); | 315 LoadExistingPrefs(); |
| 271 | 316 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 282 ASSERT_TRUE( | 327 ASSERT_TRUE( |
| 283 manager_->InitializePrefsFromMasterPrefs(*master_prefs)); | 328 manager_->InitializePrefsFromMasterPrefs(*master_prefs)); |
| 284 | 329 |
| 285 LoadExistingPrefs(); | 330 LoadExistingPrefs(); |
| 286 | 331 |
| 287 // Verify that InitializePrefsFromMasterPrefs correctly applied the MACs | 332 // Verify that InitializePrefsFromMasterPrefs correctly applied the MACs |
| 288 // necessary to authenticate these values. | 333 // necessary to authenticate these values. |
| 289 ExpectStringValueEquals(kTrackedAtomic, kFoobar); | 334 ExpectStringValueEquals(kTrackedAtomic, kFoobar); |
| 290 ExpectStringValueEquals(kProtectedAtomic, kHelloWorld); | 335 ExpectStringValueEquals(kProtectedAtomic, kHelloWorld); |
| 291 } | 336 } |
| 337 | |
| 338 TEST_F(ProfilePrefStoreManagerTest, UnprotectedToProtected) { | |
| 339 InitializePrefs(); | |
| 340 LoadExistingPrefs(); | |
| 341 ExpectStringValueEquals(kUnprotectedAtomic, kFoobar); | |
| 342 | |
| 343 PrefHashFilter::TrackedPreferenceMetadata new_protected = { | |
| 344 99u, kUnprotectedAtomic, PrefHashFilter::ENFORCE_ON_LOAD, | |
| 345 PrefHashFilter::TRACKING_STRATEGY_ATOMIC}; | |
| 346 configuration_.push_back(new_protected); | |
| 347 ReloadConfiguration(); | |
| 348 LoadExistingPrefs(); | |
| 349 ExpectStringValueEquals(kUnprotectedAtomic, kFoobar); | |
| 350 } | |
| 351 | |
| 352 TEST_F(ProfilePrefStoreManagerTest, UnprotectedToProtectedWithoutTrust) { | |
|
robertshield
2014/03/25 03:05:12
Can we add a test that simulates partial migration
erikwright (departed)
2014/03/25 20:28:26
Yes. That's a bit trickier so I'm going to upload
| |
| 353 InitializePrefs(); | |
| 354 PrefHashFilter::TrackedPreferenceMetadata new_protected = { | |
| 355 99u, kUnprotectedAtomic, PrefHashFilter::ENFORCE_ON_LOAD, | |
| 356 PrefHashFilter::TRACKING_STRATEGY_ATOMIC}; | |
| 357 configuration_.push_back(new_protected); | |
| 358 ReloadConfiguration(); | |
| 359 ProfilePrefStoreManager::ResetAllPrefHashStores(&local_state_); | |
| 360 | |
| 361 LoadExistingPrefs(); | |
| 362 ASSERT_FALSE(pref_store_->GetValue(kUnprotectedAtomic, NULL)); | |
| 363 } | |
| 364 | |
| 365 | |
| 366 TEST_F(ProfilePrefStoreManagerTest, ProtectedToUnprotected) { | |
| 367 InitializePrefs(); | |
| 368 ProfilePrefStoreManager::ResetAllPrefHashStores(&local_state_); | |
| 369 | |
| 370 for (std::vector<PrefHashFilter::TrackedPreferenceMetadata>::iterator it = | |
| 371 configuration_.begin(); | |
| 372 it != configuration_.end(); | |
| 373 ++it) { | |
| 374 if (it->name == std::string(kProtectedAtomic)) { | |
| 375 configuration_.erase(it); | |
| 376 break; | |
| 377 } | |
| 378 } | |
| 379 | |
| 380 ReloadConfiguration(); | |
| 381 | |
| 382 LoadExistingPrefs(); | |
| 383 ExpectStringValueEquals(kProtectedAtomic, kHelloWorld); | |
| 384 | |
| 385 // Accessing the value of the previously proteted pref didn't trigger its move | |
| 386 // to the unprotected preferences file, though the loading of the pref store | |
| 387 // should still have caused the MAC store to be recalculated. | |
| 388 LoadExistingPrefs(); | |
| 389 ExpectStringValueEquals(kProtectedAtomic, kHelloWorld); | |
| 390 | |
| 391 // Trigger the logic that migrates it back to the unprotected preferences | |
| 392 // file. | |
| 393 pref_store_->SetValue(kProtectedAtomic, new base::StringValue(kGoodbyeWorld)); | |
| 394 LoadExistingPrefs(); | |
| 395 ExpectStringValueEquals(kProtectedAtomic, kGoodbyeWorld); | |
| 396 } | |
| 397 | |
| 398 // Add test coverage for when Reset events should and should not be recorded. | |
| OLD | NEW |