blob: 4e17a7ced8d1135e4e282c62fb270475efc0148f [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"
[email protected]a7ff4b72013-10-17 20:56:0215#include "chrome/browser/extensions/extension_service.h"
[email protected]f8aefb132013-10-30 09:29:5216#include "chrome/browser/extensions/extension_sync_service.h"
[email protected]23a85362014-07-07 23:26:1917#include "chrome/browser/extensions/permissions_updater.h"
rdevlin.cronincb9f86e2015-10-15 15:13:4218#include "chrome/browser/extensions/scripting_permissions_modifier.h"
elijahtaylor0def4432014-10-06 18:15:1119#include "chrome/browser/extensions/shared_module_service.h"
[email protected]1d5cf4142014-01-24 18:25:2220#include "chrome/browser/profiles/profile.h"
[email protected]bb2feea2014-03-18 22:08:1321#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
tapted70cdc812017-03-23 20:48:1922#include "chrome/common/chrome_features.h"
[email protected]a7ff4b72013-10-17 20:56:0223#include "chrome/common/chrome_switches.h"
[email protected]a7ff4b72013-10-17 20:56:0224#include "chrome/common/extensions/sync_helper.h"
treibb6af28cd2015-12-01 11:19:4625#include "components/variations/variations_associated_data.h"
[email protected]617342a42013-12-18 23:34:0326#include "content/public/browser/site_instance.h"
[email protected]489db0842014-01-22 18:20:0327#include "extensions/browser/extension_prefs.h"
[email protected]599539802014-01-07 23:06:0028#include "extensions/browser/extension_registry.h"
[email protected]59b0e602014-01-30 00:41:2429#include "extensions/browser/extension_system.h"
[email protected]30e190f82014-05-26 16:44:3930#include "extensions/browser/extension_util.h"
[email protected]e4452d32013-11-15 23:07:4131#include "extensions/common/extension.h"
[email protected]4b7908842014-04-07 23:50:2232#include "extensions/common/extension_icon_set.h"
[email protected]a7ff4b72013-10-17 20:56:0233#include "extensions/common/manifest.h"
tfarina0bcdf362015-06-29 22:19:2634#include "extensions/common/manifest_handlers/app_isolation_info.h"
[email protected]1f7de252013-11-06 22:02:0035#include "extensions/common/manifest_handlers/incognito_info.h"
[email protected]4d67e9d2014-08-18 22:03:5436#include "extensions/common/permissions/permissions_data.h"
mukai4245dfe82014-09-05 17:40:5137#include "extensions/grit/extensions_browser_resources.h"
[email protected]7eb20e32014-04-30 08:50:5638#include "ui/base/resource/resource_bundle.h"
Michael Giuffrida7efeed142017-06-07 06:29:2139#include "url/gurl.h"
[email protected]a7ff4b72013-10-17 20:56:0240
treib13251192016-06-29 07:13:1541#if defined(OS_CHROMEOS)
42#include "chrome/browser/chromeos/file_manager/app_id.h"
43#endif
44
[email protected]1d5cf4142014-01-24 18:25:2245namespace extensions {
46namespace util {
[email protected]a7ff4b72013-10-17 20:56:0247
[email protected]b33c8c22014-05-29 19:51:0848namespace {
mamir192d7882016-06-22 17:10:1649// The entry into the prefs used to flag an extension as installed by custodian.
50// It is relevant only for supervised users.
51const char kWasInstalledByCustodianPrefName[] = "was_installed_by_custodian";
52
thestig7b4bd932014-09-09 22:44:3153// 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:0275void SetIsIncognitoEnabled(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:2276 content::BrowserContext* context,
[email protected]a7ff4b72013-10-17 20:56:0277 bool enabled) {
thestig7b4bd932014-09-09 22:44:3178 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
79 const Extension* extension =
80 registry->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
[email protected]a7ff4b72013-10-17 20:56:0281
[email protected]1d5cf4142014-01-24 18:25:2282 if (extension) {
kundajie548e7442015-09-18 23:19:0983 if (!util::CanBeIncognitoEnabled(extension))
[email protected]1d5cf4142014-01-24 18:25:2284 return;
85
treibc644a1c2015-07-13 08:37:0486 // TODO(treib,kalman): Should this be Manifest::IsComponentLocation(..)?
87 // (which also checks for EXTERNAL_COMPONENT).
[email protected]1d5cf4142014-01-24 18:25:2288 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.
treib13251192016-06-29 07:13:1592 bool syncable = sync_helper::IsSyncableComponentExtension(extension);
93#if defined(OS_CHROMEOS)
94 // For some users, the file manager app somehow ended up being synced even
95 // though it's supposed to be unsyncable; see crbug.com/576964. If the bad
96 // data ever gets cleaned up, this hack should be removed.
97 syncable = syncable || extension->id() == file_manager::kFileManagerAppId;
98#endif
99 DCHECK(syncable);
[email protected]1d5cf4142014-01-24 18:25:22100
101 // If we are here, make sure the we aren't trying to change the value.
thestig7b4bd932014-09-09 22:44:31102 DCHECK_EQ(enabled, IsIncognitoEnabled(extension_id, context));
[email protected]1d5cf4142014-01-24 18:25:22103 return;
104 }
[email protected]a7ff4b72013-10-17 20:56:02105 }
106
thestig7b4bd932014-09-09 22:44:31107 ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(context);
[email protected]a7ff4b72013-10-17 20:56:02108 // Broadcast unloaded and loaded events to update browser state. Only bother
109 // if the value changed and the extension is actually enabled, since there is
110 // no UI otherwise.
111 bool old_enabled = extension_prefs->IsIncognitoEnabled(extension_id);
112 if (enabled == old_enabled)
113 return;
114
115 extension_prefs->SetIsIncognitoEnabled(extension_id, enabled);
116
thestig7b4bd932014-09-09 22:44:31117 std::string id = ReloadExtensionIfEnabled(extension_id, context);
[email protected]a7ff4b72013-10-17 20:56:02118
119 // Reloading the extension invalidates the |extension| pointer.
thestig7b4bd932014-09-09 22:44:31120 extension = registry->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
[email protected]f8aefb132013-10-30 09:29:52121 if (extension) {
thestig7b4bd932014-09-09 22:44:31122 Profile* profile = Profile::FromBrowserContext(context);
123 ExtensionSyncService::Get(profile)->SyncExtensionChangeIfNeeded(*extension);
[email protected]f8aefb132013-10-30 09:29:52124 }
[email protected]a7ff4b72013-10-17 20:56:02125}
126
127bool CanCrossIncognito(const Extension* extension,
[email protected]1d5cf4142014-01-24 18:25:22128 content::BrowserContext* context) {
[email protected]a7ff4b72013-10-17 20:56:02129 // We allow the extension to see events and data from another profile iff it
130 // uses "spanning" behavior and it has incognito access. "split" mode
131 // extensions only see events for a matching profile.
132 CHECK(extension);
[email protected]1d5cf4142014-01-24 18:25:22133 return IsIncognitoEnabled(extension->id(), context) &&
134 !IncognitoInfo::IsSplitMode(extension);
[email protected]a7ff4b72013-10-17 20:56:02135}
136
137bool CanLoadInIncognito(const Extension* extension,
[email protected]1d5cf4142014-01-24 18:25:22138 content::BrowserContext* context) {
139 CHECK(extension);
[email protected]a7ff4b72013-10-17 20:56:02140 if (extension->is_hosted_app())
141 return true;
142 // Packaged apps and regular extensions need to be enabled specifically for
143 // incognito (and split mode should be set).
[email protected]1d5cf4142014-01-24 18:25:22144 return IncognitoInfo::IsSplitMode(extension) &&
145 IsIncognitoEnabled(extension->id(), context);
[email protected]a7ff4b72013-10-17 20:56:02146}
147
[email protected]1d5cf4142014-01-24 18:25:22148bool AllowFileAccess(const std::string& extension_id,
149 content::BrowserContext* context) {
avi3ef9ec9e2014-12-22 22:50:17150 return base::CommandLine::ForCurrentProcess()->HasSwitch(
[email protected]1d5cf4142014-01-24 18:25:22151 switches::kDisableExtensionsFileAccessCheck) ||
152 ExtensionPrefs::Get(context)->AllowFileAccess(extension_id);
[email protected]a7ff4b72013-10-17 20:56:02153}
154
[email protected]1d5cf4142014-01-24 18:25:22155void SetAllowFileAccess(const std::string& extension_id,
156 content::BrowserContext* context,
[email protected]a7ff4b72013-10-17 20:56:02157 bool allow) {
158 // Reload to update browser state. Only bother if the value changed and the
159 // extension is actually enabled, since there is no UI otherwise.
[email protected]1d5cf4142014-01-24 18:25:22160 if (allow == AllowFileAccess(extension_id, context))
[email protected]a7ff4b72013-10-17 20:56:02161 return;
162
[email protected]7c82539c2014-02-19 06:09:17163 ExtensionPrefs::Get(context)->SetAllowFileAccess(extension_id, allow);
[email protected]a7ff4b72013-10-17 20:56:02164
thestig7b4bd932014-09-09 22:44:31165 ReloadExtensionIfEnabled(extension_id, context);
[email protected]a7ff4b72013-10-17 20:56:02166}
167
mamir192d7882016-06-22 17:10:16168void SetWasInstalledByCustodian(const std::string& extension_id,
169 content::BrowserContext* context,
170 bool installed_by_custodian) {
171 if (installed_by_custodian == WasInstalledByCustodian(extension_id, context))
172 return;
173
174 ExtensionPrefs::Get(context)->UpdateExtensionPref(
175 extension_id, kWasInstalledByCustodianPrefName,
vabrfb687dc2017-03-22 11:40:57176 installed_by_custodian ? base::MakeUnique<base::Value>(true) : nullptr);
mamir192d7882016-06-22 17:10:16177 ExtensionService* service =
178 ExtensionSystem::Get(context)->extension_service();
179
mamir192d7882016-06-22 17:10:16180 if (!installed_by_custodian) {
181 // If installed_by_custodian changes to false, the extension may need to
182 // be unloaded now.
183 service->ReloadExtension(extension_id);
184 return;
185 }
186
mamire9609642016-06-28 22:17:54187 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
mamir192d7882016-06-22 17:10:16188 // If it is already enabled, do nothing.
189 if (registry->enabled_extensions().Contains(extension_id))
190 return;
191
192 // If the extension is not loaded, it may need to be reloaded.
193 // Example is a pre-installed extension that was unloaded when a
194 // supervised user flag has been received.
mamire9609642016-06-28 22:17:54195 if (!registry->GetInstalledExtension(extension_id)) {
mamir192d7882016-06-22 17:10:16196 service->ReloadExtension(extension_id);
197 }
198}
199
200bool WasInstalledByCustodian(const std::string& extension_id,
201 content::BrowserContext* context) {
202 bool installed_by_custodian = false;
203 ExtensionPrefs* prefs = ExtensionPrefs::Get(context);
204 prefs->ReadPrefAsBoolean(extension_id, kWasInstalledByCustodianPrefName,
205 &installed_by_custodian);
206 return installed_by_custodian;
207}
208
[email protected]f5ea0962013-11-22 09:20:47209bool IsAppLaunchable(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:22210 content::BrowserContext* context) {
[email protected]47e19402014-06-27 09:01:14211 int reason = ExtensionPrefs::Get(context)->GetDisableReasons(extension_id);
Minh X. Nguyen45479012017-08-18 21:35:36212 return !((reason & disable_reason::DISABLE_UNSUPPORTED_REQUIREMENT) ||
213 (reason & disable_reason::DISABLE_CORRUPTED));
[email protected]f5ea0962013-11-22 09:20:47214}
215
216bool IsAppLaunchableWithoutEnabling(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:22217 content::BrowserContext* context) {
218 return ExtensionRegistry::Get(context)->GetExtensionById(
219 extension_id, ExtensionRegistry::ENABLED) != NULL;
[email protected]f5ea0962013-11-22 09:20:47220}
221
treibc644a1c2015-07-13 08:37:04222bool ShouldSync(const Extension* extension,
223 content::BrowserContext* context) {
224 return sync_helper::IsSyncable(extension) &&
[email protected]658eae52014-06-14 20:28:05225 !ExtensionPrefs::Get(context)->DoNotSync(extension->id());
226}
227
[email protected]617342a42013-12-18 23:34:03228bool IsExtensionIdle(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:22229 content::BrowserContext* context) {
elijahtaylor0def4432014-10-06 18:15:11230 std::vector<std::string> ids_to_check;
231 ids_to_check.push_back(extension_id);
[email protected]617342a42013-12-18 23:34:03232
elijahtaylor0def4432014-10-06 18:15:11233 const Extension* extension =
234 ExtensionRegistry::Get(context)
235 ->GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
236 if (extension && extension->is_shared_module()) {
237 // We have to check all the extensions that use this shared module for idle
238 // to tell whether it is really 'idle'.
239 SharedModuleService* service = ExtensionSystem::Get(context)
240 ->extension_service()
241 ->shared_module_service();
dchengc963c7142016-04-08 03:55:22242 std::unique_ptr<ExtensionSet> dependents =
elijahtaylor0def4432014-10-06 18:15:11243 service->GetDependentExtensions(extension);
244 for (ExtensionSet::const_iterator i = dependents->begin();
245 i != dependents->end();
246 i++) {
247 ids_to_check.push_back((*i)->id());
248 }
249 }
250
reillyg0ea3fa902014-10-28 15:30:23251 ProcessManager* process_manager = ProcessManager::Get(context);
elijahtaylor0def4432014-10-06 18:15:11252 for (std::vector<std::string>::const_iterator i = ids_to_check.begin();
253 i != ids_to_check.end();
254 i++) {
255 const std::string id = (*i);
256 ExtensionHost* host = process_manager->GetBackgroundHostForExtension(id);
257 if (host)
258 return false;
259
rdevlin.cronin3d4261522015-02-10 00:48:15260 scoped_refptr<content::SiteInstance> site_instance =
elijahtaylor0def4432014-10-06 18:15:11261 process_manager->GetSiteInstanceForURL(
262 Extension::GetBaseURLFromExtensionId(id));
263 if (site_instance && site_instance->HasProcess())
264 return false;
265
rdevlin.cronin6ae04a012015-04-03 20:19:40266 if (!process_manager->GetRenderFrameHostsForExtension(id).empty())
elijahtaylor0def4432014-10-06 18:15:11267 return false;
268 }
269 return true;
[email protected]617342a42013-12-18 23:34:03270}
271
dchengc963c7142016-04-08 03:55:22272std::unique_ptr<base::DictionaryValue> GetExtensionInfo(
273 const Extension* extension) {
[email protected]bb2feea2014-03-18 22:08:13274 DCHECK(extension);
dchengc963c7142016-04-08 03:55:22275 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
[email protected]bb2feea2014-03-18 22:08:13276
277 dict->SetString("id", extension->id());
278 dict->SetString("name", extension->name());
279
280 GURL icon = extensions::ExtensionIconSource::GetIconURL(
estade32426e02016-12-18 01:26:17281 extension, extension_misc::EXTENSION_ICON_SMALLISH,
[email protected]bb2feea2014-03-18 22:08:13282 ExtensionIconSet::MATCH_BIGGER,
estade32426e02016-12-18 01:26:17283 false); // Not grayscale.
[email protected]bb2feea2014-03-18 22:08:13284 dict->SetString("icon", icon.spec());
285
dcheng1fc00f12015-12-26 22:18:03286 return dict;
[email protected]bb2feea2014-03-18 22:08:13287}
288
[email protected]7eb20e32014-04-30 08:50:56289const gfx::ImageSkia& GetDefaultAppIcon() {
290 return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
291 IDR_APP_DEFAULT_ICON);
292}
293
294const gfx::ImageSkia& GetDefaultExtensionIcon() {
295 return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
296 IDR_EXTENSION_DEFAULT_ICON);
297}
298
benwellsc431c0ae2015-01-27 22:04:06299bool IsNewBookmarkAppsEnabled() {
dominicknfa0e3df2016-01-14 05:38:32300#if defined(OS_MACOSX)
benwellsc421ccdb2017-06-28 05:10:32301 return base::FeatureList::IsEnabled(features::kBookmarkApps) ||
benwells0eee2292017-06-28 08:41:22302 base::FeatureList::IsEnabled(features::kAppBanners) ||
303 base::FeatureList::IsEnabled(features::kExperimentalAppBanners);
dominicknfa0e3df2016-01-14 05:38:32304#else
tapted70cdc812017-03-23 20:48:19305 return true;
dominicknfa0e3df2016-01-14 05:38:32306#endif
benwells39f23ae2014-08-27 08:01:52307}
308
dominickn2b10cbd2015-08-20 02:09:18309bool CanHostedAppsOpenInWindows() {
310#if defined(OS_MACOSX)
311 return base::CommandLine::ForCurrentProcess()->HasSwitch(
Giovanni Ortuño Urquidi45020e232017-07-12 06:10:17312 switches::kEnableHostedAppsInWindows) ||
313 base::FeatureList::IsEnabled(features::kDesktopPWAWindowing);
dominickn2b10cbd2015-08-20 02:09:18314#else
315 return true;
316#endif
317}
318
mamir192d7882016-06-22 17:10:16319bool IsExtensionSupervised(const Extension* extension, Profile* profile) {
320 return WasInstalledByCustodian(extension->id(), profile) &&
321 profile->IsSupervised();
treibbb9a1962015-02-25 13:40:59322}
323
[email protected]1d5cf4142014-01-24 18:25:22324} // namespace util
325} // namespace extensions