958c5e95a410afaf79acecd13e8e34debda0dae4
[platform/framework/web/crosswalk.git] / src / extensions / common / permissions / permissions_data.cc
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
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();
41 }
42
43 PermissionsData::~PermissionsData() {
44 }
45
46 // static
47 void PermissionsData::SetPolicyDelegate(PolicyDelegate* delegate) {
48   g_policy_delegate = delegate;
49 }
50
51 // static
52 bool PermissionsData::CanSilentlyIncreasePermissions(
53     const Extension* extension) {
54   return extension->location() != Manifest::INTERNAL;
55 }
56
57 // static
58 bool 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
69 bool 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
76 bool 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
116 void 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
124 void 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
136 void 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
142 bool PermissionsData::HasAPIPermission(APIPermission::ID permission) const {
143   return active_permissions()->HasAPIPermission(permission);
144 }
145
146 bool PermissionsData::HasAPIPermission(
147     const std::string& permission_name) const {
148   return active_permissions()->HasAPIPermission(permission_name);
149 }
150
151 bool 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
166 bool PermissionsData::CheckAPIPermissionWithParam(
167     APIPermission::ID permission,
168     const APIPermission::CheckParam* param) const {
169   return active_permissions()->CheckAPIPermissionWithParam(permission, param);
170 }
171
172 const URLPatternSet& PermissionsData::GetEffectiveHostPermissions() const {
173   return active_permissions()->effective_hosts();
174 }
175
176 bool PermissionsData::HasHostPermission(const GURL& url) const {
177   return active_permissions()->HasExplicitAccessToOrigin(url);
178 }
179
180 bool PermissionsData::HasEffectiveAccessToAllHosts() const {
181   return active_permissions()->HasEffectiveAccessToAllHosts();
182 }
183
184 PermissionMessages 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
193 std::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
201 std::vector<base::string16>
202 PermissionsData::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
209 bool 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
216 bool 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
234 PermissionsData::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
251 bool 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
269 PermissionsData::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
286 bool 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
311 scoped_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
320 bool 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
334 PermissionsData::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