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}
41
42PermissionsData::~PermissionsData() {
43}
44
45// static
46void PermissionsData::SetPolicyDelegate(PolicyDelegate* delegate) {
47  g_policy_delegate = delegate;
48}
49
50// static
51bool PermissionsData::CanSilentlyIncreasePermissions(
52    const Extension* extension) {
53  return extension->location() != Manifest::INTERNAL;
54}
55
56// static
57bool PermissionsData::CanExecuteScriptEverywhere(const Extension* extension) {
58  if (extension->location() == Manifest::COMPONENT)
59    return true;
60
61  const ExtensionsClient::ScriptingWhitelist& whitelist =
62      ExtensionsClient::Get()->GetScriptingWhitelist();
63
64  return std::find(whitelist.begin(), whitelist.end(), extension->id()) !=
65         whitelist.end();
66}
67
68bool PermissionsData::ShouldSkipPermissionWarnings(
69    const std::string& extension_id) {
70  // See http://b/4946060 for more details.
71  return extension_id == std::string("nckgahadagoaajjgafhacjanaoiihapd");
72}
73
74// static
75bool PermissionsData::IsRestrictedUrl(const GURL& document_url,
76                                      const GURL& top_frame_url,
77                                      const Extension* extension,
78                                      std::string* error) {
79  if (CanExecuteScriptEverywhere(extension))
80    return false;
81
82  // Check if the scheme is valid for extensions. If not, return.
83  if (!URLPattern::IsValidSchemeForExtensions(document_url.scheme()) &&
84      document_url.spec() != url::kAboutBlankURL) {
85    if (error) {
86      *error = ErrorUtils::FormatErrorMessage(
87                   manifest_errors::kCannotAccessPage,
88                   document_url.spec());
89    }
90    return true;
91  }
92
93  if (!ExtensionsClient::Get()->IsScriptableURL(document_url, error))
94    return true;
95
96  bool allow_on_chrome_urls = base::CommandLine::ForCurrentProcess()->HasSwitch(
97                                  switches::kExtensionsOnChromeURLs);
98  if (document_url.SchemeIs(content::kChromeUIScheme) &&
99      !allow_on_chrome_urls) {
100    if (error)
101      *error = manifest_errors::kCannotAccessChromeUrl;
102    return true;
103  }
104
105  if (top_frame_url.SchemeIs(kExtensionScheme) &&
106      top_frame_url.host() != extension->id() &&
107      !allow_on_chrome_urls) {
108    if (error)
109      *error = manifest_errors::kCannotAccessExtensionUrl;
110    return true;
111  }
112
113  return false;
114}
115
116void PermissionsData::SetActivePermissions(
117    const PermissionSet* permissions) const {
118  base::AutoLock auto_lock(runtime_lock_);
119  active_permissions_unsafe_ = permissions;
120}
121
122void PermissionsData::UpdateTabSpecificPermissions(
123    int tab_id,
124    scoped_refptr<const PermissionSet> permissions) const {
125  base::AutoLock auto_lock(runtime_lock_);
126  CHECK_GE(tab_id, 0);
127  TabPermissionsMap::iterator iter = tab_specific_permissions_.find(tab_id);
128  if (iter == tab_specific_permissions_.end())
129    tab_specific_permissions_[tab_id] = permissions;
130  else
131    iter->second = PermissionSet::CreateUnion(iter->second, permissions);
132}
133
134void PermissionsData::ClearTabSpecificPermissions(int tab_id) const {
135  base::AutoLock auto_lock(runtime_lock_);
136  CHECK_GE(tab_id, 0);
137  tab_specific_permissions_.erase(tab_id);
138}
139
140bool PermissionsData::HasAPIPermission(APIPermission::ID permission) const {
141  return active_permissions()->HasAPIPermission(permission);
142}
143
144bool PermissionsData::HasAPIPermission(
145    const std::string& permission_name) const {
146  return active_permissions()->HasAPIPermission(permission_name);
147}
148
149bool PermissionsData::HasAPIPermissionForTab(
150    int tab_id,
151    APIPermission::ID permission) const {
152  if (HasAPIPermission(permission))
153    return true;
154
155  scoped_refptr<const PermissionSet> tab_permissions =
156      GetTabSpecificPermissions(tab_id);
157
158  // Place autolock below the HasAPIPermission() and
159  // GetTabSpecificPermissions(), since each already acquires the lock.
160  base::AutoLock auto_lock(runtime_lock_);
161  return tab_permissions.get() && tab_permissions->HasAPIPermission(permission);
162}
163
164bool PermissionsData::CheckAPIPermissionWithParam(
165    APIPermission::ID permission,
166    const APIPermission::CheckParam* param) const {
167  return active_permissions()->CheckAPIPermissionWithParam(permission, param);
168}
169
170const URLPatternSet& PermissionsData::GetEffectiveHostPermissions() const {
171  return active_permissions()->effective_hosts();
172}
173
174bool PermissionsData::HasHostPermission(const GURL& url) const {
175  return active_permissions()->HasExplicitAccessToOrigin(url);
176}
177
178bool PermissionsData::HasEffectiveAccessToAllHosts() const {
179  return active_permissions()->HasEffectiveAccessToAllHosts();
180}
181
182PermissionMessages PermissionsData::GetPermissionMessages() const {
183  if (ShouldSkipPermissionWarnings(extension_id_)) {
184    return PermissionMessages();
185  } else {
186    return PermissionMessageProvider::Get()->GetPermissionMessages(
187        active_permissions(), manifest_type_);
188  }
189}
190
191std::vector<base::string16> PermissionsData::GetPermissionMessageStrings()
192    const {
193  if (ShouldSkipPermissionWarnings(extension_id_))
194    return std::vector<base::string16>();
195  return PermissionMessageProvider::Get()->GetWarningMessages(
196      active_permissions(), manifest_type_);
197}
198
199std::vector<base::string16>
200PermissionsData::GetPermissionMessageDetailsStrings() const {
201  if (ShouldSkipPermissionWarnings(extension_id_))
202    return std::vector<base::string16>();
203  return PermissionMessageProvider::Get()->GetWarningMessagesDetails(
204      active_permissions(), manifest_type_);
205}
206
207bool PermissionsData::CanAccessPage(const Extension* extension,
208                                    const GURL& document_url,
209                                    const GURL& top_frame_url,
210                                    int tab_id,
211                                    int process_id,
212                                    std::string* error) const {
213  return CanRunOnPage(extension,
214                      document_url,
215                      top_frame_url,
216                      tab_id,
217                      process_id,
218                      active_permissions()->explicit_hosts(),
219                      error);
220}
221
222bool PermissionsData::CanRunContentScriptOnPage(const Extension* extension,
223                                                const GURL& document_url,
224                                                const GURL& top_frame_url,
225                                                int tab_id,
226                                                int process_id,
227                                                std::string* error) const {
228  return CanRunOnPage(extension,
229                      document_url,
230                      top_frame_url,
231                      tab_id,
232                      process_id,
233                      active_permissions()->scriptable_hosts(),
234                      error);
235}
236
237bool PermissionsData::CanCaptureVisiblePage(int tab_id,
238                                            std::string* error) const {
239  const URLPattern all_urls(URLPattern::SCHEME_ALL,
240                            URLPattern::kAllUrlsPattern);
241
242  if (active_permissions()->explicit_hosts().ContainsPattern(all_urls))
243    return true;
244
245  if (tab_id >= 0) {
246    scoped_refptr<const PermissionSet> tab_permissions =
247        GetTabSpecificPermissions(tab_id);
248    if (tab_permissions &&
249        tab_permissions->HasAPIPermission(APIPermission::kTab)) {
250      return true;
251    }
252    if (error)
253      *error = manifest_errors::kActiveTabPermissionNotGranted;
254    return false;
255  }
256
257  if (error)
258    *error = manifest_errors::kAllURLOrActiveTabNeeded;
259  return false;
260}
261
262// static
263bool PermissionsData::RequiresActionForScriptExecution(
264    const Extension* extension) const {
265  return RequiresActionForScriptExecution(extension, -1, GURL());
266}
267
268// static
269bool PermissionsData::RequiresActionForScriptExecution(
270    const Extension* extension,
271    int tab_id,
272    const GURL& url) const {
273  // For now, the user should be notified when an extension with all hosts
274  // permission tries to execute a script on a page. Exceptions for policy-
275  // enabled and component extensions, and extensions which are whitelisted to
276  // execute scripts everywhere.
277  if (!extension->ShouldDisplayInExtensionSettings() ||
278      Manifest::IsPolicyLocation(extension->location()) ||
279      Manifest::IsComponentLocation(extension->location()) ||
280      CanExecuteScriptEverywhere(extension) ||
281      !active_permissions()->ShouldWarnAllHosts()) {
282    return false;
283  }
284
285  // If the extension has explicit permission to run on the given tab, then
286  // we don't need to alert the user.
287  if (HasTabSpecificPermissionToExecuteScript(tab_id, url))
288    return false;
289
290  return true;
291}
292
293scoped_refptr<const PermissionSet> PermissionsData::GetTabSpecificPermissions(
294    int tab_id) const {
295  base::AutoLock auto_lock(runtime_lock_);
296  CHECK_GE(tab_id, 0);
297  TabPermissionsMap::const_iterator iter =
298      tab_specific_permissions_.find(tab_id);
299  return (iter != tab_specific_permissions_.end()) ? iter->second : NULL;
300}
301
302bool PermissionsData::HasTabSpecificPermissionToExecuteScript(
303    int tab_id,
304    const GURL& url) const {
305  if (tab_id >= 0) {
306    scoped_refptr<const PermissionSet> tab_permissions =
307        GetTabSpecificPermissions(tab_id);
308    if (tab_permissions.get() &&
309        tab_permissions->explicit_hosts().MatchesSecurityOrigin(url)) {
310      return true;
311    }
312  }
313  return false;
314}
315
316bool PermissionsData::CanRunOnPage(const Extension* extension,
317                                   const GURL& document_url,
318                                   const GURL& top_frame_url,
319                                   int tab_id,
320                                   int process_id,
321                                   const URLPatternSet& permitted_url_patterns,
322                                   std::string* error) const {
323  if (g_policy_delegate &&
324      !g_policy_delegate->CanExecuteScriptOnPage(
325          extension, document_url, top_frame_url, tab_id, process_id, error)) {
326    return false;
327  }
328
329  if (IsRestrictedUrl(document_url, top_frame_url, extension, error))
330    return false;
331
332  if (HasTabSpecificPermissionToExecuteScript(tab_id, top_frame_url))
333    return true;
334
335  bool can_access = permitted_url_patterns.MatchesURL(document_url);
336
337  if (!can_access && error) {
338    *error = ErrorUtils::FormatErrorMessage(manifest_errors::kCannotAccessPage,
339                                            document_url.spec());
340  }
341
342  return can_access;
343}
344
345}  // namespace extensions
346