blob: 6b27885445973a01fb41f875222c267a0e1e99c6 [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]1d5cf4142014-01-24 18:25:2212#include "chrome/browser/profiles/profile.h"
[email protected]bb2feea2014-03-18 22:08:1313#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
[email protected]a7ff4b72013-10-17 20:56:0214#include "chrome/common/chrome_switches.h"
[email protected]ca0336342014-03-21 12:58:3415#include "chrome/common/extensions/manifest_handlers/app_isolation_info.h"
[email protected]a7ff4b72013-10-17 20:56:0216#include "chrome/common/extensions/sync_helper.h"
[email protected]617342a42013-12-18 23:34:0317#include "content/public/browser/site_instance.h"
[email protected]489db0842014-01-22 18:20:0318#include "extensions/browser/extension_prefs.h"
[email protected]599539802014-01-07 23:06:0019#include "extensions/browser/extension_registry.h"
[email protected]59b0e602014-01-30 00:41:2420#include "extensions/browser/extension_system.h"
[email protected]30e190f82014-05-26 16:44:3921#include "extensions/browser/extension_util.h"
[email protected]e4452d32013-11-15 23:07:4122#include "extensions/common/extension.h"
[email protected]4b7908842014-04-07 23:50:2223#include "extensions/common/extension_icon_set.h"
[email protected]277c4142014-06-19 20:08:5424#include "extensions/common/features/simple_feature.h"
[email protected]a7ff4b72013-10-17 20:56:0225#include "extensions/common/manifest.h"
[email protected]1f7de252013-11-06 22:02:0026#include "extensions/common/manifest_handlers/incognito_info.h"
[email protected]7eb20e32014-04-30 08:50:5627#include "grit/theme_resources.h"
28#include "ui/base/resource/resource_bundle.h"
[email protected]a7ff4b72013-10-17 20:56:0229
[email protected]1d5cf4142014-01-24 18:25:2230namespace extensions {
31namespace util {
[email protected]a7ff4b72013-10-17 20:56:0232
[email protected]b33c8c22014-05-29 19:51:0833namespace {
34// The entry into the ExtensionPrefs for allowing an extension to script on
35// all urls without explicit permission.
36const char kExtensionAllowedOnAllUrlsPrefName[] =
37 "extension_can_script_all_urls";
[email protected]277c4142014-06-19 20:08:5438
39// Returns true if |extension_id| for an external component extension should
40// always be enabled in incognito windows.
41bool IsWhitelistedForIncognito(const std::string& extension_id) {
42 static const char* kExtensionWhitelist[] = {
43 "D5736E4B5CF695CB93A2FB57E4FDC6E5AFAB6FE2", // http://crbug.com/312900
44 "D57DE394F36DC1C3220E7604C575D29C51A6C495", // http://crbug.com/319444
45 "3F65507A3B39259B38C8173C6FFA3D12DF64CCE9" // http://crbug.com/371562
46 };
47
48 return extensions::SimpleFeature::IsIdInList(
49 extension_id,
50 std::set<std::string>(
51 kExtensionWhitelist,
52 kExtensionWhitelist + arraysize(kExtensionWhitelist)));
[email protected]b33c8c22014-05-29 19:51:0853}
[email protected]277c4142014-06-19 20:08:5454} // namespace
[email protected]b33c8c22014-05-29 19:51:0855
[email protected]a7ff4b72013-10-17 20:56:0256bool IsIncognitoEnabled(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:2257 content::BrowserContext* context) {
58 const Extension* extension = ExtensionRegistry::Get(context)->
59 GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
60 if (extension) {
61 if (!extension->can_be_incognito_enabled())
62 return false;
63 // If this is an existing component extension we always allow it to
64 // work in incognito mode.
65 if (extension->location() == Manifest::COMPONENT)
66 return true;
[email protected]277c4142014-06-19 20:08:5467 if (extension->location() == Manifest::EXTERNAL_COMPONENT &&
68 IsWhitelistedForIncognito(extension_id)) {
69 return true;
70 }
[email protected]1d5cf4142014-01-24 18:25:2271 }
[email protected]a7ff4b72013-10-17 20:56:0272
[email protected]1d5cf4142014-01-24 18:25:2273 return ExtensionPrefs::Get(context)->IsIncognitoEnabled(extension_id);
[email protected]a7ff4b72013-10-17 20:56:0274}
75
76void SetIsIncognitoEnabled(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:2277 content::BrowserContext* context,
[email protected]a7ff4b72013-10-17 20:56:0278 bool enabled) {
[email protected]1d5cf4142014-01-24 18:25:2279 ExtensionService* service =
[email protected]59b0e602014-01-30 00:41:2480 ExtensionSystem::Get(context)->extension_service();
[email protected]1d5cf4142014-01-24 18:25:2281 CHECK(service);
[email protected]a7ff4b72013-10-17 20:56:0282 const Extension* extension = service->GetInstalledExtension(extension_id);
[email protected]a7ff4b72013-10-17 20:56:0283
[email protected]1d5cf4142014-01-24 18:25:2284 if (extension) {
85 if (!extension->can_be_incognito_enabled())
86 return;
87
88 if (extension->location() == Manifest::COMPONENT) {
89 // This shouldn't be called for component extensions unless it is called
90 // by sync, for syncable component extensions.
91 // See http://crbug.com/112290 and associated CLs for the sordid history.
92 DCHECK(sync_helper::IsSyncable(extension));
93
94 // If we are here, make sure the we aren't trying to change the value.
95 DCHECK_EQ(enabled, IsIncognitoEnabled(extension_id, service->profile()));
96 return;
97 }
[email protected]a7ff4b72013-10-17 20:56:0298 }
99
[email protected]7c82539c2014-02-19 06:09:17100 ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(service->profile());
[email protected]a7ff4b72013-10-17 20:56:02101 // Broadcast unloaded and loaded events to update browser state. Only bother
102 // if the value changed and the extension is actually enabled, since there is
103 // no UI otherwise.
104 bool old_enabled = extension_prefs->IsIncognitoEnabled(extension_id);
105 if (enabled == old_enabled)
106 return;
107
108 extension_prefs->SetIsIncognitoEnabled(extension_id, enabled);
109
110 bool extension_is_enabled = service->extensions()->Contains(extension_id);
111
112 // When we reload the extension the ID may be invalidated if we've passed it
113 // by const ref everywhere. Make a copy to be safe.
114 std::string id = extension_id;
115 if (extension_is_enabled)
116 service->ReloadExtension(id);
117
118 // Reloading the extension invalidates the |extension| pointer.
119 extension = service->GetInstalledExtension(id);
[email protected]f8aefb132013-10-30 09:29:52120 if (extension) {
121 ExtensionSyncService::Get(service->profile())->
122 SyncExtensionChangeIfNeeded(*extension);
123 }
[email protected]a7ff4b72013-10-17 20:56:02124}
125
126bool CanCrossIncognito(const Extension* extension,
[email protected]1d5cf4142014-01-24 18:25:22127 content::BrowserContext* context) {
[email protected]a7ff4b72013-10-17 20:56:02128 // We allow the extension to see events and data from another profile iff it
129 // uses "spanning" behavior and it has incognito access. "split" mode
130 // extensions only see events for a matching profile.
131 CHECK(extension);
[email protected]1d5cf4142014-01-24 18:25:22132 return IsIncognitoEnabled(extension->id(), context) &&
133 !IncognitoInfo::IsSplitMode(extension);
[email protected]a7ff4b72013-10-17 20:56:02134}
135
136bool CanLoadInIncognito(const Extension* extension,
[email protected]1d5cf4142014-01-24 18:25:22137 content::BrowserContext* context) {
138 CHECK(extension);
[email protected]a7ff4b72013-10-17 20:56:02139 if (extension->is_hosted_app())
140 return true;
141 // Packaged apps and regular extensions need to be enabled specifically for
142 // incognito (and split mode should be set).
[email protected]1d5cf4142014-01-24 18:25:22143 return IncognitoInfo::IsSplitMode(extension) &&
144 IsIncognitoEnabled(extension->id(), context);
[email protected]a7ff4b72013-10-17 20:56:02145}
146
[email protected]1d5cf4142014-01-24 18:25:22147bool AllowFileAccess(const std::string& extension_id,
148 content::BrowserContext* context) {
149 return CommandLine::ForCurrentProcess()->HasSwitch(
150 switches::kDisableExtensionsFileAccessCheck) ||
151 ExtensionPrefs::Get(context)->AllowFileAccess(extension_id);
[email protected]a7ff4b72013-10-17 20:56:02152}
153
[email protected]1d5cf4142014-01-24 18:25:22154void SetAllowFileAccess(const std::string& extension_id,
155 content::BrowserContext* context,
[email protected]a7ff4b72013-10-17 20:56:02156 bool allow) {
[email protected]1d5cf4142014-01-24 18:25:22157 ExtensionService* service =
[email protected]59b0e602014-01-30 00:41:24158 ExtensionSystem::Get(context)->extension_service();
[email protected]1d5cf4142014-01-24 18:25:22159 CHECK(service);
160
[email protected]a7ff4b72013-10-17 20:56:02161 // Reload to update browser state. Only bother if the value changed and the
162 // extension is actually enabled, since there is no UI otherwise.
[email protected]1d5cf4142014-01-24 18:25:22163 if (allow == AllowFileAccess(extension_id, context))
[email protected]a7ff4b72013-10-17 20:56:02164 return;
165
[email protected]7c82539c2014-02-19 06:09:17166 ExtensionPrefs::Get(context)->SetAllowFileAccess(extension_id, allow);
[email protected]a7ff4b72013-10-17 20:56:02167
[email protected]1d5cf4142014-01-24 18:25:22168 bool extension_is_enabled = service->extensions()->Contains(extension_id);
[email protected]a7ff4b72013-10-17 20:56:02169 if (extension_is_enabled)
[email protected]1d5cf4142014-01-24 18:25:22170 service->ReloadExtension(extension_id);
[email protected]a7ff4b72013-10-17 20:56:02171}
172
[email protected]b33c8c22014-05-29 19:51:08173bool AllowedScriptingOnAllUrls(const std::string& extension_id,
174 content::BrowserContext* context) {
175 bool allowed = false;
176 return ExtensionPrefs::Get(context)->ReadPrefAsBoolean(
177 extension_id,
178 kExtensionAllowedOnAllUrlsPrefName,
179 &allowed) &&
180 allowed;
181}
182
183void SetAllowedScriptingOnAllUrls(const std::string& extension_id,
184 content::BrowserContext* context,
185 bool allowed) {
186 ExtensionPrefs::Get(context)->UpdateExtensionPref(
187 extension_id,
188 kExtensionAllowedOnAllUrlsPrefName,
189 allowed ? new base::FundamentalValue(true) : NULL);
190}
191
[email protected]f5ea0962013-11-22 09:20:47192bool IsAppLaunchable(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:22193 content::BrowserContext* context) {
[email protected]47e19402014-06-27 09:01:14194 int reason = ExtensionPrefs::Get(context)->GetDisableReasons(extension_id);
195 return !((reason & Extension::DISABLE_UNSUPPORTED_REQUIREMENT) ||
196 (reason & Extension::DISABLE_CORRUPTED));
[email protected]f5ea0962013-11-22 09:20:47197}
198
199bool IsAppLaunchableWithoutEnabling(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:22200 content::BrowserContext* context) {
201 return ExtensionRegistry::Get(context)->GetExtensionById(
202 extension_id, ExtensionRegistry::ENABLED) != NULL;
[email protected]f5ea0962013-11-22 09:20:47203}
204
[email protected]658eae52014-06-14 20:28:05205bool ShouldSyncExtension(const Extension* extension,
206 content::BrowserContext* context) {
207 return sync_helper::IsSyncableExtension(extension) &&
208 !ExtensionPrefs::Get(context)->DoNotSync(extension->id());
209}
210
[email protected]30e190f82014-05-26 16:44:39211bool ShouldSyncApp(const Extension* app, content::BrowserContext* context) {
212 return sync_helper::IsSyncableApp(app) &&
[email protected]658eae52014-06-14 20:28:05213 !util::IsEphemeralApp(app->id(), context) &&
214 !ExtensionPrefs::Get(context)->DoNotSync(app->id());
[email protected]30e190f82014-05-26 16:44:39215}
216
[email protected]617342a42013-12-18 23:34:03217bool IsExtensionIdle(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:22218 content::BrowserContext* context) {
219 ProcessManager* process_manager =
[email protected]59b0e602014-01-30 00:41:24220 ExtensionSystem::Get(context)->process_manager();
[email protected]617342a42013-12-18 23:34:03221 DCHECK(process_manager);
[email protected]1d5cf4142014-01-24 18:25:22222 ExtensionHost* host =
[email protected]617342a42013-12-18 23:34:03223 process_manager->GetBackgroundHostForExtension(extension_id);
224 if (host)
225 return false;
226
227 content::SiteInstance* site_instance = process_manager->GetSiteInstanceForURL(
228 Extension::GetBaseURLFromExtensionId(extension_id));
[email protected]1d5cf4142014-01-24 18:25:22229 if (site_instance && site_instance->HasProcess())
[email protected]617342a42013-12-18 23:34:03230 return false;
[email protected]617342a42013-12-18 23:34:03231
232 return process_manager->GetRenderViewHostsForExtension(extension_id).empty();
233}
234
[email protected]3a746ec2014-03-15 05:30:56235GURL GetSiteForExtensionId(const std::string& extension_id,
236 content::BrowserContext* context) {
237 return content::SiteInstance::GetSiteForURL(
238 context, Extension::GetBaseURLFromExtensionId(extension_id));
239}
240
[email protected]bb2feea2014-03-18 22:08:13241scoped_ptr<base::DictionaryValue> GetExtensionInfo(const Extension* extension) {
242 DCHECK(extension);
243 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
244
245 dict->SetString("id", extension->id());
246 dict->SetString("name", extension->name());
247
248 GURL icon = extensions::ExtensionIconSource::GetIconURL(
249 extension,
250 extension_misc::EXTENSION_ICON_SMALLISH,
251 ExtensionIconSet::MATCH_BIGGER,
252 false, // Not grayscale.
253 NULL); // Don't set bool if exists.
254 dict->SetString("icon", icon.spec());
255
256 return dict.Pass();
257}
258
[email protected]ca0336342014-03-21 12:58:34259bool HasIsolatedStorage(const ExtensionInfo& info) {
260 if (!info.extension_manifest.get())
261 return false;
262
263 std::string error;
264 scoped_refptr<const Extension> extension(Extension::Create(
265 info.extension_path,
266 info.extension_location,
267 *info.extension_manifest,
268 Extension::NO_FLAGS,
269 info.extension_id,
270 &error));
271 if (!extension.get())
272 return false;
273
274 return AppIsolationInfo::HasIsolatedStorage(extension.get());
275}
276
277bool SiteHasIsolatedStorage(const GURL& extension_site_url,
278 content::BrowserContext* context) {
279 const Extension* extension = ExtensionRegistry::Get(context)->
280 enabled_extensions().GetExtensionOrAppByURL(extension_site_url);
[email protected]9a87b6c2014-06-18 07:32:10281 if (!extension)
282 return false;
[email protected]ca0336342014-03-21 12:58:34283
[email protected]9a87b6c2014-06-18 07:32:10284 return AppIsolationInfo::HasIsolatedStorage(extension);
[email protected]ca0336342014-03-21 12:58:34285}
286
[email protected]7eb20e32014-04-30 08:50:56287const gfx::ImageSkia& GetDefaultAppIcon() {
288 return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
289 IDR_APP_DEFAULT_ICON);
290}
291
292const gfx::ImageSkia& GetDefaultExtensionIcon() {
293 return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
294 IDR_EXTENSION_DEFAULT_ICON);
295}
296
[email protected]1d5cf4142014-01-24 18:25:22297} // namespace util
298} // namespace extensions