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