Initialize Tizen 2.3
[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 <string>
24 #include <sys/time.h>
25 #include <ctime>
26 #include <cstdlib>
27 #include <limits.h>
28 #include <regex.h>
29
30 #include <dpl/platform.h>
31 #include <dpl/utils/wrt_utility.h>
32 #include <dpl/utils/path.h>
33 #include <dpl/localization/w3c_file_localization.h>
34
35 #include <pkg-manager/pkgmgr_signal.h>
36 #include <app_manager.h>
37 #include <privilege-control.h>
38 #include "root_parser.h"
39 #include "widget_parser.h"
40 #include "parser_runner.h"
41 #include <widget_install/job_widget_install.h>
42 #include <widget_install/task_certify.h>
43 #include <widget_install/task_process_config.h>
44 #include <widget_install/task_file_manipulation.h>
45 #include <widget_install/task_ace_check.h>
46 #include <widget_install/task_smack.h>
47 #include <widget_install/task_manifest_file.h>
48 #include <widget_install/task_prepare_files.h>
49 #include <widget_install/task_recovery.h>
50 #include <widget_install/task_install_ospsvc.h>
51 #include <widget_install/task_update_files.h>
52 #include <widget_install/task_database.h>
53 #include <widget_install/task_remove_backup.h>
54 #include <widget_install/task_encrypt_resource.h>
55 #include <widget_install/task_pkg_info_update.h>
56 #include <widget_install/task_commons.h>
57 #include <widget_install/task_prepare_reinstall.h>
58 #include <widget_install/task_configuration.h>
59 #include <widget_install/task_user_data_manipulation.h>
60 #include <widget_install/task_status_check.h>
61 #if ENABLE(PRE_LAUNCH)
62 #include <widget_install/task_prelaunching_registration.h>
63 #endif
64 #include <widget_install_to_external.h>
65 #include <boost/optional/optional_io.hpp>
66 #include <boost/filesystem.hpp>
67 #include <dpl/log/secure_log.h>
68
69 namespace bf = boost::filesystem;
70
71 using namespace WrtDB;
72 using namespace Jobs::Exceptions;
73
74 namespace Jobs {
75 namespace WidgetInstall {
76
77 JobWidgetInstall::JobWidgetInstall(
78     std::string const &widgetPath,
79     std::string const &tzPkgId,
80     const Jobs::WidgetInstall::WidgetInstallationStruct &
81     installerStruct) :
82     Job(UnknownInstallation),
83     JobContextBase<Jobs::WidgetInstall::WidgetInstallationStruct>(installerStruct),
84     m_exceptionCaught(Jobs::Exceptions::Success)
85 {
86     m_installerContext.mode = m_jobStruct.m_installMode;
87     m_installerContext.requestedPath = widgetPath;
88     m_jobStruct.pkgmgrInterface->setPkgname(tzPkgId);
89
90     if (InstallMode::Command::RECOVERY == m_installerContext.mode.command) {
91         m_installerContext.widgetConfig.tzPkgid = DPL::FromUTF8String(tzPkgId);
92         AddTask(new TaskRecovery(this));
93     }
94
95     //start configuration of installation
96     AddTask(new TaskConfiguration(this));
97
98     m_installerContext.callerPkgId
99             = DPL::FromUTF8String(m_jobStruct.pkgmgrInterface->getCallerId());
100     _D("Caller Package Id : %s", DPL::ToUTF8String(m_installerContext.callerPkgId).c_str());
101 }
102
103 void JobWidgetInstall::appendNewInstallationTaskList()
104 {
105     _D("Configure installation succeeded");
106     SetProgressFlag(true);
107
108     AddTask(new TaskFileManipulation(this));
109     AddTask(new TaskProcessConfig(this));
110     if (m_installerContext.widgetConfig.packagingType ==
111         WrtDB::PKG_TYPE_HOSTED_WEB_APP)
112     {
113         AddTask(new TaskPrepareFiles(this));
114     }
115     AddTask(new TaskCertify(this));
116     AddTask(new TaskUserDataManipulation(this));
117     if (m_installerContext.needEncryption) {
118         AddTask(new TaskEncryptResource(this));
119     }
120     AddTask(new TaskManifestFile(this));
121     if (m_installerContext.widgetConfig.packagingType ==
122         PKG_TYPE_HYBRID_WEB_APP) {
123         AddTask(new TaskInstallOspsvc(this));
124     }
125     AddTask(new TaskDatabase(this));
126     AddTask(new TaskAceCheck(this));
127     AddTask(new TaskSmack(this));
128     AddTask(new TaskPkgInfoUpdate(this));
129 #if ENABLE(PRE_LAUNCH)
130     if (m_installerContext.isNeedPreLaunching) {
131         AddTask(new TaskPreLaunchingRegistration(this));
132     }
133 #endif
134 }
135
136 void JobWidgetInstall::appendUpdateInstallationTaskList()
137 {
138     _D("Configure installation updated");
139     _D("Widget Update");
140     SetProgressFlag(true);
141     AddTask(new TaskStatusCheck(this));
142
143     if (m_installerContext.mode.command ==
144         InstallMode::Command::REINSTALL) {
145         AddTask(new TaskPrepareReinstall(this));
146     }
147
148     if (m_installerContext.mode.extension !=
149             InstallMode::ExtensionType::DIRECTORY) {
150         AddTask(new TaskUpdateFiles(this));
151         AddTask(new TaskFileManipulation(this));
152     }
153
154     AddTask(new TaskProcessConfig(this));
155
156     if (m_installerContext.widgetConfig.packagingType ==
157         WrtDB::PKG_TYPE_HOSTED_WEB_APP) {
158         AddTask(new TaskPrepareFiles(this));
159     }
160
161     AddTask(new TaskCertify(this));
162     AddTask(new TaskUserDataManipulation(this));
163     if (m_installerContext.needEncryption) {
164         AddTask(new TaskEncryptResource(this));
165     }
166     AddTask(new TaskManifestFile(this));
167     if (m_installerContext.widgetConfig.packagingType ==
168         PKG_TYPE_HYBRID_WEB_APP) {
169         AddTask(new TaskInstallOspsvc(this));
170     }
171
172     AddTask(new TaskDatabase(this));
173     AddTask(new TaskAceCheck(this));
174     //TODO: remove widgetHandle from this task and move before database task
175     // by now widget handle is needed in ace check
176     // Any error in acecheck while update will break widget
177     AddTask(new TaskSmack(this));
178     AddTask(new TaskRemoveBackupFiles(this));
179     AddTask(new TaskPkgInfoUpdate(this));
180 }
181
182 void JobWidgetInstall::appendRDSUpdateTaskList()
183 {
184     _D("Configure installation RDS updated");
185     SetProgressFlag(true);
186     AddTask(new TaskStatusCheck(this));
187     AddTask(new TaskPrepareReinstall(this));
188     AddTask(new TaskCertify(this));
189 }
190
191 void JobWidgetInstall::appendRecoveryTaskList()
192 {
193     _D("Recovery Task");
194     SetProgressFlag(true);
195
196     AddTask(new TaskProcessConfig(this));
197
198     AddTask(new TaskCertify(this));
199     AddTask(new TaskManifestFile(this));
200     if (m_installerContext.widgetConfig.packagingType ==
201         PKG_TYPE_HYBRID_WEB_APP) {
202         AddTask(new TaskInstallOspsvc(this));
203     }
204     AddTask(new TaskSmack(this));
205 }
206
207 void JobWidgetInstall::appendFotaInstallationTaskList()
208 {
209     /* TODO */
210     _D("Configure installation succeeded");
211     SetProgressFlag(true);
212
213     AddTask(new TaskProcessConfig(this));
214     AddTask(new TaskCertify(this));
215     AddTask(new TaskUserDataManipulation(this));
216     if (m_installerContext.needEncryption) {
217         AddTask(new TaskEncryptResource(this));
218     }
219     AddTask(new TaskManifestFile(this));
220     if (m_installerContext.widgetConfig.packagingType ==
221         PKG_TYPE_HYBRID_WEB_APP)
222     {
223         AddTask(new TaskInstallOspsvc(this));
224     }
225     AddTask(new TaskDatabase(this));
226     AddTask(new TaskAceCheck(this));
227     AddTask(new TaskSmack(this));
228     AddTask(new TaskPkgInfoUpdate(this));
229 }
230
231 void JobWidgetInstall::appendFotaUpdateTaskList()
232 {
233     _D("Configure installation updated");
234     _D("Widget Update");
235     SetProgressFlag(true);
236
237     AddTask(new TaskProcessConfig(this));
238     AddTask(new TaskCertify(this));
239     AddTask(new TaskUserDataManipulation(this));
240     if (m_installerContext.needEncryption) {
241         AddTask(new TaskEncryptResource(this));
242     }
243
244     AddTask(new TaskManifestFile(this));
245     if (m_installerContext.widgetConfig.packagingType ==
246         PKG_TYPE_HYBRID_WEB_APP)
247     {
248         AddTask(new TaskInstallOspsvc(this));
249     }
250
251     AddTask(new TaskDatabase(this));
252     AddTask(new TaskAceCheck(this));
253     //TODO: remove widgetHandle from this task and move before database task
254     // by now widget handle is needed in ace check
255     // Any error in acecheck while update will break widget
256     AddTask(new TaskSmack(this));
257     AddTask(new TaskPkgInfoUpdate(this));
258 #if ENABLE(PRE_LAUNCH)
259     if (m_installerContext.isNeedPreLaunching) {
260         AddTask(new TaskPreLaunchingRegistration(this));
261     }
262 #endif
263 }
264
265 void JobWidgetInstall::SendProgress()
266 {
267     using namespace PackageManager;
268     if (GetProgressFlag() != false) {
269         if (GetInstallerStruct().progressCallback != NULL) {
270             // send progress signal of pkgmgr
271             GetInstallerStruct().pkgmgrInterface->sendProgressInstall(GetProgressPercent());
272
273             _D("Call widget install progressCallback");
274             GetInstallerStruct().progressCallback(
275                 GetInstallerStruct().userParam,
276                 GetProgressPercent(),
277                 GetProgressDescription());
278         }
279     }
280 }
281
282 void JobWidgetInstall::SendProgressIconPath(const std::string &path)
283 {
284     using namespace PackageManager;
285     if (GetProgressFlag() != false) {
286         if (GetInstallerStruct().progressCallback != NULL) {
287             // send progress signal of pkgmgr
288             GetInstallerStruct().pkgmgrInterface->sendIconPath(path);
289         }
290     }
291 }
292
293 void JobWidgetInstall::SendFinishedSuccess()
294 {
295     using namespace PackageManager;
296     // TODO : sync should move to separate task.
297     sync();
298
299     if (INSTALL_LOCATION_TYPE_PREFER_EXTERNAL == m_installerContext.locationType) {
300         if (m_installerContext.isUpdateMode) {
301             WidgetInstallToExtSingleton::Instance().postUpgrade(true);
302         } else {
303             WidgetInstallToExtSingleton::Instance().postInstallation(true);
304         }
305         WidgetInstallToExtSingleton::Instance().deinitialize();
306     }
307
308     /* smack label of ".mmc" is changed to "wrt-installer" after calling above function.
309        smack label of ".mmc" must be set to [pkgid] to success uninstallation by app2ext. */
310     std::string mmcDir = m_installerContext.locations->getPackageInstallationDir() + "/.mmc";
311     std::string pkgid = DPL::ToUTF8String(m_installerContext.widgetConfig.tzPkgid);
312     if (PC_OPERATION_SUCCESS != perm_app_setup_path(pkgid.c_str(), mmcDir.c_str(), APP_PATH_PRIVATE)) {
313         _W("change to wrt-installer label to %s", mmcDir.c_str());
314     }
315
316     //inform widget info
317     JobWidgetInstall::displayWidgetInfo();
318
319     TizenAppId& tizenId = m_installerContext.widgetConfig.tzAppid;
320
321     // send signal of pkgmgr
322     GetInstallerStruct().pkgmgrInterface->endJob(m_exceptionCaught);
323
324     _D("Call widget install successfinishedCallback");
325     GetInstallerStruct().finishedCallback(GetInstallerStruct().userParam,
326                                           DPL::ToUTF8String(
327                                               tizenId), Jobs::Exceptions::Success);
328 }
329
330 void JobWidgetInstall::SendFinishedFailure()
331 {
332     using namespace PackageManager;
333
334     // print error message
335     LOGE("Error number: %d", m_exceptionCaught);
336     LOGE("Error message: %s", m_exceptionMessage.c_str());
337     fprintf(stderr, "[Err:%d] %s", m_exceptionCaught, m_exceptionMessage.c_str());
338
339     TizenAppId & tizenId = m_installerContext.widgetConfig.tzAppid;
340
341     _D("Call widget install failure finishedCallback");
342
343     // send signal of pkgmgr
344     GetInstallerStruct().pkgmgrInterface->endJob(m_exceptionCaught, m_exceptionMessage.c_str());
345
346     GetInstallerStruct().finishedCallback(GetInstallerStruct().userParam,
347                                           DPL::ToUTF8String(
348                                               tizenId), m_exceptionCaught);
349 }
350
351 void JobWidgetInstall::SaveExceptionData(const Jobs::JobExceptionBase &e)
352 {
353     m_exceptionCaught = static_cast<Jobs::Exceptions::Type>(e.getParam());
354     m_exceptionMessage = e.GetMessage();
355 }
356
357 void JobWidgetInstall::displayWidgetInfo()
358 {
359     if (m_installerContext.widgetConfig.webAppType.appType == WrtDB::APP_TYPE_TIZENWEBAPP)
360     {
361         WidgetDAOReadOnly dao(m_installerContext.widgetConfig.tzAppid);
362
363         std::ostringstream out;
364         WidgetLocalizedInfo localizedInfo =
365         W3CFileLocalization::getLocalizedInfo(dao.getTizenAppId());
366         WidgetSize size = dao.getPreferredSize();
367         DPL::OptionalString startFile =
368         W3CFileLocalization::getStartFile(dao.getTizenAppId());
369
370         out << std::endl <<
371         "===================================== INSTALLED WIDGET INFO =========" \
372         "============================";
373         if (!!(localizedInfo.name))
374             out << std::endl << "Name:                        " << *(localizedInfo.name);
375         else
376             out << std::endl << "Name:                        " << "--";
377         out << std::endl << "AppId:                       " << dao.getTizenAppId();
378         out << std::endl << "Width:                       " << size.width;
379         out << std::endl << "Height:                      " << size.height;
380         if (!!(startFile))
381             out << std::endl << "Start File:                  " << *(startFile);
382         else
383             out << std::endl << "Start File:                  " << "--";
384         if (!!(dao.getVersion()))
385             out << std::endl << "Version:                     " << *(dao.getVersion());
386         else
387             out << std::endl << "Version:                     " << "--";
388         if (!!(localizedInfo.license))
389             out << std::endl << "Licence:                     " << *(localizedInfo.license);
390         else
391             out << std::endl << "Licence:                     " << "--";
392         if (!!(localizedInfo.licenseHref))
393             out << std::endl << "Licence Href:                " << *(localizedInfo.licenseHref);
394         else
395             out << std::endl << "Licence Href:                " << "--";
396         if (!!(localizedInfo.description))
397             out << std::endl << "Description:                 " << *(localizedInfo.description);
398         else
399             out << std::endl << "Description:                 " << "--";
400         if (!!(dao.getGUID()))
401             out << std::endl << "Widget Id:                   " << *(dao.getGUID());
402         else
403             out << std::endl << "Widget Id:                   " << "--";
404
405         OptionalWidgetIcon icon = W3CFileLocalization::getIcon(dao.getTizenAppId());
406         DPL::OptionalString iconSrc =
407             !!icon ? icon->src : DPL::OptionalString();
408         if (!!(iconSrc))
409             out << std::endl << "Icon:                        " << *(iconSrc);
410         else
411             out << std::endl << "Icon:                        " << "--";
412
413         out << std::endl << "Preferences:";
414         {
415             PropertyDAOReadOnly::WidgetPreferenceList list = dao.getPropertyList();
416             FOREACH(it, list)
417             {
418                 out << std::endl << "  Key:                       " <<
419                 it->key_name;
420                 out << std::endl << "  Readonly:                  " <<
421                 it->readonly;
422             }
423         }
424
425         out << std::endl;
426
427         _D("%s", out.str().c_str());
428     }
429 }
430
431 void JobWidgetInstall::SecureRemove(const bf::path& path)
432 {
433     if (path.empty()) {
434         _E("error for get path");
435         ThrowMsg(Jobs::WidgetInstall::Exceptions::RemovingFileFailure, "Try to remove insecure location");
436         return;
437     }
438
439     const char* blacklist[] = {
440         "/",
441         "/opt",
442         "/opt/",
443         "/opt/share",
444         "/opt/share/",
445         "/opt/share/widget",
446         "/opt/share/widget/",
447         "/opt/share/widget/temp_info",
448         "/opt/share/widget/temp_info/",
449         "/opt/share/packages",
450         "/opt/share/packages/",
451         "/opt/share/applications",
452         "/opt/share/applications/",
453         "/opt/usr",
454         "/opt/usr/",
455         "/opt/usr/apps",
456         "/opt/usr/apps/",
457         NULL
458     };
459
460     char* canonicalizeFilePath = canonicalize_file_name(path.c_str());
461     if (!canonicalizeFilePath) {
462         _E("error : a pathname[%s] component is unreadable or does not exist", path.c_str());
463         //ThrowMsg(Jobs::WidgetInstall::Exceptions::RemovingFileFailure, "Try to remove insecure location");
464         return;
465     }
466
467     int idx = 0;
468     while(blacklist[idx]){
469         char* cmpFilePath = canonicalize_file_name(blacklist[idx]);
470         if (cmpFilePath) {
471             if(!strcmp(canonicalizeFilePath, cmpFilePath)) {
472                 _E("illegal access : %s", path.c_str());
473                 free(cmpFilePath);
474                 free(canonicalizeFilePath);
475                 ThrowMsg(Jobs::WidgetInstall::Exceptions::RemovingFileFailure, "Try to remove insecure location");
476                 return;
477             }
478             free(cmpFilePath);
479         }
480         idx++;
481     }
482     free(canonicalizeFilePath);
483     bf::remove_all(path);
484 }
485 } //namespace WidgetInstall
486 } //namespace Jobs