1 // Copyright 2013 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.
5 #include "chrome/browser/extensions/extension_util.h"
7 #include "base/command_line.h"
8 #include "base/logging.h"
9 #include "base/values.h"
10 #include "chrome/browser/extensions/extension_service.h"
11 #include "chrome/browser/extensions/extension_sync_service.h"
12 #include "chrome/browser/extensions/permissions_updater.h"
13 #include "chrome/browser/extensions/shared_module_service.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
16 #include "chrome/common/chrome_switches.h"
17 #include "chrome/common/extensions/manifest_handlers/app_isolation_info.h"
18 #include "chrome/common/extensions/sync_helper.h"
19 #include "content/public/browser/site_instance.h"
20 #include "extensions/browser/extension_prefs.h"
21 #include "extensions/browser/extension_registry.h"
22 #include "extensions/browser/extension_system.h"
23 #include "extensions/browser/extension_util.h"
24 #include "extensions/common/extension.h"
25 #include "extensions/common/extension_icon_set.h"
26 #include "extensions/common/feature_switch.h"
27 #include "extensions/common/features/simple_feature.h"
28 #include "extensions/common/manifest.h"
29 #include "extensions/common/manifest_handlers/incognito_info.h"
30 #include "extensions/common/permissions/permissions_data.h"
31 #include "extensions/grit/extensions_browser_resources.h"
32 #include "ui/base/resource/resource_bundle.h"
34 namespace extensions
{
39 // The entry into the ExtensionPrefs for allowing an extension to script on
40 // all urls without explicit permission.
41 const char kExtensionAllowedOnAllUrlsPrefName
[] =
42 "extension_can_script_all_urls";
44 // Returns true if |extension_id| for an external component extension should
45 // always be enabled in incognito windows.
46 bool IsWhitelistedForIncognito(const std::string
& extension_id
) {
47 static const char* const kExtensionWhitelist
[] = {
48 "D5736E4B5CF695CB93A2FB57E4FDC6E5AFAB6FE2", // http://crbug.com/312900
49 "D57DE394F36DC1C3220E7604C575D29C51A6C495", // http://crbug.com/319444
50 "3F65507A3B39259B38C8173C6FFA3D12DF64CCE9" // http://crbug.com/371562
53 return extensions::SimpleFeature::IsIdInList(
55 std::set
<std::string
>(
57 kExtensionWhitelist
+ arraysize(kExtensionWhitelist
)));
60 // Returns |extension_id|. See note below.
61 std::string
ReloadExtensionIfEnabled(const std::string
& extension_id
,
62 content::BrowserContext
* context
) {
63 ExtensionRegistry
* registry
= ExtensionRegistry::Get(context
);
64 bool extension_is_enabled
=
65 registry
->enabled_extensions().Contains(extension_id
);
67 if (!extension_is_enabled
)
70 // When we reload the extension the ID may be invalidated if we've passed it
71 // by const ref everywhere. Make a copy to be safe. http://crbug.com/103762
72 std::string id
= extension_id
;
73 ExtensionService
* service
=
74 ExtensionSystem::Get(context
)->extension_service();
76 service
->ReloadExtension(id
);
82 bool IsIncognitoEnabled(const std::string
& extension_id
,
83 content::BrowserContext
* context
) {
84 const Extension
* extension
= ExtensionRegistry::Get(context
)->
85 GetExtensionById(extension_id
, ExtensionRegistry::ENABLED
);
87 if (!extension
->can_be_incognito_enabled())
89 // If this is an existing component extension we always allow it to
90 // work in incognito mode.
91 if (extension
->location() == Manifest::COMPONENT
)
93 if (extension
->location() == Manifest::EXTERNAL_COMPONENT
&&
94 IsWhitelistedForIncognito(extension_id
)) {
99 return ExtensionPrefs::Get(context
)->IsIncognitoEnabled(extension_id
);
102 void SetIsIncognitoEnabled(const std::string
& extension_id
,
103 content::BrowserContext
* context
,
105 ExtensionRegistry
* registry
= ExtensionRegistry::Get(context
);
106 const Extension
* extension
=
107 registry
->GetExtensionById(extension_id
, ExtensionRegistry::EVERYTHING
);
110 if (!extension
->can_be_incognito_enabled())
113 if (extension
->location() == Manifest::COMPONENT
) {
114 // This shouldn't be called for component extensions unless it is called
115 // by sync, for syncable component extensions.
116 // See http://crbug.com/112290 and associated CLs for the sordid history.
117 DCHECK(sync_helper::IsSyncable(extension
));
119 // If we are here, make sure the we aren't trying to change the value.
120 DCHECK_EQ(enabled
, IsIncognitoEnabled(extension_id
, context
));
125 ExtensionPrefs
* extension_prefs
= ExtensionPrefs::Get(context
);
126 // Broadcast unloaded and loaded events to update browser state. Only bother
127 // if the value changed and the extension is actually enabled, since there is
129 bool old_enabled
= extension_prefs
->IsIncognitoEnabled(extension_id
);
130 if (enabled
== old_enabled
)
133 extension_prefs
->SetIsIncognitoEnabled(extension_id
, enabled
);
135 std::string id
= ReloadExtensionIfEnabled(extension_id
, context
);
137 // Reloading the extension invalidates the |extension| pointer.
138 extension
= registry
->GetExtensionById(id
, ExtensionRegistry::EVERYTHING
);
140 Profile
* profile
= Profile::FromBrowserContext(context
);
141 ExtensionSyncService::Get(profile
)->SyncExtensionChangeIfNeeded(*extension
);
145 bool CanCrossIncognito(const Extension
* extension
,
146 content::BrowserContext
* context
) {
147 // We allow the extension to see events and data from another profile iff it
148 // uses "spanning" behavior and it has incognito access. "split" mode
149 // extensions only see events for a matching profile.
151 return IsIncognitoEnabled(extension
->id(), context
) &&
152 !IncognitoInfo::IsSplitMode(extension
);
155 bool CanLoadInIncognito(const Extension
* extension
,
156 content::BrowserContext
* context
) {
158 if (extension
->is_hosted_app())
160 // Packaged apps and regular extensions need to be enabled specifically for
161 // incognito (and split mode should be set).
162 return IncognitoInfo::IsSplitMode(extension
) &&
163 IsIncognitoEnabled(extension
->id(), context
);
166 bool AllowFileAccess(const std::string
& extension_id
,
167 content::BrowserContext
* context
) {
168 return CommandLine::ForCurrentProcess()->HasSwitch(
169 switches::kDisableExtensionsFileAccessCheck
) ||
170 ExtensionPrefs::Get(context
)->AllowFileAccess(extension_id
);
173 void SetAllowFileAccess(const std::string
& extension_id
,
174 content::BrowserContext
* context
,
176 // Reload to update browser state. Only bother if the value changed and the
177 // extension is actually enabled, since there is no UI otherwise.
178 if (allow
== AllowFileAccess(extension_id
, context
))
181 ExtensionPrefs::Get(context
)->SetAllowFileAccess(extension_id
, allow
);
183 ReloadExtensionIfEnabled(extension_id
, context
);
186 bool AllowedScriptingOnAllUrls(const std::string
& extension_id
,
187 content::BrowserContext
* context
) {
188 bool allowed
= false;
189 return ExtensionPrefs::Get(context
)->ReadPrefAsBoolean(
191 kExtensionAllowedOnAllUrlsPrefName
,
196 void SetAllowedScriptingOnAllUrls(const std::string
& extension_id
,
197 content::BrowserContext
* context
,
199 if (allowed
== AllowedScriptingOnAllUrls(extension_id
, context
))
200 return; // Nothing to do here.
202 ExtensionPrefs::Get(context
)->UpdateExtensionPref(
204 kExtensionAllowedOnAllUrlsPrefName
,
205 allowed
? new base::FundamentalValue(true) : NULL
);
207 const Extension
* extension
=
208 ExtensionRegistry::Get(context
)->enabled_extensions().GetByID(
211 PermissionsUpdater
updater(context
);
213 updater
.GrantWithheldImpliedAllHosts(extension
);
215 updater
.WithholdImpliedAllHosts(extension
);
219 bool ScriptsMayRequireActionForExtension(const Extension
* extension
) {
220 // An extension requires user action to execute scripts iff the switch to do
221 // so is enabled, the extension shows up in chrome:extensions (so the user can
222 // grant withheld permissions), the extension is not part of chrome or
223 // corporate policy, and also not on the scripting whitelist.
224 return FeatureSwitch::scripts_require_action()->IsEnabled() &&
225 extension
->ShouldDisplayInExtensionSettings() &&
226 !Manifest::IsPolicyLocation(extension
->location()) &&
227 !Manifest::IsComponentLocation(extension
->location()) &&
228 !PermissionsData::CanExecuteScriptEverywhere(extension
);
231 bool IsAppLaunchable(const std::string
& extension_id
,
232 content::BrowserContext
* context
) {
233 int reason
= ExtensionPrefs::Get(context
)->GetDisableReasons(extension_id
);
234 return !((reason
& Extension::DISABLE_UNSUPPORTED_REQUIREMENT
) ||
235 (reason
& Extension::DISABLE_CORRUPTED
));
238 bool IsAppLaunchableWithoutEnabling(const std::string
& extension_id
,
239 content::BrowserContext
* context
) {
240 return ExtensionRegistry::Get(context
)->GetExtensionById(
241 extension_id
, ExtensionRegistry::ENABLED
) != NULL
;
244 bool ShouldSyncExtension(const Extension
* extension
,
245 content::BrowserContext
* context
) {
246 return sync_helper::IsSyncableExtension(extension
) &&
247 !ExtensionPrefs::Get(context
)->DoNotSync(extension
->id());
250 bool ShouldSyncApp(const Extension
* app
, content::BrowserContext
* context
) {
251 return sync_helper::IsSyncableApp(app
) &&
252 !util::IsEphemeralApp(app
->id(), context
) &&
253 !ExtensionPrefs::Get(context
)->DoNotSync(app
->id());
256 bool IsExtensionIdle(const std::string
& extension_id
,
257 content::BrowserContext
* context
) {
258 std::vector
<std::string
> ids_to_check
;
259 ids_to_check
.push_back(extension_id
);
261 const Extension
* extension
=
262 ExtensionRegistry::Get(context
)
263 ->GetExtensionById(extension_id
, ExtensionRegistry::ENABLED
);
264 if (extension
&& extension
->is_shared_module()) {
265 // We have to check all the extensions that use this shared module for idle
266 // to tell whether it is really 'idle'.
267 SharedModuleService
* service
= ExtensionSystem::Get(context
)
268 ->extension_service()
269 ->shared_module_service();
270 scoped_ptr
<ExtensionSet
> dependents
=
271 service
->GetDependentExtensions(extension
);
272 for (ExtensionSet::const_iterator i
= dependents
->begin();
273 i
!= dependents
->end();
275 ids_to_check
.push_back((*i
)->id());
279 ProcessManager
* process_manager
= ProcessManager::Get(context
);
280 for (std::vector
<std::string
>::const_iterator i
= ids_to_check
.begin();
281 i
!= ids_to_check
.end();
283 const std::string id
= (*i
);
284 ExtensionHost
* host
= process_manager
->GetBackgroundHostForExtension(id
);
288 content::SiteInstance
* site_instance
=
289 process_manager
->GetSiteInstanceForURL(
290 Extension::GetBaseURLFromExtensionId(id
));
291 if (site_instance
&& site_instance
->HasProcess())
294 if (!process_manager
->GetRenderViewHostsForExtension(id
).empty())
300 GURL
GetSiteForExtensionId(const std::string
& extension_id
,
301 content::BrowserContext
* context
) {
302 return content::SiteInstance::GetSiteForURL(
303 context
, Extension::GetBaseURLFromExtensionId(extension_id
));
306 scoped_ptr
<base::DictionaryValue
> GetExtensionInfo(const Extension
* extension
) {
308 scoped_ptr
<base::DictionaryValue
> dict(new base::DictionaryValue
);
310 dict
->SetString("id", extension
->id());
311 dict
->SetString("name", extension
->name());
313 GURL icon
= extensions::ExtensionIconSource::GetIconURL(
315 extension_misc::EXTENSION_ICON_SMALLISH
,
316 ExtensionIconSet::MATCH_BIGGER
,
317 false, // Not grayscale.
318 NULL
); // Don't set bool if exists.
319 dict
->SetString("icon", icon
.spec());
324 bool HasIsolatedStorage(const ExtensionInfo
& info
) {
325 if (!info
.extension_manifest
.get())
329 scoped_refptr
<const Extension
> extension(Extension::Create(
331 info
.extension_location
,
332 *info
.extension_manifest
,
336 if (!extension
.get())
339 return AppIsolationInfo::HasIsolatedStorage(extension
.get());
342 bool SiteHasIsolatedStorage(const GURL
& extension_site_url
,
343 content::BrowserContext
* context
) {
344 const Extension
* extension
= ExtensionRegistry::Get(context
)->
345 enabled_extensions().GetExtensionOrAppByURL(extension_site_url
);
349 return AppIsolationInfo::HasIsolatedStorage(extension
);
352 const gfx::ImageSkia
& GetDefaultAppIcon() {
353 return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
354 IDR_APP_DEFAULT_ICON
);
357 const gfx::ImageSkia
& GetDefaultExtensionIcon() {
358 return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
359 IDR_EXTENSION_DEFAULT_ICON
);
362 bool IsStreamlinedHostedAppsEnabled() {
363 return !CommandLine::ForCurrentProcess()->HasSwitch(
364 switches::kDisableNewBookmarkApps
);
368 } // namespace extensions