blob: 204c3508fc67714b57e262c4f1fd4e658697ada4 [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
Hans Wennborg1790e6b2020-04-24 19:10:339#include "base/check_op.h"
[email protected]a7ff4b72013-10-17 20:56:0210#include "base/command_line.h"
tapted70cdc812017-03-23 20:48:1911#include "base/feature_list.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"
Yuta Hijikata1290fee22020-11-25 09:46:2815#include "build/chromeos_buildflags.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"
[email protected]a7ff4b72013-10-17 20:56:0226#include "chrome/common/chrome_switches.h"
Alan Cutter70927ec92018-03-22 00:58:4927#include "chrome/common/extensions/api/url_handlers/url_handlers_parser.h"
[email protected]a7ff4b72013-10-17 20:56:0228#include "chrome/common/extensions/sync_helper.h"
treibb6af28cd2015-12-01 11:19:4629#include "components/variations/variations_associated_data.h"
Evan Stade89158192021-01-27 18:45:2330#include "components/webapps/browser/banners/app_banner_manager.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"
Swapnilf6f2f1d2021-01-14 18:50:4339#include "extensions/common/extension_urls.h"
[email protected]a7ff4b72013-10-17 20:56:0240#include "extensions/common/manifest.h"
tfarina0bcdf362015-06-29 22:19:2641#include "extensions/common/manifest_handlers/app_isolation_info.h"
[email protected]1f7de252013-11-06 22:02:0042#include "extensions/common/manifest_handlers/incognito_info.h"
Danan S5f430882020-01-14 04:52:5543#include "extensions/common/manifest_handlers/permissions_parser.h"
[email protected]4d67e9d2014-08-18 22:03:5444#include "extensions/common/permissions/permissions_data.h"
mukai4245dfe82014-09-05 17:40:5145#include "extensions/grit/extensions_browser_resources.h"
[email protected]7eb20e32014-04-30 08:50:5646#include "ui/base/resource/resource_bundle.h"
Michael Giuffrida7efeed142017-06-07 06:29:2147#include "url/gurl.h"
[email protected]a7ff4b72013-10-17 20:56:0248
Yuta Hijikata1290fee22020-11-25 09:46:2849#if BUILDFLAG(IS_CHROMEOS_ASH)
Yeunjoo Choie409e8e2021-07-06 11:09:3950#include "chrome/browser/ash/file_manager/app_id.h"
Yeunjoo Choi15ab1ac2021-02-04 17:15:0751#include "chrome/browser/ash/profiles/profile_helper.h"
treib13251192016-06-29 07:13:1552#endif
53
[email protected]1d5cf4142014-01-24 18:25:2254namespace extensions {
55namespace util {
[email protected]a7ff4b72013-10-17 20:56:0256
[email protected]b33c8c22014-05-29 19:51:0857namespace {
thestig7b4bd932014-09-09 22:44:3158// Returns |extension_id|. See note below.
59std::string ReloadExtensionIfEnabled(const std::string& extension_id,
60 content::BrowserContext* context) {
61 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
62 bool extension_is_enabled =
63 registry->enabled_extensions().Contains(extension_id);
64
65 if (!extension_is_enabled)
66 return extension_id;
67
68 // When we reload the extension the ID may be invalidated if we've passed it
69 // by const ref everywhere. Make a copy to be safe. http://crbug.com/103762
70 std::string id = extension_id;
71 ExtensionService* service =
72 ExtensionSystem::Get(context)->extension_service();
73 CHECK(service);
74 service->ReloadExtension(id);
75 return id;
76}
77
[email protected]277c4142014-06-19 20:08:5478} // namespace
[email protected]b33c8c22014-05-29 19:51:0879
Aaron Colwell8c430642020-08-04 01:55:2080bool HasIsolatedStorage(const std::string& extension_id,
81 content::BrowserContext* context) {
82 const Extension* extension =
83 ExtensionRegistry::Get(context)->enabled_extensions().GetByID(
84 extension_id);
Pavol Marko41c37b12019-08-07 10:56:3285
Yuta Hijikata1290fee22020-11-25 09:46:2886#if BUILDFLAG(IS_CHROMEOS_ASH)
Pavol Marko41c37b12019-08-07 10:56:3287 const bool is_policy_extension =
88 extension && Manifest::IsPolicyLocation(extension->location());
89 Profile* profile = Profile::FromBrowserContext(context);
Yeunjoo Choi36f21d542022-01-13 03:12:3390 if (profile && ash::ProfileHelper::IsSigninProfile(profile) &&
Pavol Marko41c37b12019-08-07 10:56:3291 is_policy_extension) {
92 return true;
93 }
94#endif
95
96 return extension && AppIsolationInfo::HasIsolatedStorage(extension);
97}
98
[email protected]a7ff4b72013-10-17 20:56:0299void SetIsIncognitoEnabled(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:22100 content::BrowserContext* context,
[email protected]a7ff4b72013-10-17 20:56:02101 bool enabled) {
thestig7b4bd932014-09-09 22:44:31102 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
103 const Extension* extension =
104 registry->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
[email protected]a7ff4b72013-10-17 20:56:02105
[email protected]1d5cf4142014-01-24 18:25:22106 if (extension) {
kundajie548e7442015-09-18 23:19:09107 if (!util::CanBeIncognitoEnabled(extension))
[email protected]1d5cf4142014-01-24 18:25:22108 return;
109
treibc644a1c2015-07-13 08:37:04110 // TODO(treib,kalman): Should this be Manifest::IsComponentLocation(..)?
Gyuyoung Kim5626c752021-03-18 22:58:11111 // (which also checks for kExternalComponent).
112 if (extension->location() == mojom::ManifestLocation::kComponent) {
[email protected]1d5cf4142014-01-24 18:25:22113 // This shouldn't be called for component extensions unless it is called
114 // by sync, for syncable component extensions.
115 // See http://crbug.com/112290 and associated CLs for the sordid history.
treib13251192016-06-29 07:13:15116 bool syncable = sync_helper::IsSyncableComponentExtension(extension);
Yuta Hijikata1290fee22020-11-25 09:46:28117#if BUILDFLAG(IS_CHROMEOS_ASH)
treib13251192016-06-29 07:13:15118 // For some users, the file manager app somehow ended up being synced even
119 // though it's supposed to be unsyncable; see crbug.com/576964. If the bad
120 // data ever gets cleaned up, this hack should be removed.
121 syncable = syncable || extension->id() == file_manager::kFileManagerAppId;
122#endif
123 DCHECK(syncable);
[email protected]1d5cf4142014-01-24 18:25:22124
125 // If we are here, make sure the we aren't trying to change the value.
thestig7b4bd932014-09-09 22:44:31126 DCHECK_EQ(enabled, IsIncognitoEnabled(extension_id, context));
[email protected]1d5cf4142014-01-24 18:25:22127 return;
128 }
[email protected]a7ff4b72013-10-17 20:56:02129 }
130
thestig7b4bd932014-09-09 22:44:31131 ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(context);
[email protected]a7ff4b72013-10-17 20:56:02132 // Broadcast unloaded and loaded events to update browser state. Only bother
133 // if the value changed and the extension is actually enabled, since there is
134 // no UI otherwise.
135 bool old_enabled = extension_prefs->IsIncognitoEnabled(extension_id);
136 if (enabled == old_enabled)
137 return;
138
139 extension_prefs->SetIsIncognitoEnabled(extension_id, enabled);
140
thestig7b4bd932014-09-09 22:44:31141 std::string id = ReloadExtensionIfEnabled(extension_id, context);
[email protected]a7ff4b72013-10-17 20:56:02142
143 // Reloading the extension invalidates the |extension| pointer.
thestig7b4bd932014-09-09 22:44:31144 extension = registry->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
[email protected]f8aefb132013-10-30 09:29:52145 if (extension) {
thestig7b4bd932014-09-09 22:44:31146 Profile* profile = Profile::FromBrowserContext(context);
147 ExtensionSyncService::Get(profile)->SyncExtensionChangeIfNeeded(*extension);
[email protected]f8aefb132013-10-30 09:29:52148 }
[email protected]a7ff4b72013-10-17 20:56:02149}
150
[email protected]a7ff4b72013-10-17 20:56:02151bool CanLoadInIncognito(const Extension* extension,
[email protected]1d5cf4142014-01-24 18:25:22152 content::BrowserContext* context) {
153 CHECK(extension);
[email protected]a7ff4b72013-10-17 20:56:02154 if (extension->is_hosted_app())
155 return true;
156 // Packaged apps and regular extensions need to be enabled specifically for
157 // incognito (and split mode should be set).
[email protected]1d5cf4142014-01-24 18:25:22158 return IncognitoInfo::IsSplitMode(extension) &&
159 IsIncognitoEnabled(extension->id(), context);
[email protected]a7ff4b72013-10-17 20:56:02160}
161
[email protected]1d5cf4142014-01-24 18:25:22162bool AllowFileAccess(const std::string& extension_id,
163 content::BrowserContext* context) {
avi3ef9ec9e2014-12-22 22:50:17164 return base::CommandLine::ForCurrentProcess()->HasSwitch(
Oscar Johansson7f4c1b932018-06-12 06:11:58165 ::switches::kDisableExtensionsFileAccessCheck) ||
[email protected]1d5cf4142014-01-24 18:25:22166 ExtensionPrefs::Get(context)->AllowFileAccess(extension_id);
[email protected]a7ff4b72013-10-17 20:56:02167}
168
[email protected]1d5cf4142014-01-24 18:25:22169void SetAllowFileAccess(const std::string& extension_id,
170 content::BrowserContext* context,
[email protected]a7ff4b72013-10-17 20:56:02171 bool allow) {
172 // Reload to update browser state. Only bother if the value changed and the
173 // extension is actually enabled, since there is no UI otherwise.
[email protected]1d5cf4142014-01-24 18:25:22174 if (allow == AllowFileAccess(extension_id, context))
[email protected]a7ff4b72013-10-17 20:56:02175 return;
176
[email protected]7c82539c2014-02-19 06:09:17177 ExtensionPrefs::Get(context)->SetAllowFileAccess(extension_id, allow);
[email protected]a7ff4b72013-10-17 20:56:02178
thestig7b4bd932014-09-09 22:44:31179 ReloadExtensionIfEnabled(extension_id, context);
[email protected]a7ff4b72013-10-17 20:56:02180}
181
[email protected]f5ea0962013-11-22 09:20:47182bool IsAppLaunchable(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:22183 content::BrowserContext* context) {
[email protected]47e19402014-06-27 09:01:14184 int reason = ExtensionPrefs::Get(context)->GetDisableReasons(extension_id);
Minh X. Nguyen45479012017-08-18 21:35:36185 return !((reason & disable_reason::DISABLE_UNSUPPORTED_REQUIREMENT) ||
186 (reason & disable_reason::DISABLE_CORRUPTED));
[email protected]f5ea0962013-11-22 09:20:47187}
188
189bool IsAppLaunchableWithoutEnabling(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:22190 content::BrowserContext* context) {
191 return ExtensionRegistry::Get(context)->GetExtensionById(
192 extension_id, ExtensionRegistry::ENABLED) != NULL;
[email protected]f5ea0962013-11-22 09:20:47193}
194
treibc644a1c2015-07-13 08:37:04195bool ShouldSync(const Extension* extension,
196 content::BrowserContext* context) {
Swapnilf6f2f1d2021-01-14 18:50:43197 ExtensionManagement* extension_management =
198 ExtensionManagementFactory::GetForBrowserContext(context);
199 // Update URL is overridden only for non webstore extensions and offstore
200 // extensions should not be synced.
201 if (extension_management->IsUpdateUrlOverridden(extension->id())) {
202 const GURL update_url =
203 extension_management->GetEffectiveUpdateURL(*extension);
204 DCHECK(!extension_urls::IsWebstoreUpdateUrl(update_url))
205 << "Update URL cannot be overridden to be the webstore URL!";
206 return false;
207 }
treibc644a1c2015-07-13 08:37:04208 return sync_helper::IsSyncable(extension) &&
[email protected]658eae52014-06-14 20:28:05209 !ExtensionPrefs::Get(context)->DoNotSync(extension->id());
210}
211
[email protected]617342a42013-12-18 23:34:03212bool IsExtensionIdle(const std::string& extension_id,
[email protected]1d5cf4142014-01-24 18:25:22213 content::BrowserContext* context) {
elijahtaylor0def4432014-10-06 18:15:11214 std::vector<std::string> ids_to_check;
215 ids_to_check.push_back(extension_id);
[email protected]617342a42013-12-18 23:34:03216
elijahtaylor0def4432014-10-06 18:15:11217 const Extension* extension =
218 ExtensionRegistry::Get(context)
219 ->GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
220 if (extension && extension->is_shared_module()) {
221 // We have to check all the extensions that use this shared module for idle
222 // to tell whether it is really 'idle'.
223 SharedModuleService* service = ExtensionSystem::Get(context)
224 ->extension_service()
225 ->shared_module_service();
dchengc963c7142016-04-08 03:55:22226 std::unique_ptr<ExtensionSet> dependents =
elijahtaylor0def4432014-10-06 18:15:11227 service->GetDependentExtensions(extension);
228 for (ExtensionSet::const_iterator i = dependents->begin();
229 i != dependents->end();
230 i++) {
231 ids_to_check.push_back((*i)->id());
232 }
233 }
234
reillyg0ea3fa902014-10-28 15:30:23235 ProcessManager* process_manager = ProcessManager::Get(context);
elijahtaylor0def4432014-10-06 18:15:11236 for (std::vector<std::string>::const_iterator i = ids_to_check.begin();
237 i != ids_to_check.end();
238 i++) {
239 const std::string id = (*i);
240 ExtensionHost* host = process_manager->GetBackgroundHostForExtension(id);
241 if (host)
242 return false;
243
rdevlin.cronin3d4261522015-02-10 00:48:15244 scoped_refptr<content::SiteInstance> site_instance =
elijahtaylor0def4432014-10-06 18:15:11245 process_manager->GetSiteInstanceForURL(
246 Extension::GetBaseURLFromExtensionId(id));
247 if (site_instance && site_instance->HasProcess())
248 return false;
249
rdevlin.cronin6ae04a012015-04-03 20:19:40250 if (!process_manager->GetRenderFrameHostsForExtension(id).empty())
elijahtaylor0def4432014-10-06 18:15:11251 return false;
252 }
253 return true;
[email protected]617342a42013-12-18 23:34:03254}
255
dchengc963c7142016-04-08 03:55:22256std::unique_ptr<base::DictionaryValue> GetExtensionInfo(
257 const Extension* extension) {
[email protected]bb2feea2014-03-18 22:08:13258 DCHECK(extension);
dchengc963c7142016-04-08 03:55:22259 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
[email protected]bb2feea2014-03-18 22:08:13260
261 dict->SetString("id", extension->id());
262 dict->SetString("name", extension->name());
263
264 GURL icon = extensions::ExtensionIconSource::GetIconURL(
estade32426e02016-12-18 01:26:17265 extension, extension_misc::EXTENSION_ICON_SMALLISH,
[email protected]bb2feea2014-03-18 22:08:13266 ExtensionIconSet::MATCH_BIGGER,
estade32426e02016-12-18 01:26:17267 false); // Not grayscale.
[email protected]bb2feea2014-03-18 22:08:13268 dict->SetString("icon", icon.spec());
269
dcheng1fc00f12015-12-26 22:18:03270 return dict;
[email protected]bb2feea2014-03-18 22:08:13271}
272
[email protected]7eb20e32014-04-30 08:50:56273const gfx::ImageSkia& GetDefaultAppIcon() {
Lei Zhang7640d542017-10-03 16:26:49274 return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
[email protected]7eb20e32014-04-30 08:50:56275 IDR_APP_DEFAULT_ICON);
276}
277
278const gfx::ImageSkia& GetDefaultExtensionIcon() {
Lei Zhang7640d542017-10-03 16:26:49279 return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
[email protected]7eb20e32014-04-30 08:50:56280 IDR_EXTENSION_DEFAULT_ICON);
281}
282
Danan S5f430882020-01-14 04:52:55283std::unique_ptr<const PermissionSet> GetInstallPromptPermissionSetForExtension(
284 const Extension* extension,
285 Profile* profile,
286 bool include_optional_permissions) {
287 // Initialize permissions if they have not already been set so that
288 // any transformations are correctly reflected in the install prompt.
289 PermissionsUpdater(profile, PermissionsUpdater::INIT_FLAG_TRANSIENT)
290 .InitializePermissions(extension);
291
292 std::unique_ptr<const PermissionSet> permissions_to_display =
293 extension->permissions_data()->active_permissions().Clone();
294
295 if (include_optional_permissions) {
296 const PermissionSet& optional_permissions =
297 PermissionsParser::GetOptionalPermissions(extension);
298 permissions_to_display = PermissionSet::CreateUnion(*permissions_to_display,
299 optional_permissions);
300 }
301 return permissions_to_display;
302}
303
Lukasz Anforowicz507151f2021-05-04 20:27:03304std::vector<content::BrowserContext*> GetAllRelatedProfiles(
305 Profile* profile,
306 const Extension& extension) {
Lukasz Anforowicz223d2532021-03-09 17:04:07307 std::vector<content::BrowserContext*> related_contexts;
Lukasz Anforowicz223d2532021-03-09 17:04:07308 related_contexts.push_back(profile->GetOriginalProfile());
Lukasz Anforowicz507151f2021-05-04 20:27:03309
310 // The returned `related_contexts` should include all the related incognito
311 // profiles if the extension is globally allowed in incognito (this is a
312 // global, rather than per-profile toggle - this is why we it can be checked
313 // globally here, rather than once for every incognito profile looped over
314 // below).
315 if (IsIncognitoEnabled(extension.id(), profile)) {
316 std::vector<Profile*> off_the_record_profiles =
317 profile->GetAllOffTheRecordProfiles();
318 related_contexts.reserve(related_contexts.size() +
319 off_the_record_profiles.size());
320 for (Profile* off_the_record_profile : off_the_record_profiles)
321 related_contexts.push_back(off_the_record_profile);
322 }
Lukasz Anforowicz223d2532021-03-09 17:04:07323
324 return related_contexts;
325}
326
[email protected]1d5cf4142014-01-24 18:25:22327} // namespace util
328} // namespace extensions