• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
22 namespace extensions {
23 
24 namespace {
25 
26 PermissionsData::PolicyDelegate* g_policy_delegate = NULL;
27 
28 }  // namespace
29 
PermissionsData(const Extension * extension)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 }
41 
~PermissionsData()42 PermissionsData::~PermissionsData() {
43 }
44 
45 // static
SetPolicyDelegate(PolicyDelegate * delegate)46 void PermissionsData::SetPolicyDelegate(PolicyDelegate* delegate) {
47   g_policy_delegate = delegate;
48 }
49 
50 // static
CanSilentlyIncreasePermissions(const Extension * extension)51 bool PermissionsData::CanSilentlyIncreasePermissions(
52     const Extension* extension) {
53   return extension->location() != Manifest::INTERNAL;
54 }
55 
56 // static
CanExecuteScriptEverywhere(const Extension * extension)57 bool 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 
ShouldSkipPermissionWarnings(const std::string & extension_id)68 bool 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
IsRestrictedUrl(const GURL & document_url,const GURL & top_frame_url,const Extension * extension,std::string * error)75 bool 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 
SetActivePermissions(const PermissionSet * permissions) const116 void PermissionsData::SetActivePermissions(
117     const PermissionSet* permissions) const {
118   base::AutoLock auto_lock(runtime_lock_);
119   active_permissions_unsafe_ = permissions;
120 }
121 
UpdateTabSpecificPermissions(int tab_id,scoped_refptr<const PermissionSet> permissions) const122 void 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 
ClearTabSpecificPermissions(int tab_id) const134 void 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 
HasAPIPermission(APIPermission::ID permission) const140 bool PermissionsData::HasAPIPermission(APIPermission::ID permission) const {
141   return active_permissions()->HasAPIPermission(permission);
142 }
143 
HasAPIPermission(const std::string & permission_name) const144 bool PermissionsData::HasAPIPermission(
145     const std::string& permission_name) const {
146   return active_permissions()->HasAPIPermission(permission_name);
147 }
148 
HasAPIPermissionForTab(int tab_id,APIPermission::ID permission) const149 bool 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 
CheckAPIPermissionWithParam(APIPermission::ID permission,const APIPermission::CheckParam * param) const164 bool PermissionsData::CheckAPIPermissionWithParam(
165     APIPermission::ID permission,
166     const APIPermission::CheckParam* param) const {
167   return active_permissions()->CheckAPIPermissionWithParam(permission, param);
168 }
169 
GetEffectiveHostPermissions() const170 const URLPatternSet& PermissionsData::GetEffectiveHostPermissions() const {
171   return active_permissions()->effective_hosts();
172 }
173 
HasHostPermission(const GURL & url) const174 bool PermissionsData::HasHostPermission(const GURL& url) const {
175   return active_permissions()->HasExplicitAccessToOrigin(url);
176 }
177 
HasEffectiveAccessToAllHosts() const178 bool PermissionsData::HasEffectiveAccessToAllHosts() const {
179   return active_permissions()->HasEffectiveAccessToAllHosts();
180 }
181 
GetPermissionMessages() const182 PermissionMessages 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 
GetPermissionMessageStrings() const191 std::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 
199 std::vector<base::string16>
GetPermissionMessageDetailsStrings() const200 PermissionsData::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 
CanAccessPage(const Extension * extension,const GURL & document_url,const GURL & top_frame_url,int tab_id,int process_id,std::string * error) const207 bool 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 
CanRunContentScriptOnPage(const Extension * extension,const GURL & document_url,const GURL & top_frame_url,int tab_id,int process_id,std::string * error) const222 bool 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 
CanCaptureVisiblePage(int tab_id,std::string * error) const237 bool 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
RequiresActionForScriptExecution(const Extension * extension) const263 bool PermissionsData::RequiresActionForScriptExecution(
264     const Extension* extension) const {
265   return RequiresActionForScriptExecution(extension, -1, GURL());
266 }
267 
268 // static
RequiresActionForScriptExecution(const Extension * extension,int tab_id,const GURL & url) const269 bool 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 
GetTabSpecificPermissions(int tab_id) const293 scoped_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 
HasTabSpecificPermissionToExecuteScript(int tab_id,const GURL & url) const302 bool 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 
CanRunOnPage(const Extension * extension,const GURL & document_url,const GURL & top_frame_url,int tab_id,int process_id,const URLPatternSet & permitted_url_patterns,std::string * error) const316 bool 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