Adding Peter Thatcher to the owners file.
[chromium-blink-merge.git] / extensions / common / permissions / permissions_data.cc
blob2202758b172e681a9365d9d0ece38bda285a0de0
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 GURL& top_frame_url,
87 const Extension* extension,
88 std::string* error) {
89 if (extension && CanExecuteScriptEverywhere(extension))
90 return false;
92 // Check if the scheme is valid for extensions. If not, return.
93 if (!URLPattern::IsValidSchemeForExtensions(document_url.scheme()) &&
94 document_url.spec() != url::kAboutBlankURL) {
95 if (error) {
96 *error = ErrorUtils::FormatErrorMessage(
97 manifest_errors::kCannotAccessPage,
98 document_url.spec());
100 return true;
103 if (!ExtensionsClient::Get()->IsScriptableURL(document_url, error))
104 return true;
106 bool allow_on_chrome_urls = base::CommandLine::ForCurrentProcess()->HasSwitch(
107 switches::kExtensionsOnChromeURLs);
108 if (document_url.SchemeIs(content::kChromeUIScheme) &&
109 !allow_on_chrome_urls) {
110 if (error)
111 *error = manifest_errors::kCannotAccessChromeUrl;
112 return true;
115 if (extension && top_frame_url.SchemeIs(kExtensionScheme) &&
116 top_frame_url.host() != extension->id() && !allow_on_chrome_urls) {
117 if (error)
118 *error = manifest_errors::kCannotAccessExtensionUrl;
119 return true;
122 return false;
125 void PermissionsData::SetPermissions(
126 const scoped_refptr<const PermissionSet>& active,
127 const scoped_refptr<const PermissionSet>& withheld) const {
128 base::AutoLock auto_lock(runtime_lock_);
129 active_permissions_unsafe_ = active;
130 withheld_permissions_unsafe_ = withheld;
133 void PermissionsData::UpdateTabSpecificPermissions(
134 int tab_id,
135 scoped_refptr<const PermissionSet> permissions) const {
136 base::AutoLock auto_lock(runtime_lock_);
137 CHECK_GE(tab_id, 0);
138 TabPermissionsMap::iterator iter = tab_specific_permissions_.find(tab_id);
139 if (iter == tab_specific_permissions_.end())
140 tab_specific_permissions_[tab_id] = permissions;
141 else
142 iter->second =
143 PermissionSet::CreateUnion(iter->second.get(), permissions.get());
146 void PermissionsData::ClearTabSpecificPermissions(int tab_id) const {
147 base::AutoLock auto_lock(runtime_lock_);
148 CHECK_GE(tab_id, 0);
149 tab_specific_permissions_.erase(tab_id);
152 bool PermissionsData::HasAPIPermission(APIPermission::ID permission) const {
153 return active_permissions()->HasAPIPermission(permission);
156 bool PermissionsData::HasAPIPermission(
157 const std::string& permission_name) const {
158 return active_permissions()->HasAPIPermission(permission_name);
161 bool PermissionsData::HasAPIPermissionForTab(
162 int tab_id,
163 APIPermission::ID permission) const {
164 if (HasAPIPermission(permission))
165 return true;
167 scoped_refptr<const PermissionSet> tab_permissions =
168 GetTabSpecificPermissions(tab_id);
170 // Place autolock below the HasAPIPermission() and
171 // GetTabSpecificPermissions(), since each already acquires the lock.
172 base::AutoLock auto_lock(runtime_lock_);
173 return tab_permissions.get() && tab_permissions->HasAPIPermission(permission);
176 bool PermissionsData::CheckAPIPermissionWithParam(
177 APIPermission::ID permission,
178 const APIPermission::CheckParam* param) const {
179 return active_permissions()->CheckAPIPermissionWithParam(permission, param);
182 URLPatternSet PermissionsData::GetEffectiveHostPermissions() const {
183 base::AutoLock auto_lock(runtime_lock_);
184 URLPatternSet effective_hosts = active_permissions_unsafe_->effective_hosts();
185 for (const auto& val : tab_specific_permissions_)
186 effective_hosts.AddPatterns(val.second->effective_hosts());
187 return effective_hosts;
190 bool PermissionsData::HasHostPermission(const GURL& url) const {
191 return active_permissions()->HasExplicitAccessToOrigin(url);
194 bool PermissionsData::HasEffectiveAccessToAllHosts() const {
195 return active_permissions()->HasEffectiveAccessToAllHosts();
198 PermissionMessageIDs PermissionsData::GetLegacyPermissionMessageIDs() const {
199 if (ShouldSkipPermissionWarnings(extension_id_)) {
200 return PermissionMessageIDs();
201 } else {
202 return PermissionMessageProvider::Get()->GetLegacyPermissionMessageIDs(
203 active_permissions().get(), manifest_type_);
207 PermissionMessageStrings PermissionsData::GetPermissionMessageStrings() const {
208 if (ShouldSkipPermissionWarnings(extension_id_))
209 return PermissionMessageStrings();
210 return PermissionMessageProvider::Get()->GetPermissionMessageStrings(
211 active_permissions().get(), manifest_type_);
214 std::vector<base::string16> PermissionsData::GetLegacyPermissionMessageStrings()
215 const {
216 if (ShouldSkipPermissionWarnings(extension_id_))
217 return std::vector<base::string16>();
218 return PermissionMessageProvider::Get()->GetLegacyWarningMessages(
219 active_permissions().get(), manifest_type_);
222 std::vector<base::string16>
223 PermissionsData::GetLegacyPermissionMessageDetailsStrings() const {
224 if (ShouldSkipPermissionWarnings(extension_id_))
225 return std::vector<base::string16>();
226 return PermissionMessageProvider::Get()->GetLegacyWarningMessagesDetails(
227 active_permissions().get(), manifest_type_);
230 CoalescedPermissionMessages PermissionsData::GetCoalescedPermissionMessages()
231 const {
232 return PermissionMessageProvider::Get()->GetCoalescedPermissionMessages(
233 PermissionMessageProvider::Get()->GetAllPermissionIDs(
234 active_permissions().get(), manifest_type_));
237 bool PermissionsData::HasWithheldImpliedAllHosts() const {
238 // Since we currently only withhold all_hosts, it's sufficient to check
239 // that either set is not empty.
240 return !withheld_permissions()->explicit_hosts().is_empty() ||
241 !withheld_permissions()->scriptable_hosts().is_empty();
244 bool PermissionsData::CanAccessPage(const Extension* extension,
245 const GURL& document_url,
246 const GURL& top_frame_url,
247 int tab_id,
248 int process_id,
249 std::string* error) const {
250 AccessType result = CanRunOnPage(extension,
251 document_url,
252 top_frame_url,
253 tab_id,
254 process_id,
255 active_permissions()->explicit_hosts(),
256 withheld_permissions()->explicit_hosts(),
257 error);
258 // TODO(rdevlin.cronin) Update callers so that they only need ACCESS_ALLOWED.
259 return result == ACCESS_ALLOWED || result == ACCESS_WITHHELD;
262 PermissionsData::AccessType PermissionsData::GetPageAccess(
263 const Extension* extension,
264 const GURL& document_url,
265 const GURL& top_frame_url,
266 int tab_id,
267 int process_id,
268 std::string* error) const {
269 return CanRunOnPage(extension,
270 document_url,
271 top_frame_url,
272 tab_id,
273 process_id,
274 active_permissions()->explicit_hosts(),
275 withheld_permissions()->explicit_hosts(),
276 error);
279 bool PermissionsData::CanRunContentScriptOnPage(const Extension* extension,
280 const GURL& document_url,
281 const GURL& top_frame_url,
282 int tab_id,
283 int process_id,
284 std::string* error) const {
285 AccessType result = CanRunOnPage(extension,
286 document_url,
287 top_frame_url,
288 tab_id,
289 process_id,
290 active_permissions()->scriptable_hosts(),
291 withheld_permissions()->scriptable_hosts(),
292 error);
293 // TODO(rdevlin.cronin) Update callers so that they only need ACCESS_ALLOWED.
294 return result == ACCESS_ALLOWED || result == ACCESS_WITHHELD;
297 PermissionsData::AccessType PermissionsData::GetContentScriptAccess(
298 const Extension* extension,
299 const GURL& document_url,
300 const GURL& top_frame_url,
301 int tab_id,
302 int process_id,
303 std::string* error) const {
304 return CanRunOnPage(extension,
305 document_url,
306 top_frame_url,
307 tab_id,
308 process_id,
309 active_permissions()->scriptable_hosts(),
310 withheld_permissions()->scriptable_hosts(),
311 error);
314 bool PermissionsData::CanCaptureVisiblePage(int tab_id,
315 std::string* error) const {
316 const URLPattern all_urls(URLPattern::SCHEME_ALL,
317 URLPattern::kAllUrlsPattern);
319 if (active_permissions()->explicit_hosts().ContainsPattern(all_urls))
320 return true;
322 if (tab_id >= 0) {
323 scoped_refptr<const PermissionSet> tab_permissions =
324 GetTabSpecificPermissions(tab_id);
325 if (tab_permissions.get() &&
326 tab_permissions->HasAPIPermission(APIPermission::kTab)) {
327 return true;
329 if (error)
330 *error = manifest_errors::kActiveTabPermissionNotGranted;
331 return false;
334 if (error)
335 *error = manifest_errors::kAllURLOrActiveTabNeeded;
336 return false;
339 scoped_refptr<const PermissionSet> PermissionsData::GetTabSpecificPermissions(
340 int tab_id) const {
341 base::AutoLock auto_lock(runtime_lock_);
342 CHECK_GE(tab_id, 0);
343 TabPermissionsMap::const_iterator iter =
344 tab_specific_permissions_.find(tab_id);
345 return (iter != tab_specific_permissions_.end()) ? iter->second : NULL;
348 bool PermissionsData::HasTabSpecificPermissionToExecuteScript(
349 int tab_id,
350 const GURL& url) const {
351 if (tab_id >= 0) {
352 scoped_refptr<const PermissionSet> tab_permissions =
353 GetTabSpecificPermissions(tab_id);
354 if (tab_permissions.get() &&
355 tab_permissions->explicit_hosts().MatchesSecurityOrigin(url)) {
356 return true;
359 return false;
362 PermissionsData::AccessType PermissionsData::CanRunOnPage(
363 const Extension* extension,
364 const GURL& document_url,
365 const GURL& top_frame_url,
366 int tab_id,
367 int process_id,
368 const URLPatternSet& permitted_url_patterns,
369 const URLPatternSet& withheld_url_patterns,
370 std::string* error) const {
371 if (g_policy_delegate &&
372 !g_policy_delegate->CanExecuteScriptOnPage(
373 extension, document_url, top_frame_url, tab_id, process_id, error)) {
374 return ACCESS_DENIED;
377 if (IsRestrictedUrl(document_url, top_frame_url, extension, error))
378 return ACCESS_DENIED;
380 if (HasTabSpecificPermissionToExecuteScript(tab_id, top_frame_url))
381 return ACCESS_ALLOWED;
383 if (permitted_url_patterns.MatchesURL(document_url))
384 return ACCESS_ALLOWED;
386 if (withheld_url_patterns.MatchesURL(document_url))
387 return ACCESS_WITHHELD;
389 if (error) {
390 *error = ErrorUtils::FormatErrorMessage(manifest_errors::kCannotAccessPage,
391 document_url.spec());
393 return ACCESS_DENIED;
396 } // namespace extensions