permissions_data.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
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.
4
5#include "extensions/common/permissions/permissions_data.h"
6
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"
19#include "url/gurl.h"
20#include "url/url_constants.h"
21
22namespace extensions {
23
24namespace {
25
26PermissionsData::PolicyDelegate* g_policy_delegate = NULL;
27
28}  // namespace
29
30PermissionsData::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();
41}
42
43PermissionsData::~PermissionsData() {
44}
45
46// static
47void PermissionsData::SetPolicyDelegate(PolicyDelegate* delegate) {
48  g_policy_delegate = delegate;
49}
50
51// static
52bool PermissionsData::CanSilentlyIncreasePermissions(
53    const Extension* extension) {
54  return extension->location() != Manifest::INTERNAL;
55}
56
57// static
58bool PermissionsData::CanExecuteScriptEverywhere(const Extension* extension) {
59  if (extension->location() == Manifest::COMPONENT)
60    return true;
61
62  const ExtensionsClient::ScriptingWhitelist& whitelist =
63      ExtensionsClient::Get()->GetScriptingWhitelist();
64
65  return std::find(whitelist.begin(), whitelist.end(), extension->id()) !=
66         whitelist.end();
67}
68
69bool PermissionsData::ShouldSkipPermissionWarnings(
70    const std::string& extension_id) {
71  // See http://b/4946060 for more details.
72  return extension_id == std::string("nckgahadagoaajjgafhacjanaoiihapd");
73}
74
75// static
76bool PermissionsData::IsRestrictedUrl(const GURL& document_url,
77                                      const GURL& top_frame_url,
78                                      const Extension* extension,
79                                      std::string* error) {
80  if (extension && CanExecuteScriptEverywhere(extension))
81    return false;
82
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) {
86    if (error) {
87      *error = ErrorUtils::FormatErrorMessage(
88                   manifest_errors::kCannotAccessPage,
89                   document_url.spec());
90    }
91    return true;
92  }
93
94  if (!ExtensionsClient::Get()->IsScriptableURL(document_url, error))
95    return true;
96
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) {
101    if (error)
102      *error = manifest_errors::kCannotAccessChromeUrl;
103    return true;
104  }
105
106  if (extension && top_frame_url.SchemeIs(kExtensionScheme) &&
107      top_frame_url.host() != extension->id() && !allow_on_chrome_urls) {
108    if (error)
109      *error = manifest_errors::kCannotAccessExtensionUrl;
110    return true;
111  }
112
113  return false;
114}
115
116void 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;
122}
123
124void PermissionsData::UpdateTabSpecificPermissions(
125    int tab_id,
126    scoped_refptr<const PermissionSet> permissions) const {
127  base::AutoLock auto_lock(runtime_lock_);
128  CHECK_GE(tab_id, 0);
129  TabPermissionsMap::iterator iter = tab_specific_permissions_.find(tab_id);
130  if (iter == tab_specific_permissions_.end())
131    tab_specific_permissions_[tab_id] = permissions;
132  else
133    iter->second = PermissionSet::CreateUnion(iter->second, permissions);
134}
135
136void PermissionsData::ClearTabSpecificPermissions(int tab_id) const {
137  base::AutoLock auto_lock(runtime_lock_);
138  CHECK_GE(tab_id, 0);
139  tab_specific_permissions_.erase(tab_id);
140}
141
142bool PermissionsData::HasAPIPermission(APIPermission::ID permission) const {
143  return active_permissions()->HasAPIPermission(permission);
144}
145
146bool PermissionsData::HasAPIPermission(
147    const std::string& permission_name) const {
148  return active_permissions()->HasAPIPermission(permission_name);
149}
150
151bool PermissionsData::HasAPIPermissionForTab(
152    int tab_id,
153    APIPermission::ID permission) const {
154  if (HasAPIPermission(permission))
155    return true;
156
157  scoped_refptr<const PermissionSet> tab_permissions =
158      GetTabSpecificPermissions(tab_id);
159
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);
164}
165
166bool PermissionsData::CheckAPIPermissionWithParam(
167    APIPermission::ID permission,
168    const APIPermission::CheckParam* param) const {
169  return active_permissions()->CheckAPIPermissionWithParam(permission, param);
170}
171
172const URLPatternSet& PermissionsData::GetEffectiveHostPermissions() const {
173  return active_permissions()->effective_hosts();
174}
175
176bool PermissionsData::HasHostPermission(const GURL& url) const {
177  return active_permissions()->HasExplicitAccessToOrigin(url);
178}
179
180bool PermissionsData::HasEffectiveAccessToAllHosts() const {
181  return active_permissions()->HasEffectiveAccessToAllHosts();
182}
183
184PermissionMessages PermissionsData::GetPermissionMessages() const {
185  if (ShouldSkipPermissionWarnings(extension_id_)) {
186    return PermissionMessages();
187  } else {
188    return PermissionMessageProvider::Get()->GetPermissionMessages(
189        active_permissions(), manifest_type_);
190  }
191}
192
193std::vector<base::string16> PermissionsData::GetPermissionMessageStrings()
194    const {
195  if (ShouldSkipPermissionWarnings(extension_id_))
196    return std::vector<base::string16>();
197  return PermissionMessageProvider::Get()->GetWarningMessages(
198      active_permissions(), manifest_type_);
199}
200
201std::vector<base::string16>
202PermissionsData::GetPermissionMessageDetailsStrings() const {
203  if (ShouldSkipPermissionWarnings(extension_id_))
204    return std::vector<base::string16>();
205  return PermissionMessageProvider::Get()->GetWarningMessagesDetails(
206      active_permissions(), manifest_type_);
207}
208
209bool 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();
214}
215
216bool PermissionsData::CanAccessPage(const Extension* extension,
217                                    const GURL& document_url,
218                                    const GURL& top_frame_url,
219                                    int tab_id,
220                                    int process_id,
221                                    std::string* error) const {
222  AccessType result = CanRunOnPage(extension,
223                                   document_url,
224                                   top_frame_url,
225                                   tab_id,
226                                   process_id,
227                                   active_permissions()->explicit_hosts(),
228                                   withheld_permissions()->explicit_hosts(),
229                                   error);
230  // TODO(rdevlin.cronin) Update callers so that they only need ACCESS_ALLOWED.
231  return result == ACCESS_ALLOWED || result == ACCESS_WITHHELD;
232}
233
234PermissionsData::AccessType PermissionsData::GetPageAccess(
235    const Extension* extension,
236    const GURL& document_url,
237    const GURL& top_frame_url,
238    int tab_id,
239    int process_id,
240    std::string* error) const {
241  return CanRunOnPage(extension,
242                      document_url,
243                      top_frame_url,
244                      tab_id,
245                      process_id,
246                      active_permissions()->explicit_hosts(),
247                      withheld_permissions()->explicit_hosts(),
248                      error);
249}
250
251bool PermissionsData::CanRunContentScriptOnPage(const Extension* extension,
252                                                const GURL& document_url,
253                                                const GURL& top_frame_url,
254                                                int tab_id,
255                                                int process_id,
256                                                std::string* error) const {
257  AccessType result = CanRunOnPage(extension,
258                                   document_url,
259                                   top_frame_url,
260                                   tab_id,
261                                   process_id,
262                                   active_permissions()->scriptable_hosts(),
263                                   withheld_permissions()->scriptable_hosts(),
264                                   error);
265  // TODO(rdevlin.cronin) Update callers so that they only need ACCESS_ALLOWED.
266  return result == ACCESS_ALLOWED || result == ACCESS_WITHHELD;
267}
268
269PermissionsData::AccessType PermissionsData::GetContentScriptAccess(
270    const Extension* extension,
271    const GURL& document_url,
272    const GURL& top_frame_url,
273    int tab_id,
274    int process_id,
275    std::string* error) const {
276  return CanRunOnPage(extension,
277                      document_url,
278                      top_frame_url,
279                      tab_id,
280                      process_id,
281                      active_permissions()->scriptable_hosts(),
282                      withheld_permissions()->scriptable_hosts(),
283                      error);
284}
285
286bool PermissionsData::CanCaptureVisiblePage(int tab_id,
287                                            std::string* error) const {
288  const URLPattern all_urls(URLPattern::SCHEME_ALL,
289                            URLPattern::kAllUrlsPattern);
290
291  if (active_permissions()->explicit_hosts().ContainsPattern(all_urls))
292    return true;
293
294  if (tab_id >= 0) {
295    scoped_refptr<const PermissionSet> tab_permissions =
296        GetTabSpecificPermissions(tab_id);
297    if (tab_permissions &&
298        tab_permissions->HasAPIPermission(APIPermission::kTab)) {
299      return true;
300    }
301    if (error)
302      *error = manifest_errors::kActiveTabPermissionNotGranted;
303    return false;
304  }
305
306  if (error)
307    *error = manifest_errors::kAllURLOrActiveTabNeeded;
308  return false;
309}
310
311scoped_refptr<const PermissionSet> PermissionsData::GetTabSpecificPermissions(
312    int tab_id) const {
313  base::AutoLock auto_lock(runtime_lock_);
314  CHECK_GE(tab_id, 0);
315  TabPermissionsMap::const_iterator iter =
316      tab_specific_permissions_.find(tab_id);
317  return (iter != tab_specific_permissions_.end()) ? iter->second : NULL;
318}
319
320bool PermissionsData::HasTabSpecificPermissionToExecuteScript(
321    int tab_id,
322    const GURL& url) const {
323  if (tab_id >= 0) {
324    scoped_refptr<const PermissionSet> tab_permissions =
325        GetTabSpecificPermissions(tab_id);
326    if (tab_permissions.get() &&
327        tab_permissions->explicit_hosts().MatchesSecurityOrigin(url)) {
328      return true;
329    }
330  }
331  return false;
332}
333
334PermissionsData::AccessType PermissionsData::CanRunOnPage(
335    const Extension* extension,
336    const GURL& document_url,
337    const GURL& top_frame_url,
338    int tab_id,
339    int process_id,
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;
347  }
348
349  if (IsRestrictedUrl(document_url, top_frame_url, extension, error))
350    return ACCESS_DENIED;
351
352  if (HasTabSpecificPermissionToExecuteScript(tab_id, top_frame_url))
353    return ACCESS_ALLOWED;
354
355  if (permitted_url_patterns.MatchesURL(document_url))
356    return ACCESS_ALLOWED;
357
358  if (withheld_url_patterns.MatchesURL(document_url))
359    return ACCESS_WITHHELD;
360
361  if (error) {
362    *error = ErrorUtils::FormatErrorMessage(manifest_errors::kCannotAccessPage,
363                                            document_url.spec());
364  }
365  return ACCESS_DENIED;
366}
367
368}  // namespace extensions
369