OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 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. |
| 4 |
| 5 #include "chrome/browser/protector/protected_prefs_watcher.h" |
| 6 |
| 7 #include "base/base64.h" |
| 8 #include "base/logging.h" |
| 9 #include "base/metrics/histogram.h" |
| 10 #include "base/stringprintf.h" |
| 11 #include "base/values.h" |
| 12 #include "chrome/browser/prefs/pref_service.h" |
| 13 #include "chrome/browser/prefs/pref_set_observer.h" |
| 14 #include "chrome/browser/prefs/scoped_user_pref_update.h" |
| 15 #include "chrome/browser/profiles/profile.h" |
| 16 #include "chrome/browser/protector/histograms.h" |
| 17 #include "chrome/browser/protector/protector_service.h" |
| 18 #include "chrome/common/chrome_notification_types.h" |
| 19 #include "chrome/common/pref_names.h" |
| 20 #include "content/public/browser/notification_service.h" |
| 21 |
| 22 namespace protector { |
| 23 |
| 24 namespace { |
| 25 |
| 26 const char kBackupPrefsPrefix[] = "backup."; |
| 27 |
| 28 // Backup pref names. |
| 29 const char kBackupHomePage[] = "backup.homepage"; |
| 30 const char kBackupHomePageIsNewTabPage[] = "backup.homepage_is_newtabpage"; |
| 31 const char kBackupShowHomeButton[] = "backup.browser.show_home_button"; |
| 32 const char kBackupRestoreOnStartup[] = "backup.session.restore_on_startup"; |
| 33 const char kBackupURLsToRestoreOnStartup[] = |
| 34 "backup.session.urls_to_restore_on_startup"; |
| 35 const char kBackupExtensionsIDs[] = "backup.extensions.ids"; |
| 36 const char kBackupSignature[] = "backup._signature"; |
| 37 |
| 38 } // namespace |
| 39 |
| 40 ProtectedPrefsWatcher::ProtectedPrefsWatcher(Profile* profile) |
| 41 : did_startup_settings_change_(false), |
| 42 profile_(profile) { |
| 43 pref_observer_.reset(PrefSetObserver::CreateProtectedPrefSetObserver( |
| 44 profile->GetPrefs(), this)); |
| 45 UpdateCachedPrefs(); |
| 46 if (!HasBackup()) { |
| 47 UpdateBackupSignature(); |
| 48 UMA_HISTOGRAM_ENUMERATION( |
| 49 kProtectorHistogramPrefs, |
| 50 kProtectorErrorValueValidZero, |
| 51 kProtectorErrorCount); |
| 52 } else if (IsSignatureValid()) { |
| 53 UMA_HISTOGRAM_ENUMERATION( |
| 54 kProtectorHistogramPrefs, |
| 55 kProtectorErrorValueValid, |
| 56 kProtectorErrorCount); |
| 57 } else { |
| 58 // Report an invalid signature. |
| 59 LOG(WARNING) << "Invalid backup signature"; |
| 60 UMA_HISTOGRAM_ENUMERATION( |
| 61 kProtectorHistogramPrefs, |
| 62 kProtectorErrorBackupInvalid, |
| 63 kProtectorErrorCount); |
| 64 } |
| 65 VLOG(1) << "Initialized pref watcher"; |
| 66 } |
| 67 |
| 68 ProtectedPrefsWatcher::~ProtectedPrefsWatcher() { |
| 69 } |
| 70 |
| 71 // static |
| 72 void ProtectedPrefsWatcher::RegisterUserPrefs(PrefService* prefs) { |
| 73 prefs->RegisterStringPref(kBackupHomePage, "", |
| 74 PrefService::UNSYNCABLE_PREF); |
| 75 prefs->RegisterBooleanPref(kBackupHomePageIsNewTabPage, false, |
| 76 PrefService::UNSYNCABLE_PREF); |
| 77 prefs->RegisterBooleanPref(kBackupShowHomeButton, false, |
| 78 PrefService::UNSYNCABLE_PREF); |
| 79 prefs->RegisterIntegerPref(kBackupRestoreOnStartup, 0, |
| 80 PrefService::UNSYNCABLE_PREF); |
| 81 prefs->RegisterListPref(kBackupURLsToRestoreOnStartup, |
| 82 PrefService::UNSYNCABLE_PREF); |
| 83 prefs->RegisterListPref(kBackupExtensionsIDs, |
| 84 PrefService::UNSYNCABLE_PREF); |
| 85 prefs->RegisterStringPref(kBackupSignature, "", |
| 86 PrefService::UNSYNCABLE_PREF); |
| 87 } |
| 88 |
| 89 void ProtectedPrefsWatcher::ValidatePrefs() { |
| 90 // TODO(ivankr): this is a stub that always updates the backup to match the |
| 91 // settings. Replace it with an actual check. |
| 92 UpdateBackupSignature(); |
| 93 } |
| 94 |
| 95 const base::Value* ProtectedPrefsWatcher::GetBackupForPref( |
| 96 const std::string& path) const { |
| 97 std::string backup_path = std::string(kBackupPrefsPrefix) + path; |
| 98 const PrefService::Preference* backup_pref = |
| 99 profile_->GetPrefs()->FindPreference(backup_path.c_str()); |
| 100 if (!backup_pref || backup_pref->IsDefaultValue() || |
| 101 // These do not directly correspond to any real preference. |
| 102 backup_path == kBackupExtensionsIDs || |
| 103 backup_path == kBackupSignature) { |
| 104 LOG(WARNING) << "No backup for pref: " << path; |
| 105 return NULL; |
| 106 } |
| 107 return backup_pref->GetValue(); |
| 108 } |
| 109 |
| 110 void ProtectedPrefsWatcher::Observe( |
| 111 int type, |
| 112 const content::NotificationSource& source, |
| 113 const content::NotificationDetails& details) { |
| 114 DCHECK(type == chrome::NOTIFICATION_PREF_CHANGED); |
| 115 const std::string* pref_name = content::Details<std::string>(details).ptr(); |
| 116 DCHECK(pref_name && pref_observer_->IsObserved(*pref_name)); |
| 117 // For changes in extension dictionary, do nothing if the IDs list remained |
| 118 // the same. |
| 119 if (*pref_name == ExtensionPrefs::kExtensionsPref && !UpdateCachedPrefs()) |
| 120 return; |
| 121 UpdateBackupSignature(); |
| 122 } |
| 123 |
| 124 bool ProtectedPrefsWatcher::UpdateCachedPrefs() { |
| 125 ExtensionPrefs::ExtensionIdSet extension_ids; |
| 126 // Direct access to the extensions prefs is required becase ExtensionService |
| 127 // may not yet have been initialized. |
| 128 ExtensionPrefs::GetExtensionsFrom( |
| 129 profile_->GetPrefs()->GetDictionary(ExtensionPrefs::kExtensionsPref), |
| 130 &extension_ids); |
| 131 if (extension_ids == cached_extension_ids_) |
| 132 return false; |
| 133 cached_extension_ids_.swap(extension_ids); |
| 134 return true; |
| 135 } |
| 136 |
| 137 void ProtectedPrefsWatcher::UpdateBackupSignature() { |
| 138 PrefService* prefs = profile_->GetPrefs(); |
| 139 // Copy actual settings into backup. |
| 140 prefs->SetString(kBackupHomePage, prefs->GetString(prefs::kHomePage)); |
| 141 prefs->SetBoolean(kBackupHomePageIsNewTabPage, |
| 142 prefs->GetBoolean(prefs::kHomePageIsNewTabPage)); |
| 143 prefs->SetBoolean(kBackupShowHomeButton, |
| 144 prefs->GetBoolean(prefs::kShowHomeButton)); |
| 145 prefs->SetInteger(kBackupRestoreOnStartup, |
| 146 prefs->GetInteger(prefs::kRestoreOnStartup)); |
| 147 prefs->Set(kBackupURLsToRestoreOnStartup, |
| 148 *prefs->GetList(prefs::kURLsToRestoreOnStartup)); |
| 149 { |
| 150 ListPrefUpdate extension_ids_update(prefs, kBackupExtensionsIDs); |
| 151 base::ListValue* extension_ids = extension_ids_update.Get(); |
| 152 extension_ids->Clear(); |
| 153 for (ExtensionPrefs::ExtensionIdSet::const_iterator it = |
| 154 cached_extension_ids_.begin(); |
| 155 it != cached_extension_ids_.end(); ++it) { |
| 156 extension_ids->Append(base::Value::CreateStringValue(*it)); |
| 157 } |
| 158 } |
| 159 // Update the signature. |
| 160 std::string signed_data = GetSignatureData(prefs); |
| 161 DCHECK(!signed_data.empty()); |
| 162 std::string signature = SignSetting(signed_data); |
| 163 DCHECK(!signature.empty()); |
| 164 std::string signature_base64; |
| 165 if (!base::Base64Encode(signature, &signature_base64)) |
| 166 NOTREACHED(); |
| 167 prefs->SetString(kBackupSignature, signature_base64); |
| 168 // Schedule disk write on FILE thread as soon as possible. |
| 169 prefs->CommitPendingWrite(); |
| 170 VLOG(1) << "Updated backup signature"; |
| 171 } |
| 172 |
| 173 bool ProtectedPrefsWatcher::IsSignatureValid() const { |
| 174 DCHECK(HasBackup()); |
| 175 PrefService* prefs = profile_->GetPrefs(); |
| 176 std::string signed_data = GetSignatureData(prefs); |
| 177 DCHECK(!signed_data.empty()); |
| 178 std::string signature; |
| 179 if (!base::Base64Decode(prefs->GetString(kBackupSignature), &signature)) |
| 180 return false; |
| 181 return IsSettingValid(signed_data, signature); |
| 182 } |
| 183 |
| 184 bool ProtectedPrefsWatcher::HasBackup() const { |
| 185 // TODO(ivankr): as soon as some irreversible change to Preferences happens, |
| 186 // add a condition that this change has occured as well (otherwise it's |
| 187 // possible to simply clear the "backup" dictionary to make settings |
| 188 // unprotected). |
| 189 return profile_->GetPrefs()->HasPrefPath(kBackupSignature); |
| 190 } |
| 191 |
| 192 std::string ProtectedPrefsWatcher::GetSignatureData(PrefService* prefs) const { |
| 193 // std::stringstream data; |
| 194 std::string data = base::StringPrintf( |
| 195 "%s|%d|%d|%d", |
| 196 prefs->GetString(kBackupHomePage).c_str(), |
| 197 prefs->GetBoolean(kBackupHomePageIsNewTabPage) ? 1 : 0, |
| 198 prefs->GetBoolean(kBackupShowHomeButton) ? 1 : 0, |
| 199 prefs->GetInteger(kBackupRestoreOnStartup)); |
| 200 const base::ListValue* startup_urls = |
| 201 prefs->GetList(kBackupURLsToRestoreOnStartup); |
| 202 for (base::ListValue::const_iterator it = startup_urls->begin(); |
| 203 it != startup_urls->end(); ++it) { |
| 204 std::string url; |
| 205 if (!(*it)->GetAsString(&url)) |
| 206 NOTREACHED(); |
| 207 base::StringAppendF(&data, "|%s", url.c_str()); |
| 208 } |
| 209 // These are safe to use becase they are always up-to-date and returned in |
| 210 // a consistent (sorted) order. |
| 211 for (ExtensionPrefs::ExtensionIdSet::const_iterator it = |
| 212 cached_extension_ids_.begin(); |
| 213 it != cached_extension_ids_.end(); ++it) { |
| 214 base::StringAppendF(&data, "|%s", it->c_str()); |
| 215 } |
| 216 return data; |
| 217 } |
| 218 |
| 219 } // namespace protector |
OLD | NEW |