Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(267)

Side by Side Diff: chrome/browser/protector/protected_prefs_watcher.cc

Issue 11493003: Remove the protector service. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix implicit ExtensionSystem -> TemplateURLService dependency Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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/bind.h"
9 #include "base/logging.h"
10 #include "base/metrics/histogram.h"
11 #include "base/stringprintf.h"
12 #include "base/values.h"
13 #include "chrome/browser/extensions/extension_prefs.h"
14 #include "chrome/browser/prefs/pref_service.h"
15 #include "chrome/browser/prefs/scoped_user_pref_update.h"
16 #include "chrome/browser/prefs/session_startup_pref.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/protector/histograms.h"
19 #include "chrome/browser/protector/protector_utils.h"
20 #include "chrome/common/chrome_notification_types.h"
21 #include "chrome/common/pref_names.h"
22 #include "content/public/browser/notification_service.h"
23
24 using extensions::ExtensionPrefs;
25
26 namespace protector {
27
28 namespace {
29
30 // Prefix added to names of backup entries.
31 const char kBackupPrefsPrefix[] = "backup.";
32
33 // Names of prefs that are backed up.
34 const char* const kProtectedPrefNames[] = {
35 prefs::kHomePage,
36 prefs::kHomePageIsNewTabPage,
37 prefs::kShowHomeButton,
38 prefs::kRestoreOnStartup,
39 prefs::kURLsToRestoreOnStartup,
40 prefs::kPinnedTabs
41 };
42
43 // Backup pref names.
44 const char kBackupHomePage[] = "backup.homepage";
45 const char kBackupHomePageIsNewTabPage[] = "backup.homepage_is_newtabpage";
46 const char kBackupShowHomeButton[] = "backup.browser.show_home_button";
47 const char kBackupRestoreOnStartup[] = "backup.session.restore_on_startup";
48 const char kBackupURLsToRestoreOnStartup[] =
49 "backup.session.urls_to_restore_on_startup";
50 const char kBackupPinnedTabs[] = "backup.pinned_tabs";
51
52 // Special backup entries.
53 const char kBackupExtensionsIDs[] = "backup.extensions.ids";
54 const char kBackupSignature[] = "backup._signature";
55 const char kBackupVersion[] = "backup._version";
56
57 // Returns name of the backup entry for pref |pref_name|.
58 std::string GetBackupNameFor(const std::string& pref_name) {
59 return kBackupPrefsPrefix + pref_name;
60 }
61
62 // Appends a list of strings to |out|.
63 void StringAppendStringList(const base::ListValue* list, std::string* out) {
64 for (base::ListValue::const_iterator it = list->begin(); it != list->end();
65 ++it) {
66 std::string item;
67 if (!(*it)->GetAsString(&item))
68 NOTREACHED();
69 base::StringAppendF(out, "|%s", item.c_str());
70 }
71 }
72
73 // Appends a dictionary with string values to |out|.
74 void StringAppendStringDictionary(const base::DictionaryValue* dict,
75 std::string* out) {
76 for (base::DictionaryValue::Iterator it(*dict); it.HasNext(); it.Advance()) {
77 std::string value;
78 if (!it.value().GetAsString(&value))
79 NOTREACHED();
80 base::StringAppendF(out, "|%s|%s", it.key().c_str(), value.c_str());
81 }
82 }
83
84 void StringAppendBoolean(PrefService* prefs,
85 const char* path,
86 std::string* out) {
87 if (prefs->HasPrefPath(path))
88 base::StringAppendF(out, "|%d", prefs->GetBoolean(path) ? 1 : 0);
89 else
90 base::StringAppendF(out, "|");
91 }
92
93 void StringAppendInteger(PrefService* prefs,
94 const char* path,
95 std::string* out) {
96 if (prefs->HasPrefPath(path))
97 base::StringAppendF(out, "|%d", prefs->GetInteger(path));
98 else
99 base::StringAppendF(out, "|");
100 }
101
102 } // namespace
103
104 // static
105 const int ProtectedPrefsWatcher::kCurrentVersionNumber = 4;
106
107 ProtectedPrefsWatcher::ProtectedPrefsWatcher(Profile* profile)
108 : is_backup_valid_(true),
109 profile_(profile) {
110 // Perform necessary pref migrations before actually starting to observe
111 // pref changes, otherwise the migration would affect the backup data as well.
112 EnsurePrefsMigration();
113
114 pref_observer_.Init(profile->GetPrefs());
115 PrefChangeRegistrar::NamedChangeCallback callback = base::Bind(
116 &ProtectedPrefsWatcher::OnPreferenceChanged, base::Unretained(this));
117 pref_observer_.Add(prefs::kHomePageIsNewTabPage, callback);
118 pref_observer_.Add(prefs::kHomePage, callback);
119 pref_observer_.Add(prefs::kShowHomeButton, callback);
120 // Session startup.
121 pref_observer_.Add(prefs::kRestoreOnStartup, callback);
122 pref_observer_.Add(prefs::kURLsToRestoreOnStartup, callback);
123 // Pinned tabs.
124 pref_observer_.Add(prefs::kPinnedTabs, callback);
125 // Extensions.
126 pref_observer_.Add(ExtensionPrefs::kExtensionsPref, callback);
127
128 UpdateCachedPrefs();
129 ValidateBackup();
130 VLOG(1) << "Initialized pref watcher";
131 }
132
133 ProtectedPrefsWatcher::~ProtectedPrefsWatcher() {
134 }
135
136 // static
137 void ProtectedPrefsWatcher::RegisterUserPrefs(PrefService* prefs) {
138 prefs->RegisterStringPref(kBackupHomePage, "",
139 PrefService::UNSYNCABLE_PREF);
140 prefs->RegisterBooleanPref(kBackupHomePageIsNewTabPage, false,
141 PrefService::UNSYNCABLE_PREF);
142 prefs->RegisterBooleanPref(kBackupShowHomeButton, false,
143 PrefService::UNSYNCABLE_PREF);
144 prefs->RegisterIntegerPref(kBackupRestoreOnStartup, 0,
145 PrefService::UNSYNCABLE_PREF);
146 prefs->RegisterListPref(kBackupURLsToRestoreOnStartup,
147 PrefService::UNSYNCABLE_PREF);
148 prefs->RegisterListPref(kBackupPinnedTabs,
149 PrefService::UNSYNCABLE_PREF);
150 prefs->RegisterListPref(kBackupExtensionsIDs,
151 PrefService::UNSYNCABLE_PREF);
152 prefs->RegisterStringPref(kBackupSignature, "",
153 PrefService::UNSYNCABLE_PREF);
154 prefs->RegisterIntegerPref(kBackupVersion, 1,
155 PrefService::UNSYNCABLE_PREF);
156 }
157
158 bool ProtectedPrefsWatcher::DidPrefChange(const std::string& path) const {
159 std::string backup_path = GetBackupNameFor(path);
160 PrefService* prefs = profile_->GetPrefs();
161 const PrefService::Preference* new_pref = prefs->FindPreference(path.c_str());
162 DCHECK(new_pref);
163 const PrefService::Preference* backup_pref =
164 profile_->GetPrefs()->FindPreference(backup_path.c_str());
165 DCHECK(backup_pref);
166 if (new_pref->IsDefaultValue())
167 return !backup_pref->IsDefaultValue();
168 if (!new_pref->IsUserControlled())
169 return false;
170 return !backup_pref->GetValue()->Equals(new_pref->GetValue());
171 }
172
173 const base::Value* ProtectedPrefsWatcher::GetBackupForPref(
174 const std::string& path) const {
175 if (!is_backup_valid_)
176 return NULL;
177 std::string backup_path = GetBackupNameFor(path);
178 // These do not directly correspond to any real preference.
179 DCHECK(backup_path != kBackupExtensionsIDs &&
180 backup_path != kBackupSignature);
181 PrefService* prefs = profile_->GetPrefs();
182 // If backup is not set, return the default value of the actual pref.
183 // TODO(ivankr): return NULL instead and handle appropriately in SettingChange
184 // classes.
185 if (!prefs->HasPrefPath(backup_path.c_str()))
186 return prefs->GetDefaultPrefValue(path.c_str());
187 const PrefService::Preference* backup_pref =
188 profile_->GetPrefs()->FindPreference(backup_path.c_str());
189 DCHECK(backup_pref);
190 return backup_pref->GetValue();
191 }
192
193 void ProtectedPrefsWatcher::ForceUpdateBackup() {
194 UMA_HISTOGRAM_ENUMERATION(
195 kProtectorHistogramPrefs,
196 kProtectorErrorForcedUpdate,
197 kProtectorErrorCount);
198 InitBackup();
199 }
200
201 void ProtectedPrefsWatcher::OnPreferenceChanged(const std::string& pref_name) {
202 DCHECK(pref_observer_.IsObserved(pref_name));
203 if (UpdateBackupEntry(pref_name))
204 UpdateBackupSignature();
205 }
206
207 void ProtectedPrefsWatcher::EnsurePrefsMigration() {
208 SessionStartupPref::MigrateIfNecessary(profile_->GetPrefs());
209 }
210
211 bool ProtectedPrefsWatcher::UpdateCachedPrefs() {
212 // ExtensionService may not yet have been initialized, so using static method
213 // exposed for this purpose.
214 extensions::ExtensionIdList extension_ids =
215 ExtensionPrefs::GetExtensionsFrom(profile_->GetPrefs());
216 if (extension_ids == cached_extension_ids_)
217 return false;
218 cached_extension_ids_.swap(extension_ids);
219 return true;
220 }
221
222 bool ProtectedPrefsWatcher::HasBackup() const {
223 // TODO(ivankr): as soon as some irreversible change to Preferences happens,
224 // add a condition that this change has occured as well (otherwise it's
225 // possible to simply clear the "backup" dictionary to make settings
226 // unprotected).
227 return profile_->GetPrefs()->HasPrefPath(kBackupSignature);
228 }
229
230 void ProtectedPrefsWatcher::InitBackup() {
231 PrefService* prefs = profile_->GetPrefs();
232 for (size_t i = 0; i < arraysize(kProtectedPrefNames); ++i) {
233 const base::Value* user_value =
234 prefs->GetUserPrefValue(kProtectedPrefNames[i]);
235 if (user_value)
236 prefs->Set(GetBackupNameFor(kProtectedPrefNames[i]).c_str(), *user_value);
237 }
238 ListPrefUpdate extension_ids_update(prefs, kBackupExtensionsIDs);
239 base::ListValue* extension_ids = extension_ids_update.Get();
240 extension_ids->Clear();
241 for (extensions::ExtensionIdList::const_iterator it =
242 cached_extension_ids_.begin();
243 it != cached_extension_ids_.end(); ++it) {
244 extension_ids->Append(base::Value::CreateStringValue(*it));
245 }
246 prefs->SetInteger(kBackupVersion, kCurrentVersionNumber);
247 UpdateBackupSignature();
248 }
249
250 void ProtectedPrefsWatcher::MigrateOldBackupIfNeeded() {
251 PrefService* prefs = profile_->GetPrefs();
252
253 int current_version = prefs->GetInteger(kBackupVersion);
254 VLOG(1) << "Backup version: " << current_version;
255 if (current_version == kCurrentVersionNumber)
256 return;
257
258 switch (current_version) {
259 case 1: {
260 // Add pinned tabs.
261 const base::Value* pinned_tabs =
262 prefs->GetUserPrefValue(prefs::kPinnedTabs);
263 if (pinned_tabs)
264 prefs->Set(kBackupPinnedTabs, *pinned_tabs);
265 }
266 // FALL THROUGH
267
268 case 2:
269 // SessionStartupPref migration.
270 DCHECK(prefs->GetBoolean(prefs::kRestoreOnStartupMigrated));
271 prefs->SetInteger(kBackupRestoreOnStartup,
272 prefs->GetInteger(prefs::kRestoreOnStartup));
273 prefs->Set(kBackupURLsToRestoreOnStartup,
274 *prefs->GetList(prefs::kURLsToRestoreOnStartup));
275 // FALL THROUGH
276
277 case 3:
278 // Reset to default values backup prefs whose actual prefs are not set.
279 for (size_t i = 0; i < arraysize(kProtectedPrefNames); ++i) {
280 if (!prefs->HasPrefPath(kProtectedPrefNames[i]))
281 prefs->ClearPref(GetBackupNameFor(kProtectedPrefNames[i]).c_str());
282 }
283 // FALL THROUGH
284 }
285
286 prefs->SetInteger(kBackupVersion, kCurrentVersionNumber);
287 UpdateBackupSignature();
288 }
289
290 bool ProtectedPrefsWatcher::UpdateBackupEntry(const std::string& path) {
291 std::string backup_path = GetBackupNameFor(path);
292 PrefService* prefs = profile_->GetPrefs();
293 const PrefService::Preference* pref = prefs->FindPreference(path.c_str());
294 if (path == ExtensionPrefs::kExtensionsPref) {
295 // For changes in extension dictionary, do nothing if the IDs list remained
296 // the same.
297 if (!UpdateCachedPrefs())
298 return false;
299 ListPrefUpdate extension_ids_update(prefs, kBackupExtensionsIDs);
300 base::ListValue* extension_ids = extension_ids_update.Get();
301 extension_ids->Clear();
302 for (extensions::ExtensionIdList::const_iterator it =
303 cached_extension_ids_.begin();
304 it != cached_extension_ids_.end(); ++it) {
305 extension_ids->Append(base::Value::CreateStringValue(*it));
306 }
307 } else if (!prefs->HasPrefPath(path.c_str())) {
308 // Preference has been removed, remove the backup as well.
309 prefs->ClearPref(backup_path.c_str());
310 } else if (!pref->IsUserControlled()) {
311 return false;
312 } else {
313 prefs->Set(backup_path.c_str(), *pref->GetValue());
314 }
315 VLOG(1) << "Updated backup entry for: " << path;
316 return true;
317 }
318
319 void ProtectedPrefsWatcher::UpdateBackupSignature() {
320 PrefService* prefs = profile_->GetPrefs();
321 std::string signed_data = GetSignatureData(prefs);
322 DCHECK(!signed_data.empty());
323 std::string signature = SignSetting(signed_data);
324 DCHECK(!signature.empty());
325 std::string signature_base64;
326 if (!base::Base64Encode(signature, &signature_base64))
327 NOTREACHED();
328 prefs->SetString(kBackupSignature, signature_base64);
329 // Schedule disk write on FILE thread as soon as possible.
330 prefs->CommitPendingWrite();
331 VLOG(1) << "Updated backup signature";
332 }
333
334 bool ProtectedPrefsWatcher::IsSignatureValid() const {
335 DCHECK(HasBackup());
336 PrefService* prefs = profile_->GetPrefs();
337 std::string signed_data = GetSignatureData(prefs);
338 DCHECK(!signed_data.empty());
339 std::string signature;
340 if (!base::Base64Decode(prefs->GetString(kBackupSignature), &signature))
341 return false;
342 return IsSettingValid(signed_data, signature);
343 }
344
345 void ProtectedPrefsWatcher::ValidateBackup() {
346 if (!HasBackup()) {
347 // Create initial backup entries and sign them.
348 InitBackup();
349 UMA_HISTOGRAM_ENUMERATION(
350 kProtectorHistogramPrefs,
351 kProtectorErrorValueValidZero,
352 kProtectorErrorCount);
353 } else if (IsSignatureValid()) {
354 MigrateOldBackupIfNeeded();
355 UMA_HISTOGRAM_ENUMERATION(
356 kProtectorHistogramPrefs,
357 kProtectorErrorValueValid,
358 kProtectorErrorCount);
359 } else {
360 LOG(WARNING) << "Invalid backup signature";
361 is_backup_valid_ = false;
362 // The whole backup has been compromised, overwrite it.
363 InitBackup();
364 UMA_HISTOGRAM_ENUMERATION(
365 kProtectorHistogramPrefs,
366 kProtectorErrorBackupInvalid,
367 kProtectorErrorCount);
368 }
369 }
370
371 std::string ProtectedPrefsWatcher::GetSignatureData(PrefService* prefs) const {
372 int current_version = prefs->GetInteger(kBackupVersion);
373 // TODO(ivankr): replace this with some existing reliable serializer.
374 // JSONWriter isn't a good choice because JSON formatting may change suddenly.
375 std::string data = prefs->GetString(kBackupHomePage);
376 StringAppendBoolean(prefs, kBackupHomePageIsNewTabPage, &data);
377 StringAppendBoolean(prefs, kBackupShowHomeButton, &data);
378 StringAppendInteger(prefs, kBackupRestoreOnStartup, &data);
379 StringAppendStringList(prefs->GetList(kBackupURLsToRestoreOnStartup), &data);
380 StringAppendStringList(prefs->GetList(kBackupExtensionsIDs), &data);
381 if (current_version >= 2) {
382 // Version itself is included only since version 2 since it wasn't there
383 // in version 1.
384 base::StringAppendF(&data, "|v%d", current_version);
385 const base::ListValue* pinned_tabs = prefs->GetList(kBackupPinnedTabs);
386 for (base::ListValue::const_iterator it = pinned_tabs->begin();
387 it != pinned_tabs->end(); ++it) {
388 const base::DictionaryValue* tab = NULL;
389 if (!(*it)->GetAsDictionary(&tab)) {
390 NOTREACHED();
391 continue;
392 }
393 StringAppendStringDictionary(tab, &data);
394 }
395 }
396 return data;
397 }
398
399 } // namespace protector
OLDNEW
« no previous file with comments | « chrome/browser/protector/protected_prefs_watcher.h ('k') | chrome/browser/protector/protected_prefs_watcher_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698