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