• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "base/command_line.h"
8 #include "base/logging.h"
9 #include "base/values.h"
10 #include "chrome/browser/extensions/extension_service.h"
11 #include "chrome/browser/extensions/extension_sync_service.h"
12 #include "chrome/browser/extensions/permissions_updater.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
15 #include "chrome/common/chrome_switches.h"
16 #include "chrome/common/extensions/manifest_handlers/app_isolation_info.h"
17 #include "chrome/common/extensions/sync_helper.h"
18 #include "content/public/browser/site_instance.h"
19 #include "extensions/browser/extension_prefs.h"
20 #include "extensions/browser/extension_registry.h"
21 #include "extensions/browser/extension_system.h"
22 #include "extensions/browser/extension_util.h"
23 #include "extensions/common/extension.h"
24 #include "extensions/common/extension_icon_set.h"
25 #include "extensions/common/feature_switch.h"
26 #include "extensions/common/features/simple_feature.h"
27 #include "extensions/common/manifest.h"
28 #include "extensions/common/manifest_handlers/incognito_info.h"
29 #include "extensions/common/permissions/permissions_data.h"
30 #include "extensions/grit/extensions_browser_resources.h"
31 #include "ui/base/resource/resource_bundle.h"
32 
33 namespace extensions {
34 namespace util {
35 
36 namespace {
37 
38 // The entry into the ExtensionPrefs for allowing an extension to script on
39 // all urls without explicit permission.
40 const char kExtensionAllowedOnAllUrlsPrefName[] =
41     "extension_can_script_all_urls";
42 
43 // Returns true if |extension_id| for an external component extension should
44 // always be enabled in incognito windows.
IsWhitelistedForIncognito(const std::string & extension_id)45 bool IsWhitelistedForIncognito(const std::string& extension_id) {
46   static const char* kExtensionWhitelist[] = {
47     "D5736E4B5CF695CB93A2FB57E4FDC6E5AFAB6FE2",  // http://crbug.com/312900
48     "D57DE394F36DC1C3220E7604C575D29C51A6C495",  // http://crbug.com/319444
49     "3F65507A3B39259B38C8173C6FFA3D12DF64CCE9"   // http://crbug.com/371562
50   };
51 
52   return extensions::SimpleFeature::IsIdInList(
53       extension_id,
54       std::set<std::string>(
55           kExtensionWhitelist,
56           kExtensionWhitelist + arraysize(kExtensionWhitelist)));
57 }
58 
59 // Returns |extension_id|. See note below.
ReloadExtensionIfEnabled(const std::string & extension_id,content::BrowserContext * context)60 std::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 
79 }  // namespace
80 
IsIncognitoEnabled(const std::string & extension_id,content::BrowserContext * context)81 bool IsIncognitoEnabled(const std::string& extension_id,
82                         content::BrowserContext* context) {
83   const Extension* extension = ExtensionRegistry::Get(context)->
84       GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
85   if (extension) {
86     if (!extension->can_be_incognito_enabled())
87       return false;
88     // If this is an existing component extension we always allow it to
89     // work in incognito mode.
90     if (extension->location() == Manifest::COMPONENT)
91       return true;
92     if (extension->location() == Manifest::EXTERNAL_COMPONENT &&
93         IsWhitelistedForIncognito(extension_id)) {
94       return true;
95     }
96   }
97 
98   return ExtensionPrefs::Get(context)->IsIncognitoEnabled(extension_id);
99 }
100 
SetIsIncognitoEnabled(const std::string & extension_id,content::BrowserContext * context,bool enabled)101 void SetIsIncognitoEnabled(const std::string& extension_id,
102                            content::BrowserContext* context,
103                            bool enabled) {
104   ExtensionRegistry* registry = ExtensionRegistry::Get(context);
105   const Extension* extension =
106       registry->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
107 
108   if (extension) {
109     if (!extension->can_be_incognito_enabled())
110       return;
111 
112     if (extension->location() == Manifest::COMPONENT) {
113       // 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.
116       DCHECK(sync_helper::IsSyncable(extension));
117 
118       // If we are here, make sure the we aren't trying to change the value.
119       DCHECK_EQ(enabled, IsIncognitoEnabled(extension_id, context));
120       return;
121     }
122   }
123 
124   ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(context);
125   // Broadcast unloaded and loaded events to update browser state. Only bother
126   // if the value changed and the extension is actually enabled, since there is
127   // no UI otherwise.
128   bool old_enabled = extension_prefs->IsIncognitoEnabled(extension_id);
129   if (enabled == old_enabled)
130     return;
131 
132   extension_prefs->SetIsIncognitoEnabled(extension_id, enabled);
133 
134   std::string id = ReloadExtensionIfEnabled(extension_id, context);
135 
136   // Reloading the extension invalidates the |extension| pointer.
137   extension = registry->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
138   if (extension) {
139     Profile* profile = Profile::FromBrowserContext(context);
140     ExtensionSyncService::Get(profile)->SyncExtensionChangeIfNeeded(*extension);
141   }
142 }
143 
CanCrossIncognito(const Extension * extension,content::BrowserContext * context)144 bool CanCrossIncognito(const Extension* extension,
145                        content::BrowserContext* context) {
146   // We allow the extension to see events and data from another profile iff it
147   // uses "spanning" behavior and it has incognito access. "split" mode
148   // extensions only see events for a matching profile.
149   CHECK(extension);
150   return IsIncognitoEnabled(extension->id(), context) &&
151          !IncognitoInfo::IsSplitMode(extension);
152 }
153 
CanLoadInIncognito(const Extension * extension,content::BrowserContext * context)154 bool CanLoadInIncognito(const Extension* extension,
155                         content::BrowserContext* context) {
156   CHECK(extension);
157   if (extension->is_hosted_app())
158     return true;
159   // Packaged apps and regular extensions need to be enabled specifically for
160   // incognito (and split mode should be set).
161   return IncognitoInfo::IsSplitMode(extension) &&
162          IsIncognitoEnabled(extension->id(), context);
163 }
164 
AllowFileAccess(const std::string & extension_id,content::BrowserContext * context)165 bool AllowFileAccess(const std::string& extension_id,
166                      content::BrowserContext* context) {
167   return CommandLine::ForCurrentProcess()->HasSwitch(
168              switches::kDisableExtensionsFileAccessCheck) ||
169          ExtensionPrefs::Get(context)->AllowFileAccess(extension_id);
170 }
171 
SetAllowFileAccess(const std::string & extension_id,content::BrowserContext * context,bool allow)172 void SetAllowFileAccess(const std::string& extension_id,
173                         content::BrowserContext* context,
174                         bool allow) {
175   // Reload to update browser state. Only bother if the value changed and the
176   // extension is actually enabled, since there is no UI otherwise.
177   if (allow == AllowFileAccess(extension_id, context))
178     return;
179 
180   ExtensionPrefs::Get(context)->SetAllowFileAccess(extension_id, allow);
181 
182   ReloadExtensionIfEnabled(extension_id, context);
183 }
184 
AllowedScriptingOnAllUrls(const std::string & extension_id,content::BrowserContext * context)185 bool AllowedScriptingOnAllUrls(const std::string& extension_id,
186                                content::BrowserContext* context) {
187   bool allowed = false;
188   return ExtensionPrefs::Get(context)->ReadPrefAsBoolean(
189              extension_id,
190              kExtensionAllowedOnAllUrlsPrefName,
191              &allowed) &&
192          allowed;
193 }
194 
SetAllowedScriptingOnAllUrls(const std::string & extension_id,content::BrowserContext * context,bool allowed)195 void SetAllowedScriptingOnAllUrls(const std::string& extension_id,
196                                   content::BrowserContext* context,
197                                   bool allowed) {
198   if (allowed == AllowedScriptingOnAllUrls(extension_id, context))
199     return;  // Nothing to do here.
200 
201   ExtensionPrefs::Get(context)->UpdateExtensionPref(
202       extension_id,
203       kExtensionAllowedOnAllUrlsPrefName,
204       allowed ? new base::FundamentalValue(true) : NULL);
205 
206   const Extension* extension =
207       ExtensionRegistry::Get(context)->enabled_extensions().GetByID(
208           extension_id);
209   if (extension) {
210     PermissionsUpdater updater(context);
211     if (allowed)
212       updater.GrantWithheldImpliedAllHosts(extension);
213     else
214       updater.WithholdImpliedAllHosts(extension);
215   }
216 }
217 
ScriptsMayRequireActionForExtension(const Extension * extension)218 bool ScriptsMayRequireActionForExtension(const Extension* extension) {
219   // An extension requires user action to execute scripts iff the switch to do
220   // so is enabled, the extension shows up in chrome:extensions (so the user can
221   // grant withheld permissions), the extension is not part of chrome or
222   // corporate policy, and also not on the scripting whitelist.
223   return FeatureSwitch::scripts_require_action()->IsEnabled() &&
224       extension->ShouldDisplayInExtensionSettings() &&
225       !Manifest::IsPolicyLocation(extension->location()) &&
226       !Manifest::IsComponentLocation(extension->location()) &&
227       !PermissionsData::CanExecuteScriptEverywhere(extension);
228 }
229 
IsAppLaunchable(const std::string & extension_id,content::BrowserContext * context)230 bool IsAppLaunchable(const std::string& extension_id,
231                      content::BrowserContext* context) {
232   int reason = ExtensionPrefs::Get(context)->GetDisableReasons(extension_id);
233   return !((reason & Extension::DISABLE_UNSUPPORTED_REQUIREMENT) ||
234            (reason & Extension::DISABLE_CORRUPTED));
235 }
236 
IsAppLaunchableWithoutEnabling(const std::string & extension_id,content::BrowserContext * context)237 bool IsAppLaunchableWithoutEnabling(const std::string& extension_id,
238                                     content::BrowserContext* context) {
239   return ExtensionRegistry::Get(context)->GetExtensionById(
240       extension_id, ExtensionRegistry::ENABLED) != NULL;
241 }
242 
ShouldSyncExtension(const Extension * extension,content::BrowserContext * context)243 bool ShouldSyncExtension(const Extension* extension,
244                          content::BrowserContext* context) {
245   return sync_helper::IsSyncableExtension(extension) &&
246          !ExtensionPrefs::Get(context)->DoNotSync(extension->id());
247 }
248 
ShouldSyncApp(const Extension * app,content::BrowserContext * context)249 bool ShouldSyncApp(const Extension* app, content::BrowserContext* context) {
250   return sync_helper::IsSyncableApp(app) &&
251          !util::IsEphemeralApp(app->id(), context) &&
252          !ExtensionPrefs::Get(context)->DoNotSync(app->id());
253 }
254 
IsExtensionIdle(const std::string & extension_id,content::BrowserContext * context)255 bool IsExtensionIdle(const std::string& extension_id,
256                      content::BrowserContext* context) {
257   ProcessManager* process_manager =
258       ExtensionSystem::Get(context)->process_manager();
259   DCHECK(process_manager);
260   ExtensionHost* host =
261       process_manager->GetBackgroundHostForExtension(extension_id);
262   if (host)
263     return false;
264 
265   content::SiteInstance* site_instance = process_manager->GetSiteInstanceForURL(
266       Extension::GetBaseURLFromExtensionId(extension_id));
267   if (site_instance && site_instance->HasProcess())
268     return false;
269 
270   return process_manager->GetRenderViewHostsForExtension(extension_id).empty();
271 }
272 
GetSiteForExtensionId(const std::string & extension_id,content::BrowserContext * context)273 GURL GetSiteForExtensionId(const std::string& extension_id,
274                            content::BrowserContext* context) {
275   return content::SiteInstance::GetSiteForURL(
276       context, Extension::GetBaseURLFromExtensionId(extension_id));
277 }
278 
GetExtensionInfo(const Extension * extension)279 scoped_ptr<base::DictionaryValue> GetExtensionInfo(const Extension* extension) {
280   DCHECK(extension);
281   scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
282 
283   dict->SetString("id", extension->id());
284   dict->SetString("name", extension->name());
285 
286   GURL icon = extensions::ExtensionIconSource::GetIconURL(
287       extension,
288       extension_misc::EXTENSION_ICON_SMALLISH,
289       ExtensionIconSet::MATCH_BIGGER,
290       false,  // Not grayscale.
291       NULL);  // Don't set bool if exists.
292   dict->SetString("icon", icon.spec());
293 
294   return dict.Pass();
295 }
296 
HasIsolatedStorage(const ExtensionInfo & info)297 bool HasIsolatedStorage(const ExtensionInfo& info) {
298   if (!info.extension_manifest.get())
299     return false;
300 
301   std::string error;
302   scoped_refptr<const Extension> extension(Extension::Create(
303       info.extension_path,
304       info.extension_location,
305       *info.extension_manifest,
306       Extension::NO_FLAGS,
307       info.extension_id,
308       &error));
309   if (!extension.get())
310     return false;
311 
312   return AppIsolationInfo::HasIsolatedStorage(extension.get());
313 }
314 
SiteHasIsolatedStorage(const GURL & extension_site_url,content::BrowserContext * context)315 bool SiteHasIsolatedStorage(const GURL& extension_site_url,
316                             content::BrowserContext* context) {
317   const Extension* extension = ExtensionRegistry::Get(context)->
318       enabled_extensions().GetExtensionOrAppByURL(extension_site_url);
319   if (!extension)
320     return false;
321 
322   return AppIsolationInfo::HasIsolatedStorage(extension);
323 }
324 
GetDefaultAppIcon()325 const gfx::ImageSkia& GetDefaultAppIcon() {
326   return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
327       IDR_APP_DEFAULT_ICON);
328 }
329 
GetDefaultExtensionIcon()330 const gfx::ImageSkia& GetDefaultExtensionIcon() {
331   return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
332       IDR_EXTENSION_DEFAULT_ICON);
333 }
334 
IsStreamlinedHostedAppsEnabled()335 bool IsStreamlinedHostedAppsEnabled() {
336   return CommandLine::ForCurrentProcess()->HasSwitch(
337           switches::kEnableStreamlinedHostedApps);
338 }
339 
340 }  // namespace util
341 }  // namespace extensions
342