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