extension_util.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
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
30namespace extensions {
31namespace util {
32
33namespace {
34// The entry into the ExtensionPrefs for allowing an extension to script on
35// all urls without explicit permission.
36const 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.
41bool 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
56bool 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
76void 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
126bool 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
136bool 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
147bool 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
154void 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
173bool 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
183void 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
192bool 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
198bool IsAppLaunchableWithoutEnabling(const std::string& extension_id,
199                                    content::BrowserContext* context) {
200  return ExtensionRegistry::Get(context)->GetExtensionById(
201      extension_id, ExtensionRegistry::ENABLED) != NULL;
202}
203
204bool ShouldSyncExtension(const Extension* extension,
205                         content::BrowserContext* context) {
206  return sync_helper::IsSyncableExtension(extension) &&
207         !ExtensionPrefs::Get(context)->DoNotSync(extension->id());
208}
209
210bool 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
216bool 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
234GURL GetSiteForExtensionId(const std::string& extension_id,
235                           content::BrowserContext* context) {
236  return content::SiteInstance::GetSiteForURL(
237      context, Extension::GetBaseURLFromExtensionId(extension_id));
238}
239
240scoped_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
258bool 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
276bool 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
286const gfx::ImageSkia& GetDefaultAppIcon() {
287  return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
288      IDR_APP_DEFAULT_ICON);
289}
290
291const gfx::ImageSkia& GetDefaultExtensionIcon() {
292  return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
293      IDR_EXTENSION_DEFAULT_ICON);
294}
295
296}  // namespace util
297}  // namespace extensions
298