extension_prefs.cc revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
1// Copyright (c) 2010 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_util.h"
8#include "base/string_number_conversions.h"
9#include "base/utf_string_conversions.h"
10#include "chrome/common/extensions/extension.h"
11#include "chrome/common/pref_names.h"
12
13using base::Time;
14
15namespace {
16
17// Additional preferences keys
18
19// Where an extension was installed from. (see Extension::Location)
20const char kPrefLocation[] = "location";
21
22// Enabled, disabled, killed, etc. (see Extension::State)
23const char kPrefState[] = "state";
24
25// The path to the current version's manifest file.
26const char kPrefPath[] = "path";
27
28// The dictionary containing the extension's manifest.
29const char kPrefManifest[] = "manifest";
30
31// The version number.
32const char kPrefVersion[] = "manifest.version";
33
34// Indicates if an extension is blacklisted:
35const char kPrefBlacklist[] = "blacklist";
36
37// Indicates whether to show an install warning when the user enables.
38const char kExtensionDidEscalatePermissions[] = "install_warning_on_enable";
39
40// A preference that tracks admin policy regarding which extensions the user
41// can and can not install. This preference is a list object, containing
42// strings that list extension ids. Denylist can contain "*" meaning all
43// extensions.
44const char kExtensionInstallAllowList[] = "extensions.install.allowlist";
45const char kExtensionInstallDenyList[] = "extensions.install.denylist";
46
47// A preference that tracks browser action toolbar configuration. This is a list
48// object stored in the Preferences file. The extensions are stored by ID.
49const char kExtensionToolbar[] = "extensions.toolbar";
50
51// The key for a serialized Time value indicating the start of the day (from the
52// server's perspective) an extension last included a "ping" parameter during
53// its update check.
54const char kLastPingDay[] = "lastpingday";
55
56// Path for settings specific to blacklist update.
57const char kExtensionsBlacklistUpdate[] = "extensions.blacklistupdate";
58
59// Path and sub-keys for the idle install info dictionary preference.
60const char kIdleInstallInfo[] = "idle_install_info";
61const char kIdleInstallInfoCrxPath[] = "crx_path";
62const char kIdleInstallInfoVersion[] = "version";
63const char kIdleInstallInfoFetchTime[] = "fetch_time";
64
65
66// A preference that, if true, will allow this extension to run in incognito
67// mode.
68const char kPrefIncognitoEnabled[] = "incognito";
69
70// A preference to control whether an extension is allowed to inject script in
71// pages with file URLs.
72const char kPrefAllowFileAccess[] = "allowFileAccess";
73
74// A preference set by the web store to indicate login information for
75// purchased apps.
76const char kWebStoreLogin[] = "extensions.webstore_login";
77
78// A preference set by the the NTP to persist the desired launch container type
79// used for apps.
80const char kPrefLaunchType[] = "launchType";
81
82}  // namespace
83
84////////////////////////////////////////////////////////////////////////////////
85
86namespace {
87
88// TODO(asargent) - This is cleanup code for a key that was introduced into
89// the extensions.settings sub-dictionary which wasn't a valid extension
90// id. We can remove this in a couple of months. (See http://crbug.com/40017
91// and http://crbug.com/39745 for more details).
92static void CleanupBadExtensionKeys(PrefService* prefs) {
93  DictionaryValue* dictionary =
94      prefs->GetMutableDictionary(ExtensionPrefs::kExtensionsPref);
95  std::set<std::string> bad_keys;
96  for (DictionaryValue::key_iterator i = dictionary->begin_keys();
97       i != dictionary->end_keys(); ++i) {
98    const std::string& key_name(*i);
99    if (!Extension::IdIsValid(key_name)) {
100      bad_keys.insert(key_name);
101    }
102  }
103  bool dirty = false;
104  for (std::set<std::string>::iterator i = bad_keys.begin();
105       i != bad_keys.end(); ++i) {
106    dirty = true;
107    dictionary->Remove(*i, NULL);
108  }
109  if (dirty)
110    prefs->ScheduleSavePersistentPrefs();
111}
112
113}  // namespace
114
115ExtensionPrefs::ExtensionPrefs(PrefService* prefs, const FilePath& root_dir)
116    : prefs_(prefs),
117      install_directory_(root_dir) {
118  // TODO(asargent) - Remove this in a couple of months. (See comment above
119  // CleanupBadExtensionKeys).
120  CleanupBadExtensionKeys(prefs);
121
122  MakePathsRelative();
123}
124
125// static
126const char ExtensionPrefs::kExtensionsPref[] = "extensions.settings";
127
128static FilePath::StringType MakePathRelative(const FilePath& parent,
129                                             const FilePath& child,
130                                             bool *dirty) {
131  if (!parent.IsParent(child))
132    return child.value();
133
134  if (dirty)
135    *dirty = true;
136  FilePath::StringType retval = child.value().substr(
137      parent.value().length());
138  if (FilePath::IsSeparator(retval[0]))
139    return retval.substr(1);
140  else
141    return retval;
142}
143
144void ExtensionPrefs::MakePathsRelative() {
145  bool dirty = false;
146  const DictionaryValue* dict = prefs_->GetMutableDictionary(kExtensionsPref);
147  if (!dict || dict->empty())
148    return;
149
150  for (DictionaryValue::key_iterator i = dict->begin_keys();
151       i != dict->end_keys(); ++i) {
152    DictionaryValue* extension_dict;
153    if (!dict->GetDictionaryWithoutPathExpansion(*i, &extension_dict))
154      continue;
155    int location_value;
156    if (extension_dict->GetInteger(kPrefLocation, &location_value) &&
157        location_value == Extension::LOAD) {
158      // Unpacked extensions can have absolute paths.
159      continue;
160    }
161    FilePath::StringType path_string;
162    if (!extension_dict->GetString(kPrefPath, &path_string))
163      continue;
164    FilePath path(path_string);
165    if (path.IsAbsolute()) {
166      extension_dict->SetString(kPrefPath,
167          MakePathRelative(install_directory_, path, &dirty));
168    }
169  }
170  if (dirty)
171    SavePrefsAndNotify();
172}
173
174void ExtensionPrefs::MakePathsAbsolute(DictionaryValue* dict) {
175  if (!dict || dict->empty())
176    return;
177
178  for (DictionaryValue::key_iterator i = dict->begin_keys();
179       i != dict->end_keys(); ++i) {
180    DictionaryValue* extension_dict;
181    if (!dict->GetDictionaryWithoutPathExpansion(*i, &extension_dict)) {
182      NOTREACHED();
183      continue;
184    }
185
186    int location_value;
187    if (extension_dict->GetInteger(kPrefLocation, &location_value) &&
188        location_value == Extension::LOAD) {
189      // Unpacked extensions will already have absolute paths.
190      continue;
191    }
192
193    FilePath::StringType path_string;
194    if (!extension_dict->GetString(kPrefPath, &path_string))
195      continue;
196
197    DCHECK(!FilePath(path_string).IsAbsolute());
198    extension_dict->SetString(
199        kPrefPath, install_directory_.Append(path_string).value());
200  }
201}
202
203DictionaryValue* ExtensionPrefs::CopyCurrentExtensions() {
204  const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref);
205  if (extensions) {
206    DictionaryValue* copy =
207        static_cast<DictionaryValue*>(extensions->DeepCopy());
208    MakePathsAbsolute(copy);
209    return copy;
210  }
211  return new DictionaryValue;
212}
213
214bool ExtensionPrefs::ReadBooleanFromPref(
215    DictionaryValue* ext, const std::string& pref_key) {
216  if (!ext->HasKey(pref_key)) return false;
217  bool bool_value = false;
218  if (!ext->GetBoolean(pref_key, &bool_value)) {
219    NOTREACHED() << "Failed to fetch " << pref_key << " flag.";
220    // In case we could not fetch the flag, we treat it as false.
221    return false;
222  }
223  return bool_value;
224}
225
226bool ExtensionPrefs::ReadExtensionPrefBoolean(
227    const std::string& extension_id, const std::string& pref_key) {
228  const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref);
229  if (!extensions)
230    return false;
231
232  DictionaryValue* ext = NULL;
233  if (!extensions->GetDictionary(extension_id, &ext)) {
234    // No such extension yet.
235    return false;
236  }
237  return ReadBooleanFromPref(ext, pref_key);
238}
239
240bool ExtensionPrefs::ReadIntegerFromPref(
241    DictionaryValue* ext, const std::string& pref_key, int* out_value) {
242  if (!ext->HasKey(pref_key)) return false;
243  if (!ext->GetInteger(pref_key, out_value)) {
244    NOTREACHED() << "Failed to fetch " << pref_key << " flag.";
245    // In case we could not fetch the flag, we treat it as false.
246    return false;
247  }
248  return out_value != NULL;
249}
250
251bool ExtensionPrefs::ReadExtensionPrefInteger(
252    const std::string& extension_id, const std::string& pref_key,
253    int* out_value) {
254  const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref);
255  if (!extensions)
256    return false;
257  DictionaryValue* ext = NULL;
258  if (!extensions->GetDictionary(extension_id, &ext)) {
259    // No such extension yet.
260    return false;
261  }
262  return ReadIntegerFromPref(ext, pref_key, out_value);
263}
264
265void ExtensionPrefs::SavePrefsAndNotify() {
266  prefs_->ScheduleSavePersistentPrefs();
267  prefs_->pref_notifier()->OnUserPreferenceSet(kExtensionsPref);
268}
269
270bool ExtensionPrefs::IsBlacklistBitSet(DictionaryValue* ext) {
271  return ReadBooleanFromPref(ext, kPrefBlacklist);
272}
273
274bool ExtensionPrefs::IsExtensionBlacklisted(const std::string& extension_id) {
275  return ReadExtensionPrefBoolean(extension_id, kPrefBlacklist);
276}
277
278bool ExtensionPrefs::IsExtensionAllowedByPolicy(
279    const std::string& extension_id) {
280  std::string string_value;
281
282  const ListValue* blacklist = prefs_->GetList(kExtensionInstallDenyList);
283  if (!blacklist || blacklist->empty())
284    return true;
285
286  // Check the whitelist first.
287  const ListValue* whitelist = prefs_->GetList(kExtensionInstallAllowList);
288  if (whitelist) {
289    for (ListValue::const_iterator it = whitelist->begin();
290         it != whitelist->end(); ++it) {
291      if (!(*it)->GetAsString(&string_value))
292        LOG(WARNING) << "Failed to read whitelist string.";
293      else if (string_value == extension_id)
294        return true;
295    }
296  }
297
298  // Then check the blacklist (the admin blacklist, not the Google blacklist).
299  if (blacklist) {
300    for (ListValue::const_iterator it = blacklist->begin();
301         it != blacklist->end(); ++it) {
302      if (!(*it)->GetAsString(&string_value)) {
303        LOG(WARNING) << "Failed to read blacklist string.";
304      } else {
305        if (string_value == "*")
306          return false;  // Only whitelisted extensions are allowed.
307        if (string_value == extension_id)
308          return false;
309      }
310    }
311  }
312
313  return true;
314}
315
316bool ExtensionPrefs::DidExtensionEscalatePermissions(
317    const std::string& extension_id) {
318  return ReadExtensionPrefBoolean(extension_id,
319                                  kExtensionDidEscalatePermissions);
320}
321
322void ExtensionPrefs::SetDidExtensionEscalatePermissions(
323    Extension* extension, bool did_escalate) {
324  UpdateExtensionPref(extension->id(), kExtensionDidEscalatePermissions,
325                      Value::CreateBooleanValue(did_escalate));
326  prefs_->ScheduleSavePersistentPrefs();
327}
328
329void ExtensionPrefs::UpdateBlacklist(
330    const std::set<std::string>& blacklist_set) {
331  std::vector<std::string> remove_pref_ids;
332  std::set<std::string> used_id_set;
333  const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref);
334
335  if (extensions) {
336    for (DictionaryValue::key_iterator extension_id = extensions->begin_keys();
337         extension_id != extensions->end_keys(); ++extension_id) {
338      DictionaryValue* ext;
339      if (!extensions->GetDictionaryWithoutPathExpansion(*extension_id, &ext)) {
340        NOTREACHED() << "Invalid pref for extension " << *extension_id;
341        continue;
342      }
343      const std::string& id(*extension_id);
344      if (blacklist_set.find(id) == blacklist_set.end()) {
345        if (!IsBlacklistBitSet(ext)) {
346          // This extension is not in blacklist. And it was not blacklisted
347          // before.
348          continue;
349        } else {
350          if (ext->size() == 1) {
351            // We should remove the entry if the only flag here is blacklist.
352            remove_pref_ids.push_back(id);
353          } else {
354            // Remove the blacklist bit.
355            ext->Remove(kPrefBlacklist, NULL);
356          }
357        }
358      } else {
359        if (!IsBlacklistBitSet(ext)) {
360          // Only set the blacklist if it was not set.
361          ext->SetBoolean(kPrefBlacklist, true);
362        }
363        // Keep the record if this extension is already processed.
364        used_id_set.insert(id);
365      }
366    }
367  }
368
369  // Iterate the leftovers to set blacklist in pref
370  std::set<std::string>::const_iterator set_itr = blacklist_set.begin();
371  for (; set_itr != blacklist_set.end(); ++set_itr) {
372    if (used_id_set.find(*set_itr) == used_id_set.end()) {
373      UpdateExtensionPref(*set_itr, kPrefBlacklist,
374        Value::CreateBooleanValue(true));
375    }
376  }
377  for (unsigned int i = 0; i < remove_pref_ids.size(); ++i) {
378    DeleteExtensionPrefs(remove_pref_ids[i]);
379  }
380  SavePrefsAndNotify();
381  return;
382}
383
384Time ExtensionPrefs::LastPingDayImpl(const DictionaryValue* dictionary) const {
385  if (dictionary && dictionary->HasKey(kLastPingDay)) {
386    std::string string_value;
387    int64 value;
388    dictionary->GetString(kLastPingDay, &string_value);
389    if (base::StringToInt64(string_value, &value)) {
390      return Time::FromInternalValue(value);
391    }
392  }
393  return Time();
394}
395
396void ExtensionPrefs::SetLastPingDayImpl(const Time& time,
397                                        DictionaryValue* dictionary) {
398  if (!dictionary) {
399    NOTREACHED();
400    return;
401  }
402  std::string value = base::Int64ToString(time.ToInternalValue());
403  dictionary->SetString(kLastPingDay, value);
404  SavePrefsAndNotify();
405}
406
407Time ExtensionPrefs::LastPingDay(const std::string& extension_id) const {
408  DCHECK(Extension::IdIsValid(extension_id));
409  return LastPingDayImpl(GetExtensionPref(extension_id));
410}
411
412Time ExtensionPrefs::BlacklistLastPingDay() const {
413  return LastPingDayImpl(prefs_->GetDictionary(kExtensionsBlacklistUpdate));
414}
415
416void ExtensionPrefs::SetLastPingDay(const std::string& extension_id,
417                                    const Time& time) {
418  DCHECK(Extension::IdIsValid(extension_id));
419  SetLastPingDayImpl(time, GetExtensionPref(extension_id));
420}
421
422void ExtensionPrefs::SetBlacklistLastPingDay(const Time& time) {
423  SetLastPingDayImpl(time,
424                     prefs_->GetMutableDictionary(kExtensionsBlacklistUpdate));
425}
426
427bool ExtensionPrefs::IsIncognitoEnabled(const std::string& extension_id) {
428  return ReadExtensionPrefBoolean(extension_id, kPrefIncognitoEnabled);
429}
430
431void ExtensionPrefs::SetIsIncognitoEnabled(const std::string& extension_id,
432                                           bool enabled) {
433  UpdateExtensionPref(extension_id, kPrefIncognitoEnabled,
434                      Value::CreateBooleanValue(enabled));
435  SavePrefsAndNotify();
436}
437
438bool ExtensionPrefs::AllowFileAccess(const std::string& extension_id) {
439  return ReadExtensionPrefBoolean(extension_id, kPrefAllowFileAccess);
440}
441
442void ExtensionPrefs::SetAllowFileAccess(const std::string& extension_id,
443                                        bool allow) {
444  UpdateExtensionPref(extension_id, kPrefAllowFileAccess,
445                      Value::CreateBooleanValue(allow));
446  SavePrefsAndNotify();
447}
448
449ExtensionPrefs::LaunchType ExtensionPrefs::GetLaunchType(
450    const std::string& extension_id) {
451  int value;
452  if (ReadExtensionPrefInteger(extension_id, kPrefLaunchType, &value) && (
453      value == LAUNCH_PINNED ||
454      value == LAUNCH_REGULAR ||
455      value == LAUNCH_FULLSCREEN)) {
456    return static_cast<LaunchType>(value);
457  }
458  return LAUNCH_PINNED;
459}
460
461void ExtensionPrefs::SetLaunchType(const std::string& extension_id,
462                                   LaunchType launch_type) {
463  UpdateExtensionPref(extension_id, kPrefLaunchType,
464      Value::CreateIntegerValue(static_cast<int>(launch_type)));
465  SavePrefsAndNotify();
466}
467
468void ExtensionPrefs::GetKilledExtensionIds(std::set<std::string>* killed_ids) {
469  const DictionaryValue* dict = prefs_->GetDictionary(kExtensionsPref);
470  if (!dict || dict->empty())
471    return;
472
473  for (DictionaryValue::key_iterator i = dict->begin_keys();
474       i != dict->end_keys(); ++i) {
475    const std::string& key_name(*i);
476    if (!Extension::IdIsValid(key_name)) {
477      LOG(WARNING) << "Invalid external extension ID encountered: " << key_name;
478      continue;
479    }
480
481    DictionaryValue* extension;
482    if (!dict->GetDictionary(key_name, &extension)) {
483      NOTREACHED();
484      continue;
485    }
486
487    // Check to see if the extension has been killed.
488    int state;
489    if (extension->GetInteger(kPrefState, &state) &&
490        state == static_cast<int>(Extension::KILLBIT)) {
491      killed_ids->insert(StringToLowerASCII(key_name));
492    }
493  }
494}
495
496std::vector<std::string> ExtensionPrefs::GetToolbarOrder() {
497  std::vector<std::string> extension_ids;
498  const ListValue* toolbar_order = prefs_->GetList(kExtensionToolbar);
499  if (toolbar_order) {
500    for (size_t i = 0; i < toolbar_order->GetSize(); ++i) {
501      std::string extension_id;
502      if (toolbar_order->GetString(i, &extension_id))
503        extension_ids.push_back(extension_id);
504    }
505  }
506  return extension_ids;
507}
508
509void ExtensionPrefs::SetToolbarOrder(
510    const std::vector<std::string>& extension_ids) {
511  ListValue* toolbar_order = prefs_->GetMutableList(kExtensionToolbar);
512  toolbar_order->Clear();
513  for (std::vector<std::string>::const_iterator iter = extension_ids.begin();
514       iter != extension_ids.end(); ++iter) {
515    toolbar_order->Append(new StringValue(*iter));
516  }
517  SavePrefsAndNotify();
518}
519
520void ExtensionPrefs::OnExtensionInstalled(
521    Extension* extension, Extension::State initial_state,
522    bool initial_incognito_enabled) {
523  const std::string& id = extension->id();
524  UpdateExtensionPref(id, kPrefState,
525                      Value::CreateIntegerValue(initial_state));
526  UpdateExtensionPref(id, kPrefIncognitoEnabled,
527                      Value::CreateBooleanValue(initial_incognito_enabled));
528  UpdateExtensionPref(id, kPrefLocation,
529                      Value::CreateIntegerValue(extension->location()));
530  FilePath::StringType path = MakePathRelative(install_directory_,
531      extension->path(), NULL);
532  UpdateExtensionPref(id, kPrefPath, Value::CreateStringValue(path));
533  // We store prefs about LOAD extensions, but don't cache their manifest
534  // since it may change on disk.
535  if (extension->location() != Extension::LOAD) {
536    UpdateExtensionPref(id, kPrefManifest,
537                        extension->manifest_value()->DeepCopy());
538  }
539  SavePrefsAndNotify();
540}
541
542void ExtensionPrefs::OnExtensionUninstalled(const std::string& extension_id,
543                                            const Extension::Location& location,
544                                            bool external_uninstall) {
545  // For external extensions, we save a preference reminding ourself not to try
546  // and install the extension anymore (except when |external_uninstall| is
547  // true, which signifies that the registry key was deleted or the pref file
548  // no longer lists the extension).
549  if (!external_uninstall && Extension::IsExternalLocation(location)) {
550    UpdateExtensionPref(extension_id, kPrefState,
551                        Value::CreateIntegerValue(Extension::KILLBIT));
552    SavePrefsAndNotify();
553  } else {
554    DeleteExtensionPrefs(extension_id);
555  }
556}
557
558Extension::State ExtensionPrefs::GetExtensionState(
559    const std::string& extension_id) {
560  DictionaryValue* extension = GetExtensionPref(extension_id);
561
562  // If the extension doesn't have a pref, it's a --load-extension.
563  if (!extension)
564    return Extension::ENABLED;
565
566  int state = -1;
567  if (!extension->GetInteger(kPrefState, &state) ||
568      state < 0 || state >= Extension::NUM_STATES) {
569    LOG(ERROR) << "Bad or missing pref 'state' for extension '"
570               << extension_id << "'";
571    return Extension::ENABLED;
572  }
573  return static_cast<Extension::State>(state);
574}
575
576void ExtensionPrefs::SetExtensionState(Extension* extension,
577                                       Extension::State state) {
578  UpdateExtensionPref(extension->id(), kPrefState,
579                      Value::CreateIntegerValue(state));
580  SavePrefsAndNotify();
581}
582
583std::string ExtensionPrefs::GetVersionString(const std::string& extension_id) {
584  DictionaryValue* extension = GetExtensionPref(extension_id);
585  if (!extension)
586    return std::string();
587
588  std::string version;
589  if (!extension->GetString(kPrefVersion, &version)) {
590    LOG(ERROR) << "Bad or missing pref 'version' for extension '"
591               << extension_id << "'";
592  }
593
594  return version;
595}
596
597void ExtensionPrefs::UpdateManifest(Extension* extension) {
598  if (extension->location() != Extension::LOAD) {
599    UpdateExtensionPref(extension->id(), kPrefManifest,
600                        extension->manifest_value()->DeepCopy());
601    SavePrefsAndNotify();
602  }
603}
604
605FilePath ExtensionPrefs::GetExtensionPath(const std::string& extension_id) {
606  const DictionaryValue* dict = prefs_->GetDictionary(kExtensionsPref);
607  if (!dict || dict->empty())
608    return FilePath();
609
610  std::string path;
611  if (!dict->GetString(extension_id + "." + kPrefPath, &path))
612    return FilePath();
613
614  return install_directory_.Append(FilePath::FromWStringHack(UTF8ToWide(path)));
615}
616
617void ExtensionPrefs::UpdateExtensionPref(const std::string& extension_id,
618                                         const std::string& key,
619                                         Value* data_value) {
620  if (!Extension::IdIsValid(extension_id)) {
621    NOTREACHED() << "Invalid extension_id " << extension_id;
622    return;
623  }
624  DictionaryValue* extension = GetOrCreateExtensionPref(extension_id);
625  extension->Set(key, data_value);
626}
627
628void ExtensionPrefs::DeleteExtensionPrefs(const std::string& extension_id) {
629  DictionaryValue* dict = prefs_->GetMutableDictionary(kExtensionsPref);
630  if (dict->HasKey(extension_id)) {
631    dict->Remove(extension_id, NULL);
632    SavePrefsAndNotify();
633  }
634}
635
636DictionaryValue* ExtensionPrefs::GetOrCreateExtensionPref(
637    const std::string& extension_id) {
638  DCHECK(Extension::IdIsValid(extension_id));
639  DictionaryValue* dict = prefs_->GetMutableDictionary(kExtensionsPref);
640  DictionaryValue* extension = NULL;
641  if (!dict->GetDictionary(extension_id, &extension)) {
642    // Extension pref does not exist, create it.
643    extension = new DictionaryValue();
644    dict->Set(extension_id, extension);
645  }
646  return extension;
647}
648
649DictionaryValue* ExtensionPrefs::GetExtensionPref(
650    const std::string& extension_id) const {
651  const DictionaryValue* dict = prefs_->GetDictionary(kExtensionsPref);
652  if (!dict)
653    return NULL;
654  DictionaryValue* extension = NULL;
655  dict->GetDictionary(extension_id, &extension);
656  return extension;
657}
658
659// Helper function for GetInstalledExtensionsInfo.
660static ExtensionInfo* GetInstalledExtensionInfoImpl(
661    DictionaryValue* extension_data,
662    DictionaryValue::key_iterator extension_id) {
663  DictionaryValue* ext;
664  if (!extension_data->GetDictionaryWithoutPathExpansion(*extension_id, &ext)) {
665    LOG(WARNING) << "Invalid pref for extension " << *extension_id;
666    NOTREACHED();
667    return NULL;
668  }
669  if (ext->HasKey(kPrefBlacklist)) {
670    bool is_blacklisted = false;
671    if (!ext->GetBoolean(kPrefBlacklist, &is_blacklisted)) {
672      NOTREACHED() << "Invalid blacklist pref:" << *extension_id;
673      return NULL;
674    }
675    if (is_blacklisted) {
676      return NULL;
677    }
678  }
679  int state_value;
680  if (!ext->GetInteger(kPrefState, &state_value)) {
681    // This can legitimately happen if we store preferences for component
682    // extensions.
683    return NULL;
684  }
685  if (state_value == Extension::KILLBIT) {
686    LOG(WARNING) << "External extension has been uninstalled by the user "
687                 << *extension_id;
688    return NULL;
689  }
690  FilePath::StringType path;
691  if (!ext->GetString(kPrefPath, &path)) {
692    return NULL;
693  }
694  int location_value;
695  if (!ext->GetInteger(kPrefLocation, &location_value)) {
696    return NULL;
697  }
698
699  // Only the following extension types can be installed permanently in the
700  // preferences.
701  Extension::Location location =
702      static_cast<Extension::Location>(location_value);
703  if (location != Extension::INTERNAL &&
704      location != Extension::LOAD &&
705      !Extension::IsExternalLocation(location)) {
706    NOTREACHED();
707    return NULL;
708  }
709
710  DictionaryValue* manifest = NULL;
711  if (location != Extension::LOAD &&
712      !ext->GetDictionary(kPrefManifest, &manifest)) {
713    LOG(WARNING) << "Missing manifest for extension " << *extension_id;
714    // Just a warning for now.
715  }
716
717  return new ExtensionInfo(manifest, *extension_id, FilePath(path), location);
718}
719
720ExtensionPrefs::ExtensionsInfo* ExtensionPrefs::GetInstalledExtensionsInfo() {
721  scoped_ptr<DictionaryValue> extension_data(CopyCurrentExtensions());
722
723  ExtensionsInfo* extensions_info = new ExtensionsInfo;
724
725  for (DictionaryValue::key_iterator extension_id(
726           extension_data->begin_keys());
727       extension_id != extension_data->end_keys(); ++extension_id) {
728    if (!Extension::IdIsValid(*extension_id))
729      continue;
730
731    ExtensionInfo* info = GetInstalledExtensionInfoImpl(extension_data.get(),
732                                                        extension_id);
733    if (info)
734      extensions_info->push_back(linked_ptr<ExtensionInfo>(info));
735  }
736
737  return extensions_info;
738}
739
740ExtensionInfo* ExtensionPrefs::GetInstalledExtensionInfo(
741    const std::string& extension_id) {
742  scoped_ptr<DictionaryValue> extension_data(CopyCurrentExtensions());
743
744  for (DictionaryValue::key_iterator extension_iter(
745           extension_data->begin_keys());
746       extension_iter != extension_data->end_keys(); ++extension_iter) {
747    if (*extension_iter == extension_id) {
748      return GetInstalledExtensionInfoImpl(extension_data.get(),
749                                           extension_iter);
750    }
751  }
752
753  return NULL;
754}
755
756void ExtensionPrefs::SetIdleInstallInfo(const std::string& extension_id,
757                                        const FilePath& crx_path,
758                                        const std::string& version,
759                                        const base::Time& fetch_time) {
760  DictionaryValue* extension_prefs = GetExtensionPref(extension_id);
761  if (!extension_prefs) {
762    NOTREACHED();
763    return;
764  }
765  extension_prefs->Remove(kIdleInstallInfo, NULL);
766  DictionaryValue* info = new DictionaryValue();
767  info->SetString(kIdleInstallInfoCrxPath, crx_path.value());
768  info->SetString(kIdleInstallInfoVersion, version);
769  info->SetString(kIdleInstallInfoFetchTime,
770                  base::Int64ToString(fetch_time.ToInternalValue()));
771  extension_prefs->Set(kIdleInstallInfo, info);
772  SavePrefsAndNotify();
773}
774
775bool ExtensionPrefs::RemoveIdleInstallInfo(const std::string& extension_id) {
776  DictionaryValue* extension_prefs = GetExtensionPref(extension_id);
777  if (!extension_prefs)
778    return false;
779  bool result = extension_prefs->Remove(kIdleInstallInfo, NULL);
780  SavePrefsAndNotify();
781  return result;
782}
783
784bool ExtensionPrefs::GetIdleInstallInfo(const std::string& extension_id,
785                                        FilePath* crx_path,
786                                        std::string* version,
787                                        base::Time* fetch_time) {
788  DictionaryValue* extension_prefs = GetExtensionPref(extension_id);
789  if (!extension_prefs)
790    return false;
791
792  // Do all the reads from the prefs together, and don't do any assignment
793  // to the out parameters unless all the reads succeed.
794  DictionaryValue* info = NULL;
795  if (!extension_prefs->GetDictionary(kIdleInstallInfo, &info))
796    return false;
797
798  FilePath::StringType path_string;
799  if (!info->GetString(kIdleInstallInfoCrxPath, &path_string))
800    return false;
801
802  std::string tmp_version;
803  if (!info->GetString(kIdleInstallInfoVersion, &tmp_version))
804    return false;
805
806  std::string fetch_time_string;
807  if (!info->GetString(kIdleInstallInfoFetchTime, &fetch_time_string))
808    return false;
809
810  int64 fetch_time_value;
811  if (!base::StringToInt64(fetch_time_string, &fetch_time_value))
812    return false;
813
814  if (crx_path)
815    *crx_path = FilePath(path_string);
816
817  if (version)
818    *version = tmp_version;
819
820  if (fetch_time)
821    *fetch_time = base::Time::FromInternalValue(fetch_time_value);
822
823  return true;
824}
825
826std::set<std::string> ExtensionPrefs::GetIdleInstallInfoIds() {
827  std::set<std::string> result;
828
829  const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref);
830  if (!extensions)
831    return result;
832
833  for (DictionaryValue::key_iterator iter = extensions->begin_keys();
834       iter != extensions->end_keys(); ++iter) {
835    const std::string& id(*iter);
836    if (!Extension::IdIsValid(id)) {
837      NOTREACHED();
838      continue;
839    }
840
841    DictionaryValue* extension_prefs = GetExtensionPref(id);
842    if (!extension_prefs)
843      continue;
844
845    DictionaryValue* info = NULL;
846    if (extension_prefs->GetDictionary(kIdleInstallInfo, &info))
847      result.insert(id);
848  }
849  return result;
850}
851
852bool ExtensionPrefs::GetWebStoreLogin(std::string* result) {
853  if (prefs_->HasPrefPath(kWebStoreLogin)) {
854    *result = prefs_->GetString(kWebStoreLogin);
855    return true;
856  }
857  return false;
858}
859
860void ExtensionPrefs::SetWebStoreLogin(const std::string& login) {
861  prefs_->SetString(kWebStoreLogin, login);
862  SavePrefsAndNotify();
863}
864
865// static
866void ExtensionPrefs::RegisterUserPrefs(PrefService* prefs) {
867  prefs->RegisterDictionaryPref(kExtensionsPref);
868  prefs->RegisterListPref(kExtensionToolbar);
869  prefs->RegisterIntegerPref(prefs::kExtensionToolbarSize, -1);
870  prefs->RegisterDictionaryPref(kExtensionsBlacklistUpdate);
871  prefs->RegisterListPref(kExtensionInstallAllowList);
872  prefs->RegisterListPref(kExtensionInstallDenyList);
873  prefs->RegisterStringPref(kWebStoreLogin, std::string() /* default_value */);
874}
875