1// Copyright (c) 2012 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/api/web_request/web_request_permissions.h" 6 7#include "base/strings/string_util.h" 8#include "base/strings/stringprintf.h" 9#include "content/public/browser/resource_request_info.h" 10#include "extensions/browser/guest_view/web_view/web_view_renderer_state.h" 11#include "extensions/browser/info_map.h" 12#include "extensions/common/constants.h" 13#include "extensions/common/extension.h" 14#include "extensions/common/extension_urls.h" 15#include "extensions/common/permissions/permissions_data.h" 16#include "net/url_request/url_request.h" 17#include "url/gurl.h" 18 19using content::ResourceRequestInfo; 20 21namespace { 22 23// Returns true if the URL is sensitive and requests to this URL must not be 24// modified/canceled by extensions, e.g. because it is targeted to the webstore 25// to check for updates, extension blacklisting, etc. 26bool IsSensitiveURL(const GURL& url) { 27 // TODO(battre) Merge this, CanExtensionAccessURL and 28 // PermissionsData::CanAccessPage into one function. 29 bool sensitive_chrome_url = false; 30 const std::string host = url.host(); 31 const char kGoogleCom[] = ".google.com"; 32 const char kClient[] = "clients"; 33 if (EndsWith(host, kGoogleCom, true)) { 34 // Check for "clients[0-9]*.google.com" hosts. 35 // This protects requests to several internal services such as sync, 36 // extension update pings, captive portal detection, fraudulent certificate 37 // reporting, autofill and others. 38 if (StartsWithASCII(host, kClient, true)) { 39 bool match = true; 40 for (std::string::const_iterator i = host.begin() + strlen(kClient), 41 end = host.end() - strlen(kGoogleCom); i != end; ++i) { 42 if (!isdigit(*i)) { 43 match = false; 44 break; 45 } 46 } 47 sensitive_chrome_url = sensitive_chrome_url || match; 48 } 49 // This protects requests to safe browsing, link doctor, and possibly 50 // others. 51 sensitive_chrome_url = sensitive_chrome_url || 52 EndsWith(url.host(), ".clients.google.com", true) || 53 url.host() == "sb-ssl.google.com" || 54 (url.host() == "chrome.google.com" && 55 StartsWithASCII(url.path(), "/webstore", true)); 56 } 57 GURL::Replacements replacements; 58 replacements.ClearQuery(); 59 replacements.ClearRef(); 60 GURL url_without_query = url.ReplaceComponents(replacements); 61 return sensitive_chrome_url || 62 extension_urls::IsWebstoreUpdateUrl(url_without_query) || 63 extension_urls::IsBlacklistUpdateUrl(url); 64} 65 66// Returns true if the scheme is one we want to allow extensions to have access 67// to. Extensions still need specific permissions for a given URL, which is 68// covered by CanExtensionAccessURL. 69bool HasWebRequestScheme(const GURL& url) { 70 return (url.SchemeIs(url::kAboutScheme) || url.SchemeIs(url::kFileScheme) || 71 url.SchemeIs(url::kFileSystemScheme) || 72 url.SchemeIs(url::kFtpScheme) || url.SchemeIs(url::kHttpScheme) || 73 url.SchemeIs(url::kHttpsScheme) || 74 url.SchemeIs(extensions::kExtensionScheme)); 75} 76 77} // namespace 78 79// static 80bool WebRequestPermissions::HideRequest( 81 const extensions::InfoMap* extension_info_map, 82 const net::URLRequest* request) { 83 // Hide requests from the Chrome WebStore App or signin process. 84 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request); 85 if (info) { 86 int process_id = info->GetChildID(); 87 // Never hide requests from guest processes. 88 if (extensions::WebViewRendererState::GetInstance()->IsGuest(process_id)) 89 return false; 90 91 if (extension_info_map && ( 92 extension_info_map->IsSigninProcess(process_id) || 93 extension_info_map->process_map().Contains( 94 extensions::kWebStoreAppId, process_id))) { 95 return true; 96 } 97 } 98 99 const GURL& url = request->url(); 100 return IsSensitiveURL(url) || !HasWebRequestScheme(url); 101} 102 103// static 104bool WebRequestPermissions::CanExtensionAccessURL( 105 const extensions::InfoMap* extension_info_map, 106 const std::string& extension_id, 107 const GURL& url, 108 bool crosses_incognito, 109 HostPermissionsCheck host_permissions_check) { 110 // extension_info_map can be NULL in testing. 111 if (!extension_info_map) 112 return true; 113 114 const extensions::Extension* extension = 115 extension_info_map->extensions().GetByID(extension_id); 116 if (!extension) 117 return false; 118 119 // Check if this event crosses incognito boundaries when it shouldn't. 120 if (crosses_incognito && !extension_info_map->CanCrossIncognito(extension)) 121 return false; 122 123 switch (host_permissions_check) { 124 case DO_NOT_CHECK_HOST: 125 break; 126 case REQUIRE_HOST_PERMISSION: 127 // about: URLs are not covered in host permissions, but are allowed 128 // anyway. 129 if (!((url.SchemeIs(url::kAboutScheme) || 130 extension->permissions_data()->HasHostPermission(url) || 131 url.GetOrigin() == extension->url()))) { 132 return false; 133 } 134 break; 135 case REQUIRE_ALL_URLS: 136 if (!extension->permissions_data()->HasEffectiveAccessToAllHosts()) 137 return false; 138 break; 139 } 140 141 return true; 142} 143