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