1 // Copyright (c) 2011 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/extensions/extension_prefs.h"
6
7 #include "base/string_number_conversions.h"
8 #include "base/string_util.h"
9 #include "base/utf_string_conversions.h"
10 #include "chrome/browser/extensions/extension_pref_store.h"
11 #include "chrome/browser/prefs/pref_notifier.h"
12 #include "chrome/browser/prefs/scoped_user_pref_update.h"
13 #include "chrome/common/url_constants.h"
14 #include "chrome/common/extensions/extension.h"
15 #include "chrome/common/extensions/url_pattern.h"
16 #include "chrome/common/pref_names.h"
17 #include "content/common/notification_service.h"
18
19 using base::Time;
20
21 namespace {
22
23 // Additional preferences keys
24
25 // Where an extension was installed from. (see Extension::Location)
26 const char kPrefLocation[] = "location";
27
28 // Enabled, disabled, killed, etc. (see Extension::State)
29 const char kPrefState[] = "state";
30
31 // The path to the current version's manifest file.
32 const char kPrefPath[] = "path";
33
34 // The dictionary containing the extension's manifest.
35 const char kPrefManifest[] = "manifest";
36
37 // The version number.
38 const char kPrefVersion[] = "manifest.version";
39
40 // Indicates if an extension is blacklisted:
41 const char kPrefBlacklist[] = "blacklist";
42
43 // Indicates whether to show an install warning when the user enables.
44 const char kExtensionDidEscalatePermissions[] = "install_warning_on_enable";
45
46 // A preference that tracks browser action toolbar configuration. This is a list
47 // object stored in the Preferences file. The extensions are stored by ID.
48 const char kExtensionToolbar[] = "extensions.toolbar";
49
50 // The key for a serialized Time value indicating the start of the day (from the
51 // server's perspective) an extension last included a "ping" parameter during
52 // its update check.
53 const char kLastPingDay[] = "lastpingday";
54
55 // Similar to kLastPingDay, but for "active" instead of "rollcall" pings.
56 const char kLastActivePingDay[] = "last_active_pingday";
57
58 // A bit we use to keep track of whether we need to do an "active" ping.
59 const char kActiveBit[] = "active_bit";
60
61 // Path for settings specific to blacklist update.
62 const char kExtensionsBlacklistUpdate[] = "extensions.blacklistupdate";
63
64 // Path and sub-keys for the idle install info dictionary preference.
65 const char kIdleInstallInfo[] = "idle_install_info";
66 const char kIdleInstallInfoCrxPath[] = "crx_path";
67 const char kIdleInstallInfoVersion[] = "version";
68 const char kIdleInstallInfoFetchTime[] = "fetch_time";
69
70
71 // A preference that, if true, will allow this extension to run in incognito
72 // mode.
73 const char kPrefIncognitoEnabled[] = "incognito";
74
75 // A preference to control whether an extension is allowed to inject script in
76 // pages with file URLs.
77 const char kPrefAllowFileAccess[] = "allowFileAccess";
78
79 // A preference set by the web store to indicate login information for
80 // purchased apps.
81 const char kWebStoreLogin[] = "extensions.webstore_login";
82
83 // A preference set by the the NTP to persist the desired launch container type
84 // used for apps.
85 const char kPrefLaunchType[] = "launchType";
86
87 // A preference determining the order of which the apps appear on the NTP.
88 const char kPrefAppLaunchIndex[] = "app_launcher_index";
89
90 // A preference determining the page on which an app appears in the NTP.
91 const char kPrefPageIndex[] = "page_index";
92
93 // A preference specifying if the user dragged the app on the NTP.
94 const char kPrefUserDraggedApp[] = "user_dragged_app_ntp";
95
96 // A preference for storing extra data sent in update checks for an extension.
97 const char kUpdateUrlData[] = "update_url_data";
98
99 // Whether the browser action is visible in the toolbar.
100 const char kBrowserActionVisible[] = "browser_action_visible";
101
102 // Preferences that hold which permissions the user has granted the extension.
103 // We explicitly keep track of these so that extensions can contain unknown
104 // permissions, for backwards compatibility reasons, and we can still prompt
105 // the user to accept them once recognized.
106 const char kPrefGrantedPermissionsAPI[] = "granted_permissions.api";
107 const char kPrefGrantedPermissionsHost[] = "granted_permissions.host";
108 const char kPrefGrantedPermissionsAll[] = "granted_permissions.full";
109
110 // A preference that indicates when an extension was installed.
111 const char kPrefInstallTime[] = "install_time";
112
113 // A preference that contains any extension-controlled preferences.
114 const char kPrefPreferences[] = "preferences";
115
116 // Provider of write access to a dictionary storing extension prefs.
117 class ScopedExtensionPrefUpdate : public DictionaryPrefUpdate {
118 public:
ScopedExtensionPrefUpdate(PrefService * service,const std::string & extension_id)119 ScopedExtensionPrefUpdate(PrefService* service,
120 const std::string& extension_id) :
121 DictionaryPrefUpdate(service, ExtensionPrefs::kExtensionsPref),
122 extension_id_(extension_id) {}
~ScopedExtensionPrefUpdate()123 virtual ~ScopedExtensionPrefUpdate() {}
Get()124 virtual DictionaryValue* Get() {
125 DictionaryValue* dict = DictionaryPrefUpdate::Get();
126 DictionaryValue* extension = NULL;
127 if (!dict->GetDictionary(extension_id_, &extension)) {
128 // Extension pref does not exist, create it.
129 extension = new DictionaryValue();
130 dict->Set(extension_id_, extension);
131 }
132 return extension;
133 }
134
135 private:
136 const std::string extension_id_;
137
138 DISALLOW_COPY_AND_ASSIGN(ScopedExtensionPrefUpdate);
139 };
140
141 // Provider of write access to a dictionary storing extension controlled prefs.
142 class ScopedExtensionControlledPrefUpdate : public DictionaryPrefUpdate {
143 public:
ScopedExtensionControlledPrefUpdate(PrefService * service,const std::string & extension_id)144 ScopedExtensionControlledPrefUpdate(PrefService* service,
145 const std::string& extension_id) :
146 DictionaryPrefUpdate(service, ExtensionPrefs::kExtensionsPref),
147 extension_id_(extension_id) {}
~ScopedExtensionControlledPrefUpdate()148 virtual ~ScopedExtensionControlledPrefUpdate() {}
Get()149 virtual DictionaryValue* Get() {
150 DictionaryValue* dict = DictionaryPrefUpdate::Get();
151 DictionaryValue* preferences = NULL;
152 std::string key = extension_id_ + std::string(".") + kPrefPreferences;
153 if (!dict->GetDictionary(key, &preferences)) {
154 preferences = new DictionaryValue;
155 dict->Set(key, preferences);
156 }
157 return preferences;
158 }
159
160 private:
161 const std::string extension_id_;
162
163 DISALLOW_COPY_AND_ASSIGN(ScopedExtensionControlledPrefUpdate);
164 };
165
166 // TODO(mihaip): This is cleanup code for keys for unpacked extensions (which
167 // are derived from paths). As part of the wstring removal, we changed the way
168 // we hash paths, so we need to move prefs from their old synthesized IDs to
169 // their new ones. We can remove this by July 2011. (See http://crbug.com/75945
170 // for more details).
CleanupBadExtensionKeys(const FilePath & root_dir,PrefService * prefs)171 static void CleanupBadExtensionKeys(const FilePath& root_dir,
172 PrefService* prefs) {
173 const DictionaryValue* dictionary =
174 prefs->GetDictionary(ExtensionPrefs::kExtensionsPref);
175 std::map<std::string, std::string> remapped_keys;
176 for (DictionaryValue::key_iterator i = dictionary->begin_keys();
177 i != dictionary->end_keys(); ++i) {
178 DictionaryValue* ext;
179 if (!dictionary->GetDictionaryWithoutPathExpansion(*i, &ext))
180 continue;
181
182 int location;
183 FilePath::StringType path_str;
184 if (!ext->GetInteger(kPrefLocation, &location) ||
185 !ext->GetString(kPrefPath, &path_str)) {
186 continue;
187 }
188
189 // Only unpacked extensions have generated IDs.
190 if (location != Extension::LOAD)
191 continue;
192
193 const std::string& prefs_id(*i);
194 FilePath path(path_str);
195 // The persisted path can be relative to the root dir (see
196 // MakePath(s)Relative), but the ID is generated before that, using the
197 // absolute path, so we need to undo that.
198 if (!path.IsAbsolute()) {
199 path = root_dir.Append(path);
200 }
201 std::string computed_id = Extension::GenerateIdForPath(path);
202
203 if (prefs_id != computed_id) {
204 remapped_keys[prefs_id] = computed_id;
205 }
206 }
207
208 if (!remapped_keys.empty()) {
209 DictionaryPrefUpdate update(prefs, ExtensionPrefs::kExtensionsPref);
210 DictionaryValue* update_dictionary = update.Get();
211 for (std::map<std::string, std::string>::const_iterator i =
212 remapped_keys.begin();
213 i != remapped_keys.end();
214 ++i) {
215 // Don't clobber prefs under the correct ID if they already exist.
216 if (update_dictionary->HasKey(i->second)) {
217 CHECK(update_dictionary->RemoveWithoutPathExpansion(i->first, NULL));
218 continue;
219 }
220 Value* extension_prefs = NULL;
221 CHECK(update_dictionary->RemoveWithoutPathExpansion(
222 i->first, &extension_prefs));
223 update_dictionary->SetWithoutPathExpansion(i->second, extension_prefs);
224 }
225
226 prefs->ScheduleSavePersistentPrefs();
227 }
228 }
229
ExtentToStringSet(const ExtensionExtent & host_extent,std::set<std::string> * result)230 static void ExtentToStringSet(const ExtensionExtent& host_extent,
231 std::set<std::string>* result) {
232 ExtensionExtent::PatternList patterns = host_extent.patterns();
233 ExtensionExtent::PatternList::const_iterator i;
234
235 for (i = patterns.begin(); i != patterns.end(); ++i)
236 result->insert(i->GetAsString());
237 }
238
239 } // namespace
240
ExtensionPrefs(PrefService * prefs,const FilePath & root_dir,ExtensionPrefValueMap * extension_pref_value_map)241 ExtensionPrefs::ExtensionPrefs(
242 PrefService* prefs,
243 const FilePath& root_dir,
244 ExtensionPrefValueMap* extension_pref_value_map)
245 : prefs_(prefs),
246 install_directory_(root_dir),
247 extension_pref_value_map_(extension_pref_value_map) {
248 // TODO(mihaip): Remove this by July 2011 (see comment above).
249 CleanupBadExtensionKeys(root_dir, prefs_);
250
251 MakePathsRelative();
252
253 InitPrefStore();
254 }
255
~ExtensionPrefs()256 ExtensionPrefs::~ExtensionPrefs() {}
257
258 // static
259 const char ExtensionPrefs::kExtensionsPref[] = "extensions.settings";
260
MakePathRelative(const FilePath & parent,const FilePath & child)261 static FilePath::StringType MakePathRelative(const FilePath& parent,
262 const FilePath& child) {
263 if (!parent.IsParent(child))
264 return child.value();
265
266 FilePath::StringType retval = child.value().substr(
267 parent.value().length());
268 if (FilePath::IsSeparator(retval[0]))
269 return retval.substr(1);
270 else
271 return retval;
272 }
273
MakePathsRelative()274 void ExtensionPrefs::MakePathsRelative() {
275 const DictionaryValue* dict = prefs_->GetDictionary(kExtensionsPref);
276 if (!dict || dict->empty())
277 return;
278
279 // Collect all extensions ids with absolute paths in |absolute_keys|.
280 std::set<std::string> absolute_keys;
281 for (DictionaryValue::key_iterator i = dict->begin_keys();
282 i != dict->end_keys(); ++i) {
283 DictionaryValue* extension_dict = NULL;
284 if (!dict->GetDictionaryWithoutPathExpansion(*i, &extension_dict))
285 continue;
286 int location_value;
287 if (extension_dict->GetInteger(kPrefLocation, &location_value) &&
288 location_value == Extension::LOAD) {
289 // Unpacked extensions can have absolute paths.
290 continue;
291 }
292 FilePath::StringType path_string;
293 if (!extension_dict->GetString(kPrefPath, &path_string))
294 continue;
295 FilePath path(path_string);
296 if (path.IsAbsolute())
297 absolute_keys.insert(*i);
298 }
299 if (absolute_keys.empty())
300 return;
301
302 // Fix these paths.
303 DictionaryPrefUpdate update(prefs_, kExtensionsPref);
304 const DictionaryValue* update_dict = update.Get();
305 for (std::set<std::string>::iterator i = absolute_keys.begin();
306 i != absolute_keys.end(); ++i) {
307 DictionaryValue* extension_dict = NULL;
308 update_dict->GetDictionaryWithoutPathExpansion(*i, &extension_dict);
309 FilePath::StringType path_string;
310 extension_dict->GetString(kPrefPath, &path_string);
311 FilePath path(path_string);
312 extension_dict->SetString(kPrefPath,
313 MakePathRelative(install_directory_, path));
314 }
315 SavePrefs();
316 }
317
MakePathsAbsolute(DictionaryValue * dict)318 void ExtensionPrefs::MakePathsAbsolute(DictionaryValue* dict) {
319 if (!dict || dict->empty())
320 return;
321
322 for (DictionaryValue::key_iterator i = dict->begin_keys();
323 i != dict->end_keys(); ++i) {
324 DictionaryValue* extension_dict = NULL;
325 if (!dict->GetDictionaryWithoutPathExpansion(*i, &extension_dict)) {
326 NOTREACHED();
327 continue;
328 }
329
330 int location_value;
331 if (extension_dict->GetInteger(kPrefLocation, &location_value) &&
332 location_value == Extension::LOAD) {
333 // Unpacked extensions will already have absolute paths.
334 continue;
335 }
336
337 FilePath::StringType path_string;
338 if (!extension_dict->GetString(kPrefPath, &path_string))
339 continue;
340
341 DCHECK(!FilePath(path_string).IsAbsolute());
342 extension_dict->SetString(
343 kPrefPath, install_directory_.Append(path_string).value());
344 }
345 }
346
CopyCurrentExtensions()347 DictionaryValue* ExtensionPrefs::CopyCurrentExtensions() {
348 const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref);
349 if (extensions) {
350 DictionaryValue* copy = extensions->DeepCopy();
351 MakePathsAbsolute(copy);
352 return copy;
353 }
354 return new DictionaryValue;
355 }
356
ReadBooleanFromPref(const DictionaryValue * ext,const std::string & pref_key)357 bool ExtensionPrefs::ReadBooleanFromPref(
358 const DictionaryValue* ext, const std::string& pref_key) {
359 bool bool_value = false;
360 if (!ext->GetBoolean(pref_key, &bool_value))
361 return false;
362
363 return bool_value;
364 }
365
ReadExtensionPrefBoolean(const std::string & extension_id,const std::string & pref_key)366 bool ExtensionPrefs::ReadExtensionPrefBoolean(
367 const std::string& extension_id, const std::string& pref_key) {
368 const DictionaryValue* ext = GetExtensionPref(extension_id);
369 if (!ext) {
370 // No such extension yet.
371 return false;
372 }
373 return ReadBooleanFromPref(ext, pref_key);
374 }
375
ReadIntegerFromPref(const DictionaryValue * ext,const std::string & pref_key,int * out_value)376 bool ExtensionPrefs::ReadIntegerFromPref(
377 const DictionaryValue* ext, const std::string& pref_key, int* out_value) {
378 if (!ext->GetInteger(pref_key, out_value))
379 return false;
380
381 return out_value != NULL;
382 }
383
ReadExtensionPrefInteger(const std::string & extension_id,const std::string & pref_key,int * out_value)384 bool ExtensionPrefs::ReadExtensionPrefInteger(
385 const std::string& extension_id, const std::string& pref_key,
386 int* out_value) {
387 const DictionaryValue* ext = GetExtensionPref(extension_id);
388 if (!ext) {
389 // No such extension yet.
390 return false;
391 }
392 return ReadIntegerFromPref(ext, pref_key, out_value);
393 }
394
ReadExtensionPrefList(const std::string & extension_id,const std::string & pref_key,const ListValue ** out_value)395 bool ExtensionPrefs::ReadExtensionPrefList(
396 const std::string& extension_id, const std::string& pref_key,
397 const ListValue** out_value) {
398 const DictionaryValue* ext = GetExtensionPref(extension_id);
399 ListValue* out = NULL;
400 if (!ext || !ext->GetList(pref_key, &out))
401 return false;
402 *out_value = out;
403
404 return out_value != NULL;
405 }
406
ReadExtensionPrefStringSet(const std::string & extension_id,const std::string & pref_key,std::set<std::string> * result)407 bool ExtensionPrefs::ReadExtensionPrefStringSet(
408 const std::string& extension_id,
409 const std::string& pref_key,
410 std::set<std::string>* result) {
411 const ListValue* value = NULL;
412 if (!ReadExtensionPrefList(extension_id, pref_key, &value))
413 return false;
414
415 result->clear();
416
417 for (size_t i = 0; i < value->GetSize(); ++i) {
418 std::string item;
419 if (!value->GetString(i, &item))
420 return false;
421 result->insert(item);
422 }
423
424 return true;
425 }
426
AddToExtensionPrefStringSet(const std::string & extension_id,const std::string & pref_key,const std::set<std::string> & added_value)427 void ExtensionPrefs::AddToExtensionPrefStringSet(
428 const std::string& extension_id,
429 const std::string& pref_key,
430 const std::set<std::string>& added_value) {
431 std::set<std::string> old_value;
432 std::set<std::string> new_value;
433 ReadExtensionPrefStringSet(extension_id, pref_key, &old_value);
434
435 std::set_union(old_value.begin(), old_value.end(),
436 added_value.begin(), added_value.end(),
437 std::inserter(new_value, new_value.begin()));
438
439 ListValue* value = new ListValue();
440 for (std::set<std::string>::const_iterator iter = new_value.begin();
441 iter != new_value.end(); ++iter)
442 value->Append(Value::CreateStringValue(*iter));
443
444 UpdateExtensionPref(extension_id, pref_key, value);
445 prefs_->ScheduleSavePersistentPrefs();
446 }
447
SavePrefs()448 void ExtensionPrefs::SavePrefs() {
449 prefs_->ScheduleSavePersistentPrefs();
450 }
451
IsBlacklistBitSet(DictionaryValue * ext)452 bool ExtensionPrefs::IsBlacklistBitSet(DictionaryValue* ext) {
453 return ReadBooleanFromPref(ext, kPrefBlacklist);
454 }
455
IsExtensionBlacklisted(const std::string & extension_id)456 bool ExtensionPrefs::IsExtensionBlacklisted(const std::string& extension_id) {
457 return ReadExtensionPrefBoolean(extension_id, kPrefBlacklist);
458 }
459
IsExtensionAllowedByPolicy(const std::string & extension_id)460 bool ExtensionPrefs::IsExtensionAllowedByPolicy(
461 const std::string& extension_id) {
462 std::string string_value;
463
464 const ListValue* blacklist =
465 prefs_->GetList(prefs::kExtensionInstallDenyList);
466 if (!blacklist || blacklist->empty())
467 return true;
468
469 // Check the whitelist first.
470 const ListValue* whitelist =
471 prefs_->GetList(prefs::kExtensionInstallAllowList);
472 if (whitelist) {
473 for (ListValue::const_iterator it = whitelist->begin();
474 it != whitelist->end(); ++it) {
475 if (!(*it)->GetAsString(&string_value))
476 LOG(WARNING) << "Failed to read whitelist string.";
477 else if (string_value == extension_id)
478 return true;
479 }
480 }
481
482 // Then check the blacklist (the admin blacklist, not the Google blacklist).
483 if (blacklist) {
484 for (ListValue::const_iterator it = blacklist->begin();
485 it != blacklist->end(); ++it) {
486 if (!(*it)->GetAsString(&string_value)) {
487 LOG(WARNING) << "Failed to read blacklist string.";
488 } else {
489 if (string_value == "*")
490 return false; // Only whitelisted extensions are allowed.
491 if (string_value == extension_id)
492 return false;
493 }
494 }
495 }
496
497 return true;
498 }
499
DidExtensionEscalatePermissions(const std::string & extension_id)500 bool ExtensionPrefs::DidExtensionEscalatePermissions(
501 const std::string& extension_id) {
502 return ReadExtensionPrefBoolean(extension_id,
503 kExtensionDidEscalatePermissions);
504 }
505
SetDidExtensionEscalatePermissions(const Extension * extension,bool did_escalate)506 void ExtensionPrefs::SetDidExtensionEscalatePermissions(
507 const Extension* extension, bool did_escalate) {
508 UpdateExtensionPref(extension->id(), kExtensionDidEscalatePermissions,
509 Value::CreateBooleanValue(did_escalate));
510 prefs_->ScheduleSavePersistentPrefs();
511 }
512
UpdateBlacklist(const std::set<std::string> & blacklist_set)513 void ExtensionPrefs::UpdateBlacklist(
514 const std::set<std::string>& blacklist_set) {
515 std::vector<std::string> remove_pref_ids;
516 std::set<std::string> used_id_set;
517 const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref);
518
519 if (extensions) {
520 for (DictionaryValue::key_iterator extension_id = extensions->begin_keys();
521 extension_id != extensions->end_keys(); ++extension_id) {
522 DictionaryValue* ext;
523 if (!extensions->GetDictionaryWithoutPathExpansion(*extension_id, &ext)) {
524 NOTREACHED() << "Invalid pref for extension " << *extension_id;
525 continue;
526 }
527 const std::string& id(*extension_id);
528 if (blacklist_set.find(id) == blacklist_set.end()) {
529 if (!IsBlacklistBitSet(ext)) {
530 // This extension is not in blacklist. And it was not blacklisted
531 // before.
532 continue;
533 } else {
534 if (ext->size() == 1) {
535 // We should remove the entry if the only flag here is blacklist.
536 remove_pref_ids.push_back(id);
537 } else {
538 // Remove the blacklist bit.
539 ext->Remove(kPrefBlacklist, NULL);
540 }
541 }
542 } else {
543 if (!IsBlacklistBitSet(ext)) {
544 // Only set the blacklist if it was not set.
545 ext->SetBoolean(kPrefBlacklist, true);
546 }
547 // Keep the record if this extension is already processed.
548 used_id_set.insert(id);
549 }
550 }
551 }
552
553 // Iterate the leftovers to set blacklist in pref
554 std::set<std::string>::const_iterator set_itr = blacklist_set.begin();
555 for (; set_itr != blacklist_set.end(); ++set_itr) {
556 if (used_id_set.find(*set_itr) == used_id_set.end()) {
557 UpdateExtensionPref(*set_itr, kPrefBlacklist,
558 Value::CreateBooleanValue(true));
559 }
560 }
561 for (unsigned int i = 0; i < remove_pref_ids.size(); ++i) {
562 DeleteExtensionPrefs(remove_pref_ids[i]);
563 }
564 SavePrefs();
565 return;
566 }
567
568 namespace {
569
570 // Serializes |time| as a string value mapped to |key| in |dictionary|.
SaveTime(DictionaryValue * dictionary,const char * key,const Time & time)571 void SaveTime(DictionaryValue* dictionary, const char* key, const Time& time) {
572 if (!dictionary)
573 return;
574 std::string string_value = base::Int64ToString(time.ToInternalValue());
575 dictionary->SetString(key, string_value);
576 }
577
578 // The opposite of SaveTime. If |key| is not found, this returns an empty Time
579 // (is_null() will return true).
ReadTime(const DictionaryValue * dictionary,const char * key)580 Time ReadTime(const DictionaryValue* dictionary, const char* key) {
581 if (!dictionary)
582 return Time();
583 std::string string_value;
584 int64 value;
585 if (dictionary->GetString(key, &string_value)) {
586 if (base::StringToInt64(string_value, &value)) {
587 return Time::FromInternalValue(value);
588 }
589 }
590 return Time();
591 }
592
593 } // namespace
594
LastPingDay(const std::string & extension_id) const595 Time ExtensionPrefs::LastPingDay(const std::string& extension_id) const {
596 DCHECK(Extension::IdIsValid(extension_id));
597 return ReadTime(GetExtensionPref(extension_id), kLastPingDay);
598 }
599
SetLastPingDay(const std::string & extension_id,const Time & time)600 void ExtensionPrefs::SetLastPingDay(const std::string& extension_id,
601 const Time& time) {
602 DCHECK(Extension::IdIsValid(extension_id));
603 ScopedExtensionPrefUpdate update(prefs_, extension_id);
604 SaveTime(update.Get(), kLastPingDay, time);
605 }
606
BlacklistLastPingDay() const607 Time ExtensionPrefs::BlacklistLastPingDay() const {
608 return ReadTime(prefs_->GetDictionary(kExtensionsBlacklistUpdate),
609 kLastPingDay);
610 }
611
SetBlacklistLastPingDay(const Time & time)612 void ExtensionPrefs::SetBlacklistLastPingDay(const Time& time) {
613 DictionaryPrefUpdate update(prefs_, kExtensionsBlacklistUpdate);
614 SaveTime(update.Get(), kLastPingDay, time);
615 }
616
LastActivePingDay(const std::string & extension_id)617 Time ExtensionPrefs::LastActivePingDay(const std::string& extension_id) {
618 DCHECK(Extension::IdIsValid(extension_id));
619 return ReadTime(GetExtensionPref(extension_id), kLastActivePingDay);
620 }
621
SetLastActivePingDay(const std::string & extension_id,const base::Time & time)622 void ExtensionPrefs::SetLastActivePingDay(const std::string& extension_id,
623 const base::Time& time) {
624 DCHECK(Extension::IdIsValid(extension_id));
625 ScopedExtensionPrefUpdate update(prefs_, extension_id);
626 SaveTime(update.Get(), kLastActivePingDay, time);
627 }
628
GetActiveBit(const std::string & extension_id)629 bool ExtensionPrefs::GetActiveBit(const std::string& extension_id) {
630 const DictionaryValue* dictionary = GetExtensionPref(extension_id);
631 bool result = false;
632 if (dictionary && dictionary->GetBoolean(kActiveBit, &result))
633 return result;
634 return false;
635 }
636
SetActiveBit(const std::string & extension_id,bool active)637 void ExtensionPrefs::SetActiveBit(const std::string& extension_id,
638 bool active) {
639 ScopedExtensionPrefUpdate update(prefs_, extension_id);
640 update.Get()->SetBoolean(kActiveBit, active);
641 }
642
GetGrantedPermissions(const std::string & extension_id,bool * full_access,std::set<std::string> * api_permissions,ExtensionExtent * host_extent)643 bool ExtensionPrefs::GetGrantedPermissions(
644 const std::string& extension_id,
645 bool* full_access,
646 std::set<std::string>* api_permissions,
647 ExtensionExtent* host_extent) {
648 CHECK(Extension::IdIsValid(extension_id));
649
650 const DictionaryValue* ext = GetExtensionPref(extension_id);
651 if (!ext || !ext->GetBoolean(kPrefGrantedPermissionsAll, full_access))
652 return false;
653
654 ReadExtensionPrefStringSet(
655 extension_id, kPrefGrantedPermissionsAPI, api_permissions);
656
657 std::set<std::string> host_permissions;
658 ReadExtensionPrefStringSet(
659 extension_id, kPrefGrantedPermissionsHost, &host_permissions);
660 bool allow_file_access = AllowFileAccess(extension_id);
661
662 // The granted host permissions contain hosts from the manifest's
663 // "permissions" array and from the content script "matches" arrays,
664 // so the URLPattern needs to accept valid schemes from both types.
665 for (std::set<std::string>::iterator i = host_permissions.begin();
666 i != host_permissions.end(); ++i) {
667 URLPattern pattern(
668 Extension::kValidHostPermissionSchemes |
669 UserScript::kValidUserScriptSchemes);
670
671 // Parse without strict checks, so that new strict checks do not
672 // fail on a pattern in an installed extension.
673 if (URLPattern::PARSE_SUCCESS != pattern.Parse(
674 *i, URLPattern::PARSE_LENIENT)) {
675 NOTREACHED(); // Corrupt prefs? Hand editing?
676 } else {
677 if (!allow_file_access && pattern.MatchesScheme(chrome::kFileScheme)) {
678 pattern.set_valid_schemes(
679 pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
680 }
681 host_extent->AddPattern(pattern);
682 }
683 }
684
685 return true;
686 }
687
AddGrantedPermissions(const std::string & extension_id,const bool full_access,const std::set<std::string> & api_permissions,const ExtensionExtent & host_extent)688 void ExtensionPrefs::AddGrantedPermissions(
689 const std::string& extension_id,
690 const bool full_access,
691 const std::set<std::string>& api_permissions,
692 const ExtensionExtent& host_extent) {
693 CHECK(Extension::IdIsValid(extension_id));
694
695 UpdateExtensionPref(extension_id, kPrefGrantedPermissionsAll,
696 Value::CreateBooleanValue(full_access));
697
698 if (!api_permissions.empty()) {
699 AddToExtensionPrefStringSet(
700 extension_id, kPrefGrantedPermissionsAPI, api_permissions);
701 }
702
703 if (!host_extent.is_empty()) {
704 std::set<std::string> host_permissions;
705 ExtentToStringSet(host_extent, &host_permissions);
706
707 AddToExtensionPrefStringSet(
708 extension_id, kPrefGrantedPermissionsHost, host_permissions);
709 }
710
711 SavePrefs();
712 }
713
IsIncognitoEnabled(const std::string & extension_id)714 bool ExtensionPrefs::IsIncognitoEnabled(const std::string& extension_id) {
715 return ReadExtensionPrefBoolean(extension_id, kPrefIncognitoEnabled);
716 }
717
SetIsIncognitoEnabled(const std::string & extension_id,bool enabled)718 void ExtensionPrefs::SetIsIncognitoEnabled(const std::string& extension_id,
719 bool enabled) {
720 UpdateExtensionPref(extension_id, kPrefIncognitoEnabled,
721 Value::CreateBooleanValue(enabled));
722 SavePrefs();
723 }
724
AllowFileAccess(const std::string & extension_id)725 bool ExtensionPrefs::AllowFileAccess(const std::string& extension_id) {
726 return ReadExtensionPrefBoolean(extension_id, kPrefAllowFileAccess);
727 }
728
SetAllowFileAccess(const std::string & extension_id,bool allow)729 void ExtensionPrefs::SetAllowFileAccess(const std::string& extension_id,
730 bool allow) {
731 UpdateExtensionPref(extension_id, kPrefAllowFileAccess,
732 Value::CreateBooleanValue(allow));
733 SavePrefs();
734 }
735
HasAllowFileAccessSetting(const std::string & extension_id) const736 bool ExtensionPrefs::HasAllowFileAccessSetting(
737 const std::string& extension_id) const {
738 const DictionaryValue* ext = GetExtensionPref(extension_id);
739 return ext && ext->HasKey(kPrefAllowFileAccess);
740 }
741
GetLaunchType(const std::string & extension_id,ExtensionPrefs::LaunchType default_pref_value)742 ExtensionPrefs::LaunchType ExtensionPrefs::GetLaunchType(
743 const std::string& extension_id,
744 ExtensionPrefs::LaunchType default_pref_value) {
745 int value = -1;
746 LaunchType result = LAUNCH_REGULAR;
747
748 if (ReadExtensionPrefInteger(extension_id, kPrefLaunchType, &value) &&
749 (value == LAUNCH_PINNED ||
750 value == LAUNCH_REGULAR ||
751 value == LAUNCH_FULLSCREEN ||
752 value == LAUNCH_WINDOW)) {
753 result = static_cast<LaunchType>(value);
754 } else {
755 result = default_pref_value;
756 }
757 #if defined(OS_MACOSX)
758 // App windows are not yet supported on mac. Pref sync could make
759 // the launch type LAUNCH_WINDOW, even if there is no UI to set it
760 // on mac.
761 if (result == LAUNCH_WINDOW)
762 result = LAUNCH_REGULAR;
763 #endif
764
765 return result;
766 }
767
GetLaunchContainer(const Extension * extension,ExtensionPrefs::LaunchType default_pref_value)768 extension_misc::LaunchContainer ExtensionPrefs::GetLaunchContainer(
769 const Extension* extension,
770 ExtensionPrefs::LaunchType default_pref_value) {
771 extension_misc::LaunchContainer manifest_launch_container =
772 extension->launch_container();
773
774 const extension_misc::LaunchContainer kInvalidLaunchContainer =
775 static_cast<extension_misc::LaunchContainer>(-1);
776
777 extension_misc::LaunchContainer result = kInvalidLaunchContainer;
778
779 if (manifest_launch_container == extension_misc::LAUNCH_PANEL) {
780 // Apps with app.launch.container = 'panel' should always
781 // open in a panel.
782 result = extension_misc::LAUNCH_PANEL;
783
784 } else if (manifest_launch_container == extension_misc::LAUNCH_TAB) {
785 // Look for prefs that indicate the user's choice of launch
786 // container. The app's menu on the NTP provides a UI to set
787 // this preference. If no preference is set, |default_pref_value|
788 // is used.
789 ExtensionPrefs::LaunchType prefs_launch_type =
790 GetLaunchType(extension->id(), default_pref_value);
791
792 if (prefs_launch_type == ExtensionPrefs::LAUNCH_WINDOW) {
793 // If the pref is set to launch a window (or no pref is set, and
794 // window opening is the default), make the container a window.
795 result = extension_misc::LAUNCH_WINDOW;
796
797 } else {
798 // All other launch types (tab, pinned, fullscreen) are
799 // implemented as tabs in a window.
800 result = extension_misc::LAUNCH_TAB;
801 }
802 } else {
803 // If a new value for app.launch.container is added, logic
804 // for it should be added here. extension_misc::LAUNCH_WINDOW
805 // is not present because there is no way to set it in a manifest.
806 NOTREACHED() << manifest_launch_container;
807 }
808
809 // All paths should set |result|.
810 if (result == kInvalidLaunchContainer) {
811 DLOG(FATAL) << "Failed to set a launch container.";
812 result = extension_misc::LAUNCH_TAB;
813 }
814
815 return result;
816 }
817
SetLaunchType(const std::string & extension_id,LaunchType launch_type)818 void ExtensionPrefs::SetLaunchType(const std::string& extension_id,
819 LaunchType launch_type) {
820 UpdateExtensionPref(extension_id, kPrefLaunchType,
821 Value::CreateIntegerValue(static_cast<int>(launch_type)));
822 SavePrefs();
823 }
824
IsExternalExtensionUninstalled(const std::string & id) const825 bool ExtensionPrefs::IsExternalExtensionUninstalled(
826 const std::string& id) const {
827 const DictionaryValue* extension = GetExtensionPref(id);
828 if (!extension)
829 return false;
830 int state = 0;
831 return extension->GetInteger(kPrefState, &state) &&
832 state == static_cast<int>(Extension::EXTERNAL_EXTENSION_UNINSTALLED);
833 }
834
GetToolbarOrder()835 std::vector<std::string> ExtensionPrefs::GetToolbarOrder() {
836 ExtensionPrefs::ExtensionIdSet extension_ids;
837 const ListValue* toolbar_order = prefs_->GetList(kExtensionToolbar);
838 if (toolbar_order) {
839 for (size_t i = 0; i < toolbar_order->GetSize(); ++i) {
840 std::string extension_id;
841 if (toolbar_order->GetString(i, &extension_id))
842 extension_ids.push_back(extension_id);
843 }
844 }
845 return extension_ids;
846 }
847
SetToolbarOrder(const std::vector<std::string> & extension_ids)848 void ExtensionPrefs::SetToolbarOrder(
849 const std::vector<std::string>& extension_ids) {
850 ListPrefUpdate update(prefs_, kExtensionToolbar);
851 ListValue* toolbar_order = update.Get();
852 toolbar_order->Clear();
853 for (std::vector<std::string>::const_iterator iter = extension_ids.begin();
854 iter != extension_ids.end(); ++iter) {
855 toolbar_order->Append(new StringValue(*iter));
856 }
857 SavePrefs();
858 }
859
OnExtensionInstalled(const Extension * extension,Extension::State initial_state,bool initial_incognito_enabled)860 void ExtensionPrefs::OnExtensionInstalled(
861 const Extension* extension, Extension::State initial_state,
862 bool initial_incognito_enabled) {
863 const std::string& id = extension->id();
864 CHECK(Extension::IdIsValid(id));
865 ScopedExtensionPrefUpdate update(prefs_, id);
866 DictionaryValue* extension_dict = update.Get();
867 const base::Time install_time = GetCurrentTime();
868 extension_dict->Set(kPrefState, Value::CreateIntegerValue(initial_state));
869 extension_dict->Set(kPrefIncognitoEnabled,
870 Value::CreateBooleanValue(initial_incognito_enabled));
871 extension_dict->Set(kPrefLocation,
872 Value::CreateIntegerValue(extension->location()));
873 extension_dict->Set(kPrefInstallTime,
874 Value::CreateStringValue(
875 base::Int64ToString(install_time.ToInternalValue())));
876 extension_dict->Set(kPrefPreferences, new DictionaryValue());
877
878 FilePath::StringType path = MakePathRelative(install_directory_,
879 extension->path());
880 extension_dict->Set(kPrefPath, Value::CreateStringValue(path));
881 // We store prefs about LOAD extensions, but don't cache their manifest
882 // since it may change on disk.
883 if (extension->location() != Extension::LOAD) {
884 extension_dict->Set(kPrefManifest,
885 extension->manifest_value()->DeepCopy());
886 }
887 extension_dict->Set(kPrefAppLaunchIndex,
888 Value::CreateIntegerValue(GetNextAppLaunchIndex()));
889 extension_pref_value_map_->RegisterExtension(
890 id, install_time, initial_state == Extension::ENABLED);
891 SavePrefs();
892 }
893
OnExtensionUninstalled(const std::string & extension_id,const Extension::Location & location,bool external_uninstall)894 void ExtensionPrefs::OnExtensionUninstalled(const std::string& extension_id,
895 const Extension::Location& location,
896 bool external_uninstall) {
897 // For external extensions, we save a preference reminding ourself not to try
898 // and install the extension anymore (except when |external_uninstall| is
899 // true, which signifies that the registry key was deleted or the pref file
900 // no longer lists the extension).
901 if (!external_uninstall && Extension::IsExternalLocation(location)) {
902 UpdateExtensionPref(extension_id, kPrefState,
903 Value::CreateIntegerValue(
904 Extension::EXTERNAL_EXTENSION_UNINSTALLED));
905 SavePrefs();
906 extension_pref_value_map_->SetExtensionState(extension_id, false);
907 } else {
908 DeleteExtensionPrefs(extension_id);
909 }
910 }
911
GetExtensionState(const std::string & extension_id) const912 Extension::State ExtensionPrefs::GetExtensionState(
913 const std::string& extension_id) const {
914 const DictionaryValue* extension = GetExtensionPref(extension_id);
915
916 // If the extension doesn't have a pref, it's a --load-extension.
917 if (!extension)
918 return Extension::ENABLED;
919
920 int state = -1;
921 if (!extension->GetInteger(kPrefState, &state) ||
922 state < 0 || state >= Extension::NUM_STATES) {
923 LOG(ERROR) << "Bad or missing pref 'state' for extension '"
924 << extension_id << "'";
925 return Extension::ENABLED;
926 }
927 return static_cast<Extension::State>(state);
928 }
929
SetExtensionState(const Extension * extension,Extension::State state)930 void ExtensionPrefs::SetExtensionState(const Extension* extension,
931 Extension::State state) {
932 UpdateExtensionPref(extension->id(), kPrefState,
933 Value::CreateIntegerValue(state));
934 SavePrefs();
935
936 bool enabled = (state == Extension::ENABLED);
937 extension_pref_value_map_->SetExtensionState(extension->id(), enabled);
938 }
939
GetBrowserActionVisibility(const Extension * extension)940 bool ExtensionPrefs::GetBrowserActionVisibility(const Extension* extension) {
941 const DictionaryValue* extension_prefs = GetExtensionPref(extension->id());
942 if (!extension_prefs)
943 return true;
944 bool visible = false;
945 if (!extension_prefs->GetBoolean(kBrowserActionVisible, &visible) || visible)
946 return true;
947
948 return false;
949 }
950
SetBrowserActionVisibility(const Extension * extension,bool visible)951 void ExtensionPrefs::SetBrowserActionVisibility(const Extension* extension,
952 bool visible) {
953 if (GetBrowserActionVisibility(extension) == visible)
954 return;
955
956 UpdateExtensionPref(extension->id(), kBrowserActionVisible,
957 Value::CreateBooleanValue(visible));
958 SavePrefs();
959
960 NotificationService::current()->Notify(
961 NotificationType::EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
962 Source<ExtensionPrefs>(this),
963 Details<const Extension>(extension));
964 }
965
GetVersionString(const std::string & extension_id)966 std::string ExtensionPrefs::GetVersionString(const std::string& extension_id) {
967 const DictionaryValue* extension = GetExtensionPref(extension_id);
968 if (!extension)
969 return std::string();
970
971 std::string version;
972 if (!extension->GetString(kPrefVersion, &version)) {
973 LOG(ERROR) << "Bad or missing pref 'version' for extension '"
974 << extension_id << "'";
975 }
976
977 return version;
978 }
979
UpdateManifest(const Extension * extension)980 void ExtensionPrefs::UpdateManifest(const Extension* extension) {
981 if (extension->location() != Extension::LOAD) {
982 const DictionaryValue* extension_dict = GetExtensionPref(extension->id());
983 if (!extension_dict)
984 return;
985 DictionaryValue* old_manifest = NULL;
986 bool update_required =
987 !extension_dict->GetDictionary(kPrefManifest, &old_manifest) ||
988 !extension->manifest_value()->Equals(old_manifest);
989 if (update_required) {
990 UpdateExtensionPref(extension->id(), kPrefManifest,
991 extension->manifest_value()->DeepCopy());
992 }
993 SavePrefs();
994 }
995 }
996
GetExtensionPath(const std::string & extension_id)997 FilePath ExtensionPrefs::GetExtensionPath(const std::string& extension_id) {
998 const DictionaryValue* dict = prefs_->GetDictionary(kExtensionsPref);
999 if (!dict || dict->empty())
1000 return FilePath();
1001
1002 std::string path;
1003 if (!dict->GetString(extension_id + "." + kPrefPath, &path))
1004 return FilePath();
1005
1006 return install_directory_.Append(FilePath::FromWStringHack(UTF8ToWide(path)));
1007 }
1008
UpdateExtensionPref(const std::string & extension_id,const std::string & key,Value * data_value)1009 void ExtensionPrefs::UpdateExtensionPref(const std::string& extension_id,
1010 const std::string& key,
1011 Value* data_value) {
1012 if (!Extension::IdIsValid(extension_id)) {
1013 NOTREACHED() << "Invalid extension_id " << extension_id;
1014 return;
1015 }
1016 ScopedExtensionPrefUpdate update(prefs_, extension_id);
1017 DictionaryValue* extension = update.Get();
1018 extension->Set(key, data_value);
1019 }
1020
DeleteExtensionPrefs(const std::string & extension_id)1021 void ExtensionPrefs::DeleteExtensionPrefs(const std::string& extension_id) {
1022 DictionaryPrefUpdate update(prefs_, kExtensionsPref);
1023 DictionaryValue* dict = update.Get();
1024 if (dict->HasKey(extension_id)) {
1025 dict->Remove(extension_id, NULL);
1026 SavePrefs();
1027 }
1028 extension_pref_value_map_->UnregisterExtension(extension_id);
1029 }
1030
GetExtensionPref(const std::string & extension_id) const1031 const DictionaryValue* ExtensionPrefs::GetExtensionPref(
1032 const std::string& extension_id) const {
1033 const DictionaryValue* dict = prefs_->GetDictionary(kExtensionsPref);
1034 if (!dict)
1035 return NULL;
1036 DictionaryValue* extension = NULL;
1037 dict->GetDictionary(extension_id, &extension);
1038 return extension;
1039 }
1040
1041 // Helper function for GetInstalledExtensionsInfo.
GetInstalledExtensionInfoImpl(DictionaryValue * extension_data,DictionaryValue::key_iterator extension_id)1042 static ExtensionInfo* GetInstalledExtensionInfoImpl(
1043 DictionaryValue* extension_data,
1044 DictionaryValue::key_iterator extension_id) {
1045 DictionaryValue* ext;
1046 if (!extension_data->GetDictionaryWithoutPathExpansion(*extension_id, &ext)) {
1047 LOG(WARNING) << "Invalid pref for extension " << *extension_id;
1048 NOTREACHED();
1049 return NULL;
1050 }
1051 if (ext->HasKey(kPrefBlacklist)) {
1052 bool is_blacklisted = false;
1053 if (!ext->GetBoolean(kPrefBlacklist, &is_blacklisted)) {
1054 NOTREACHED() << "Invalid blacklist pref:" << *extension_id;
1055 return NULL;
1056 }
1057 if (is_blacklisted) {
1058 return NULL;
1059 }
1060 }
1061 int state_value;
1062 if (!ext->GetInteger(kPrefState, &state_value)) {
1063 // This can legitimately happen if we store preferences for component
1064 // extensions.
1065 return NULL;
1066 }
1067 if (state_value == Extension::EXTERNAL_EXTENSION_UNINSTALLED) {
1068 LOG(WARNING) << "External extension with id " << *extension_id
1069 << " has been uninstalled by the user";
1070 return NULL;
1071 }
1072 FilePath::StringType path;
1073 if (!ext->GetString(kPrefPath, &path)) {
1074 return NULL;
1075 }
1076 int location_value;
1077 if (!ext->GetInteger(kPrefLocation, &location_value)) {
1078 return NULL;
1079 }
1080
1081 // Only the following extension types can be installed permanently in the
1082 // preferences.
1083 Extension::Location location =
1084 static_cast<Extension::Location>(location_value);
1085 if (location != Extension::INTERNAL &&
1086 location != Extension::LOAD &&
1087 !Extension::IsExternalLocation(location)) {
1088 NOTREACHED();
1089 return NULL;
1090 }
1091
1092 DictionaryValue* manifest = NULL;
1093 if (location != Extension::LOAD &&
1094 !ext->GetDictionary(kPrefManifest, &manifest)) {
1095 LOG(WARNING) << "Missing manifest for extension " << *extension_id;
1096 // Just a warning for now.
1097 }
1098
1099 return new ExtensionInfo(manifest, *extension_id, FilePath(path), location);
1100 }
1101
GetInstalledExtensionsInfo()1102 ExtensionPrefs::ExtensionsInfo* ExtensionPrefs::GetInstalledExtensionsInfo() {
1103 scoped_ptr<DictionaryValue> extension_data(CopyCurrentExtensions());
1104
1105 ExtensionsInfo* extensions_info = new ExtensionsInfo;
1106
1107 for (DictionaryValue::key_iterator extension_id(
1108 extension_data->begin_keys());
1109 extension_id != extension_data->end_keys(); ++extension_id) {
1110 if (!Extension::IdIsValid(*extension_id))
1111 continue;
1112
1113 ExtensionInfo* info = GetInstalledExtensionInfoImpl(extension_data.get(),
1114 extension_id);
1115 if (info)
1116 extensions_info->push_back(linked_ptr<ExtensionInfo>(info));
1117 }
1118
1119 return extensions_info;
1120 }
1121
GetInstalledExtensionInfo(const std::string & extension_id)1122 ExtensionInfo* ExtensionPrefs::GetInstalledExtensionInfo(
1123 const std::string& extension_id) {
1124 scoped_ptr<DictionaryValue> extension_data(CopyCurrentExtensions());
1125
1126 for (DictionaryValue::key_iterator extension_iter(
1127 extension_data->begin_keys());
1128 extension_iter != extension_data->end_keys(); ++extension_iter) {
1129 if (*extension_iter == extension_id) {
1130 return GetInstalledExtensionInfoImpl(extension_data.get(),
1131 extension_iter);
1132 }
1133 }
1134
1135 return NULL;
1136 }
1137
SetIdleInstallInfo(const std::string & extension_id,const FilePath & crx_path,const std::string & version,const base::Time & fetch_time)1138 void ExtensionPrefs::SetIdleInstallInfo(const std::string& extension_id,
1139 const FilePath& crx_path,
1140 const std::string& version,
1141 const base::Time& fetch_time) {
1142 ScopedExtensionPrefUpdate update(prefs_, extension_id);
1143 DictionaryValue* extension_prefs = update.Get();
1144 if (!extension_prefs) {
1145 NOTREACHED();
1146 return;
1147 }
1148 extension_prefs->Remove(kIdleInstallInfo, NULL);
1149 DictionaryValue* info = new DictionaryValue();
1150 info->SetString(kIdleInstallInfoCrxPath, crx_path.value());
1151 info->SetString(kIdleInstallInfoVersion, version);
1152 info->SetString(kIdleInstallInfoFetchTime,
1153 base::Int64ToString(fetch_time.ToInternalValue()));
1154 extension_prefs->Set(kIdleInstallInfo, info);
1155 SavePrefs();
1156 }
1157
RemoveIdleInstallInfo(const std::string & extension_id)1158 bool ExtensionPrefs::RemoveIdleInstallInfo(const std::string& extension_id) {
1159 if (!GetExtensionPref(extension_id))
1160 return false;
1161 ScopedExtensionPrefUpdate update(prefs_, extension_id);
1162 DictionaryValue* extension_prefs = update.Get();
1163 bool result = extension_prefs->Remove(kIdleInstallInfo, NULL);
1164 SavePrefs();
1165 return result;
1166 }
1167
GetIdleInstallInfo(const std::string & extension_id,FilePath * crx_path,std::string * version,base::Time * fetch_time)1168 bool ExtensionPrefs::GetIdleInstallInfo(const std::string& extension_id,
1169 FilePath* crx_path,
1170 std::string* version,
1171 base::Time* fetch_time) {
1172 const DictionaryValue* extension_prefs = GetExtensionPref(extension_id);
1173 if (!extension_prefs)
1174 return false;
1175
1176 // Do all the reads from the prefs together, and don't do any assignment
1177 // to the out parameters unless all the reads succeed.
1178 DictionaryValue* info = NULL;
1179 if (!extension_prefs->GetDictionary(kIdleInstallInfo, &info))
1180 return false;
1181
1182 FilePath::StringType path_string;
1183 if (!info->GetString(kIdleInstallInfoCrxPath, &path_string))
1184 return false;
1185
1186 std::string tmp_version;
1187 if (!info->GetString(kIdleInstallInfoVersion, &tmp_version))
1188 return false;
1189
1190 std::string fetch_time_string;
1191 if (!info->GetString(kIdleInstallInfoFetchTime, &fetch_time_string))
1192 return false;
1193
1194 int64 fetch_time_value;
1195 if (!base::StringToInt64(fetch_time_string, &fetch_time_value))
1196 return false;
1197
1198 if (crx_path)
1199 *crx_path = FilePath(path_string);
1200
1201 if (version)
1202 *version = tmp_version;
1203
1204 if (fetch_time)
1205 *fetch_time = base::Time::FromInternalValue(fetch_time_value);
1206
1207 return true;
1208 }
1209
GetIdleInstallInfoIds()1210 std::set<std::string> ExtensionPrefs::GetIdleInstallInfoIds() {
1211 std::set<std::string> result;
1212
1213 const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref);
1214 if (!extensions)
1215 return result;
1216
1217 for (DictionaryValue::key_iterator iter = extensions->begin_keys();
1218 iter != extensions->end_keys(); ++iter) {
1219 const std::string& id(*iter);
1220 if (!Extension::IdIsValid(id)) {
1221 NOTREACHED();
1222 continue;
1223 }
1224
1225 const DictionaryValue* extension_prefs = GetExtensionPref(id);
1226 if (!extension_prefs)
1227 continue;
1228
1229 if (extension_prefs->GetDictionary(kIdleInstallInfo, NULL))
1230 result.insert(id);
1231 }
1232 return result;
1233 }
1234
GetWebStoreLogin(std::string * result)1235 bool ExtensionPrefs::GetWebStoreLogin(std::string* result) {
1236 if (prefs_->HasPrefPath(kWebStoreLogin)) {
1237 *result = prefs_->GetString(kWebStoreLogin);
1238 return true;
1239 }
1240 return false;
1241 }
1242
SetWebStoreLogin(const std::string & login)1243 void ExtensionPrefs::SetWebStoreLogin(const std::string& login) {
1244 prefs_->SetString(kWebStoreLogin, login);
1245 SavePrefs();
1246 }
1247
GetAppLaunchIndex(const std::string & extension_id)1248 int ExtensionPrefs::GetAppLaunchIndex(const std::string& extension_id) {
1249 int value;
1250 if (ReadExtensionPrefInteger(extension_id, kPrefAppLaunchIndex, &value))
1251 return value;
1252
1253 return -1;
1254 }
1255
SetAppLaunchIndex(const std::string & extension_id,int index)1256 void ExtensionPrefs::SetAppLaunchIndex(const std::string& extension_id,
1257 int index) {
1258 DCHECK_GE(index, 0);
1259 UpdateExtensionPref(extension_id, kPrefAppLaunchIndex,
1260 Value::CreateIntegerValue(index));
1261 SavePrefs();
1262 }
1263
GetNextAppLaunchIndex()1264 int ExtensionPrefs::GetNextAppLaunchIndex() {
1265 const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref);
1266 if (!extensions)
1267 return 0;
1268
1269 int max_value = -1;
1270 for (DictionaryValue::key_iterator extension_id = extensions->begin_keys();
1271 extension_id != extensions->end_keys(); ++extension_id) {
1272 int value = GetAppLaunchIndex(*extension_id);
1273 if (value > max_value)
1274 max_value = value;
1275 }
1276 return max_value + 1;
1277 }
1278
SetAppLauncherOrder(const std::vector<std::string> & extension_ids)1279 void ExtensionPrefs::SetAppLauncherOrder(
1280 const std::vector<std::string>& extension_ids) {
1281 for (size_t i = 0; i < extension_ids.size(); ++i)
1282 SetAppLaunchIndex(extension_ids.at(i), i);
1283
1284 NotificationService::current()->Notify(
1285 NotificationType::EXTENSION_LAUNCHER_REORDERED,
1286 Source<ExtensionPrefs>(this),
1287 NotificationService::NoDetails());
1288 }
1289
GetPageIndex(const std::string & extension_id)1290 int ExtensionPrefs::GetPageIndex(const std::string& extension_id) {
1291 int value;
1292 if (ReadExtensionPrefInteger(extension_id, kPrefPageIndex, &value))
1293 return value;
1294
1295 return -1;
1296 }
1297
SetPageIndex(const std::string & extension_id,int index)1298 void ExtensionPrefs::SetPageIndex(const std::string& extension_id, int index) {
1299 CHECK_GE(index, 0);
1300 UpdateExtensionPref(extension_id, kPrefPageIndex,
1301 Value::CreateIntegerValue(index));
1302 SavePrefs();
1303 }
1304
WasAppDraggedByUser(const std::string & extension_id)1305 bool ExtensionPrefs::WasAppDraggedByUser(const std::string& extension_id) {
1306 const DictionaryValue* dictionary = GetExtensionPref(extension_id);
1307 if (!dictionary) {
1308 NOTREACHED();
1309 return false;
1310 }
1311
1312 return ReadBooleanFromPref(dictionary, kPrefUserDraggedApp);
1313 }
1314
SetAppDraggedByUser(const std::string & extension_id)1315 void ExtensionPrefs::SetAppDraggedByUser(const std::string& extension_id) {
1316 if (!GetExtensionPref(extension_id)) {
1317 NOTREACHED();
1318 return;
1319 }
1320
1321 ScopedExtensionPrefUpdate update(prefs_, extension_id);
1322 DictionaryValue* dictionary = update.Get();
1323 dictionary->SetBoolean(kPrefUserDraggedApp, true);
1324 SavePrefs();
1325 }
1326
SetUpdateUrlData(const std::string & extension_id,const std::string & data)1327 void ExtensionPrefs::SetUpdateUrlData(const std::string& extension_id,
1328 const std::string& data) {
1329 if (!GetExtensionPref(extension_id)) {
1330 NOTREACHED();
1331 return;
1332 }
1333
1334 ScopedExtensionPrefUpdate update(prefs_, extension_id);
1335 DictionaryValue* dictionary = update.Get();
1336 dictionary->SetString(kUpdateUrlData, data);
1337 SavePrefs();
1338 }
1339
GetUpdateUrlData(const std::string & extension_id)1340 std::string ExtensionPrefs::GetUpdateUrlData(const std::string& extension_id) {
1341 const DictionaryValue* dictionary = GetExtensionPref(extension_id);
1342 if (!dictionary)
1343 return std::string();
1344
1345 std::string data;
1346 dictionary->GetString(kUpdateUrlData, &data);
1347 return data;
1348 }
1349
GetCurrentTime() const1350 base::Time ExtensionPrefs::GetCurrentTime() const {
1351 return base::Time::Now();
1352 }
1353
GetInstallTime(const std::string & extension_id) const1354 base::Time ExtensionPrefs::GetInstallTime(
1355 const std::string& extension_id) const {
1356 const DictionaryValue* extension = GetExtensionPref(extension_id);
1357 if (!extension) {
1358 NOTREACHED();
1359 return base::Time();
1360 }
1361 std::string install_time_str;
1362 if (!extension->GetString(kPrefInstallTime, &install_time_str))
1363 return base::Time();
1364 int64 install_time_i64 = 0;
1365 if (!base::StringToInt64(install_time_str, &install_time_i64))
1366 return base::Time();
1367 return base::Time::FromInternalValue(install_time_i64);
1368 }
1369
GetExtensions(ExtensionIdSet * out)1370 void ExtensionPrefs::GetExtensions(ExtensionIdSet* out) {
1371 CHECK(out);
1372
1373 scoped_ptr<ExtensionsInfo> extensions_info(GetInstalledExtensionsInfo());
1374
1375 for (size_t i = 0; i < extensions_info->size(); ++i) {
1376 ExtensionInfo* info = extensions_info->at(i).get();
1377 out->push_back(info->extension_id);
1378 }
1379 }
1380
FixMissingPrefs(const ExtensionIdSet & extension_ids)1381 void ExtensionPrefs::FixMissingPrefs(const ExtensionIdSet& extension_ids) {
1382 // Fix old entries that did not get an installation time entry when they
1383 // were installed or don't have a preferences field.
1384 bool persist_required = false;
1385 for (ExtensionIdSet::const_iterator ext_id = extension_ids.begin();
1386 ext_id != extension_ids.end(); ++ext_id) {
1387 if (GetInstallTime(*ext_id) == base::Time()) {
1388 LOG(INFO) << "Could not parse installation time of extension "
1389 << *ext_id << ". It was probably installed before setting "
1390 << kPrefInstallTime << " was introduced. Updating "
1391 << kPrefInstallTime << " to the current time.";
1392 const base::Time install_time = GetCurrentTime();
1393 ScopedExtensionPrefUpdate update(prefs_, *ext_id);
1394 DictionaryValue* extension = update.Get();
1395 extension->Set(kPrefInstallTime,
1396 Value::CreateStringValue(
1397 base::Int64ToString(install_time.ToInternalValue())));
1398 persist_required = true;
1399 }
1400 }
1401 if (persist_required)
1402 SavePrefs();
1403 }
1404
GetExtensionControlledPrefs(const std::string & extension_id) const1405 const DictionaryValue* ExtensionPrefs::GetExtensionControlledPrefs(
1406 const std::string& extension_id) const {
1407 std::string key = extension_id + std::string(".") + kPrefPreferences;
1408 DictionaryValue* preferences = NULL;
1409 // First try the regular lookup.
1410 {
1411 const DictionaryValue* source_dict = prefs_->GetDictionary(kExtensionsPref);
1412 if (source_dict->GetDictionary(key, &preferences))
1413 return preferences;
1414 }
1415 // And then create a dictionary if it did not exist before.
1416 {
1417 DictionaryPrefUpdate update(prefs_, kExtensionsPref);
1418 update.Get()->Set(key, new DictionaryValue);
1419 }
1420 const DictionaryValue* source_dict = prefs_->GetDictionary(kExtensionsPref);
1421 source_dict->GetDictionary(key, &preferences);
1422 return preferences;
1423 }
1424
InitPrefStore()1425 void ExtensionPrefs::InitPrefStore() {
1426 // When this is called, the PrefService is initialized and provides access
1427 // to the user preferences stored in a JSON file.
1428 ExtensionIdSet extension_ids;
1429 GetExtensions(&extension_ids);
1430 // Create empty preferences dictionary for each extension (these dictionaries
1431 // are pruned when persisting the preferneces to disk).
1432 {
1433 DictionaryPrefUpdate update(prefs_, kExtensionsPref);
1434 const DictionaryValue* source_dict = prefs_->GetDictionary(kExtensionsPref);
1435 for (ExtensionIdSet::iterator ext_id = extension_ids.begin();
1436 ext_id != extension_ids.end(); ++ext_id) {
1437 std::string key = *ext_id + std::string(".") + kPrefPreferences;
1438 if (!source_dict->GetDictionary(key, NULL))
1439 update.Get()->Set(key, new DictionaryValue);
1440 }
1441 }
1442
1443 FixMissingPrefs(extension_ids);
1444 // Store extension controlled preference values in the
1445 // |extension_pref_value_map_|, which then informs the subscribers
1446 // (ExtensionPrefStores) about the winning values.
1447 for (ExtensionIdSet::iterator ext_id = extension_ids.begin();
1448 ext_id != extension_ids.end(); ++ext_id) {
1449 extension_pref_value_map_->RegisterExtension(
1450 *ext_id,
1451 GetInstallTime(*ext_id),
1452 GetExtensionState(*ext_id) == Extension::ENABLED);
1453
1454 const DictionaryValue* prefs = GetExtensionControlledPrefs(*ext_id);
1455 for (DictionaryValue::key_iterator i = prefs->begin_keys();
1456 i != prefs->end_keys(); ++i) {
1457 Value* value;
1458 if (!prefs->GetWithoutPathExpansion(*i, &value))
1459 continue;
1460 extension_pref_value_map_->SetExtensionPref(
1461 *ext_id, *i, false, value->DeepCopy());
1462 }
1463 }
1464
1465 extension_pref_value_map_->NotifyInitializationCompleted();
1466 }
1467
1468
SetExtensionControlledPref(const std::string & extension_id,const std::string & pref_key,bool incognito,Value * value)1469 void ExtensionPrefs::SetExtensionControlledPref(const std::string& extension_id,
1470 const std::string& pref_key,
1471 bool incognito,
1472 Value* value) {
1473 #ifndef NDEBUG
1474 const PrefService::Preference* pref =
1475 pref_service()->FindPreference(pref_key.c_str());
1476 DCHECK(pref) << "Extension controlled preference key " << pref_key
1477 << " not registered.";
1478 DCHECK_EQ(pref->GetType(), value->GetType())
1479 << "Extension controlled preference " << pref_key << " has wrong type.";
1480 #endif
1481
1482 if (!incognito) {
1483 // Also store in persisted Preferences file to recover after a
1484 // browser restart.
1485 ScopedExtensionControlledPrefUpdate update(prefs_, extension_id);
1486 DictionaryValue* dict = update.Get();
1487 dict->SetWithoutPathExpansion(pref_key, value->DeepCopy());
1488 pref_service()->ScheduleSavePersistentPrefs();
1489 }
1490
1491 extension_pref_value_map_->SetExtensionPref(
1492 extension_id, pref_key, incognito, value);
1493 }
1494
RemoveExtensionControlledPref(const std::string & extension_id,const std::string & pref_key,bool incognito)1495 void ExtensionPrefs::RemoveExtensionControlledPref(
1496 const std::string& extension_id,
1497 const std::string& pref_key,
1498 bool incognito) {
1499 DCHECK(pref_service()->FindPreference(pref_key.c_str()))
1500 << "Extension controlled preference key " << pref_key
1501 << " not registered.";
1502
1503 if (!incognito) {
1504 // Also store in persisted Preferences file to recover after a
1505 // browser restart.
1506 ScopedExtensionControlledPrefUpdate update(prefs_, extension_id);
1507 DictionaryValue* dict = update.Get();
1508 dict->RemoveWithoutPathExpansion(pref_key, NULL);
1509 pref_service()->ScheduleSavePersistentPrefs();
1510 }
1511
1512 extension_pref_value_map_->RemoveExtensionPref(
1513 extension_id, pref_key, incognito);
1514 }
1515
CanExtensionControlPref(const std::string & extension_id,const std::string & pref_key,bool incognito)1516 bool ExtensionPrefs::CanExtensionControlPref(const std::string& extension_id,
1517 const std::string& pref_key,
1518 bool incognito) {
1519 DCHECK(pref_service()->FindPreference(pref_key.c_str()))
1520 << "Extension controlled preference key " << pref_key
1521 << " not registered.";
1522
1523 return extension_pref_value_map_->CanExtensionControlPref(extension_id,
1524 pref_key,
1525 incognito);
1526 }
1527
DoesExtensionControlPref(const std::string & extension_id,const std::string & pref_key,bool incognito)1528 bool ExtensionPrefs::DoesExtensionControlPref(const std::string& extension_id,
1529 const std::string& pref_key,
1530 bool incognito) {
1531 DCHECK(pref_service()->FindPreference(pref_key.c_str()))
1532 << "Extension controlled preference key " << pref_key
1533 << " not registered.";
1534
1535 return extension_pref_value_map_->DoesExtensionControlPref(extension_id,
1536 pref_key,
1537 incognito);
1538 }
1539
HasIncognitoPrefValue(const std::string & pref_key)1540 bool ExtensionPrefs::HasIncognitoPrefValue(const std::string& pref_key) {
1541 bool has_incognito_pref_value = false;
1542 extension_pref_value_map_->GetEffectivePrefValue(pref_key,
1543 true,
1544 &has_incognito_pref_value);
1545 return has_incognito_pref_value;
1546 }
1547
1548 // static
RegisterUserPrefs(PrefService * prefs)1549 void ExtensionPrefs::RegisterUserPrefs(PrefService* prefs) {
1550 prefs->RegisterDictionaryPref(kExtensionsPref);
1551 prefs->RegisterListPref(kExtensionToolbar);
1552 prefs->RegisterIntegerPref(prefs::kExtensionToolbarSize, -1);
1553 prefs->RegisterDictionaryPref(kExtensionsBlacklistUpdate);
1554 prefs->RegisterListPref(prefs::kExtensionInstallAllowList);
1555 prefs->RegisterListPref(prefs::kExtensionInstallDenyList);
1556 prefs->RegisterListPref(prefs::kExtensionInstallForceList);
1557 prefs->RegisterStringPref(kWebStoreLogin, std::string() /* default_value */);
1558 }
1559