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