• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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