Fix crash on app list start page contents not existing.
[chromium-blink-merge.git] / extensions / common / permissions / permissions_data.cc
blobdcf2ec729bf63745016c7189836ab1ea9f64810c
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"
20 #include "url/gurl.h"
21 #include "url/url_constants.h"
23 namespace extensions {
25 namespace {
27 PermissionsData::PolicyDelegate* g_policy_delegate = NULL;
29 } // namespace
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() {
47 // static
48 void PermissionsData::SetPolicyDelegate(PolicyDelegate* delegate) {
49 g_policy_delegate = delegate;
52 // static
53 bool PermissionsData::CanExecuteScriptEverywhere(const Extension* extension) {
54 if (extension->location() == Manifest::COMPONENT)
55 return true;
57 const ExtensionsClient::ScriptingWhitelist& whitelist =
58 ExtensionsClient::Get()->GetScriptingWhitelist();
60 return std::find(whitelist.begin(), whitelist.end(), extension->id()) !=
61 whitelist.end();
64 // static
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");
85 // static
86 bool PermissionsData::IsRestrictedUrl(const GURL& document_url,
87 const GURL& top_frame_url,
88 const Extension* extension,
89 std::string* error) {
90 if (extension && CanExecuteScriptEverywhere(extension))
91 return false;
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) {
96 if (error) {
97 *error = ErrorUtils::FormatErrorMessage(
98 manifest_errors::kCannotAccessPage,
99 document_url.spec());
101 return true;
104 if (!ExtensionsClient::Get()->IsScriptableURL(document_url, error))
105 return true;
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) {
111 if (error)
112 *error = manifest_errors::kCannotAccessChromeUrl;
113 return true;
116 if (extension && top_frame_url.SchemeIs(kExtensionScheme) &&
117 top_frame_url.host() != extension->id() && !allow_on_chrome_urls) {
118 if (error)
119 *error = manifest_errors::kCannotAccessExtensionUrl;
120 return true;
123 return false;
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(
135 int tab_id,
136 scoped_refptr<const PermissionSet> permissions) const {
137 base::AutoLock auto_lock(runtime_lock_);
138 CHECK_GE(tab_id, 0);
139 TabPermissionsMap::iterator iter = tab_specific_permissions_.find(tab_id);
140 if (iter == tab_specific_permissions_.end())
141 tab_specific_permissions_[tab_id] = permissions;
142 else
143 iter->second =
144 PermissionSet::CreateUnion(iter->second.get(), permissions.get());
147 void PermissionsData::ClearTabSpecificPermissions(int tab_id) const {
148 base::AutoLock auto_lock(runtime_lock_);
149 CHECK_GE(tab_id, 0);
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(
163 int tab_id,
164 APIPermission::ID permission) const {
165 if (HasAPIPermission(permission))
166 return true;
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();
202 } else {
203 return PermissionMessageProvider::Get()->GetPermissionMessages(
204 active_permissions().get(), manifest_type_);
208 std::vector<base::string16> PermissionsData::GetPermissionMessageStrings()
209 const {
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()
225 const {
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,
241 int tab_id,
242 int process_id,
243 std::string* error) const {
244 AccessType result = CanRunOnPage(extension,
245 document_url,
246 top_frame_url,
247 tab_id,
248 process_id,
249 active_permissions()->explicit_hosts(),
250 withheld_permissions()->explicit_hosts(),
251 error);
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,
260 int tab_id,
261 int process_id,
262 std::string* error) const {
263 return CanRunOnPage(extension,
264 document_url,
265 top_frame_url,
266 tab_id,
267 process_id,
268 active_permissions()->explicit_hosts(),
269 withheld_permissions()->explicit_hosts(),
270 error);
273 bool PermissionsData::CanRunContentScriptOnPage(const Extension* extension,
274 const GURL& document_url,
275 const GURL& top_frame_url,
276 int tab_id,
277 int process_id,
278 std::string* error) const {
279 AccessType result = CanRunOnPage(extension,
280 document_url,
281 top_frame_url,
282 tab_id,
283 process_id,
284 active_permissions()->scriptable_hosts(),
285 withheld_permissions()->scriptable_hosts(),
286 error);
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,
295 int tab_id,
296 int process_id,
297 std::string* error) const {
298 return CanRunOnPage(extension,
299 document_url,
300 top_frame_url,
301 tab_id,
302 process_id,
303 active_permissions()->scriptable_hosts(),
304 withheld_permissions()->scriptable_hosts(),
305 error);
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))
314 return true;
316 if (tab_id >= 0) {
317 scoped_refptr<const PermissionSet> tab_permissions =
318 GetTabSpecificPermissions(tab_id);
319 if (tab_permissions.get() &&
320 tab_permissions->HasAPIPermission(APIPermission::kTab)) {
321 return true;
323 if (error)
324 *error = manifest_errors::kActiveTabPermissionNotGranted;
325 return false;
328 if (error)
329 *error = manifest_errors::kAllURLOrActiveTabNeeded;
330 return false;
333 scoped_refptr<const PermissionSet> PermissionsData::GetTabSpecificPermissions(
334 int tab_id) const {
335 base::AutoLock auto_lock(runtime_lock_);
336 CHECK_GE(tab_id, 0);
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(
343 int tab_id,
344 const GURL& url) const {
345 if (tab_id >= 0) {
346 scoped_refptr<const PermissionSet> tab_permissions =
347 GetTabSpecificPermissions(tab_id);
348 if (tab_permissions.get() &&
349 tab_permissions->explicit_hosts().MatchesSecurityOrigin(url)) {
350 return true;
353 return false;
356 PermissionsData::AccessType PermissionsData::CanRunOnPage(
357 const Extension* extension,
358 const GURL& document_url,
359 const GURL& top_frame_url,
360 int tab_id,
361 int process_id,
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;
383 if (error) {
384 *error = ErrorUtils::FormatErrorMessage(manifest_errors::kCannotAccessPage,
385 document_url.spec());
387 return ACCESS_DENIED;
390 } // namespace extensions