blob: 11fb243b12ca56d7284e21c0702882549521fbaf [file] [log] [blame]
[email protected]a7ff4b72013-10-17 20:56:021// 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.
4
5#include "chrome/browser/extensions/extension_util.h"
6
7#include "base/command_line.h"
[email protected]bb2feea2014-03-18 22:08:138#include "base/logging.h"
9#include "base/values.h"
[email protected]a7ff4b72013-10-17 20:56:0210#include "chrome/browser/extensions/extension_service.h"
[email protected]f8aefb132013-10-30 09:29:5211#include "chrome/browser/extensions/extension_sync_service.h"
[email protected]23a85362014-07-07 23:26:1912#include "chrome/browser/extensions/permissions_updater.h"
elijahtaylor0def4432014-10-06 18:15:1113#include "chrome/browser/extensions/shared_module_service.h"
[email protected]1d5cf4142014-01-24 18:25:2214#include "chrome/browser/profiles/profile.h"
[email protected]bb2feea2014-03-18 22:08:1315#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
[email protected]a7ff4b72013-10-17 20:56:0216#include "chrome/common/chrome_switches.h"
[email protected]ca0336342014-03-21 12:58:3417#include "chrome/common/extensions/manifest_handlers/app_isolation_info.h"
[email protected]a7ff4b72013-10-17 20:56:0218#include "chrome/common/extensions/sync_helper.h"
[email protected]617342a42013-12-18 23:34:0319#include "content/public/browser/site_instance.h"
[email protected]489db0842014-01-22 18:20:0320#include "extensions/browser/extension_prefs.h"
[email protected]599539802014-01-07 23:06:0021#include "extensions/browser/extension_registry.h"
[email protected]59b0e602014-01-30 00:41:2422#include "extensions/browser/extension_system.h"
[email protected]30e190f82014-05-26 16:44:3923#include "extensions/browser/extension_util.h"
[email protected]e4452d32013-11-15 23:07:4124#include "extensions/common/extension.h"
[email protected]4b7908842014-04-07 23:50:2225#include "extensions/common/extension_icon_set.h"
[email protected]4d67e9d2014-08-18 22:03:5426#include "extensions/common/feature_switch.h"
kalman642103282014-12-15 03:59:0927#include "extensions/common/features/behavior_feature.h"
28#include "extensions/common/features/feature_provider.h"
[email protected]a7ff4b72013-10-17 20:56:0229#include "extensions/common/manifest.h"
[email protected]1f7de252013-11-06 22:02:0030#include "extensions/common/manifest_handlers/incognito_info.h"
[email protected]4d67e9d2014-08-18 22:03:5431#include "extensions/common/permissions/permissions_data.h"
mukai4245dfe82014-09-05 17:40:5132#include "extensions/grit/extensions_browser_resources.h"
[email protected]7eb20e32014-04-30 08:50:5633#include "ui/base/resource/resource_bundle.h"
[email protected]a7ff4b72013-10-17 20:56:0234
[email protected]1d5cf4142014-01-24 18:25:2235namespace extensions {
36namespace util {
[email protected]a7ff4b72013-10-17 20:56:0237
[email protected]b33c8c22014-05-29 19:51:0838namespace {
thestig7b4bd932014-09-09 22:44:3139
[email protected]b33c8c22014-05-29 19:51:0840// The entry into the ExtensionPrefs for allowing an extension to script on
41// all urls without explicit permission.
42const char kExtensionAllowedOnAllUrlsPrefName[] =
43 "extension_can_script_all_urls";
[email protected]277c4142014-06-19 20:08:5444
kalman642103282014-12-15 03:59:0945// Returns true if |extension| should always be enabled in incognito mode.
46bool IsWhitelistedForIncognito(const Extension* extension) {
kalman38ec4882014-12-18 09:40:3847 return FeatureProvider::GetBehaviorFeature(
48 BehaviorFeature::kWhitelistedForIncognito)
kalman642103282014-12-15 03:59:0949 ->IsAvailableToExtension(extension)
50 .is_available();
[email protected]b33c8c22014-05-29 19:51:0851}
thestig7b4bd932014-09-09 22:44:3152
53// Returns |extension_id|. See note below.
54std::string ReloadExtensionIfEnabled(const std::string& extension_id,
55 content::BrowserContext* context) {
56 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
57 bool extension_is_enabled =
58 registry->enabled_extensions().Contains(extension_id);
59
60 if (!extension_is_enabled)
61 return extension_id;
62
63 // When we reload the extension the ID may be invalidated if we've passed it
64 // by const ref everywhere. Make a copy to be safe. http://crbug.com/103762
65 std::string id = extension_id;
66 ExtensionService* service =
67 ExtensionSystem::Get(context)->extension_service();
68 CHECK(service);
69 service->ReloadExtension(id);
70 return id;
71}
72
[email protected]277c4142014-06-19 20:08:5473} // namespace
[email protected]b33c8c22014-05-29 19:51:0874
[email protected]a7ff4b72013-10-17 20:56:0275bool IsIncognitoEnabled(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:2276 content::BrowserContext* context) {
77 const Extension* extension = ExtensionRegistry::Get(context)->
78 GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
79 if (extension) {
80 if (!extension->can_be_incognito_enabled())
81 return false;
82 // If this is an existing component extension we always allow it to
83 // work in incognito mode.
84 if (extension->location() == Manifest::COMPONENT)
85 return true;
kalman642103282014-12-15 03:59:0986 if (IsWhitelistedForIncognito(extension))
[email protected]277c4142014-06-19 20:08:5487 return true;
[email protected]1d5cf4142014-01-24 18:25:2288 }
[email protected]1d5cf4142014-01-24 18:25:2289 return ExtensionPrefs::Get(context)->IsIncognitoEnabled(extension_id);
[email protected]a7ff4b72013-10-17 20:56:0290}
91
92void SetIsIncognitoEnabled(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:2293 content::BrowserContext* context,
[email protected]a7ff4b72013-10-17 20:56:0294 bool enabled) {
thestig7b4bd932014-09-09 22:44:3195 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
96 const Extension* extension =
97 registry->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
[email protected]a7ff4b72013-10-17 20:56:0298
[email protected]1d5cf4142014-01-24 18:25:2299 if (extension) {
100 if (!extension->can_be_incognito_enabled())
101 return;
102
103 if (extension->location() == Manifest::COMPONENT) {
104 // This shouldn't be called for component extensions unless it is called
105 // by sync, for syncable component extensions.
106 // See http://crbug.com/112290 and associated CLs for the sordid history.
107 DCHECK(sync_helper::IsSyncable(extension));
108
109 // If we are here, make sure the we aren't trying to change the value.
thestig7b4bd932014-09-09 22:44:31110 DCHECK_EQ(enabled, IsIncognitoEnabled(extension_id, context));
[email protected]1d5cf4142014-01-24 18:25:22111 return;
112 }
[email protected]a7ff4b72013-10-17 20:56:02113 }
114
thestig7b4bd932014-09-09 22:44:31115 ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(context);
[email protected]a7ff4b72013-10-17 20:56:02116 // Broadcast unloaded and loaded events to update browser state. Only bother
117 // if the value changed and the extension is actually enabled, since there is
118 // no UI otherwise.
119 bool old_enabled = extension_prefs->IsIncognitoEnabled(extension_id);
120 if (enabled == old_enabled)
121 return;
122
123 extension_prefs->SetIsIncognitoEnabled(extension_id, enabled);
124
thestig7b4bd932014-09-09 22:44:31125 std::string id = ReloadExtensionIfEnabled(extension_id, context);
[email protected]a7ff4b72013-10-17 20:56:02126
127 // Reloading the extension invalidates the |extension| pointer.
thestig7b4bd932014-09-09 22:44:31128 extension = registry->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
[email protected]f8aefb132013-10-30 09:29:52129 if (extension) {
thestig7b4bd932014-09-09 22:44:31130 Profile* profile = Profile::FromBrowserContext(context);
131 ExtensionSyncService::Get(profile)->SyncExtensionChangeIfNeeded(*extension);
[email protected]f8aefb132013-10-30 09:29:52132 }
[email protected]a7ff4b72013-10-17 20:56:02133}
134
135bool CanCrossIncognito(const Extension* extension,
[email protected]1d5cf4142014-01-24 18:25:22136 content::BrowserContext* context) {
[email protected]a7ff4b72013-10-17 20:56:02137 // We allow the extension to see events and data from another profile iff it
138 // uses "spanning" behavior and it has incognito access. "split" mode
139 // extensions only see events for a matching profile.
140 CHECK(extension);
[email protected]1d5cf4142014-01-24 18:25:22141 return IsIncognitoEnabled(extension->id(), context) &&
142 !IncognitoInfo::IsSplitMode(extension);
[email protected]a7ff4b72013-10-17 20:56:02143}
144
145bool CanLoadInIncognito(const Extension* extension,
[email protected]1d5cf4142014-01-24 18:25:22146 content::BrowserContext* context) {
147 CHECK(extension);
[email protected]a7ff4b72013-10-17 20:56:02148 if (extension->is_hosted_app())
149 return true;
150 // Packaged apps and regular extensions need to be enabled specifically for
151 // incognito (and split mode should be set).
[email protected]1d5cf4142014-01-24 18:25:22152 return IncognitoInfo::IsSplitMode(extension) &&
153 IsIncognitoEnabled(extension->id(), context);
[email protected]a7ff4b72013-10-17 20:56:02154}
155
[email protected]1d5cf4142014-01-24 18:25:22156bool AllowFileAccess(const std::string& extension_id,
157 content::BrowserContext* context) {
158 return CommandLine::ForCurrentProcess()->HasSwitch(
159 switches::kDisableExtensionsFileAccessCheck) ||
160 ExtensionPrefs::Get(context)->AllowFileAccess(extension_id);
[email protected]a7ff4b72013-10-17 20:56:02161}
162
[email protected]1d5cf4142014-01-24 18:25:22163void SetAllowFileAccess(const std::string& extension_id,
164 content::BrowserContext* context,
[email protected]a7ff4b72013-10-17 20:56:02165 bool allow) {
166 // Reload to update browser state. Only bother if the value changed and the
167 // extension is actually enabled, since there is no UI otherwise.
[email protected]1d5cf4142014-01-24 18:25:22168 if (allow == AllowFileAccess(extension_id, context))
[email protected]a7ff4b72013-10-17 20:56:02169 return;
170
[email protected]7c82539c2014-02-19 06:09:17171 ExtensionPrefs::Get(context)->SetAllowFileAccess(extension_id, allow);
[email protected]a7ff4b72013-10-17 20:56:02172
thestig7b4bd932014-09-09 22:44:31173 ReloadExtensionIfEnabled(extension_id, context);
[email protected]a7ff4b72013-10-17 20:56:02174}
175
[email protected]b33c8c22014-05-29 19:51:08176bool AllowedScriptingOnAllUrls(const std::string& extension_id,
177 content::BrowserContext* context) {
178 bool allowed = false;
179 return ExtensionPrefs::Get(context)->ReadPrefAsBoolean(
180 extension_id,
181 kExtensionAllowedOnAllUrlsPrefName,
182 &allowed) &&
183 allowed;
184}
185
186void SetAllowedScriptingOnAllUrls(const std::string& extension_id,
187 content::BrowserContext* context,
188 bool allowed) {
[email protected]23a85362014-07-07 23:26:19189 if (allowed == AllowedScriptingOnAllUrls(extension_id, context))
190 return; // Nothing to do here.
191
[email protected]b33c8c22014-05-29 19:51:08192 ExtensionPrefs::Get(context)->UpdateExtensionPref(
193 extension_id,
194 kExtensionAllowedOnAllUrlsPrefName,
195 allowed ? new base::FundamentalValue(true) : NULL);
[email protected]23a85362014-07-07 23:26:19196
197 const Extension* extension =
198 ExtensionRegistry::Get(context)->enabled_extensions().GetByID(
199 extension_id);
200 if (extension) {
201 PermissionsUpdater updater(context);
202 if (allowed)
203 updater.GrantWithheldImpliedAllHosts(extension);
204 else
205 updater.WithholdImpliedAllHosts(extension);
206 }
[email protected]b33c8c22014-05-29 19:51:08207}
208
[email protected]4d67e9d2014-08-18 22:03:54209bool ScriptsMayRequireActionForExtension(const Extension* extension) {
210 // An extension requires user action to execute scripts iff the switch to do
211 // so is enabled, the extension shows up in chrome:extensions (so the user can
212 // grant withheld permissions), the extension is not part of chrome or
213 // corporate policy, and also not on the scripting whitelist.
214 return FeatureSwitch::scripts_require_action()->IsEnabled() &&
215 extension->ShouldDisplayInExtensionSettings() &&
216 !Manifest::IsPolicyLocation(extension->location()) &&
217 !Manifest::IsComponentLocation(extension->location()) &&
218 !PermissionsData::CanExecuteScriptEverywhere(extension);
219}
220
[email protected]f5ea0962013-11-22 09:20:47221bool IsAppLaunchable(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:22222 content::BrowserContext* context) {
[email protected]47e19402014-06-27 09:01:14223 int reason = ExtensionPrefs::Get(context)->GetDisableReasons(extension_id);
224 return !((reason & Extension::DISABLE_UNSUPPORTED_REQUIREMENT) ||
225 (reason & Extension::DISABLE_CORRUPTED));
[email protected]f5ea0962013-11-22 09:20:47226}
227
228bool IsAppLaunchableWithoutEnabling(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:22229 content::BrowserContext* context) {
230 return ExtensionRegistry::Get(context)->GetExtensionById(
231 extension_id, ExtensionRegistry::ENABLED) != NULL;
[email protected]f5ea0962013-11-22 09:20:47232}
233
[email protected]658eae52014-06-14 20:28:05234bool ShouldSyncExtension(const Extension* extension,
235 content::BrowserContext* context) {
236 return sync_helper::IsSyncableExtension(extension) &&
237 !ExtensionPrefs::Get(context)->DoNotSync(extension->id());
238}
239
[email protected]30e190f82014-05-26 16:44:39240bool ShouldSyncApp(const Extension* app, content::BrowserContext* context) {
241 return sync_helper::IsSyncableApp(app) &&
[email protected]658eae52014-06-14 20:28:05242 !util::IsEphemeralApp(app->id(), context) &&
243 !ExtensionPrefs::Get(context)->DoNotSync(app->id());
[email protected]30e190f82014-05-26 16:44:39244}
245
[email protected]617342a42013-12-18 23:34:03246bool IsExtensionIdle(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:22247 content::BrowserContext* context) {
elijahtaylor0def4432014-10-06 18:15:11248 std::vector<std::string> ids_to_check;
249 ids_to_check.push_back(extension_id);
[email protected]617342a42013-12-18 23:34:03250
elijahtaylor0def4432014-10-06 18:15:11251 const Extension* extension =
252 ExtensionRegistry::Get(context)
253 ->GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
254 if (extension && extension->is_shared_module()) {
255 // We have to check all the extensions that use this shared module for idle
256 // to tell whether it is really 'idle'.
257 SharedModuleService* service = ExtensionSystem::Get(context)
258 ->extension_service()
259 ->shared_module_service();
260 scoped_ptr<ExtensionSet> dependents =
261 service->GetDependentExtensions(extension);
262 for (ExtensionSet::const_iterator i = dependents->begin();
263 i != dependents->end();
264 i++) {
265 ids_to_check.push_back((*i)->id());
266 }
267 }
268
reillyg0ea3fa902014-10-28 15:30:23269 ProcessManager* process_manager = ProcessManager::Get(context);
elijahtaylor0def4432014-10-06 18:15:11270 for (std::vector<std::string>::const_iterator i = ids_to_check.begin();
271 i != ids_to_check.end();
272 i++) {
273 const std::string id = (*i);
274 ExtensionHost* host = process_manager->GetBackgroundHostForExtension(id);
275 if (host)
276 return false;
277
278 content::SiteInstance* site_instance =
279 process_manager->GetSiteInstanceForURL(
280 Extension::GetBaseURLFromExtensionId(id));
281 if (site_instance && site_instance->HasProcess())
282 return false;
283
284 if (!process_manager->GetRenderViewHostsForExtension(id).empty())
285 return false;
286 }
287 return true;
[email protected]617342a42013-12-18 23:34:03288}
289
[email protected]3a746ec2014-03-15 05:30:56290GURL GetSiteForExtensionId(const std::string& extension_id,
291 content::BrowserContext* context) {
292 return content::SiteInstance::GetSiteForURL(
293 context, Extension::GetBaseURLFromExtensionId(extension_id));
294}
295
[email protected]bb2feea2014-03-18 22:08:13296scoped_ptr<base::DictionaryValue> GetExtensionInfo(const Extension* extension) {
297 DCHECK(extension);
298 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
299
300 dict->SetString("id", extension->id());
301 dict->SetString("name", extension->name());
302
303 GURL icon = extensions::ExtensionIconSource::GetIconURL(
304 extension,
305 extension_misc::EXTENSION_ICON_SMALLISH,
306 ExtensionIconSet::MATCH_BIGGER,
307 false, // Not grayscale.
308 NULL); // Don't set bool if exists.
309 dict->SetString("icon", icon.spec());
310
311 return dict.Pass();
312}
313
[email protected]ca0336342014-03-21 12:58:34314bool HasIsolatedStorage(const ExtensionInfo& info) {
315 if (!info.extension_manifest.get())
316 return false;
317
318 std::string error;
319 scoped_refptr<const Extension> extension(Extension::Create(
320 info.extension_path,
321 info.extension_location,
322 *info.extension_manifest,
323 Extension::NO_FLAGS,
324 info.extension_id,
325 &error));
326 if (!extension.get())
327 return false;
328
329 return AppIsolationInfo::HasIsolatedStorage(extension.get());
330}
331
332bool SiteHasIsolatedStorage(const GURL& extension_site_url,
333 content::BrowserContext* context) {
334 const Extension* extension = ExtensionRegistry::Get(context)->
335 enabled_extensions().GetExtensionOrAppByURL(extension_site_url);
[email protected]9a87b6c2014-06-18 07:32:10336 if (!extension)
337 return false;
[email protected]ca0336342014-03-21 12:58:34338
[email protected]9a87b6c2014-06-18 07:32:10339 return AppIsolationInfo::HasIsolatedStorage(extension);
[email protected]ca0336342014-03-21 12:58:34340}
341
[email protected]7eb20e32014-04-30 08:50:56342const gfx::ImageSkia& GetDefaultAppIcon() {
343 return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
344 IDR_APP_DEFAULT_ICON);
345}
346
347const gfx::ImageSkia& GetDefaultExtensionIcon() {
348 return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
349 IDR_EXTENSION_DEFAULT_ICON);
350}
351
benwells39f23ae2014-08-27 08:01:52352bool IsStreamlinedHostedAppsEnabled() {
benwells3354b1edc2014-12-12 01:23:01353 return !CommandLine::ForCurrentProcess()->HasSwitch(
354 switches::kDisableNewBookmarkApps);
benwells39f23ae2014-08-27 08:01:52355}
356
[email protected]1d5cf4142014-01-24 18:25:22357} // namespace util
358} // namespace extensions