Encrypt widget on update.
[framework/web/wrt-installer.git] / src / jobs / widget_install / job_widget_install.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    job_widget_install.cpp
18  * @author  Radoslaw Wicik r.wicik@samsung.com
19  * @author  Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
20  * @version 1.0
21  * @brief   Implementation file for main installer task
22  */
23 #include <memory>
24 #include <string>
25 #include <sys/time.h>
26 #include <ctime>
27 #include <cstdlib>
28 #include <limits.h>
29 #include <regex.h>
30
31 #include <dpl/noncopyable.h>
32 #include <dpl/abstract_waitable_input_adapter.h>
33 #include <dpl/abstract_waitable_output_adapter.h>
34 #include <dpl/zip_input.h>
35 #include <dpl/binary_queue.h>
36 #include <dpl/copy.h>
37 #include <dpl/assert.h>
38 #include <dpl/sstream.h>
39 #include <dpl/file_input.h>
40 #include <dpl/utils/wrt_utility.h>
41 #include <dpl/wrt-dao-ro/common_dao_types.h>
42 #include <dpl/wrt-dao-ro/widget_dao_read_only.h>
43 #include <dpl/wrt-dao-ro/global_config.h>
44 #include <dpl/wrt-dao-ro/config_parser_data.h>
45 #include <dpl/wrt-dao-rw/global_dao.h> // TODO remove
46 #include <dpl/localization/w3c_file_localization.h>
47
48 #include <libiriwrapper.h>
49 #include <pkg-manager/pkgmgr_signal.h>
50 #include <app_manager.h>
51 //#include <drm_client.h>
52 #include <drm-oem-intel.h> //temporary code
53
54 #include "root_parser.h"
55 #include "widget_parser.h"
56 #include "parser_runner.h"
57 #include <widget_install/job_widget_install.h>
58 #include <widget_install/task_certify.h>
59 #include <widget_install/task_widget_config.h>
60 #include <widget_install/task_file_manipulation.h>
61 #include <widget_install/task_ace_check.h>
62 #include <widget_install/task_smack.h>
63 #include <widget_install/task_manifest_file.h>
64 #include <widget_install/task_prepare_files.h>
65 #include <widget_install/task_recovery.h>
66 #include <widget_install/task_install_ospsvc.h>
67 #include <widget_install/task_update_files.h>
68 #include <widget_install/task_database.h>
69 #include <widget_install/task_remove_backup.h>
70 #include <widget_install/task_encrypt_resource.h>
71 #include <widget_install/task_certificates.h>
72 #include <widget_install/task_unzip.h>
73 #include <widget_install/task_commons.h>
74
75 #include <widget_install/task_plugins_copy.h>
76
77 #include <widget_install/widget_install_errors.h>
78 #include <widget_install/widget_install_context.h>
79 #include <widget_install_to_external.h>
80
81 using namespace WrtDB;
82 using namespace Jobs::Exceptions;
83
84 namespace // anonymous
85 {
86 const char * const CONFIG_XML = "config.xml";
87 const char * const WITH_OSP_XML = "res/wgt/config.xml";
88
89 //allowed: a-z, A-Z, 0-9
90 const char* REG_TIZENID_PATTERN = "^[a-zA-Z0-9]{10}.{1,}$";
91 const char* REG_NAME_PATTERN = "^[a-zA-Z0-9._-]{1,}$";
92 const size_t PACKAGE_ID_LENGTH = 10;
93
94 static const DPL::String SETTING_VALUE_ENCRYPTION = L"encryption";
95 static const DPL::String SETTING_VALUE_ENCRYPTION_ENABLE = L"enable";
96 const DPL::String SETTING_VALUE_INSTALLTOEXT_NAME =
97     L"install-location-type";
98 const DPL::String SETTING_VALUE_INSTALLTOEXT_PREPER_EXT =
99     L"prefer-external";
100
101 const std::string XML_EXTENSION = ".xml";
102
103 bool hasExtension(const std::string& filename, const std::string& extension)
104 {
105     LogDebug("Looking for extension " << extension << " in: " << filename);
106     size_t fileLen = filename.length();
107     size_t extLen = extension.length();
108     if (fileLen < extLen) {
109         LogError("Filename " << filename << " is shorter than extension "
110                              << extension);
111         return false;
112     }
113     return (0 == filename.compare(fileLen - extLen, extLen, extension));
114 }
115
116 bool checkTizenPkgIdExist(const std::string& tizenPkgId)
117 {
118     std::string installPath =
119         std::string(GlobalConfig::GetUserInstalledWidgetPath()) +
120         "/" + tizenPkgId;
121     std::string preinstallPath =
122         std::string(GlobalConfig::GetUserPreloadedWidgetPath()) +
123         "/" + tizenPkgId;
124
125     struct stat dirStat;
126     if ((stat(installPath.c_str(), &dirStat) == 0) ||
127         (stat(preinstallPath.c_str(), &dirStat) == 0))
128     {
129         return true;
130     }
131     return false;
132 }
133 } // namespace anonymous
134
135 namespace Jobs {
136 namespace WidgetInstall {
137 class InstallerTaskFail :
138     public DPL::TaskDecl<InstallerTaskFail>
139 {
140   private:
141     ConfigureResult m_result;
142
143     void StepFail()
144     {
145         if (m_result == ConfigureResult::Deferred) {
146             ThrowMsg(Jobs::WidgetInstall::Exceptions::Deferred,
147                     "widget installation or update deferred!");
148         } else if (m_result == ConfigureResult::Failed_InvalidConfig) {
149             ThrowMsg(Jobs::WidgetInstall::Exceptions::WidgetConfigFileInvalid,
150                     "invalid config");
151         } else if (m_result == ConfigureResult::Failed_LowerVersion) {
152             ThrowMsg(Jobs::WidgetInstall::Exceptions::PackageLowerVersion,
153                     "package version is lower than installed version");
154         } else if (m_result == ConfigureResult::Failed_AlreadyInstalled) {
155             ThrowMsg(Jobs::WidgetInstall::Exceptions::PackageAlreadyInstalled,
156                     "package is already installed");
157         } else if (m_result == ConfigureResult::Failed_WidgetRunning) {
158             ThrowMsg(Jobs::WidgetInstall::Exceptions::WidgetRunningError,
159                     "widget is running");
160         } else if (m_result == ConfigureResult::Failed_DrmError) {
161             ThrowMsg(Jobs::WidgetInstall::Exceptions::DRMFailed,
162                     "drm failed");
163         } else {
164             ThrowMsg(Jobs::WidgetInstall::Exceptions::NotAllowed,
165                     "widget installation or update not allowed!");
166         }
167     }
168
169   public:
170     InstallerTaskFail(ConfigureResult result) :
171         DPL::TaskDecl<InstallerTaskFail>(this),
172         m_result(result)
173     {
174         AddStep(&InstallerTaskFail::StepFail);
175     }
176 };
177
178 JobWidgetInstall::JobWidgetInstall(
179     std::string const &widgetPath,
180     const WidgetInstallationStruct &
181     installerStruct) :
182     Job(Installation),
183     JobContextBase<WidgetInstallationStruct>(installerStruct),
184     m_exceptionCaught(Jobs::Exceptions::Success)
185 {
186     m_installerContext.m_quiet = m_jobStruct.m_quiet;
187
188     ConfigureResult result = PrePareInstallation(widgetPath);
189
190     if (result == ConfigureResult::Ok) {
191         LogInfo("Configure installation succeeded");
192         m_installerContext.job->SetProgressFlag(true);
193
194         AddTask(new TaskRecovery(m_installerContext));
195
196         // Create installation tasks
197         if (m_installerContext.widgetConfig.packagingType !=
198             WrtDB::PKG_TYPE_DIRECTORY_WEB_APP &&
199             m_installerContext.widgetConfig.packagingType !=
200             WrtDB::PKG_TYPE_HOSTED_WEB_APP &&
201             !m_isDRM)
202         {
203             AddTask(new TaskUnzip(m_installerContext));
204         }
205
206         AddTask(new TaskWidgetConfig(m_installerContext));
207         if (m_installerContext.widgetConfig.packagingType ==
208             WrtDB::PKG_TYPE_HOSTED_WEB_APP)
209         {
210             AddTask(new TaskPrepareFiles(m_installerContext));
211         }
212         AddTask(new TaskCertify(m_installerContext));
213         if (m_needEncryption) {
214             AddTask(new TaskEncryptResource(m_installerContext));
215         }
216
217         AddTask(new TaskFileManipulation(m_installerContext));
218         // TODO: Update progress information for this task
219
220         //This is sort of quick solution, because ACE verdicts are based upon
221         //data from DAO (DB). So AceCheck for now has to be AFTER DbUpdate
222         //task.
223         AddTask(new TaskSmack(m_installerContext));
224
225         AddTask(new TaskManifestFile(m_installerContext));
226         if (m_installerContext.widgetConfig.packagingType ==
227             PKG_TYPE_HYBRID_WEB_APP)
228         {
229             AddTask(new TaskInstallOspsvc(m_installerContext));
230         }
231         AddTask(new TaskCertificates(m_installerContext));
232         AddTask(new TaskPluginsCopy(m_installerContext));
233         AddTask(new TaskDatabase(m_installerContext));
234         AddTask(new TaskAceCheck(m_installerContext));
235     } else if (result == ConfigureResult::Updated) {
236         LogInfo("Configure installation updated");
237         LogInfo("Widget Update");
238         m_installerContext.job->SetProgressFlag(true);
239         if (m_installerContext.widgetConfig.packagingType !=
240             WrtDB::PKG_TYPE_HOSTED_WEB_APP &&
241             m_installerContext.widgetConfig.packagingType !=
242             WrtDB::PKG_TYPE_DIRECTORY_WEB_APP &&
243             !m_isDRM)
244         {
245             AddTask(new TaskUnzip(m_installerContext));
246         }
247
248         AddTask(new TaskWidgetConfig(m_installerContext));
249
250         if (m_installerContext.widgetConfig.packagingType ==
251             WrtDB::PKG_TYPE_HOSTED_WEB_APP)
252         {
253             AddTask(new TaskPrepareFiles(m_installerContext));
254         }
255
256         AddTask(new TaskCertify(m_installerContext));
257         if (m_needEncryption) {
258             AddTask(new TaskEncryptResource(m_installerContext));
259         }
260
261         if (m_installerContext.widgetConfig.packagingType !=
262             WrtDB::PKG_TYPE_DIRECTORY_WEB_APP)
263         {
264             AddTask(new TaskUpdateFiles(m_installerContext));
265         }
266
267         /* TODO : To backup file, save md5 values */
268         AddTask(new TaskSmack(m_installerContext));
269
270         AddTask(new TaskManifestFile(m_installerContext));
271         if (m_installerContext.widgetConfig.packagingType ==
272             PKG_TYPE_HYBRID_WEB_APP)
273         {
274             AddTask(new TaskInstallOspsvc(m_installerContext));
275         }
276         if (m_installerContext.widgetConfig.packagingType !=
277             WrtDB::PKG_TYPE_DIRECTORY_WEB_APP)
278         {
279             AddTask(new TaskRemoveBackupFiles(m_installerContext));
280         }
281         AddTask(new TaskPluginsCopy(m_installerContext));
282         AddTask(new TaskDatabase(m_installerContext));
283         AddTask(new TaskAceCheck(m_installerContext));
284         //TODO: remove widgetHandle from this task and move before database task
285         // by now widget handle is needed in ace check
286         // Any error in acecheck while update will break widget
287     } else if (result == ConfigureResult::Deferred) {
288         // Installation is deferred
289         LogInfo("Configure installation deferred");
290
291         AddTask(new InstallerTaskFail(result));
292     } else if (result >= ConfigureResult::Failed &&
293             result <= ConfigureResult::Failed_DrmError) {
294         // Installation is not allowed to proceed due to widget update policy
295         LogWarning("Configure installation failed!");
296
297         AddTask(new InstallerTaskFail(result));
298     } else {
299         Assert(false && "Invalid configure result!");
300     }
301 }
302
303 ConfigureResult JobWidgetInstall::PrePareInstallation(
304     const std::string &widgetPath)
305 {
306     ConfigureResult result;
307     m_needEncryption = false;
308
309     Try
310     {
311         std::string tempDir =
312             Jobs::WidgetInstall::createTempPath(m_jobStruct.m_preload);
313
314         m_isDRM = isDRMWidget(widgetPath);
315         if (true == m_isDRM) {
316             LogDebug("decrypt DRM widget");
317             if (DecryptDRMWidget(widgetPath, tempDir)) {
318                 LogDebug("Failed decrypt DRM widget");
319                 return ConfigureResult::Failed_DrmError;
320             }
321         }
322
323         LogDebug("widgetPath:" << widgetPath);
324
325         m_installerContext.widgetConfig.packagingType =
326             checkPackageType(widgetPath, tempDir);
327         ConfigParserData configData = getWidgetDataFromXML(
328                 widgetPath,
329                 tempDir,
330                 m_installerContext.widgetConfig.packagingType,
331                 m_isDRM);
332         LogDebug("widget packaging type : " <<
333                  m_installerContext.widgetConfig.packagingType.pkgType);
334
335         setTizenId(configData);
336         setApplicationType(configData);
337         m_needEncryption = detectResourceEncryption(configData);
338         setInstallLocationType(configData);
339
340         // Configure installation
341         result = ConfigureInstallation(widgetPath, configData, tempDir);
342     }
343     Catch(Exceptions::ExtractFileFailed)
344     {
345         LogError("Failed to create temporary path for widget");
346         result = ConfigureResult::Failed_InvalidConfig;
347     }
348
349     return result;
350 }
351
352 void JobWidgetInstall::setTizenId(
353     const WrtDB::ConfigParserData &configInfo)
354 {
355     bool shouldMakeAppid = false;
356     using namespace PackageManager;
357     if (!!configInfo.tizenAppId) {
358         LogDebug("Setting tizenAppId provided in config.xml: " <<
359                  configInfo.tizenAppId);
360
361         m_installerContext.widgetConfig.tzAppid = *configInfo.tizenAppId;
362         //check package id.
363         if (!!configInfo.tizenPkgId) {
364             LogDebug("Setting tizenPkgId provided in config.xml: " <<
365                      configInfo.tizenPkgId);
366
367             m_installerContext.widgetConfig.tzPkgid = *configInfo.tizenPkgId;
368         } else {
369             DPL::String appid = *configInfo.tizenAppId;
370             if (appid.length() > PACKAGE_ID_LENGTH) {
371                 m_installerContext.widgetConfig.tzPkgid =
372                     appid.substr(0, PACKAGE_ID_LENGTH);
373             } else {
374                 //old version appid only has 10byte random character is able to install for a while.
375                 //this case appid equal pkgid.
376                 m_installerContext.widgetConfig.tzPkgid =
377                     *configInfo.tizenAppId;
378                 shouldMakeAppid = true;
379             }
380         }
381     } else {
382         shouldMakeAppid = true;
383         TizenPkgId pkgId = WidgetDAOReadOnly::generatePkgId();
384         LogDebug("Checking if pkg id is unique");
385         while (true) {
386             if (checkTizenPkgIdExist(DPL::ToUTF8String(pkgId))) {
387                 //path exist, chose another one
388                 pkgId = WidgetDAOReadOnly::generatePkgId();
389                 continue;
390             }
391             break;
392         }
393         m_installerContext.widgetConfig.tzPkgid = pkgId;
394         LogInfo("tizen_id name was generated by WRT: " <<
395                 m_installerContext.widgetConfig.tzPkgid);
396     }
397
398     if (shouldMakeAppid == true) {
399         DPL::OptionalString name;
400         DPL::OptionalString defaultLocale = configInfo.defaultlocale;
401
402         FOREACH(localizedData, configInfo.localizedDataSet)
403         {
404             Locale i = localizedData->first;
405             if (!!defaultLocale) {
406                 if (defaultLocale == i) {
407                     name = localizedData->second.name;
408                     break;
409                 }
410             } else {
411                 name = localizedData->second.name;
412                 break;
413             }
414         }
415         regex_t regx;
416         if (regcomp(&regx, REG_NAME_PATTERN, REG_NOSUB | REG_EXTENDED) != 0) {
417             LogDebug("Regcomp failed");
418         }
419
420         LogDebug("Name : " << name);
421         if (!name || (regexec(&regx, DPL::ToUTF8String(*name).c_str(),
422                               static_cast<size_t>(0), NULL, 0) != REG_NOERROR))
423         {
424             // TODO : generate name move to wrt-commons
425             std::string allowedString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
426             std::ostringstream genName;
427             struct timeval tv;
428             gettimeofday(&tv, NULL);
429             unsigned int seed = time(NULL) + tv.tv_usec;
430
431             genName << "_" << allowedString[rand_r(&seed) % allowedString.length()];
432             name = DPL::FromUTF8String(genName.str());
433             LogDebug("name was generated by WRT");
434         }
435         regfree(&regx);
436         LogDebug("Name : " << name);
437         std::ostringstream genid;
438         genid << m_installerContext.widgetConfig.tzPkgid << "." << name;
439         LogDebug("tizen appid was generated by WRT : " << genid.str());
440
441         DPL::OptionalString appid = DPL::FromUTF8String(genid.str());
442         NormalizeAndTrimSpaceString(appid);
443         m_installerContext.widgetConfig.tzAppid = *appid;
444     }
445
446     // send start signal of pkgmgr
447     getInstallerStruct().pkgmgrInterface->setPkgname(DPL::ToUTF8String(
448                                                          m_installerContext.
449                                                              widgetConfig.
450                                                              tzPkgid));
451     LogInfo("Tizen App Id : " << m_installerContext.widgetConfig.tzAppid);
452     LogInfo("Tizen Pkg Id : " << m_installerContext.widgetConfig.tzPkgid);
453     LogInfo("W3C Widget GUID : " << m_installerContext.widgetConfig.guid);
454 }
455
456 void JobWidgetInstall::configureWidgetLocation(const std::string & widgetPath,
457                                                const std::string& tempPath)
458 {
459     m_installerContext.locations =
460         WidgetLocation(DPL::ToUTF8String(m_installerContext.widgetConfig.
461                                              tzPkgid),
462                        widgetPath, tempPath,
463                        m_installerContext.widgetConfig.packagingType,
464                        m_installerContext.locationType);
465     m_installerContext.locations->registerAppid(
466         DPL::ToUTF8String(m_installerContext.widgetConfig.tzAppid));
467
468     LogInfo("widgetSource " << widgetPath);
469 }
470
471 ConfigureResult JobWidgetInstall::ConfigureInstallation(
472     const std::string &widgetSource,
473     const WrtDB::ConfigParserData &configData,
474     const std::string &tempPath)
475 {
476     WidgetUpdateInfo update = detectWidgetUpdate(
477             configData,
478             m_installerContext.
479                 widgetConfig.webAppType,
480             m_installerContext.
481                 widgetConfig.tzAppid);
482     ConfigureResult result = checkWidgetUpdate(update);
483
484     // Validate tizenId
485     regex_t reg;
486     if (regcomp(&reg, REG_TIZENID_PATTERN, REG_NOSUB | REG_EXTENDED) != 0) {
487         LogDebug("Regcomp failed");
488     }
489
490     if ((regexec(&reg,
491                  DPL::ToUTF8String(m_installerContext.widgetConfig.tzAppid).
492                      c_str(),
493                      static_cast<size_t>(0), NULL, 0) == REG_NOMATCH) ||
494         (checkTizenPkgIdExist(DPL::ToUTF8String(m_installerContext.widgetConfig
495                                                     .tzPkgid)) &&
496          result != ConfigureResult::Updated))
497     {
498         //it is true when tizenId does not fit REG_TIZENID_PATTERN
499         LogError("tizen_id provided but not proper or pkgId directory exists");
500         //TODO(t.iwanek): appId is unique, what about installation of
501         // abcdefghij.test1 and abcdefghij.test2?
502         regfree(&reg);
503         return ConfigureResult::Failed_AlreadyInstalled;
504     }
505     regfree(&reg);
506
507     configureWidgetLocation(widgetSource, tempPath);
508
509     // Init installer context
510     m_installerContext.installStep = InstallerContext::INSTALL_START;
511     m_installerContext.job = this;
512     m_installerContext.existingWidgetInfo = update.existingWidgetInfo;
513     m_installerContext.widgetConfig.shareHref = std::string();
514
515     return result;
516 }
517
518 ConfigureResult JobWidgetInstall::checkWidgetUpdate(
519     const WidgetUpdateInfo &update)
520 {
521     LogInfo(
522         "Widget install/update: incoming guid = '" <<
523         update.incomingGUID << "'");
524     LogInfo(
525         "Widget install/update: incoming version = '" <<
526         update.incomingVersion << "'");
527
528     // Check policy
529     WidgetUpdateMode::Type updateTypeCheckBit;
530
531     if (update.existingWidgetInfo.isExist == false) {
532         LogInfo("Widget info does not exist");
533         updateTypeCheckBit = WidgetUpdateMode::NotInstalled;
534
535         getInstallerStruct().pkgmgrInterface->sendSignal(
536                 PKGMGR_START_KEY,
537                 PKGMGR_START_INSTALL);
538
539     } else {
540         LogInfo("Widget info exists. appid: " <<
541                 update.existingWidgetInfo.tzAppid);
542
543         getInstallerStruct().pkgmgrInterface->sendSignal(
544                 PKGMGR_START_KEY,
545                 PKGMGR_START_UPDATE);
546
547         TizenAppId tzAppid = update.existingWidgetInfo.tzAppid;
548
549         LogInfo("Widget model exists. tizen app id: " << tzAppid);
550
551         // Check running state
552         bool isRunning = false;
553         int retval = app_manager_is_running(DPL::ToUTF8String(
554                                             tzAppid).c_str(), &isRunning);
555         if (APP_MANAGER_ERROR_NONE != retval) {
556             LogError("Fail to get running state");
557             return ConfigureResult::Failed_WidgetRunning;
558         }
559
560         if (true == isRunning) {
561             // Must be deferred when update in progress
562             if (m_jobStruct.updateMode == WidgetUpdateMode::PolicyWac) {
563                 LogInfo(
564                     "Widget is already running. Policy is update according to WAC");
565
566                 return ConfigureResult::Deferred;
567             } else {
568                 LogInfo(
569                     "Widget is already running. Policy is not update according to WAC");
570
571                 return ConfigureResult::Failed_WidgetRunning;
572             }
573         }
574
575         m_installerContext.widgetConfig.tzAppid = tzAppid;
576         OptionalWidgetVersion existingVersion;
577         existingVersion = update.existingWidgetInfo.existingVersion;
578         OptionalWidgetVersion incomingVersion = update.incomingVersion;
579
580         updateTypeCheckBit = CalcWidgetUpdatePolicy(existingVersion,
581                                                     incomingVersion);
582         // Calc proceed flag
583         if ((m_jobStruct.updateMode & updateTypeCheckBit) > 0 ||
584             m_jobStruct.updateMode ==
585             WidgetUpdateMode::PolicyDirectoryForceInstall)
586         {
587             LogInfo("Whether widget policy allow proceed ok");
588             return ConfigureResult::Updated;
589         } else {
590             return ConfigureResult::Failed_LowerVersion;
591         }
592     }
593     return ConfigureResult::Ok;
594 }
595
596 WidgetUpdateMode::Type JobWidgetInstall::CalcWidgetUpdatePolicy(
597     const OptionalWidgetVersion &existingVersion,
598     const OptionalWidgetVersion &incomingVersion) const
599 {
600     // Widget is installed, check versions
601     if (!existingVersion && !incomingVersion) {
602         return WidgetUpdateMode::ExistingVersionEqual;
603     } else if (!existingVersion && !!incomingVersion) {
604         return WidgetUpdateMode::ExistingVersionNewer;
605     } else if (!!existingVersion && !incomingVersion) {
606         return WidgetUpdateMode::ExistingVersionOlder;
607     } else {
608         LogInfo("Existing widget: version = '" << *existingVersion << "'");
609
610         if (!existingVersion->IsWac() && !incomingVersion->IsWac()) {
611             return WidgetUpdateMode::BothVersionsNotStd;
612         } else if (!existingVersion->IsWac()) {
613             return WidgetUpdateMode::ExistingVersionNotStd;
614         } else if (!incomingVersion->IsWac()) {
615             return WidgetUpdateMode::IncomingVersionNotStd;
616         } else {
617             // Both versions are WAC-comparable. Do compare.
618             if (*incomingVersion == *existingVersion) {
619                 return WidgetUpdateMode::ExistingVersionEqual;
620             } else if (*incomingVersion > *existingVersion) {
621                 return WidgetUpdateMode::ExistingVersionOlder;
622             } else {
623                 return WidgetUpdateMode::ExistingVersionNewer;
624             }
625         }
626     }
627 }
628
629 ConfigParserData JobWidgetInstall::getWidgetDataFromXML(
630     const std::string &widgetSource,
631     const std::string &tempPath,
632     WrtDB::PackagingType pkgType,
633     bool isDRM)
634 {
635     // Parse config
636     ParserRunner parser;
637     ConfigParserData configInfo;
638
639     Try
640     {
641         if (pkgType == PKG_TYPE_HOSTED_WEB_APP) {
642             parser.Parse(widgetSource,
643                          ElementParserPtr(
644                              new RootParser<WidgetParser>(configInfo,
645                                                           DPL::FromUTF32String(
646                                                               L"widget"))));
647         } else if (pkgType == PKG_TYPE_DIRECTORY_WEB_APP) {
648             parser.Parse(widgetSource + '/' + WITH_OSP_XML,
649                          ElementParserPtr(
650                              new RootParser<WidgetParser>(
651                                  configInfo,
652                                  DPL::FromUTF32String(L"widget"))));
653         } else {
654             if (!isDRM) {
655                 std::unique_ptr<DPL::ZipInput> zipFile(
656                     new DPL::ZipInput(widgetSource));
657
658                 std::unique_ptr<DPL::ZipInput::File> configFile;
659
660                 // Open config.xml file
661                 if (pkgType == PKG_TYPE_HYBRID_WEB_APP) {
662                     configFile.reset(zipFile->OpenFile(WITH_OSP_XML));
663                 } else {
664                     configFile.reset(zipFile->OpenFile(CONFIG_XML));
665                 }
666
667                 // Extract config
668                 DPL::BinaryQueue buffer;
669                 DPL::AbstractWaitableInputAdapter inputAdapter(configFile.get());
670                 DPL::AbstractWaitableOutputAdapter outputAdapter(&buffer);
671                 DPL::Copy(&inputAdapter, &outputAdapter);
672                 parser.Parse(&buffer,
673                              ElementParserPtr(
674                                  new RootParser<WidgetParser>(configInfo,
675                                                               DPL::
676                                                                   FromUTF32String(
677                                                                   L"widget"))));
678             } else {
679                 // DRM widget
680                 std::string configFile;
681                 if (pkgType == PKG_TYPE_HYBRID_WEB_APP) {
682                     configFile = tempPath + "/" + WITH_OSP_XML;
683                 } else {
684                     configFile = tempPath + "/" + CONFIG_XML;
685                 }
686
687                 parser.Parse(configFile,
688                              ElementParserPtr(
689                                  new RootParser<WidgetParser>(configInfo,
690                                                               DPL::
691                                                                   FromUTF32String(
692                                                                   L"widget"))));
693             }
694         }
695     }
696     Catch(DPL::ZipInput::Exception::OpenFailed)
697     {
698         LogError("Failed to open widget package");
699         return ConfigParserData();
700     }
701     Catch(DPL::ZipInput::Exception::OpenFileFailed)
702     {
703         LogError("Failed to open config.xml file");
704         return ConfigParserData();
705     }
706     Catch(DPL::CopyFailed)
707     {
708         LogError("Failed to extract config.xml file");
709         return ConfigParserData();
710     }
711     Catch(DPL::FileInput::Exception::OpenFailed)
712     {
713         LogError("Failed to open config.xml file");
714         return ConfigParserData();
715     }
716     Catch(ElementParser::Exception::ParseError)
717     {
718         LogError("Failed to parse config.xml file");
719         return ConfigParserData();
720     }
721     Catch(DPL::ZipInput::Exception::SeekFileFailed)
722     {
723         LogError("Failed to seek widget archive - corrupted package?");
724         return ConfigParserData();
725     }
726     return configInfo;
727 }
728
729 WidgetUpdateInfo JobWidgetInstall::detectWidgetUpdate(
730     const ConfigParserData &configInfo,
731     const WrtDB::WidgetType appType,
732     const WrtDB::TizenAppId &tizenId)
733 {
734     LogInfo("Checking up widget package for config.xml...");
735
736     DPL::OptionalString widgetGUID;
737     OptionalWidgetVersion widgetVersion;
738
739     // Check widget id
740     widgetGUID = configInfo.widget_id;
741
742     if (widgetGUID.IsNull()) {
743         LogWarning("Installed widget has no GUID");
744         return WidgetUpdateInfo();
745     }
746
747     LogDebug("Installed widget GUID: " << *widgetGUID);
748
749     // Locate widget ID with this GUID
750     // Incoming widget version
751     if (!configInfo.version.IsNull()) {
752         widgetVersion =
753             DPL::Optional<WidgetVersion>(
754                 WidgetVersion(*configInfo.version));
755     }
756
757     if (appType == APP_TYPE_WAC20) {
758         Try
759         {
760             // Search widget handle by GUID
761             WidgetDAOReadOnly dao(widgetGUID);
762             return WidgetUpdateInfo(
763                        widgetGUID,
764                        widgetVersion,
765                        WidgetUpdateInfo::ExistingWidgetInfo(
766                            dao.getTzAppId(), dao.getVersion()));
767         }
768         Catch(WidgetDAOReadOnly::Exception::WidgetNotExist)
769         {
770             // GUID isn't installed
771             return WidgetUpdateInfo(
772                        widgetGUID,
773                        widgetVersion,
774                        WidgetUpdateInfo::ExistingWidgetInfo());
775         }
776     } else {
777         Try
778         {
779             // Search widget handle by appId
780             WidgetDAOReadOnly dao(tizenId);
781             return WidgetUpdateInfo(
782                        widgetGUID,
783                        widgetVersion,
784                        WidgetUpdateInfo::ExistingWidgetInfo(
785                            dao.getTzAppId(), dao.getVersion()));
786         }
787         Catch(WidgetDAOReadOnly::Exception::WidgetNotExist)
788         {
789             // GUID isn't installed
790             return WidgetUpdateInfo(
791                        widgetGUID,
792                        widgetVersion,
793                        WidgetUpdateInfo::ExistingWidgetInfo());
794         }
795     }
796 }
797
798 void JobWidgetInstall::SendProgress()
799 {
800     using namespace PackageManager;
801     if (GetProgressFlag() != false) {
802         if (getInstallerStruct().progressCallback != NULL) {
803             // send progress signal of pkgmgr
804             std::ostringstream percent;
805             percent << static_cast<int>(GetProgressPercent());
806             getInstallerStruct().pkgmgrInterface->sendSignal(
807                 PKGMGR_PROGRESS_KEY,
808                 percent.str());
809
810             LogDebug("Call widget install progressCallbak");
811             getInstallerStruct().progressCallback(
812                 getInstallerStruct().userParam,
813                 GetProgressPercent(),
814                 GetProgressDescription());
815         }
816     }
817 }
818
819 void JobWidgetInstall::SendProgressIconPath(const std::string &path)
820 {
821     using namespace PackageManager;
822     if (GetProgressFlag() != false) {
823         if (getInstallerStruct().progressCallback != NULL) {
824             // send progress signal of pkgmgr
825             getInstallerStruct().pkgmgrInterface->sendSignal(
826                 PKGMGR_ICON_PATH,
827                 path);
828         }
829     }
830 }
831
832 void JobWidgetInstall::SendFinishedSuccess()
833 {
834     using namespace PackageManager;
835     // TODO : sync should move to separate task.
836     sync();
837
838     if (INSTALL_LOCATION_TYPE_EXTERNAL == m_installerContext.locationType) {
839         if (false == m_installerContext.existingWidgetInfo.isExist) {
840             WidgetInstallToExtSingleton::Instance().postInstallation(true);
841         } else {
842             WidgetInstallToExtSingleton::Instance().postUpgrade(true);
843         }
844         WidgetInstallToExtSingleton::Instance().deinitialize();
845     }
846
847     // remove widget install information file
848     unlink(m_installerContext.installInfo.c_str());
849
850     //inform widget info
851     JobWidgetInstall::displayWidgetInfo();
852
853     TizenAppId& tizenId = m_installerContext.widgetConfig.tzAppid;
854
855     // send signal of pkgmgr
856     getInstallerStruct().pkgmgrInterface->sendSignal(
857         PKGMGR_END_KEY,
858         PKGMGR_END_SUCCESS);
859
860     LogDebug("Call widget install successfinishedCallback");
861     getInstallerStruct().finishedCallback(getInstallerStruct().userParam,
862                                           DPL::ToUTF8String(
863                                               tizenId), Jobs::Exceptions::Success);
864 }
865
866 void JobWidgetInstall::SendFinishedFailure()
867 {
868     using namespace PackageManager;
869     // remove widget install information file
870     unlink(m_installerContext.installInfo.c_str());
871
872     LogError("Error number: " << m_exceptionCaught);
873     LogError("Message: " << m_exceptionMessage);
874     TizenAppId & tizenId = m_installerContext.widgetConfig.tzAppid;
875
876     LogDebug("Call widget install failure finishedCallback");
877     std::stringstream errorNum;
878     errorNum << m_exceptionCaught;
879
880     // send signal of pkgmgr
881     getInstallerStruct().pkgmgrInterface->sendSignal(
882         PKGMGR_ERROR,
883         errorNum.str());
884
885     getInstallerStruct().pkgmgrInterface->sendSignal(
886         PKGMGR_END_KEY,
887         PKGMGR_END_FAILURE);
888
889     getInstallerStruct().finishedCallback(getInstallerStruct().userParam,
890                                           DPL::ToUTF8String(
891                                               tizenId), m_exceptionCaught);
892 }
893
894 void JobWidgetInstall::SaveExceptionData(const Jobs::JobExceptionBase &e)
895 {
896     m_exceptionCaught = static_cast<Jobs::Exceptions::Type>(e.getParam());
897     m_exceptionMessage = e.GetMessage();
898 }
899
900 void JobWidgetInstall::displayWidgetInfo()
901 {
902     WidgetDAOReadOnly dao(m_installerContext.widgetConfig.tzAppid);
903
904     std::ostringstream out;
905     WidgetLocalizedInfo localizedInfo =
906         W3CFileLocalization::getLocalizedInfo(dao.getTzAppId());
907
908     out << std::endl <<
909     "===================================== INSTALLED WIDGET INFO =========" \
910     "============================";
911     out << std::endl << "Name:                        " << localizedInfo.name;
912     out << std::endl << "AppId:                     " << dao.getTzAppId();
913     WidgetSize size = dao.getPreferredSize();
914     out << std::endl << "Width:                       " << size.width;
915     out << std::endl << "Height:                      " << size.height;
916     out << std::endl << "Start File:                  " <<
917     W3CFileLocalization::getStartFile(dao.getTzAppId());
918     out << std::endl << "Version:                     " << dao.getVersion();
919     out << std::endl << "Licence:                     " <<
920     localizedInfo.license;
921     out << std::endl << "Licence Href:                " <<
922     localizedInfo.licenseHref;
923     out << std::endl << "Description:                 " <<
924     localizedInfo.description;
925     out << std::endl << "Widget Id:                   " << dao.getGUID();
926     out << std::endl << "Widget recognized:           " << dao.isRecognized();
927     out << std::endl << "Widget distributor signed:   " <<
928     dao.isDistributorSigned();
929     out << std::endl << "Widget trusted:              " << dao.isTrusted();
930
931     OptionalWidgetIcon icon = W3CFileLocalization::getIcon(dao.getTzAppId());
932     DPL::OptionalString iconSrc =
933         !!icon ? icon->src : DPL::OptionalString::Null;
934     out << std::endl << "Icon:                        " << iconSrc;
935
936     out << std::endl << "Preferences:";
937     {
938         PropertyDAOReadOnly::WidgetPreferenceList list = dao.getPropertyList();
939         FOREACH(it, list)
940         {
941             out << std::endl << "  Key:                       " <<
942             it->key_name;
943             out << std::endl << "      Readonly:              " <<
944             it->readonly;
945         }
946     }
947
948     out << std::endl << "Features:";
949     {
950         WidgetFeatureSet list = dao.getFeaturesList();
951         FOREACH(it, list)
952         {
953             out << std::endl << "  Name:                      " << it->name;
954         }
955     }
956
957     out << std::endl;
958
959     LogInfo(out.str());
960 }
961
962 WrtDB::PackagingType JobWidgetInstall::checkPackageType(
963     const std::string &widgetSource,
964     const std::string &tempPath)
965 {
966     // Check installation type (direcotory/ or config.xml or widget.wgt)
967     if (WidgetUpdateMode::PolicyDirectoryForceInstall ==
968         m_jobStruct.updateMode)
969     {
970         LogDebug("Install directly from directory");
971         return PKG_TYPE_DIRECTORY_WEB_APP;
972     }
973     if (hasExtension(widgetSource, XML_EXTENSION)) {
974         LogInfo("Hosted app installation");
975         return PKG_TYPE_HOSTED_WEB_APP;
976     }
977
978     if (m_isDRM) {
979         std::string configFile = tempPath + "/" + CONFIG_XML;
980         if (WrtUtilFileExists(configFile)) {
981             return PKG_TYPE_NOMAL_WEB_APP;
982         }
983
984         configFile = tempPath + "/" + WITH_OSP_XML;
985         if (WrtUtilFileExists(configFile)) {
986             return PKG_TYPE_HYBRID_WEB_APP;
987         }
988     } else {
989         std::unique_ptr<DPL::ZipInput> zipFile;
990
991         Try
992         {
993             // Open zip file
994             zipFile.reset(new DPL::ZipInput(widgetSource));
995         }
996         Catch(DPL::ZipInput::Exception::OpenFailed)
997         {
998             LogDebug("Failed to open widget package");
999             return PKG_TYPE_UNKNOWN;
1000         }
1001         Catch(DPL::ZipInput::Exception::SeekFileFailed)
1002         {
1003             LogError("Failed to seek widget package file");
1004             return PKG_TYPE_UNKNOWN;
1005         }
1006
1007         Try
1008         {
1009             // Open config.xml file in package root
1010             std::unique_ptr<DPL::ZipInput::File> configFile(
1011                 zipFile->OpenFile(CONFIG_XML));
1012             return PKG_TYPE_NOMAL_WEB_APP;
1013         }
1014         Catch(DPL::ZipInput::Exception::OpenFileFailed)
1015         {
1016             LogDebug("Could not find config.xml");
1017         }
1018
1019         Try
1020         {
1021             // Open config.xml file in package root
1022             std::unique_ptr<DPL::ZipInput::File> configFile(
1023                 zipFile->OpenFile(WITH_OSP_XML));
1024
1025             return PKG_TYPE_HYBRID_WEB_APP;
1026         }
1027         Catch(DPL::ZipInput::Exception::OpenFileFailed)
1028         {
1029             LogDebug("Could not find wgt/config.xml");
1030             return PKG_TYPE_UNKNOWN;
1031         }
1032     }
1033
1034     return PKG_TYPE_UNKNOWN;
1035 }
1036
1037 void JobWidgetInstall::setApplicationType(
1038     const WrtDB::ConfigParserData &configInfo)
1039 {
1040     FOREACH(iterator, configInfo.nameSpaces) {
1041         LogInfo("namespace = [" << *iterator << "]");
1042         AppType currentAppType = APP_TYPE_UNKNOWN;
1043
1044         if (*iterator == ConfigurationNamespace::W3CWidgetNamespaceName) {
1045             continue;
1046         } else if (
1047             *iterator ==
1048             ConfigurationNamespace::WacWidgetNamespaceNameForLinkElement ||
1049             *iterator ==
1050             ConfigurationNamespace::WacWidgetNamespaceName)
1051         {
1052             currentAppType = APP_TYPE_WAC20;
1053         } else if (*iterator ==
1054                    ConfigurationNamespace::TizenWebAppNamespaceName)
1055         {
1056             currentAppType = APP_TYPE_TIZENWEBAPP;
1057         }
1058
1059         if (m_installerContext.widgetConfig.webAppType ==
1060             APP_TYPE_UNKNOWN)
1061         {
1062             m_installerContext.widgetConfig.webAppType = currentAppType;
1063         } else if (m_installerContext.widgetConfig.webAppType ==
1064                    currentAppType)
1065         {
1066             continue;
1067         } else {
1068             ThrowMsg(Exceptions::WidgetConfigFileInvalid,
1069                      "Config.xml has more than one namespace");
1070         }
1071     }
1072
1073     // If there is no define, type set to WAC 2.0
1074     if (m_installerContext.widgetConfig.webAppType == APP_TYPE_UNKNOWN) {
1075         m_installerContext.widgetConfig.webAppType = APP_TYPE_WAC20;
1076     }
1077
1078     LogInfo("type = [" <<
1079             m_installerContext.widgetConfig.webAppType.getApptypeToString() <<
1080             "]");
1081 }
1082
1083 bool JobWidgetInstall::detectResourceEncryption(
1084     const WrtDB::ConfigParserData &configData)
1085 {
1086     FOREACH(it, configData.settingsList)
1087     {
1088         if (it->m_name == SETTING_VALUE_ENCRYPTION &&
1089             it->m_value == SETTING_VALUE_ENCRYPTION_ENABLE)
1090         {
1091             LogDebug("resource need encryption");
1092             return true;
1093         }
1094     }
1095     return false;
1096 }
1097
1098 void JobWidgetInstall::setInstallLocationType(
1099     const
1100     WrtDB::ConfigParserData &
1101     configData)
1102 {
1103     m_installerContext.locationType = INSTALL_LOCATION_TYPE_NOMAL;
1104
1105     if (true == m_jobStruct.m_preload) {
1106         m_installerContext.locationType =
1107             INSTALL_LOCATION_TYPE_PRELOAD;
1108     } else {
1109         FOREACH(it, configData.settingsList)
1110         {
1111             if (it->m_name == SETTING_VALUE_INSTALLTOEXT_NAME &&
1112                 it->m_value ==
1113                 SETTING_VALUE_INSTALLTOEXT_PREPER_EXT)
1114             {
1115                 LogDebug("This widget will be installed to sd card");
1116                 m_installerContext.locationType =
1117                     INSTALL_LOCATION_TYPE_EXTERNAL;
1118             }
1119         }
1120     }
1121 }
1122
1123 bool JobWidgetInstall::isDRMWidget(std::string widgetPath)
1124 {
1125     /* TODO :
1126      * drm_bool_type_e is_drm_file = DRM_UNKNOWN;
1127      * int ret = -1;
1128      *
1129      * ret = drm_is_drm_file(widgetPath.c_str(), &is_drm_file);
1130      * if(DRM_RETURN_SUCCESS == ret && DRM_TRUE == is_drm_file) {
1131      */
1132
1133     /* blow code temporary code for drm. */
1134     int ret = drm_oem_intel_isDrmFile(const_cast<char*>(widgetPath.c_str()));
1135     if (1 == ret) {
1136         return true;
1137     } else {
1138         return false;
1139     }
1140 }
1141
1142 bool JobWidgetInstall::DecryptDRMWidget(std::string widgetPath,
1143                                         std::string destPath)
1144 {
1145     /* TODO :
1146      * drm_trusted_sapps_decrypt_package_info_s package_info;
1147      *
1148      * strncpy(package_info.sadcf_filepath, widgetPath.c_str(),
1149      *      sizeof(package_info.sadcf_filepath));
1150      * strncpy(package_info.decrypt_filepath, destPath.c_str(),
1151      *      sizeof(package_info.decrypt_filepath));
1152      *
1153      * drm_trusted_request_type_e requestType =
1154      *  DRM_TRUSTED_REQ_TYPE_SAPPS_DECRYPT_PACKAGE;
1155      *
1156      * int ret = drm_trusted_handle_request(requestType,
1157      *                                   (void *)&package_info, NULL);
1158      * if (DRM_TRUSTED_RETURN_SUCCESS == ret) {
1159      *  return true;
1160      * } else {
1161      *  return false;
1162      * }
1163      */
1164     if (drm_oem_intel_decrypt_package(const_cast<char*>(widgetPath.c_str()),
1165                                       const_cast<char*>(destPath.c_str())) != 0)
1166     {
1167         return true;
1168     } else {
1169         return false;
1170     }
1171 }
1172 } //namespace WidgetInstall
1173 } //namespace Jobs