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/sync_helper.h"
18 #include "content/public/browser/site_instance.h"
19 #include "extensions/browser/extension_prefs.h"
20 #include "extensions/browser/extension_registry.h"
21 #include "extensions/browser/extension_system.h"
22 #include "extensions/browser/extension_util.h"
23 #include "extensions/common/extension.h"
24 #include "extensions/common/extension_icon_set.h"
25 #include "extensions/common/feature_switch.h"
26 #include "extensions/common/features/behavior_feature.h"
27 #include "extensions/common/features/feature_provider.h"
28 #include "extensions/common/manifest.h"
29 #include "extensions/common/manifest_handlers/app_isolation_info.h"
30 #include "extensions/common/manifest_handlers/incognito_info.h"
31 #include "extensions/common/permissions/permissions_data.h"
32 #include "extensions/grit/extensions_browser_resources.h"
33 #include "ui/base/resource/resource_bundle.h"
35 namespace extensions
{
40 // The entry into the ExtensionPrefs for allowing an extension to script on
41 // all urls without explicit permission.
42 const char kExtensionAllowedOnAllUrlsPrefName
[] =
43 "extension_can_script_all_urls";
45 // The entry into the prefs for when a user has explicitly set the "extension
46 // allowed on all urls" pref.
47 const char kHasSetScriptOnAllUrlsPrefName
[] = "has_set_script_all_urls";
49 // Returns true if |extension| should always be enabled in incognito mode.
50 bool IsWhitelistedForIncognito(const Extension
* extension
) {
51 return FeatureProvider::GetBehaviorFeature(
52 BehaviorFeature::kWhitelistedForIncognito
)
53 ->IsAvailableToExtension(extension
)
57 // Returns |extension_id|. See note below.
58 std::string
ReloadExtensionIfEnabled(const std::string
& extension_id
,
59 content::BrowserContext
* context
) {
60 ExtensionRegistry
* registry
= ExtensionRegistry::Get(context
);
61 bool extension_is_enabled
=
62 registry
->enabled_extensions().Contains(extension_id
);
64 if (!extension_is_enabled
)
67 // When we reload the extension the ID may be invalidated if we've passed it
68 // by const ref everywhere. Make a copy to be safe. http://crbug.com/103762
69 std::string id
= extension_id
;
70 ExtensionService
* service
=
71 ExtensionSystem::Get(context
)->extension_service();
73 service
->ReloadExtension(id
);
77 // Sets the preference for scripting on all urls to |allowed|, optionally
78 // updating the extension's active permissions (based on |update_permissions|).
79 void SetAllowedScriptingOnAllUrlsHelper(
80 content::BrowserContext
* context
,
81 const std::string
& extension_id
,
83 bool update_permissions
) {
84 // TODO(devlin): Right now, we always need to have a value for this pref.
85 // Once the scripts-require-action feature launches, we can change the set
86 // to be null if false.
87 ExtensionPrefs::Get(context
)->UpdateExtensionPref(
89 kExtensionAllowedOnAllUrlsPrefName
,
90 new base::FundamentalValue(allowed
));
92 if (update_permissions
) {
93 const Extension
* extension
=
94 ExtensionRegistry::Get(context
)->enabled_extensions().GetByID(
97 PermissionsUpdater
updater(context
);
99 updater
.GrantWithheldImpliedAllHosts(extension
);
101 updater
.WithholdImpliedAllHosts(extension
);
103 // If this was an update to permissions, we also need to sync the change.
104 ExtensionSyncService
* sync_service
= ExtensionSyncService::Get(context
);
105 if (sync_service
) // sync_service can be null in unittests.
106 sync_service
->SyncExtensionChangeIfNeeded(*extension
);
113 bool IsIncognitoEnabled(const std::string
& extension_id
,
114 content::BrowserContext
* context
) {
115 const Extension
* extension
= ExtensionRegistry::Get(context
)->
116 GetExtensionById(extension_id
, ExtensionRegistry::ENABLED
);
118 if (!extension
->can_be_incognito_enabled())
120 // If this is an existing component extension we always allow it to
121 // work in incognito mode.
122 if (extension
->location() == Manifest::COMPONENT
)
124 if (IsWhitelistedForIncognito(extension
))
127 return ExtensionPrefs::Get(context
)->IsIncognitoEnabled(extension_id
);
130 void SetIsIncognitoEnabled(const std::string
& extension_id
,
131 content::BrowserContext
* context
,
133 ExtensionRegistry
* registry
= ExtensionRegistry::Get(context
);
134 const Extension
* extension
=
135 registry
->GetExtensionById(extension_id
, ExtensionRegistry::EVERYTHING
);
138 if (!extension
->can_be_incognito_enabled())
141 // TODO(treib,kalman): Should this be Manifest::IsComponentLocation(..)?
142 // (which also checks for EXTERNAL_COMPONENT).
143 if (extension
->location() == Manifest::COMPONENT
) {
144 // This shouldn't be called for component extensions unless it is called
145 // by sync, for syncable component extensions.
146 // See http://crbug.com/112290 and associated CLs for the sordid history.
147 DCHECK(sync_helper::IsSyncableComponentExtension(extension
));
149 // If we are here, make sure the we aren't trying to change the value.
150 DCHECK_EQ(enabled
, IsIncognitoEnabled(extension_id
, context
));
155 ExtensionPrefs
* extension_prefs
= ExtensionPrefs::Get(context
);
156 // Broadcast unloaded and loaded events to update browser state. Only bother
157 // if the value changed and the extension is actually enabled, since there is
159 bool old_enabled
= extension_prefs
->IsIncognitoEnabled(extension_id
);
160 if (enabled
== old_enabled
)
163 extension_prefs
->SetIsIncognitoEnabled(extension_id
, enabled
);
165 std::string id
= ReloadExtensionIfEnabled(extension_id
, context
);
167 // Reloading the extension invalidates the |extension| pointer.
168 extension
= registry
->GetExtensionById(id
, ExtensionRegistry::EVERYTHING
);
170 Profile
* profile
= Profile::FromBrowserContext(context
);
171 ExtensionSyncService::Get(profile
)->SyncExtensionChangeIfNeeded(*extension
);
175 bool CanCrossIncognito(const Extension
* extension
,
176 content::BrowserContext
* context
) {
177 // We allow the extension to see events and data from another profile iff it
178 // uses "spanning" behavior and it has incognito access. "split" mode
179 // extensions only see events for a matching profile.
181 return IsIncognitoEnabled(extension
->id(), context
) &&
182 !IncognitoInfo::IsSplitMode(extension
);
185 bool CanLoadInIncognito(const Extension
* extension
,
186 content::BrowserContext
* context
) {
188 if (extension
->is_hosted_app())
190 // Packaged apps and regular extensions need to be enabled specifically for
191 // incognito (and split mode should be set).
192 return IncognitoInfo::IsSplitMode(extension
) &&
193 IsIncognitoEnabled(extension
->id(), context
);
196 bool AllowFileAccess(const std::string
& extension_id
,
197 content::BrowserContext
* context
) {
198 return base::CommandLine::ForCurrentProcess()->HasSwitch(
199 switches::kDisableExtensionsFileAccessCheck
) ||
200 ExtensionPrefs::Get(context
)->AllowFileAccess(extension_id
);
203 void SetAllowFileAccess(const std::string
& extension_id
,
204 content::BrowserContext
* context
,
206 // Reload to update browser state. Only bother if the value changed and the
207 // extension is actually enabled, since there is no UI otherwise.
208 if (allow
== AllowFileAccess(extension_id
, context
))
211 ExtensionPrefs::Get(context
)->SetAllowFileAccess(extension_id
, allow
);
213 ReloadExtensionIfEnabled(extension_id
, context
);
216 bool AllowedScriptingOnAllUrls(const std::string
& extension_id
,
217 content::BrowserContext
* context
) {
218 bool allowed
= false;
219 ExtensionPrefs
* prefs
= ExtensionPrefs::Get(context
);
220 if (!prefs
->ReadPrefAsBoolean(extension_id
,
221 kExtensionAllowedOnAllUrlsPrefName
,
223 // If there is no value present, we make one, defaulting it to the value of
224 // the 'scripts require action' flag. If the flag is on, then the extension
225 // does not have permission to script on all urls by default.
226 allowed
= DefaultAllowedScriptingOnAllUrls();
227 SetAllowedScriptingOnAllUrlsHelper(context
, extension_id
, allowed
, false);
232 void SetAllowedScriptingOnAllUrls(const std::string
& extension_id
,
233 content::BrowserContext
* context
,
235 if (allowed
!= AllowedScriptingOnAllUrls(extension_id
, context
)) {
236 SetAllowedScriptingOnAllUrlsHelper(context
, extension_id
, allowed
, true);
237 ExtensionPrefs::Get(context
)->UpdateExtensionPref(
239 kHasSetScriptOnAllUrlsPrefName
,
240 new base::FundamentalValue(true));
244 bool HasSetAllowedScriptingOnAllUrls(const std::string
& extension_id
,
245 content::BrowserContext
* context
) {
246 bool did_set
= false;
247 return ExtensionPrefs::Get(context
)->ReadPrefAsBoolean(
249 kHasSetScriptOnAllUrlsPrefName
,
250 &did_set
) && did_set
;
253 bool DefaultAllowedScriptingOnAllUrls() {
254 return !FeatureSwitch::scripts_require_action()->IsEnabled();
257 bool IsAppLaunchable(const std::string
& extension_id
,
258 content::BrowserContext
* context
) {
259 int reason
= ExtensionPrefs::Get(context
)->GetDisableReasons(extension_id
);
260 return !((reason
& Extension::DISABLE_UNSUPPORTED_REQUIREMENT
) ||
261 (reason
& Extension::DISABLE_CORRUPTED
));
264 bool IsAppLaunchableWithoutEnabling(const std::string
& extension_id
,
265 content::BrowserContext
* context
) {
266 return ExtensionRegistry::Get(context
)->GetExtensionById(
267 extension_id
, ExtensionRegistry::ENABLED
) != NULL
;
270 bool ShouldSync(const Extension
* extension
,
271 content::BrowserContext
* context
) {
272 return sync_helper::IsSyncable(extension
) &&
273 !util::IsEphemeralApp(extension
->id(), context
) &&
274 !ExtensionPrefs::Get(context
)->DoNotSync(extension
->id());
277 bool IsExtensionIdle(const std::string
& extension_id
,
278 content::BrowserContext
* context
) {
279 std::vector
<std::string
> ids_to_check
;
280 ids_to_check
.push_back(extension_id
);
282 const Extension
* extension
=
283 ExtensionRegistry::Get(context
)
284 ->GetExtensionById(extension_id
, ExtensionRegistry::ENABLED
);
285 if (extension
&& extension
->is_shared_module()) {
286 // We have to check all the extensions that use this shared module for idle
287 // to tell whether it is really 'idle'.
288 SharedModuleService
* service
= ExtensionSystem::Get(context
)
289 ->extension_service()
290 ->shared_module_service();
291 scoped_ptr
<ExtensionSet
> dependents
=
292 service
->GetDependentExtensions(extension
);
293 for (ExtensionSet::const_iterator i
= dependents
->begin();
294 i
!= dependents
->end();
296 ids_to_check
.push_back((*i
)->id());
300 ProcessManager
* process_manager
= ProcessManager::Get(context
);
301 for (std::vector
<std::string
>::const_iterator i
= ids_to_check
.begin();
302 i
!= ids_to_check
.end();
304 const std::string id
= (*i
);
305 ExtensionHost
* host
= process_manager
->GetBackgroundHostForExtension(id
);
309 scoped_refptr
<content::SiteInstance
> site_instance
=
310 process_manager
->GetSiteInstanceForURL(
311 Extension::GetBaseURLFromExtensionId(id
));
312 if (site_instance
&& site_instance
->HasProcess())
315 if (!process_manager
->GetRenderFrameHostsForExtension(id
).empty())
321 GURL
GetSiteForExtensionId(const std::string
& extension_id
,
322 content::BrowserContext
* context
) {
323 return content::SiteInstance::GetSiteForURL(
324 context
, Extension::GetBaseURLFromExtensionId(extension_id
));
327 scoped_ptr
<base::DictionaryValue
> GetExtensionInfo(const Extension
* extension
) {
329 scoped_ptr
<base::DictionaryValue
> dict(new base::DictionaryValue
);
331 dict
->SetString("id", extension
->id());
332 dict
->SetString("name", extension
->name());
334 GURL icon
= extensions::ExtensionIconSource::GetIconURL(
336 extension_misc::EXTENSION_ICON_SMALLISH
,
337 ExtensionIconSet::MATCH_BIGGER
,
338 false, // Not grayscale.
339 NULL
); // Don't set bool if exists.
340 dict
->SetString("icon", icon
.spec());
345 bool HasIsolatedStorage(const ExtensionInfo
& info
) {
346 if (!info
.extension_manifest
.get())
350 scoped_refptr
<const Extension
> extension(Extension::Create(
352 info
.extension_location
,
353 *info
.extension_manifest
,
357 if (!extension
.get())
360 return AppIsolationInfo::HasIsolatedStorage(extension
.get());
363 bool SiteHasIsolatedStorage(const GURL
& extension_site_url
,
364 content::BrowserContext
* context
) {
365 const Extension
* extension
= ExtensionRegistry::Get(context
)->
366 enabled_extensions().GetExtensionOrAppByURL(extension_site_url
);
370 return AppIsolationInfo::HasIsolatedStorage(extension
);
373 const gfx::ImageSkia
& GetDefaultAppIcon() {
374 return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
375 IDR_APP_DEFAULT_ICON
);
378 const gfx::ImageSkia
& GetDefaultExtensionIcon() {
379 return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
380 IDR_EXTENSION_DEFAULT_ICON
);
383 bool IsNewBookmarkAppsEnabled() {
384 #if defined(OS_MACOSX)
385 return base::CommandLine::ForCurrentProcess()->HasSwitch(
386 switches::kEnableNewBookmarkApps
);
388 return !base::CommandLine::ForCurrentProcess()->HasSwitch(
389 switches::kDisableNewBookmarkApps
);
393 bool IsExtensionSupervised(const Extension
* extension
, Profile
* profile
) {
394 return extension
->was_installed_by_custodian() && profile
->IsSupervised();
398 } // namespace extensions