permissions_data.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
1// Copyright (c) 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 "extensions/common/permissions/permissions_data.h" 6 7#include "base/command_line.h" 8#include "content/public/common/url_constants.h" 9#include "extensions/common/constants.h" 10#include "extensions/common/error_utils.h" 11#include "extensions/common/extensions_client.h" 12#include "extensions/common/manifest.h" 13#include "extensions/common/manifest_constants.h" 14#include "extensions/common/manifest_handlers/permissions_parser.h" 15#include "extensions/common/permissions/permission_message_provider.h" 16#include "extensions/common/switches.h" 17#include "extensions/common/url_pattern_set.h" 18#include "extensions/common/user_script.h" 19#include "url/gurl.h" 20#include "url/url_constants.h" 21 22namespace extensions { 23 24namespace { 25 26PermissionsData::PolicyDelegate* g_policy_delegate = NULL; 27 28} // namespace 29 30PermissionsData::PermissionsData(const Extension* extension) 31 : extension_id_(extension->id()), manifest_type_(extension->GetType()) { 32 base::AutoLock auto_lock(runtime_lock_); 33 scoped_refptr<const PermissionSet> required_permissions = 34 PermissionsParser::GetRequiredPermissions(extension); 35 active_permissions_unsafe_ = 36 new PermissionSet(required_permissions->apis(), 37 required_permissions->manifest_permissions(), 38 required_permissions->explicit_hosts(), 39 required_permissions->scriptable_hosts()); 40 withheld_permissions_unsafe_ = new PermissionSet(); 41} 42 43PermissionsData::~PermissionsData() { 44} 45 46// static 47void PermissionsData::SetPolicyDelegate(PolicyDelegate* delegate) { 48 g_policy_delegate = delegate; 49} 50 51// static 52bool PermissionsData::CanSilentlyIncreasePermissions( 53 const Extension* extension) { 54 return extension->location() != Manifest::INTERNAL; 55} 56 57// static 58bool PermissionsData::CanExecuteScriptEverywhere(const Extension* extension) { 59 if (extension->location() == Manifest::COMPONENT) 60 return true; 61 62 const ExtensionsClient::ScriptingWhitelist& whitelist = 63 ExtensionsClient::Get()->GetScriptingWhitelist(); 64 65 return std::find(whitelist.begin(), whitelist.end(), extension->id()) != 66 whitelist.end(); 67} 68 69bool PermissionsData::ShouldSkipPermissionWarnings( 70 const std::string& extension_id) { 71 // See http://b/4946060 for more details. 72 return extension_id == std::string("nckgahadagoaajjgafhacjanaoiihapd"); 73} 74 75// static 76bool PermissionsData::IsRestrictedUrl(const GURL& document_url, 77 const GURL& top_frame_url, 78 const Extension* extension, 79 std::string* error) { 80 if (extension && CanExecuteScriptEverywhere(extension)) 81 return false; 82 83 // Check if the scheme is valid for extensions. If not, return. 84 if (!URLPattern::IsValidSchemeForExtensions(document_url.scheme()) && 85 document_url.spec() != url::kAboutBlankURL) { 86 if (error) { 87 *error = ErrorUtils::FormatErrorMessage( 88 manifest_errors::kCannotAccessPage, 89 document_url.spec()); 90 } 91 return true; 92 } 93 94 if (!ExtensionsClient::Get()->IsScriptableURL(document_url, error)) 95 return true; 96 97 bool allow_on_chrome_urls = base::CommandLine::ForCurrentProcess()->HasSwitch( 98 switches::kExtensionsOnChromeURLs); 99 if (document_url.SchemeIs(content::kChromeUIScheme) && 100 !allow_on_chrome_urls) { 101 if (error) 102 *error = manifest_errors::kCannotAccessChromeUrl; 103 return true; 104 } 105 106 if (extension && top_frame_url.SchemeIs(kExtensionScheme) && 107 top_frame_url.host() != extension->id() && !allow_on_chrome_urls) { 108 if (error) 109 *error = manifest_errors::kCannotAccessExtensionUrl; 110 return true; 111 } 112 113 return false; 114} 115 116void PermissionsData::SetPermissions( 117 const scoped_refptr<const PermissionSet>& active, 118 const scoped_refptr<const PermissionSet>& withheld) const { 119 base::AutoLock auto_lock(runtime_lock_); 120 active_permissions_unsafe_ = active; 121 withheld_permissions_unsafe_ = withheld; 122} 123 124void PermissionsData::UpdateTabSpecificPermissions( 125 int tab_id, 126 scoped_refptr<const PermissionSet> permissions) const { 127 base::AutoLock auto_lock(runtime_lock_); 128 CHECK_GE(tab_id, 0); 129 TabPermissionsMap::iterator iter = tab_specific_permissions_.find(tab_id); 130 if (iter == tab_specific_permissions_.end()) 131 tab_specific_permissions_[tab_id] = permissions; 132 else 133 iter->second = PermissionSet::CreateUnion(iter->second, permissions); 134} 135 136void PermissionsData::ClearTabSpecificPermissions(int tab_id) const { 137 base::AutoLock auto_lock(runtime_lock_); 138 CHECK_GE(tab_id, 0); 139 tab_specific_permissions_.erase(tab_id); 140} 141 142bool PermissionsData::HasAPIPermission(APIPermission::ID permission) const { 143 return active_permissions()->HasAPIPermission(permission); 144} 145 146bool PermissionsData::HasAPIPermission( 147 const std::string& permission_name) const { 148 return active_permissions()->HasAPIPermission(permission_name); 149} 150 151bool PermissionsData::HasAPIPermissionForTab( 152 int tab_id, 153 APIPermission::ID permission) const { 154 if (HasAPIPermission(permission)) 155 return true; 156 157 scoped_refptr<const PermissionSet> tab_permissions = 158 GetTabSpecificPermissions(tab_id); 159 160 // Place autolock below the HasAPIPermission() and 161 // GetTabSpecificPermissions(), since each already acquires the lock. 162 base::AutoLock auto_lock(runtime_lock_); 163 return tab_permissions.get() && tab_permissions->HasAPIPermission(permission); 164} 165 166bool PermissionsData::CheckAPIPermissionWithParam( 167 APIPermission::ID permission, 168 const APIPermission::CheckParam* param) const { 169 return active_permissions()->CheckAPIPermissionWithParam(permission, param); 170} 171 172const URLPatternSet& PermissionsData::GetEffectiveHostPermissions() const { 173 return active_permissions()->effective_hosts(); 174} 175 176bool PermissionsData::HasHostPermission(const GURL& url) const { 177 return active_permissions()->HasExplicitAccessToOrigin(url); 178} 179 180bool PermissionsData::HasEffectiveAccessToAllHosts() const { 181 return active_permissions()->HasEffectiveAccessToAllHosts(); 182} 183 184PermissionMessages PermissionsData::GetPermissionMessages() const { 185 if (ShouldSkipPermissionWarnings(extension_id_)) { 186 return PermissionMessages(); 187 } else { 188 return PermissionMessageProvider::Get()->GetPermissionMessages( 189 active_permissions(), manifest_type_); 190 } 191} 192 193std::vector<base::string16> PermissionsData::GetPermissionMessageStrings() 194 const { 195 if (ShouldSkipPermissionWarnings(extension_id_)) 196 return std::vector<base::string16>(); 197 return PermissionMessageProvider::Get()->GetWarningMessages( 198 active_permissions(), manifest_type_); 199} 200 201std::vector<base::string16> 202PermissionsData::GetPermissionMessageDetailsStrings() const { 203 if (ShouldSkipPermissionWarnings(extension_id_)) 204 return std::vector<base::string16>(); 205 return PermissionMessageProvider::Get()->GetWarningMessagesDetails( 206 active_permissions(), manifest_type_); 207} 208 209bool PermissionsData::HasWithheldImpliedAllHosts() const { 210 // Since we currently only withhold all_hosts, it's sufficient to check 211 // that either set is not empty. 212 return !withheld_permissions()->explicit_hosts().is_empty() || 213 !withheld_permissions()->scriptable_hosts().is_empty(); 214} 215 216bool PermissionsData::CanAccessPage(const Extension* extension, 217 const GURL& document_url, 218 const GURL& top_frame_url, 219 int tab_id, 220 int process_id, 221 std::string* error) const { 222 AccessType result = CanRunOnPage(extension, 223 document_url, 224 top_frame_url, 225 tab_id, 226 process_id, 227 active_permissions()->explicit_hosts(), 228 withheld_permissions()->explicit_hosts(), 229 error); 230 // TODO(rdevlin.cronin) Update callers so that they only need ACCESS_ALLOWED. 231 return result == ACCESS_ALLOWED || result == ACCESS_WITHHELD; 232} 233 234PermissionsData::AccessType PermissionsData::GetPageAccess( 235 const Extension* extension, 236 const GURL& document_url, 237 const GURL& top_frame_url, 238 int tab_id, 239 int process_id, 240 std::string* error) const { 241 return CanRunOnPage(extension, 242 document_url, 243 top_frame_url, 244 tab_id, 245 process_id, 246 active_permissions()->explicit_hosts(), 247 withheld_permissions()->explicit_hosts(), 248 error); 249} 250 251bool PermissionsData::CanRunContentScriptOnPage(const Extension* extension, 252 const GURL& document_url, 253 const GURL& top_frame_url, 254 int tab_id, 255 int process_id, 256 std::string* error) const { 257 AccessType result = CanRunOnPage(extension, 258 document_url, 259 top_frame_url, 260 tab_id, 261 process_id, 262 active_permissions()->scriptable_hosts(), 263 withheld_permissions()->scriptable_hosts(), 264 error); 265 // TODO(rdevlin.cronin) Update callers so that they only need ACCESS_ALLOWED. 266 return result == ACCESS_ALLOWED || result == ACCESS_WITHHELD; 267} 268 269PermissionsData::AccessType PermissionsData::GetContentScriptAccess( 270 const Extension* extension, 271 const GURL& document_url, 272 const GURL& top_frame_url, 273 int tab_id, 274 int process_id, 275 std::string* error) const { 276 return CanRunOnPage(extension, 277 document_url, 278 top_frame_url, 279 tab_id, 280 process_id, 281 active_permissions()->scriptable_hosts(), 282 withheld_permissions()->scriptable_hosts(), 283 error); 284} 285 286bool PermissionsData::CanCaptureVisiblePage(int tab_id, 287 std::string* error) const { 288 const URLPattern all_urls(URLPattern::SCHEME_ALL, 289 URLPattern::kAllUrlsPattern); 290 291 if (active_permissions()->explicit_hosts().ContainsPattern(all_urls)) 292 return true; 293 294 if (tab_id >= 0) { 295 scoped_refptr<const PermissionSet> tab_permissions = 296 GetTabSpecificPermissions(tab_id); 297 if (tab_permissions && 298 tab_permissions->HasAPIPermission(APIPermission::kTab)) { 299 return true; 300 } 301 if (error) 302 *error = manifest_errors::kActiveTabPermissionNotGranted; 303 return false; 304 } 305 306 if (error) 307 *error = manifest_errors::kAllURLOrActiveTabNeeded; 308 return false; 309} 310 311scoped_refptr<const PermissionSet> PermissionsData::GetTabSpecificPermissions( 312 int tab_id) const { 313 base::AutoLock auto_lock(runtime_lock_); 314 CHECK_GE(tab_id, 0); 315 TabPermissionsMap::const_iterator iter = 316 tab_specific_permissions_.find(tab_id); 317 return (iter != tab_specific_permissions_.end()) ? iter->second : NULL; 318} 319 320bool PermissionsData::HasTabSpecificPermissionToExecuteScript( 321 int tab_id, 322 const GURL& url) const { 323 if (tab_id >= 0) { 324 scoped_refptr<const PermissionSet> tab_permissions = 325 GetTabSpecificPermissions(tab_id); 326 if (tab_permissions.get() && 327 tab_permissions->explicit_hosts().MatchesSecurityOrigin(url)) { 328 return true; 329 } 330 } 331 return false; 332} 333 334PermissionsData::AccessType PermissionsData::CanRunOnPage( 335 const Extension* extension, 336 const GURL& document_url, 337 const GURL& top_frame_url, 338 int tab_id, 339 int process_id, 340 const URLPatternSet& permitted_url_patterns, 341 const URLPatternSet& withheld_url_patterns, 342 std::string* error) const { 343 if (g_policy_delegate && 344 !g_policy_delegate->CanExecuteScriptOnPage( 345 extension, document_url, top_frame_url, tab_id, process_id, error)) { 346 return ACCESS_DENIED; 347 } 348 349 if (IsRestrictedUrl(document_url, top_frame_url, extension, error)) 350 return ACCESS_DENIED; 351 352 if (HasTabSpecificPermissionToExecuteScript(tab_id, top_frame_url)) 353 return ACCESS_ALLOWED; 354 355 if (permitted_url_patterns.MatchesURL(document_url)) 356 return ACCESS_ALLOWED; 357 358 if (withheld_url_patterns.MatchesURL(document_url)) 359 return ACCESS_WITHHELD; 360 361 if (error) { 362 *error = ErrorUtils::FormatErrorMessage(manifest_errors::kCannotAccessPage, 363 document_url.spec()); 364 } 365 return ACCESS_DENIED; 366} 367 368} // namespace extensions 369