blob: 6e33a9a9170367358d0255afddf19271d88c5eb4 [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"
[email protected]277c4142014-06-19 20:08:5427#include "extensions/common/features/simple_feature.h"
[email protected]a7ff4b72013-10-17 20:56:0228#include "extensions/common/manifest.h"
[email protected]1f7de252013-11-06 22:02:0029#include "extensions/common/manifest_handlers/incognito_info.h"
[email protected]4d67e9d2014-08-18 22:03:5430#include "extensions/common/permissions/permissions_data.h"
mukai4245dfe82014-09-05 17:40:5131#include "extensions/grit/extensions_browser_resources.h"
[email protected]7eb20e32014-04-30 08:50:5632#include "ui/base/resource/resource_bundle.h"
[email protected]a7ff4b72013-10-17 20:56:0233
[email protected]1d5cf4142014-01-24 18:25:2234namespace extensions {
35namespace util {
[email protected]a7ff4b72013-10-17 20:56:0236
[email protected]b33c8c22014-05-29 19:51:0837namespace {
thestig7b4bd932014-09-09 22:44:3138
[email protected]b33c8c22014-05-29 19:51:0839// The entry into the ExtensionPrefs for allowing an extension to script on
40// all urls without explicit permission.
41const char kExtensionAllowedOnAllUrlsPrefName[] =
42 "extension_can_script_all_urls";
[email protected]277c4142014-06-19 20:08:5443
44// Returns true if |extension_id| for an external component extension should
45// always be enabled in incognito windows.
46bool IsWhitelistedForIncognito(const std::string& extension_id) {
47 static const char* kExtensionWhitelist[] = {
48 "D5736E4B5CF695CB93A2FB57E4FDC6E5AFAB6FE2", // http://crbug.com/312900
49 "D57DE394F36DC1C3220E7604C575D29C51A6C495", // http://crbug.com/319444
50 "3F65507A3B39259B38C8173C6FFA3D12DF64CCE9" // http://crbug.com/371562
51 };
52
53 return extensions::SimpleFeature::IsIdInList(
54 extension_id,
55 std::set<std::string>(
56 kExtensionWhitelist,
57 kExtensionWhitelist + arraysize(kExtensionWhitelist)));
[email protected]b33c8c22014-05-29 19:51:0858}
thestig7b4bd932014-09-09 22:44:3159
60// Returns |extension_id|. See note below.
61std::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);
66
67 if (!extension_is_enabled)
68 return extension_id;
69
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();
75 CHECK(service);
76 service->ReloadExtension(id);
77 return id;
78}
79
[email protected]277c4142014-06-19 20:08:5480} // namespace
[email protected]b33c8c22014-05-29 19:51:0881
[email protected]a7ff4b72013-10-17 20:56:0282bool IsIncognitoEnabled(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:2283 content::BrowserContext* context) {
84 const Extension* extension = ExtensionRegistry::Get(context)->
85 GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
86 if (extension) {
87 if (!extension->can_be_incognito_enabled())
88 return false;
89 // If this is an existing component extension we always allow it to
90 // work in incognito mode.
91 if (extension->location() == Manifest::COMPONENT)
92 return true;
[email protected]277c4142014-06-19 20:08:5493 if (extension->location() == Manifest::EXTERNAL_COMPONENT &&
94 IsWhitelistedForIncognito(extension_id)) {
95 return true;
96 }
[email protected]1d5cf4142014-01-24 18:25:2297 }
[email protected]a7ff4b72013-10-17 20:56:0298
[email protected]1d5cf4142014-01-24 18:25:2299 return ExtensionPrefs::Get(context)->IsIncognitoEnabled(extension_id);
[email protected]a7ff4b72013-10-17 20:56:02100}
101
102void SetIsIncognitoEnabled(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:22103 content::BrowserContext* context,
[email protected]a7ff4b72013-10-17 20:56:02104 bool enabled) {
thestig7b4bd932014-09-09 22:44:31105 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
106 const Extension* extension =
107 registry->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
[email protected]a7ff4b72013-10-17 20:56:02108
[email protected]1d5cf4142014-01-24 18:25:22109 if (extension) {
110 if (!extension->can_be_incognito_enabled())
111 return;
112
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));
118
119 // If we are here, make sure the we aren't trying to change the value.
thestig7b4bd932014-09-09 22:44:31120 DCHECK_EQ(enabled, IsIncognitoEnabled(extension_id, context));
[email protected]1d5cf4142014-01-24 18:25:22121 return;
122 }
[email protected]a7ff4b72013-10-17 20:56:02123 }
124
thestig7b4bd932014-09-09 22:44:31125 ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(context);
[email protected]a7ff4b72013-10-17 20:56:02126 // 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
128 // no UI otherwise.
129 bool old_enabled = extension_prefs->IsIncognitoEnabled(extension_id);
130 if (enabled == old_enabled)
131 return;
132
133 extension_prefs->SetIsIncognitoEnabled(extension_id, enabled);
134
thestig7b4bd932014-09-09 22:44:31135 std::string id = ReloadExtensionIfEnabled(extension_id, context);
[email protected]a7ff4b72013-10-17 20:56:02136
137 // Reloading the extension invalidates the |extension| pointer.
thestig7b4bd932014-09-09 22:44:31138 extension = registry->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
[email protected]f8aefb132013-10-30 09:29:52139 if (extension) {
thestig7b4bd932014-09-09 22:44:31140 Profile* profile = Profile::FromBrowserContext(context);
141 ExtensionSyncService::Get(profile)->SyncExtensionChangeIfNeeded(*extension);
[email protected]f8aefb132013-10-30 09:29:52142 }
[email protected]a7ff4b72013-10-17 20:56:02143}
144
145bool CanCrossIncognito(const Extension* extension,
[email protected]1d5cf4142014-01-24 18:25:22146 content::BrowserContext* context) {
[email protected]a7ff4b72013-10-17 20:56:02147 // 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.
150 CHECK(extension);
[email protected]1d5cf4142014-01-24 18:25:22151 return IsIncognitoEnabled(extension->id(), context) &&
152 !IncognitoInfo::IsSplitMode(extension);
[email protected]a7ff4b72013-10-17 20:56:02153}
154
155bool CanLoadInIncognito(const Extension* extension,
[email protected]1d5cf4142014-01-24 18:25:22156 content::BrowserContext* context) {
157 CHECK(extension);
[email protected]a7ff4b72013-10-17 20:56:02158 if (extension->is_hosted_app())
159 return true;
160 // Packaged apps and regular extensions need to be enabled specifically for
161 // incognito (and split mode should be set).
[email protected]1d5cf4142014-01-24 18:25:22162 return IncognitoInfo::IsSplitMode(extension) &&
163 IsIncognitoEnabled(extension->id(), context);
[email protected]a7ff4b72013-10-17 20:56:02164}
165
[email protected]1d5cf4142014-01-24 18:25:22166bool 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);
[email protected]a7ff4b72013-10-17 20:56:02171}
172
[email protected]1d5cf4142014-01-24 18:25:22173void SetAllowFileAccess(const std::string& extension_id,
174 content::BrowserContext* context,
[email protected]a7ff4b72013-10-17 20:56:02175 bool allow) {
[email protected]a7ff4b72013-10-17 20:56:02176 // Reload to update browser state. Only bother if the value changed and the
177 // extension is actually enabled, since there is no UI otherwise.
[email protected]1d5cf4142014-01-24 18:25:22178 if (allow == AllowFileAccess(extension_id, context))
[email protected]a7ff4b72013-10-17 20:56:02179 return;
180
[email protected]7c82539c2014-02-19 06:09:17181 ExtensionPrefs::Get(context)->SetAllowFileAccess(extension_id, allow);
[email protected]a7ff4b72013-10-17 20:56:02182
thestig7b4bd932014-09-09 22:44:31183 ReloadExtensionIfEnabled(extension_id, context);
[email protected]a7ff4b72013-10-17 20:56:02184}
185
[email protected]b33c8c22014-05-29 19:51:08186bool AllowedScriptingOnAllUrls(const std::string& extension_id,
187 content::BrowserContext* context) {
188 bool allowed = false;
189 return ExtensionPrefs::Get(context)->ReadPrefAsBoolean(
190 extension_id,
191 kExtensionAllowedOnAllUrlsPrefName,
192 &allowed) &&
193 allowed;
194}
195
196void SetAllowedScriptingOnAllUrls(const std::string& extension_id,
197 content::BrowserContext* context,
198 bool allowed) {
[email protected]23a85362014-07-07 23:26:19199 if (allowed == AllowedScriptingOnAllUrls(extension_id, context))
200 return; // Nothing to do here.
201
[email protected]b33c8c22014-05-29 19:51:08202 ExtensionPrefs::Get(context)->UpdateExtensionPref(
203 extension_id,
204 kExtensionAllowedOnAllUrlsPrefName,
205 allowed ? new base::FundamentalValue(true) : NULL);
[email protected]23a85362014-07-07 23:26:19206
207 const Extension* extension =
208 ExtensionRegistry::Get(context)->enabled_extensions().GetByID(
209 extension_id);
210 if (extension) {
211 PermissionsUpdater updater(context);
212 if (allowed)
213 updater.GrantWithheldImpliedAllHosts(extension);
214 else
215 updater.WithholdImpliedAllHosts(extension);
216 }
[email protected]b33c8c22014-05-29 19:51:08217}
218
[email protected]4d67e9d2014-08-18 22:03:54219bool 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);
229}
230
[email protected]f5ea0962013-11-22 09:20:47231bool IsAppLaunchable(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:22232 content::BrowserContext* context) {
[email protected]47e19402014-06-27 09:01:14233 int reason = ExtensionPrefs::Get(context)->GetDisableReasons(extension_id);
234 return !((reason & Extension::DISABLE_UNSUPPORTED_REQUIREMENT) ||
235 (reason & Extension::DISABLE_CORRUPTED));
[email protected]f5ea0962013-11-22 09:20:47236}
237
238bool IsAppLaunchableWithoutEnabling(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:22239 content::BrowserContext* context) {
240 return ExtensionRegistry::Get(context)->GetExtensionById(
241 extension_id, ExtensionRegistry::ENABLED) != NULL;
[email protected]f5ea0962013-11-22 09:20:47242}
243
[email protected]658eae52014-06-14 20:28:05244bool ShouldSyncExtension(const Extension* extension,
245 content::BrowserContext* context) {
246 return sync_helper::IsSyncableExtension(extension) &&
247 !ExtensionPrefs::Get(context)->DoNotSync(extension->id());
248}
249
[email protected]30e190f82014-05-26 16:44:39250bool ShouldSyncApp(const Extension* app, content::BrowserContext* context) {
251 return sync_helper::IsSyncableApp(app) &&
[email protected]658eae52014-06-14 20:28:05252 !util::IsEphemeralApp(app->id(), context) &&
253 !ExtensionPrefs::Get(context)->DoNotSync(app->id());
[email protected]30e190f82014-05-26 16:44:39254}
255
[email protected]617342a42013-12-18 23:34:03256bool IsExtensionIdle(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:22257 content::BrowserContext* context) {
elijahtaylor0def4432014-10-06 18:15:11258 std::vector<std::string> ids_to_check;
259 ids_to_check.push_back(extension_id);
[email protected]617342a42013-12-18 23:34:03260
elijahtaylor0def4432014-10-06 18:15:11261 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();
274 i++) {
275 ids_to_check.push_back((*i)->id());
276 }
277 }
278
reillyg0ea3fa902014-10-28 15:30:23279 ProcessManager* process_manager = ProcessManager::Get(context);
elijahtaylor0def4432014-10-06 18:15:11280 for (std::vector<std::string>::const_iterator i = ids_to_check.begin();
281 i != ids_to_check.end();
282 i++) {
283 const std::string id = (*i);
284 ExtensionHost* host = process_manager->GetBackgroundHostForExtension(id);
285 if (host)
286 return false;
287
288 content::SiteInstance* site_instance =
289 process_manager->GetSiteInstanceForURL(
290 Extension::GetBaseURLFromExtensionId(id));
291 if (site_instance && site_instance->HasProcess())
292 return false;
293
294 if (!process_manager->GetRenderViewHostsForExtension(id).empty())
295 return false;
296 }
297 return true;
[email protected]617342a42013-12-18 23:34:03298}
299
[email protected]3a746ec2014-03-15 05:30:56300GURL GetSiteForExtensionId(const std::string& extension_id,
301 content::BrowserContext* context) {
302 return content::SiteInstance::GetSiteForURL(
303 context, Extension::GetBaseURLFromExtensionId(extension_id));
304}
305
[email protected]bb2feea2014-03-18 22:08:13306scoped_ptr<base::DictionaryValue> GetExtensionInfo(const Extension* extension) {
307 DCHECK(extension);
308 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
309
310 dict->SetString("id", extension->id());
311 dict->SetString("name", extension->name());
312
313 GURL icon = extensions::ExtensionIconSource::GetIconURL(
314 extension,
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());
320
321 return dict.Pass();
322}
323
[email protected]ca0336342014-03-21 12:58:34324bool HasIsolatedStorage(const ExtensionInfo& info) {
325 if (!info.extension_manifest.get())
326 return false;
327
328 std::string error;
329 scoped_refptr<const Extension> extension(Extension::Create(
330 info.extension_path,
331 info.extension_location,
332 *info.extension_manifest,
333 Extension::NO_FLAGS,
334 info.extension_id,
335 &error));
336 if (!extension.get())
337 return false;
338
339 return AppIsolationInfo::HasIsolatedStorage(extension.get());
340}
341
342bool SiteHasIsolatedStorage(const GURL& extension_site_url,
343 content::BrowserContext* context) {
344 const Extension* extension = ExtensionRegistry::Get(context)->
345 enabled_extensions().GetExtensionOrAppByURL(extension_site_url);
[email protected]9a87b6c2014-06-18 07:32:10346 if (!extension)
347 return false;
[email protected]ca0336342014-03-21 12:58:34348
[email protected]9a87b6c2014-06-18 07:32:10349 return AppIsolationInfo::HasIsolatedStorage(extension);
[email protected]ca0336342014-03-21 12:58:34350}
351
[email protected]7eb20e32014-04-30 08:50:56352const gfx::ImageSkia& GetDefaultAppIcon() {
353 return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
354 IDR_APP_DEFAULT_ICON);
355}
356
357const gfx::ImageSkia& GetDefaultExtensionIcon() {
358 return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
359 IDR_EXTENSION_DEFAULT_ICON);
360}
361
benwells39f23ae2014-08-27 08:01:52362bool IsStreamlinedHostedAppsEnabled() {
363 return CommandLine::ForCurrentProcess()->HasSwitch(
364 switches::kEnableStreamlinedHostedApps);
365}
366
[email protected]1d5cf4142014-01-24 18:25:22367} // namespace util
368} // namespace extensions