2 * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * @file bundle_uri_handling.cpp
18 * @author Marcin Kaminski (marcin.ka@samsung.com)
22 #include "bundle_uri_handling.h"
23 #include <dpl/log/log.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>
34 #include <dpl/localization/w3c_file_localization.h>
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
42 // WKBundle API (i.e. message sending)
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:",
61 char const * const ACE_IGNORED_SCHEMA[] = { "file://", "widget://", "data:",
62 "tel:", "sms:", "mmsto:", "mailto:",
66 bool wildcardCompare(std::string wildcardString, std::string target)
68 std::string re = wildcardString;
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);
85 // replace wildcard character to regex type
86 pcrecpp::RE("\\\*").GlobalReplace(".*", &re);
88 return pcrecpp::RE(re).FullMatch(target);
91 bool checkWARP(const char *url, const DPL::String& tizenId)
93 // ignore WARP in test mode
94 if (GlobalSettings::WarpTestModeEnabled()) {
98 if (WarpIRI::isIRISchemaIgnored(url)) {
99 // scheme is not supported by WARP
103 WrtDB::WidgetDAOReadOnly dao = WrtDB::WidgetDAOReadOnly(tizenId);
104 WrtDB::WidgetAccessInfoList widgetAccessInfoList;
105 dao.getWidgetAccessInfo(widgetAccessInfoList);
107 return (static_cast<WidgetAccessList>(widgetAccessInfoList)).isRequiredIRI(
108 DPL::FromUTF8String(std::string(url)));
111 bool checkAllowNavigation(const char *url, const DPL::String& tizenId)
117 DPL::ScopedPtr<iri_t> iri(iri_parse(url));
118 if (!iri->scheme || !iri->host || strlen(iri->host) == 0) {
121 std::string scheme = iri->scheme;
122 std::string host = iri->host;
124 if (scheme.find(SCHEME_TYPE_HTTP) == std::string::npos) {
125 LogDebug("url doesn't need to check allow-navigation");
129 WrtDB::WidgetDAOReadOnly dao = WrtDB::WidgetDAOReadOnly(tizenId);
130 WrtDB::WidgetAllowNavigationInfoList list;
131 dao.getWidgetAllowNavigationInfo(list);
134 if (wildcardCompare(DPL::ToUTF8String(it->scheme), scheme) &&
135 wildcardCompare(DPL::ToUTF8String(it->host), host))
144 bool preventSymlink(const std::string & url)
146 if(0 != strncmp(url.c_str(), SCHEME_TYPE_FILE, strlen(SCHEME_TYPE_FILE)))
150 if(url.size() >= strlen(SCHEME_TYPE_FILE) + 3)
152 std::string file = url.substr(strlen(SCHEME_TYPE_FILE) + 3);
154 if(0 != stat(file.c_str(), &st)) return true;
155 return !S_ISLNK(st.st_mode);
163 bool checkACE(const char* url, bool xhr, const DPL::String& tizenId)
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])))
176 const char *devCapNamesMarkup = "externalNetworkAccess";
177 const char *devCapNamesXHR = "XMLHttpRequest";
179 ace_request_t aceRequest;
181 aceRequest.widget_handle = WrtDB::WidgetDAOReadOnly::getHandle(tizenId);
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];
191 aceRequest.dev_cap_list.items[0].name =
192 const_cast<ace_string_t>(devCapNamesXHR);
194 aceRequest.dev_cap_list.items[0].name =
195 const_cast<ace_string_t>(devCapNamesMarkup);
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);
205 ace_bool_t result = ACE_FALSE;
207 LogDebug("Making ace check with new C-API");
209 ace_return_t ret = ace_check_access(&aceRequest, &result);
211 LogDebug("Result is: " << static_cast<int>(result));
213 delete[] aceRequest.dev_cap_list.items[0].param_list.items;
214 delete[] aceRequest.dev_cap_list.items;
216 return ACE_OK == ret && ACE_TRUE == result;
218 } // namespace (anonymous)
220 namespace BundleURIHandling {
221 bool processURI(const DPL::String& inputURI,
222 const DPL::String& tizenId,
223 WrtDB::WidgetSecurityModelVersion version)
225 DPL::Optional<DPL::String> optionalUri(inputURI);
226 if (optionalUri.IsNull()) {
227 LogDebug("uri is empty");
231 std::string uri = DPL::ToUTF8String(inputURI);
233 WrtDB::WidgetSecurityModelVersion::WIDGET_SECURITY_MODEL_V1)
235 if (!checkWARP(uri.c_str(), tizenId)) {
236 LogWarning("Request was blocked by WARP: " << uri);
241 if (!checkACE(uri.c_str(), true, tizenId)) {
242 LogWarning("Request was blocked by ACE: " << uri);
246 if (!preventSymlink(uri)) {
247 LogWarning("Request for symlink is invalid: " << uri);
254 bool processMainResource(const DPL::String& inputURI,
255 const DPL::String& tizenId,
256 WrtDB::WidgetSecurityModelVersion version)
258 DPL::Optional<DPL::String> optionalUri(inputURI);
259 if (optionalUri.IsNull()) {
260 LogDebug("uri is empty");
264 std::string uri = DPL::ToUTF8String(inputURI);
266 WrtDB::WidgetSecurityModelVersion::WIDGET_SECURITY_MODEL_V1)
268 if (!checkWARP(uri.c_str(), tizenId)) {
269 LogWarning("Request was blocked by WARP: " << uri);
272 } else if (version ==
273 WrtDB::WidgetSecurityModelVersion::WIDGET_SECURITY_MODEL_V2)
275 #ifdef ALLOW_NAVIGATION_ENABLED
276 if (!checkAllowNavigation(uri.c_str(), tizenId)) {
277 LogWarning("Request was blocked by WARP: " << uri);
285 if (!checkACE(uri.c_str(), true, tizenId)) {
286 LogWarning("Request was blocked by ACE: " << uri);
290 if (!preventSymlink(uri)) {
291 LogWarning("Request for symlink is invalid: " << uri);
298 DPL::OptionalString localizeURI(const DPL::String& inputURI,
299 const DPL::String& tizenId)
301 std::string uri = DPL::ToUTF8String(inputURI);
302 LogDebug("localizing url: " << uri);
303 auto urlcstr = uri.c_str();
304 const char *end = strstr(urlcstr, ":");
306 LogDebug("no schema in link, return null");
308 return DPL::Optional<DPL::String>::Null;
310 std::string scheme(urlcstr, end);
312 #ifdef APP_SCHEME_ENABLED
313 if (scheme != SCHEME_TYPE_WIDGET && scheme != SCHEME_TYPE_FILE && scheme != SCHEME_TYPE_APP) {
315 if (scheme != SCHEME_TYPE_WIDGET && scheme != SCHEME_TYPE_FILE) {
317 LogDebug("scheme doesn't need to localize");
318 return DPL::OptionalString(inputURI);
321 DPL::Optional<DPL::String> found =
322 W3CFileLocalization::getFilePathInWidgetPackageFromUrl(
324 DPL::FromUTF8String(uri));
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);
331 DPL::String uri(L"file://" + *found);
332 LogDebug("Will load resource: " << uri);
333 LogDebug("finished");
334 return DPL::OptionalString(uri);
337 } // namespace BundleURIHandling