1d34020ae0bdf43b915a8d342a330b9f5fe14e0f
[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 <dpl/utils/wrt_global_settings.h>
26 // For dao creation (widget info fetching)
27 #include <dpl/wrt-dao-ro/widget_dao_read_only.h>
28 // security checks for URI
29 #include <ace-common/ace_api_common.h>
30 #include <ace-client/ace_api_client.h>
31 #include <dpl/utils/warp_iri.h>
32 // URI localization
33 #include <dpl/localization/w3c_file_localization.h>
34 // WARP check
35 #include <widget_data_types.h>
36 #include <dpl/wrt-dao-ro/common_dao_types.h>
37 // WKBundle API (i.e. message sending)
38 #include <WKBundle.h>
39 #include <WKString.h>
40 #include <WKType.h>
41
42 namespace {
43
44 char const * const SCHEME_TYPE_FILE = "file";
45 char const * const SCHEME_TYPE_WIDGET = "widget";
46 char const * const WARP_ERROR_MSG =
47         "file:///usr/etc/wrt/warp_security_error.msg";
48 char const * const PARAM_URL = "param:url";
49 char const * const ACE_IGNORED_SCHEMA[] = { "file://", "widget://", "data:",
50     "tel:", "sms:", "mmsto:", "mailto:", 0 };
51
52 WKStringRef block_message = WKStringCreateWithUTF8CString("uri_block_msg");
53
54
55 bool checkWARP(const char *url, const DPL::String& tizenId)
56 {
57     // ignore WARP in test mode
58     if (GlobalSettings::WarpTestModeEnabled()) {
59         return true;
60     }
61
62     if (WarpIRI::isIRISchemaIgnored(url)) {
63         // scheme is not supported by WARP
64         return true;
65     }
66
67     WrtDB::WidgetDAOReadOnly dao = WrtDB::WidgetDAOReadOnly(tizenId);
68     WrtDB::WidgetAccessInfoList widgetAccessInfoList;
69     dao.getWidgetAccessInfo(widgetAccessInfoList);
70
71     return (static_cast<WidgetAccessList>(widgetAccessInfoList)).isRequiredIRI(
72             DPL::FromUTF8String(std::string(url)));
73 }
74
75 bool checkACE(const char* url, bool xhr, const DPL::String& tizenId)
76 {
77     if (url) {
78         for (size_t i = 0; ACE_IGNORED_SCHEMA[i]; ++i) {
79             if (0 == strncmp(url,
80                              ACE_IGNORED_SCHEMA[i],
81                              strlen(ACE_IGNORED_SCHEMA[i])))
82             {
83                 return true;
84             }
85         }
86     }
87
88     const char *devCapNamesMarkup = "externalNetworkAccess";
89     const char *devCapNamesXHR = "XMLHttpRequest";
90
91     ace_request_t aceRequest;
92
93     aceRequest.widget_handle = WrtDB::WidgetDAOReadOnly::getHandle(tizenId);
94
95     // TODO! We should get session id from somewhere (outside Widget Process)
96     const std::string session = "";
97     aceRequest.session_id = const_cast<ace_session_id_t>(session.c_str());
98     aceRequest.feature_list.count = 0;
99     aceRequest.dev_cap_list.count = 1;
100     aceRequest.dev_cap_list.items = new ace_dev_cap_t[1];
101
102     if (xhr) {
103         aceRequest.dev_cap_list.items[0].name =
104                 const_cast<ace_string_t>(devCapNamesXHR);
105     } else {
106         aceRequest.dev_cap_list.items[0].name =
107                 const_cast<ace_string_t>(devCapNamesMarkup);
108     }
109
110     aceRequest.dev_cap_list.items[0].param_list.count = 1;
111     aceRequest.dev_cap_list.items[0].param_list.items = new ace_param_t[1];
112     aceRequest.dev_cap_list.items[0].param_list.items[0].name =
113             const_cast<ace_string_t>(PARAM_URL);
114     aceRequest.dev_cap_list.items[0].param_list.items[0].value =
115             const_cast<ace_string_t>(url);
116
117
118     ace_bool_t result = ACE_FALSE;
119
120     LogDebug("Making ace check with new C-API");
121
122     ace_return_t ret = ace_check_access(&aceRequest, &result);
123
124     LogDebug("Result is: " << static_cast<int>(result));
125
126     delete [] aceRequest.dev_cap_list.items[0].param_list.items;
127     delete [] aceRequest.dev_cap_list.items;
128
129     return ACE_OK == ret && ACE_TRUE == result;
130 }
131
132
133 bool filterURIBySecurity(DPL::OptionalString &op_uri,
134          bool is_xhr,
135          const DPL::String& tizenId)
136 {
137     if (!op_uri)
138     {
139         return true; //accept empty uri
140     }
141
142     auto uri = DPL::ToUTF8String(*op_uri);
143     if (!checkWARP(uri.c_str(), tizenId))
144     {
145         LogDebug("Request was blocked by WARP: " << uri);
146         return false;
147     }
148
149     if (!checkACE(uri.c_str(), is_xhr, tizenId))
150     {
151         LogDebug("Request was blocked by ACE: " << uri);
152         return false;
153     }
154
155     return true;
156 }
157 } // namespace (anonymous)
158
159 namespace BundleURIHandling {
160
161 DPL::Optional<DPL::String> processURI(const DPL::String& inputURI,
162         bool is_xhr, const DPL::String& tizenId, WKBundleRef bundle)
163 {
164     DPL::Optional<DPL::String> uri = localizeURI(inputURI, tizenId);
165
166     if (uri.IsNull())
167     {
168         LogDebug("uri is empty");
169         return uri;
170     }
171
172     // check ACE, WARP
173     if (!filterURIBySecurity(uri, is_xhr, tizenId))
174     {
175         WKStringRef urlStr = WKStringCreateWithUTF8CString(
176                 DPL::ToUTF8String(*uri).c_str());
177         WKTypeRef retVal = NULL;
178         // Send information about blocked URI to view_logic
179         LogInfo("Sent blocked uri to open browser later : " << uri);
180         WKBundlePostSynchronousMessage(bundle, block_message,
181                 urlStr, &retVal);
182         WKRelease(urlStr);
183         WKRelease(retVal);
184         return DPL::Optional<DPL::String>::Null;
185     }
186
187     return uri;
188 }
189
190 DPL::OptionalString localizeURI(const DPL::String& inputURI,
191         const DPL::String& tizenId)
192 {
193     auto uri = DPL::ToUTF8String(inputURI);
194     LogDebug("localizing url: " << uri);
195
196     auto urlcstr = uri.c_str();
197
198     const char *end = strstr(urlcstr, ":");
199     if (!end) {
200         LogDebug("no schema in link, return null");
201         // lack of schema
202         return DPL::Optional<DPL::String>::Null;
203     }
204
205     std::string scheme(urlcstr, end);
206     if (scheme != SCHEME_TYPE_WIDGET && scheme != SCHEME_TYPE_FILE) {
207         LogDebug("scheme doesn't need to localize");
208         return DPL::OptionalString(inputURI);
209     }
210
211     DPL::Optional<DPL::String> found =
212         W3CFileLocalization::getFilePathInWidgetPackageFromUrl(
213             tizenId,
214             DPL::FromUTF8String(uri));
215
216     if (found.IsNull()) {
217         // In this case, path doesn't need to localize. return input uri
218         LogDebug("Path not found within current locale in current widget");
219         return DPL::OptionalString(inputURI);
220     } else {
221         DPL::String uri(L"file://" + *found);
222         LogDebug("Will load resource: " << uri);
223         LogDebug("finished");
224         return DPL::OptionalString(uri);
225     }
226 }
227
228 } // namespace BundleURIHandling