Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / extension_util.cc
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/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
31 namespace extensions {
32 namespace util {
33
34 namespace {
35 // The entry into the ExtensionPrefs for allowing an extension to script on
36 // all urls without explicit permission.
37 const 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.
42 bool 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
57 bool 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
77 void 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
127 bool 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
137 bool 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
148 bool 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
155 void 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
174 bool 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
184 void 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
207 bool 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
214 bool IsAppLaunchableWithoutEnabling(const std::string& extension_id,
215                                     content::BrowserContext* context) {
216   return ExtensionRegistry::Get(context)->GetExtensionById(
217       extension_id, ExtensionRegistry::ENABLED) != NULL;
218 }
219
220 bool ShouldSyncExtension(const Extension* extension,
221                          content::BrowserContext* context) {
222   return sync_helper::IsSyncableExtension(extension) &&
223          !ExtensionPrefs::Get(context)->DoNotSync(extension->id());
224 }
225
226 bool 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
232 bool 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
250 GURL GetSiteForExtensionId(const std::string& extension_id,
251                            content::BrowserContext* context) {
252   return content::SiteInstance::GetSiteForURL(
253       context, Extension::GetBaseURLFromExtensionId(extension_id));
254 }
255
256 scoped_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
274 bool 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
292 bool 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
302 const gfx::ImageSkia& GetDefaultAppIcon() {
303   return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
304       IDR_APP_DEFAULT_ICON);
305 }
306
307 const gfx::ImageSkia& GetDefaultExtensionIcon() {
308   return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
309       IDR_EXTENSION_DEFAULT_ICON);
310 }
311
312 }  // namespace util
313 }  // namespace extensions