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/secure_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>
46 char const * const SCHEME_TYPE_FILE = "file";
47 char const * const SCHEME_TYPE_WIDGET = "widget";
48 char const * const SCHEME_TYPE_APP = "app";
49 char const * const SCHEME_TYPE_HTTP = "http";
50 char const * const PARAM_URL = "param:url";
51 #ifdef APP_SCHEME_ENABLED
52 char const * const ACE_IGNORED_SCHEMA[] = { "file://", "widget://", "app://",
53 "data:", "tel:", "sms:", "mmsto:",
56 char const * const ACE_IGNORED_SCHEMA[] = { "file://", "widget://", "data:",
57 "tel:", "sms:", "mmsto:", "mailto:",
61 bool wildcardCompare(std::string wildcardString, std::string target)
63 std::string re = wildcardString;
65 // replace special character to meaning character
66 pcrecpp::RE("\\\\").GlobalReplace("\\\\\\\\", &re);
67 pcrecpp::RE("\\.").GlobalReplace("\\\\.", &re);
68 pcrecpp::RE("\\+").GlobalReplace("\\\\+", &re);
69 pcrecpp::RE("\\?").GlobalReplace("\\\\?", &re);
70 pcrecpp::RE("\\^").GlobalReplace("\\\\^", &re);
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);
80 // replace wildcard character to regex type
81 pcrecpp::RE("\\*").GlobalReplace(".*", &re);
83 return pcrecpp::RE(re).FullMatch(target);
86 bool checkWARP(const char *url, const DPL::String& tizenId)
88 // ignore WARP in test mode
89 if (GlobalSettings::WarpTestModeEnabled()) {
93 if (WarpIRI::isIRISchemaIgnored(url)) {
94 // scheme is not supported by WARP
98 WrtDB::WidgetDAOReadOnly dao = WrtDB::WidgetDAOReadOnly(tizenId);
99 WrtDB::WidgetAccessInfoList widgetAccessInfoList;
100 dao.getWidgetAccessInfo(widgetAccessInfoList);
102 // temporary solution for libiri parsing error
103 // This code will be removed
104 std::string urlstr = url;
105 size_t pos = urlstr.find_first_of("#?");
106 if (pos != std::string::npos) {
107 urlstr = urlstr.substr(0, pos);
110 return (static_cast<WidgetAccessList>(widgetAccessInfoList)).isRequiredIRI(
111 DPL::FromUTF8String(urlstr));
114 bool checkWhitelist(const char *url)
120 iri_t* iri = iri_parse(url);
124 if (!iri->scheme || !iri->host || strlen(iri->host) == 0) {
129 std::string scheme = iri->scheme;
130 std::string host = iri->host;
133 if (scheme.find(SCHEME_TYPE_HTTP) == std::string::npos) {
137 WidgetAccessList whiteURIList(WrtDB::GlobalDAOReadOnly::GetWhiteURIList());
138 return whiteURIList.isRequiredIRI(DPL::FromUTF8String(host));
141 bool checkAllowNavigation(const char *url, const DPL::String& tizenId)
147 DPL::ScopedPtr<iri_t> iri(iri_parse(url));
148 if (!iri->scheme || !iri->host || strlen(iri->host) == 0) {
151 std::string scheme = iri->scheme;
152 std::string host = iri->host;
154 if (scheme.find(SCHEME_TYPE_HTTP) == std::string::npos) {
158 WrtDB::WidgetDAOReadOnly dao = WrtDB::WidgetDAOReadOnly(tizenId);
159 WrtDB::WidgetAllowNavigationInfoList list;
160 dao.getWidgetAllowNavigationInfo(list);
163 if (wildcardCompare(DPL::ToUTF8String(it->scheme), scheme) &&
164 wildcardCompare(DPL::ToUTF8String(it->host), host))
173 bool preventSymlink(const std::string & url)
175 if(0 != strncmp(url.c_str(), SCHEME_TYPE_FILE, strlen(SCHEME_TYPE_FILE)))
180 if(url.size() >= strlen(SCHEME_TYPE_FILE) + 3)
182 std::string file = url.substr(strlen(SCHEME_TYPE_FILE) + 3);
184 if(0 != stat(file.c_str(), &st)) return true;
185 return !S_ISLNK(st.st_mode);
193 bool checkACE(const char* url, bool xhr, const DPL::String& tizenId)
196 for (size_t i = 0; ACE_IGNORED_SCHEMA[i]; ++i) {
197 if (0 == strncmp(url,
198 ACE_IGNORED_SCHEMA[i],
199 strlen(ACE_IGNORED_SCHEMA[i])))
206 const char *devCapNamesMarkup = "externalNetworkAccess";
207 const char *devCapNamesXHR = "XMLHttpRequest";
209 ace_request_t aceRequest;
211 aceRequest.widget_handle = WrtDB::WidgetDAOReadOnly::getHandle(tizenId);
213 // TODO! We should get session id from somewhere (outside Widget Process)
214 const std::string session = "";
215 aceRequest.session_id = const_cast<ace_session_id_t>(session.c_str());
216 aceRequest.feature_list.count = 0;
217 aceRequest.dev_cap_list.count = 1;
218 aceRequest.dev_cap_list.items = new ace_dev_cap_t[1];
221 aceRequest.dev_cap_list.items[0].name =
222 const_cast<ace_string_t>(devCapNamesXHR);
224 aceRequest.dev_cap_list.items[0].name =
225 const_cast<ace_string_t>(devCapNamesMarkup);
228 aceRequest.dev_cap_list.items[0].param_list.count = 1;
229 aceRequest.dev_cap_list.items[0].param_list.items = new ace_param_t[1];
230 aceRequest.dev_cap_list.items[0].param_list.items[0].name =
231 const_cast<ace_string_t>(PARAM_URL);
232 aceRequest.dev_cap_list.items[0].param_list.items[0].value =
233 const_cast<ace_string_t>(url);
235 ace_check_result_t result = ACE_PRIVILEGE_DENIED;
236 ace_return_t ret = ace_check_access_ex(&aceRequest, &result);
238 _D("Result is: %d", static_cast<int>(result));
240 delete[] aceRequest.dev_cap_list.items[0].param_list.items;
241 delete[] aceRequest.dev_cap_list.items;
243 return ACE_OK == ret && ACE_ACCESS_GRANTED == result;
245 } // namespace (anonymous)
247 namespace InjectedBundleURIHandling {
248 bool processURI(const std::string& inputURI,
249 const DPL::String& tizenId,
250 WrtDB::WidgetSecurityModelVersion version)
252 if (version == WrtDB::WidgetSecurityModelVersion::WIDGET_SECURITY_MODEL_V1)
254 if (!checkWARP(inputURI.c_str(), tizenId)) {
255 _E("Request was blocked by WARP: %s", inputURI.c_str());
260 // disable for performance
261 // if (!preventSymlink(inputURI)) {
262 // LogWarning("Request for symlink is invalid: " << inputURI);
269 bool processURI(const DPL::String& inputURI,
270 const DPL::String& tizenId,
271 WrtDB::WidgetSecurityModelVersion version)
273 DPL::Optional<DPL::String> optionalUri(inputURI);
274 if (optionalUri.IsNull()) {
279 std::string uri = DPL::ToUTF8String(inputURI);
280 return processURI(uri, tizenId, version);
283 bool processMainResource(const DPL::String& inputURI,
284 const DPL::String& tizenId,
285 WrtDB::WidgetSecurityModelVersion version)
287 DPL::Optional<DPL::String> optionalUri(inputURI);
288 if (optionalUri.IsNull()) {
293 std::string uri = DPL::ToUTF8String(inputURI);
295 WrtDB::WidgetSecurityModelVersion::WIDGET_SECURITY_MODEL_V1)
297 if (!checkWARP(uri.c_str(), tizenId)) {
298 _E("Request was blocked by WARP: %s", uri.c_str());
301 } else if (version ==
302 WrtDB::WidgetSecurityModelVersion::WIDGET_SECURITY_MODEL_V2)
304 #ifdef ALLOW_NAVIGATION_ENABLED
305 if (!checkAllowNavigation(uri.c_str(), tizenId)) {
306 _E("Request was blocked by allow-navigation: %s", uri.c_str());
314 // disable for performance
315 // if (!preventSymlink(uri)) {
316 // LogWarning("Request for symlink is invalid: " << uri);
322 bool processURIForPlugin(const char* url)
324 return checkWhitelist(url);
327 std::string localizeURI(const std::string& inputURI, const std::string& tizenId)
329 if (inputURI.compare(0, strlen(SCHEME_TYPE_WIDGET), SCHEME_TYPE_WIDGET) &&
330 inputURI.compare(0, strlen(SCHEME_TYPE_FILE), SCHEME_TYPE_FILE) &&
331 inputURI.compare(0, strlen(SCHEME_TYPE_APP), SCHEME_TYPE_APP))
333 _D("scheme doesn't need to localize");
337 std::string localizedURI = W3CFileLocalization::getFilePathInWidgetPackageFromUrl(tizenId, inputURI);
339 if (localizedURI.empty()) {
342 return std::string("file://") + localizedURI;
346 DPL::OptionalString localizeURI(const DPL::String& inputURI,
347 const DPL::String& tizenId)
349 std::string uri = DPL::ToUTF8String(inputURI);
350 const char* urlcstr = uri.c_str();
351 const char *end = strstr(urlcstr, ":");
353 _W("no schema in link, return null");
354 return DPL::Optional<DPL::String>::Null;
356 std::string scheme(urlcstr, end);
358 #ifdef APP_SCHEME_ENABLED
359 if (scheme != SCHEME_TYPE_WIDGET && scheme != SCHEME_TYPE_FILE && scheme != SCHEME_TYPE_APP) {
361 if (scheme != SCHEME_TYPE_WIDGET && scheme != SCHEME_TYPE_FILE) {
363 _D("scheme doesn't need to localize");
364 return DPL::OptionalString(inputURI);
367 DPL::Optional<DPL::String> found =
368 W3CFileLocalization::getFilePathInWidgetPackageFromUrl(
370 DPL::FromUTF8String(uri));
372 if (found.IsNull()) {
373 // In this case, path doesn't need to localize. return input uri
374 _W("Path not found within current locale in current widget");
375 return DPL::OptionalString(inputURI);
377 DPL::String uri(L"file://" + *found);
378 _D("Will load resource: %s", DPL::ToUTF8String(uri).c_str());
379 return DPL::OptionalString(uri);
382 } // namespace InjectedBundleURIHandling