Extract code handling PrinterProviderAPI from PrintPreviewHandler
[chromium-blink-merge.git] / chrome / browser / extensions / extension_util.cc
blob8cf30d46feae30ee57ece1d0a80ac6b349edfc30
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/behavior_feature.h"
28 #include "extensions/common/features/feature_provider.h"
29 #include "extensions/common/manifest.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 {
36 namespace util {
38 namespace {
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)
54 .is_available();
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)
65 return extension_id;
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();
72 CHECK(service);
73 service->ReloadExtension(id);
74 return 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,
82 bool allowed,
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(
88 extension_id,
89 kExtensionAllowedOnAllUrlsPrefName,
90 new base::FundamentalValue(allowed));
92 if (update_permissions) {
93 const Extension* extension =
94 ExtensionRegistry::Get(context)->enabled_extensions().GetByID(
95 extension_id);
96 if (extension) {
97 PermissionsUpdater updater(context);
98 if (allowed)
99 updater.GrantWithheldImpliedAllHosts(extension);
100 else
101 updater.WithholdImpliedAllHosts(extension);
106 } // namespace
108 bool IsIncognitoEnabled(const std::string& extension_id,
109 content::BrowserContext* context) {
110 const Extension* extension = ExtensionRegistry::Get(context)->
111 GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
112 if (extension) {
113 if (!extension->can_be_incognito_enabled())
114 return false;
115 // If this is an existing component extension we always allow it to
116 // work in incognito mode.
117 if (extension->location() == Manifest::COMPONENT)
118 return true;
119 if (IsWhitelistedForIncognito(extension))
120 return true;
122 return ExtensionPrefs::Get(context)->IsIncognitoEnabled(extension_id);
125 void SetIsIncognitoEnabled(const std::string& extension_id,
126 content::BrowserContext* context,
127 bool enabled) {
128 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
129 const Extension* extension =
130 registry->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
132 if (extension) {
133 if (!extension->can_be_incognito_enabled())
134 return;
136 if (extension->location() == Manifest::COMPONENT) {
137 // This shouldn't be called for component extensions unless it is called
138 // by sync, for syncable component extensions.
139 // See http://crbug.com/112290 and associated CLs for the sordid history.
140 DCHECK(sync_helper::IsSyncable(extension));
142 // If we are here, make sure the we aren't trying to change the value.
143 DCHECK_EQ(enabled, IsIncognitoEnabled(extension_id, context));
144 return;
148 ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(context);
149 // Broadcast unloaded and loaded events to update browser state. Only bother
150 // if the value changed and the extension is actually enabled, since there is
151 // no UI otherwise.
152 bool old_enabled = extension_prefs->IsIncognitoEnabled(extension_id);
153 if (enabled == old_enabled)
154 return;
156 extension_prefs->SetIsIncognitoEnabled(extension_id, enabled);
158 std::string id = ReloadExtensionIfEnabled(extension_id, context);
160 // Reloading the extension invalidates the |extension| pointer.
161 extension = registry->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
162 if (extension) {
163 Profile* profile = Profile::FromBrowserContext(context);
164 ExtensionSyncService::Get(profile)->SyncExtensionChangeIfNeeded(*extension);
168 bool CanCrossIncognito(const Extension* extension,
169 content::BrowserContext* context) {
170 // We allow the extension to see events and data from another profile iff it
171 // uses "spanning" behavior and it has incognito access. "split" mode
172 // extensions only see events for a matching profile.
173 CHECK(extension);
174 return IsIncognitoEnabled(extension->id(), context) &&
175 !IncognitoInfo::IsSplitMode(extension);
178 bool CanLoadInIncognito(const Extension* extension,
179 content::BrowserContext* context) {
180 CHECK(extension);
181 if (extension->is_hosted_app())
182 return true;
183 // Packaged apps and regular extensions need to be enabled specifically for
184 // incognito (and split mode should be set).
185 return IncognitoInfo::IsSplitMode(extension) &&
186 IsIncognitoEnabled(extension->id(), context);
189 bool AllowFileAccess(const std::string& extension_id,
190 content::BrowserContext* context) {
191 return base::CommandLine::ForCurrentProcess()->HasSwitch(
192 switches::kDisableExtensionsFileAccessCheck) ||
193 ExtensionPrefs::Get(context)->AllowFileAccess(extension_id);
196 void SetAllowFileAccess(const std::string& extension_id,
197 content::BrowserContext* context,
198 bool allow) {
199 // Reload to update browser state. Only bother if the value changed and the
200 // extension is actually enabled, since there is no UI otherwise.
201 if (allow == AllowFileAccess(extension_id, context))
202 return;
204 ExtensionPrefs::Get(context)->SetAllowFileAccess(extension_id, allow);
206 ReloadExtensionIfEnabled(extension_id, context);
209 bool AllowedScriptingOnAllUrls(const std::string& extension_id,
210 content::BrowserContext* context) {
211 bool allowed = false;
212 ExtensionPrefs* prefs = ExtensionPrefs::Get(context);
213 if (!prefs->ReadPrefAsBoolean(extension_id,
214 kExtensionAllowedOnAllUrlsPrefName,
215 &allowed)) {
216 // If there is no value present, we make one, defaulting it to the value of
217 // the 'scripts require action' flag. If the flag is on, then the extension
218 // does not have permission to script on all urls by default.
219 allowed = DefaultAllowedScriptingOnAllUrls();
220 SetAllowedScriptingOnAllUrlsHelper(context, extension_id, allowed, false);
222 return allowed;
225 void SetAllowedScriptingOnAllUrls(const std::string& extension_id,
226 content::BrowserContext* context,
227 bool allowed) {
228 if (allowed != AllowedScriptingOnAllUrls(extension_id, context)) {
229 SetAllowedScriptingOnAllUrlsHelper(context, extension_id, allowed, true);
230 ExtensionPrefs::Get(context)->UpdateExtensionPref(
231 extension_id,
232 kHasSetScriptOnAllUrlsPrefName,
233 new base::FundamentalValue(true));
237 bool HasSetAllowedScriptingOnAllUrls(const std::string& extension_id,
238 content::BrowserContext* context) {
239 bool did_set = false;
240 return ExtensionPrefs::Get(context)->ReadPrefAsBoolean(
241 extension_id,
242 kHasSetScriptOnAllUrlsPrefName,
243 &did_set) && did_set;
246 bool DefaultAllowedScriptingOnAllUrls() {
247 return !FeatureSwitch::scripts_require_action()->IsEnabled();
250 bool ScriptsMayRequireActionForExtension(
251 const Extension* extension,
252 const PermissionSet* permissions) {
253 // An extension may require user action to execute scripts iff the extension
254 // shows up in chrome:extensions (so the user can grant withheld permissions),
255 // is not part of chrome or corporate policy, not on the scripting whitelist,
256 // and requires enough permissions that we should withhold them.
257 return extension->ShouldDisplayInExtensionSettings() &&
258 !Manifest::IsPolicyLocation(extension->location()) &&
259 !Manifest::IsComponentLocation(extension->location()) &&
260 !PermissionsData::CanExecuteScriptEverywhere(extension) &&
261 permissions->ShouldWarnAllHosts();
264 bool IsAppLaunchable(const std::string& extension_id,
265 content::BrowserContext* context) {
266 int reason = ExtensionPrefs::Get(context)->GetDisableReasons(extension_id);
267 return !((reason & Extension::DISABLE_UNSUPPORTED_REQUIREMENT) ||
268 (reason & Extension::DISABLE_CORRUPTED));
271 bool IsAppLaunchableWithoutEnabling(const std::string& extension_id,
272 content::BrowserContext* context) {
273 return ExtensionRegistry::Get(context)->GetExtensionById(
274 extension_id, ExtensionRegistry::ENABLED) != NULL;
277 bool ShouldSyncExtension(const Extension* extension,
278 content::BrowserContext* context) {
279 return sync_helper::IsSyncableExtension(extension) &&
280 !ExtensionPrefs::Get(context)->DoNotSync(extension->id());
283 bool ShouldSyncApp(const Extension* app, content::BrowserContext* context) {
284 return sync_helper::IsSyncableApp(app) &&
285 !util::IsEphemeralApp(app->id(), context) &&
286 !ExtensionPrefs::Get(context)->DoNotSync(app->id());
289 bool IsExtensionIdle(const std::string& extension_id,
290 content::BrowserContext* context) {
291 std::vector<std::string> ids_to_check;
292 ids_to_check.push_back(extension_id);
294 const Extension* extension =
295 ExtensionRegistry::Get(context)
296 ->GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
297 if (extension && extension->is_shared_module()) {
298 // We have to check all the extensions that use this shared module for idle
299 // to tell whether it is really 'idle'.
300 SharedModuleService* service = ExtensionSystem::Get(context)
301 ->extension_service()
302 ->shared_module_service();
303 scoped_ptr<ExtensionSet> dependents =
304 service->GetDependentExtensions(extension);
305 for (ExtensionSet::const_iterator i = dependents->begin();
306 i != dependents->end();
307 i++) {
308 ids_to_check.push_back((*i)->id());
312 ProcessManager* process_manager = ProcessManager::Get(context);
313 for (std::vector<std::string>::const_iterator i = ids_to_check.begin();
314 i != ids_to_check.end();
315 i++) {
316 const std::string id = (*i);
317 ExtensionHost* host = process_manager->GetBackgroundHostForExtension(id);
318 if (host)
319 return false;
321 scoped_refptr<content::SiteInstance> site_instance =
322 process_manager->GetSiteInstanceForURL(
323 Extension::GetBaseURLFromExtensionId(id));
324 if (site_instance && site_instance->HasProcess())
325 return false;
327 if (!process_manager->GetRenderViewHostsForExtension(id).empty())
328 return false;
330 return true;
333 GURL GetSiteForExtensionId(const std::string& extension_id,
334 content::BrowserContext* context) {
335 return content::SiteInstance::GetSiteForURL(
336 context, Extension::GetBaseURLFromExtensionId(extension_id));
339 scoped_ptr<base::DictionaryValue> GetExtensionInfo(const Extension* extension) {
340 DCHECK(extension);
341 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
343 dict->SetString("id", extension->id());
344 dict->SetString("name", extension->name());
346 GURL icon = extensions::ExtensionIconSource::GetIconURL(
347 extension,
348 extension_misc::EXTENSION_ICON_SMALLISH,
349 ExtensionIconSet::MATCH_BIGGER,
350 false, // Not grayscale.
351 NULL); // Don't set bool if exists.
352 dict->SetString("icon", icon.spec());
354 return dict.Pass();
357 bool HasIsolatedStorage(const ExtensionInfo& info) {
358 if (!info.extension_manifest.get())
359 return false;
361 std::string error;
362 scoped_refptr<const Extension> extension(Extension::Create(
363 info.extension_path,
364 info.extension_location,
365 *info.extension_manifest,
366 Extension::NO_FLAGS,
367 info.extension_id,
368 &error));
369 if (!extension.get())
370 return false;
372 return AppIsolationInfo::HasIsolatedStorage(extension.get());
375 bool SiteHasIsolatedStorage(const GURL& extension_site_url,
376 content::BrowserContext* context) {
377 const Extension* extension = ExtensionRegistry::Get(context)->
378 enabled_extensions().GetExtensionOrAppByURL(extension_site_url);
379 if (!extension)
380 return false;
382 return AppIsolationInfo::HasIsolatedStorage(extension);
385 const gfx::ImageSkia& GetDefaultAppIcon() {
386 return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
387 IDR_APP_DEFAULT_ICON);
390 const gfx::ImageSkia& GetDefaultExtensionIcon() {
391 return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
392 IDR_EXTENSION_DEFAULT_ICON);
395 bool IsNewBookmarkAppsEnabled() {
396 return !base::CommandLine::ForCurrentProcess()->HasSwitch(
397 switches::kDisableNewBookmarkApps);
400 } // namespace util
401 } // namespace extensions