1 // 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 <vector>
8
9 #include "base/check_op.h"
10 #include "base/command_line.h"
11 #include "base/feature_list.h"
12 #include "base/metrics/field_trial.h"
13 #include "base/values.h"
14 #include "build/build_config.h"
15 #include "chrome/browser/banners/app_banner_manager.h"
16 #include "chrome/browser/extensions/extension_service.h"
17 #include "chrome/browser/extensions/extension_sync_service.h"
18 #include "chrome/browser/extensions/launch_util.h"
19 #include "chrome/browser/extensions/permissions_updater.h"
20 #include "chrome/browser/extensions/scripting_permissions_modifier.h"
21 #include "chrome/browser/extensions/shared_module_service.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/browser/ui/browser.h"
24 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
25 #include "chrome/browser/web_applications/extensions/bookmark_app_util.h"
26 #include "chrome/common/chrome_switches.h"
27 #include "chrome/common/extensions/api/url_handlers/url_handlers_parser.h"
28 #include "chrome/common/extensions/sync_helper.h"
29 #include "components/variations/variations_associated_data.h"
30 #include "content/public/browser/site_instance.h"
31 #include "extensions/browser/disable_reason.h"
32 #include "extensions/browser/extension_prefs.h"
33 #include "extensions/browser/extension_registry.h"
34 #include "extensions/browser/extension_system.h"
35 #include "extensions/browser/extension_util.h"
36 #include "extensions/common/extension.h"
37 #include "extensions/common/extension_icon_set.h"
38 #include "extensions/common/manifest.h"
39 #include "extensions/common/manifest_handlers/app_isolation_info.h"
40 #include "extensions/common/manifest_handlers/incognito_info.h"
41 #include "extensions/common/manifest_handlers/permissions_parser.h"
42 #include "extensions/common/permissions/permissions_data.h"
43 #include "extensions/grit/extensions_browser_resources.h"
44 #include "ui/base/resource/resource_bundle.h"
45 #include "url/gurl.h"
46
47 #if defined(OS_CHROMEOS)
48 #include "chrome/browser/chromeos/file_manager/app_id.h"
49 #include "chrome/browser/chromeos/profiles/profile_helper.h"
50 #endif
51
52 namespace extensions {
53 namespace util {
54
55 namespace {
56 // Returns |extension_id|. See note below.
ReloadExtensionIfEnabled(const std::string & extension_id,content::BrowserContext * context)57 std::string ReloadExtensionIfEnabled(const std::string& extension_id,
58 content::BrowserContext* context) {
59 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
60 bool extension_is_enabled =
61 registry->enabled_extensions().Contains(extension_id);
62
63 if (!extension_is_enabled)
64 return extension_id;
65
66 // When we reload the extension the ID may be invalidated if we've passed it
67 // by const ref everywhere. Make a copy to be safe. http://crbug.com/103762
68 std::string id = extension_id;
69 ExtensionService* service =
70 ExtensionSystem::Get(context)->extension_service();
71 CHECK(service);
72 service->ReloadExtension(id);
73 return id;
74 }
75
76 } // namespace
77
IsExtensionSiteWithIsolatedStorage(const GURL & site_url,content::BrowserContext * context)78 bool IsExtensionSiteWithIsolatedStorage(const GURL& site_url,
79 content::BrowserContext* context) {
80 if (!site_url.SchemeIs(extensions::kExtensionScheme))
81 return false;
82
83 // The host in an extension site URL is the extension_id.
84 DCHECK(site_url.has_host());
85 return HasIsolatedStorage(site_url.host(), context);
86 }
87
HasIsolatedStorage(const std::string & extension_id,content::BrowserContext * context)88 bool HasIsolatedStorage(const std::string& extension_id,
89 content::BrowserContext* context) {
90 const Extension* extension =
91 ExtensionRegistry::Get(context)->enabled_extensions().GetByID(
92 extension_id);
93
94 #if defined(OS_CHROMEOS)
95 const bool is_policy_extension =
96 extension && Manifest::IsPolicyLocation(extension->location());
97 Profile* profile = Profile::FromBrowserContext(context);
98 if (profile && chromeos::ProfileHelper::IsSigninProfile(profile) &&
99 is_policy_extension) {
100 return true;
101 }
102 #endif
103
104 return extension && AppIsolationInfo::HasIsolatedStorage(extension);
105 }
106
SetIsIncognitoEnabled(const std::string & extension_id,content::BrowserContext * context,bool enabled)107 void SetIsIncognitoEnabled(const std::string& extension_id,
108 content::BrowserContext* context,
109 bool enabled) {
110 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
111 const Extension* extension =
112 registry->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
113
114 if (extension) {
115 if (!util::CanBeIncognitoEnabled(extension))
116 return;
117
118 // TODO(treib,kalman): Should this be Manifest::IsComponentLocation(..)?
119 // (which also checks for EXTERNAL_COMPONENT).
120 if (extension->location() == Manifest::COMPONENT) {
121 // This shouldn't be called for component extensions unless it is called
122 // by sync, for syncable component extensions.
123 // See http://crbug.com/112290 and associated CLs for the sordid history.
124 bool syncable = sync_helper::IsSyncableComponentExtension(extension);
125 #if defined(OS_CHROMEOS)
126 // For some users, the file manager app somehow ended up being synced even
127 // though it's supposed to be unsyncable; see crbug.com/576964. If the bad
128 // data ever gets cleaned up, this hack should be removed.
129 syncable = syncable || extension->id() == file_manager::kFileManagerAppId;
130 #endif
131 DCHECK(syncable);
132
133 // If we are here, make sure the we aren't trying to change the value.
134 DCHECK_EQ(enabled, IsIncognitoEnabled(extension_id, context));
135 return;
136 }
137 }
138
139 ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(context);
140 // Broadcast unloaded and loaded events to update browser state. Only bother
141 // if the value changed and the extension is actually enabled, since there is
142 // no UI otherwise.
143 bool old_enabled = extension_prefs->IsIncognitoEnabled(extension_id);
144 if (enabled == old_enabled)
145 return;
146
147 extension_prefs->SetIsIncognitoEnabled(extension_id, enabled);
148
149 std::string id = ReloadExtensionIfEnabled(extension_id, context);
150
151 // Reloading the extension invalidates the |extension| pointer.
152 extension = registry->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
153 if (extension) {
154 Profile* profile = Profile::FromBrowserContext(context);
155 ExtensionSyncService::Get(profile)->SyncExtensionChangeIfNeeded(*extension);
156 }
157 }
158
CanLoadInIncognito(const Extension * extension,content::BrowserContext * context)159 bool CanLoadInIncognito(const Extension* extension,
160 content::BrowserContext* context) {
161 CHECK(extension);
162 if (extension->is_hosted_app())
163 return true;
164 // Packaged apps and regular extensions need to be enabled specifically for
165 // incognito (and split mode should be set).
166 return IncognitoInfo::IsSplitMode(extension) &&
167 IsIncognitoEnabled(extension->id(), context);
168 }
169
AllowFileAccess(const std::string & extension_id,content::BrowserContext * context)170 bool AllowFileAccess(const std::string& extension_id,
171 content::BrowserContext* context) {
172 return base::CommandLine::ForCurrentProcess()->HasSwitch(
173 ::switches::kDisableExtensionsFileAccessCheck) ||
174 ExtensionPrefs::Get(context)->AllowFileAccess(extension_id);
175 }
176
SetAllowFileAccess(const std::string & extension_id,content::BrowserContext * context,bool allow)177 void SetAllowFileAccess(const std::string& extension_id,
178 content::BrowserContext* context,
179 bool allow) {
180 // Reload to update browser state. Only bother if the value changed and the
181 // extension is actually enabled, since there is no UI otherwise.
182 if (allow == AllowFileAccess(extension_id, context))
183 return;
184
185 ExtensionPrefs::Get(context)->SetAllowFileAccess(extension_id, allow);
186
187 ReloadExtensionIfEnabled(extension_id, context);
188 }
189
IsAppLaunchable(const std::string & extension_id,content::BrowserContext * context)190 bool IsAppLaunchable(const std::string& extension_id,
191 content::BrowserContext* context) {
192 int reason = ExtensionPrefs::Get(context)->GetDisableReasons(extension_id);
193 return !((reason & disable_reason::DISABLE_UNSUPPORTED_REQUIREMENT) ||
194 (reason & disable_reason::DISABLE_CORRUPTED));
195 }
196
IsAppLaunchableWithoutEnabling(const std::string & extension_id,content::BrowserContext * context)197 bool IsAppLaunchableWithoutEnabling(const std::string& extension_id,
198 content::BrowserContext* context) {
199 return ExtensionRegistry::Get(context)->GetExtensionById(
200 extension_id, ExtensionRegistry::ENABLED) != NULL;
201 }
202
ShouldSync(const Extension * extension,content::BrowserContext * context)203 bool ShouldSync(const Extension* extension,
204 content::BrowserContext* context) {
205 return sync_helper::IsSyncable(extension) &&
206 !ExtensionPrefs::Get(context)->DoNotSync(extension->id());
207 }
208
IsExtensionIdle(const std::string & extension_id,content::BrowserContext * context)209 bool IsExtensionIdle(const std::string& extension_id,
210 content::BrowserContext* context) {
211 std::vector<std::string> ids_to_check;
212 ids_to_check.push_back(extension_id);
213
214 const Extension* extension =
215 ExtensionRegistry::Get(context)
216 ->GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
217 if (extension && extension->is_shared_module()) {
218 // We have to check all the extensions that use this shared module for idle
219 // to tell whether it is really 'idle'.
220 SharedModuleService* service = ExtensionSystem::Get(context)
221 ->extension_service()
222 ->shared_module_service();
223 std::unique_ptr<ExtensionSet> dependents =
224 service->GetDependentExtensions(extension);
225 for (ExtensionSet::const_iterator i = dependents->begin();
226 i != dependents->end();
227 i++) {
228 ids_to_check.push_back((*i)->id());
229 }
230 }
231
232 ProcessManager* process_manager = ProcessManager::Get(context);
233 for (std::vector<std::string>::const_iterator i = ids_to_check.begin();
234 i != ids_to_check.end();
235 i++) {
236 const std::string id = (*i);
237 ExtensionHost* host = process_manager->GetBackgroundHostForExtension(id);
238 if (host)
239 return false;
240
241 scoped_refptr<content::SiteInstance> site_instance =
242 process_manager->GetSiteInstanceForURL(
243 Extension::GetBaseURLFromExtensionId(id));
244 if (site_instance && site_instance->HasProcess())
245 return false;
246
247 if (!process_manager->GetRenderFrameHostsForExtension(id).empty())
248 return false;
249 }
250 return true;
251 }
252
GetExtensionInfo(const Extension * extension)253 std::unique_ptr<base::DictionaryValue> GetExtensionInfo(
254 const Extension* extension) {
255 DCHECK(extension);
256 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
257
258 dict->SetString("id", extension->id());
259 dict->SetString("name", extension->name());
260
261 GURL icon = extensions::ExtensionIconSource::GetIconURL(
262 extension, extension_misc::EXTENSION_ICON_SMALLISH,
263 ExtensionIconSet::MATCH_BIGGER,
264 false); // Not grayscale.
265 dict->SetString("icon", icon.spec());
266
267 return dict;
268 }
269
GetDefaultAppIcon()270 const gfx::ImageSkia& GetDefaultAppIcon() {
271 return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
272 IDR_APP_DEFAULT_ICON);
273 }
274
GetDefaultExtensionIcon()275 const gfx::ImageSkia& GetDefaultExtensionIcon() {
276 return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
277 IDR_EXTENSION_DEFAULT_ICON);
278 }
279
GetInstallPromptPermissionSetForExtension(const Extension * extension,Profile * profile,bool include_optional_permissions)280 std::unique_ptr<const PermissionSet> GetInstallPromptPermissionSetForExtension(
281 const Extension* extension,
282 Profile* profile,
283 bool include_optional_permissions) {
284 // Initialize permissions if they have not already been set so that
285 // any transformations are correctly reflected in the install prompt.
286 PermissionsUpdater(profile, PermissionsUpdater::INIT_FLAG_TRANSIENT)
287 .InitializePermissions(extension);
288
289 std::unique_ptr<const PermissionSet> permissions_to_display =
290 extension->permissions_data()->active_permissions().Clone();
291
292 if (include_optional_permissions) {
293 const PermissionSet& optional_permissions =
294 PermissionsParser::GetOptionalPermissions(extension);
295 permissions_to_display = PermissionSet::CreateUnion(*permissions_to_display,
296 optional_permissions);
297 }
298 return permissions_to_display;
299 }
300
301 } // namespace util
302 } // namespace extensions
303