c4c87d1a7c81923d66d4eaad3561000cebab3344
[platform/framework/web/wrt.git] / src / view / webkit / injected-bundle / wrt-injected-bundle.cpp
1 /*
2  * Copyright (c) 2011 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    wrt-injected-bundle.cpp
18  * @author  Lukasz Wrzosek (l.wrzosek@samsung.com)
19  * @brief   Implementation file for injected bundle
20  */
21 #include "wrt-injected-bundle.h"
22
23 #include <WKBundle.h>
24 #include <WKBundleInitialize.h>
25 #include <WKBundlePage.h>
26 #include <WKBundleFrame.h>
27 #include <WKURLRequest.h>
28 #include <WKString.h>
29 #include <WKType.h>
30 #include <WKURL.h>
31 #include <WKError.h>
32 #include <WKURLResponseTizen.h>
33 #include <WKBundlePagePrivate.h>
34 #include <WKBundlePrivate.h>
35
36 #include <string>
37 #include <cstdio>
38 #include <sstream>
39 #include <sys/stat.h>
40 #include <set>
41 #include <openssl/sha.h>
42 #include <openssl/hmac.h>
43 #include <openssl/evp.h>
44 #include <openssl/bio.h>
45 #include <openssl/buffer.h>
46
47 #include <dpl/log/log.h>
48 #include <dpl/foreach.h>
49 #include <dpl/assert.h>
50 #include <dpl/wrt-dao-ro/WrtDatabase.h>
51 #include <dpl/localization/localization_utils.h>
52 #include <dpl/string.h>
53 #include <dpl/wrt-dao-ro/global_config.h>
54 #include <dpl/wrt-dao-ro/widget_dao_read_only.h>
55 #include <dpl/wrt-dao-ro/common_dao_types.h>
56 #include <dpl/utils/mime_type_utils.h>
57 #include <dpl/localization/LanguageTagsProvider.h>
58 #include <dpl/event/main_event_dispatcher.h>
59 #ifdef DECRYPT
60 #include <FBaseByteBuffer.h>
61 #include <security/FSecCrypto_TrustZoneService.h>
62 #endif
63
64 #include <wrt_plugin_module.h>
65 #include <profiling_util.h>
66
67 #include <vconf.h>
68 #include <appcore-efl.h>
69
70 #include "messages_names.h"
71
72 #include <scheme.h>
73 #include <scheme_action_map_type.h>
74 #include <scheme_action_map_data.h>
75
76 #include <js_overlay_types.h>
77
78 #include <sys/time.h>
79 #include <sys/resource.h>
80 #include <privilege-control.h>
81
82 // URI localization on WebProcess side
83 #include "injected_bundle_uri_handling.h"
84 extern "C" {
85 void InitWebAppInfo(const char* appId, const char* rootPath);
86 }
87
88 namespace {
89 const char * const uriBlockedMessageName = "uri_blocked_msg";
90 #ifdef MULTIPROCESS_SERVICE_SUPPORT_INLINE
91 const char * const webProcessPidMessageName = "web_process_pid_msg";
92 #endif
93 const char * const SCHEME_HTTP = "http";
94 const char * const SCHEME_HTTPS = "https";
95 const char * const SCHEME_FILE = "file";
96 const char * const SCHEME_FILE_SLASH = "file://";
97 const char * const SCHEME_BOX_SLASH = "box://";
98 const char * const DATA_STRING = "data:";
99 const char * const BASE64_STRING = ";base64,";
100 const char * const BLANK_PAGE_URL = "about:blank";
101 const char * const HTML_MIME = "text/html";
102 const char * const PHP_MIME = "application/x-php";
103 const char * const VIEWMODE_TYPE_FULLSCREEN = "fullscreen";
104 const char * const VIEWMODE_TYPE_MAXIMIZED = "maximized";
105 const std::size_t FILE_BUF_MAX_SIZE = 1024; // bytes
106 const std::size_t PLAIN_CHUNK_SIZE = 1008; // bytes
107 const unsigned int UID_ROOT = 0;
108 const unsigned int DEFAULT_PRIORITY = 0;
109 const char * const PRIVILEGE_APP_TYPE = "wgt";
110 #ifdef CORS_WHITELISTING_ENABLED
111 const char * const warpAllowProtocolsForWildcard[] = { "http", "https" };
112 #endif
113
114 #ifdef DECRYPT
115 static bool m_initWebApp = false;
116
117 Tizen::Base::ByteBuffer *DecryptChunkByTrustZone(
118         Tizen::Base::ByteBuffer *appInfo,
119         const unsigned char *inBuffer,
120         int inBufSize)
121 {
122     using namespace Tizen::Base;
123
124     if (!m_initWebApp) {
125         char* pAppId = null;
126         pAppId = (char*)calloc(appInfo->GetRemaining()+1, 1);
127         memcpy(pAppId, appInfo->GetPointer(), appInfo->GetRemaining());
128
129         InitWebAppInfo(pAppId, "");
130         free (pAppId);
131         m_initWebApp = true;
132     }
133
134     Tizen::Security::Crypto::_TrustZoneService* pInstance;
135     pInstance = Tizen::Security::Crypto::_TrustZoneService::GetInstance();
136
137     ByteBuffer pBuf;
138     pBuf.Construct(inBufSize);
139     const byte *pByte = reinterpret_cast<const byte*>(inBuffer);
140
141     if (pBuf.SetArray(pByte, 0, inBufSize) != E_SUCCESS) {
142         LogDebug("Couldnot set pBuf");
143         return NULL;
144     }
145
146     pBuf.Flip();
147
148     return pInstance->_TrustZoneService::DecryptN(*appInfo, pBuf);
149 }
150 #endif // DECRYPT
151
152 }
153
154 Bundle::Bundle(WKBundleRef bundle) :
155     m_bundle(bundle),
156     m_scale(0),
157     m_encodedBundle(""),
158     m_theme(""),
159     m_willRemoveContext(NULL),
160     m_encrypted(false),
161     m_widgetType(WrtDB::APP_TYPE_UNKNOWN),
162     m_securityModelVersion(
163         WrtDB::WidgetSecurityModelVersion::WIDGET_SECURITY_MODEL_V1),
164     m_initialized(false)
165 {
166     LOG_PROFILE_START("Bundle attachToThread");
167     WrtDB::WrtDatabase::attachToThreadRO();
168     LOG_PROFILE_STOP("Bundle attachToThread");
169 #ifdef MULTIPROCESS_SERVICE_SUPPORT_INLINE
170     sendWebProcessPid();
171 #endif
172 }
173
174 Bundle::~Bundle()
175 {
176     WrtDB::WrtDatabase::detachFromThread();
177
178     if (!m_pagesList.empty()) {
179         LogError("There are not closed pages!");
180     }
181     WKRelease(m_bundle);
182 }
183
184 void Bundle::didCreatePageCallback(
185     WKBundleRef /*bundle*/,
186     WKBundlePageRef page,
187     const void* clientInfo)
188 {
189     LOG_PROFILE_START("didCreatePageCallback");
190     LogDebug("didCreatePageCallback called");
191     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
192     This->didCreatePage(page);
193     LOG_PROFILE_STOP("didCreatePageCallback");
194 }
195
196 void Bundle::didReceiveMessageCallback(
197     WKBundleRef /*bundle*/,
198     WKStringRef messageName,
199     WKTypeRef messageBody,
200     const void *clientInfo)
201 {
202     LogDebug("didReceiveMessageCallback called");
203     Bundle* bundle = static_cast<Bundle*>(const_cast<void*>(clientInfo));
204     bundle->didReceiveMessage(messageName, messageBody);
205 }
206
207 void Bundle::willDestroyPageCallback(
208     WKBundleRef /*bundle*/,
209     WKBundlePageRef page,
210     const void* clientInfo)
211 {
212     LogDebug("willDestroyPageCallback called");
213     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
214     This->willDestroyPage(page);
215 }
216
217 void Bundle::didCreatePage(WKBundlePageRef page)
218 {
219     auto mainFrame = WKBundlePageGetMainFrame(page);
220     auto context = WKBundleFrameGetJavaScriptContext(mainFrame);
221     m_pagesList.push_back(page);
222     m_pageGlobalContext.insertContextForPage(page, context);
223     LogDebug("created Page : " << page << " created JSContext : " << context);
224
225     WKBundlePageResourceLoadClient resourceLoadClient = {
226         kWKBundlePageResourceLoadClientCurrentVersion,  /* version */
227         this, /* clientinfo */
228         0, /* didInitiateLoadForResource */
229         willSendRequestForFrameCallback, /* willSendRequestForFrame */
230         0, /* didReceiveResponseForResource */
231         0, /* didReceiveContentLengthForResource */
232         didFinishLoadForResourceCallback, /* didFinishLoadForResource */
233         0, /* didFailLoadForResource */
234         0, /* shouldCacheResponse */
235         0, /* shouldUseCredentialStorage */
236     };
237     WKBundlePageSetResourceLoadClient(page, &resourceLoadClient);
238
239     WKBundlePageLoaderClient loaderClient = {
240         kWKBundlePageLoaderClientCurrentVersion,
241         this, /* clientinfo */
242         didStartProvisionalLoadForFrameCallback, /* didStartProvisionalLoadForFrame */
243         0, /* didReceiveServerRedirectForProvisionalLoadForFrame */
244         0, /* didFailProvisionalLoadWithErrorForFrame */
245         didCommitLoadForFrameCallback, /* didCommitLoadForFrame */
246         0, /* didFinishDocumentLoadForFrame */
247         0, /* didFinishLoadForFrame */
248         0, /* didFailLoadWithErrorForFrame */
249         0, /* didSameDocumentNavigationForFrame */
250         0, /* didReceiveTitleForFrame */
251         0, /* didFirstLayoutForFrame */
252         0, /* didFirstVisuallyNonEmptyLayoutForFrame */
253         didRemoveFrameFromHierarchyCallback, /* didRemoveFrameFromHierarchy */
254         0, /* didDisplayInsecureContentForFrame */
255         0, /* didRunInsecureContentForFrame */
256         0, /* didClearWindowObjectForFrame */
257         0, /* didCancelClientRedirectForFrame */
258         0, /* willPerformClientRedirectForFrame */
259         0, /* didHandleOnloadEventsForFrame */
260         0, /* didLayoutForFrame */
261         0, /* didNewFirstVisuallyNonEmptyLayout */
262         0, /* didDetectXSSForFrame */
263         0, /* shouldGoToBackForwardListItem */
264         0, /* globalObjectIsAvailableForFrame */
265         0, /* willDisconnectDOMWindowExtensionFromGlobalObject */
266         0, /* didReconnectDOMWindowExtensionToGlobalObject */
267         0, /* willDestroyGlobalObjectForDOMWindowExtension */
268         0, /* didFinishProgress */
269         0, /* shouldForceUniversalAccessFromLocalURL */
270         0, /* didReceiveIntentForFrame */
271         0, /* registerIntentServiceForFrame */
272     };
273     WKBundlePageSetPageLoaderClient(page, &loaderClient);
274
275
276     WKBundlePagePolicyClient policyClient = {
277         kWKBundlePagePolicyClientCurrentVersion, /* version */
278         this,                                    /* clientInfo */
279         decidePolicyForNavigationActionCallback, /* decidePolicyForNavigationAction */
280         decidePolicyForNewWindowActionCallback,  /* decidePolicyForNavigationAction */
281         decidePolicyForResponseCallback,         /* decidePolicyForResponse */
282         0,                                       /* unableToImplementPolicy */
283     };
284     WKBundlePageSetPolicyClient(page, &policyClient);
285 }
286
287 void Bundle::willDestroyPage(WKBundlePageRef page)
288 {
289     LogDebug("Destroyed page : " << page);
290
291     auto context = m_pageGlobalContext.getContextForPage(page);
292     m_pagesList.remove(page);
293     m_pageGlobalContext.removeContextForPage(page);
294     m_pageContext[page].erase(context);
295
296     PluginModule::unloadFrame(context);
297     PluginModule::stop(context);
298 }
299
300 void Bundle::fixWKMessageArgs(std::string & argScale,
301                               std::string & argEncodedBundle,
302                               std::string & argTheme)
303 {
304     if (argScale != "null" && argScale[0] == '_') {
305         argScale.erase(0, 1);
306
307         std::stringstream ssScale(argScale);
308         ssScale >> m_scale;
309     }
310
311     if (argEncodedBundle != "null" && argEncodedBundle[0] == '_') {
312         argEncodedBundle.erase(0, 1);
313
314         m_encodedBundle = argEncodedBundle;
315     }
316
317     if (argTheme != "null" && argTheme[0] == '_') {
318         argTheme.erase(0, 1);
319
320         m_theme = argTheme;
321     }
322 }
323
324 #ifdef CORS_WHITELISTING_ENABLED
325 void Bundle::bypassCORSforWARPAccessList(WrtDB::WidgetDAOReadOnly & dao)
326 {
327     // bypassing CORS using origin whitelist
328     WrtDB::WidgetAccessInfoList WAList;
329     dao.getWidgetAccessInfo(WAList);
330     FOREACH(it, WAList)
331     {
332         const WrtDB::WidgetAccessInfo & access = *it;
333         WKURLRef url = WKURLCreateWithUTF8CString(DPL::ToUTF8String(access.strIRI).c_str());
334
335 #ifdef APP_SCHEME_ENABLED
336         std::string source = std::string("app://") + DPL::ToUTF8String(m_widgetTizenId) + "/";
337 #else
338         std::string source = DPL::ToUTF8String(dao.getFullPath());
339 #endif
340
341         LogDebug("WARP to WK whitelist position: " << source << " for "
342             << access.strIRI << " subDomains: " << access.bSubDomains);
343
344         WKStringRef wkSource = WKStringCreateWithUTF8CString(source.c_str());
345         WKStringRef wkHost;
346         WKStringRef wkProtocol;
347         if(access.strIRI == L"*")
348         {
349             //wildcard force to explicitly say which protocol is used
350             // passed wkHost if empty means wildcard -> allow everything but protocol has to be set.
351             for(unsigned i = 0; i < sizeof(warpAllowProtocolsForWildcard) / sizeof(char*); i++)
352             {
353                 wkHost = WKStringCreateWithUTF8CString("");
354                 wkProtocol = WKStringCreateWithUTF8CString(warpAllowProtocolsForWildcard[i]);
355                 WKBundleAddOriginAccessWhitelistEntry(m_bundle,
356                     wkSource, wkProtocol, wkHost, access.bSubDomains);
357             }
358         }
359         else
360         {
361             wkHost = WKURLCopyHostName(url);
362             wkProtocol = WKURLCopyScheme(url);
363             WKBundleAddOriginAccessWhitelistEntry(m_bundle,
364                 wkSource, wkProtocol, wkHost, access.bSubDomains);
365         }
366
367         WKRelease(wkHost);
368         WKRelease(wkProtocol);
369         WKRelease(wkSource);
370     }
371 }
372 #endif
373
374 void Bundle::didReceiveMessage(WKStringRef messageName, WKTypeRef messageBody)
375 {
376     LogDebug("got message type: " << toString(messageName).c_str());
377     if (WKStringIsEqualToUTF8CString(messageName,
378                                      BundleMessages::START))
379     {
380         if (!messageBody || WKStringGetTypeID() != WKGetTypeID(messageBody)) {
381             LogError("Wrong message format received, ignoring");
382             return;
383         }
384
385         auto msgString = toString(static_cast<WKStringRef>(messageBody));
386         LogDebug("Got message text: " << msgString);
387         LogDebug("loading Page : " << m_pagesList.back() <<
388                  " loading JSContext : " <<
389                  m_pageGlobalContext.getContextForPage(m_pagesList.back()));
390         // set information from ui process
391         std::stringstream ssMsg(msgString);
392         std::string argScale;
393         std::string argEncodedBundle;
394         std::string argTheme;
395
396         std::string id;
397         ssMsg >> id;
398         m_widgetTizenId = DPL::FromASCIIString(id);
399
400         ssMsg >> argScale;
401         ssMsg >> argEncodedBundle;
402         ssMsg >> argTheme;
403         ssMsg >> m_encrypted;
404         LogWarning("m_encrypted : " << m_encrypted);
405
406         // ** Language tags setting completed **
407         fixWKMessageArgs(argScale, argEncodedBundle, argTheme);
408     } else if (WKStringIsEqualToUTF8CString(messageName,
409                                             BundleMessages::SHUTDOWN))
410     {
411         LogDebug("shutdown plugins");
412
413         if (m_pagesList.empty()) {
414             PluginModule::shutdown();
415         } else {
416             LogInfo(
417                 "PluginModule shutdown ignored, there are still alive pages!");
418         }
419     }
420     else if (WKStringIsEqualToUTF8CString(messageName,
421                                           BundleMessages::SET_CUSTOM_PROPERTIES))
422     {
423         LogDebug("reset custom properties of window objects");
424         // set information from ui process
425         auto msgString = toString(static_cast<WKStringRef>(messageBody));
426
427         std::string argScale;
428         std::string argEncodedBundle;
429         std::string argTheme;
430
431         std::stringstream ssMsg(msgString);
432         ssMsg >> argScale;
433         ssMsg >> argEncodedBundle;
434         ssMsg >> argTheme;
435
436         fixWKMessageArgs(argScale, argEncodedBundle, argTheme);
437
438         //apply for each context
439         PageGlobalContextContainer::const_iterator it = m_pageGlobalContext.begin();
440         for (; it != m_pageGlobalContext.end(); ++it) {
441             PluginModule::setCustomProperties(it->second,
442                                               m_scale,
443                                               m_encodedBundle.c_str(),
444                                               m_theme.c_str());
445         }
446     } else if (WKStringIsEqualToUTF8CString(
447                    messageName,
448                    BundleMessages::DISPATCH_JAVASCRIPT_EVENT))
449     {
450         LogDebug("dispatch javascript event to created frames");
451         // set information from ui process
452         auto text = toString(static_cast<WKStringRef>(messageBody));
453         int eventType;
454         void *args = NULL;
455         std::stringstream ss(text);
456         ss >> eventType;
457
458         using namespace WrtPlugins::W3C;
459         // set arguments to be sent to js handler of this custom event
460         if (eventType == SoftKeyboardChangeCustomEvent) {
461             args = new SoftKeyboardChangeArgs;
462             ss >> static_cast<SoftKeyboardChangeArgs *>(args)->state;
463             ss >> static_cast<SoftKeyboardChangeArgs *>(args)->width;
464             ss >> static_cast<SoftKeyboardChangeArgs *>(args)->height;
465         }
466
467         //apply for each context
468         PageGlobalContextContainer::const_iterator it = m_pageGlobalContext.begin();
469         for (; it != m_pageGlobalContext.end(); ++it) {
470             PluginModule::dispatchJavaScriptEvent(
471                 it->second,
472                 static_cast<WrtPlugins::W3C::CustomEventType>(eventType),
473                 args);
474         }
475
476         if (args) {
477             delete static_cast<SoftKeyboardChangeArgs *>(args);
478         }
479     } else if (WKStringIsEqualToUTF8CString(
480                    messageName,
481                    BundleMessages::INIT))
482     {
483         LogDebug("initializing plugins");
484
485         if (!m_initialized)
486         {
487             auto msgString = toString(static_cast<WKStringRef>(messageBody));
488
489             m_widgetTizenId = DPL::FromASCIIString(msgString);
490
491             WrtDB::WidgetDAOReadOnly dao(m_widgetTizenId);
492
493             // process pool - set app_privilige
494             if (UID_ROOT == getuid())
495             {
496                 using namespace WrtDB::GlobalConfig;
497
498                 std::string appPath;
499                 std::string tzAppId = DPL::ToUTF8String(dao.getTzAppId());
500                 std::string tzPkgId = DPL::ToUTF8String(dao.getTizenPkgId());
501                 DPL::OptionalString installedPath = dao.getWidgetInstalledPath();
502                 if (installedPath.IsNull()) {
503                     appPath = std::string(GetUserInstalledWidgetPath()) + "/" +
504                         tzPkgId + GetUserWidgetExecPath() + "/" + tzAppId;
505                 } else {
506                     appPath = DPL::ToUTF8String(*installedPath) +
507                         GetUserWidgetExecPath() + "/" + tzAppId;
508                 }
509
510                 LogDebug("set_app_privilege(" << appPath << ")");
511                 set_app_privilege(tzPkgId.c_str(), PRIVILEGE_APP_TYPE, appPath.c_str());
512             }
513
514             /* This type of message is received when widget is restarting
515              * (proably in other situation too). Widget restart can be
516              * called after system language change so language tags have to
517              * be recreated here.
518              * Do NOT MOVE LanguageTags reset before m_widgetHandle initialization
519              */
520             // reset language tags (create new tags based on system locales)
521             LanguageTagsProviderSingleton::Instance().resetLanguageTags();
522             DPL::OptionalString defaultLocale = dao.getDefaultlocale();
523             if (!defaultLocale.IsNull()) {
524                 LanguageTagsProviderSingleton::Instance().addWidgetDefaultLocales(
525                     *defaultLocale);
526             }
527             LanguageTags tags =
528                 LanguageTagsProviderSingleton::Instance().getLanguageTags();
529             LogDebug("Current widget locales (language tags):");
530             FOREACH(it, tags) {
531                 LogDebug("Locale: " << *it);
532             }
533
534             m_widgetType = dao.getWidgetType();
535             LogDebug("m_widgetType : " << m_widgetType.getApptypeToString() <<
536                      "(m_widgetTizenId:" << m_widgetTizenId << ")");
537
538             LogDebug("Preload PluginLogicSingleton");
539             PluginModule::init(WrtDB::WidgetDAOReadOnly::getHandle(m_widgetTizenId));
540             LogDebug("Preload PluginLogicSingleton_end");
541
542             m_securityModelVersion = dao.getSecurityModelVersion();
543 #ifdef CORS_WHITELISTING_ENABLED
544             bypassCORSforWARPAccessList(dao);
545 #endif
546             m_initialized = true;
547         }
548         else
549         {
550             LogDebug("already initalized");
551         }
552     }
553 }
554
555 WKURLRequestRef Bundle::willSendRequestForFrameCallback(
556     WKBundlePageRef /*page*/,
557     WKBundleFrameRef /*frame*/,
558     uint64_t /*resourceIdentifier*/,
559     WKURLRequestRef request,
560     WKURLResponseRef /*response*/,
561     const void *clientInfo)
562 {
563     LogDebug("willSendRequestForFrameCallback called");
564     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
565     return This->willSendRequestForFrame(request);
566 }
567
568 void Bundle::didStartProvisionalLoadForFrameCallback(
569     WKBundlePageRef page,
570     WKBundleFrameRef frame,
571     WKTypeRef* /*userData*/,
572     const void *clientInfo)
573 {
574     LogDebug("didStartProvisionalLoadForFrameCallback called");
575     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
576
577     // set viewmode
578     WrtDB::WidgetDAOReadOnly dao(This->m_widgetTizenId);
579     WrtDB::WindowModeList modeList = dao.getWindowModes();
580     FOREACH(it, modeList) {
581         std::string viewMode = DPL::ToUTF8String(*it);
582         if (viewMode == VIEWMODE_TYPE_FULLSCREEN
583             || viewMode == VIEWMODE_TYPE_MAXIMIZED)
584         {
585             WKBundlePageSetViewMode(
586                 page,
587                 WKStringCreateWithUTF8CString(viewMode.c_str()));
588             break;
589         }
590     }
591
592     if (This->m_pageGlobalContext.find(page) == This->m_pageGlobalContext.end()) {
593         return;
594     }
595     if (This->m_pageContext.count(page) == 0) {
596         return;
597     }
598
599     JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame);
600
601     ContextSet::iterator i = This->m_pageContext[page].find(context);
602
603     if (i == This->m_pageContext[page].end()) {
604         LogDebug("Initially attached frame");
605         return;
606     }
607
608     This->m_pageContext[page].erase(i);
609     This->m_willRemoveContext = context;
610 }
611
612 void Bundle::didRemoveFrameFromHierarchyCallback(
613     WKBundlePageRef page,
614     WKBundleFrameRef frame,
615     WKTypeRef* /*userData*/,
616     const void *clientInfo)
617 {
618     LogDebug("didRemoveFrameFromHierarchyCallback called");
619     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
620
621     if (This->m_pageContext.count(page) == 0) {
622         LogDebug("his->m_pageContext.count(page) == 0");
623         return;
624     }
625
626     JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame);
627
628     ContextSet::iterator i = This->m_pageContext[page].find(context);
629
630     if (i == This->m_pageContext[page].end()) {
631         LogWarning("Tried to unload frame which has never been loaded");
632         return;
633     }
634
635     This->m_pageContext[page].erase(i);
636
637     PluginModule::unloadFrame(context);
638 }
639
640 void Bundle::didFinishLoadForResourceCallback(
641     WKBundlePageRef /*page*/,
642     WKBundleFrameRef /*frame*/,
643     uint64_t /*resourceIdentifier*/,
644     const void* /*clientInfo*/)
645 {
646     LogDebug("didFinishLoadForResourceCallback called");
647 }
648
649 void Bundle::didCommitLoadForFrameCallback(
650     WKBundlePageRef page,
651     WKBundleFrameRef frame,
652     WKTypeRef* /*userData*/,
653     const void *clientInfo)
654 {
655     LogInfo("didCommitLoadForFrameCallback called");
656     LOG_PROFILE_START("didCommitLoadForFrameCallback");
657     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
658
659     WKURLRef url = WKBundleFrameCopyURL(frame);
660
661     if (url == NULL) {
662         LogInfo("url is NULL");
663         return;
664     }
665
666     if (This->m_willRemoveContext) {
667         PluginModule::unloadFrame(This->m_willRemoveContext);
668         This->m_willRemoveContext = NULL;
669     }
670
671     JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame);
672
673     This->m_pageContext[page].insert(context);
674
675     if (!WKBundleFrameIsMainFrame(frame)) {
676         LogInfo("frame isn't main frame");
677         PluginModule::start(
678             WrtDB::WidgetDAOReadOnly::getHandle(This->m_widgetTizenId),
679             context,
680             This->m_scale,
681             This->m_encodedBundle.c_str(),
682             This->m_theme.c_str());
683         PluginModule::loadFrame(context);
684         return;
685     }
686
687     std::string urlStr = toString(url);
688     if (InjectedBundleURIHandling::processURIForPlugin(urlStr.c_str())) {
689         LogDebug("start plugin");
690         if(This->m_pageGlobalContext.find(page) != This->m_pageGlobalContext.end())
691         {
692             LogDebug("Previous context: " << This->m_pageGlobalContext.getContextForPage(page));
693             PluginModule::stop(This->m_pageGlobalContext.getContextForPage(page));
694         }
695         LogDebug("New context: " << context);
696         //note that since we need old context for unloading plugins it must be sotred
697         //custom container take care of increamenting and decrementing references
698         This->m_pageGlobalContext.insertContextForPage(page, context);
699         LOG_PROFILE_START("PluginModule start");
700         PluginModule::start(
701             WrtDB::WidgetDAOReadOnly::getHandle(This->m_widgetTizenId),
702             context,
703             This->m_scale,
704             This->m_encodedBundle.c_str(),
705             This->m_theme.c_str() );
706         LOG_PROFILE_STOP("PluginModule start");
707
708         PluginModule::loadFrame(context);
709     } else {
710         LogDebug("stop plugin");
711         if(This->m_pageGlobalContext.find(page) != This->m_pageGlobalContext.end())
712         {
713             LogDebug("Previous context: " << This->m_pageGlobalContext.getContextForPage(page));
714             PluginModule::stop(This->m_pageGlobalContext.getContextForPage(page));
715         }
716         LogDebug("New context: " << context);
717         This->m_pageGlobalContext.insertContextForPage(page, context);
718     }
719     LOG_PROFILE_STOP("didCommitLoadForFrameCallback");
720 }
721
722 WKBundlePagePolicyAction Bundle::decidePolicyForNavigationActionCallback(
723     WKBundlePageRef page,
724     WKBundleFrameRef frame,
725     WKBundleNavigationActionRef navigationAction,
726     WKURLRequestRef request,
727     WKTypeRef* userData,
728     const void* clientInfo)
729 {
730     LogDebug("decidePolicyForNavigationActionCallback called");
731
732     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
733     return This->decidePolicyForAction(false,
734                                        page,
735                                        frame,
736                                        navigationAction,
737                                        request,
738                                        userData);
739 }
740
741 WKBundlePagePolicyAction Bundle::decidePolicyForNewWindowActionCallback(
742     WKBundlePageRef page,
743     WKBundleFrameRef frame,
744     WKBundleNavigationActionRef navigationAction,
745     WKURLRequestRef request,
746     WKStringRef /*frameName*/,
747     WKTypeRef* userData,
748     const void* clientInfo)
749 {
750     LogDebug("decidePolicyForNewWindowActionCallback called");
751
752     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
753     return This->decidePolicyForAction(true,
754                                        page,
755                                        frame,
756                                        navigationAction,
757                                        request,
758                                        userData);
759 }
760
761 WKBundlePagePolicyAction Bundle::decidePolicyForResponseCallback(
762     WKBundlePageRef /* page */,
763     WKBundleFrameRef /* frame */,
764     WKURLResponseRef response,
765     WKURLRequestRef /* request */,
766     WKTypeRef*          /* userData */,
767     const void*         /* clientInfo */)
768 {
769     LogDebug("decidePolicyForResponseCallback called");
770
771     Assert(response);
772     WKStringRef contentTypeRef = WKURLResponseEflCopyContentType(response);
773
774     std::string contentType = toString(contentTypeRef);
775     LogDebug("contentTypeRef : " << contentType);
776     WKRelease(contentTypeRef);
777
778     if (contentType == HTML_MIME) {
779         LogDebug("Accepting HTML_MIME type");
780         return WKBundlePagePolicyActionUse;
781     }
782     if (contentType == PHP_MIME) {
783         LogDebug("Accepting php type");
784         return WKBundlePagePolicyActionUse;
785     }
786
787     return WKBundlePagePolicyActionPassThrough;
788 }
789
790 WKURLRequestRef Bundle::willSendRequestForFrame(WKURLRequestRef request)
791 {
792     LogDebug("willSendReq got " << toString(request).c_str());
793     WKURLRef url = WKURLRequestCopyURL(request);
794     WKStringRef urlStr = WKURLCopyString(url);
795
796     DPL::String dplurl = DPL::FromUTF8String(toString(urlStr));
797     WKRelease(urlStr);
798
799     DPL::Optional<DPL::String> localizedUrl =
800         InjectedBundleURIHandling::localizeURI(dplurl, m_widgetTizenId);
801     bool ret =
802         InjectedBundleURIHandling::processURI(*localizedUrl,
803                                              m_widgetTizenId,
804                                              m_securityModelVersion);
805
806     if (!ret) {
807         LogDebug("Not permitted resource: " << *localizedUrl);
808         return NULL;
809     }
810
811     LogDebug("URI processing result: " << *localizedUrl);
812     std::string tmpUrlStr = DPL::ToUTF8String(*localizedUrl);
813     WKURLRef tmpUrl = WKURLCreateWithUTF8CString(tmpUrlStr.c_str());
814     std::string scheme = toString(WKURLCopyScheme(url)); //scheme of original request
815     WKRelease(url);
816
817 #ifdef APP_SCHEME_ENABLED
818     if(scheme == SCHEME_FILE) {
819         LogError("File schema blocked for: " << dplurl);
820         return NULL;
821     }
822 #endif
823
824     // Return value must contain details information of input
825     // WKURLRequestRef. Current webkit2 doesn't support api that
826     // copy WKURLRequestRef or change url only. Before webkit2
827     // support api, callback return original WKURLRequestRef in the
828     // case of external scheme
829
830     // external scheme also need to send message to UI process for
831     // checking roaming and security
832     if (scheme == SCHEME_HTTP || scheme == SCHEME_HTTPS) {
833         LogDebug("external scheme return original WKURLRequestRef");
834         WKRelease(tmpUrl);
835         WKRetain(request);
836         return request;
837     } else {
838         std::string checkUrl = toString(tmpUrl);
839
840         if (m_encrypted) {
841             int getFileSize;
842             if (isEncryptedResource(checkUrl, getFileSize)) {
843                 std::string decryptString = DecryptResource(checkUrl,
844                                                             getFileSize);
845                 if (!decryptString.empty()) {
846                     std::string destString = DATA_STRING;
847
848                     std::string mimeString =
849                         DPL::ToUTF8String(
850                             MimeTypeUtils::identifyFileMimeType(
851                                 DPL::FromUTF8String(checkUrl)));
852
853                     destString += mimeString;
854                     destString += BASE64_STRING;
855
856                     decryptString.insert(0, destString);
857
858                     WKURLRef destUrl =
859                         WKURLCreateWithUTF8CString(decryptString.c_str());
860
861                     WKURLRequestRef req = WKURLRequestCreateWithWKURL(
862                             destUrl);
863                     WKRelease(destUrl);
864                     LogDebug("return value " << decryptString << "]]");
865                     return req;
866                 }
867             }
868         }
869         WKURLRequestRef req = WKURLRequestCreateWithWKURL(tmpUrl);
870         WKRelease(tmpUrl);
871         LogDebug("return value " << toString(req).c_str());
872         return req;
873     }
874 }
875
876 WKBundlePagePolicyAction Bundle::decidePolicyForAction(
877     bool isNewWindow,
878     WKBundlePageRef /* page */,
879     WKBundleFrameRef frame,
880     WKBundleNavigationActionRef /* navigationAction */,
881     WKURLRequestRef request,
882     WKTypeRef* /* userData */)
883 {
884     using namespace ViewModule;
885     using namespace ViewModule::SchemeActionMap;
886
887     char const * const TIZEN_SCHEME = "tizen";
888
889     std::string request_uri = toString(request);
890
891     LogInfo("Uri being checked: " << request_uri);
892
893     // exception uri
894     if (request_uri == BLANK_PAGE_URL) {
895         return WKBundlePagePolicyActionUse;
896     }
897
898     // in case of box scheme, unconditionally PassThrough should be returned
899     if (!request_uri.compare(0, 6, SCHEME_BOX_SLASH)) {
900         return WKBundlePagePolicyActionPassThrough;
901     }
902
903     DPL::String dplUrl = DPL::FromUTF8String(request_uri);
904     bool ret =
905         InjectedBundleURIHandling::processMainResource(dplUrl,
906                                                        m_widgetTizenId,
907                                                        m_securityModelVersion);
908     if (!ret) {
909         std::string blockedUrl = DPL::ToUTF8String(dplUrl);
910         LogDebug("URI is blocked: " << blockedUrl);
911
912         // Send information about blocked URI to UIProcess
913         WKStringRef urlStr = WKStringCreateWithUTF8CString(blockedUrl.c_str());
914         WKTypeRef retVal = NULL;
915         WKStringRef blockMessage = WKStringCreateWithUTF8CString(uriBlockedMessageName);
916         WKBundlePostSynchronousMessage(m_bundle, blockMessage, urlStr, &retVal);
917         WKRelease(urlStr);
918         WKRelease(retVal);
919         WKRelease(blockMessage);
920         return WKBundlePagePolicyActionPassThrough;
921     }
922
923     // get scheme string
924     std::string request_scheme = getScheme(request_uri);
925
926     // is tizen schem?
927     if (request_scheme == TIZEN_SCHEME) {
928         return WKBundlePagePolicyActionPassThrough;
929     }
930
931     // scheme action
932     Scheme scheme(request_scheme);
933     LogDebug("Scheme: " << request_scheme);
934
935     Scheme::Type type = scheme.GetType();
936     if (type < Scheme::FILE || type >= Scheme::COUNT) {
937         LogError("Invalid scheme: " << request_scheme);
938         return WKBundlePagePolicyActionPassThrough;
939     }
940
941     bool mainFrame = WKBundleFrameIsMainFrame(frame);
942     NavigationContext ctx = mainFrame ? TOP_LEVEL : FRAME_LEVEL;
943     if (isNewWindow) {
944         ctx = NEW_WINDOW;
945     }
946
947     LogDebug("Scheme type: " << type);
948     LogDebug("Navigation context: " << ctx);
949     LogDebug("Application type: " << m_widgetType.getApptypeToString());
950
951     UriAction action;
952
953     if (m_widgetType == WrtDB::APP_TYPE_TIZENWEBAPP) {
954         action = g_tizenActionMap[type][ctx];
955     } else {
956         LogError("Unsupported application type: " << type);
957         return WKBundlePagePolicyActionPassThrough;
958     }
959
960     LogDebug("Uri action: " << action);
961
962     if (action != URI_ACTION_WRT) {
963         return WKBundlePagePolicyActionPassThrough;
964     }
965
966     return WKBundlePagePolicyActionUse;
967 }
968
969 std::string Bundle::toString(WKStringRef str)
970 {
971     if (WKStringIsEmpty(str)) {
972         return std::string();
973     }
974     size_t size = WKStringGetMaximumUTF8CStringSize(str);
975     char buffer[size + 1];
976     WKStringGetUTF8CString(str, buffer, size + 1);
977     return buffer;
978 }
979
980 std::string Bundle::toString(WKURLRef url)
981 {
982     WKStringRef urlStr = WKURLCopyString(url);
983     std::string str = toString(urlStr);
984     WKRelease(urlStr);
985     return str;
986 }
987
988 std::string Bundle::toString(WKURLRequestRef req)
989 {
990     WKURLRef reqUrl = WKURLRequestCopyURL(req);
991     std::string str = toString(reqUrl);
992     WKRelease(reqUrl);
993     return str;
994 }
995
996 std::string Bundle::toString(WKErrorRef err)
997 {
998     WKStringRef domErr = WKErrorCopyDomain(err);
999     WKStringRef desc = WKErrorCopyLocalizedDescription(err);
1000     std::string str = toString(domErr) + "\n" + toString(desc);
1001     WKRelease(domErr);
1002     WKRelease(desc);
1003     return str;
1004 }
1005
1006 std::string Bundle::getScheme(std::string uri)
1007 {
1008     std::size_t found = uri.find(':');
1009     std::string str;
1010
1011     if (found != std::string::npos) {
1012         str = uri.substr(0, found);
1013     }
1014
1015     return str;
1016 }
1017
1018 bool Bundle::isEncryptedResource(std::string Url, int &size)
1019 {
1020     if (m_encryptedFiles.empty()) {
1021         WrtDB::WidgetDAOReadOnly(m_widgetTizenId).
1022             getEncryptedFileList(m_encryptedFiles);
1023     }
1024
1025     std::set<WrtDB::EncryptedFileInfo>::iterator it;
1026     WrtDB::EncryptedFileInfo info;
1027     std::string filePath;
1028
1029     if (0 != strncmp(Url.c_str(), SCHEME_FILE_SLASH, strlen(SCHEME_FILE_SLASH))) {
1030         return false;
1031     }
1032
1033     filePath = Url.substr(strlen(SCHEME_FILE_SLASH));
1034     info.fileName = DPL::FromUTF8String(filePath);
1035
1036     if (m_encryptedFiles.end() != (it = m_encryptedFiles.find(info)))
1037     {
1038         LogDebug(" info file name : " << it->fileName);
1039         LogDebug(" info file size : " << it->fileSize);
1040         size = it->fileSize;
1041         return true;
1042     }
1043     return false;
1044 }
1045
1046 std::string Bundle::DecryptResource(std::string resource, int size)
1047 {
1048 #ifdef DECRYPT
1049     std::string filePath;
1050
1051     size_t pos = resource.find_first_not_of(SCHEME_FILE_SLASH);
1052     if (std::string::npos != pos) {
1053         filePath = resource.substr(pos - 1);
1054     }
1055
1056     struct stat buf;
1057     if (0 == stat(filePath.c_str(), &buf)) {
1058         const std::size_t fileSize = buf.st_size;
1059         std::unique_ptr<unsigned char[]> inChunk;
1060
1061         FILE* fp = fopen(filePath.c_str(), "rb");
1062         if (NULL == fp) {
1063             LogDebug("Couldnot open file : " << filePath);
1064             return std::string();
1065         }
1066
1067         std::unique_ptr<unsigned char[]> DecryptedString(new unsigned
1068                 char[fileSize]);
1069         std::string pkgid(DPL::ToUTF8String(m_widgetTizenId));
1070
1071         using namespace Tizen::Base;
1072         const byte *b_pkgid = reinterpret_cast<const byte*>(pkgid.c_str());
1073         ByteBuffer appInfo;
1074         appInfo.Construct(pkgid.length());
1075         if (appInfo.SetArray(b_pkgid, 0, pkgid.length()) != E_SUCCESS) {
1076             LogDebug("Couldnot set appInfo");
1077             fclose(fp);
1078             return std::string();
1079         }
1080         appInfo.Flip();
1081
1082         int writeCount = 0;
1083         do {
1084             unsigned char getDecSize[4];
1085             memset(getDecSize, 0x00, sizeof(getDecSize));
1086
1087             size_t readSize = fread(getDecSize, sizeof(unsigned char),
1088                     sizeof(getDecSize), fp);
1089             if (0 != readSize) {
1090                 int readBufSize = 0;
1091                 std::istringstream(std::string((char*)getDecSize)) >> readBufSize;
1092                 inChunk.reset(new unsigned char[readBufSize]);
1093
1094                 size_t decReadSize = fread(inChunk.get(), sizeof(unsigned char),
1095                         readBufSize, fp);
1096                 if (0 != decReadSize) {
1097                     ByteBuffer *getBuffer =
1098                         DecryptChunkByTrustZone(&appInfo, inChunk.get(),
1099                                 decReadSize);
1100                     memcpy(DecryptedString.get() + writeCount,
1101                             getBuffer->GetPointer(), getBuffer->GetRemaining());
1102                     writeCount += getBuffer->GetRemaining();
1103                     getBuffer->Reset();
1104                 }
1105             }
1106
1107         } while( 0 == std::feof(fp));
1108         fclose(fp);
1109
1110         memset(DecryptedString.get() + size, '\n', fileSize - size);
1111         LogDebug("resource need to encoding base64");
1112         BIO *bmem, *b64;
1113         BUF_MEM *bptr;
1114
1115         b64 = BIO_new(BIO_f_base64());
1116         bmem = BIO_new(BIO_s_mem());
1117         b64 = BIO_push(b64, bmem);
1118         BIO_write(b64, DecryptedString.get(), fileSize);
1119         BIO_flush(b64);
1120         BIO_get_mem_ptr(b64, &bptr);
1121
1122         std::string base64Enc((char *)bptr->data, bptr->length - 1);
1123         BIO_free_all(b64);
1124
1125         return base64Enc;
1126     }
1127 #endif
1128     return std::string();
1129 }
1130
1131 #ifdef MULTIPROCESS_SERVICE_SUPPORT_INLINE
1132 void Bundle::sendWebProcessPid()
1133 {
1134     std::stringstream strPid;
1135     strPid << getpid();
1136     WKStringRef pidStr = WKStringCreateWithUTF8CString(strPid.str().c_str());
1137     WKTypeRef retVal = NULL;
1138     WKStringRef message = WKStringCreateWithUTF8CString(webProcessPidMessageName);
1139     WKBundlePostSynchronousMessage(m_bundle, message, pidStr, &retVal);
1140     WKRelease(pidStr);
1141     WKRelease(retVal);
1142     WKRelease(message);
1143 }
1144 #endif
1145
1146 extern "C"
1147 {
1148 WK_EXPORT
1149 void WKBundleInitialize(WKBundleRef bundle,
1150                         WKTypeRef)
1151 {
1152     DPL::Log::LogSystemSingleton::Instance().SetTag("WRT-BUNDLE");
1153     LogDebug("Bundle initialized");
1154
1155     DPL::Event::GetMainEventDispatcherInstance().ResetCrossEventCallHandler();
1156     LogDebug("ResetCrossEventCallHandler()");
1157
1158     static Bundle s_bundle(bundle);
1159
1160     WKBundleClient client = {
1161         kWKBundleClientCurrentVersion,
1162         &s_bundle,
1163         &Bundle::didCreatePageCallback,
1164         &Bundle::willDestroyPageCallback,
1165         0,     /* didInitializePageGroup */
1166         &Bundle::didReceiveMessageCallback
1167     };
1168     WKBundleSetClient(bundle, &client);
1169
1170     // process pool - restore process priority
1171     if (UID_ROOT == getuid())
1172     {
1173         setpriority(PRIO_PROCESS, 0, DEFAULT_PRIORITY);
1174     }
1175 }
1176 }