Upstreaming browser/ui/uikit_ui_util from iOS.
[chromium-blink-merge.git] / extensions / common / permissions / permissions_data.cc
blob694ccfcf030aec69aaec2cdb63a5d9a32486992b
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_util.h"
17 #include "extensions/common/switches.h"
18 #include "extensions/common/url_pattern_set.h"
19 #include "url/gurl.h"
20 #include "url/url_constants.h"
22 namespace extensions {
24 namespace {
26 PermissionsData::PolicyDelegate* g_policy_delegate = NULL;
28 } // namespace
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() {
46 // static
47 void PermissionsData::SetPolicyDelegate(PolicyDelegate* delegate) {
48 g_policy_delegate = delegate;
51 // static
52 bool PermissionsData::CanExecuteScriptEverywhere(const Extension* extension) {
53 if (extension->location() == Manifest::COMPONENT)
54 return true;
56 const ExtensionsClient::ScriptingWhitelist& whitelist =
57 ExtensionsClient::Get()->GetScriptingWhitelist();
59 return std::find(whitelist.begin(), whitelist.end(), extension->id()) !=
60 whitelist.end();
63 // static
64 bool PermissionsData::ScriptsMayRequireActionForExtension(
65 const Extension* extension,
66 const PermissionSet* permissions) {
67 // An extension may require user action to execute scripts iff the extension
68 // shows up in chrome:extensions (so the user can grant withheld permissions),
69 // is not part of chrome or corporate policy, not on the scripting whitelist,
70 // and requires enough permissions that we should withhold them.
71 return extension->ShouldDisplayInExtensionSettings() &&
72 !Manifest::IsPolicyLocation(extension->location()) &&
73 !Manifest::IsComponentLocation(extension->location()) &&
74 !CanExecuteScriptEverywhere(extension) &&
75 permissions->ShouldWarnAllHosts();
78 bool PermissionsData::ShouldSkipPermissionWarnings(
79 const std::string& extension_id) {
80 // See http://b/4946060 for more details.
81 return extension_id == std::string("nckgahadagoaajjgafhacjanaoiihapd");
84 // static
85 bool PermissionsData::IsRestrictedUrl(const GURL& document_url,
86 const Extension* extension,
87 std::string* error) {
88 if (extension && CanExecuteScriptEverywhere(extension))
89 return false;
91 // Check if the scheme is valid for extensions. If not, return.
92 if (!URLPattern::IsValidSchemeForExtensions(document_url.scheme()) &&
93 document_url.spec() != url::kAboutBlankURL) {
94 if (error) {
95 *error = ErrorUtils::FormatErrorMessage(
96 manifest_errors::kCannotAccessPage,
97 document_url.spec());
99 return true;
102 if (!ExtensionsClient::Get()->IsScriptableURL(document_url, error))
103 return true;
105 bool allow_on_chrome_urls = base::CommandLine::ForCurrentProcess()->HasSwitch(
106 switches::kExtensionsOnChromeURLs);
107 if (document_url.SchemeIs(content::kChromeUIScheme) &&
108 !allow_on_chrome_urls) {
109 if (error)
110 *error = manifest_errors::kCannotAccessChromeUrl;
111 return true;
114 if (extension && document_url.SchemeIs(kExtensionScheme) &&
115 document_url.host() != extension->id() && !allow_on_chrome_urls) {
116 if (error)
117 *error = manifest_errors::kCannotAccessExtensionUrl;
118 return true;
121 return false;
124 void PermissionsData::SetPermissions(
125 const scoped_refptr<const PermissionSet>& active,
126 const scoped_refptr<const PermissionSet>& withheld) const {
127 base::AutoLock auto_lock(runtime_lock_);
128 active_permissions_unsafe_ = active;
129 withheld_permissions_unsafe_ = withheld;
132 void PermissionsData::UpdateTabSpecificPermissions(
133 int tab_id,
134 scoped_refptr<const PermissionSet> permissions) const {
135 base::AutoLock auto_lock(runtime_lock_);
136 CHECK_GE(tab_id, 0);
137 TabPermissionsMap::iterator iter = tab_specific_permissions_.find(tab_id);
138 if (iter == tab_specific_permissions_.end())
139 tab_specific_permissions_[tab_id] = permissions;
140 else
141 iter->second =
142 PermissionSet::CreateUnion(iter->second.get(), permissions.get());
145 void PermissionsData::ClearTabSpecificPermissions(int tab_id) const {
146 base::AutoLock auto_lock(runtime_lock_);
147 CHECK_GE(tab_id, 0);
148 tab_specific_permissions_.erase(tab_id);
151 bool PermissionsData::HasAPIPermission(APIPermission::ID permission) const {
152 return active_permissions()->HasAPIPermission(permission);
155 bool PermissionsData::HasAPIPermission(
156 const std::string& permission_name) const {
157 return active_permissions()->HasAPIPermission(permission_name);
160 bool PermissionsData::HasAPIPermissionForTab(
161 int tab_id,
162 APIPermission::ID permission) const {
163 if (HasAPIPermission(permission))
164 return true;
166 scoped_refptr<const PermissionSet> tab_permissions =
167 GetTabSpecificPermissions(tab_id);
169 // Place autolock below the HasAPIPermission() and
170 // GetTabSpecificPermissions(), since each already acquires the lock.
171 base::AutoLock auto_lock(runtime_lock_);
172 return tab_permissions.get() && tab_permissions->HasAPIPermission(permission);
175 bool PermissionsData::CheckAPIPermissionWithParam(
176 APIPermission::ID permission,
177 const APIPermission::CheckParam* param) const {
178 return active_permissions()->CheckAPIPermissionWithParam(permission, param);
181 URLPatternSet PermissionsData::GetEffectiveHostPermissions() const {
182 base::AutoLock auto_lock(runtime_lock_);
183 URLPatternSet effective_hosts = active_permissions_unsafe_->effective_hosts();
184 for (const auto& val : tab_specific_permissions_)
185 effective_hosts.AddPatterns(val.second->effective_hosts());
186 return effective_hosts;
189 bool PermissionsData::HasHostPermission(const GURL& url) const {
190 return active_permissions()->HasExplicitAccessToOrigin(url);
193 bool PermissionsData::HasEffectiveAccessToAllHosts() const {
194 return active_permissions()->HasEffectiveAccessToAllHosts();
197 CoalescedPermissionMessages PermissionsData::GetPermissionMessages() const {
198 return PermissionMessageProvider::Get()->GetPermissionMessages(
199 PermissionMessageProvider::Get()->GetAllPermissionIDs(
200 active_permissions().get(), manifest_type_));
203 bool PermissionsData::HasWithheldImpliedAllHosts() const {
204 // Since we currently only withhold all_hosts, it's sufficient to check
205 // that either set is not empty.
206 return !withheld_permissions()->explicit_hosts().is_empty() ||
207 !withheld_permissions()->scriptable_hosts().is_empty();
210 bool PermissionsData::CanAccessPage(const Extension* extension,
211 const GURL& document_url,
212 int tab_id,
213 int process_id,
214 std::string* error) const {
215 AccessType result = CanRunOnPage(extension,
216 document_url,
217 tab_id,
218 process_id,
219 active_permissions()->explicit_hosts(),
220 withheld_permissions()->explicit_hosts(),
221 error);
222 // TODO(rdevlin.cronin) Update callers so that they only need ACCESS_ALLOWED.
223 return result == ACCESS_ALLOWED || result == ACCESS_WITHHELD;
226 PermissionsData::AccessType PermissionsData::GetPageAccess(
227 const Extension* extension,
228 const GURL& document_url,
229 int tab_id,
230 int process_id,
231 std::string* error) const {
232 return CanRunOnPage(extension,
233 document_url,
234 tab_id,
235 process_id,
236 active_permissions()->explicit_hosts(),
237 withheld_permissions()->explicit_hosts(),
238 error);
241 bool PermissionsData::CanRunContentScriptOnPage(const Extension* extension,
242 const GURL& document_url,
243 int tab_id,
244 int process_id,
245 std::string* error) const {
246 AccessType result = CanRunOnPage(extension,
247 document_url,
248 tab_id,
249 process_id,
250 active_permissions()->scriptable_hosts(),
251 withheld_permissions()->scriptable_hosts(),
252 error);
253 // TODO(rdevlin.cronin) Update callers so that they only need ACCESS_ALLOWED.
254 return result == ACCESS_ALLOWED || result == ACCESS_WITHHELD;
257 PermissionsData::AccessType PermissionsData::GetContentScriptAccess(
258 const Extension* extension,
259 const GURL& document_url,
260 int tab_id,
261 int process_id,
262 std::string* error) const {
263 return CanRunOnPage(extension,
264 document_url,
265 tab_id,
266 process_id,
267 active_permissions()->scriptable_hosts(),
268 withheld_permissions()->scriptable_hosts(),
269 error);
272 bool PermissionsData::CanCaptureVisiblePage(int tab_id,
273 std::string* error) const {
274 const URLPattern all_urls(URLPattern::SCHEME_ALL,
275 URLPattern::kAllUrlsPattern);
277 if (active_permissions()->explicit_hosts().ContainsPattern(all_urls))
278 return true;
280 if (tab_id >= 0) {
281 scoped_refptr<const PermissionSet> tab_permissions =
282 GetTabSpecificPermissions(tab_id);
283 if (tab_permissions.get() &&
284 tab_permissions->HasAPIPermission(APIPermission::kTab)) {
285 return true;
287 if (error)
288 *error = manifest_errors::kActiveTabPermissionNotGranted;
289 return false;
292 if (error)
293 *error = manifest_errors::kAllURLOrActiveTabNeeded;
294 return false;
297 PermissionsData::TabPermissionsMap
298 PermissionsData::CopyTabSpecificPermissionsMap() const {
299 base::AutoLock auto_lock(runtime_lock_);
300 return tab_specific_permissions_;
303 scoped_refptr<const PermissionSet> PermissionsData::GetTabSpecificPermissions(
304 int tab_id) const {
305 base::AutoLock auto_lock(runtime_lock_);
306 CHECK_GE(tab_id, 0);
307 TabPermissionsMap::const_iterator iter =
308 tab_specific_permissions_.find(tab_id);
309 return (iter != tab_specific_permissions_.end()) ? iter->second : NULL;
312 bool PermissionsData::HasTabSpecificPermissionToExecuteScript(
313 int tab_id,
314 const GURL& url) const {
315 if (tab_id >= 0) {
316 scoped_refptr<const PermissionSet> tab_permissions =
317 GetTabSpecificPermissions(tab_id);
318 if (tab_permissions.get() &&
319 tab_permissions->explicit_hosts().MatchesSecurityOrigin(url)) {
320 return true;
323 return false;
326 PermissionsData::AccessType PermissionsData::CanRunOnPage(
327 const Extension* extension,
328 const GURL& document_url,
329 int tab_id,
330 int process_id,
331 const URLPatternSet& permitted_url_patterns,
332 const URLPatternSet& withheld_url_patterns,
333 std::string* error) const {
334 if (g_policy_delegate &&
335 !g_policy_delegate->CanExecuteScriptOnPage(
336 extension, document_url, tab_id, process_id, error)) {
337 return ACCESS_DENIED;
340 if (IsRestrictedUrl(document_url, extension, error))
341 return ACCESS_DENIED;
343 if (HasTabSpecificPermissionToExecuteScript(tab_id, document_url))
344 return ACCESS_ALLOWED;
346 if (permitted_url_patterns.MatchesURL(document_url))
347 return ACCESS_ALLOWED;
349 if (withheld_url_patterns.MatchesURL(document_url))
350 return ACCESS_WITHHELD;
352 if (error) {
353 *error = ErrorUtils::FormatErrorMessage(manifest_errors::kCannotAccessPage,
354 document_url.spec());
356 return ACCESS_DENIED;
359 } // namespace extensions