[Release] wrt_0.8.191
[platform/framework/web/wrt.git] / src / view / webkit / bundles / bundle_uri_handling.cpp
1 /*
2  * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @file    bundle_uri_handling.cpp
18  * @author  Marcin Kaminski (marcin.ka@samsung.com)
19  * @version 1.0
20  */
21
22 #include "bundle_uri_handling.h"
23 #include <dpl/log/log.h>
24 #include <string.h>
25 #include <sys/stat.h>
26 #include <dpl/utils/wrt_global_settings.h>
27 // For dao creation (widget info fetching)
28 #include <dpl/wrt-dao-ro/widget_dao_read_only.h>
29 // security checks for URI
30 #include <ace-common/ace_api_common.h>
31 #include <ace-client/ace_api_client.h>
32 #include <dpl/utils/warp_iri.h>
33 // URI localization
34 #include <dpl/localization/w3c_file_localization.h>
35 // WARP check
36 #include <widget_data_types.h>
37 #include <dpl/wrt-dao-ro/common_dao_types.h>
38 #include <dpl/scoped_ptr.h>
39 // allow-navigation check
40 #include <pcrecpp.h>
41 #include <iri.h>
42 // WKBundle API (i.e. message sending)
43 #include <WKBundle.h>
44 #include <WKString.h>
45 #include <WKType.h>
46
47
48 namespace {
49 char const * const SCHEME_TYPE_FILE = "file";
50 char const * const SCHEME_TYPE_WIDGET = "widget";
51 char const * const SCHEME_TYPE_APP = "app";
52 char const * const SCHEME_TYPE_HTTP = "http";
53 char const * const WARP_ERROR_MSG =
54     "file:///usr/etc/wrt/warp_security_error.msg";
55 char const * const PARAM_URL = "param:url";
56 #ifdef APP_SCHEME_ENABLED
57 char const * const ACE_IGNORED_SCHEMA[] = { "file://", "widget://", "app://",
58                                             "data:", "tel:", "sms:", "mmsto:",
59                                             "mailto:", 0 };
60 #else
61 char const * const ACE_IGNORED_SCHEMA[] = { "file://", "widget://", "data:",
62                                             "tel:", "sms:", "mmsto:", "mailto:",
63                                             0 };
64 #endif
65
66 bool wildcardCompare(std::string wildcardString, std::string target)
67 {
68     std::string re = wildcardString;
69
70     // replace special character to meaning character
71     pcrecpp::RE("\\\\").GlobalReplace("\\\\\\\\", &re);
72     pcrecpp::RE("\\.").GlobalReplace("\\\\.", &re);
73     pcrecpp::RE("\\+").GlobalReplace("\\\\+", &re);
74     pcrecpp::RE("\\?").GlobalReplace("\\\\?", &re);
75     pcrecpp::RE("\\^").GlobalReplace("\\\\^", &re);
76     pcrecpp::RE("\\$").GlobalReplace("\\\\$", &re);
77     pcrecpp::RE("\\[").GlobalReplace("\\\\[", &re);
78     pcrecpp::RE("\\]").GlobalReplace("\\\\]", &re);
79     pcrecpp::RE("\\{").GlobalReplace("\\\\{", &re);
80     pcrecpp::RE("\\}").GlobalReplace("\\\\}", &re);
81     pcrecpp::RE("\\(").GlobalReplace("\\\\(", &re);
82     pcrecpp::RE("\\)").GlobalReplace("\\\\)", &re);
83     pcrecpp::RE("\\|").GlobalReplace("\\\\|", &re);
84
85     // replace wildcard character to regex type
86     pcrecpp::RE("\\\*").GlobalReplace(".*", &re);
87
88     return pcrecpp::RE(re).FullMatch(target);
89 }
90
91 bool checkWARP(const char *url, const DPL::String& tizenId)
92 {
93     // ignore WARP in test mode
94     if (GlobalSettings::WarpTestModeEnabled()) {
95         return true;
96     }
97
98     if (WarpIRI::isIRISchemaIgnored(url)) {
99         // scheme is not supported by WARP
100         return true;
101     }
102
103     WrtDB::WidgetDAOReadOnly dao = WrtDB::WidgetDAOReadOnly(tizenId);
104     WrtDB::WidgetAccessInfoList widgetAccessInfoList;
105     dao.getWidgetAccessInfo(widgetAccessInfoList);
106
107     return (static_cast<WidgetAccessList>(widgetAccessInfoList)).isRequiredIRI(
108                DPL::FromUTF8String(std::string(url)));
109 }
110
111 bool checkAllowNavigation(const char *url, const DPL::String& tizenId)
112 {
113     if (url == NULL) {
114         return true;
115     }
116
117     DPL::ScopedPtr<iri_t> iri(iri_parse(url));
118     if (!iri->scheme || !iri->host || strlen(iri->host) == 0) {
119         return true;
120     }
121     std::string scheme = iri->scheme;
122     std::string host = iri->host;
123
124     if (scheme.find(SCHEME_TYPE_HTTP) == std::string::npos) {
125         LogDebug("url doesn't need to check allow-navigation");
126         return true;
127     }
128
129     WrtDB::WidgetDAOReadOnly dao = WrtDB::WidgetDAOReadOnly(tizenId);
130     WrtDB::WidgetAllowNavigationInfoList list;
131     dao.getWidgetAllowNavigationInfo(list);
132
133     FOREACH(it, list) {
134         if (wildcardCompare(DPL::ToUTF8String(it->scheme), scheme) &&
135             wildcardCompare(DPL::ToUTF8String(it->host), host))
136         {
137             return true;
138         }
139     }
140     LogDebug("deny");
141     return false;
142 }
143
144 bool preventSymlink(const std::string & url)
145 {
146     if(0 != strncmp(url.c_str(), SCHEME_TYPE_FILE, strlen(SCHEME_TYPE_FILE)))
147     {
148         return true;
149     }
150     if(url.size() >= strlen(SCHEME_TYPE_FILE) + 3)
151     {
152         std::string file = url.substr(strlen(SCHEME_TYPE_FILE) + 3);
153         struct stat st;
154         if(0 != stat(file.c_str(), &st)) return true;
155         return !S_ISLNK(st.st_mode);
156     }
157     else
158     {
159         return true;
160     }
161 }
162
163 bool checkACE(const char* url, bool xhr, const DPL::String& tizenId)
164 {
165     if (url) {
166         for (size_t i = 0; ACE_IGNORED_SCHEMA[i]; ++i) {
167             if (0 == strncmp(url,
168                              ACE_IGNORED_SCHEMA[i],
169                              strlen(ACE_IGNORED_SCHEMA[i])))
170             {
171                 return true;
172             }
173         }
174     }
175
176     const char *devCapNamesMarkup = "externalNetworkAccess";
177     const char *devCapNamesXHR = "XMLHttpRequest";
178
179     ace_request_t aceRequest;
180
181     aceRequest.widget_handle = WrtDB::WidgetDAOReadOnly::getHandle(tizenId);
182
183     // TODO! We should get session id from somewhere (outside Widget Process)
184     const std::string session = "";
185     aceRequest.session_id = const_cast<ace_session_id_t>(session.c_str());
186     aceRequest.feature_list.count = 0;
187     aceRequest.dev_cap_list.count = 1;
188     aceRequest.dev_cap_list.items = new ace_dev_cap_t[1];
189
190     if (xhr) {
191         aceRequest.dev_cap_list.items[0].name =
192             const_cast<ace_string_t>(devCapNamesXHR);
193     } else {
194         aceRequest.dev_cap_list.items[0].name =
195             const_cast<ace_string_t>(devCapNamesMarkup);
196     }
197
198     aceRequest.dev_cap_list.items[0].param_list.count = 1;
199     aceRequest.dev_cap_list.items[0].param_list.items = new ace_param_t[1];
200     aceRequest.dev_cap_list.items[0].param_list.items[0].name =
201         const_cast<ace_string_t>(PARAM_URL);
202     aceRequest.dev_cap_list.items[0].param_list.items[0].value =
203         const_cast<ace_string_t>(url);
204
205     ace_bool_t result = ACE_FALSE;
206
207     LogDebug("Making ace check with new C-API");
208
209     ace_return_t ret = ace_check_access(&aceRequest, &result);
210
211     LogDebug("Result is: " << static_cast<int>(result));
212
213     delete[] aceRequest.dev_cap_list.items[0].param_list.items;
214     delete[] aceRequest.dev_cap_list.items;
215
216     return ACE_OK == ret && ACE_TRUE == result;
217 }
218 } // namespace (anonymous)
219
220 namespace BundleURIHandling {
221 bool processURI(const DPL::String& inputURI,
222                 const DPL::String& tizenId,
223                 WrtDB::WidgetSecurityModelVersion version)
224 {
225     DPL::Optional<DPL::String> optionalUri(inputURI);
226     if (optionalUri.IsNull()) {
227         LogDebug("uri is empty");
228         return true;
229     }
230
231     std::string uri = DPL::ToUTF8String(inputURI);
232     if (version ==
233         WrtDB::WidgetSecurityModelVersion::WIDGET_SECURITY_MODEL_V1)
234     {
235         if (!checkWARP(uri.c_str(), tizenId)) {
236             LogWarning("Request was blocked by WARP: " << uri);
237             return false;
238         }
239     }
240
241     if (!checkACE(uri.c_str(), true, tizenId)) {
242         LogWarning("Request was blocked by ACE: " << uri);
243         return false;
244     }
245
246     if (!preventSymlink(uri)) {
247         LogWarning("Request for symlink is invalid: " << uri);
248         return false;
249     }
250
251     return true;
252 }
253
254 bool processMainResource(const DPL::String& inputURI,
255                          const DPL::String& tizenId,
256                          WrtDB::WidgetSecurityModelVersion version)
257 {
258     DPL::Optional<DPL::String> optionalUri(inputURI);
259     if (optionalUri.IsNull()) {
260         LogDebug("uri is empty");
261         return true;
262     }
263
264     std::string uri = DPL::ToUTF8String(inputURI);
265     if (version ==
266         WrtDB::WidgetSecurityModelVersion::WIDGET_SECURITY_MODEL_V1)
267     {
268         if (!checkWARP(uri.c_str(), tizenId)) {
269             LogWarning("Request was blocked by WARP: " << uri);
270             return false;
271         }
272     } else if (version ==
273         WrtDB::WidgetSecurityModelVersion::WIDGET_SECURITY_MODEL_V2)
274     {
275 #ifdef ALLOW_NAVIGATION_ENABLED
276         if (!checkAllowNavigation(uri.c_str(), tizenId)) {
277             LogWarning("Request was blocked by WARP: " << uri);
278             return false;
279         }
280 #else
281         return false;
282 #endif
283     }
284
285     if (!checkACE(uri.c_str(), true, tizenId)) {
286         LogWarning("Request was blocked by ACE: " << uri);
287         return false;
288     }
289
290     if (!preventSymlink(uri)) {
291         LogWarning("Request for symlink is invalid: " << uri);
292         return false;
293     }
294
295     return true;
296 }
297
298 DPL::OptionalString localizeURI(const DPL::String& inputURI,
299                                 const DPL::String& tizenId)
300 {
301     std::string uri = DPL::ToUTF8String(inputURI);
302     LogDebug("localizing url: " << uri);
303     auto urlcstr = uri.c_str();
304     const char *end = strstr(urlcstr, ":");
305     if (!end) {
306         LogDebug("no schema in link, return null");
307         // lack of schema
308         return DPL::Optional<DPL::String>::Null;
309     }
310     std::string scheme(urlcstr, end);
311
312 #ifdef APP_SCHEME_ENABLED
313     if (scheme != SCHEME_TYPE_WIDGET && scheme != SCHEME_TYPE_FILE && scheme != SCHEME_TYPE_APP) {
314 #else
315     if (scheme != SCHEME_TYPE_WIDGET && scheme != SCHEME_TYPE_FILE) {
316 #endif
317         LogDebug("scheme doesn't need to localize");
318         return DPL::OptionalString(inputURI);
319     }
320
321     DPL::Optional<DPL::String> found =
322         W3CFileLocalization::getFilePathInWidgetPackageFromUrl(
323             tizenId,
324             DPL::FromUTF8String(uri));
325
326     if (found.IsNull()) {
327         // In this case, path doesn't need to localize. return input uri
328         LogDebug("Path not found within current locale in current widget");
329         return DPL::OptionalString(inputURI);
330     } else {
331         DPL::String uri(L"file://" + *found);
332         LogDebug("Will load resource: " << uri);
333         LogDebug("finished");
334         return DPL::OptionalString(uri);
335     }
336 }
337 } // namespace BundleURIHandling