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