extension_util.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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/manifest.h" 25#include "extensions/common/manifest_handlers/incognito_info.h" 26#include "grit/theme_resources.h" 27#include "ui/base/resource/resource_bundle.h" 28 29namespace extensions { 30namespace util { 31 32namespace { 33// The entry into the ExtensionPrefs for allowing an extension to script on 34// all urls without explicit permission. 35const char kExtensionAllowedOnAllUrlsPrefName[] = 36 "extension_can_script_all_urls"; 37} 38 39bool IsIncognitoEnabled(const std::string& extension_id, 40 content::BrowserContext* context) { 41 const Extension* extension = ExtensionRegistry::Get(context)-> 42 GetExtensionById(extension_id, ExtensionRegistry::ENABLED); 43 if (extension) { 44 if (!extension->can_be_incognito_enabled()) 45 return false; 46 // If this is an existing component extension we always allow it to 47 // work in incognito mode. 48 if (extension->location() == Manifest::COMPONENT) 49 return true; 50 } 51 52 return ExtensionPrefs::Get(context)->IsIncognitoEnabled(extension_id); 53} 54 55void SetIsIncognitoEnabled(const std::string& extension_id, 56 content::BrowserContext* context, 57 bool enabled) { 58 ExtensionService* service = 59 ExtensionSystem::Get(context)->extension_service(); 60 CHECK(service); 61 const Extension* extension = service->GetInstalledExtension(extension_id); 62 63 if (extension) { 64 if (!extension->can_be_incognito_enabled()) 65 return; 66 67 if (extension->location() == Manifest::COMPONENT) { 68 // This shouldn't be called for component extensions unless it is called 69 // by sync, for syncable component extensions. 70 // See http://crbug.com/112290 and associated CLs for the sordid history. 71 DCHECK(sync_helper::IsSyncable(extension)); 72 73 // If we are here, make sure the we aren't trying to change the value. 74 DCHECK_EQ(enabled, IsIncognitoEnabled(extension_id, service->profile())); 75 return; 76 } 77 } 78 79 ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(service->profile()); 80 // Broadcast unloaded and loaded events to update browser state. Only bother 81 // if the value changed and the extension is actually enabled, since there is 82 // no UI otherwise. 83 bool old_enabled = extension_prefs->IsIncognitoEnabled(extension_id); 84 if (enabled == old_enabled) 85 return; 86 87 extension_prefs->SetIsIncognitoEnabled(extension_id, enabled); 88 89 bool extension_is_enabled = service->extensions()->Contains(extension_id); 90 91 // When we reload the extension the ID may be invalidated if we've passed it 92 // by const ref everywhere. Make a copy to be safe. 93 std::string id = extension_id; 94 if (extension_is_enabled) 95 service->ReloadExtension(id); 96 97 // Reloading the extension invalidates the |extension| pointer. 98 extension = service->GetInstalledExtension(id); 99 if (extension) { 100 ExtensionSyncService::Get(service->profile())-> 101 SyncExtensionChangeIfNeeded(*extension); 102 } 103} 104 105bool CanCrossIncognito(const Extension* extension, 106 content::BrowserContext* context) { 107 // We allow the extension to see events and data from another profile iff it 108 // uses "spanning" behavior and it has incognito access. "split" mode 109 // extensions only see events for a matching profile. 110 CHECK(extension); 111 return IsIncognitoEnabled(extension->id(), context) && 112 !IncognitoInfo::IsSplitMode(extension); 113} 114 115bool CanLoadInIncognito(const Extension* extension, 116 content::BrowserContext* context) { 117 CHECK(extension); 118 if (extension->is_hosted_app()) 119 return true; 120 // Packaged apps and regular extensions need to be enabled specifically for 121 // incognito (and split mode should be set). 122 return IncognitoInfo::IsSplitMode(extension) && 123 IsIncognitoEnabled(extension->id(), context); 124} 125 126bool AllowFileAccess(const std::string& extension_id, 127 content::BrowserContext* context) { 128 return CommandLine::ForCurrentProcess()->HasSwitch( 129 switches::kDisableExtensionsFileAccessCheck) || 130 ExtensionPrefs::Get(context)->AllowFileAccess(extension_id); 131} 132 133void SetAllowFileAccess(const std::string& extension_id, 134 content::BrowserContext* context, 135 bool allow) { 136 ExtensionService* service = 137 ExtensionSystem::Get(context)->extension_service(); 138 CHECK(service); 139 140 // Reload to update browser state. Only bother if the value changed and the 141 // extension is actually enabled, since there is no UI otherwise. 142 if (allow == AllowFileAccess(extension_id, context)) 143 return; 144 145 ExtensionPrefs::Get(context)->SetAllowFileAccess(extension_id, allow); 146 147 bool extension_is_enabled = service->extensions()->Contains(extension_id); 148 if (extension_is_enabled) 149 service->ReloadExtension(extension_id); 150} 151 152bool AllowedScriptingOnAllUrls(const std::string& extension_id, 153 content::BrowserContext* context) { 154 bool allowed = false; 155 return ExtensionPrefs::Get(context)->ReadPrefAsBoolean( 156 extension_id, 157 kExtensionAllowedOnAllUrlsPrefName, 158 &allowed) && 159 allowed; 160} 161 162void SetAllowedScriptingOnAllUrls(const std::string& extension_id, 163 content::BrowserContext* context, 164 bool allowed) { 165 ExtensionPrefs::Get(context)->UpdateExtensionPref( 166 extension_id, 167 kExtensionAllowedOnAllUrlsPrefName, 168 allowed ? new base::FundamentalValue(true) : NULL); 169} 170 171bool IsAppLaunchable(const std::string& extension_id, 172 content::BrowserContext* context) { 173 return !(ExtensionPrefs::Get(context)->GetDisableReasons(extension_id) & 174 Extension::DISABLE_UNSUPPORTED_REQUIREMENT); 175} 176 177bool IsAppLaunchableWithoutEnabling(const std::string& extension_id, 178 content::BrowserContext* context) { 179 return ExtensionRegistry::Get(context)->GetExtensionById( 180 extension_id, ExtensionRegistry::ENABLED) != NULL; 181} 182 183bool ShouldSyncApp(const Extension* app, content::BrowserContext* context) { 184 return sync_helper::IsSyncableApp(app) && 185 !util::IsEphemeralApp(app->id(), context); 186} 187 188bool IsExtensionIdle(const std::string& extension_id, 189 content::BrowserContext* context) { 190 ProcessManager* process_manager = 191 ExtensionSystem::Get(context)->process_manager(); 192 DCHECK(process_manager); 193 ExtensionHost* host = 194 process_manager->GetBackgroundHostForExtension(extension_id); 195 if (host) 196 return false; 197 198 content::SiteInstance* site_instance = process_manager->GetSiteInstanceForURL( 199 Extension::GetBaseURLFromExtensionId(extension_id)); 200 if (site_instance && site_instance->HasProcess()) 201 return false; 202 203 return process_manager->GetRenderViewHostsForExtension(extension_id).empty(); 204} 205 206GURL GetSiteForExtensionId(const std::string& extension_id, 207 content::BrowserContext* context) { 208 return content::SiteInstance::GetSiteForURL( 209 context, Extension::GetBaseURLFromExtensionId(extension_id)); 210} 211 212scoped_ptr<base::DictionaryValue> GetExtensionInfo(const Extension* extension) { 213 DCHECK(extension); 214 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue); 215 216 dict->SetString("id", extension->id()); 217 dict->SetString("name", extension->name()); 218 219 GURL icon = extensions::ExtensionIconSource::GetIconURL( 220 extension, 221 extension_misc::EXTENSION_ICON_SMALLISH, 222 ExtensionIconSet::MATCH_BIGGER, 223 false, // Not grayscale. 224 NULL); // Don't set bool if exists. 225 dict->SetString("icon", icon.spec()); 226 227 return dict.Pass(); 228} 229 230bool HasIsolatedStorage(const ExtensionInfo& info) { 231 if (!info.extension_manifest.get()) 232 return false; 233 234 std::string error; 235 scoped_refptr<const Extension> extension(Extension::Create( 236 info.extension_path, 237 info.extension_location, 238 *info.extension_manifest, 239 Extension::NO_FLAGS, 240 info.extension_id, 241 &error)); 242 if (!extension.get()) 243 return false; 244 245 return AppIsolationInfo::HasIsolatedStorage(extension.get()); 246} 247 248bool SiteHasIsolatedStorage(const GURL& extension_site_url, 249 content::BrowserContext* context) { 250 const Extension* extension = ExtensionRegistry::Get(context)-> 251 enabled_extensions().GetExtensionOrAppByURL(extension_site_url); 252 if (extension) 253 return AppIsolationInfo::HasIsolatedStorage(extension); 254 255 if (extension_site_url.SchemeIs(kExtensionScheme)) { 256 // The site URL may also be from an evicted ephemeral app. We do not 257 // immediately delete their data when they are removed from extension 258 // system. 259 ExtensionPrefs* prefs = ExtensionPrefs::Get(context); 260 DCHECK(prefs); 261 scoped_ptr<ExtensionInfo> info = prefs->GetEvictedEphemeralAppInfo( 262 extension_site_url.host()); 263 if (info.get()) 264 return HasIsolatedStorage(*info); 265 } 266 267 return false; 268} 269 270const gfx::ImageSkia& GetDefaultAppIcon() { 271 return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed( 272 IDR_APP_DEFAULT_ICON); 273} 274 275const gfx::ImageSkia& GetDefaultExtensionIcon() { 276 return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed( 277 IDR_EXTENSION_DEFAULT_ICON); 278} 279 280} // namespace util 281} // namespace extensions 282