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