| Index: chrome/browser/protector/protected_prefs_watcher.cc
|
| diff --git a/chrome/browser/protector/protected_prefs_watcher.cc b/chrome/browser/protector/protected_prefs_watcher.cc
|
| deleted file mode 100644
|
| index 4c926dbd4840c5b5262f23b5c8cf61ffa7407c27..0000000000000000000000000000000000000000
|
| --- a/chrome/browser/protector/protected_prefs_watcher.cc
|
| +++ /dev/null
|
| @@ -1,399 +0,0 @@
|
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "chrome/browser/protector/protected_prefs_watcher.h"
|
| -
|
| -#include "base/base64.h"
|
| -#include "base/bind.h"
|
| -#include "base/logging.h"
|
| -#include "base/metrics/histogram.h"
|
| -#include "base/stringprintf.h"
|
| -#include "base/values.h"
|
| -#include "chrome/browser/extensions/extension_prefs.h"
|
| -#include "chrome/browser/prefs/pref_service.h"
|
| -#include "chrome/browser/prefs/scoped_user_pref_update.h"
|
| -#include "chrome/browser/prefs/session_startup_pref.h"
|
| -#include "chrome/browser/profiles/profile.h"
|
| -#include "chrome/browser/protector/histograms.h"
|
| -#include "chrome/browser/protector/protector_utils.h"
|
| -#include "chrome/common/chrome_notification_types.h"
|
| -#include "chrome/common/pref_names.h"
|
| -#include "content/public/browser/notification_service.h"
|
| -
|
| -using extensions::ExtensionPrefs;
|
| -
|
| -namespace protector {
|
| -
|
| -namespace {
|
| -
|
| -// Prefix added to names of backup entries.
|
| -const char kBackupPrefsPrefix[] = "backup.";
|
| -
|
| -// Names of prefs that are backed up.
|
| -const char* const kProtectedPrefNames[] = {
|
| - prefs::kHomePage,
|
| - prefs::kHomePageIsNewTabPage,
|
| - prefs::kShowHomeButton,
|
| - prefs::kRestoreOnStartup,
|
| - prefs::kURLsToRestoreOnStartup,
|
| - prefs::kPinnedTabs
|
| -};
|
| -
|
| -// Backup pref names.
|
| -const char kBackupHomePage[] = "backup.homepage";
|
| -const char kBackupHomePageIsNewTabPage[] = "backup.homepage_is_newtabpage";
|
| -const char kBackupShowHomeButton[] = "backup.browser.show_home_button";
|
| -const char kBackupRestoreOnStartup[] = "backup.session.restore_on_startup";
|
| -const char kBackupURLsToRestoreOnStartup[] =
|
| - "backup.session.urls_to_restore_on_startup";
|
| -const char kBackupPinnedTabs[] = "backup.pinned_tabs";
|
| -
|
| -// Special backup entries.
|
| -const char kBackupExtensionsIDs[] = "backup.extensions.ids";
|
| -const char kBackupSignature[] = "backup._signature";
|
| -const char kBackupVersion[] = "backup._version";
|
| -
|
| -// Returns name of the backup entry for pref |pref_name|.
|
| -std::string GetBackupNameFor(const std::string& pref_name) {
|
| - return kBackupPrefsPrefix + pref_name;
|
| -}
|
| -
|
| -// Appends a list of strings to |out|.
|
| -void StringAppendStringList(const base::ListValue* list, std::string* out) {
|
| - for (base::ListValue::const_iterator it = list->begin(); it != list->end();
|
| - ++it) {
|
| - std::string item;
|
| - if (!(*it)->GetAsString(&item))
|
| - NOTREACHED();
|
| - base::StringAppendF(out, "|%s", item.c_str());
|
| - }
|
| -}
|
| -
|
| -// Appends a dictionary with string values to |out|.
|
| -void StringAppendStringDictionary(const base::DictionaryValue* dict,
|
| - std::string* out) {
|
| - for (base::DictionaryValue::Iterator it(*dict); it.HasNext(); it.Advance()) {
|
| - std::string value;
|
| - if (!it.value().GetAsString(&value))
|
| - NOTREACHED();
|
| - base::StringAppendF(out, "|%s|%s", it.key().c_str(), value.c_str());
|
| - }
|
| -}
|
| -
|
| -void StringAppendBoolean(PrefService* prefs,
|
| - const char* path,
|
| - std::string* out) {
|
| - if (prefs->HasPrefPath(path))
|
| - base::StringAppendF(out, "|%d", prefs->GetBoolean(path) ? 1 : 0);
|
| - else
|
| - base::StringAppendF(out, "|");
|
| -}
|
| -
|
| -void StringAppendInteger(PrefService* prefs,
|
| - const char* path,
|
| - std::string* out) {
|
| - if (prefs->HasPrefPath(path))
|
| - base::StringAppendF(out, "|%d", prefs->GetInteger(path));
|
| - else
|
| - base::StringAppendF(out, "|");
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -// static
|
| -const int ProtectedPrefsWatcher::kCurrentVersionNumber = 4;
|
| -
|
| -ProtectedPrefsWatcher::ProtectedPrefsWatcher(Profile* profile)
|
| - : is_backup_valid_(true),
|
| - profile_(profile) {
|
| - // Perform necessary pref migrations before actually starting to observe
|
| - // pref changes, otherwise the migration would affect the backup data as well.
|
| - EnsurePrefsMigration();
|
| -
|
| - pref_observer_.Init(profile->GetPrefs());
|
| - PrefChangeRegistrar::NamedChangeCallback callback = base::Bind(
|
| - &ProtectedPrefsWatcher::OnPreferenceChanged, base::Unretained(this));
|
| - pref_observer_.Add(prefs::kHomePageIsNewTabPage, callback);
|
| - pref_observer_.Add(prefs::kHomePage, callback);
|
| - pref_observer_.Add(prefs::kShowHomeButton, callback);
|
| - // Session startup.
|
| - pref_observer_.Add(prefs::kRestoreOnStartup, callback);
|
| - pref_observer_.Add(prefs::kURLsToRestoreOnStartup, callback);
|
| - // Pinned tabs.
|
| - pref_observer_.Add(prefs::kPinnedTabs, callback);
|
| - // Extensions.
|
| - pref_observer_.Add(ExtensionPrefs::kExtensionsPref, callback);
|
| -
|
| - UpdateCachedPrefs();
|
| - ValidateBackup();
|
| - VLOG(1) << "Initialized pref watcher";
|
| -}
|
| -
|
| -ProtectedPrefsWatcher::~ProtectedPrefsWatcher() {
|
| -}
|
| -
|
| -// static
|
| -void ProtectedPrefsWatcher::RegisterUserPrefs(PrefService* prefs) {
|
| - prefs->RegisterStringPref(kBackupHomePage, "",
|
| - PrefService::UNSYNCABLE_PREF);
|
| - prefs->RegisterBooleanPref(kBackupHomePageIsNewTabPage, false,
|
| - PrefService::UNSYNCABLE_PREF);
|
| - prefs->RegisterBooleanPref(kBackupShowHomeButton, false,
|
| - PrefService::UNSYNCABLE_PREF);
|
| - prefs->RegisterIntegerPref(kBackupRestoreOnStartup, 0,
|
| - PrefService::UNSYNCABLE_PREF);
|
| - prefs->RegisterListPref(kBackupURLsToRestoreOnStartup,
|
| - PrefService::UNSYNCABLE_PREF);
|
| - prefs->RegisterListPref(kBackupPinnedTabs,
|
| - PrefService::UNSYNCABLE_PREF);
|
| - prefs->RegisterListPref(kBackupExtensionsIDs,
|
| - PrefService::UNSYNCABLE_PREF);
|
| - prefs->RegisterStringPref(kBackupSignature, "",
|
| - PrefService::UNSYNCABLE_PREF);
|
| - prefs->RegisterIntegerPref(kBackupVersion, 1,
|
| - PrefService::UNSYNCABLE_PREF);
|
| -}
|
| -
|
| -bool ProtectedPrefsWatcher::DidPrefChange(const std::string& path) const {
|
| - std::string backup_path = GetBackupNameFor(path);
|
| - PrefService* prefs = profile_->GetPrefs();
|
| - const PrefService::Preference* new_pref = prefs->FindPreference(path.c_str());
|
| - DCHECK(new_pref);
|
| - const PrefService::Preference* backup_pref =
|
| - profile_->GetPrefs()->FindPreference(backup_path.c_str());
|
| - DCHECK(backup_pref);
|
| - if (new_pref->IsDefaultValue())
|
| - return !backup_pref->IsDefaultValue();
|
| - if (!new_pref->IsUserControlled())
|
| - return false;
|
| - return !backup_pref->GetValue()->Equals(new_pref->GetValue());
|
| -}
|
| -
|
| -const base::Value* ProtectedPrefsWatcher::GetBackupForPref(
|
| - const std::string& path) const {
|
| - if (!is_backup_valid_)
|
| - return NULL;
|
| - std::string backup_path = GetBackupNameFor(path);
|
| - // These do not directly correspond to any real preference.
|
| - DCHECK(backup_path != kBackupExtensionsIDs &&
|
| - backup_path != kBackupSignature);
|
| - PrefService* prefs = profile_->GetPrefs();
|
| - // If backup is not set, return the default value of the actual pref.
|
| - // TODO(ivankr): return NULL instead and handle appropriately in SettingChange
|
| - // classes.
|
| - if (!prefs->HasPrefPath(backup_path.c_str()))
|
| - return prefs->GetDefaultPrefValue(path.c_str());
|
| - const PrefService::Preference* backup_pref =
|
| - profile_->GetPrefs()->FindPreference(backup_path.c_str());
|
| - DCHECK(backup_pref);
|
| - return backup_pref->GetValue();
|
| -}
|
| -
|
| -void ProtectedPrefsWatcher::ForceUpdateBackup() {
|
| - UMA_HISTOGRAM_ENUMERATION(
|
| - kProtectorHistogramPrefs,
|
| - kProtectorErrorForcedUpdate,
|
| - kProtectorErrorCount);
|
| - InitBackup();
|
| -}
|
| -
|
| -void ProtectedPrefsWatcher::OnPreferenceChanged(const std::string& pref_name) {
|
| - DCHECK(pref_observer_.IsObserved(pref_name));
|
| - if (UpdateBackupEntry(pref_name))
|
| - UpdateBackupSignature();
|
| -}
|
| -
|
| -void ProtectedPrefsWatcher::EnsurePrefsMigration() {
|
| - SessionStartupPref::MigrateIfNecessary(profile_->GetPrefs());
|
| -}
|
| -
|
| -bool ProtectedPrefsWatcher::UpdateCachedPrefs() {
|
| - // ExtensionService may not yet have been initialized, so using static method
|
| - // exposed for this purpose.
|
| - extensions::ExtensionIdList extension_ids =
|
| - ExtensionPrefs::GetExtensionsFrom(profile_->GetPrefs());
|
| - if (extension_ids == cached_extension_ids_)
|
| - return false;
|
| - cached_extension_ids_.swap(extension_ids);
|
| - return true;
|
| -}
|
| -
|
| -bool ProtectedPrefsWatcher::HasBackup() const {
|
| - // TODO(ivankr): as soon as some irreversible change to Preferences happens,
|
| - // add a condition that this change has occured as well (otherwise it's
|
| - // possible to simply clear the "backup" dictionary to make settings
|
| - // unprotected).
|
| - return profile_->GetPrefs()->HasPrefPath(kBackupSignature);
|
| -}
|
| -
|
| -void ProtectedPrefsWatcher::InitBackup() {
|
| - PrefService* prefs = profile_->GetPrefs();
|
| - for (size_t i = 0; i < arraysize(kProtectedPrefNames); ++i) {
|
| - const base::Value* user_value =
|
| - prefs->GetUserPrefValue(kProtectedPrefNames[i]);
|
| - if (user_value)
|
| - prefs->Set(GetBackupNameFor(kProtectedPrefNames[i]).c_str(), *user_value);
|
| - }
|
| - ListPrefUpdate extension_ids_update(prefs, kBackupExtensionsIDs);
|
| - base::ListValue* extension_ids = extension_ids_update.Get();
|
| - extension_ids->Clear();
|
| - for (extensions::ExtensionIdList::const_iterator it =
|
| - cached_extension_ids_.begin();
|
| - it != cached_extension_ids_.end(); ++it) {
|
| - extension_ids->Append(base::Value::CreateStringValue(*it));
|
| - }
|
| - prefs->SetInteger(kBackupVersion, kCurrentVersionNumber);
|
| - UpdateBackupSignature();
|
| -}
|
| -
|
| -void ProtectedPrefsWatcher::MigrateOldBackupIfNeeded() {
|
| - PrefService* prefs = profile_->GetPrefs();
|
| -
|
| - int current_version = prefs->GetInteger(kBackupVersion);
|
| - VLOG(1) << "Backup version: " << current_version;
|
| - if (current_version == kCurrentVersionNumber)
|
| - return;
|
| -
|
| - switch (current_version) {
|
| - case 1: {
|
| - // Add pinned tabs.
|
| - const base::Value* pinned_tabs =
|
| - prefs->GetUserPrefValue(prefs::kPinnedTabs);
|
| - if (pinned_tabs)
|
| - prefs->Set(kBackupPinnedTabs, *pinned_tabs);
|
| - }
|
| - // FALL THROUGH
|
| -
|
| - case 2:
|
| - // SessionStartupPref migration.
|
| - DCHECK(prefs->GetBoolean(prefs::kRestoreOnStartupMigrated));
|
| - prefs->SetInteger(kBackupRestoreOnStartup,
|
| - prefs->GetInteger(prefs::kRestoreOnStartup));
|
| - prefs->Set(kBackupURLsToRestoreOnStartup,
|
| - *prefs->GetList(prefs::kURLsToRestoreOnStartup));
|
| - // FALL THROUGH
|
| -
|
| - case 3:
|
| - // Reset to default values backup prefs whose actual prefs are not set.
|
| - for (size_t i = 0; i < arraysize(kProtectedPrefNames); ++i) {
|
| - if (!prefs->HasPrefPath(kProtectedPrefNames[i]))
|
| - prefs->ClearPref(GetBackupNameFor(kProtectedPrefNames[i]).c_str());
|
| - }
|
| - // FALL THROUGH
|
| - }
|
| -
|
| - prefs->SetInteger(kBackupVersion, kCurrentVersionNumber);
|
| - UpdateBackupSignature();
|
| -}
|
| -
|
| -bool ProtectedPrefsWatcher::UpdateBackupEntry(const std::string& path) {
|
| - std::string backup_path = GetBackupNameFor(path);
|
| - PrefService* prefs = profile_->GetPrefs();
|
| - const PrefService::Preference* pref = prefs->FindPreference(path.c_str());
|
| - if (path == ExtensionPrefs::kExtensionsPref) {
|
| - // For changes in extension dictionary, do nothing if the IDs list remained
|
| - // the same.
|
| - if (!UpdateCachedPrefs())
|
| - return false;
|
| - ListPrefUpdate extension_ids_update(prefs, kBackupExtensionsIDs);
|
| - base::ListValue* extension_ids = extension_ids_update.Get();
|
| - extension_ids->Clear();
|
| - for (extensions::ExtensionIdList::const_iterator it =
|
| - cached_extension_ids_.begin();
|
| - it != cached_extension_ids_.end(); ++it) {
|
| - extension_ids->Append(base::Value::CreateStringValue(*it));
|
| - }
|
| - } else if (!prefs->HasPrefPath(path.c_str())) {
|
| - // Preference has been removed, remove the backup as well.
|
| - prefs->ClearPref(backup_path.c_str());
|
| - } else if (!pref->IsUserControlled()) {
|
| - return false;
|
| - } else {
|
| - prefs->Set(backup_path.c_str(), *pref->GetValue());
|
| - }
|
| - VLOG(1) << "Updated backup entry for: " << path;
|
| - return true;
|
| -}
|
| -
|
| -void ProtectedPrefsWatcher::UpdateBackupSignature() {
|
| - PrefService* prefs = profile_->GetPrefs();
|
| - std::string signed_data = GetSignatureData(prefs);
|
| - DCHECK(!signed_data.empty());
|
| - std::string signature = SignSetting(signed_data);
|
| - DCHECK(!signature.empty());
|
| - std::string signature_base64;
|
| - if (!base::Base64Encode(signature, &signature_base64))
|
| - NOTREACHED();
|
| - prefs->SetString(kBackupSignature, signature_base64);
|
| - // Schedule disk write on FILE thread as soon as possible.
|
| - prefs->CommitPendingWrite();
|
| - VLOG(1) << "Updated backup signature";
|
| -}
|
| -
|
| -bool ProtectedPrefsWatcher::IsSignatureValid() const {
|
| - DCHECK(HasBackup());
|
| - PrefService* prefs = profile_->GetPrefs();
|
| - std::string signed_data = GetSignatureData(prefs);
|
| - DCHECK(!signed_data.empty());
|
| - std::string signature;
|
| - if (!base::Base64Decode(prefs->GetString(kBackupSignature), &signature))
|
| - return false;
|
| - return IsSettingValid(signed_data, signature);
|
| -}
|
| -
|
| -void ProtectedPrefsWatcher::ValidateBackup() {
|
| - if (!HasBackup()) {
|
| - // Create initial backup entries and sign them.
|
| - InitBackup();
|
| - UMA_HISTOGRAM_ENUMERATION(
|
| - kProtectorHistogramPrefs,
|
| - kProtectorErrorValueValidZero,
|
| - kProtectorErrorCount);
|
| - } else if (IsSignatureValid()) {
|
| - MigrateOldBackupIfNeeded();
|
| - UMA_HISTOGRAM_ENUMERATION(
|
| - kProtectorHistogramPrefs,
|
| - kProtectorErrorValueValid,
|
| - kProtectorErrorCount);
|
| - } else {
|
| - LOG(WARNING) << "Invalid backup signature";
|
| - is_backup_valid_ = false;
|
| - // The whole backup has been compromised, overwrite it.
|
| - InitBackup();
|
| - UMA_HISTOGRAM_ENUMERATION(
|
| - kProtectorHistogramPrefs,
|
| - kProtectorErrorBackupInvalid,
|
| - kProtectorErrorCount);
|
| - }
|
| -}
|
| -
|
| -std::string ProtectedPrefsWatcher::GetSignatureData(PrefService* prefs) const {
|
| - int current_version = prefs->GetInteger(kBackupVersion);
|
| - // TODO(ivankr): replace this with some existing reliable serializer.
|
| - // JSONWriter isn't a good choice because JSON formatting may change suddenly.
|
| - std::string data = prefs->GetString(kBackupHomePage);
|
| - StringAppendBoolean(prefs, kBackupHomePageIsNewTabPage, &data);
|
| - StringAppendBoolean(prefs, kBackupShowHomeButton, &data);
|
| - StringAppendInteger(prefs, kBackupRestoreOnStartup, &data);
|
| - StringAppendStringList(prefs->GetList(kBackupURLsToRestoreOnStartup), &data);
|
| - StringAppendStringList(prefs->GetList(kBackupExtensionsIDs), &data);
|
| - if (current_version >= 2) {
|
| - // Version itself is included only since version 2 since it wasn't there
|
| - // in version 1.
|
| - base::StringAppendF(&data, "|v%d", current_version);
|
| - const base::ListValue* pinned_tabs = prefs->GetList(kBackupPinnedTabs);
|
| - for (base::ListValue::const_iterator it = pinned_tabs->begin();
|
| - it != pinned_tabs->end(); ++it) {
|
| - const base::DictionaryValue* tab = NULL;
|
| - if (!(*it)->GetAsDictionary(&tab)) {
|
| - NOTREACHED();
|
| - continue;
|
| - }
|
| - StringAppendStringDictionary(tab, &data);
|
| - }
|
| - }
|
| - return data;
|
| -}
|
| -
|
| -} // namespace protector
|
|
|