• 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/profiles/profile.h"
13 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/common/extensions/manifest_handlers/app_isolation_info.h"
16 #include "chrome/common/extensions/sync_helper.h"
17 #include "content/public/browser/site_instance.h"
18 #include "extensions/browser/extension_prefs.h"
19 #include "extensions/browser/extension_registry.h"
20 #include "extensions/browser/extension_system.h"
21 #include "extensions/browser/extension_util.h"
22 #include "extensions/common/extension.h"
23 #include "extensions/common/extension_icon_set.h"
24 #include "extensions/common/features/simple_feature.h"
25 #include "extensions/common/manifest.h"
26 #include "extensions/common/manifest_handlers/incognito_info.h"
27 #include "grit/theme_resources.h"
28 #include "ui/base/resource/resource_bundle.h"
29 
30 namespace extensions {
31 namespace util {
32 
33 namespace {
34 // The entry into the ExtensionPrefs for allowing an extension to script on
35 // all urls without explicit permission.
36 const char kExtensionAllowedOnAllUrlsPrefName[] =
37     "extension_can_script_all_urls";
38 
39 // Returns true if |extension_id| for an external component extension should
40 // always be enabled in incognito windows.
IsWhitelistedForIncognito(const std::string & extension_id)41 bool IsWhitelistedForIncognito(const std::string& extension_id) {
42   static const char* kExtensionWhitelist[] = {
43     "D5736E4B5CF695CB93A2FB57E4FDC6E5AFAB6FE2",  // http://crbug.com/312900
44     "D57DE394F36DC1C3220E7604C575D29C51A6C495",  // http://crbug.com/319444
45     "3F65507A3B39259B38C8173C6FFA3D12DF64CCE9"   // http://crbug.com/371562
46   };
47 
48   return extensions::SimpleFeature::IsIdInList(
49       extension_id,
50       std::set<std::string>(
51           kExtensionWhitelist,
52           kExtensionWhitelist + arraysize(kExtensionWhitelist)));
53 }
54 }  // namespace
55 
IsIncognitoEnabled(const std::string & extension_id,content::BrowserContext * context)56 bool IsIncognitoEnabled(const std::string& extension_id,
57                         content::BrowserContext* context) {
58   const Extension* extension = ExtensionRegistry::Get(context)->
59       GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
60   if (extension) {
61     if (!extension->can_be_incognito_enabled())
62       return false;
63     // If this is an existing component extension we always allow it to
64     // work in incognito mode.
65     if (extension->location() == Manifest::COMPONENT)
66       return true;
67     if (extension->location() == Manifest::EXTERNAL_COMPONENT &&
68         IsWhitelistedForIncognito(extension_id)) {
69       return true;
70     }
71   }
72 
73   return ExtensionPrefs::Get(context)->IsIncognitoEnabled(extension_id);
74 }
75 
SetIsIncognitoEnabled(const std::string & extension_id,content::BrowserContext * context,bool enabled)76 void SetIsIncognitoEnabled(const std::string& extension_id,
77                            content::BrowserContext* context,
78                            bool enabled) {
79   ExtensionService* service =
80       ExtensionSystem::Get(context)->extension_service();
81   CHECK(service);
82   const Extension* extension = service->GetInstalledExtension(extension_id);
83 
84   if (extension) {
85     if (!extension->can_be_incognito_enabled())
86       return;
87 
88     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.
92       DCHECK(sync_helper::IsSyncable(extension));
93 
94       // If we are here, make sure the we aren't trying to change the value.
95       DCHECK_EQ(enabled, IsIncognitoEnabled(extension_id, service->profile()));
96       return;
97     }
98   }
99 
100   ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(service->profile());
101   // Broadcast unloaded and loaded events to update browser state. Only bother
102   // if the value changed and the extension is actually enabled, since there is
103   // no UI otherwise.
104   bool old_enabled = extension_prefs->IsIncognitoEnabled(extension_id);
105   if (enabled == old_enabled)
106     return;
107 
108   extension_prefs->SetIsIncognitoEnabled(extension_id, enabled);
109 
110   bool extension_is_enabled = service->extensions()->Contains(extension_id);
111 
112   // When we reload the extension the ID may be invalidated if we've passed it
113   // by const ref everywhere. Make a copy to be safe.
114   std::string id = extension_id;
115   if (extension_is_enabled)
116     service->ReloadExtension(id);
117 
118   // Reloading the extension invalidates the |extension| pointer.
119   extension = service->GetInstalledExtension(id);
120   if (extension) {
121     ExtensionSyncService::Get(service->profile())->
122         SyncExtensionChangeIfNeeded(*extension);
123   }
124 }
125 
CanCrossIncognito(const Extension * extension,content::BrowserContext * context)126 bool CanCrossIncognito(const Extension* extension,
127                        content::BrowserContext* context) {
128   // We allow the extension to see events and data from another profile iff it
129   // uses "spanning" behavior and it has incognito access. "split" mode
130   // extensions only see events for a matching profile.
131   CHECK(extension);
132   return IsIncognitoEnabled(extension->id(), context) &&
133          !IncognitoInfo::IsSplitMode(extension);
134 }
135 
CanLoadInIncognito(const Extension * extension,content::BrowserContext * context)136 bool CanLoadInIncognito(const Extension* extension,
137                         content::BrowserContext* context) {
138   CHECK(extension);
139   if (extension->is_hosted_app())
140     return true;
141   // Packaged apps and regular extensions need to be enabled specifically for
142   // incognito (and split mode should be set).
143   return IncognitoInfo::IsSplitMode(extension) &&
144          IsIncognitoEnabled(extension->id(), context);
145 }
146 
AllowFileAccess(const std::string & extension_id,content::BrowserContext * context)147 bool AllowFileAccess(const std::string& extension_id,
148                      content::BrowserContext* context) {
149   return CommandLine::ForCurrentProcess()->HasSwitch(
150              switches::kDisableExtensionsFileAccessCheck) ||
151          ExtensionPrefs::Get(context)->AllowFileAccess(extension_id);
152 }
153 
SetAllowFileAccess(const std::string & extension_id,content::BrowserContext * context,bool allow)154 void SetAllowFileAccess(const std::string& extension_id,
155                         content::BrowserContext* context,
156                         bool allow) {
157   ExtensionService* service =
158       ExtensionSystem::Get(context)->extension_service();
159   CHECK(service);
160 
161   // Reload to update browser state. Only bother if the value changed and the
162   // extension is actually enabled, since there is no UI otherwise.
163   if (allow == AllowFileAccess(extension_id, context))
164     return;
165 
166   ExtensionPrefs::Get(context)->SetAllowFileAccess(extension_id, allow);
167 
168   bool extension_is_enabled = service->extensions()->Contains(extension_id);
169   if (extension_is_enabled)
170     service->ReloadExtension(extension_id);
171 }
172 
AllowedScriptingOnAllUrls(const std::string & extension_id,content::BrowserContext * context)173 bool AllowedScriptingOnAllUrls(const std::string& extension_id,
174                                content::BrowserContext* context) {
175   bool allowed = false;
176   return ExtensionPrefs::Get(context)->ReadPrefAsBoolean(
177              extension_id,
178              kExtensionAllowedOnAllUrlsPrefName,
179              &allowed) &&
180          allowed;
181 }
182 
SetAllowedScriptingOnAllUrls(const std::string & extension_id,content::BrowserContext * context,bool allowed)183 void SetAllowedScriptingOnAllUrls(const std::string& extension_id,
184                                   content::BrowserContext* context,
185                                   bool allowed) {
186   ExtensionPrefs::Get(context)->UpdateExtensionPref(
187       extension_id,
188       kExtensionAllowedOnAllUrlsPrefName,
189       allowed ? new base::FundamentalValue(true) : NULL);
190 }
191 
IsAppLaunchable(const std::string & extension_id,content::BrowserContext * context)192 bool IsAppLaunchable(const std::string& extension_id,
193                      content::BrowserContext* context) {
194   return !(ExtensionPrefs::Get(context)->GetDisableReasons(extension_id) &
195            Extension::DISABLE_UNSUPPORTED_REQUIREMENT);
196 }
197 
IsAppLaunchableWithoutEnabling(const std::string & extension_id,content::BrowserContext * context)198 bool IsAppLaunchableWithoutEnabling(const std::string& extension_id,
199                                     content::BrowserContext* context) {
200   return ExtensionRegistry::Get(context)->GetExtensionById(
201       extension_id, ExtensionRegistry::ENABLED) != NULL;
202 }
203 
ShouldSyncExtension(const Extension * extension,content::BrowserContext * context)204 bool ShouldSyncExtension(const Extension* extension,
205                          content::BrowserContext* context) {
206   return sync_helper::IsSyncableExtension(extension) &&
207          !ExtensionPrefs::Get(context)->DoNotSync(extension->id());
208 }
209 
ShouldSyncApp(const Extension * app,content::BrowserContext * context)210 bool ShouldSyncApp(const Extension* app, content::BrowserContext* context) {
211   return sync_helper::IsSyncableApp(app) &&
212          !util::IsEphemeralApp(app->id(), context) &&
213          !ExtensionPrefs::Get(context)->DoNotSync(app->id());
214 }
215 
IsExtensionIdle(const std::string & extension_id,content::BrowserContext * context)216 bool IsExtensionIdle(const std::string& extension_id,
217                      content::BrowserContext* context) {
218   ProcessManager* process_manager =
219       ExtensionSystem::Get(context)->process_manager();
220   DCHECK(process_manager);
221   ExtensionHost* host =
222       process_manager->GetBackgroundHostForExtension(extension_id);
223   if (host)
224     return false;
225 
226   content::SiteInstance* site_instance = process_manager->GetSiteInstanceForURL(
227       Extension::GetBaseURLFromExtensionId(extension_id));
228   if (site_instance && site_instance->HasProcess())
229     return false;
230 
231   return process_manager->GetRenderViewHostsForExtension(extension_id).empty();
232 }
233 
GetSiteForExtensionId(const std::string & extension_id,content::BrowserContext * context)234 GURL GetSiteForExtensionId(const std::string& extension_id,
235                            content::BrowserContext* context) {
236   return content::SiteInstance::GetSiteForURL(
237       context, Extension::GetBaseURLFromExtensionId(extension_id));
238 }
239 
GetExtensionInfo(const Extension * extension)240 scoped_ptr<base::DictionaryValue> GetExtensionInfo(const Extension* extension) {
241   DCHECK(extension);
242   scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
243 
244   dict->SetString("id", extension->id());
245   dict->SetString("name", extension->name());
246 
247   GURL icon = extensions::ExtensionIconSource::GetIconURL(
248       extension,
249       extension_misc::EXTENSION_ICON_SMALLISH,
250       ExtensionIconSet::MATCH_BIGGER,
251       false,  // Not grayscale.
252       NULL);  // Don't set bool if exists.
253   dict->SetString("icon", icon.spec());
254 
255   return dict.Pass();
256 }
257 
HasIsolatedStorage(const ExtensionInfo & info)258 bool HasIsolatedStorage(const ExtensionInfo& info) {
259   if (!info.extension_manifest.get())
260     return false;
261 
262   std::string error;
263   scoped_refptr<const Extension> extension(Extension::Create(
264       info.extension_path,
265       info.extension_location,
266       *info.extension_manifest,
267       Extension::NO_FLAGS,
268       info.extension_id,
269       &error));
270   if (!extension.get())
271     return false;
272 
273   return AppIsolationInfo::HasIsolatedStorage(extension.get());
274 }
275 
SiteHasIsolatedStorage(const GURL & extension_site_url,content::BrowserContext * context)276 bool SiteHasIsolatedStorage(const GURL& extension_site_url,
277                             content::BrowserContext* context) {
278   const Extension* extension = ExtensionRegistry::Get(context)->
279       enabled_extensions().GetExtensionOrAppByURL(extension_site_url);
280   if (!extension)
281     return false;
282 
283   return AppIsolationInfo::HasIsolatedStorage(extension);
284 }
285 
GetDefaultAppIcon()286 const gfx::ImageSkia& GetDefaultAppIcon() {
287   return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
288       IDR_APP_DEFAULT_ICON);
289 }
290 
GetDefaultExtensionIcon()291 const gfx::ImageSkia& GetDefaultExtensionIcon() {
292   return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
293       IDR_EXTENSION_DEFAULT_ICON);
294 }
295 
296 }  // namespace util
297 }  // namespace extensions
298