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.
5 #include "extensions/common/permissions/permissions_data.h"
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"
20 #include "url/url_constants.h"
22 namespace extensions {
26 PermissionsData::PolicyDelegate* g_policy_delegate = NULL;
30 PermissionsData::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();
43 PermissionsData::~PermissionsData() {
47 void PermissionsData::SetPolicyDelegate(PolicyDelegate* delegate) {
48 g_policy_delegate = delegate;
52 bool PermissionsData::CanSilentlyIncreasePermissions(
53 const Extension* extension) {
54 return extension->location() != Manifest::INTERNAL;
58 bool PermissionsData::CanExecuteScriptEverywhere(const Extension* extension) {
59 if (extension->location() == Manifest::COMPONENT)
62 const ExtensionsClient::ScriptingWhitelist& whitelist =
63 ExtensionsClient::Get()->GetScriptingWhitelist();
65 return std::find(whitelist.begin(), whitelist.end(), extension->id()) !=
69 bool PermissionsData::ShouldSkipPermissionWarnings(
70 const std::string& extension_id) {
71 // See http://b/4946060 for more details.
72 return extension_id == std::string("nckgahadagoaajjgafhacjanaoiihapd");
76 bool PermissionsData::IsRestrictedUrl(const GURL& document_url,
77 const GURL& top_frame_url,
78 const Extension* extension,
80 if (extension && CanExecuteScriptEverywhere(extension))
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) {
87 *error = ErrorUtils::FormatErrorMessage(
88 manifest_errors::kCannotAccessPage,
94 if (!ExtensionsClient::Get()->IsScriptableURL(document_url, error))
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) {
102 *error = manifest_errors::kCannotAccessChromeUrl;
106 if (extension && top_frame_url.SchemeIs(kExtensionScheme) &&
107 top_frame_url.host() != extension->id() && !allow_on_chrome_urls) {
109 *error = manifest_errors::kCannotAccessExtensionUrl;
116 void 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;
124 void PermissionsData::UpdateTabSpecificPermissions(
126 scoped_refptr<const PermissionSet> permissions) const {
127 base::AutoLock auto_lock(runtime_lock_);
129 TabPermissionsMap::iterator iter = tab_specific_permissions_.find(tab_id);
130 if (iter == tab_specific_permissions_.end())
131 tab_specific_permissions_[tab_id] = permissions;
133 iter->second = PermissionSet::CreateUnion(iter->second, permissions);
136 void PermissionsData::ClearTabSpecificPermissions(int tab_id) const {
137 base::AutoLock auto_lock(runtime_lock_);
139 tab_specific_permissions_.erase(tab_id);
142 bool PermissionsData::HasAPIPermission(APIPermission::ID permission) const {
143 return active_permissions()->HasAPIPermission(permission);
146 bool PermissionsData::HasAPIPermission(
147 const std::string& permission_name) const {
148 return active_permissions()->HasAPIPermission(permission_name);
151 bool PermissionsData::HasAPIPermissionForTab(
153 APIPermission::ID permission) const {
154 if (HasAPIPermission(permission))
157 scoped_refptr<const PermissionSet> tab_permissions =
158 GetTabSpecificPermissions(tab_id);
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);
166 bool PermissionsData::CheckAPIPermissionWithParam(
167 APIPermission::ID permission,
168 const APIPermission::CheckParam* param) const {
169 return active_permissions()->CheckAPIPermissionWithParam(permission, param);
172 const URLPatternSet& PermissionsData::GetEffectiveHostPermissions() const {
173 return active_permissions()->effective_hosts();
176 bool PermissionsData::HasHostPermission(const GURL& url) const {
177 return active_permissions()->HasExplicitAccessToOrigin(url);
180 bool PermissionsData::HasEffectiveAccessToAllHosts() const {
181 return active_permissions()->HasEffectiveAccessToAllHosts();
184 PermissionMessages PermissionsData::GetPermissionMessages() const {
185 if (ShouldSkipPermissionWarnings(extension_id_)) {
186 return PermissionMessages();
188 return PermissionMessageProvider::Get()->GetPermissionMessages(
189 active_permissions(), manifest_type_);
193 std::vector<base::string16> PermissionsData::GetPermissionMessageStrings()
195 if (ShouldSkipPermissionWarnings(extension_id_))
196 return std::vector<base::string16>();
197 return PermissionMessageProvider::Get()->GetWarningMessages(
198 active_permissions(), manifest_type_);
201 std::vector<base::string16>
202 PermissionsData::GetPermissionMessageDetailsStrings() const {
203 if (ShouldSkipPermissionWarnings(extension_id_))
204 return std::vector<base::string16>();
205 return PermissionMessageProvider::Get()->GetWarningMessagesDetails(
206 active_permissions(), manifest_type_);
209 bool 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();
216 bool PermissionsData::CanAccessPage(const Extension* extension,
217 const GURL& document_url,
218 const GURL& top_frame_url,
221 std::string* error) const {
222 AccessType result = CanRunOnPage(extension,
227 active_permissions()->explicit_hosts(),
228 withheld_permissions()->explicit_hosts(),
230 // TODO(rdevlin.cronin) Update callers so that they only need ACCESS_ALLOWED.
231 return result == ACCESS_ALLOWED || result == ACCESS_WITHHELD;
234 PermissionsData::AccessType PermissionsData::GetPageAccess(
235 const Extension* extension,
236 const GURL& document_url,
237 const GURL& top_frame_url,
240 std::string* error) const {
241 return CanRunOnPage(extension,
246 active_permissions()->explicit_hosts(),
247 withheld_permissions()->explicit_hosts(),
251 bool PermissionsData::CanRunContentScriptOnPage(const Extension* extension,
252 const GURL& document_url,
253 const GURL& top_frame_url,
256 std::string* error) const {
257 AccessType result = CanRunOnPage(extension,
262 active_permissions()->scriptable_hosts(),
263 withheld_permissions()->scriptable_hosts(),
265 // TODO(rdevlin.cronin) Update callers so that they only need ACCESS_ALLOWED.
266 return result == ACCESS_ALLOWED || result == ACCESS_WITHHELD;
269 PermissionsData::AccessType PermissionsData::GetContentScriptAccess(
270 const Extension* extension,
271 const GURL& document_url,
272 const GURL& top_frame_url,
275 std::string* error) const {
276 return CanRunOnPage(extension,
281 active_permissions()->scriptable_hosts(),
282 withheld_permissions()->scriptable_hosts(),
286 bool PermissionsData::CanCaptureVisiblePage(int tab_id,
287 std::string* error) const {
288 const URLPattern all_urls(URLPattern::SCHEME_ALL,
289 URLPattern::kAllUrlsPattern);
291 if (active_permissions()->explicit_hosts().ContainsPattern(all_urls))
295 scoped_refptr<const PermissionSet> tab_permissions =
296 GetTabSpecificPermissions(tab_id);
297 if (tab_permissions &&
298 tab_permissions->HasAPIPermission(APIPermission::kTab)) {
302 *error = manifest_errors::kActiveTabPermissionNotGranted;
307 *error = manifest_errors::kAllURLOrActiveTabNeeded;
311 scoped_refptr<const PermissionSet> PermissionsData::GetTabSpecificPermissions(
313 base::AutoLock auto_lock(runtime_lock_);
315 TabPermissionsMap::const_iterator iter =
316 tab_specific_permissions_.find(tab_id);
317 return (iter != tab_specific_permissions_.end()) ? iter->second : NULL;
320 bool PermissionsData::HasTabSpecificPermissionToExecuteScript(
322 const GURL& url) const {
324 scoped_refptr<const PermissionSet> tab_permissions =
325 GetTabSpecificPermissions(tab_id);
326 if (tab_permissions.get() &&
327 tab_permissions->explicit_hosts().MatchesSecurityOrigin(url)) {
334 PermissionsData::AccessType PermissionsData::CanRunOnPage(
335 const Extension* extension,
336 const GURL& document_url,
337 const GURL& top_frame_url,
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;
349 if (IsRestrictedUrl(document_url, top_frame_url, extension, error))
350 return ACCESS_DENIED;
352 if (HasTabSpecificPermissionToExecuteScript(tab_id, top_frame_url))
353 return ACCESS_ALLOWED;
355 if (permitted_url_patterns.MatchesURL(document_url))
356 return ACCESS_ALLOWED;
358 if (withheld_url_patterns.MatchesURL(document_url))
359 return ACCESS_WITHHELD;
362 *error = ErrorUtils::FormatErrorMessage(manifest_errors::kCannotAccessPage,
363 document_url.spec());
365 return ACCESS_DENIED;
368 } // namespace extensions