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