| 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
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..78a4a1014224d90b1a021917a0fe2bf1b448ac87
|
| --- /dev/null
|
| +++ b/chrome/browser/protector/protected_prefs_watcher.cc
|
| @@ -0,0 +1,219 @@
|
| +// 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/logging.h"
|
| +#include "base/metrics/histogram.h"
|
| +#include "base/stringprintf.h"
|
| +#include "base/values.h"
|
| +#include "chrome/browser/prefs/pref_service.h"
|
| +#include "chrome/browser/prefs/pref_set_observer.h"
|
| +#include "chrome/browser/prefs/scoped_user_pref_update.h"
|
| +#include "chrome/browser/profiles/profile.h"
|
| +#include "chrome/browser/protector/histograms.h"
|
| +#include "chrome/browser/protector/protector_service.h"
|
| +#include "chrome/common/chrome_notification_types.h"
|
| +#include "chrome/common/pref_names.h"
|
| +#include "content/public/browser/notification_service.h"
|
| +
|
| +namespace protector {
|
| +
|
| +namespace {
|
| +
|
| +const char kBackupPrefsPrefix[] = "backup.";
|
| +
|
| +// 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 kBackupExtensionsIDs[] = "backup.extensions.ids";
|
| +const char kBackupSignature[] = "backup._signature";
|
| +
|
| +} // namespace
|
| +
|
| +ProtectedPrefsWatcher::ProtectedPrefsWatcher(Profile* profile)
|
| + : did_startup_settings_change_(false),
|
| + profile_(profile) {
|
| + pref_observer_.reset(PrefSetObserver::CreateProtectedPrefSetObserver(
|
| + profile->GetPrefs(), this));
|
| + UpdateCachedPrefs();
|
| + if (!HasBackup()) {
|
| + UpdateBackupSignature();
|
| + UMA_HISTOGRAM_ENUMERATION(
|
| + kProtectorHistogramPrefs,
|
| + kProtectorErrorValueValidZero,
|
| + kProtectorErrorCount);
|
| + } else if (IsSignatureValid()) {
|
| + UMA_HISTOGRAM_ENUMERATION(
|
| + kProtectorHistogramPrefs,
|
| + kProtectorErrorValueValid,
|
| + kProtectorErrorCount);
|
| + } else {
|
| + // Report an invalid signature.
|
| + LOG(WARNING) << "Invalid backup signature";
|
| + UMA_HISTOGRAM_ENUMERATION(
|
| + kProtectorHistogramPrefs,
|
| + kProtectorErrorBackupInvalid,
|
| + kProtectorErrorCount);
|
| + }
|
| + 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(kBackupExtensionsIDs,
|
| + PrefService::UNSYNCABLE_PREF);
|
| + prefs->RegisterStringPref(kBackupSignature, "",
|
| + PrefService::UNSYNCABLE_PREF);
|
| +}
|
| +
|
| +void ProtectedPrefsWatcher::ValidatePrefs() {
|
| + // TODO(ivankr): this is a stub that always updates the backup to match the
|
| + // settings. Replace it with an actual check.
|
| + UpdateBackupSignature();
|
| +}
|
| +
|
| +const base::Value* ProtectedPrefsWatcher::GetBackupForPref(
|
| + const std::string& path) const {
|
| + std::string backup_path = std::string(kBackupPrefsPrefix) + path;
|
| + const PrefService::Preference* backup_pref =
|
| + profile_->GetPrefs()->FindPreference(backup_path.c_str());
|
| + if (!backup_pref || backup_pref->IsDefaultValue() ||
|
| + // These do not directly correspond to any real preference.
|
| + backup_path == kBackupExtensionsIDs ||
|
| + backup_path == kBackupSignature) {
|
| + LOG(WARNING) << "No backup for pref: " << path;
|
| + return NULL;
|
| + }
|
| + return backup_pref->GetValue();
|
| +}
|
| +
|
| +void ProtectedPrefsWatcher::Observe(
|
| + int type,
|
| + const content::NotificationSource& source,
|
| + const content::NotificationDetails& details) {
|
| + DCHECK(type == chrome::NOTIFICATION_PREF_CHANGED);
|
| + const std::string* pref_name = content::Details<std::string>(details).ptr();
|
| + DCHECK(pref_name && pref_observer_->IsObserved(*pref_name));
|
| + // For changes in extension dictionary, do nothing if the IDs list remained
|
| + // the same.
|
| + if (*pref_name == ExtensionPrefs::kExtensionsPref && !UpdateCachedPrefs())
|
| + return;
|
| + UpdateBackupSignature();
|
| +}
|
| +
|
| +bool ProtectedPrefsWatcher::UpdateCachedPrefs() {
|
| + ExtensionPrefs::ExtensionIdSet extension_ids;
|
| + // Direct access to the extensions prefs is required becase ExtensionService
|
| + // may not yet have been initialized.
|
| + ExtensionPrefs::GetExtensionsFrom(
|
| + profile_->GetPrefs()->GetDictionary(ExtensionPrefs::kExtensionsPref),
|
| + &extension_ids);
|
| + if (extension_ids == cached_extension_ids_)
|
| + return false;
|
| + cached_extension_ids_.swap(extension_ids);
|
| + return true;
|
| +}
|
| +
|
| +void ProtectedPrefsWatcher::UpdateBackupSignature() {
|
| + PrefService* prefs = profile_->GetPrefs();
|
| + // Copy actual settings into backup.
|
| + prefs->SetString(kBackupHomePage, prefs->GetString(prefs::kHomePage));
|
| + prefs->SetBoolean(kBackupHomePageIsNewTabPage,
|
| + prefs->GetBoolean(prefs::kHomePageIsNewTabPage));
|
| + prefs->SetBoolean(kBackupShowHomeButton,
|
| + prefs->GetBoolean(prefs::kShowHomeButton));
|
| + prefs->SetInteger(kBackupRestoreOnStartup,
|
| + prefs->GetInteger(prefs::kRestoreOnStartup));
|
| + prefs->Set(kBackupURLsToRestoreOnStartup,
|
| + *prefs->GetList(prefs::kURLsToRestoreOnStartup));
|
| + {
|
| + ListPrefUpdate extension_ids_update(prefs, kBackupExtensionsIDs);
|
| + base::ListValue* extension_ids = extension_ids_update.Get();
|
| + extension_ids->Clear();
|
| + for (ExtensionPrefs::ExtensionIdSet::const_iterator it =
|
| + cached_extension_ids_.begin();
|
| + it != cached_extension_ids_.end(); ++it) {
|
| + extension_ids->Append(base::Value::CreateStringValue(*it));
|
| + }
|
| + }
|
| + // Update the signature.
|
| + 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);
|
| +}
|
| +
|
| +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);
|
| +}
|
| +
|
| +std::string ProtectedPrefsWatcher::GetSignatureData(PrefService* prefs) const {
|
| + // std::stringstream data;
|
| + std::string data = base::StringPrintf(
|
| + "%s|%d|%d|%d",
|
| + prefs->GetString(kBackupHomePage).c_str(),
|
| + prefs->GetBoolean(kBackupHomePageIsNewTabPage) ? 1 : 0,
|
| + prefs->GetBoolean(kBackupShowHomeButton) ? 1 : 0,
|
| + prefs->GetInteger(kBackupRestoreOnStartup));
|
| + const base::ListValue* startup_urls =
|
| + prefs->GetList(kBackupURLsToRestoreOnStartup);
|
| + for (base::ListValue::const_iterator it = startup_urls->begin();
|
| + it != startup_urls->end(); ++it) {
|
| + std::string url;
|
| + if (!(*it)->GetAsString(&url))
|
| + NOTREACHED();
|
| + base::StringAppendF(&data, "|%s", url.c_str());
|
| + }
|
| + // These are safe to use becase they are always up-to-date and returned in
|
| + // a consistent (sorted) order.
|
| + for (ExtensionPrefs::ExtensionIdSet::const_iterator it =
|
| + cached_extension_ids_.begin();
|
| + it != cached_extension_ids_.end(); ++it) {
|
| + base::StringAppendF(&data, "|%s", it->c_str());
|
| + }
|
| + return data;
|
| +}
|
| +
|
| +} // namespace protector
|
|
|