Supervised user import: Listen for profile creation/deletion
[chromium-blink-merge.git] / chrome / common / extensions / chrome_extensions_client.cc
blob7d8860882faaa8ffb4cb15cb542dc48877cce620
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.
5 #include "chrome/common/extensions/chrome_extensions_client.h"
7 #include "base/command_line.h"
8 #include "base/files/file_path.h"
9 #include "base/metrics/histogram_macros.h"
10 #include "base/strings/string_util.h"
11 #include "base/values.h"
12 #include "chrome/common/chrome_switches.h"
13 #include "chrome/common/chrome_version_info.h"
14 #include "chrome/common/extensions/api/extension_action/action_info.h"
15 #include "chrome/common/extensions/api/generated_schemas.h"
16 #include "chrome/common/extensions/chrome_manifest_handlers.h"
17 #include "chrome/common/extensions/extension_constants.h"
18 #include "chrome/common/extensions/features/chrome_channel_feature_filter.h"
19 #include "chrome/common/extensions/features/feature_channel.h"
20 #include "chrome/common/extensions/manifest_handlers/theme_handler.h"
21 #include "chrome/common/url_constants.h"
22 #include "chrome/grit/chromium_strings.h"
23 #include "chrome/grit/common_resources.h"
24 #include "chrome/grit/extensions_api_resources.h"
25 #include "chrome/grit/generated_resources.h"
26 #include "content/public/common/url_constants.h"
27 #include "extensions/common/api/generated_schemas.h"
28 #include "extensions/common/common_manifest_handlers.h"
29 #include "extensions/common/constants.h"
30 #include "extensions/common/extension.h"
31 #include "extensions/common/extension_api.h"
32 #include "extensions/common/extension_icon_set.h"
33 #include "extensions/common/extension_urls.h"
34 #include "extensions/common/features/api_feature.h"
35 #include "extensions/common/features/base_feature_provider.h"
36 #include "extensions/common/features/behavior_feature.h"
37 #include "extensions/common/features/feature_provider.h"
38 #include "extensions/common/features/json_feature_provider_source.h"
39 #include "extensions/common/features/manifest_feature.h"
40 #include "extensions/common/features/permission_feature.h"
41 #include "extensions/common/features/simple_feature.h"
42 #include "extensions/common/manifest_constants.h"
43 #include "extensions/common/manifest_handler.h"
44 #include "extensions/common/manifest_handlers/icons_handler.h"
45 #include "extensions/common/permissions/api_permission_set.h"
46 #include "extensions/common/permissions/permission_message.h"
47 #include "extensions/common/permissions/permissions_info.h"
48 #include "extensions/common/url_pattern.h"
49 #include "extensions/common/url_pattern_set.h"
50 #include "extensions/grit/extensions_resources.h"
51 #include "ui/base/l10n/l10n_util.h"
52 #include "url/gurl.h"
54 namespace extensions {
56 namespace {
58 // TODO(battre): Delete the HTTP URL once the blacklist is downloaded via HTTPS.
59 const char kExtensionBlocklistUrlPrefix[] =
60 "http://www.gstatic.com/chrome/extensions/blacklist";
61 const char kExtensionBlocklistHttpsUrlPrefix[] =
62 "https://www.gstatic.com/chrome/extensions/blacklist";
64 const char kThumbsWhiteListedExtension[] = "khopmbdjffemhegeeobelklnbglcdgfh";
66 template <class FeatureClass>
67 SimpleFeature* CreateFeature() {
68 SimpleFeature* feature = new FeatureClass;
69 feature->AddFilter(
70 scoped_ptr<SimpleFeatureFilter>(new ChromeChannelFeatureFilter(feature)));
71 return feature;
74 // Mirrors chrome::VersionInfo for histograms.
75 enum ChromeChannelForHistogram {
76 CHANNEL_UNKNOWN,
77 CHANNEL_CANARY,
78 CHANNEL_DEV,
79 CHANNEL_BETA,
80 CHANNEL_STABLE,
81 NUM_CHANNELS_FOR_HISTOGRAM
84 ChromeChannelForHistogram GetChromeChannelForHistogram(
85 chrome::VersionInfo::Channel channel) {
86 switch (channel) {
87 case chrome::VersionInfo::CHANNEL_UNKNOWN:
88 return CHANNEL_UNKNOWN;
89 case chrome::VersionInfo::CHANNEL_CANARY:
90 return CHANNEL_CANARY;
91 case chrome::VersionInfo::CHANNEL_DEV:
92 return CHANNEL_DEV;
93 case chrome::VersionInfo::CHANNEL_BETA:
94 return CHANNEL_BETA;
95 case chrome::VersionInfo::CHANNEL_STABLE:
96 return CHANNEL_STABLE;
98 NOTREACHED() << channel;
99 return CHANNEL_UNKNOWN;
102 } // namespace
104 static base::LazyInstance<ChromeExtensionsClient> g_client =
105 LAZY_INSTANCE_INITIALIZER;
107 ChromeExtensionsClient::ChromeExtensionsClient()
108 : chrome_api_permissions_(ChromeAPIPermissions()),
109 extensions_api_permissions_(ExtensionsAPIPermissions()) {
112 ChromeExtensionsClient::~ChromeExtensionsClient() {
115 void ChromeExtensionsClient::Initialize() {
116 // Registration could already be finalized in unit tests, where the utility
117 // thread runs in-process.
118 if (!ManifestHandler::IsRegistrationFinalized()) {
119 RegisterCommonManifestHandlers();
120 RegisterChromeManifestHandlers();
121 ManifestHandler::FinalizeRegistration();
124 // Set up permissions.
125 PermissionsInfo::GetInstance()->AddProvider(chrome_api_permissions_);
126 PermissionsInfo::GetInstance()->AddProvider(extensions_api_permissions_);
128 // Set up the scripting whitelist.
129 // Whitelist ChromeVox, an accessibility extension from Google that needs
130 // the ability to script webui pages. This is temporary and is not
131 // meant to be a general solution.
132 // TODO(dmazzoni): remove this once we have an extension API that
133 // allows any extension to request read-only access to webui pages.
134 scripting_whitelist_.push_back(extension_misc::kChromeVoxExtensionId);
137 const PermissionMessageProvider&
138 ChromeExtensionsClient::GetPermissionMessageProvider() const {
139 return permission_message_provider_;
142 const std::string ChromeExtensionsClient::GetProductName() {
143 return l10n_util::GetStringUTF8(IDS_PRODUCT_NAME);
146 scoped_ptr<FeatureProvider> ChromeExtensionsClient::CreateFeatureProvider(
147 const std::string& name) const {
148 scoped_ptr<FeatureProvider> provider;
149 scoped_ptr<JSONFeatureProviderSource> source(
150 CreateFeatureProviderSource(name));
151 if (name == "api") {
152 provider.reset(new BaseFeatureProvider(source->dictionary(),
153 CreateFeature<APIFeature>));
154 } else if (name == "manifest") {
155 provider.reset(new BaseFeatureProvider(source->dictionary(),
156 CreateFeature<ManifestFeature>));
157 } else if (name == "permission") {
158 provider.reset(new BaseFeatureProvider(source->dictionary(),
159 CreateFeature<PermissionFeature>));
160 } else if (name == "behavior") {
161 provider.reset(new BaseFeatureProvider(source->dictionary(),
162 CreateFeature<BehaviorFeature>));
163 } else {
164 NOTREACHED();
166 return provider.Pass();
169 scoped_ptr<JSONFeatureProviderSource>
170 ChromeExtensionsClient::CreateFeatureProviderSource(
171 const std::string& name) const {
172 scoped_ptr<JSONFeatureProviderSource> source(
173 new JSONFeatureProviderSource(name));
174 if (name == "api") {
175 source->LoadJSON(IDR_EXTENSION_API_FEATURES);
176 source->LoadJSON(IDR_CHROME_EXTENSION_API_FEATURES);
177 } else if (name == "manifest") {
178 source->LoadJSON(IDR_EXTENSION_MANIFEST_FEATURES);
179 source->LoadJSON(IDR_CHROME_EXTENSION_MANIFEST_FEATURES);
180 } else if (name == "permission") {
181 source->LoadJSON(IDR_EXTENSION_PERMISSION_FEATURES);
182 source->LoadJSON(IDR_CHROME_EXTENSION_PERMISSION_FEATURES);
183 } else if (name == "behavior") {
184 source->LoadJSON(IDR_EXTENSION_BEHAVIOR_FEATURES);
185 } else {
186 NOTREACHED();
187 source.reset();
189 return source.Pass();
192 void ChromeExtensionsClient::FilterHostPermissions(
193 const URLPatternSet& hosts,
194 URLPatternSet* new_hosts,
195 std::set<PermissionMessage>* messages) const {
196 // When editing this function, be sure to add the same functionality to
197 // FilterHostPermissions() below.
198 // TODO(sashab): Deprecate and remove this function.
199 for (URLPatternSet::const_iterator i = hosts.begin();
200 i != hosts.end(); ++i) {
201 // Filters out every URL pattern that matches chrome:// scheme.
202 if (i->scheme() == content::kChromeUIScheme) {
203 // chrome://favicon is the only URL for chrome:// scheme that we
204 // want to support. We want to deprecate the "chrome" scheme.
205 // We should not add any additional "host" here.
206 if (GURL(chrome::kChromeUIFaviconURL).host() != i->host())
207 continue;
208 messages->insert(PermissionMessage(
209 PermissionMessage::kFavicon,
210 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_FAVICON)));
211 } else {
212 new_hosts->AddPattern(*i);
217 void ChromeExtensionsClient::FilterHostPermissions(
218 const URLPatternSet& hosts,
219 URLPatternSet* new_hosts,
220 PermissionIDSet* permissions) const {
221 // When editing this function, be sure to add the same functionality to
222 // FilterHostPermissions() above.
223 for (URLPatternSet::const_iterator i = hosts.begin(); i != hosts.end(); ++i) {
224 // Filters out every URL pattern that matches chrome:// scheme.
225 if (i->scheme() == content::kChromeUIScheme) {
226 // chrome://favicon is the only URL for chrome:// scheme that we
227 // want to support. We want to deprecate the "chrome" scheme.
228 // We should not add any additional "host" here.
229 if (GURL(chrome::kChromeUIFaviconURL).host() != i->host())
230 continue;
231 permissions->insert(APIPermission::kFavicon);
232 } else {
233 new_hosts->AddPattern(*i);
238 void ChromeExtensionsClient::SetScriptingWhitelist(
239 const ExtensionsClient::ScriptingWhitelist& whitelist) {
240 scripting_whitelist_ = whitelist;
243 const ExtensionsClient::ScriptingWhitelist&
244 ChromeExtensionsClient::GetScriptingWhitelist() const {
245 return scripting_whitelist_;
248 URLPatternSet ChromeExtensionsClient::GetPermittedChromeSchemeHosts(
249 const Extension* extension,
250 const APIPermissionSet& api_permissions) const {
251 URLPatternSet hosts;
252 // Regular extensions are only allowed access to chrome://favicon.
253 hosts.AddPattern(URLPattern(URLPattern::SCHEME_CHROMEUI,
254 chrome::kChromeUIFaviconURL));
256 // Experimental extensions are also allowed chrome://thumb.
258 // TODO: A public API should be created for retrieving thumbnails.
259 // See http://crbug.com/222856. A temporary hack is implemented here to
260 // make chrome://thumbs available to NTP Russia extension as
261 // non-experimental.
262 if ((api_permissions.find(APIPermission::kExperimental) !=
263 api_permissions.end()) ||
264 (extension->id() == kThumbsWhiteListedExtension &&
265 extension->from_webstore())) {
266 hosts.AddPattern(URLPattern(URLPattern::SCHEME_CHROMEUI,
267 chrome::kChromeUIThumbnailURL));
269 return hosts;
272 bool ChromeExtensionsClient::IsScriptableURL(
273 const GURL& url, std::string* error) const {
274 // The gallery is special-cased as a restricted URL for scripting to prevent
275 // access to special JS bindings we expose to the gallery (and avoid things
276 // like extensions removing the "report abuse" link).
277 // TODO(erikkay): This seems like the wrong test. Shouldn't we we testing
278 // against the store app extent?
279 GURL store_url(extension_urls::GetWebstoreLaunchURL());
280 if (url.host() == store_url.host()) {
281 if (error)
282 *error = manifest_errors::kCannotScriptGallery;
283 return false;
285 return true;
288 bool ChromeExtensionsClient::IsAPISchemaGenerated(
289 const std::string& name) const {
290 // Test from most common to least common.
291 return api::GeneratedSchemas::IsGenerated(name) ||
292 core_api::GeneratedSchemas::IsGenerated(name);
295 base::StringPiece ChromeExtensionsClient::GetAPISchema(
296 const std::string& name) const {
297 // Test from most common to least common.
298 if (api::GeneratedSchemas::IsGenerated(name))
299 return api::GeneratedSchemas::Get(name);
301 return core_api::GeneratedSchemas::Get(name);
304 void ChromeExtensionsClient::RegisterAPISchemaResources(
305 ExtensionAPI* api) const {
306 api->RegisterSchemaResource("accessibilityPrivate",
307 IDR_EXTENSION_API_JSON_ACCESSIBILITYPRIVATE);
308 api->RegisterSchemaResource("app", IDR_EXTENSION_API_JSON_APP);
309 api->RegisterSchemaResource("browserAction",
310 IDR_EXTENSION_API_JSON_BROWSERACTION);
311 api->RegisterSchemaResource("commands", IDR_EXTENSION_API_JSON_COMMANDS);
312 api->RegisterSchemaResource("declarativeContent",
313 IDR_EXTENSION_API_JSON_DECLARATIVE_CONTENT);
314 api->RegisterSchemaResource("fileBrowserHandler",
315 IDR_EXTENSION_API_JSON_FILEBROWSERHANDLER);
316 api->RegisterSchemaResource("inputMethodPrivate",
317 IDR_EXTENSION_API_JSON_INPUTMETHODPRIVATE);
318 api->RegisterSchemaResource("pageAction", IDR_EXTENSION_API_JSON_PAGEACTION);
319 api->RegisterSchemaResource("privacy", IDR_EXTENSION_API_JSON_PRIVACY);
320 api->RegisterSchemaResource("processes", IDR_EXTENSION_API_JSON_PROCESSES);
321 api->RegisterSchemaResource("proxy", IDR_EXTENSION_API_JSON_PROXY);
322 api->RegisterSchemaResource("ttsEngine", IDR_EXTENSION_API_JSON_TTSENGINE);
323 api->RegisterSchemaResource("tts", IDR_EXTENSION_API_JSON_TTS);
324 api->RegisterSchemaResource("types", IDR_EXTENSION_API_JSON_TYPES);
325 api->RegisterSchemaResource("types.private",
326 IDR_EXTENSION_API_JSON_TYPES_PRIVATE);
327 api->RegisterSchemaResource("webstore", IDR_EXTENSION_API_JSON_WEBSTORE);
330 bool ChromeExtensionsClient::ShouldSuppressFatalErrors() const {
331 // Suppress fatal everywhere until the cause of bugs like http://crbug/471599
332 // are fixed. This would typically be:
333 // return GetCurrentChannel() > chrome::VersionInfo::CHANNEL_DEV;
334 return true;
337 void ChromeExtensionsClient::RecordDidSuppressFatalError() {
338 UMA_HISTOGRAM_ENUMERATION("Extensions.DidSuppressJavaScriptException",
339 GetChromeChannelForHistogram(GetCurrentChannel()),
340 NUM_CHANNELS_FOR_HISTOGRAM);
343 std::string ChromeExtensionsClient::GetWebstoreBaseURL() const {
344 std::string gallery_prefix = extension_urls::kChromeWebstoreBaseURL;
345 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
346 switches::kAppsGalleryURL))
347 gallery_prefix =
348 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
349 switches::kAppsGalleryURL);
350 if (EndsWith(gallery_prefix, "/", true))
351 gallery_prefix = gallery_prefix.substr(0, gallery_prefix.length() - 1);
352 return gallery_prefix;
355 std::string ChromeExtensionsClient::GetWebstoreUpdateURL() const {
356 base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
357 if (cmdline->HasSwitch(switches::kAppsGalleryUpdateURL))
358 return cmdline->GetSwitchValueASCII(switches::kAppsGalleryUpdateURL);
359 else
360 return extension_urls::GetDefaultWebstoreUpdateUrl().spec();
363 bool ChromeExtensionsClient::IsBlacklistUpdateURL(const GURL& url) const {
364 // The extension blacklist URL is returned from the update service and
365 // therefore not determined by Chromium. If the location of the blacklist file
366 // ever changes, we need to update this function. A DCHECK in the
367 // ExtensionUpdater ensures that we notice a change. This is the full URL
368 // of a blacklist:
369 // http://www.gstatic.com/chrome/extensions/blacklist/l_0_0_0_7.txt
370 return StartsWithASCII(url.spec(), kExtensionBlocklistUrlPrefix, true) ||
371 StartsWithASCII(url.spec(), kExtensionBlocklistHttpsUrlPrefix, true);
374 std::set<base::FilePath> ChromeExtensionsClient::GetBrowserImagePaths(
375 const Extension* extension) {
376 std::set<base::FilePath> image_paths =
377 ExtensionsClient::GetBrowserImagePaths(extension);
379 // Theme images
380 const base::DictionaryValue* theme_images =
381 extensions::ThemeInfo::GetImages(extension);
382 if (theme_images) {
383 for (base::DictionaryValue::Iterator it(*theme_images); !it.IsAtEnd();
384 it.Advance()) {
385 base::FilePath::StringType path;
386 if (it.value().GetAsString(&path))
387 image_paths.insert(base::FilePath(path));
391 const extensions::ActionInfo* page_action =
392 extensions::ActionInfo::GetPageActionInfo(extension);
393 if (page_action && !page_action->default_icon.empty())
394 page_action->default_icon.GetPaths(&image_paths);
396 const extensions::ActionInfo* browser_action =
397 extensions::ActionInfo::GetBrowserActionInfo(extension);
398 if (browser_action && !browser_action->default_icon.empty())
399 browser_action->default_icon.GetPaths(&image_paths);
401 return image_paths;
404 // static
405 ChromeExtensionsClient* ChromeExtensionsClient::GetInstance() {
406 return g_client.Pointer();
409 } // namespace extensions