blob: eb721285c35adafb797414e0ed86d7507d52b9e5 [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
tbarzic858a8482016-12-07 01:04:507#include <vector>
8
[email protected]a7ff4b72013-10-17 20:56:029#include "base/command_line.h"
tapted70cdc812017-03-23 20:48:1910#include "base/feature_list.h"
[email protected]bb2feea2014-03-18 22:08:1311#include "base/logging.h"
treib3202d592015-07-31 08:33:1612#include "base/metrics/field_trial.h"
[email protected]bb2feea2014-03-18 22:08:1313#include "base/values.h"
avia2f4804a2015-12-24 23:11:1314#include "build/build_config.h"
Matt Giucad4870432017-11-24 01:04:3815#include "chrome/browser/banners/app_banner_manager.h"
[email protected]a7ff4b72013-10-17 20:56:0216#include "chrome/browser/extensions/extension_service.h"
[email protected]f8aefb132013-10-30 09:29:5217#include "chrome/browser/extensions/extension_sync_service.h"
Alan Cutter70927ec92018-03-22 00:58:4918#include "chrome/browser/extensions/launch_util.h"
[email protected]23a85362014-07-07 23:26:1919#include "chrome/browser/extensions/permissions_updater.h"
rdevlin.cronincb9f86e2015-10-15 15:13:4220#include "chrome/browser/extensions/scripting_permissions_modifier.h"
elijahtaylor0def4432014-10-06 18:15:1121#include "chrome/browser/extensions/shared_module_service.h"
[email protected]1d5cf4142014-01-24 18:25:2222#include "chrome/browser/profiles/profile.h"
Alan Cutter09965802018-03-27 07:25:2923#include "chrome/browser/ui/browser.h"
[email protected]bb2feea2014-03-18 22:08:1324#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
Ben Wellse13d31692018-08-31 00:22:3325#include "chrome/browser/web_applications/extensions/bookmark_app_util.h"
tapted70cdc812017-03-23 20:48:1926#include "chrome/common/chrome_features.h"
[email protected]a7ff4b72013-10-17 20:56:0227#include "chrome/common/chrome_switches.h"
Alan Cutter70927ec92018-03-22 00:58:4928#include "chrome/common/extensions/api/url_handlers/url_handlers_parser.h"
[email protected]a7ff4b72013-10-17 20:56:0229#include "chrome/common/extensions/sync_helper.h"
treibb6af28cd2015-12-01 11:19:4630#include "components/variations/variations_associated_data.h"
[email protected]617342a42013-12-18 23:34:0331#include "content/public/browser/site_instance.h"
Devlin Croninbffe949eb2018-01-12 03:03:4032#include "extensions/browser/disable_reason.h"
[email protected]489db0842014-01-22 18:20:0333#include "extensions/browser/extension_prefs.h"
[email protected]599539802014-01-07 23:06:0034#include "extensions/browser/extension_registry.h"
[email protected]59b0e602014-01-30 00:41:2435#include "extensions/browser/extension_system.h"
[email protected]30e190f82014-05-26 16:44:3936#include "extensions/browser/extension_util.h"
[email protected]e4452d32013-11-15 23:07:4137#include "extensions/common/extension.h"
[email protected]4b7908842014-04-07 23:50:2238#include "extensions/common/extension_icon_set.h"
[email protected]a7ff4b72013-10-17 20:56:0239#include "extensions/common/manifest.h"
tfarina0bcdf362015-06-29 22:19:2640#include "extensions/common/manifest_handlers/app_isolation_info.h"
[email protected]1f7de252013-11-06 22:02:0041#include "extensions/common/manifest_handlers/incognito_info.h"
[email protected]4d67e9d2014-08-18 22:03:5442#include "extensions/common/permissions/permissions_data.h"
mukai4245dfe82014-09-05 17:40:5143#include "extensions/grit/extensions_browser_resources.h"
[email protected]7eb20e32014-04-30 08:50:5644#include "ui/base/resource/resource_bundle.h"
Michael Giuffrida7efeed142017-06-07 06:29:2145#include "url/gurl.h"
[email protected]a7ff4b72013-10-17 20:56:0246
treib13251192016-06-29 07:13:1547#if defined(OS_CHROMEOS)
48#include "chrome/browser/chromeos/file_manager/app_id.h"
49#endif
50
[email protected]1d5cf4142014-01-24 18:25:2251namespace extensions {
52namespace util {
[email protected]a7ff4b72013-10-17 20:56:0253
[email protected]b33c8c22014-05-29 19:51:0854namespace {
mamir192d7882016-06-22 17:10:1655// The entry into the prefs used to flag an extension as installed by custodian.
56// It is relevant only for supervised users.
57const char kWasInstalledByCustodianPrefName[] = "was_installed_by_custodian";
58
thestig7b4bd932014-09-09 22:44:3159// Returns |extension_id|. See note below.
60std::string ReloadExtensionIfEnabled(const std::string& extension_id,
61 content::BrowserContext* context) {
62 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
63 bool extension_is_enabled =
64 registry->enabled_extensions().Contains(extension_id);
65
66 if (!extension_is_enabled)
67 return extension_id;
68
69 // When we reload the extension the ID may be invalidated if we've passed it
70 // by const ref everywhere. Make a copy to be safe. http://crbug.com/103762
71 std::string id = extension_id;
72 ExtensionService* service =
73 ExtensionSystem::Get(context)->extension_service();
74 CHECK(service);
75 service->ReloadExtension(id);
76 return id;
77}
78
[email protected]277c4142014-06-19 20:08:5479} // namespace
[email protected]b33c8c22014-05-29 19:51:0880
[email protected]a7ff4b72013-10-17 20:56:0281void SetIsIncognitoEnabled(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:2282 content::BrowserContext* context,
[email protected]a7ff4b72013-10-17 20:56:0283 bool enabled) {
thestig7b4bd932014-09-09 22:44:3184 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
85 const Extension* extension =
86 registry->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
[email protected]a7ff4b72013-10-17 20:56:0287
[email protected]1d5cf4142014-01-24 18:25:2288 if (extension) {
kundajie548e7442015-09-18 23:19:0989 if (!util::CanBeIncognitoEnabled(extension))
[email protected]1d5cf4142014-01-24 18:25:2290 return;
91
treibc644a1c2015-07-13 08:37:0492 // TODO(treib,kalman): Should this be Manifest::IsComponentLocation(..)?
93 // (which also checks for EXTERNAL_COMPONENT).
[email protected]1d5cf4142014-01-24 18:25:2294 if (extension->location() == Manifest::COMPONENT) {
95 // This shouldn't be called for component extensions unless it is called
96 // by sync, for syncable component extensions.
97 // See http://crbug.com/112290 and associated CLs for the sordid history.
treib13251192016-06-29 07:13:1598 bool syncable = sync_helper::IsSyncableComponentExtension(extension);
99#if defined(OS_CHROMEOS)
100 // For some users, the file manager app somehow ended up being synced even
101 // though it's supposed to be unsyncable; see crbug.com/576964. If the bad
102 // data ever gets cleaned up, this hack should be removed.
103 syncable = syncable || extension->id() == file_manager::kFileManagerAppId;
104#endif
105 DCHECK(syncable);
[email protected]1d5cf4142014-01-24 18:25:22106
107 // If we are here, make sure the we aren't trying to change the value.
thestig7b4bd932014-09-09 22:44:31108 DCHECK_EQ(enabled, IsIncognitoEnabled(extension_id, context));
[email protected]1d5cf4142014-01-24 18:25:22109 return;
110 }
[email protected]a7ff4b72013-10-17 20:56:02111 }
112
thestig7b4bd932014-09-09 22:44:31113 ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(context);
[email protected]a7ff4b72013-10-17 20:56:02114 // Broadcast unloaded and loaded events to update browser state. Only bother
115 // if the value changed and the extension is actually enabled, since there is
116 // no UI otherwise.
117 bool old_enabled = extension_prefs->IsIncognitoEnabled(extension_id);
118 if (enabled == old_enabled)
119 return;
120
121 extension_prefs->SetIsIncognitoEnabled(extension_id, enabled);
122
thestig7b4bd932014-09-09 22:44:31123 std::string id = ReloadExtensionIfEnabled(extension_id, context);
[email protected]a7ff4b72013-10-17 20:56:02124
125 // Reloading the extension invalidates the |extension| pointer.
thestig7b4bd932014-09-09 22:44:31126 extension = registry->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
[email protected]f8aefb132013-10-30 09:29:52127 if (extension) {
thestig7b4bd932014-09-09 22:44:31128 Profile* profile = Profile::FromBrowserContext(context);
129 ExtensionSyncService::Get(profile)->SyncExtensionChangeIfNeeded(*extension);
[email protected]f8aefb132013-10-30 09:29:52130 }
[email protected]a7ff4b72013-10-17 20:56:02131}
132
133bool CanCrossIncognito(const Extension* extension,
[email protected]1d5cf4142014-01-24 18:25:22134 content::BrowserContext* context) {
[email protected]a7ff4b72013-10-17 20:56:02135 // We allow the extension to see events and data from another profile iff it
136 // uses "spanning" behavior and it has incognito access. "split" mode
137 // extensions only see events for a matching profile.
138 CHECK(extension);
[email protected]1d5cf4142014-01-24 18:25:22139 return IsIncognitoEnabled(extension->id(), context) &&
140 !IncognitoInfo::IsSplitMode(extension);
[email protected]a7ff4b72013-10-17 20:56:02141}
142
143bool CanLoadInIncognito(const Extension* extension,
[email protected]1d5cf4142014-01-24 18:25:22144 content::BrowserContext* context) {
145 CHECK(extension);
[email protected]a7ff4b72013-10-17 20:56:02146 if (extension->is_hosted_app())
147 return true;
148 // Packaged apps and regular extensions need to be enabled specifically for
149 // incognito (and split mode should be set).
[email protected]1d5cf4142014-01-24 18:25:22150 return IncognitoInfo::IsSplitMode(extension) &&
151 IsIncognitoEnabled(extension->id(), context);
[email protected]a7ff4b72013-10-17 20:56:02152}
153
[email protected]1d5cf4142014-01-24 18:25:22154bool AllowFileAccess(const std::string& extension_id,
155 content::BrowserContext* context) {
avi3ef9ec9e2014-12-22 22:50:17156 return base::CommandLine::ForCurrentProcess()->HasSwitch(
Oscar Johansson7f4c1b932018-06-12 06:11:58157 ::switches::kDisableExtensionsFileAccessCheck) ||
[email protected]1d5cf4142014-01-24 18:25:22158 ExtensionPrefs::Get(context)->AllowFileAccess(extension_id);
[email protected]a7ff4b72013-10-17 20:56:02159}
160
[email protected]1d5cf4142014-01-24 18:25:22161void SetAllowFileAccess(const std::string& extension_id,
162 content::BrowserContext* context,
[email protected]a7ff4b72013-10-17 20:56:02163 bool allow) {
164 // Reload to update browser state. Only bother if the value changed and the
165 // extension is actually enabled, since there is no UI otherwise.
[email protected]1d5cf4142014-01-24 18:25:22166 if (allow == AllowFileAccess(extension_id, context))
[email protected]a7ff4b72013-10-17 20:56:02167 return;
168
[email protected]7c82539c2014-02-19 06:09:17169 ExtensionPrefs::Get(context)->SetAllowFileAccess(extension_id, allow);
[email protected]a7ff4b72013-10-17 20:56:02170
thestig7b4bd932014-09-09 22:44:31171 ReloadExtensionIfEnabled(extension_id, context);
[email protected]a7ff4b72013-10-17 20:56:02172}
173
mamir192d7882016-06-22 17:10:16174void SetWasInstalledByCustodian(const std::string& extension_id,
175 content::BrowserContext* context,
176 bool installed_by_custodian) {
177 if (installed_by_custodian == WasInstalledByCustodian(extension_id, context))
178 return;
179
Karan Bhatia2a117232017-08-23 00:24:56180 ExtensionPrefs* prefs = ExtensionPrefs::Get(context);
181
182 prefs->UpdateExtensionPref(
mamir192d7882016-06-22 17:10:16183 extension_id, kWasInstalledByCustodianPrefName,
Jinho Bangb5216cec2018-01-17 19:43:11184 installed_by_custodian ? std::make_unique<base::Value>(true) : nullptr);
mamir192d7882016-06-22 17:10:16185 ExtensionService* service =
186 ExtensionSystem::Get(context)->extension_service();
187
mamir192d7882016-06-22 17:10:16188 if (!installed_by_custodian) {
189 // If installed_by_custodian changes to false, the extension may need to
190 // be unloaded now.
191 service->ReloadExtension(extension_id);
192 return;
193 }
194
mamire9609642016-06-28 22:17:54195 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
mamir192d7882016-06-22 17:10:16196 // If it is already enabled, do nothing.
197 if (registry->enabled_extensions().Contains(extension_id))
198 return;
199
Karan Bhatia2a117232017-08-23 00:24:56200 // If the extension was disabled due to management policy, try to re-enable
201 // it. Example is a pre-installed extension that was disabled when a
mamir192d7882016-06-22 17:10:16202 // supervised user flag has been received.
Karan Bhatia2a117232017-08-23 00:24:56203 // Note: EnableExtension will fail if the extension still needs to be disabled
204 // due to manangement policy.
205 if (registry->disabled_extensions().Contains(extension_id) &&
206 prefs->GetDisableReasons(extension_id) ==
207 disable_reason::DISABLE_BLOCKED_BY_POLICY) {
208 service->EnableExtension(extension_id);
mamir192d7882016-06-22 17:10:16209 }
210}
211
212bool WasInstalledByCustodian(const std::string& extension_id,
213 content::BrowserContext* context) {
214 bool installed_by_custodian = false;
215 ExtensionPrefs* prefs = ExtensionPrefs::Get(context);
216 prefs->ReadPrefAsBoolean(extension_id, kWasInstalledByCustodianPrefName,
217 &installed_by_custodian);
218 return installed_by_custodian;
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);
Minh X. Nguyen45479012017-08-18 21:35:36224 return !((reason & disable_reason::DISABLE_UNSUPPORTED_REQUIREMENT) ||
225 (reason & disable_reason::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
treibc644a1c2015-07-13 08:37:04234bool ShouldSync(const Extension* extension,
235 content::BrowserContext* context) {
236 return sync_helper::IsSyncable(extension) &&
[email protected]658eae52014-06-14 20:28:05237 !ExtensionPrefs::Get(context)->DoNotSync(extension->id());
238}
239
[email protected]617342a42013-12-18 23:34:03240bool IsExtensionIdle(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:22241 content::BrowserContext* context) {
elijahtaylor0def4432014-10-06 18:15:11242 std::vector<std::string> ids_to_check;
243 ids_to_check.push_back(extension_id);
[email protected]617342a42013-12-18 23:34:03244
elijahtaylor0def4432014-10-06 18:15:11245 const Extension* extension =
246 ExtensionRegistry::Get(context)
247 ->GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
248 if (extension && extension->is_shared_module()) {
249 // We have to check all the extensions that use this shared module for idle
250 // to tell whether it is really 'idle'.
251 SharedModuleService* service = ExtensionSystem::Get(context)
252 ->extension_service()
253 ->shared_module_service();
dchengc963c7142016-04-08 03:55:22254 std::unique_ptr<ExtensionSet> dependents =
elijahtaylor0def4432014-10-06 18:15:11255 service->GetDependentExtensions(extension);
256 for (ExtensionSet::const_iterator i = dependents->begin();
257 i != dependents->end();
258 i++) {
259 ids_to_check.push_back((*i)->id());
260 }
261 }
262
reillyg0ea3fa902014-10-28 15:30:23263 ProcessManager* process_manager = ProcessManager::Get(context);
elijahtaylor0def4432014-10-06 18:15:11264 for (std::vector<std::string>::const_iterator i = ids_to_check.begin();
265 i != ids_to_check.end();
266 i++) {
267 const std::string id = (*i);
268 ExtensionHost* host = process_manager->GetBackgroundHostForExtension(id);
269 if (host)
270 return false;
271
rdevlin.cronin3d4261522015-02-10 00:48:15272 scoped_refptr<content::SiteInstance> site_instance =
elijahtaylor0def4432014-10-06 18:15:11273 process_manager->GetSiteInstanceForURL(
274 Extension::GetBaseURLFromExtensionId(id));
275 if (site_instance && site_instance->HasProcess())
276 return false;
277
rdevlin.cronin6ae04a012015-04-03 20:19:40278 if (!process_manager->GetRenderFrameHostsForExtension(id).empty())
elijahtaylor0def4432014-10-06 18:15:11279 return false;
280 }
281 return true;
[email protected]617342a42013-12-18 23:34:03282}
283
dchengc963c7142016-04-08 03:55:22284std::unique_ptr<base::DictionaryValue> GetExtensionInfo(
285 const Extension* extension) {
[email protected]bb2feea2014-03-18 22:08:13286 DCHECK(extension);
dchengc963c7142016-04-08 03:55:22287 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
[email protected]bb2feea2014-03-18 22:08:13288
289 dict->SetString("id", extension->id());
290 dict->SetString("name", extension->name());
291
292 GURL icon = extensions::ExtensionIconSource::GetIconURL(
estade32426e02016-12-18 01:26:17293 extension, extension_misc::EXTENSION_ICON_SMALLISH,
[email protected]bb2feea2014-03-18 22:08:13294 ExtensionIconSet::MATCH_BIGGER,
estade32426e02016-12-18 01:26:17295 false); // Not grayscale.
[email protected]bb2feea2014-03-18 22:08:13296 dict->SetString("icon", icon.spec());
297
dcheng1fc00f12015-12-26 22:18:03298 return dict;
[email protected]bb2feea2014-03-18 22:08:13299}
300
[email protected]7eb20e32014-04-30 08:50:56301const gfx::ImageSkia& GetDefaultAppIcon() {
Lei Zhang7640d542017-10-03 16:26:49302 return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
[email protected]7eb20e32014-04-30 08:50:56303 IDR_APP_DEFAULT_ICON);
304}
305
306const gfx::ImageSkia& GetDefaultExtensionIcon() {
Lei Zhang7640d542017-10-03 16:26:49307 return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
[email protected]7eb20e32014-04-30 08:50:56308 IDR_EXTENSION_DEFAULT_ICON);
309}
310
benwellsc431c0ae2015-01-27 22:04:06311bool IsNewBookmarkAppsEnabled() {
dominicknfa0e3df2016-01-14 05:38:32312#if defined(OS_MACOSX)
benwellsc421ccdb2017-06-28 05:10:32313 return base::FeatureList::IsEnabled(features::kBookmarkApps) ||
benwells0eee2292017-06-28 08:41:22314 base::FeatureList::IsEnabled(features::kAppBanners) ||
Matt Giucad4870432017-11-24 01:04:38315 banners::AppBannerManager::IsExperimentalAppBannersEnabled();
dominicknfa0e3df2016-01-14 05:38:32316#else
tapted70cdc812017-03-23 20:48:19317 return true;
dominicknfa0e3df2016-01-14 05:38:32318#endif
benwells39f23ae2014-08-27 08:01:52319}
320
dominickn2b10cbd2015-08-20 02:09:18321bool CanHostedAppsOpenInWindows() {
322#if defined(OS_MACOSX)
323 return base::CommandLine::ForCurrentProcess()->HasSwitch(
Oscar Johansson50a3c7c72018-07-06 16:59:00324 ::switches::kEnableHostedAppsInWindows) ||
Giovanni Ortuño Urquidi45020e232017-07-12 06:10:17325 base::FeatureList::IsEnabled(features::kDesktopPWAWindowing);
dominickn2b10cbd2015-08-20 02:09:18326#else
327 return true;
328#endif
329}
330
mamir192d7882016-06-22 17:10:16331bool IsExtensionSupervised(const Extension* extension, Profile* profile) {
332 return WasInstalledByCustodian(extension->id(), profile) &&
333 profile->IsSupervised();
treibbb9a1962015-02-25 13:40:59334}
335
Alan Cutter70927ec92018-03-22 00:58:49336const Extension* GetInstalledPwaForUrl(
337 content::BrowserContext* context,
338 const GURL& url,
339 base::Optional<LaunchContainer> launch_container_filter) {
Oscar Johansson7f4c1b932018-06-12 06:11:58340 DCHECK(base::FeatureList::IsEnabled(::features::kDesktopPWAWindowing));
Alan Cutter70927ec92018-03-22 00:58:49341 const ExtensionPrefs* prefs = ExtensionPrefs::Get(context);
342 for (scoped_refptr<const Extension> app :
343 ExtensionRegistry::Get(context)->enabled_extensions()) {
344 if (!app->from_bookmark())
345 continue;
Ben Wellse13d31692018-08-31 00:22:33346 if (!BookmarkAppIsLocallyInstalled(prefs, app.get()))
347 continue;
Alan Cutter70927ec92018-03-22 00:58:49348 if (launch_container_filter &&
349 GetLaunchContainer(prefs, app.get()) != *launch_container_filter) {
350 continue;
351 }
Giovanni Ortuño Urquidic1c7c2512018-07-13 03:54:30352 if (UrlHandlers::CanBookmarkAppHandleUrl(app.get(), url))
Alan Cutter70927ec92018-03-22 00:58:49353 return app.get();
354 }
355 return nullptr;
356}
357
Alan Cutter09965802018-03-27 07:25:29358const Extension* GetPwaForSecureActiveTab(Browser* browser) {
359 switch (browser->toolbar_model()->GetSecurityLevel(true)) {
360 case security_state::SECURITY_LEVEL_COUNT:
361 NOTREACHED();
362 FALLTHROUGH;
363 case security_state::NONE:
364 case security_state::HTTP_SHOW_WARNING:
365 case security_state::DANGEROUS:
366 return nullptr;
367 case security_state::EV_SECURE:
368 case security_state::SECURE:
369 case security_state::SECURE_WITH_POLICY_INSTALLED_CERT:
370 break;
371 }
372 content::WebContents* web_contents =
373 browser->tab_strip_model()->GetActiveWebContents();
374 return GetInstalledPwaForUrl(
375 web_contents->GetBrowserContext(),
376 web_contents->GetMainFrame()->GetLastCommittedURL());
377}
378
[email protected]1d5cf4142014-01-24 18:25:22379} // namespace util
380} // namespace extensions