Upstream version 11.40.277.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/extensions/shared_module_service.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
16 #include "chrome/common/chrome_switches.h"
17 #include "chrome/common/extensions/manifest_handlers/app_isolation_info.h"
18 #include "chrome/common/extensions/sync_helper.h"
19 #include "content/public/browser/site_instance.h"
20 #include "extensions/browser/extension_prefs.h"
21 #include "extensions/browser/extension_registry.h"
22 #include "extensions/browser/extension_system.h"
23 #include "extensions/browser/extension_util.h"
24 #include "extensions/common/extension.h"
25 #include "extensions/common/extension_icon_set.h"
26 #include "extensions/common/feature_switch.h"
27 #include "extensions/common/features/simple_feature.h"
28 #include "extensions/common/manifest.h"
29 #include "extensions/common/manifest_handlers/incognito_info.h"
30 #include "extensions/common/permissions/permissions_data.h"
31 #include "extensions/grit/extensions_browser_resources.h"
32 #include "ui/base/resource/resource_bundle.h"
33
34 namespace extensions {
35 namespace util {
36
37 namespace {
38
39 // The entry into the ExtensionPrefs for allowing an extension to script on
40 // all urls without explicit permission.
41 const char kExtensionAllowedOnAllUrlsPrefName[] =
42     "extension_can_script_all_urls";
43
44 // Returns true if |extension_id| for an external component extension should
45 // always be enabled in incognito windows.
46 bool IsWhitelistedForIncognito(const std::string& extension_id) {
47   static const char* const kExtensionWhitelist[] = {
48     "D5736E4B5CF695CB93A2FB57E4FDC6E5AFAB6FE2",  // http://crbug.com/312900
49     "D57DE394F36DC1C3220E7604C575D29C51A6C495",  // http://crbug.com/319444
50     "3F65507A3B39259B38C8173C6FFA3D12DF64CCE9"   // http://crbug.com/371562
51   };
52
53   return extensions::SimpleFeature::IsIdInList(
54       extension_id,
55       std::set<std::string>(
56           kExtensionWhitelist,
57           kExtensionWhitelist + arraysize(kExtensionWhitelist)));
58 }
59
60 // Returns |extension_id|. See note below.
61 std::string ReloadExtensionIfEnabled(const std::string& extension_id,
62                                      content::BrowserContext* context) {
63   ExtensionRegistry* registry = ExtensionRegistry::Get(context);
64   bool extension_is_enabled =
65       registry->enabled_extensions().Contains(extension_id);
66
67   if (!extension_is_enabled)
68     return extension_id;
69
70   // When we reload the extension the ID may be invalidated if we've passed it
71   // by const ref everywhere. Make a copy to be safe. http://crbug.com/103762
72   std::string id = extension_id;
73   ExtensionService* service =
74       ExtensionSystem::Get(context)->extension_service();
75   CHECK(service);
76   service->ReloadExtension(id);
77   return id;
78 }
79
80 }  // namespace
81
82 bool IsIncognitoEnabled(const std::string& extension_id,
83                         content::BrowserContext* context) {
84   const Extension* extension = ExtensionRegistry::Get(context)->
85       GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
86   if (extension) {
87     if (!extension->can_be_incognito_enabled())
88       return false;
89     // If this is an existing component extension we always allow it to
90     // work in incognito mode.
91     if (extension->location() == Manifest::COMPONENT)
92       return true;
93     if (extension->location() == Manifest::EXTERNAL_COMPONENT &&
94         IsWhitelistedForIncognito(extension_id)) {
95       return true;
96     }
97   }
98
99   return ExtensionPrefs::Get(context)->IsIncognitoEnabled(extension_id);
100 }
101
102 void SetIsIncognitoEnabled(const std::string& extension_id,
103                            content::BrowserContext* context,
104                            bool enabled) {
105   ExtensionRegistry* registry = ExtensionRegistry::Get(context);
106   const Extension* extension =
107       registry->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
108
109   if (extension) {
110     if (!extension->can_be_incognito_enabled())
111       return;
112
113     if (extension->location() == Manifest::COMPONENT) {
114       // This shouldn't be called for component extensions unless it is called
115       // by sync, for syncable component extensions.
116       // See http://crbug.com/112290 and associated CLs for the sordid history.
117       DCHECK(sync_helper::IsSyncable(extension));
118
119       // If we are here, make sure the we aren't trying to change the value.
120       DCHECK_EQ(enabled, IsIncognitoEnabled(extension_id, context));
121       return;
122     }
123   }
124
125   ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(context);
126   // Broadcast unloaded and loaded events to update browser state. Only bother
127   // if the value changed and the extension is actually enabled, since there is
128   // no UI otherwise.
129   bool old_enabled = extension_prefs->IsIncognitoEnabled(extension_id);
130   if (enabled == old_enabled)
131     return;
132
133   extension_prefs->SetIsIncognitoEnabled(extension_id, enabled);
134
135   std::string id = ReloadExtensionIfEnabled(extension_id, context);
136
137   // Reloading the extension invalidates the |extension| pointer.
138   extension = registry->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
139   if (extension) {
140     Profile* profile = Profile::FromBrowserContext(context);
141     ExtensionSyncService::Get(profile)->SyncExtensionChangeIfNeeded(*extension);
142   }
143 }
144
145 bool CanCrossIncognito(const Extension* extension,
146                        content::BrowserContext* context) {
147   // We allow the extension to see events and data from another profile iff it
148   // uses "spanning" behavior and it has incognito access. "split" mode
149   // extensions only see events for a matching profile.
150   CHECK(extension);
151   return IsIncognitoEnabled(extension->id(), context) &&
152          !IncognitoInfo::IsSplitMode(extension);
153 }
154
155 bool CanLoadInIncognito(const Extension* extension,
156                         content::BrowserContext* context) {
157   CHECK(extension);
158   if (extension->is_hosted_app())
159     return true;
160   // Packaged apps and regular extensions need to be enabled specifically for
161   // incognito (and split mode should be set).
162   return IncognitoInfo::IsSplitMode(extension) &&
163          IsIncognitoEnabled(extension->id(), context);
164 }
165
166 bool AllowFileAccess(const std::string& extension_id,
167                      content::BrowserContext* context) {
168   return CommandLine::ForCurrentProcess()->HasSwitch(
169              switches::kDisableExtensionsFileAccessCheck) ||
170          ExtensionPrefs::Get(context)->AllowFileAccess(extension_id);
171 }
172
173 void SetAllowFileAccess(const std::string& extension_id,
174                         content::BrowserContext* context,
175                         bool allow) {
176   // Reload to update browser state. Only bother if the value changed and the
177   // extension is actually enabled, since there is no UI otherwise.
178   if (allow == AllowFileAccess(extension_id, context))
179     return;
180
181   ExtensionPrefs::Get(context)->SetAllowFileAccess(extension_id, allow);
182
183   ReloadExtensionIfEnabled(extension_id, context);
184 }
185
186 bool AllowedScriptingOnAllUrls(const std::string& extension_id,
187                                content::BrowserContext* context) {
188   bool allowed = false;
189   return ExtensionPrefs::Get(context)->ReadPrefAsBoolean(
190              extension_id,
191              kExtensionAllowedOnAllUrlsPrefName,
192              &allowed) &&
193          allowed;
194 }
195
196 void SetAllowedScriptingOnAllUrls(const std::string& extension_id,
197                                   content::BrowserContext* context,
198                                   bool allowed) {
199   if (allowed == AllowedScriptingOnAllUrls(extension_id, context))
200     return;  // Nothing to do here.
201
202   ExtensionPrefs::Get(context)->UpdateExtensionPref(
203       extension_id,
204       kExtensionAllowedOnAllUrlsPrefName,
205       allowed ? new base::FundamentalValue(true) : NULL);
206
207   const Extension* extension =
208       ExtensionRegistry::Get(context)->enabled_extensions().GetByID(
209           extension_id);
210   if (extension) {
211     PermissionsUpdater updater(context);
212     if (allowed)
213       updater.GrantWithheldImpliedAllHosts(extension);
214     else
215       updater.WithholdImpliedAllHosts(extension);
216   }
217 }
218
219 bool ScriptsMayRequireActionForExtension(const Extension* extension) {
220   // An extension requires user action to execute scripts iff the switch to do
221   // so is enabled, the extension shows up in chrome:extensions (so the user can
222   // grant withheld permissions), the extension is not part of chrome or
223   // corporate policy, and also not on the scripting whitelist.
224   return FeatureSwitch::scripts_require_action()->IsEnabled() &&
225       extension->ShouldDisplayInExtensionSettings() &&
226       !Manifest::IsPolicyLocation(extension->location()) &&
227       !Manifest::IsComponentLocation(extension->location()) &&
228       !PermissionsData::CanExecuteScriptEverywhere(extension);
229 }
230
231 bool IsAppLaunchable(const std::string& extension_id,
232                      content::BrowserContext* context) {
233   int reason = ExtensionPrefs::Get(context)->GetDisableReasons(extension_id);
234   return !((reason & Extension::DISABLE_UNSUPPORTED_REQUIREMENT) ||
235            (reason & Extension::DISABLE_CORRUPTED));
236 }
237
238 bool IsAppLaunchableWithoutEnabling(const std::string& extension_id,
239                                     content::BrowserContext* context) {
240   return ExtensionRegistry::Get(context)->GetExtensionById(
241       extension_id, ExtensionRegistry::ENABLED) != NULL;
242 }
243
244 bool ShouldSyncExtension(const Extension* extension,
245                          content::BrowserContext* context) {
246   return sync_helper::IsSyncableExtension(extension) &&
247          !ExtensionPrefs::Get(context)->DoNotSync(extension->id());
248 }
249
250 bool ShouldSyncApp(const Extension* app, content::BrowserContext* context) {
251   return sync_helper::IsSyncableApp(app) &&
252          !util::IsEphemeralApp(app->id(), context) &&
253          !ExtensionPrefs::Get(context)->DoNotSync(app->id());
254 }
255
256 bool IsExtensionIdle(const std::string& extension_id,
257                      content::BrowserContext* context) {
258   std::vector<std::string> ids_to_check;
259   ids_to_check.push_back(extension_id);
260
261   const Extension* extension =
262       ExtensionRegistry::Get(context)
263           ->GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
264   if (extension && extension->is_shared_module()) {
265     // We have to check all the extensions that use this shared module for idle
266     // to tell whether it is really 'idle'.
267     SharedModuleService* service = ExtensionSystem::Get(context)
268                                        ->extension_service()
269                                        ->shared_module_service();
270     scoped_ptr<ExtensionSet> dependents =
271         service->GetDependentExtensions(extension);
272     for (ExtensionSet::const_iterator i = dependents->begin();
273          i != dependents->end();
274          i++) {
275       ids_to_check.push_back((*i)->id());
276     }
277   }
278
279   ProcessManager* process_manager = ProcessManager::Get(context);
280   for (std::vector<std::string>::const_iterator i = ids_to_check.begin();
281        i != ids_to_check.end();
282        i++) {
283     const std::string id = (*i);
284     ExtensionHost* host = process_manager->GetBackgroundHostForExtension(id);
285     if (host)
286       return false;
287
288     content::SiteInstance* site_instance =
289         process_manager->GetSiteInstanceForURL(
290             Extension::GetBaseURLFromExtensionId(id));
291     if (site_instance && site_instance->HasProcess())
292       return false;
293
294     if (!process_manager->GetRenderViewHostsForExtension(id).empty())
295       return false;
296   }
297   return true;
298 }
299
300 GURL GetSiteForExtensionId(const std::string& extension_id,
301                            content::BrowserContext* context) {
302   return content::SiteInstance::GetSiteForURL(
303       context, Extension::GetBaseURLFromExtensionId(extension_id));
304 }
305
306 scoped_ptr<base::DictionaryValue> GetExtensionInfo(const Extension* extension) {
307   DCHECK(extension);
308   scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
309
310   dict->SetString("id", extension->id());
311   dict->SetString("name", extension->name());
312
313   GURL icon = extensions::ExtensionIconSource::GetIconURL(
314       extension,
315       extension_misc::EXTENSION_ICON_SMALLISH,
316       ExtensionIconSet::MATCH_BIGGER,
317       false,  // Not grayscale.
318       NULL);  // Don't set bool if exists.
319   dict->SetString("icon", icon.spec());
320
321   return dict.Pass();
322 }
323
324 bool HasIsolatedStorage(const ExtensionInfo& info) {
325   if (!info.extension_manifest.get())
326     return false;
327
328   std::string error;
329   scoped_refptr<const Extension> extension(Extension::Create(
330       info.extension_path,
331       info.extension_location,
332       *info.extension_manifest,
333       Extension::NO_FLAGS,
334       info.extension_id,
335       &error));
336   if (!extension.get())
337     return false;
338
339   return AppIsolationInfo::HasIsolatedStorage(extension.get());
340 }
341
342 bool SiteHasIsolatedStorage(const GURL& extension_site_url,
343                             content::BrowserContext* context) {
344   const Extension* extension = ExtensionRegistry::Get(context)->
345       enabled_extensions().GetExtensionOrAppByURL(extension_site_url);
346   if (!extension)
347     return false;
348
349   return AppIsolationInfo::HasIsolatedStorage(extension);
350 }
351
352 const gfx::ImageSkia& GetDefaultAppIcon() {
353   return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
354       IDR_APP_DEFAULT_ICON);
355 }
356
357 const gfx::ImageSkia& GetDefaultExtensionIcon() {
358   return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
359       IDR_EXTENSION_DEFAULT_ICON);
360 }
361
362 bool IsStreamlinedHostedAppsEnabled() {
363   return CommandLine::ForCurrentProcess()->HasSwitch(
364           switches::kEnableStreamlinedHostedApps);
365 }
366
367 }  // namespace util
368 }  // namespace extensions