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
44 char const * const SCHEME_TYPE_FILE = "file";
45 char const * const SCHEME_TYPE_WIDGET = "widget";
46 char const * const SCHEME_TYPE_APP = "app";
47 char const * const SCHEME_TYPE_HTTP = "http";
48 char const * const PARAM_URL = "param:url";
49 #ifdef APP_SCHEME_ENABLED
50 char const * const ACE_IGNORED_SCHEMA[] = { "file://", "widget://", "app://",
51 "data:", "tel:", "sms:", "mmsto:",
54 char const * const ACE_IGNORED_SCHEMA[] = { "file://", "widget://", "data:",
55 "tel:", "sms:", "mmsto:", "mailto:",
59 bool wildcardCompare(std::string wildcardString, std::string target)
61 std::string re = wildcardString;
63 // replace special character to meaning character
64 pcrecpp::RE("\\\\").GlobalReplace("\\\\\\\\", &re);
65 pcrecpp::RE("\\.").GlobalReplace("\\\\.", &re);
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);
78 // replace wildcard character to regex type
79 pcrecpp::RE("\\*").GlobalReplace(".*", &re);
81 return pcrecpp::RE(re).FullMatch(target);
84 bool checkWARP(const char *url, const DPL::String& tizenId)
86 // ignore WARP in test mode
87 if (GlobalSettings::WarpTestModeEnabled()) {
91 if (WarpIRI::isIRISchemaIgnored(url)) {
92 // scheme is not supported by WARP
96 WrtDB::WidgetDAOReadOnly dao = WrtDB::WidgetDAOReadOnly(tizenId);
97 WrtDB::WidgetAccessInfoList widgetAccessInfoList;
98 dao.getWidgetAccessInfo(widgetAccessInfoList);
100 // temporary solution for libiri parsing error
101 // This code will be removed
102 std::string urlstr = url;
103 size_t pos = urlstr.find_first_of("#?");
104 if (pos != std::string::npos) {
105 urlstr = urlstr.substr(0, pos);
108 return (static_cast<WidgetAccessList>(widgetAccessInfoList)).isRequiredIRI(
109 DPL::FromUTF8String(urlstr));
112 bool checkWhitelist(const char *url)
118 iri_t* iri = iri_parse(url);
122 if (!iri->scheme || !iri->host || strlen(iri->host) == 0) {
127 std::string scheme = iri->scheme;
128 std::string host = iri->host;
131 if (scheme.find(SCHEME_TYPE_HTTP) == std::string::npos) {
138 bool checkAllowNavigation(const char *url, const DPL::String& tizenId)
144 DPL::ScopedPtr<iri_t> iri(iri_parse(url));
145 if (!iri->scheme || !iri->host || strlen(iri->host) == 0) {
148 std::string scheme = iri->scheme;
149 std::string host = iri->host;
151 if (scheme.find(SCHEME_TYPE_HTTP) == std::string::npos) {
155 WrtDB::WidgetDAOReadOnly dao = WrtDB::WidgetDAOReadOnly(tizenId);
156 WrtDB::WidgetAllowNavigationInfoList list;
157 dao.getWidgetAllowNavigationInfo(list);
160 if (wildcardCompare(DPL::ToUTF8String(it->scheme), scheme) &&
161 wildcardCompare(DPL::ToUTF8String(it->host), host))
170 bool preventSymlink(const std::string & url)
172 if(0 != strncmp(url.c_str(), SCHEME_TYPE_FILE, strlen(SCHEME_TYPE_FILE)))
177 if(url.size() >= strlen(SCHEME_TYPE_FILE) + 3)
179 std::string file = url.substr(strlen(SCHEME_TYPE_FILE) + 3);
181 if(0 != stat(file.c_str(), &st)) return true;
182 return !S_ISLNK(st.st_mode);
190 bool checkACE(const char* url, bool xhr, const DPL::String& tizenId)
193 for (size_t i = 0; ACE_IGNORED_SCHEMA[i]; ++i) {
194 if (0 == strncmp(url,
195 ACE_IGNORED_SCHEMA[i],
196 strlen(ACE_IGNORED_SCHEMA[i])))
203 const char *devCapNamesMarkup = "externalNetworkAccess";
204 const char *devCapNamesXHR = "XMLHttpRequest";
206 ace_request_t aceRequest;
208 aceRequest.widget_handle = WrtDB::WidgetDAOReadOnly::getHandle(tizenId);
210 // TODO! We should get session id from somewhere (outside Widget Process)
211 const std::string session = "";
212 aceRequest.session_id = const_cast<ace_session_id_t>(session.c_str());
213 aceRequest.feature_list.count = 0;
214 aceRequest.dev_cap_list.count = 1;
215 aceRequest.dev_cap_list.items = new ace_dev_cap_t[1];
218 aceRequest.dev_cap_list.items[0].name =
219 const_cast<ace_string_t>(devCapNamesXHR);
221 aceRequest.dev_cap_list.items[0].name =
222 const_cast<ace_string_t>(devCapNamesMarkup);
225 aceRequest.dev_cap_list.items[0].param_list.count = 1;
226 aceRequest.dev_cap_list.items[0].param_list.items = new ace_param_t[1];
227 aceRequest.dev_cap_list.items[0].param_list.items[0].name =
228 const_cast<ace_string_t>(PARAM_URL);
229 aceRequest.dev_cap_list.items[0].param_list.items[0].value =
230 const_cast<ace_string_t>(url);
232 ace_check_result_t result = ACE_PRIVILEGE_DENIED;
233 ace_return_t ret = ace_check_access_ex(&aceRequest, &result);
235 _D("Result is: %d", static_cast<int>(result));
237 delete[] aceRequest.dev_cap_list.items[0].param_list.items;
238 delete[] aceRequest.dev_cap_list.items;
240 return ACE_OK == ret && ACE_ACCESS_GRANTED == result;
242 } // namespace (anonymous)
244 namespace InjectedBundleURIHandling {
245 bool processURI(const std::string& inputURI,
246 const DPL::String& tizenId,
247 WrtDB::WidgetSecurityModelVersion version)
249 if (version == WrtDB::WidgetSecurityModelVersion::WIDGET_SECURITY_MODEL_V1)
251 if (!checkWARP(inputURI.c_str(), tizenId)) {
252 _E("Request was blocked by WARP: %s", inputURI.c_str());
257 // disable for performance
258 // if (!preventSymlink(inputURI)) {
259 // LogWarning("Request for symlink is invalid: " << inputURI);
266 bool processURI(const DPL::String& inputURI,
267 const DPL::String& tizenId,
268 WrtDB::WidgetSecurityModelVersion version)
270 DPL::Optional<DPL::String> optionalUri(inputURI);
271 if (optionalUri.IsNull()) {
276 std::string uri = DPL::ToUTF8String(inputURI);
277 return processURI(uri, tizenId, version);
280 bool processMainResource(const DPL::String& inputURI,
281 const DPL::String& tizenId,
282 WrtDB::WidgetSecurityModelVersion version)
284 DPL::Optional<DPL::String> optionalUri(inputURI);
285 if (optionalUri.IsNull()) {
290 std::string uri = DPL::ToUTF8String(inputURI);
292 WrtDB::WidgetSecurityModelVersion::WIDGET_SECURITY_MODEL_V1)
294 if (!checkWARP(uri.c_str(), tizenId)) {
295 _E("Request was blocked by WARP: %s", uri.c_str());
298 } else if (version ==
299 WrtDB::WidgetSecurityModelVersion::WIDGET_SECURITY_MODEL_V2)
301 #ifdef ALLOW_NAVIGATION_ENABLED
302 if (!checkAllowNavigation(uri.c_str(), tizenId)) {
303 _E("Request was blocked by allow-navigation: %s", uri.c_str());
311 // disable for performance
312 // if (!preventSymlink(uri)) {
313 // LogWarning("Request for symlink is invalid: " << uri);
319 bool processURIForPlugin(const char* url)
321 return checkWhitelist(url);
324 std::string localizeURI(const std::string& inputURI, const std::string& tizenId)
326 if (inputURI.compare(0, strlen(SCHEME_TYPE_WIDGET), SCHEME_TYPE_WIDGET) &&
327 inputURI.compare(0, strlen(SCHEME_TYPE_FILE), SCHEME_TYPE_FILE) &&
328 inputURI.compare(0, strlen(SCHEME_TYPE_APP), SCHEME_TYPE_APP))
330 _D("scheme doesn't need to localize");
334 std::string localizedURI = W3CFileLocalization::getFilePathInWidgetPackageFromUrl(tizenId, inputURI);
336 if (localizedURI.empty()) {
339 return std::string("file://") + localizedURI;
343 DPL::OptionalString localizeURI(const DPL::String& inputURI,
344 const DPL::String& tizenId)
346 std::string uri = DPL::ToUTF8String(inputURI);
347 const char* urlcstr = uri.c_str();
348 const char *end = strstr(urlcstr, ":");
350 _W("no schema in link, return null");
351 return DPL::Optional<DPL::String>::Null;
353 std::string scheme(urlcstr, end);
355 #ifdef APP_SCHEME_ENABLED
356 if (scheme != SCHEME_TYPE_WIDGET && scheme != SCHEME_TYPE_FILE && scheme != SCHEME_TYPE_APP) {
358 if (scheme != SCHEME_TYPE_WIDGET && scheme != SCHEME_TYPE_FILE) {
360 _D("scheme doesn't need to localize");
361 return DPL::OptionalString(inputURI);
364 DPL::Optional<DPL::String> found =
365 W3CFileLocalization::getFilePathInWidgetPackageFromUrl(
367 DPL::FromUTF8String(uri));
369 if (found.IsNull()) {
370 // In this case, path doesn't need to localize. return input uri
371 _W("Path not found within current locale in current widget");
372 return DPL::OptionalString(inputURI);
374 DPL::String uri(L"file://" + *found);
375 _D("Will load resource: %s", DPL::ToUTF8String(uri).c_str());
376 return DPL::OptionalString(uri);
379 } // namespace InjectedBundleURIHandling