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 injected_bundle_uri_handling.cpp
18 * @author Marcin Kaminski (marcin.ka@samsung.com)
22 #include "injected_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
43 #include <dpl/wrt-dao-ro/global_dao_read_only.h>
44 // WKBundle API (i.e. message sending)
50 char const * const SCHEME_TYPE_FILE = "file";
51 char const * const SCHEME_TYPE_WIDGET = "widget";
52 char const * const SCHEME_TYPE_APP = "app";
53 char const * const SCHEME_TYPE_HTTP = "http";
54 char const * const WARP_ERROR_MSG =
55 "file:///usr/etc/wrt/warp_security_error.msg";
56 char const * const PARAM_URL = "param:url";
57 #ifdef APP_SCHEME_ENABLED
58 char const * const ACE_IGNORED_SCHEMA[] = { "file://", "widget://", "app://",
59 "data:", "tel:", "sms:", "mmsto:",
62 char const * const ACE_IGNORED_SCHEMA[] = { "file://", "widget://", "data:",
63 "tel:", "sms:", "mmsto:", "mailto:",
67 bool wildcardCompare(std::string wildcardString, std::string target)
69 std::string re = wildcardString;
71 // replace special character to meaning character
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 pcrecpp::RE("\\|").GlobalReplace("\\\\|", &re);
86 // replace wildcard character to regex type
87 pcrecpp::RE("\\*").GlobalReplace(".*", &re);
89 return pcrecpp::RE(re).FullMatch(target);
92 bool checkWARP(const char *url, const DPL::String& tizenId)
94 // ignore WARP in test mode
95 if (GlobalSettings::WarpTestModeEnabled()) {
99 if (WarpIRI::isIRISchemaIgnored(url)) {
100 // scheme is not supported by WARP
104 WrtDB::WidgetDAOReadOnly dao = WrtDB::WidgetDAOReadOnly(tizenId);
105 WrtDB::WidgetAccessInfoList widgetAccessInfoList;
106 dao.getWidgetAccessInfo(widgetAccessInfoList);
108 // temporary solution for libiri parsing error
109 // This code will be removed
110 std::string urlstr = url;
111 size_t pos = urlstr.find_first_of("#?");
112 if (pos != std::string::npos) {
113 urlstr = urlstr.substr(0, pos);
116 return (static_cast<WidgetAccessList>(widgetAccessInfoList)).isRequiredIRI(
117 DPL::FromUTF8String(urlstr));
120 bool checkWhitelist(const char *url)
122 LogInfo("Check WhiteList");
127 DPL::ScopedPtr<iri_t> iri(iri_parse(url));
128 if (!iri->scheme || !iri->host || strlen(iri->host) == 0) {
131 std::string scheme = iri->scheme;
132 std::string host = iri->host;
134 if (scheme.find(SCHEME_TYPE_HTTP) == std::string::npos) {
135 LogDebug("url doesn't need to check white list");
139 WidgetAccessList whiteURIList(WrtDB::GlobalDAOReadOnly::GetWhiteURIList());
140 return whiteURIList.isRequiredIRI(DPL::FromUTF8String(host));
143 bool checkAllowNavigation(const char *url, const DPL::String& tizenId)
149 DPL::ScopedPtr<iri_t> iri(iri_parse(url));
150 if (!iri->scheme || !iri->host || strlen(iri->host) == 0) {
153 std::string scheme = iri->scheme;
154 std::string host = iri->host;
156 if (scheme.find(SCHEME_TYPE_HTTP) == std::string::npos) {
157 LogDebug("url doesn't need to check allow-navigation");
161 WrtDB::WidgetDAOReadOnly dao = WrtDB::WidgetDAOReadOnly(tizenId);
162 WrtDB::WidgetAllowNavigationInfoList list;
163 dao.getWidgetAllowNavigationInfo(list);
166 if (wildcardCompare(DPL::ToUTF8String(it->scheme), scheme) &&
167 wildcardCompare(DPL::ToUTF8String(it->host), host))
176 bool preventSymlink(const std::string & url)
178 if(0 != strncmp(url.c_str(), SCHEME_TYPE_FILE, strlen(SCHEME_TYPE_FILE)))
182 if(url.size() >= strlen(SCHEME_TYPE_FILE) + 3)
184 std::string file = url.substr(strlen(SCHEME_TYPE_FILE) + 3);
186 if(0 != stat(file.c_str(), &st)) return true;
187 return !S_ISLNK(st.st_mode);
195 bool checkACE(const char* url, bool xhr, const DPL::String& tizenId)
198 for (size_t i = 0; ACE_IGNORED_SCHEMA[i]; ++i) {
199 if (0 == strncmp(url,
200 ACE_IGNORED_SCHEMA[i],
201 strlen(ACE_IGNORED_SCHEMA[i])))
208 const char *devCapNamesMarkup = "externalNetworkAccess";
209 const char *devCapNamesXHR = "XMLHttpRequest";
211 ace_request_t aceRequest;
213 aceRequest.widget_handle = WrtDB::WidgetDAOReadOnly::getHandle(tizenId);
215 // TODO! We should get session id from somewhere (outside Widget Process)
216 const std::string session = "";
217 aceRequest.session_id = const_cast<ace_session_id_t>(session.c_str());
218 aceRequest.feature_list.count = 0;
219 aceRequest.dev_cap_list.count = 1;
220 aceRequest.dev_cap_list.items = new ace_dev_cap_t[1];
223 aceRequest.dev_cap_list.items[0].name =
224 const_cast<ace_string_t>(devCapNamesXHR);
226 aceRequest.dev_cap_list.items[0].name =
227 const_cast<ace_string_t>(devCapNamesMarkup);
230 aceRequest.dev_cap_list.items[0].param_list.count = 1;
231 aceRequest.dev_cap_list.items[0].param_list.items = new ace_param_t[1];
232 aceRequest.dev_cap_list.items[0].param_list.items[0].name =
233 const_cast<ace_string_t>(PARAM_URL);
234 aceRequest.dev_cap_list.items[0].param_list.items[0].value =
235 const_cast<ace_string_t>(url);
237 ace_bool_t result = ACE_FALSE;
239 LogDebug("Making ace check with new C-API");
241 ace_return_t ret = ace_check_access(&aceRequest, &result);
243 LogDebug("Result is: " << static_cast<int>(result));
245 delete[] aceRequest.dev_cap_list.items[0].param_list.items;
246 delete[] aceRequest.dev_cap_list.items;
248 return ACE_OK == ret && ACE_TRUE == result;
250 } // namespace (anonymous)
252 namespace InjectedBundleURIHandling {
253 bool processURI(const std::string& inputURI,
254 const DPL::String& tizenId,
255 WrtDB::WidgetSecurityModelVersion version)
257 if (version == WrtDB::WidgetSecurityModelVersion::WIDGET_SECURITY_MODEL_V1)
259 if (!checkWARP(inputURI.c_str(), tizenId))
261 LogWarning("Request was blocked by WARP: " << inputURI);
267 // disable for performance
269 if (!preventSymlink(uri)) {
270 LogWarning("Request for symlink is invalid: " << uri);
278 bool processURI(const DPL::String& inputURI,
279 const DPL::String& tizenId,
280 WrtDB::WidgetSecurityModelVersion version)
282 DPL::Optional<DPL::String> optionalUri(inputURI);
283 if (optionalUri.IsNull()) {
284 LogDebug("uri is empty");
288 std::string uri = DPL::ToUTF8String(inputURI);
290 WrtDB::WidgetSecurityModelVersion::WIDGET_SECURITY_MODEL_V1)
292 if (!checkWARP(uri.c_str(), tizenId)) {
293 LogWarning("Request was blocked by WARP: " << uri);
298 // disable for performance
300 if (!preventSymlink(uri)) {
301 LogWarning("Request for symlink is invalid: " << uri);
309 bool processMainResource(const DPL::String& inputURI,
310 const DPL::String& tizenId,
311 WrtDB::WidgetSecurityModelVersion version)
313 DPL::Optional<DPL::String> optionalUri(inputURI);
314 if (optionalUri.IsNull()) {
315 LogDebug("uri is empty");
319 std::string uri = DPL::ToUTF8String(inputURI);
321 WrtDB::WidgetSecurityModelVersion::WIDGET_SECURITY_MODEL_V1)
323 if (!checkWARP(uri.c_str(), tizenId)) {
324 LogWarning("Request was blocked by WARP: " << uri);
327 } else if (version ==
328 WrtDB::WidgetSecurityModelVersion::WIDGET_SECURITY_MODEL_V2)
330 #ifdef ALLOW_NAVIGATION_ENABLED
331 if (!checkAllowNavigation(uri.c_str(), tizenId)) {
332 LogWarning("Request was blocked by WARP: " << uri);
340 // disable for performance
342 if (!preventSymlink(uri)) {
343 LogWarning("Request for symlink is invalid: " << uri);
351 bool processURIForPlugin(const char* url)
353 if (!checkWhitelist(url)) {
359 std::string localizeURI(const std::string& inputURI, const std::string& tizenId)
361 if (inputURI.compare(0, strlen(SCHEME_TYPE_WIDGET), SCHEME_TYPE_WIDGET) &&
362 inputURI.compare(0, strlen(SCHEME_TYPE_FILE), SCHEME_TYPE_FILE) &&
363 inputURI.compare(0, strlen(SCHEME_TYPE_APP), SCHEME_TYPE_APP))
368 std::string localizedURI = W3CFileLocalization::getFilePathInWidgetPackageFromUrl(tizenId, inputURI);
370 if (localizedURI.empty())
376 return std::string("file://") + localizedURI;
380 DPL::OptionalString localizeURI(const DPL::String& inputURI,
381 const DPL::String& tizenId)
383 std::string uri = DPL::ToUTF8String(inputURI);
384 LogDebug("localizing url: " << uri);
385 auto urlcstr = uri.c_str();
386 const char *end = strstr(urlcstr, ":");
388 LogDebug("no schema in link, return null");
390 return DPL::Optional<DPL::String>::Null;
392 std::string scheme(urlcstr, end);
394 #ifdef APP_SCHEME_ENABLED
395 if (scheme != SCHEME_TYPE_WIDGET && scheme != SCHEME_TYPE_FILE && scheme != SCHEME_TYPE_APP) {
397 if (scheme != SCHEME_TYPE_WIDGET && scheme != SCHEME_TYPE_FILE) {
399 LogDebug("scheme doesn't need to localize");
400 return DPL::OptionalString(inputURI);
403 DPL::Optional<DPL::String> found =
404 W3CFileLocalization::getFilePathInWidgetPackageFromUrl(
406 DPL::FromUTF8String(uri));
408 if (found.IsNull()) {
409 // In this case, path doesn't need to localize. return input uri
410 LogDebug("Path not found within current locale in current widget");
412 return DPL::OptionalString(inputURI);
414 DPL::String uri(L"file://" + *found);
415 LogDebug("Will load resource: " << uri);
416 LogDebug("finished");
417 return DPL::OptionalString(uri);
420 } // namespace InjectedBundleURIHandling