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/extension.h"
12 #include "extensions/common/extensions_client.h"
13 #include "extensions/common/manifest.h"
14 #include "extensions/common/manifest_constants.h"
15 #include "extensions/common/manifest_handlers/permissions_parser.h"
16 #include "extensions/common/permissions/permission_message_provider.h"
17 #include "extensions/common/permissions/permission_message_util.h"
18 #include "extensions/common/switches.h"
19 #include "extensions/common/url_pattern_set.h"
21 #include "url/url_constants.h"
23 namespace extensions
{
27 PermissionsData::PolicyDelegate
* g_policy_delegate
= NULL
;
31 PermissionsData::PermissionsData(const Extension
* extension
)
32 : extension_id_(extension
->id()), manifest_type_(extension
->GetType()) {
33 base::AutoLock
auto_lock(runtime_lock_
);
34 scoped_refptr
<const PermissionSet
> required_permissions
=
35 PermissionsParser::GetRequiredPermissions(extension
);
36 active_permissions_unsafe_
=
37 new PermissionSet(required_permissions
->apis(),
38 required_permissions
->manifest_permissions(),
39 required_permissions
->explicit_hosts(),
40 required_permissions
->scriptable_hosts());
41 withheld_permissions_unsafe_
= new PermissionSet();
44 PermissionsData::~PermissionsData() {
48 void PermissionsData::SetPolicyDelegate(PolicyDelegate
* delegate
) {
49 g_policy_delegate
= delegate
;
53 bool PermissionsData::CanExecuteScriptEverywhere(const Extension
* extension
) {
54 if (extension
->location() == Manifest::COMPONENT
)
57 const ExtensionsClient::ScriptingWhitelist
& whitelist
=
58 ExtensionsClient::Get()->GetScriptingWhitelist();
60 return std::find(whitelist
.begin(), whitelist
.end(), extension
->id()) !=
65 bool PermissionsData::ScriptsMayRequireActionForExtension(
66 const Extension
* extension
,
67 const PermissionSet
* permissions
) {
68 // An extension may require user action to execute scripts iff the extension
69 // shows up in chrome:extensions (so the user can grant withheld permissions),
70 // is not part of chrome or corporate policy, not on the scripting whitelist,
71 // and requires enough permissions that we should withhold them.
72 return extension
->ShouldDisplayInExtensionSettings() &&
73 !Manifest::IsPolicyLocation(extension
->location()) &&
74 !Manifest::IsComponentLocation(extension
->location()) &&
75 !CanExecuteScriptEverywhere(extension
) &&
76 permissions
->ShouldWarnAllHosts();
79 bool PermissionsData::ShouldSkipPermissionWarnings(
80 const std::string
& extension_id
) {
81 // See http://b/4946060 for more details.
82 return extension_id
== std::string("nckgahadagoaajjgafhacjanaoiihapd");
86 bool PermissionsData::IsRestrictedUrl(const GURL
& document_url
,
87 const GURL
& top_frame_url
,
88 const Extension
* extension
,
90 if (extension
&& CanExecuteScriptEverywhere(extension
))
93 // Check if the scheme is valid for extensions. If not, return.
94 if (!URLPattern::IsValidSchemeForExtensions(document_url
.scheme()) &&
95 document_url
.spec() != url::kAboutBlankURL
) {
97 *error
= ErrorUtils::FormatErrorMessage(
98 manifest_errors::kCannotAccessPage
,
104 if (!ExtensionsClient::Get()->IsScriptableURL(document_url
, error
))
107 bool allow_on_chrome_urls
= base::CommandLine::ForCurrentProcess()->HasSwitch(
108 switches::kExtensionsOnChromeURLs
);
109 if (document_url
.SchemeIs(content::kChromeUIScheme
) &&
110 !allow_on_chrome_urls
) {
112 *error
= manifest_errors::kCannotAccessChromeUrl
;
116 if (extension
&& top_frame_url
.SchemeIs(kExtensionScheme
) &&
117 top_frame_url
.host() != extension
->id() && !allow_on_chrome_urls
) {
119 *error
= manifest_errors::kCannotAccessExtensionUrl
;
126 void PermissionsData::SetPermissions(
127 const scoped_refptr
<const PermissionSet
>& active
,
128 const scoped_refptr
<const PermissionSet
>& withheld
) const {
129 base::AutoLock
auto_lock(runtime_lock_
);
130 active_permissions_unsafe_
= active
;
131 withheld_permissions_unsafe_
= withheld
;
134 void PermissionsData::UpdateTabSpecificPermissions(
136 scoped_refptr
<const PermissionSet
> permissions
) const {
137 base::AutoLock
auto_lock(runtime_lock_
);
139 TabPermissionsMap::iterator iter
= tab_specific_permissions_
.find(tab_id
);
140 if (iter
== tab_specific_permissions_
.end())
141 tab_specific_permissions_
[tab_id
] = permissions
;
144 PermissionSet::CreateUnion(iter
->second
.get(), permissions
.get());
147 void PermissionsData::ClearTabSpecificPermissions(int tab_id
) const {
148 base::AutoLock
auto_lock(runtime_lock_
);
150 tab_specific_permissions_
.erase(tab_id
);
153 bool PermissionsData::HasAPIPermission(APIPermission::ID permission
) const {
154 return active_permissions()->HasAPIPermission(permission
);
157 bool PermissionsData::HasAPIPermission(
158 const std::string
& permission_name
) const {
159 return active_permissions()->HasAPIPermission(permission_name
);
162 bool PermissionsData::HasAPIPermissionForTab(
164 APIPermission::ID permission
) const {
165 if (HasAPIPermission(permission
))
168 scoped_refptr
<const PermissionSet
> tab_permissions
=
169 GetTabSpecificPermissions(tab_id
);
171 // Place autolock below the HasAPIPermission() and
172 // GetTabSpecificPermissions(), since each already acquires the lock.
173 base::AutoLock
auto_lock(runtime_lock_
);
174 return tab_permissions
.get() && tab_permissions
->HasAPIPermission(permission
);
177 bool PermissionsData::CheckAPIPermissionWithParam(
178 APIPermission::ID permission
,
179 const APIPermission::CheckParam
* param
) const {
180 return active_permissions()->CheckAPIPermissionWithParam(permission
, param
);
183 URLPatternSet
PermissionsData::GetEffectiveHostPermissions() const {
184 base::AutoLock
auto_lock(runtime_lock_
);
185 URLPatternSet effective_hosts
= active_permissions_unsafe_
->effective_hosts();
186 for (const auto& val
: tab_specific_permissions_
)
187 effective_hosts
.AddPatterns(val
.second
->effective_hosts());
188 return effective_hosts
;
191 bool PermissionsData::HasHostPermission(const GURL
& url
) const {
192 return active_permissions()->HasExplicitAccessToOrigin(url
);
195 bool PermissionsData::HasEffectiveAccessToAllHosts() const {
196 return active_permissions()->HasEffectiveAccessToAllHosts();
199 PermissionMessages
PermissionsData::GetPermissionMessages() const {
200 if (ShouldSkipPermissionWarnings(extension_id_
)) {
201 return PermissionMessages();
203 return PermissionMessageProvider::Get()->GetPermissionMessages(
204 active_permissions().get(), manifest_type_
);
208 std::vector
<base::string16
> PermissionsData::GetPermissionMessageStrings()
210 if (ShouldSkipPermissionWarnings(extension_id_
))
211 return std::vector
<base::string16
>();
212 return PermissionMessageProvider::Get()->GetWarningMessages(
213 active_permissions().get(), manifest_type_
);
216 std::vector
<base::string16
>
217 PermissionsData::GetPermissionMessageDetailsStrings() const {
218 if (ShouldSkipPermissionWarnings(extension_id_
))
219 return std::vector
<base::string16
>();
220 return PermissionMessageProvider::Get()->GetWarningMessagesDetails(
221 active_permissions().get(), manifest_type_
);
224 CoalescedPermissionMessages
PermissionsData::GetCoalescedPermissionMessages()
226 return PermissionMessageProvider::Get()->GetCoalescedPermissionMessages(
227 PermissionMessageProvider::Get()->GetAllPermissionIDs(
228 active_permissions().get(), manifest_type_
));
231 bool PermissionsData::HasWithheldImpliedAllHosts() const {
232 // Since we currently only withhold all_hosts, it's sufficient to check
233 // that either set is not empty.
234 return !withheld_permissions()->explicit_hosts().is_empty() ||
235 !withheld_permissions()->scriptable_hosts().is_empty();
238 bool PermissionsData::CanAccessPage(const Extension
* extension
,
239 const GURL
& document_url
,
240 const GURL
& top_frame_url
,
243 std::string
* error
) const {
244 AccessType result
= CanRunOnPage(extension
,
249 active_permissions()->explicit_hosts(),
250 withheld_permissions()->explicit_hosts(),
252 // TODO(rdevlin.cronin) Update callers so that they only need ACCESS_ALLOWED.
253 return result
== ACCESS_ALLOWED
|| result
== ACCESS_WITHHELD
;
256 PermissionsData::AccessType
PermissionsData::GetPageAccess(
257 const Extension
* extension
,
258 const GURL
& document_url
,
259 const GURL
& top_frame_url
,
262 std::string
* error
) const {
263 return CanRunOnPage(extension
,
268 active_permissions()->explicit_hosts(),
269 withheld_permissions()->explicit_hosts(),
273 bool PermissionsData::CanRunContentScriptOnPage(const Extension
* extension
,
274 const GURL
& document_url
,
275 const GURL
& top_frame_url
,
278 std::string
* error
) const {
279 AccessType result
= CanRunOnPage(extension
,
284 active_permissions()->scriptable_hosts(),
285 withheld_permissions()->scriptable_hosts(),
287 // TODO(rdevlin.cronin) Update callers so that they only need ACCESS_ALLOWED.
288 return result
== ACCESS_ALLOWED
|| result
== ACCESS_WITHHELD
;
291 PermissionsData::AccessType
PermissionsData::GetContentScriptAccess(
292 const Extension
* extension
,
293 const GURL
& document_url
,
294 const GURL
& top_frame_url
,
297 std::string
* error
) const {
298 return CanRunOnPage(extension
,
303 active_permissions()->scriptable_hosts(),
304 withheld_permissions()->scriptable_hosts(),
308 bool PermissionsData::CanCaptureVisiblePage(int tab_id
,
309 std::string
* error
) const {
310 const URLPattern
all_urls(URLPattern::SCHEME_ALL
,
311 URLPattern::kAllUrlsPattern
);
313 if (active_permissions()->explicit_hosts().ContainsPattern(all_urls
))
317 scoped_refptr
<const PermissionSet
> tab_permissions
=
318 GetTabSpecificPermissions(tab_id
);
319 if (tab_permissions
.get() &&
320 tab_permissions
->HasAPIPermission(APIPermission::kTab
)) {
324 *error
= manifest_errors::kActiveTabPermissionNotGranted
;
329 *error
= manifest_errors::kAllURLOrActiveTabNeeded
;
333 scoped_refptr
<const PermissionSet
> PermissionsData::GetTabSpecificPermissions(
335 base::AutoLock
auto_lock(runtime_lock_
);
337 TabPermissionsMap::const_iterator iter
=
338 tab_specific_permissions_
.find(tab_id
);
339 return (iter
!= tab_specific_permissions_
.end()) ? iter
->second
: NULL
;
342 bool PermissionsData::HasTabSpecificPermissionToExecuteScript(
344 const GURL
& url
) const {
346 scoped_refptr
<const PermissionSet
> tab_permissions
=
347 GetTabSpecificPermissions(tab_id
);
348 if (tab_permissions
.get() &&
349 tab_permissions
->explicit_hosts().MatchesSecurityOrigin(url
)) {
356 PermissionsData::AccessType
PermissionsData::CanRunOnPage(
357 const Extension
* extension
,
358 const GURL
& document_url
,
359 const GURL
& top_frame_url
,
362 const URLPatternSet
& permitted_url_patterns
,
363 const URLPatternSet
& withheld_url_patterns
,
364 std::string
* error
) const {
365 if (g_policy_delegate
&&
366 !g_policy_delegate
->CanExecuteScriptOnPage(
367 extension
, document_url
, top_frame_url
, tab_id
, process_id
, error
)) {
368 return ACCESS_DENIED
;
371 if (IsRestrictedUrl(document_url
, top_frame_url
, extension
, error
))
372 return ACCESS_DENIED
;
374 if (HasTabSpecificPermissionToExecuteScript(tab_id
, top_frame_url
))
375 return ACCESS_ALLOWED
;
377 if (permitted_url_patterns
.MatchesURL(document_url
))
378 return ACCESS_ALLOWED
;
380 if (withheld_url_patterns
.MatchesURL(document_url
))
381 return ACCESS_WITHHELD
;
384 *error
= ErrorUtils::FormatErrorMessage(manifest_errors::kCannotAccessPage
,
385 document_url
.spec());
387 return ACCESS_DENIED
;
390 } // namespace extensions