| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "extensions/browser/extension_prefs.h" |
| |
| #include <iterator> |
| |
| #include "base/command_line.h" |
| #include "base/prefs/pref_notifier.h" |
| #include "base/prefs/pref_service.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| #include "base/value_conversions.h" |
| #include "components/user_prefs/pref_registry_syncable.h" |
| #include "extensions/browser/admin_policy.h" |
| #include "extensions/browser/app_sorting.h" |
| #include "extensions/browser/event_router.h" |
| #include "extensions/browser/extension_pref_store.h" |
| #include "extensions/browser/extension_prefs_factory.h" |
| #include "extensions/browser/extension_prefs_observer.h" |
| #include "extensions/browser/pref_names.h" |
| #include "extensions/common/feature_switch.h" |
| #include "extensions/common/manifest.h" |
| #include "extensions/common/permissions/permission_set.h" |
| #include "extensions/common/permissions/permissions_info.h" |
| #include "extensions/common/url_pattern.h" |
| #include "extensions/common/user_script.h" |
| #include "ui/base/l10n/l10n_util.h" |
| |
| using base::Value; |
| using base::DictionaryValue; |
| using base::ListValue; |
| |
| namespace extensions { |
| |
| namespace { |
| |
| // Additional preferences keys, which are not needed by external clients. |
| |
| // True if this extension is running. Note this preference stops getting updated |
| // during Chrome shutdown (and won't be updated on a browser crash) and so can |
| // be used at startup to determine whether the extension was running when Chrome |
| // was last terminated. |
| const char kPrefRunning[] = "running"; |
| |
| // Whether this extension had windows when it was last running. |
| const char kIsActive[] = "is_active"; |
| |
| // Where an extension was installed from. (see Manifest::Location) |
| const char kPrefLocation[] = "location"; |
| |
| // Enabled, disabled, killed, etc. (see Extension::State) |
| const char kPrefState[] = "state"; |
| |
| // The path to the current version's manifest file. |
| const char kPrefPath[] = "path"; |
| |
| // The dictionary containing the extension's manifest. |
| const char kPrefManifest[] = "manifest"; |
| |
| // The version number. |
| const char kPrefVersion[] = "manifest.version"; |
| |
| // Indicates whether an extension is blacklisted. |
| const char kPrefBlacklist[] = "blacklist"; |
| |
| // If extension is greylisted. |
| const char kPrefBlacklistState[] = "blacklist_state"; |
| |
| // The count of how many times we prompted the user to acknowledge an |
| // extension. |
| const char kPrefAcknowledgePromptCount[] = "ack_prompt_count"; |
| |
| // Indicates whether the user has acknowledged various types of extensions. |
| const char kPrefExternalAcknowledged[] = "ack_external"; |
| const char kPrefBlacklistAcknowledged[] = "ack_blacklist"; |
| const char kPrefWipeoutAcknowledged[] = "ack_wiped"; |
| const char kPrefSettingsBubbleAcknowledged[] = "ack_settings_bubble"; |
| const char kPrefNtpBubbleAcknowledged[] = "ack_ntp_bubble"; |
| |
| // Indicates whether the external extension was installed during the first |
| // run of this profile. |
| const char kPrefExternalInstallFirstRun[] = "external_first_run"; |
| |
| // Indicates whether to show an install warning when the user enables. |
| const char kExtensionDidEscalatePermissions[] = "install_warning_on_enable"; |
| |
| // DO NOT USE, use kPrefDisableReasons instead. |
| // Indicates whether the extension was updated while it was disabled. |
| const char kDeprecatedPrefDisableReason[] = "disable_reason"; |
| |
| // A bitmask of all the reasons an extension is disabled. |
| const char kPrefDisableReasons[] = "disable_reasons"; |
| |
| // The key for a serialized Time value indicating the start of the day (from the |
| // server's perspective) an extension last included a "ping" parameter during |
| // its update check. |
| const char kLastPingDay[] = "lastpingday"; |
| |
| // Similar to kLastPingDay, but for "active" instead of "rollcall" pings. |
| const char kLastActivePingDay[] = "last_active_pingday"; |
| |
| // A bit we use to keep track of whether we need to do an "active" ping. |
| const char kActiveBit[] = "active_bit"; |
| |
| // Path for settings specific to blacklist update. |
| const char kExtensionsBlacklistUpdate[] = "extensions.blacklistupdate"; |
| |
| // Path for the delayed install info dictionary preference. The actual string |
| // value is a legacy artifact for when delayed installs only pertained to |
| // updates that were waiting for idle. |
| const char kDelayedInstallInfo[] = "idle_install_info"; |
| |
| // Reason why the extension's install was delayed. |
| const char kDelayedInstallReason[] = "delay_install_reason"; |
| |
| // Path for the suggested page ordinal of a delayed extension install. |
| const char kPrefSuggestedPageOrdinal[] = "suggested_page_ordinal"; |
| |
| // A preference that, if true, will allow this extension to run in incognito |
| // mode. |
| const char kPrefIncognitoEnabled[] = "incognito"; |
| |
| // A preference to control whether an extension is allowed to inject script in |
| // pages with file URLs. |
| const char kPrefAllowFileAccess[] = "newAllowFileAccess"; |
| // TODO(jstritar): As part of fixing http://crbug.com/91577, we revoked all |
| // extension file access by renaming the pref. We should eventually clean up |
| // the old flag and possibly go back to that name. |
| // const char kPrefAllowFileAccessOld[] = "allowFileAccess"; |
| |
| // A preference specifying if the user dragged the app on the NTP. |
| const char kPrefUserDraggedApp[] = "user_dragged_app_ntp"; |
| |
| // Preferences that hold which permissions the user has granted the extension. |
| // We explicitly keep track of these so that extensions can contain unknown |
| // permissions, for backwards compatibility reasons, and we can still prompt |
| // the user to accept them once recognized. We store the active permission |
| // permissions because they may differ from those defined in the manifest. |
| const char kPrefActivePermissions[] = "active_permissions"; |
| const char kPrefGrantedPermissions[] = "granted_permissions"; |
| |
| // The preference names for PermissionSet values. |
| const char kPrefAPIs[] = "api"; |
| const char kPrefManifestPermissions[] = "manifest_permissions"; |
| const char kPrefExplicitHosts[] = "explicit_host"; |
| const char kPrefScriptableHosts[] = "scriptable_host"; |
| |
| // The preference names for the old granted permissions scheme. |
| const char kPrefOldGrantedFullAccess[] = "granted_permissions.full"; |
| const char kPrefOldGrantedHosts[] = "granted_permissions.host"; |
| const char kPrefOldGrantedAPIs[] = "granted_permissions.api"; |
| |
| // A preference that indicates when an extension was installed. |
| const char kPrefInstallTime[] = "install_time"; |
| |
| // A preference which saves the creation flags for extensions. |
| const char kPrefCreationFlags[] = "creation_flags"; |
| |
| // A preference that indicates whether the extension was installed from the |
| // Chrome Web Store. |
| const char kPrefFromWebStore[] = "from_webstore"; |
| |
| // A preference that indicates whether the extension was installed from a |
| // mock App created from a bookmark. |
| const char kPrefFromBookmark[] = "from_bookmark"; |
| |
| // A preference that indicates whether the extension was installed as a |
| // default app. |
| const char kPrefWasInstalledByDefault[] = "was_installed_by_default"; |
| |
| // A preference that indicates whether the extension was installed as an |
| // OEM app. |
| const char kPrefWasInstalledByOem[] = "was_installed_by_oem"; |
| |
| // Key for Geometry Cache preference. |
| const char kPrefGeometryCache[] = "geometry_cache"; |
| |
| // A preference that indicates when an extension is last launched. |
| const char kPrefLastLaunchTime[] = "last_launch_time"; |
| |
| // A preference that marks an ephemeral app that was evicted from the cache. |
| // Their data is retained and garbage collected when inactive for a long period |
| // of time. |
| const char kPrefEvictedEphemeralApp[] = "evicted_ephemeral_app"; |
| |
| // Am installation parameter bundled with an extension. |
| const char kPrefInstallParam[] = "install_parameter"; |
| |
| // A list of installed ids and a signature. |
| const char kInstallSignature[] = "extensions.install_signature"; |
| |
| // A preference that stores the next threshold for displaying a notification |
| // when an extension or app consumes excessive disk space. This will not be |
| // set until the extension/app reaches the initial threshold. |
| const char kPrefNextStorageThreshold[] = "next_storage_threshold"; |
| |
| // If this preference is set to true, notifications will be suppressed when an |
| // extension or app consumes excessive disk space. |
| const char kPrefDisableStorageNotifications[] = "disable_storage_notifications"; |
| |
| // Provider of write access to a dictionary storing extension prefs. |
| class ScopedExtensionPrefUpdate : public DictionaryPrefUpdate { |
| public: |
| ScopedExtensionPrefUpdate(PrefService* service, |
| const std::string& extension_id) : |
| DictionaryPrefUpdate(service, pref_names::kExtensions), |
| extension_id_(extension_id) {} |
| |
| virtual ~ScopedExtensionPrefUpdate() { |
| } |
| |
| // DictionaryPrefUpdate overrides: |
| virtual base::DictionaryValue* Get() OVERRIDE { |
| base::DictionaryValue* dict = DictionaryPrefUpdate::Get(); |
| base::DictionaryValue* extension = NULL; |
| if (!dict->GetDictionary(extension_id_, &extension)) { |
| // Extension pref does not exist, create it. |
| extension = new base::DictionaryValue(); |
| dict->SetWithoutPathExpansion(extension_id_, extension); |
| } |
| return extension; |
| } |
| |
| private: |
| const std::string extension_id_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ScopedExtensionPrefUpdate); |
| }; |
| |
| std::string JoinPrefs(const std::string& parent, const char* child) { |
| return parent + "." + child; |
| } |
| |
| // Checks if kPrefBlacklist is set to true in the base::DictionaryValue. |
| // Return false if the value is false or kPrefBlacklist does not exist. |
| // This is used to decide if an extension is blacklisted. |
| bool IsBlacklistBitSet(const base::DictionaryValue* ext) { |
| bool bool_value; |
| return ext->GetBoolean(kPrefBlacklist, &bool_value) && bool_value; |
| } |
| |
| bool IsEvictedEphemeralApp(const base::DictionaryValue* ext) { |
| bool bool_value; |
| return ext->GetBoolean(kPrefEvictedEphemeralApp, &bool_value) && bool_value; |
| } |
| |
| void LoadExtensionControlledPrefs(ExtensionPrefs* prefs, |
| ExtensionPrefValueMap* value_map, |
| const std::string& extension_id, |
| ExtensionPrefsScope scope) { |
| std::string scope_string; |
| if (!pref_names::ScopeToPrefName(scope, &scope_string)) |
| return; |
| std::string key = extension_id + "." + scope_string; |
| |
| const base::DictionaryValue* source_dict = |
| prefs->pref_service()->GetDictionary(pref_names::kExtensions); |
| const base::DictionaryValue* preferences = NULL; |
| if (!source_dict->GetDictionary(key, &preferences)) |
| return; |
| |
| for (base::DictionaryValue::Iterator iter(*preferences); !iter.IsAtEnd(); |
| iter.Advance()) { |
| value_map->SetExtensionPref( |
| extension_id, iter.key(), scope, iter.value().DeepCopy()); |
| } |
| } |
| |
| } // namespace |
| |
| // |
| // TimeProvider |
| // |
| |
| ExtensionPrefs::TimeProvider::TimeProvider() { |
| } |
| |
| ExtensionPrefs::TimeProvider::~TimeProvider() { |
| } |
| |
| base::Time ExtensionPrefs::TimeProvider::GetCurrentTime() const { |
| return base::Time::Now(); |
| } |
| |
| // |
| // ScopedUpdate |
| // |
| template <typename T, base::Value::Type type_enum_value> |
| ExtensionPrefs::ScopedUpdate<T, type_enum_value>::ScopedUpdate( |
| ExtensionPrefs* prefs, |
| const std::string& extension_id, |
| const std::string& key) |
| : update_(prefs->pref_service(), pref_names::kExtensions), |
| extension_id_(extension_id), |
| key_(key) { |
| DCHECK(Extension::IdIsValid(extension_id_)); |
| } |
| |
| template <typename T, base::Value::Type type_enum_value> |
| ExtensionPrefs::ScopedUpdate<T, type_enum_value>::~ScopedUpdate() { |
| } |
| |
| template <typename T, base::Value::Type type_enum_value> |
| T* ExtensionPrefs::ScopedUpdate<T, type_enum_value>::Get() { |
| base::DictionaryValue* dict = update_.Get(); |
| base::DictionaryValue* extension = NULL; |
| base::Value* key_value = NULL; |
| if (!dict->GetDictionary(extension_id_, &extension) || |
| !extension->Get(key_, &key_value)) { |
| return NULL; |
| } |
| return key_value->GetType() == type_enum_value ? |
| static_cast<T*>(key_value) : |
| NULL; |
| } |
| |
| template <typename T, base::Value::Type type_enum_value> |
| T* ExtensionPrefs::ScopedUpdate<T, type_enum_value>::Create() { |
| base::DictionaryValue* dict = update_.Get(); |
| base::DictionaryValue* extension = NULL; |
| base::Value* key_value = NULL; |
| T* value_as_t = NULL; |
| if (!dict->GetDictionary(extension_id_, &extension)) { |
| extension = new base::DictionaryValue; |
| dict->SetWithoutPathExpansion(extension_id_, extension); |
| } |
| if (!extension->Get(key_, &key_value)) { |
| value_as_t = new T; |
| extension->SetWithoutPathExpansion(key_, value_as_t); |
| } else { |
| CHECK(key_value->GetType() == type_enum_value); |
| value_as_t = static_cast<T*>(key_value); |
| } |
| return value_as_t; |
| } |
| |
| // Explicit instantiations for Dictionary and List value types. |
| template class ExtensionPrefs::ScopedUpdate<base::DictionaryValue, |
| base::Value::TYPE_DICTIONARY>; |
| template class ExtensionPrefs::ScopedUpdate<base::ListValue, |
| base::Value::TYPE_LIST>; |
| |
| // |
| // ExtensionPrefs |
| // |
| |
| // static |
| ExtensionPrefs* ExtensionPrefs::Create( |
| PrefService* prefs, |
| const base::FilePath& root_dir, |
| ExtensionPrefValueMap* extension_pref_value_map, |
| scoped_ptr<AppSorting> app_sorting, |
| bool extensions_disabled, |
| const std::vector<ExtensionPrefsObserver*>& early_observers) { |
| return ExtensionPrefs::Create(prefs, |
| root_dir, |
| extension_pref_value_map, |
| app_sorting.Pass(), |
| extensions_disabled, |
| early_observers, |
| make_scoped_ptr(new TimeProvider())); |
| } |
| |
| // static |
| ExtensionPrefs* ExtensionPrefs::Create( |
| PrefService* pref_service, |
| const base::FilePath& root_dir, |
| ExtensionPrefValueMap* extension_pref_value_map, |
| scoped_ptr<AppSorting> app_sorting, |
| bool extensions_disabled, |
| const std::vector<ExtensionPrefsObserver*>& early_observers, |
| scoped_ptr<TimeProvider> time_provider) { |
| return new ExtensionPrefs(pref_service, |
| root_dir, |
| extension_pref_value_map, |
| app_sorting.Pass(), |
| time_provider.Pass(), |
| extensions_disabled, |
| early_observers); |
| } |
| |
| ExtensionPrefs::~ExtensionPrefs() { |
| } |
| |
| // static |
| ExtensionPrefs* ExtensionPrefs::Get(content::BrowserContext* context) { |
| return ExtensionPrefsFactory::GetInstance()->GetForBrowserContext(context); |
| } |
| |
| static base::FilePath::StringType MakePathRelative(const base::FilePath& parent, |
| const base::FilePath& child) { |
| if (!parent.IsParent(child)) |
| return child.value(); |
| |
| base::FilePath::StringType retval = child.value().substr( |
| parent.value().length()); |
| if (base::FilePath::IsSeparator(retval[0])) |
| return retval.substr(1); |
| else |
| return retval; |
| } |
| |
| void ExtensionPrefs::MakePathsRelative() { |
| const base::DictionaryValue* dict = |
| prefs_->GetDictionary(pref_names::kExtensions); |
| if (!dict || dict->empty()) |
| return; |
| |
| // Collect all extensions ids with absolute paths in |absolute_keys|. |
| std::set<std::string> absolute_keys; |
| for (base::DictionaryValue::Iterator i(*dict); !i.IsAtEnd(); i.Advance()) { |
| const base::DictionaryValue* extension_dict = NULL; |
| if (!i.value().GetAsDictionary(&extension_dict)) |
| continue; |
| int location_value; |
| if (extension_dict->GetInteger(kPrefLocation, &location_value) && |
| Manifest::IsUnpackedLocation( |
| static_cast<Manifest::Location>(location_value))) { |
| // Unpacked extensions can have absolute paths. |
| continue; |
| } |
| base::FilePath::StringType path_string; |
| if (!extension_dict->GetString(kPrefPath, &path_string)) |
| continue; |
| base::FilePath path(path_string); |
| if (path.IsAbsolute()) |
| absolute_keys.insert(i.key()); |
| } |
| if (absolute_keys.empty()) |
| return; |
| |
| // Fix these paths. |
| DictionaryPrefUpdate update(prefs_, pref_names::kExtensions); |
| base::DictionaryValue* update_dict = update.Get(); |
| for (std::set<std::string>::iterator i = absolute_keys.begin(); |
| i != absolute_keys.end(); ++i) { |
| base::DictionaryValue* extension_dict = NULL; |
| if (!update_dict->GetDictionaryWithoutPathExpansion(*i, &extension_dict)) { |
| NOTREACHED() << "Control should never reach here for extension " << *i; |
| continue; |
| } |
| base::FilePath::StringType path_string; |
| extension_dict->GetString(kPrefPath, &path_string); |
| base::FilePath path(path_string); |
| extension_dict->SetString(kPrefPath, |
| MakePathRelative(install_directory_, path)); |
| } |
| } |
| |
| const base::DictionaryValue* ExtensionPrefs::GetExtensionPref( |
| const std::string& extension_id) const { |
| const base::DictionaryValue* extensions = |
| prefs_->GetDictionary(pref_names::kExtensions); |
| const base::DictionaryValue* extension_dict = NULL; |
| if (!extensions || |
| !extensions->GetDictionary(extension_id, &extension_dict)) { |
| return NULL; |
| } |
| return extension_dict; |
| } |
| |
| void ExtensionPrefs::UpdateExtensionPref(const std::string& extension_id, |
| const std::string& key, |
| base::Value* data_value) { |
| if (!Extension::IdIsValid(extension_id)) { |
| NOTREACHED() << "Invalid extension_id " << extension_id; |
| return; |
| } |
| ScopedExtensionPrefUpdate update(prefs_, extension_id); |
| if (data_value) |
| update->Set(key, data_value); |
| else |
| update->Remove(key, NULL); |
| } |
| |
| void ExtensionPrefs::DeleteExtensionPrefs(const std::string& extension_id) { |
| extension_pref_value_map_->UnregisterExtension(extension_id); |
| FOR_EACH_OBSERVER(ExtensionPrefsObserver, |
| observer_list_, |
| OnExtensionPrefsDeleted(extension_id)); |
| DictionaryPrefUpdate update(prefs_, pref_names::kExtensions); |
| base::DictionaryValue* dict = update.Get(); |
| dict->Remove(extension_id, NULL); |
| } |
| |
| bool ExtensionPrefs::ReadPrefAsBoolean(const std::string& extension_id, |
| const std::string& pref_key, |
| bool* out_value) const { |
| const base::DictionaryValue* ext = GetExtensionPref(extension_id); |
| if (!ext || !ext->GetBoolean(pref_key, out_value)) |
| return false; |
| |
| return true; |
| } |
| |
| bool ExtensionPrefs::ReadPrefAsInteger(const std::string& extension_id, |
| const std::string& pref_key, |
| int* out_value) const { |
| const base::DictionaryValue* ext = GetExtensionPref(extension_id); |
| if (!ext || !ext->GetInteger(pref_key, out_value)) |
| return false; |
| |
| return true; |
| } |
| |
| bool ExtensionPrefs::ReadPrefAsString(const std::string& extension_id, |
| const std::string& pref_key, |
| std::string* out_value) const { |
| const base::DictionaryValue* ext = GetExtensionPref(extension_id); |
| if (!ext || !ext->GetString(pref_key, out_value)) |
| return false; |
| |
| return true; |
| } |
| |
| bool ExtensionPrefs::ReadPrefAsList(const std::string& extension_id, |
| const std::string& pref_key, |
| const base::ListValue** out_value) const { |
| const base::DictionaryValue* ext = GetExtensionPref(extension_id); |
| const base::ListValue* out = NULL; |
| if (!ext || !ext->GetList(pref_key, &out)) |
| return false; |
| if (out_value) |
| *out_value = out; |
| |
| return true; |
| } |
| |
| bool ExtensionPrefs::ReadPrefAsDictionary( |
| const std::string& extension_id, |
| const std::string& pref_key, |
| const base::DictionaryValue** out_value) const { |
| const base::DictionaryValue* ext = GetExtensionPref(extension_id); |
| const base::DictionaryValue* out = NULL; |
| if (!ext || !ext->GetDictionary(pref_key, &out)) |
| return false; |
| if (out_value) |
| *out_value = out; |
| |
| return true; |
| } |
| |
| bool ExtensionPrefs::HasPrefForExtension( |
| const std::string& extension_id) const { |
| return GetExtensionPref(extension_id) != NULL; |
| } |
| |
| bool ExtensionPrefs::ReadPrefAsURLPatternSet(const std::string& extension_id, |
| const std::string& pref_key, |
| URLPatternSet* result, |
| int valid_schemes) { |
| const base::ListValue* value = NULL; |
| if (!ReadPrefAsList(extension_id, pref_key, &value)) |
| return false; |
| |
| bool allow_file_access = AllowFileAccess(extension_id); |
| return result->Populate(*value, valid_schemes, allow_file_access, NULL); |
| } |
| |
| void ExtensionPrefs::SetExtensionPrefURLPatternSet( |
| const std::string& extension_id, |
| const std::string& pref_key, |
| const URLPatternSet& new_value) { |
| UpdateExtensionPref(extension_id, pref_key, new_value.ToValue().release()); |
| } |
| |
| bool ExtensionPrefs::ReadPrefAsBooleanAndReturn( |
| const std::string& extension_id, |
| const std::string& pref_key) const { |
| bool out_value = false; |
| return ReadPrefAsBoolean(extension_id, pref_key, &out_value) && out_value; |
| } |
| |
| PermissionSet* ExtensionPrefs::ReadPrefAsPermissionSet( |
| const std::string& extension_id, |
| const std::string& pref_key) { |
| if (!GetExtensionPref(extension_id)) |
| return NULL; |
| |
| // Retrieve the API permissions. Please refer SetExtensionPrefPermissionSet() |
| // for api_values format. |
| APIPermissionSet apis; |
| const base::ListValue* api_values = NULL; |
| std::string api_pref = JoinPrefs(pref_key, kPrefAPIs); |
| if (ReadPrefAsList(extension_id, api_pref, &api_values)) { |
| APIPermissionSet::ParseFromJSON(api_values, |
| APIPermissionSet::kAllowInternalPermissions, |
| &apis, NULL, NULL); |
| } |
| |
| // Retrieve the Manifest Keys permissions. Please refer to |
| // |SetExtensionPrefPermissionSet| for manifest_permissions_values format. |
| ManifestPermissionSet manifest_permissions; |
| const base::ListValue* manifest_permissions_values = NULL; |
| std::string manifest_permission_pref = |
| JoinPrefs(pref_key, kPrefManifestPermissions); |
| if (ReadPrefAsList(extension_id, manifest_permission_pref, |
| &manifest_permissions_values)) { |
| ManifestPermissionSet::ParseFromJSON( |
| manifest_permissions_values, &manifest_permissions, NULL, NULL); |
| } |
| |
| // Retrieve the explicit host permissions. |
| URLPatternSet explicit_hosts; |
| ReadPrefAsURLPatternSet( |
| extension_id, JoinPrefs(pref_key, kPrefExplicitHosts), |
| &explicit_hosts, Extension::kValidHostPermissionSchemes); |
| |
| // Retrieve the scriptable host permissions. |
| URLPatternSet scriptable_hosts; |
| ReadPrefAsURLPatternSet( |
| extension_id, JoinPrefs(pref_key, kPrefScriptableHosts), |
| &scriptable_hosts, UserScript::ValidUserScriptSchemes()); |
| |
| return new PermissionSet( |
| apis, manifest_permissions, explicit_hosts, scriptable_hosts); |
| } |
| |
| // Set the API or Manifest permissions. |
| // The format of api_values is: |
| // [ "permission_name1", // permissions do not support detail. |
| // "permission_name2", |
| // {"permission_name3": value }, |
| // // permission supports detail, permission detail will be stored in value. |
| // ... |
| // ] |
| template<typename T> |
| static base::ListValue* CreatePermissionList(const T& permissions) { |
| base::ListValue* values = new base::ListValue(); |
| for (typename T::const_iterator i = permissions.begin(); |
| i != permissions.end(); ++i) { |
| scoped_ptr<base::Value> detail(i->ToValue()); |
| if (detail) { |
| base::DictionaryValue* tmp = new base::DictionaryValue(); |
| tmp->Set(i->name(), detail.release()); |
| values->Append(tmp); |
| } else { |
| values->Append(new base::StringValue(i->name())); |
| } |
| } |
| return values; |
| } |
| |
| void ExtensionPrefs::SetExtensionPrefPermissionSet( |
| const std::string& extension_id, |
| const std::string& pref_key, |
| const PermissionSet* new_value) { |
| std::string api_pref = JoinPrefs(pref_key, kPrefAPIs); |
| base::ListValue* api_values = CreatePermissionList(new_value->apis()); |
| UpdateExtensionPref(extension_id, api_pref, api_values); |
| |
| std::string manifest_permissions_pref = |
| JoinPrefs(pref_key, kPrefManifestPermissions); |
| base::ListValue* manifest_permissions_values = CreatePermissionList( |
| new_value->manifest_permissions()); |
| UpdateExtensionPref(extension_id, |
| manifest_permissions_pref, |
| manifest_permissions_values); |
| |
| // Set the explicit host permissions. |
| if (!new_value->explicit_hosts().is_empty()) { |
| SetExtensionPrefURLPatternSet(extension_id, |
| JoinPrefs(pref_key, kPrefExplicitHosts), |
| new_value->explicit_hosts()); |
| } |
| |
| // Set the scriptable host permissions. |
| if (!new_value->scriptable_hosts().is_empty()) { |
| SetExtensionPrefURLPatternSet(extension_id, |
| JoinPrefs(pref_key, kPrefScriptableHosts), |
| new_value->scriptable_hosts()); |
| } |
| } |
| |
| int ExtensionPrefs::IncrementAcknowledgePromptCount( |
| const std::string& extension_id) { |
| int count = 0; |
| ReadPrefAsInteger(extension_id, kPrefAcknowledgePromptCount, &count); |
| ++count; |
| UpdateExtensionPref(extension_id, kPrefAcknowledgePromptCount, |
| new base::FundamentalValue(count)); |
| return count; |
| } |
| |
| bool ExtensionPrefs::IsExternalExtensionAcknowledged( |
| const std::string& extension_id) { |
| return ReadPrefAsBooleanAndReturn(extension_id, kPrefExternalAcknowledged); |
| } |
| |
| void ExtensionPrefs::AcknowledgeExternalExtension( |
| const std::string& extension_id) { |
| DCHECK(Extension::IdIsValid(extension_id)); |
| UpdateExtensionPref(extension_id, kPrefExternalAcknowledged, |
| new base::FundamentalValue(true)); |
| UpdateExtensionPref(extension_id, kPrefAcknowledgePromptCount, NULL); |
| } |
| |
| bool ExtensionPrefs::IsBlacklistedExtensionAcknowledged( |
| const std::string& extension_id) { |
| return ReadPrefAsBooleanAndReturn(extension_id, kPrefBlacklistAcknowledged); |
| } |
| |
| void ExtensionPrefs::AcknowledgeBlacklistedExtension( |
| const std::string& extension_id) { |
| DCHECK(Extension::IdIsValid(extension_id)); |
| UpdateExtensionPref(extension_id, kPrefBlacklistAcknowledged, |
| new base::FundamentalValue(true)); |
| UpdateExtensionPref(extension_id, kPrefAcknowledgePromptCount, NULL); |
| } |
| |
| bool ExtensionPrefs::IsExternalInstallFirstRun( |
| const std::string& extension_id) { |
| return ReadPrefAsBooleanAndReturn(extension_id, kPrefExternalInstallFirstRun); |
| } |
| |
| void ExtensionPrefs::SetExternalInstallFirstRun( |
| const std::string& extension_id) { |
| DCHECK(Extension::IdIsValid(extension_id)); |
| UpdateExtensionPref(extension_id, kPrefExternalInstallFirstRun, |
| new base::FundamentalValue(true)); |
| } |
| |
| bool ExtensionPrefs::HasWipeoutBeenAcknowledged( |
| const std::string& extension_id) { |
| return ReadPrefAsBooleanAndReturn(extension_id, kPrefWipeoutAcknowledged); |
| } |
| |
| void ExtensionPrefs::SetWipeoutAcknowledged( |
| const std::string& extension_id, |
| bool value) { |
| UpdateExtensionPref(extension_id, kPrefWipeoutAcknowledged, |
| value ? base::Value::CreateBooleanValue(value) : NULL); |
| } |
| |
| bool ExtensionPrefs::HasSettingsApiBubbleBeenAcknowledged( |
| const std::string& extension_id) { |
| return ReadPrefAsBooleanAndReturn(extension_id, |
| kPrefSettingsBubbleAcknowledged); |
| } |
| |
| void ExtensionPrefs::SetSettingsApiBubbleBeenAcknowledged( |
| const std::string& extension_id, |
| bool value) { |
| UpdateExtensionPref(extension_id, |
| kPrefSettingsBubbleAcknowledged, |
| value ? base::Value::CreateBooleanValue(value) : NULL); |
| } |
| |
| bool ExtensionPrefs::HasNtpOverriddenBubbleBeenAcknowledged( |
| const std::string& extension_id) { |
| return ReadPrefAsBooleanAndReturn(extension_id, kPrefNtpBubbleAcknowledged); |
| } |
| |
| void ExtensionPrefs::SetNtpOverriddenBubbleBeenAcknowledged( |
| const std::string& extension_id, |
| bool value) { |
| UpdateExtensionPref(extension_id, |
| kPrefNtpBubbleAcknowledged, |
| value ? base::Value::CreateBooleanValue(value) : NULL); |
| } |
| |
| bool ExtensionPrefs::SetAlertSystemFirstRun() { |
| if (prefs_->GetBoolean(pref_names::kAlertsInitialized)) { |
| return true; |
| } |
| prefs_->SetBoolean(pref_names::kAlertsInitialized, true); |
| return false; |
| } |
| |
| bool ExtensionPrefs::ExtensionsBlacklistedByDefault() const { |
| return admin_policy::BlacklistedByDefault( |
| prefs_->GetList(pref_names::kInstallDenyList)); |
| } |
| |
| bool ExtensionPrefs::DidExtensionEscalatePermissions( |
| const std::string& extension_id) { |
| return ReadPrefAsBooleanAndReturn(extension_id, |
| kExtensionDidEscalatePermissions); |
| } |
| |
| void ExtensionPrefs::SetDidExtensionEscalatePermissions( |
| const Extension* extension, bool did_escalate) { |
| UpdateExtensionPref(extension->id(), kExtensionDidEscalatePermissions, |
| new base::FundamentalValue(did_escalate)); |
| } |
| |
| int ExtensionPrefs::GetDisableReasons(const std::string& extension_id) const { |
| int value = -1; |
| if (ReadPrefAsInteger(extension_id, kPrefDisableReasons, &value) && |
| value >= 0) { |
| return value; |
| } |
| return Extension::DISABLE_NONE; |
| } |
| |
| void ExtensionPrefs::AddDisableReason(const std::string& extension_id, |
| Extension::DisableReason disable_reason) { |
| ModifyDisableReason(extension_id, disable_reason, DISABLE_REASON_ADD); |
| } |
| |
| void ExtensionPrefs::RemoveDisableReason( |
| const std::string& extension_id, |
| Extension::DisableReason disable_reason) { |
| ModifyDisableReason(extension_id, disable_reason, DISABLE_REASON_REMOVE); |
| } |
| |
| void ExtensionPrefs::ClearDisableReasons(const std::string& extension_id) { |
| ModifyDisableReason( |
| extension_id, Extension::DISABLE_NONE, DISABLE_REASON_CLEAR); |
| } |
| |
| void ExtensionPrefs::ModifyDisableReason(const std::string& extension_id, |
| Extension::DisableReason reason, |
| DisableReasonChange change) { |
| int old_value = GetDisableReasons(extension_id); |
| int new_value = old_value; |
| switch (change) { |
| case DISABLE_REASON_ADD: |
| new_value |= static_cast<int>(reason); |
| break; |
| case DISABLE_REASON_REMOVE: |
| new_value &= ~static_cast<int>(reason); |
| break; |
| case DISABLE_REASON_CLEAR: |
| new_value = Extension::DISABLE_NONE; |
| break; |
| } |
| |
| if (old_value == new_value) // no change, return. |
| return; |
| |
| if (new_value == Extension::DISABLE_NONE) { |
| UpdateExtensionPref(extension_id, kPrefDisableReasons, NULL); |
| } else { |
| UpdateExtensionPref(extension_id, |
| kPrefDisableReasons, |
| new base::FundamentalValue(new_value)); |
| } |
| |
| FOR_EACH_OBSERVER(ExtensionPrefsObserver, |
| observer_list_, |
| OnExtensionDisableReasonsChanged(extension_id, new_value)); |
| } |
| |
| std::set<std::string> ExtensionPrefs::GetBlacklistedExtensions() { |
| std::set<std::string> ids; |
| |
| const base::DictionaryValue* extensions = |
| prefs_->GetDictionary(pref_names::kExtensions); |
| if (!extensions) |
| return ids; |
| |
| for (base::DictionaryValue::Iterator it(*extensions); |
| !it.IsAtEnd(); it.Advance()) { |
| if (!it.value().IsType(base::Value::TYPE_DICTIONARY)) { |
| NOTREACHED() << "Invalid pref for extension " << it.key(); |
| continue; |
| } |
| if (IsBlacklistBitSet( |
| static_cast<const base::DictionaryValue*>(&it.value()))) { |
| ids.insert(it.key()); |
| } |
| } |
| |
| return ids; |
| } |
| |
| void ExtensionPrefs::SetExtensionBlacklisted(const std::string& extension_id, |
| bool is_blacklisted) { |
| bool currently_blacklisted = IsExtensionBlacklisted(extension_id); |
| if (is_blacklisted == currently_blacklisted) |
| return; |
| |
| // Always make sure the "acknowledged" bit is cleared since the blacklist bit |
| // is changing. |
| UpdateExtensionPref(extension_id, kPrefBlacklistAcknowledged, NULL); |
| |
| if (is_blacklisted) { |
| UpdateExtensionPref(extension_id, |
| kPrefBlacklist, |
| new base::FundamentalValue(true)); |
| } else { |
| UpdateExtensionPref(extension_id, kPrefBlacklist, NULL); |
| const base::DictionaryValue* dict = GetExtensionPref(extension_id); |
| if (dict && dict->empty()) |
| DeleteExtensionPrefs(extension_id); |
| } |
| } |
| |
| bool ExtensionPrefs::IsExtensionBlacklisted(const std::string& id) const { |
| const base::DictionaryValue* ext_prefs = GetExtensionPref(id); |
| return ext_prefs && IsBlacklistBitSet(ext_prefs); |
| } |
| |
| namespace { |
| |
| // Serializes a 64bit integer as a string value. |
| void SaveInt64(base::DictionaryValue* dictionary, |
| const char* key, |
| const int64 value) { |
| if (!dictionary) |
| return; |
| |
| std::string string_value = base::Int64ToString(value); |
| dictionary->SetString(key, string_value); |
| } |
| |
| // Deserializes a 64bit integer stored as a string value. |
| bool ReadInt64(const base::DictionaryValue* dictionary, |
| const char* key, |
| int64* value) { |
| if (!dictionary) |
| return false; |
| |
| std::string string_value; |
| if (!dictionary->GetString(key, &string_value)) |
| return false; |
| |
| return base::StringToInt64(string_value, value); |
| } |
| |
| // Serializes |time| as a string value mapped to |key| in |dictionary|. |
| void SaveTime(base::DictionaryValue* dictionary, |
| const char* key, |
| const base::Time& time) { |
| SaveInt64(dictionary, key, time.ToInternalValue()); |
| } |
| |
| // The opposite of SaveTime. If |key| is not found, this returns an empty Time |
| // (is_null() will return true). |
| base::Time ReadTime(const base::DictionaryValue* dictionary, const char* key) { |
| int64 value; |
| if (ReadInt64(dictionary, key, &value)) |
| return base::Time::FromInternalValue(value); |
| |
| return base::Time(); |
| } |
| |
| } // namespace |
| |
| base::Time ExtensionPrefs::LastPingDay(const std::string& extension_id) const { |
| DCHECK(Extension::IdIsValid(extension_id)); |
| return ReadTime(GetExtensionPref(extension_id), kLastPingDay); |
| } |
| |
| void ExtensionPrefs::SetLastPingDay(const std::string& extension_id, |
| const base::Time& time) { |
| DCHECK(Extension::IdIsValid(extension_id)); |
| ScopedExtensionPrefUpdate update(prefs_, extension_id); |
| SaveTime(update.Get(), kLastPingDay, time); |
| } |
| |
| base::Time ExtensionPrefs::BlacklistLastPingDay() const { |
| return ReadTime(prefs_->GetDictionary(kExtensionsBlacklistUpdate), |
| kLastPingDay); |
| } |
| |
| void ExtensionPrefs::SetBlacklistLastPingDay(const base::Time& time) { |
| DictionaryPrefUpdate update(prefs_, kExtensionsBlacklistUpdate); |
| SaveTime(update.Get(), kLastPingDay, time); |
| } |
| |
| base::Time ExtensionPrefs::LastActivePingDay(const std::string& extension_id) { |
| DCHECK(Extension::IdIsValid(extension_id)); |
| return ReadTime(GetExtensionPref(extension_id), kLastActivePingDay); |
| } |
| |
| void ExtensionPrefs::SetLastActivePingDay(const std::string& extension_id, |
| const base::Time& time) { |
| DCHECK(Extension::IdIsValid(extension_id)); |
| ScopedExtensionPrefUpdate update(prefs_, extension_id); |
| SaveTime(update.Get(), kLastActivePingDay, time); |
| } |
| |
| bool ExtensionPrefs::GetActiveBit(const std::string& extension_id) { |
| const base::DictionaryValue* dictionary = GetExtensionPref(extension_id); |
| bool result = false; |
| if (dictionary && dictionary->GetBoolean(kActiveBit, &result)) |
| return result; |
| return false; |
| } |
| |
| void ExtensionPrefs::SetActiveBit(const std::string& extension_id, |
| bool active) { |
| UpdateExtensionPref(extension_id, kActiveBit, |
| new base::FundamentalValue(active)); |
| } |
| |
| void ExtensionPrefs::MigratePermissions(const ExtensionIdList& extension_ids) { |
| PermissionsInfo* info = PermissionsInfo::GetInstance(); |
| for (ExtensionIdList::const_iterator ext_id = |
| extension_ids.begin(); ext_id != extension_ids.end(); ++ext_id) { |
| // An extension's granted permissions need to be migrated if the |
| // full_access bit is present. This bit was always present in the previous |
| // scheme and is never present now. |
| bool full_access; |
| const base::DictionaryValue* ext = GetExtensionPref(*ext_id); |
| if (!ext || !ext->GetBoolean(kPrefOldGrantedFullAccess, &full_access)) |
| continue; |
| |
| // Remove the full access bit (empty list will get trimmed). |
| UpdateExtensionPref( |
| *ext_id, kPrefOldGrantedFullAccess, new base::ListValue()); |
| |
| // Add the plugin permission if the full access bit was set. |
| if (full_access) { |
| const base::ListValue* apis = NULL; |
| base::ListValue* new_apis = NULL; |
| |
| std::string granted_apis = JoinPrefs(kPrefGrantedPermissions, kPrefAPIs); |
| if (ext->GetList(kPrefOldGrantedAPIs, &apis)) |
| new_apis = apis->DeepCopy(); |
| else |
| new_apis = new base::ListValue(); |
| |
| std::string plugin_name = info->GetByID(APIPermission::kPlugin)->name(); |
| new_apis->Append(new base::StringValue(plugin_name)); |
| UpdateExtensionPref(*ext_id, granted_apis, new_apis); |
| } |
| |
| // The granted permissions originally only held the effective hosts, |
| // which are a combination of host and user script host permissions. |
| // We now maintain these lists separately. For migration purposes, it |
| // does not matter how we treat the old effective hosts as long as the |
| // new effective hosts will be the same, so we move them to explicit |
| // host permissions. |
| const base::ListValue* hosts = NULL; |
| std::string explicit_hosts = |
| JoinPrefs(kPrefGrantedPermissions, kPrefExplicitHosts); |
| if (ext->GetList(kPrefOldGrantedHosts, &hosts)) { |
| UpdateExtensionPref( |
| *ext_id, explicit_hosts, hosts->DeepCopy()); |
| |
| // We can get rid of the old one by setting it to an empty list. |
| UpdateExtensionPref(*ext_id, kPrefOldGrantedHosts, new base::ListValue()); |
| } |
| } |
| } |
| |
| void ExtensionPrefs::MigrateDisableReasons( |
| const ExtensionIdList& extension_ids) { |
| for (ExtensionIdList::const_iterator ext_id = |
| extension_ids.begin(); ext_id != extension_ids.end(); ++ext_id) { |
| int value = -1; |
| if (ReadPrefAsInteger(*ext_id, kDeprecatedPrefDisableReason, &value)) { |
| int new_value = Extension::DISABLE_NONE; |
| switch (value) { |
| case Extension::DEPRECATED_DISABLE_USER_ACTION: |
| new_value = Extension::DISABLE_USER_ACTION; |
| break; |
| case Extension::DEPRECATED_DISABLE_PERMISSIONS_INCREASE: |
| new_value = Extension::DISABLE_PERMISSIONS_INCREASE; |
| break; |
| case Extension::DEPRECATED_DISABLE_RELOAD: |
| new_value = Extension::DISABLE_RELOAD; |
| break; |
| } |
| |
| UpdateExtensionPref(*ext_id, kPrefDisableReasons, |
| new base::FundamentalValue(new_value)); |
| // Remove the old disable reason. |
| UpdateExtensionPref(*ext_id, kDeprecatedPrefDisableReason, NULL); |
| } |
| } |
| } |
| |
| PermissionSet* ExtensionPrefs::GetGrantedPermissions( |
| const std::string& extension_id) { |
| CHECK(Extension::IdIsValid(extension_id)); |
| return ReadPrefAsPermissionSet(extension_id, kPrefGrantedPermissions); |
| } |
| |
| void ExtensionPrefs::AddGrantedPermissions( |
| const std::string& extension_id, |
| const PermissionSet* permissions) { |
| CHECK(Extension::IdIsValid(extension_id)); |
| |
| scoped_refptr<PermissionSet> granted_permissions( |
| GetGrantedPermissions(extension_id)); |
| |
| // The new granted permissions are the union of the already granted |
| // permissions and the newly granted permissions. |
| scoped_refptr<PermissionSet> new_perms( |
| PermissionSet::CreateUnion( |
| permissions, granted_permissions.get())); |
| |
| SetExtensionPrefPermissionSet( |
| extension_id, kPrefGrantedPermissions, new_perms.get()); |
| } |
| |
| void ExtensionPrefs::RemoveGrantedPermissions( |
| const std::string& extension_id, |
| const PermissionSet* permissions) { |
| CHECK(Extension::IdIsValid(extension_id)); |
| |
| scoped_refptr<PermissionSet> granted_permissions( |
| GetGrantedPermissions(extension_id)); |
| |
| // The new granted permissions are the difference of the already granted |
| // permissions and the newly ungranted permissions. |
| scoped_refptr<PermissionSet> new_perms( |
| PermissionSet::CreateDifference( |
| granted_permissions.get(), permissions)); |
| |
| SetExtensionPrefPermissionSet( |
| extension_id, kPrefGrantedPermissions, new_perms.get()); |
| } |
| |
| PermissionSet* ExtensionPrefs::GetActivePermissions( |
| const std::string& extension_id) { |
| CHECK(Extension::IdIsValid(extension_id)); |
| return ReadPrefAsPermissionSet(extension_id, kPrefActivePermissions); |
| } |
| |
| void ExtensionPrefs::SetActivePermissions( |
| const std::string& extension_id, |
| const PermissionSet* permissions) { |
| SetExtensionPrefPermissionSet( |
| extension_id, kPrefActivePermissions, permissions); |
| } |
| |
| void ExtensionPrefs::SetExtensionRunning(const std::string& extension_id, |
| bool is_running) { |
| base::Value* value = new base::FundamentalValue(is_running); |
| UpdateExtensionPref(extension_id, kPrefRunning, value); |
| } |
| |
| bool ExtensionPrefs::IsExtensionRunning(const std::string& extension_id) { |
| const base::DictionaryValue* extension = GetExtensionPref(extension_id); |
| if (!extension) |
| return false; |
| bool running = false; |
| extension->GetBoolean(kPrefRunning, &running); |
| return running; |
| } |
| |
| void ExtensionPrefs::SetIsActive(const std::string& extension_id, |
| bool is_active) { |
| base::Value* value = new base::FundamentalValue(is_active); |
| UpdateExtensionPref(extension_id, kIsActive, value); |
| } |
| |
| bool ExtensionPrefs::IsActive(const std::string& extension_id) { |
| const base::DictionaryValue* extension = GetExtensionPref(extension_id); |
| if (!extension) |
| return false; |
| bool is_active = false; |
| extension->GetBoolean(kIsActive, &is_active); |
| return is_active; |
| } |
| |
| bool ExtensionPrefs::IsIncognitoEnabled(const std::string& extension_id) const { |
| return ReadPrefAsBooleanAndReturn(extension_id, kPrefIncognitoEnabled); |
| } |
| |
| void ExtensionPrefs::SetIsIncognitoEnabled(const std::string& extension_id, |
| bool enabled) { |
| UpdateExtensionPref(extension_id, kPrefIncognitoEnabled, |
| new base::FundamentalValue(enabled)); |
| extension_pref_value_map_->SetExtensionIncognitoState(extension_id, enabled); |
| } |
| |
| bool ExtensionPrefs::AllowFileAccess(const std::string& extension_id) const { |
| return ReadPrefAsBooleanAndReturn(extension_id, kPrefAllowFileAccess); |
| } |
| |
| void ExtensionPrefs::SetAllowFileAccess(const std::string& extension_id, |
| bool allow) { |
| UpdateExtensionPref(extension_id, kPrefAllowFileAccess, |
| new base::FundamentalValue(allow)); |
| } |
| |
| bool ExtensionPrefs::HasAllowFileAccessSetting( |
| const std::string& extension_id) const { |
| const base::DictionaryValue* ext = GetExtensionPref(extension_id); |
| return ext && ext->HasKey(kPrefAllowFileAccess); |
| } |
| |
| bool ExtensionPrefs::DoesExtensionHaveState( |
| const std::string& id, Extension::State check_state) const { |
| const base::DictionaryValue* extension = GetExtensionPref(id); |
| int state = -1; |
| if (!extension || !extension->GetInteger(kPrefState, &state)) |
| return false; |
| |
| if (state < 0 || state >= Extension::NUM_STATES) { |
| LOG(ERROR) << "Bad pref 'state' for extension '" << id << "'"; |
| return false; |
| } |
| |
| return state == check_state; |
| } |
| |
| bool ExtensionPrefs::IsExternalExtensionUninstalled( |
| const std::string& id) const { |
| return DoesExtensionHaveState(id, Extension::EXTERNAL_EXTENSION_UNINSTALLED); |
| } |
| |
| bool ExtensionPrefs::IsExtensionDisabled( |
| const std::string& id) const { |
| return DoesExtensionHaveState(id, Extension::DISABLED); |
| } |
| |
| ExtensionIdList ExtensionPrefs::GetToolbarOrder() { |
| ExtensionIdList id_list_out; |
| GetUserExtensionPrefIntoContainer(pref_names::kToolbar, &id_list_out); |
| return id_list_out; |
| } |
| |
| void ExtensionPrefs::SetToolbarOrder(const ExtensionIdList& extension_ids) { |
| SetExtensionPrefFromContainer(pref_names::kToolbar, extension_ids); |
| } |
| |
| bool ExtensionPrefs::GetKnownDisabled(ExtensionIdSet* id_set_out) { |
| return GetUserExtensionPrefIntoContainer(pref_names::kKnownDisabled, |
| id_set_out); |
| } |
| |
| void ExtensionPrefs::SetKnownDisabled(const ExtensionIdSet& extension_ids) { |
| SetExtensionPrefFromContainer(pref_names::kKnownDisabled, extension_ids); |
| } |
| |
| void ExtensionPrefs::OnExtensionInstalled( |
| const Extension* extension, |
| Extension::State initial_state, |
| bool blacklisted_for_malware, |
| const syncer::StringOrdinal& page_ordinal, |
| const std::string& install_parameter) { |
| ScopedExtensionPrefUpdate update(prefs_, extension->id()); |
| base::DictionaryValue* extension_dict = update.Get(); |
| const base::Time install_time = time_provider_->GetCurrentTime(); |
| PopulateExtensionInfoPrefs(extension, |
| install_time, |
| initial_state, |
| blacklisted_for_malware, |
| install_parameter, |
| extension_dict); |
| FinishExtensionInfoPrefs(extension->id(), install_time, |
| extension->RequiresSortOrdinal(), |
| page_ordinal, extension_dict); |
| } |
| |
| void ExtensionPrefs::OnExtensionUninstalled(const std::string& extension_id, |
| const Manifest::Location& location, |
| bool external_uninstall) { |
| app_sorting_->ClearOrdinals(extension_id); |
| |
| // For external extensions, we save a preference reminding ourself not to try |
| // and install the extension anymore (except when |external_uninstall| is |
| // true, which signifies that the registry key was deleted or the pref file |
| // no longer lists the extension). |
| if (!external_uninstall && Manifest::IsExternalLocation(location)) { |
| UpdateExtensionPref(extension_id, kPrefState, |
| new base::FundamentalValue( |
| Extension::EXTERNAL_EXTENSION_UNINSTALLED)); |
| extension_pref_value_map_->SetExtensionState(extension_id, false); |
| FOR_EACH_OBSERVER(ExtensionPrefsObserver, |
| observer_list_, |
| OnExtensionStateChanged(extension_id, false)); |
| } else { |
| int creation_flags = GetCreationFlags(extension_id); |
| if (creation_flags & Extension::IS_EPHEMERAL) { |
| // Keep ephemeral apps around, but mark them as evicted. |
| UpdateExtensionPref(extension_id, kPrefEvictedEphemeralApp, |
| new base::FundamentalValue(true)); |
| } else { |
| DeleteExtensionPrefs(extension_id); |
| } |
| } |
| } |
| |
| void ExtensionPrefs::SetExtensionState(const std::string& extension_id, |
| Extension::State state) { |
| UpdateExtensionPref(extension_id, kPrefState, |
| new base::FundamentalValue(state)); |
| bool enabled = (state == Extension::ENABLED); |
| extension_pref_value_map_->SetExtensionState(extension_id, enabled); |
| FOR_EACH_OBSERVER(ExtensionPrefsObserver, |
| observer_list_, |
| OnExtensionStateChanged(extension_id, enabled)); |
| } |
| |
| void ExtensionPrefs::SetExtensionBlacklistState(const std::string& extension_id, |
| BlacklistState state) { |
| SetExtensionBlacklisted(extension_id, state == BLACKLISTED_MALWARE); |
| UpdateExtensionPref(extension_id, kPrefBlacklistState, |
| new base::FundamentalValue(state)); |
| } |
| |
| BlacklistState ExtensionPrefs::GetExtensionBlacklistState( |
| const std::string& extension_id) { |
| if (IsExtensionBlacklisted(extension_id)) |
| return BLACKLISTED_MALWARE; |
| const base::DictionaryValue* ext_prefs = GetExtensionPref(extension_id); |
| int int_value; |
| if (ext_prefs && ext_prefs->GetInteger(kPrefBlacklistState, &int_value)) |
| return static_cast<BlacklistState>(int_value); |
| |
| return NOT_BLACKLISTED; |
| } |
| |
| std::string ExtensionPrefs::GetVersionString(const std::string& extension_id) { |
| const base::DictionaryValue* extension = GetExtensionPref(extension_id); |
| if (!extension) |
| return std::string(); |
| |
| std::string version; |
| extension->GetString(kPrefVersion, &version); |
| |
| return version; |
| } |
| |
| void ExtensionPrefs::UpdateManifest(const Extension* extension) { |
| if (!Manifest::IsUnpackedLocation(extension->location())) { |
| const base::DictionaryValue* extension_dict = |
| GetExtensionPref(extension->id()); |
| if (!extension_dict) |
| return; |
| const base::DictionaryValue* old_manifest = NULL; |
| bool update_required = |
| !extension_dict->GetDictionary(kPrefManifest, &old_manifest) || |
| !extension->manifest()->value()->Equals(old_manifest); |
| if (update_required) { |
| UpdateExtensionPref(extension->id(), kPrefManifest, |
| extension->manifest()->value()->DeepCopy()); |
| } |
| } |
| } |
| |
| base::FilePath ExtensionPrefs::GetExtensionPath( |
| const std::string& extension_id) { |
| const base::DictionaryValue* dict = GetExtensionPref(extension_id); |
| if (!dict) |
| return base::FilePath(); |
| |
| std::string path; |
| if (!dict->GetString(kPrefPath, &path)) |
| return base::FilePath(); |
| |
| return install_directory_.Append(base::FilePath::FromUTF8Unsafe(path)); |
| } |
| |
| scoped_ptr<ExtensionInfo> ExtensionPrefs::GetInstalledInfoHelper( |
| const std::string& extension_id, |
| const base::DictionaryValue* extension) const { |
| int location_value; |
| if (!extension->GetInteger(kPrefLocation, &location_value)) |
| return scoped_ptr<ExtensionInfo>(); |
| |
| base::FilePath::StringType path; |
| if (!extension->GetString(kPrefPath, &path)) |
| return scoped_ptr<ExtensionInfo>(); |
| |
| // Make path absolute. Unpacked extensions will already have absolute paths, |
| // otherwise make it so. |
| Manifest::Location location = static_cast<Manifest::Location>(location_value); |
| if (!Manifest::IsUnpackedLocation(location)) { |
| DCHECK(location == Manifest::COMPONENT || |
| !base::FilePath(path).IsAbsolute()); |
| path = install_directory_.Append(path).value(); |
| } |
| |
| // Only the following extension types have data saved in the preferences. |
| if (location != Manifest::INTERNAL && |
| !Manifest::IsUnpackedLocation(location) && |
| !Manifest::IsExternalLocation(location)) { |
| NOTREACHED(); |
| return scoped_ptr<ExtensionInfo>(); |
| } |
| |
| const base::DictionaryValue* manifest = NULL; |
| if (!Manifest::IsUnpackedLocation(location) && |
| !extension->GetDictionary(kPrefManifest, &manifest)) { |
| LOG(WARNING) << "Missing manifest for extension " << extension_id; |
| // Just a warning for now. |
| } |
| |
| return scoped_ptr<ExtensionInfo>(new ExtensionInfo( |
| manifest, extension_id, base::FilePath(path), location)); |
| } |
| |
| scoped_ptr<ExtensionInfo> ExtensionPrefs::GetInstalledExtensionInfo( |
| const std::string& extension_id) const { |
| const base::DictionaryValue* ext = NULL; |
| const base::DictionaryValue* extensions = |
| prefs_->GetDictionary(pref_names::kExtensions); |
| if (!extensions || |
| !extensions->GetDictionaryWithoutPathExpansion(extension_id, &ext)) |
| return scoped_ptr<ExtensionInfo>(); |
| int state_value; |
| if (!ext->GetInteger(kPrefState, &state_value) || |
| state_value == Extension::ENABLED_COMPONENT) { |
| // Old preferences files may not have kPrefState for component extensions. |
| return scoped_ptr<ExtensionInfo>(); |
| } |
| |
| if (state_value == Extension::EXTERNAL_EXTENSION_UNINSTALLED) { |
| LOG(WARNING) << "External extension with id " << extension_id |
| << " has been uninstalled by the user"; |
| return scoped_ptr<ExtensionInfo>(); |
| } |
| |
| if (IsEvictedEphemeralApp(ext)) { |
| // Hide evicted ephemeral apps. |
| return scoped_ptr<ExtensionInfo>(); |
| } |
| |
| return GetInstalledInfoHelper(extension_id, ext); |
| } |
| |
| scoped_ptr<ExtensionPrefs::ExtensionsInfo> |
| ExtensionPrefs::GetInstalledExtensionsInfo() const { |
| scoped_ptr<ExtensionsInfo> extensions_info(new ExtensionsInfo); |
| |
| const base::DictionaryValue* extensions = |
| prefs_->GetDictionary(pref_names::kExtensions); |
| for (base::DictionaryValue::Iterator extension_id(*extensions); |
| !extension_id.IsAtEnd(); extension_id.Advance()) { |
| if (!Extension::IdIsValid(extension_id.key())) |
| continue; |
| |
| scoped_ptr<ExtensionInfo> info = |
| GetInstalledExtensionInfo(extension_id.key()); |
| if (info) |
| extensions_info->push_back(linked_ptr<ExtensionInfo>(info.release())); |
| } |
| |
| return extensions_info.Pass(); |
| } |
| |
| scoped_ptr<ExtensionPrefs::ExtensionsInfo> |
| ExtensionPrefs::GetUninstalledExtensionsInfo() const { |
| scoped_ptr<ExtensionsInfo> extensions_info(new ExtensionsInfo); |
| |
| const base::DictionaryValue* extensions = |
| prefs_->GetDictionary(pref_names::kExtensions); |
| for (base::DictionaryValue::Iterator extension_id(*extensions); |
| !extension_id.IsAtEnd(); extension_id.Advance()) { |
| const base::DictionaryValue* ext = NULL; |
| if (!Extension::IdIsValid(extension_id.key()) || |
| !IsExternalExtensionUninstalled(extension_id.key()) || |
| !extension_id.value().GetAsDictionary(&ext)) |
| continue; |
| |
| scoped_ptr<ExtensionInfo> info = |
| GetInstalledInfoHelper(extension_id.key(), ext); |
| if (info) |
| extensions_info->push_back(linked_ptr<ExtensionInfo>(info.release())); |
| } |
| |
| return extensions_info.Pass(); |
| } |
| |
| void ExtensionPrefs::SetDelayedInstallInfo( |
| const Extension* extension, |
| Extension::State initial_state, |
| bool blacklisted_for_malware, |
| DelayReason delay_reason, |
| const syncer::StringOrdinal& page_ordinal, |
| const std::string& install_parameter) { |
| base::DictionaryValue* extension_dict = new base::DictionaryValue(); |
| PopulateExtensionInfoPrefs(extension, |
| time_provider_->GetCurrentTime(), |
| initial_state, |
| blacklisted_for_malware, |
| install_parameter, |
| extension_dict); |
| |
| // Add transient data that is needed by FinishDelayedInstallInfo(), but |
| // should not be in the final extension prefs. All entries here should have |
| // a corresponding Remove() call in FinishDelayedInstallInfo(). |
| if (extension->RequiresSortOrdinal()) { |
| extension_dict->SetString( |
| kPrefSuggestedPageOrdinal, |
| page_ordinal.IsValid() ? page_ordinal.ToInternalValue() |
| : std::string()); |
| } |
| extension_dict->SetInteger(kDelayedInstallReason, |
| static_cast<int>(delay_reason)); |
| |
| UpdateExtensionPref(extension->id(), kDelayedInstallInfo, extension_dict); |
| } |
| |
| bool ExtensionPrefs::RemoveDelayedInstallInfo( |
| const std::string& extension_id) { |
| if (!GetExtensionPref(extension_id)) |
| return false; |
| ScopedExtensionPrefUpdate update(prefs_, extension_id); |
| bool result = update->Remove(kDelayedInstallInfo, NULL); |
| return result; |
| } |
| |
| bool ExtensionPrefs::FinishDelayedInstallInfo( |
| const std::string& extension_id) { |
| CHECK(Extension::IdIsValid(extension_id)); |
| ScopedExtensionPrefUpdate update(prefs_, extension_id); |
| base::DictionaryValue* extension_dict = update.Get(); |
| base::DictionaryValue* pending_install_dict = NULL; |
| if (!extension_dict->GetDictionary(kDelayedInstallInfo, |
| &pending_install_dict)) { |
| return false; |
| } |
| |
| // Retrieve and clear transient values populated by SetDelayedInstallInfo(). |
| // Also do any other data cleanup that makes sense. |
| std::string serialized_ordinal; |
| syncer::StringOrdinal suggested_page_ordinal; |
| bool needs_sort_ordinal = false; |
| if (pending_install_dict->GetString(kPrefSuggestedPageOrdinal, |
| &serialized_ordinal)) { |
| suggested_page_ordinal = syncer::StringOrdinal(serialized_ordinal); |
| needs_sort_ordinal = true; |
| pending_install_dict->Remove(kPrefSuggestedPageOrdinal, NULL); |
| } |
| pending_install_dict->Remove(kDelayedInstallReason, NULL); |
| |
| const base::Time install_time = time_provider_->GetCurrentTime(); |
| pending_install_dict->Set( |
| kPrefInstallTime, |
| new base::StringValue( |
| base::Int64ToString(install_time.ToInternalValue()))); |
| |
| // Commit the delayed install data. |
| for (base::DictionaryValue::Iterator it(*pending_install_dict); !it.IsAtEnd(); |
| it.Advance()) { |
| extension_dict->Set(it.key(), it.value().DeepCopy()); |
| } |
| FinishExtensionInfoPrefs(extension_id, install_time, needs_sort_ordinal, |
| suggested_page_ordinal, extension_dict); |
| return true; |
| } |
| |
| scoped_ptr<ExtensionInfo> ExtensionPrefs::GetDelayedInstallInfo( |
| const std::string& extension_id) const { |
| const base::DictionaryValue* extension_prefs = |
| GetExtensionPref(extension_id); |
| if (!extension_prefs) |
| return scoped_ptr<ExtensionInfo>(); |
| |
| const base::DictionaryValue* ext = NULL; |
| if (!extension_prefs->GetDictionary(kDelayedInstallInfo, &ext)) |
| return scoped_ptr<ExtensionInfo>(); |
| |
| return GetInstalledInfoHelper(extension_id, ext); |
| } |
| |
| ExtensionPrefs::DelayReason ExtensionPrefs::GetDelayedInstallReason( |
| const std::string& extension_id) const { |
| const base::DictionaryValue* extension_prefs = |
| GetExtensionPref(extension_id); |
| if (!extension_prefs) |
| return DELAY_REASON_NONE; |
| |
| const base::DictionaryValue* ext = NULL; |
| if (!extension_prefs->GetDictionary(kDelayedInstallInfo, &ext)) |
| return DELAY_REASON_NONE; |
| |
| int delay_reason; |
| if (!ext->GetInteger(kDelayedInstallReason, &delay_reason)) |
| return DELAY_REASON_NONE; |
| |
| return static_cast<DelayReason>(delay_reason); |
| } |
| |
| scoped_ptr<ExtensionPrefs::ExtensionsInfo> ExtensionPrefs:: |
| GetAllDelayedInstallInfo() const { |
| scoped_ptr<ExtensionsInfo> extensions_info(new ExtensionsInfo); |
| |
| const base::DictionaryValue* extensions = |
| prefs_->GetDictionary(pref_names::kExtensions); |
| for (base::DictionaryValue::Iterator extension_id(*extensions); |
| !extension_id.IsAtEnd(); extension_id.Advance()) { |
| if (!Extension::IdIsValid(extension_id.key())) |
| continue; |
| |
| scoped_ptr<ExtensionInfo> info = GetDelayedInstallInfo(extension_id.key()); |
| if (info) |
| extensions_info->push_back(linked_ptr<ExtensionInfo>(info.release())); |
| } |
| |
| return extensions_info.Pass(); |
| } |
| |
| scoped_ptr<ExtensionPrefs::ExtensionsInfo> |
| ExtensionPrefs::GetEvictedEphemeralAppsInfo() const { |
| scoped_ptr<ExtensionsInfo> extensions_info(new ExtensionsInfo); |
| |
| const base::DictionaryValue* extensions = |
| prefs_->GetDictionary(pref_names::kExtensions); |
| for (base::DictionaryValue::Iterator extension_id(*extensions); |
| !extension_id.IsAtEnd(); extension_id.Advance()) { |
| const base::DictionaryValue* ext = NULL; |
| if (!Extension::IdIsValid(extension_id.key()) || |
| !extension_id.value().GetAsDictionary(&ext)) { |
| continue; |
| } |
| |
| if (!IsEvictedEphemeralApp(ext)) |
| continue; |
| |
| scoped_ptr<ExtensionInfo> info = |
| GetInstalledInfoHelper(extension_id.key(), ext); |
| if (info) |
| extensions_info->push_back(linked_ptr<ExtensionInfo>(info.release())); |
| } |
| |
| return extensions_info.Pass(); |
| } |
| |
| scoped_ptr<ExtensionInfo> ExtensionPrefs::GetEvictedEphemeralAppInfo( |
| const std::string& extension_id) const { |
| const base::DictionaryValue* extension_prefs = GetExtensionPref(extension_id); |
| if (!extension_prefs) |
| return scoped_ptr<ExtensionInfo>(); |
| |
| if (!IsEvictedEphemeralApp(extension_prefs)) |
| return scoped_ptr<ExtensionInfo>(); |
| |
| return GetInstalledInfoHelper(extension_id, extension_prefs); |
| } |
| |
| void ExtensionPrefs::RemoveEvictedEphemeralApp( |
| const std::string& extension_id) { |
| bool evicted_ephemeral_app = false; |
| if (ReadPrefAsBoolean(extension_id, |
| kPrefEvictedEphemeralApp, |
| &evicted_ephemeral_app) && evicted_ephemeral_app) { |
| DeleteExtensionPrefs(extension_id); |
| } |
| } |
| |
| bool ExtensionPrefs::WasAppDraggedByUser(const std::string& extension_id) { |
| return ReadPrefAsBooleanAndReturn(extension_id, kPrefUserDraggedApp); |
| } |
| |
| void ExtensionPrefs::SetAppDraggedByUser(const std::string& extension_id) { |
| UpdateExtensionPref(extension_id, kPrefUserDraggedApp, |
| new base::FundamentalValue(true)); |
| } |
| |
| bool ExtensionPrefs::IsFromWebStore( |
| const std::string& extension_id) const { |
| const base::DictionaryValue* dictionary = GetExtensionPref(extension_id); |
| bool result = false; |
| if (dictionary && dictionary->GetBoolean(kPrefFromWebStore, &result)) |
| return result; |
| return false; |
| } |
| |
| bool ExtensionPrefs::IsFromBookmark( |
| const std::string& extension_id) const { |
| const base::DictionaryValue* dictionary = GetExtensionPref(extension_id); |
| bool result = false; |
| if (dictionary && dictionary->GetBoolean(kPrefFromBookmark, &result)) |
| return result; |
| return false; |
| } |
| |
| int ExtensionPrefs::GetCreationFlags(const std::string& extension_id) const { |
| int creation_flags = Extension::NO_FLAGS; |
| if (!ReadPrefAsInteger(extension_id, kPrefCreationFlags, &creation_flags)) { |
| // Since kPrefCreationFlags was added later, it will be missing for |
| // previously installed extensions. |
| if (IsFromBookmark(extension_id)) |
| creation_flags |= Extension::FROM_BOOKMARK; |
| if (IsFromWebStore(extension_id)) |
| creation_flags |= Extension::FROM_WEBSTORE; |
| if (WasInstalledByDefault(extension_id)) |
| creation_flags |= Extension::WAS_INSTALLED_BY_DEFAULT; |
| if (WasInstalledByOem(extension_id)) |
| creation_flags |= Extension::WAS_INSTALLED_BY_OEM; |
| } |
| return creation_flags; |
| } |
| |
| int ExtensionPrefs::GetDelayedInstallCreationFlags( |
| const std::string& extension_id) const { |
| int creation_flags = Extension::NO_FLAGS; |
| const base::DictionaryValue* delayed_info = NULL; |
| if (ReadPrefAsDictionary(extension_id, kDelayedInstallInfo, &delayed_info)) { |
| delayed_info->GetInteger(kPrefCreationFlags, &creation_flags); |
| } |
| return creation_flags; |
| } |
| |
| bool ExtensionPrefs::WasInstalledByDefault( |
| const std::string& extension_id) const { |
| const base::DictionaryValue* dictionary = GetExtensionPref(extension_id); |
| bool result = false; |
| if (dictionary && |
| dictionary->GetBoolean(kPrefWasInstalledByDefault, &result)) |
| return result; |
| return false; |
| } |
| |
| bool ExtensionPrefs::WasInstalledByOem(const std::string& extension_id) const { |
| const base::DictionaryValue* dictionary = GetExtensionPref(extension_id); |
| bool result = false; |
| if (dictionary && dictionary->GetBoolean(kPrefWasInstalledByOem, &result)) |
| return result; |
| return false; |
| } |
| |
| base::Time ExtensionPrefs::GetInstallTime( |
| const std::string& extension_id) const { |
| const base::DictionaryValue* extension = GetExtensionPref(extension_id); |
| if (!extension) { |
| NOTREACHED(); |
| return base::Time(); |
| } |
| std::string install_time_str; |
| if (!extension->GetString(kPrefInstallTime, &install_time_str)) |
| return base::Time(); |
| int64 install_time_i64 = 0; |
| if (!base::StringToInt64(install_time_str, &install_time_i64)) |
| return base::Time(); |
| return base::Time::FromInternalValue(install_time_i64); |
| } |
| |
| base::Time ExtensionPrefs::GetLastLaunchTime( |
| const std::string& extension_id) const { |
| const base::DictionaryValue* extension = GetExtensionPref(extension_id); |
| if (!extension) |
| return base::Time(); |
| |
| std::string launch_time_str; |
| if (!extension->GetString(kPrefLastLaunchTime, &launch_time_str)) |
| return base::Time(); |
| int64 launch_time_i64 = 0; |
| if (!base::StringToInt64(launch_time_str, &launch_time_i64)) |
| return base::Time(); |
| return base::Time::FromInternalValue(launch_time_i64); |
| } |
| |
| void ExtensionPrefs::SetLastLaunchTime(const std::string& extension_id, |
| const base::Time& time) { |
| DCHECK(Extension::IdIsValid(extension_id)); |
| ScopedExtensionPrefUpdate update(prefs_, extension_id); |
| SaveTime(update.Get(), kPrefLastLaunchTime, time); |
| } |
| |
| void ExtensionPrefs::GetExtensions(ExtensionIdList* out) { |
| CHECK(out); |
| |
| scoped_ptr<ExtensionsInfo> extensions_info(GetInstalledExtensionsInfo()); |
| |
| for (size_t i = 0; i < extensions_info->size(); ++i) { |
| ExtensionInfo* info = extensions_info->at(i).get(); |
| out->push_back(info->extension_id); |
| } |
| } |
| |
| // static |
| ExtensionIdList ExtensionPrefs::GetExtensionsFrom( |
| const PrefService* pref_service) { |
| ExtensionIdList result; |
| |
| const base::DictionaryValue* extension_prefs = NULL; |
| const base::Value* extension_prefs_value = |
| pref_service->GetUserPrefValue(pref_names::kExtensions); |
| if (!extension_prefs_value || |
| !extension_prefs_value->GetAsDictionary(&extension_prefs)) { |
| return result; // Empty set |
| } |
| |
| for (base::DictionaryValue::Iterator it(*extension_prefs); !it.IsAtEnd(); |
| it.Advance()) { |
| const base::DictionaryValue* ext = NULL; |
| if (!it.value().GetAsDictionary(&ext)) { |
| NOTREACHED() << "Invalid pref for extension " << it.key(); |
| continue; |
| } |
| if (!IsBlacklistBitSet(ext)) |
| result.push_back(it.key()); |
| } |
| return result; |
| } |
| |
| void ExtensionPrefs::AddObserver(ExtensionPrefsObserver* observer) { |
| observer_list_.AddObserver(observer); |
| } |
| |
| void ExtensionPrefs::RemoveObserver(ExtensionPrefsObserver* observer) { |
| observer_list_.RemoveObserver(observer); |
| } |
| |
| void ExtensionPrefs::FixMissingPrefs(const ExtensionIdList& extension_ids) { |
| // Fix old entries that did not get an installation time entry when they |
| // were installed or don't have a preferences field. |
| for (ExtensionIdList::const_iterator ext_id = extension_ids.begin(); |
| ext_id != extension_ids.end(); ++ext_id) { |
| if (GetInstallTime(*ext_id) == base::Time()) { |
| VLOG(1) << "Could not parse installation time of extension " |
| << *ext_id << ". It was probably installed before setting " |
| << kPrefInstallTime << " was introduced. Updating " |
| << kPrefInstallTime << " to the current time."; |
| const base::Time install_time = time_provider_->GetCurrentTime(); |
| UpdateExtensionPref(*ext_id, |
| kPrefInstallTime, |
| new base::StringValue(base::Int64ToString( |
| install_time.ToInternalValue()))); |
| } |
| } |
| } |
| |
| void ExtensionPrefs::InitPrefStore() { |
| if (extensions_disabled_) { |
| extension_pref_value_map_->NotifyInitializationCompleted(); |
| return; |
| } |
| |
| // When this is called, the PrefService is initialized and provides access |
| // to the user preferences stored in a JSON file. |
| ExtensionIdList extension_ids; |
| GetExtensions(&extension_ids); |
| // Create empty preferences dictionary for each extension (these dictionaries |
| // are pruned when persisting the preferences to disk). |
| for (ExtensionIdList::iterator ext_id = extension_ids.begin(); |
| ext_id != extension_ids.end(); ++ext_id) { |
| ScopedExtensionPrefUpdate update(prefs_, *ext_id); |
| // This creates an empty dictionary if none is stored. |
| update.Get(); |
| } |
| |
| FixMissingPrefs(extension_ids); |
| MigratePermissions(extension_ids); |
| MigrateDisableReasons(extension_ids); |
| app_sorting_->Initialize(extension_ids); |
| |
| InitExtensionControlledPrefs(extension_pref_value_map_); |
| |
| extension_pref_value_map_->NotifyInitializationCompleted(); |
| } |
| |
| bool ExtensionPrefs::HasIncognitoPrefValue(const std::string& pref_key) { |
| bool has_incognito_pref_value = false; |
| extension_pref_value_map_->GetEffectivePrefValue(pref_key, |
| true, |
| &has_incognito_pref_value); |
| return has_incognito_pref_value; |
| } |
| |
| URLPatternSet ExtensionPrefs::GetAllowedInstallSites() { |
| URLPatternSet result; |
| const base::ListValue* list = |
| prefs_->GetList(pref_names::kAllowedInstallSites); |
| CHECK(list); |
| |
| for (size_t i = 0; i < list->GetSize(); ++i) { |
| std::string entry_string; |
| URLPattern entry(URLPattern::SCHEME_ALL); |
| if (!list->GetString(i, &entry_string) || |
| entry.Parse(entry_string) != URLPattern::PARSE_SUCCESS) { |
| LOG(ERROR) << "Invalid value for preference: " |
| << pref_names::kAllowedInstallSites << "." << i; |
| continue; |
| } |
| result.AddPattern(entry); |
| } |
| |
| return result; |
| } |
| |
| const base::DictionaryValue* ExtensionPrefs::GetGeometryCache( |
| const std::string& extension_id) const { |
| const base::DictionaryValue* extension_prefs = GetExtensionPref(extension_id); |
| if (!extension_prefs) |
| return NULL; |
| |
| const base::DictionaryValue* ext = NULL; |
| if (!extension_prefs->GetDictionary(kPrefGeometryCache, &ext)) |
| return NULL; |
| |
| return ext; |
| } |
| |
| void ExtensionPrefs::SetGeometryCache( |
| const std::string& extension_id, |
| scoped_ptr<base::DictionaryValue> cache) { |
| UpdateExtensionPref(extension_id, kPrefGeometryCache, cache.release()); |
| } |
| |
| const base::DictionaryValue* ExtensionPrefs::GetInstallSignature() { |
| return prefs_->GetDictionary(kInstallSignature); |
| } |
| |
| void ExtensionPrefs::SetInstallSignature( |
| const base::DictionaryValue* signature) { |
| if (signature) { |
| prefs_->Set(kInstallSignature, *signature); |
| DVLOG(1) << "SetInstallSignature - saving"; |
| } else { |
| DVLOG(1) << "SetInstallSignature - clearing"; |
| prefs_->ClearPref(kInstallSignature); |
| } |
| } |
| |
| std::string ExtensionPrefs::GetInstallParam( |
| const std::string& extension_id) const { |
| const base::DictionaryValue* extension = GetExtensionPref(extension_id); |
| if (!extension) // Expected during unit testing. |
| return std::string(); |
| std::string install_parameter; |
| if (!extension->GetString(kPrefInstallParam, &install_parameter)) |
| return std::string(); |
| return install_parameter; |
| } |
| |
| void ExtensionPrefs::SetInstallParam(const std::string& extension_id, |
| const std::string& install_parameter) { |
| UpdateExtensionPref(extension_id, |
| kPrefInstallParam, |
| new base::StringValue(install_parameter)); |
| } |
| |
| int64 ExtensionPrefs::GetNextStorageThreshold( |
| const std::string& extension_id) const { |
| int64 next_threshold; |
| if (ReadInt64(GetExtensionPref(extension_id), |
| kPrefNextStorageThreshold, |
| &next_threshold)) { |
| return next_threshold; |
| } |
| |
| return 0; |
| } |
| |
| void ExtensionPrefs::SetNextStorageThreshold(const std::string& extension_id, |
| int64 next_threshold) { |
| ScopedExtensionPrefUpdate update(prefs_, extension_id); |
| SaveInt64(update.Get(), kPrefNextStorageThreshold, next_threshold); |
| } |
| |
| bool ExtensionPrefs::IsStorageNotificationEnabled( |
| const std::string& extension_id) const { |
| bool disable_notifications; |
| if (ReadPrefAsBoolean(extension_id, |
| kPrefDisableStorageNotifications, |
| &disable_notifications)) { |
| return !disable_notifications; |
| } |
| |
| return true; |
| } |
| |
| void ExtensionPrefs::SetStorageNotificationEnabled( |
| const std::string& extension_id, bool enable_notifications) { |
| UpdateExtensionPref( |
| extension_id, |
| kPrefDisableStorageNotifications, |
| enable_notifications ? NULL : new base::FundamentalValue(true)); |
| } |
| |
| ExtensionPrefs::ExtensionPrefs( |
| PrefService* prefs, |
| const base::FilePath& root_dir, |
| ExtensionPrefValueMap* extension_pref_value_map, |
| scoped_ptr<AppSorting> app_sorting, |
| scoped_ptr<TimeProvider> time_provider, |
| bool extensions_disabled, |
| const std::vector<ExtensionPrefsObserver*>& early_observers) |
| : prefs_(prefs), |
| install_directory_(root_dir), |
| extension_pref_value_map_(extension_pref_value_map), |
| app_sorting_(app_sorting.Pass()), |
| time_provider_(time_provider.Pass()), |
| extensions_disabled_(extensions_disabled) { |
| app_sorting_->SetExtensionScopedPrefs(this); |
| MakePathsRelative(); |
| |
| // Ensure that any early observers are watching before prefs are initialized. |
| for (std::vector<ExtensionPrefsObserver*>::const_iterator iter = |
| early_observers.begin(); |
| iter != early_observers.end(); |
| ++iter) { |
| AddObserver(*iter); |
| } |
| |
| InitPrefStore(); |
| } |
| |
| void ExtensionPrefs::SetNeedsStorageGarbageCollection(bool value) { |
| prefs_->SetBoolean(pref_names::kStorageGarbageCollect, value); |
| } |
| |
| bool ExtensionPrefs::NeedsStorageGarbageCollection() { |
| return prefs_->GetBoolean(pref_names::kStorageGarbageCollect); |
| } |
| |
| // static |
| void ExtensionPrefs::RegisterProfilePrefs( |
| user_prefs::PrefRegistrySyncable* registry) { |
| registry->RegisterDictionaryPref( |
| pref_names::kExtensions, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterListPref(pref_names::kToolbar, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| registry->RegisterIntegerPref( |
| pref_names::kToolbarSize, |
| -1, // default value |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterDictionaryPref( |
| kExtensionsBlacklistUpdate, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterListPref(pref_names::kInstallAllowList, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterListPref(pref_names::kInstallDenyList, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterDictionaryPref( |
| pref_names::kInstallForceList, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterListPref(pref_names::kAllowedTypes, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterBooleanPref( |
| pref_names::kStorageGarbageCollect, |
| false, // default value |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterInt64Pref( |
| pref_names::kLastUpdateCheck, |
| 0, // default value |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterInt64Pref( |
| pref_names::kNextUpdateCheck, |
| 0, // default value |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterListPref(pref_names::kAllowedInstallSites, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterStringPref( |
| pref_names::kLastChromeVersion, |
| std::string(), // default value |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterListPref(pref_names::kKnownDisabled, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| #if defined(TOOLKIT_VIEWS) |
| registry->RegisterIntegerPref( |
| pref_names::kBrowserActionContainerWidth, |
| 0, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| #endif |
| registry->RegisterDictionaryPref( |
| kInstallSignature, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| |
| registry->RegisterListPref(pref_names::kNativeMessagingBlacklist, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterListPref(pref_names::kNativeMessagingWhitelist, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterBooleanPref( |
| pref_names::kNativeMessagingUserLevelHosts, |
| true, // default value |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| } |
| |
| template <class ExtensionIdContainer> |
| bool ExtensionPrefs::GetUserExtensionPrefIntoContainer( |
| const char* pref, |
| ExtensionIdContainer* id_container_out) { |
| DCHECK(id_container_out->empty()); |
| |
| const base::Value* user_pref_value = prefs_->GetUserPrefValue(pref); |
| const base::ListValue* user_pref_as_list; |
| if (!user_pref_value || !user_pref_value->GetAsList(&user_pref_as_list)) |
| return false; |
| |
| std::insert_iterator<ExtensionIdContainer> insert_iterator( |
| *id_container_out, id_container_out->end()); |
| std::string extension_id; |
| for (base::ListValue::const_iterator value_it = user_pref_as_list->begin(); |
| value_it != user_pref_as_list->end(); ++value_it) { |
| if (!(*value_it)->GetAsString(&extension_id)) { |
| NOTREACHED(); |
| continue; |
| } |
| insert_iterator = extension_id; |
| } |
| return true; |
| } |
| |
| template <class ExtensionIdContainer> |
| void ExtensionPrefs::SetExtensionPrefFromContainer( |
| const char* pref, |
| const ExtensionIdContainer& strings) { |
| ListPrefUpdate update(prefs_, pref); |
| base::ListValue* list_of_values = update.Get(); |
| list_of_values->Clear(); |
| for (typename ExtensionIdContainer::const_iterator iter = strings.begin(); |
| iter != strings.end(); ++iter) { |
| list_of_values->Append(new base::StringValue(*iter)); |
| } |
| } |
| |
| void ExtensionPrefs::PopulateExtensionInfoPrefs( |
| const Extension* extension, |
| const base::Time install_time, |
| Extension::State initial_state, |
| bool blacklisted_for_malware, |
| const std::string& install_parameter, |
| base::DictionaryValue* extension_dict) { |
| // Leave the state blank for component extensions so that old chrome versions |
| // loading new profiles do not fail in GetInstalledExtensionInfo. Older |
| // Chrome versions would only check for an omitted state. |
| if (initial_state != Extension::ENABLED_COMPONENT) |
| extension_dict->Set(kPrefState, new base::FundamentalValue(initial_state)); |
| |
| extension_dict->Set(kPrefLocation, |
| new base::FundamentalValue(extension->location())); |
| extension_dict->Set(kPrefCreationFlags, |
| new base::FundamentalValue(extension->creation_flags())); |
| extension_dict->Set(kPrefFromWebStore, |
| new base::FundamentalValue(extension->from_webstore())); |
| extension_dict->Set(kPrefFromBookmark, |
| new base::FundamentalValue(extension->from_bookmark())); |
| extension_dict->Set( |
| kPrefWasInstalledByDefault, |
| new base::FundamentalValue(extension->was_installed_by_default())); |
| extension_dict->Set( |
| kPrefWasInstalledByOem, |
| new base::FundamentalValue(extension->was_installed_by_oem())); |
| extension_dict->Set(kPrefInstallTime, |
| new base::StringValue( |
| base::Int64ToString(install_time.ToInternalValue()))); |
| if (blacklisted_for_malware) |
| extension_dict->Set(kPrefBlacklist, new base::FundamentalValue(true)); |
| |
| base::FilePath::StringType path = MakePathRelative(install_directory_, |
| extension->path()); |
| extension_dict->Set(kPrefPath, new base::StringValue(path)); |
| if (!install_parameter.empty()) { |
| extension_dict->Set(kPrefInstallParam, |
| new base::StringValue(install_parameter)); |
| } |
| // We store prefs about LOAD extensions, but don't cache their manifest |
| // since it may change on disk. |
| if (!Manifest::IsUnpackedLocation(extension->location())) { |
| extension_dict->Set(kPrefManifest, |
| extension->manifest()->value()->DeepCopy()); |
| } |
| } |
| |
| void ExtensionPrefs::InitExtensionControlledPrefs( |
| ExtensionPrefValueMap* value_map) { |
| ExtensionIdList extension_ids; |
| GetExtensions(&extension_ids); |
| |
| for (ExtensionIdList::iterator extension_id = extension_ids.begin(); |
| extension_id != extension_ids.end(); |
| ++extension_id) { |
| base::Time install_time = GetInstallTime(*extension_id); |
| bool is_enabled = !IsExtensionDisabled(*extension_id); |
| bool is_incognito_enabled = IsIncognitoEnabled(*extension_id); |
| value_map->RegisterExtension( |
| *extension_id, install_time, is_enabled, is_incognito_enabled); |
| |
| FOR_EACH_OBSERVER( |
| ExtensionPrefsObserver, |
| observer_list_, |
| OnExtensionRegistered(*extension_id, install_time, is_enabled)); |
| |
| // Set regular extension controlled prefs. |
| LoadExtensionControlledPrefs( |
| this, value_map, *extension_id, kExtensionPrefsScopeRegular); |
| // Set incognito extension controlled prefs. |
| LoadExtensionControlledPrefs(this, |
| value_map, |
| *extension_id, |
| kExtensionPrefsScopeIncognitoPersistent); |
| // Set regular-only extension controlled prefs. |
| LoadExtensionControlledPrefs( |
| this, value_map, *extension_id, kExtensionPrefsScopeRegularOnly); |
| |
| FOR_EACH_OBSERVER(ExtensionPrefsObserver, |
| observer_list_, |
| OnExtensionPrefsLoaded(*extension_id, this)); |
| } |
| } |
| |
| void ExtensionPrefs::FinishExtensionInfoPrefs( |
| const std::string& extension_id, |
| const base::Time install_time, |
| bool needs_sort_ordinal, |
| const syncer::StringOrdinal& suggested_page_ordinal, |
| base::DictionaryValue* extension_dict) { |
| // Reinitializes various preferences with empty dictionaries. |
| if (!extension_dict->HasKey(pref_names::kPrefPreferences)) { |
| extension_dict->Set(pref_names::kPrefPreferences, |
| new base::DictionaryValue); |
| } |
| |
| if (!extension_dict->HasKey(pref_names::kPrefIncognitoPreferences)) { |
| extension_dict->Set(pref_names::kPrefIncognitoPreferences, |
| new base::DictionaryValue); |
| } |
| |
| if (!extension_dict->HasKey(pref_names::kPrefRegularOnlyPreferences)) { |
| extension_dict->Set(pref_names::kPrefRegularOnlyPreferences, |
| new base::DictionaryValue); |
| } |
| |
| if (!extension_dict->HasKey(pref_names::kPrefContentSettings)) |
| extension_dict->Set(pref_names::kPrefContentSettings, new base::ListValue); |
| |
| if (!extension_dict->HasKey(pref_names::kPrefIncognitoContentSettings)) { |
| extension_dict->Set(pref_names::kPrefIncognitoContentSettings, |
| new base::ListValue); |
| } |
| |
| // If this point has been reached, any pending installs should be considered |
| // out of date. |
| extension_dict->Remove(kDelayedInstallInfo, NULL); |
| |
| // Clear state that may be registered from a previous install. |
| extension_dict->Remove(EventRouter::kRegisteredEvents, NULL); |
| |
| // When evicted ephemeral apps are re-installed, this flag must be reset. |
| extension_dict->Remove(kPrefEvictedEphemeralApp, NULL); |
| |
| // FYI, all code below here races on sudden shutdown because |extension_dict|, |
| // |app_sorting_|, |extension_pref_value_map_|, and (potentially) observers |
| // are updated non-transactionally. This is probably not fixable without |
| // nested transactional updates to pref dictionaries. |
| if (needs_sort_ordinal) |
| app_sorting_->EnsureValidOrdinals(extension_id, suggested_page_ordinal); |
| |
| bool is_enabled = false; |
| int initial_state; |
| if (extension_dict->GetInteger(kPrefState, &initial_state)) { |
| is_enabled = initial_state == Extension::ENABLED; |
| } |
| bool is_incognito_enabled = IsIncognitoEnabled(extension_id); |
| |
| extension_pref_value_map_->RegisterExtension( |
| extension_id, install_time, is_enabled, is_incognito_enabled); |
| |
| FOR_EACH_OBSERVER( |
| ExtensionPrefsObserver, |
| observer_list_, |
| OnExtensionRegistered(extension_id, install_time, is_enabled)); |
| } |
| |
| } // namespace extensions |