• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "app_packager.h"
17 
18 #include "constants.h"
19 #include "json/hap_verify_info.h"
20 #include "json/module_json_utils.h"
21 #include "log.h"
22 #include "utils.h"
23 
24 namespace OHOS {
25 namespace AppPackingTool {
AppPackager(const std::map<std::string,std::string> & parameterMap,std::string & resultReceiver)26 AppPackager::AppPackager(const std::map<std::string, std::string> &parameterMap, std::string &resultReceiver)
27     : Packager(parameterMap, resultReceiver)
28 {}
29 
InitAllowedParam()30 int32_t AppPackager::InitAllowedParam()
31 {
32     allowedParameters_ = {
33         {}
34     };
35     return ERR_OK;
36 }
37 
PreProcess()38 int32_t AppPackager::PreProcess()
39 {
40     if (!CheckForceFlag()) {
41         return ERR_INVALID_VALUE;
42     }
43     bool ret = IsVerifyValidInAppMode();
44     if (!ret) {
45         return ERR_INVALID_VALUE;
46     }
47     return ERR_OK;
48 }
49 
Process()50 int32_t AppPackager::Process()
51 {
52     bool ret = CompressAppMode();
53     if (!ret) {
54         std::string outPath;
55         if (parameterMap_.find(Constants::PARAM_OUT_PATH) != parameterMap_.end()) {
56             outPath = parameterMap_.at(Constants::PARAM_OUT_PATH);
57         }
58         if (fs::exists(outPath)) {
59             fs::remove_all(outPath);
60         }
61         LOGE("App Process failed.");
62         return ERR_INVALID_VALUE;
63     }
64     return ERR_OK;
65 }
66 
PostProcess()67 int32_t AppPackager::PostProcess()
68 {
69     return ERR_OK;
70 }
71 
CheckBundleTypeConsistency(const std::string & hapPath,const std::string & hspPath)72 bool AppPackager::CheckBundleTypeConsistency(const std::string &hapPath, const std::string &hspPath)
73 {
74     std::string bundleType;
75     std::list<std::string> tmpHapPathList;
76     std::list<std::string> tmpHspPathList;
77     Packager::CompatibleProcess(hapPath, tmpHapPathList, Constants::HAP_SUFFIX);
78     Packager::CompatibleProcess(hspPath, tmpHspPathList, Constants::HSP_SUFFIX);
79     if (!tmpHapPathList.empty()) {
80         HapVerifyInfo hapVerifyInfo;
81         if (!ModuleJsonUtils::GetStageHapVerifyInfo(tmpHapPathList.front(), hapVerifyInfo)) {
82             LOGW("GetStageHapVerifyInfo failed, this hap maybe fa module");
83             return true;
84         }
85         bundleType = hapVerifyInfo.GetBundleType();
86     } else {
87         HapVerifyInfo hapVerifyInfo;
88         if (!ModuleJsonUtils::GetStageHapVerifyInfo(tmpHspPathList.front(), hapVerifyInfo)) {
89             LOGW("GetStageHapVerifyInfo failed, this hap maybe fa module");
90             return true;
91         }
92         bundleType = hapVerifyInfo.GetBundleType();
93     }
94     for (const auto& hapPath : tmpHapPathList) {
95         HapVerifyInfo hapVerifyInfo;
96         if (!ModuleJsonUtils::GetStageHapVerifyInfo(hapPath, hapVerifyInfo)) {
97             LOGW("GetStageHapVerifyInfo failed");
98             return false;
99         }
100         if (bundleType != hapVerifyInfo.GetBundleType()) {
101             LOGE("bundleType is not same");
102             return false;
103         }
104     }
105     for (const auto& hspPath : tmpHspPathList) {
106         HapVerifyInfo hapVerifyInfo;
107         if (!ModuleJsonUtils::GetStageHapVerifyInfo(hspPath, hapVerifyInfo)) {
108             LOGW("GetStageHapVerifyInfo failed");
109             return false;
110         }
111         if (bundleType != hapVerifyInfo.GetBundleType()) {
112             LOGE("bundleType is not same");
113             return false;
114         }
115     }
116     return true;
117 }
118 
VerifyIsSharedApp(const std::list<std::string> & hspPath)119 bool AppPackager::VerifyIsSharedApp(const std::list<std::string>& hspPath)
120 {
121     HapVerifyInfo hapVerifyInfo;
122     if (!ModuleJsonUtils::GetStageHapVerifyInfo(hspPath.front(), hapVerifyInfo)) {
123         return false;
124     }
125     if (hapVerifyInfo.GetBundleType() != Constants::TYPE_SHARED) {
126         return false;
127     }
128     return true;
129 }
130 
IsSharedApp(const std::string & hapPath,const std::string & hspPath)131 bool AppPackager::IsSharedApp(const std::string &hapPath, const std::string &hspPath)
132 {
133     if (!hapPath.empty()) {
134         return false;
135     }
136     if (hspPath.empty()) {
137         return false;
138     }
139     std::list<std::string> tmpHspPathList;
140     if (CompatibleProcess(hspPath, tmpHspPathList, Constants::HSP_SUFFIX)
141         && VerifyIsSharedApp(tmpHspPathList)) {
142             isSharedApp_ = true;
143         return true;
144     }
145     return false;
146 }
147 
VerifyIsAppService(const std::list<std::string> & modulePathList)148 bool AppPackager::VerifyIsAppService(const std::list<std::string>& modulePathList)
149 {
150     if (modulePathList.empty()) {
151         LOGE("Module path list is empty");
152         return false;
153     }
154 
155     for (const std::string& modulePath : modulePathList) {
156         HapVerifyInfo hapVerifyInfo;
157         if (!ModuleJsonUtils::GetStageHapVerifyInfo(modulePath, hapVerifyInfo)) {
158             return false;
159         }
160         if (hapVerifyInfo.GetBundleType() != Constants::BUNDLE_TYPE_APP_SERVICE) {
161             return false;
162         }
163     }
164     return true;
165 }
166 
IsAppService(const std::string & hapPath,const std::string & hspPath)167 bool AppPackager::IsAppService(const std::string &hapPath, const std::string &hspPath)
168 {
169     if (!hapPath.empty()) {
170         std::list<std::string> tmpHapPathList;
171         if (CompatibleProcess(hapPath, tmpHapPathList, Constants::HAP_SUFFIX)
172             && VerifyIsAppService(tmpHapPathList)) {
173                 isAppService_ = true;
174             return true;
175         }
176     }
177     if (hspPath.empty()) {
178         return false;
179     }
180     std::list<std::string> tmpHspPathList;
181     if (CompatibleProcess(hspPath, tmpHspPathList, Constants::HSP_SUFFIX)
182         && VerifyIsAppService(tmpHspPathList)) {
183             isAppService_ = true;
184         return true;
185     }
186     return false;
187 }
188 
CheckInputModulePath(const std::string & hapPath,const std::string & hspPath)189 bool AppPackager::CheckInputModulePath(const std::string &hapPath, const std::string &hspPath)
190 {
191     bool isSharedApp = IsSharedApp(hapPath, hspPath);
192     bool isAppService = IsAppService(hapPath, hspPath);
193     if (hapPath.empty() && !isSharedApp && !isAppService) {
194         LOGW("CheckInputModulePath hap-path is empty.");
195         return false;
196     }
197     if (hspPath.empty() && isAppService) {
198         LOGW("CheckInputModulePath hsp-path is empty.");
199         return false;
200     }
201     return true;
202 }
203 
GetAndCheckOutPath(std::string & outPath)204 bool AppPackager::GetAndCheckOutPath(std::string &outPath)
205 {
206     if (parameterMap_.find(Constants::PARAM_OUT_PATH) == parameterMap_.end()) {
207         LOGE("input out-path are null.");
208         return false;
209     }
210     outPath = parameterMap_.at(Constants::PARAM_OUT_PATH);
211     if (outPath.empty()) {
212         LOGE("input out-path are empty.");
213         return false;
214     }
215     if (outPath.find('.') == std::string::npos ||
216         outPath.substr(outPath.size() - Constants::APP_SUFFIX_LENGTH) != Constants::APP_SUFFIX) {
217         LOGE("out-path must end with .app.");
218         return false;
219     }
220     return true;
221 }
222 
GetAndCheckHapPathAndHspPath(std::string & hapPath,std::string & hspPath)223 bool AppPackager::GetAndCheckHapPathAndHspPath(std::string &hapPath, std::string &hspPath)
224 {
225     if (parameterMap_.find(Constants::PARAM_HAP_PATH) == parameterMap_.end() &&
226         parameterMap_.find(Constants::PARAM_HSP_PATH) == parameterMap_.end()) {
227         LOGE("input hap-path or hsp-path are all null.");
228         return false;
229     }
230     if (parameterMap_.find(Constants::PARAM_HAP_PATH) != parameterMap_.end()) {
231         hapPath = parameterMap_.at(Constants::PARAM_HAP_PATH);
232     }
233     if (parameterMap_.find(Constants::PARAM_HSP_PATH) != parameterMap_.end()) {
234         hspPath = parameterMap_.at(Constants::PARAM_HSP_PATH);
235     }
236     if (hapPath.empty() && hspPath.empty()) {
237         LOGE("input hap-path or hsp-path are all empty.");
238         return false;
239     }
240     if (!CheckBundleTypeConsistency(hapPath, hspPath)) {
241         LOGE("bundleType is inconsistent.");
242         return false;
243     }
244     if (!CheckInputModulePath(hapPath, hspPath)) {
245         LOGE("input hap-path or hsp-path is invalid.");
246     }
247     if (!hapPath.empty() && !CompatibleProcess(hapPath, formattedHapPathList_, Constants::HAP_SUFFIX)) {
248         LOGE("hap-path is invalid.");
249         return false;
250     }
251     if (!hspPath.empty() && !CompatibleProcess(hspPath, formattedHspPathList_, Constants::HSP_SUFFIX)) {
252         LOGE("hsp-path is invalid.");
253         return false;
254     }
255     return true;
256 }
257 
GetAndCheckPackInfoPath(std::string & packInfoPath)258 bool AppPackager::GetAndCheckPackInfoPath(std::string &packInfoPath)
259 {
260     if (parameterMap_.find(Constants::PARAM_PACK_INFO_PATH) == parameterMap_.end()) {
261         LOGE("input pack-info-path is null.");
262         return false;
263     }
264     packInfoPath = parameterMap_.at(Constants::PARAM_PACK_INFO_PATH);
265     if (packInfoPath.empty()) {
266         LOGE("input pack-info-path is empty.");
267         return false;
268     }
269     if (!fs::is_regular_file(packInfoPath) || fs::path(packInfoPath).filename() != Constants::PACK_INFO) {
270         LOGE("pack-info-path is invalid.");
271         return false;
272     }
273     return true;
274 }
275 
CheckSignaturePath()276 bool AppPackager::CheckSignaturePath()
277 {
278     auto it = parameterMap_.find(Constants::PARAM_SIGNATURE_PATH);
279     if (it != parameterMap_.end() && !it->second.empty()) {
280         if (!fs::is_regular_file(it->second)) {
281             LOGE("signature-path is invalid.");
282             return false;
283         }
284     }
285     return true;
286 }
287 
CheckCertificatePath()288 bool AppPackager::CheckCertificatePath()
289 {
290     auto it = parameterMap_.find(Constants::PARAM_CERTIFICATE_PATH);
291     if (it != parameterMap_.end() && !it->second.empty()) {
292         if (!fs::is_regular_file(it->second)) {
293             LOGE("certificate-path is invalid.");
294             return false;
295         }
296     }
297     return true;
298 }
299 
CheckEntrycardPath()300 bool AppPackager::CheckEntrycardPath()
301 {
302     auto it = parameterMap_.find(Constants::PARAM_ENTRYCARD_PATH);
303     if (it != parameterMap_.end() && !it->second.empty()) {
304         if (!CompatibleProcess(it->second, formattedEntryCardPathList_, Constants::PNG_SUFFIX)) {
305             LOGE("entrycard-path is invalid.");
306             return false;
307         }
308     }
309     return true;
310 }
311 
CheckPackResPath()312 bool AppPackager::CheckPackResPath()
313 {
314     auto it = parameterMap_.find(Constants::PARAM_PACK_RES_PATH);
315     if (it != parameterMap_.end() && !it->second.empty()) {
316         if (!IsPathValid(it->second, true, Constants::FILE_PACK_RES)) {
317             LOGE("pack-res-path is invalid.");
318             return false;
319         }
320     }
321     return true;
322 }
323 
IsVerifyValidInAppMode()324 bool AppPackager::IsVerifyValidInAppMode()
325 {
326     std::string hapPath;
327     std::string hspPath;
328     if (!GetAndCheckHapPathAndHspPath(hapPath, hspPath)) {
329         LOGE("GetAndCheckHapPathAndHspPath failed!");
330         return false;
331     }
332 
333     std::string packInfoPath;
334     if (!GetAndCheckPackInfoPath(packInfoPath)) {
335         LOGE("GetAndCheckPackInfoPath failed!");
336         return false;
337     }
338 
339     if (!CheckSignaturePath() || !CheckCertificatePath() || !CheckEntrycardPath() || !CheckPackResPath()) {
340         LOGE("CheckSignaturePath or CheckCertificatePath or CheckEntrycardPath or CheckPackResPath failed!");
341         return false;
342     }
343 
344     std::string outPath;
345     if (!GetAndCheckOutPath(outPath)) {
346         LOGE("GetAndCheckOutPath failed!");
347         return false;
348     }
349     std::string force;
350     if (parameterMap_.find(Constants::PARAM_FORCE) != parameterMap_.end()) {
351         force = parameterMap_.at(Constants::PARAM_FORCE);
352     }
353     return IsOutPathValid(outPath, force, Constants::APP_SUFFIX);
354 }
355 
PrepareDirectoriesAndFiles(const std::string outPath)356 bool AppPackager::PrepareDirectoriesAndFiles(const std::string outPath)
357 {
358     fs::path tempPath;
359     fs::path hspTempDirPath;
360     if (fs::exists(fs::path(outPath).parent_path().parent_path()) &&
361         fs::path(outPath).parent_path().parent_path() != fs::path("/")) {
362         tempPath = fs::path(outPath).parent_path().parent_path() / ((Constants::COMPRESSOR_APP_TEMP_DIR) +
363             Utils::GenerateUUID());
364         hspTempDirPath = fs::path(outPath).parent_path().parent_path() / ((Constants::COMPRESSOR_APP_TEMP_DIR) +
365             Utils::GenerateUUID());
366     } else {
367         tempPath = fs::path(outPath).parent_path() / ((Constants::COMPRESSOR_APP_TEMP_DIR) +
368             Utils::GenerateUUID());
369         hspTempDirPath = fs::path(outPath).parent_path() / ((Constants::COMPRESSOR_APP_TEMP_DIR) +
370             Utils::GenerateUUID());
371     }
372     if (!fs::exists(tempPath)) {
373         fs::create_directories(tempPath);
374     }
375     if (!fs::exists(hspTempDirPath)) {
376         fs::create_directories(hspTempDirPath);
377     }
378     if (!CompressHapAndHspFiles(tempPath, hspTempDirPath)) {
379         if (fs::exists(tempPath)) {
380             fs::remove_all(tempPath);
381         }
382         if (fs::exists(hspTempDirPath)) {
383             fs::remove_all(hspTempDirPath);
384         }
385         LOGE("AppPackager::CompressHapAndHspFiles failed.");
386         return false;
387     }
388     return true;
389 }
390 
CompressHapAndHspFiles(const fs::path & tempPath,const fs::path & hspTempDirPath)391 bool AppPackager::CompressHapAndHspFiles(const fs::path &tempPath, const fs::path &hspTempDirPath)
392 {
393     std::map<std::string, std::string>::const_iterator it = parameterMap_.find(Constants::PARAM_HAP_PATH);
394     std::list<std::string> fileList;
395     if (it != parameterMap_.end()) {
396         for (const auto& hapPathItem : formattedHapPathList_) {
397             fs::path hapFile = hapPathItem;
398             fs::path hapTempPath = tempPath / hapFile.filename();
399             fs::path hapUnzipTempPath = tempPath / ((Constants::COMPRESSOR_APP_TEMP_DIR) +
400                 Utils::GenerateUUID());
401             fileList.push_back(hapTempPath.string());
402             it = parameterMap_.find(Constants::PARAM_PACK_INFO_PATH);
403             if (it != parameterMap_.end()) {
404                 CompressPackinfoIntoHap(hapPathItem, hapUnzipTempPath, hapTempPath.string(), it->second);
405             }
406         }
407     }
408     it = parameterMap_.find(Constants::PARAM_HSP_PATH);
409     if (it != parameterMap_.end()) {
410         for (const auto& hspPathItem : formattedHspPathList_) {
411             fs::path hspFile = hspPathItem;
412             fs::path hspTempPath = hspTempDirPath / hspFile.filename();
413             fs::path hspUnzipTempPath = tempPath / ((Constants::COMPRESSOR_APP_TEMP_DIR) +
414             Utils::GenerateUUID());
415             fileList.push_back(hspTempPath.string());
416             it = parameterMap_.find(Constants::PARAM_PACK_INFO_PATH);
417             if (it != parameterMap_.end()) {
418                 CompressPackinfoIntoHap(hspPathItem, hspUnzipTempPath, hspTempPath.string(), it->second);
419             }
420         }
421     }
422     if (!ModuleJsonUtils::CheckHapsIsValid(fileList, isSharedApp_)) {
423         LOGE("AppPackager::CheckHapsIsValid verify failed.");
424         return false;
425     }
426     if (!AddHapListToApp(fileList)) {
427         zipWrapper_.SetZipLevel(ZipLevel::ZIP_LEVEL_DEFAULT);
428         LOGE("AppPackager::AddHapListToApp failed.");
429         return false;
430     }
431     if (fs::exists(tempPath)) {
432         fs::remove_all(tempPath);
433     }
434     if (fs::exists(hspTempDirPath)) {
435         fs::remove_all(hspTempDirPath);
436     }
437     return true;
438 }
439 
AddHapListToApp(const std::list<std::string> & fileList)440 bool AppPackager::AddHapListToApp(const std::list<std::string> &fileList)
441 {
442     for (const auto& hapPath : fileList) {
443         HapVerifyInfo hapVerifyInfo;
444         if (ModuleJsonUtils::IsModuleHap(hapPath)) {
445             if (!ModuleJsonUtils::GetStageHapVerifyInfo(hapPath, hapVerifyInfo)) {
446                 LOGW("GetStageHapVerifyInfo failed! hapPath:%s", hapPath.c_str());
447             }
448         } else {
449             if (!ModuleJsonUtils::GetFaHapVerifyInfo(hapPath, hapVerifyInfo)) {
450                 LOGW("GetFaHapVerifyInfo failed! hapPath:%s", hapPath.c_str());
451             }
452         }
453         if (hapVerifyInfo.IsDebug()) {
454             zipWrapper_.SetZipLevel(ZipLevel::ZIP_LEVEL_0);
455         }
456         if (zipWrapper_.AddFileOrDirectoryToZip(hapPath, fs::path(hapPath).filename().string()) !=
457             ZipErrCode::ZIP_ERR_SUCCESS) {
458             LOGE("AppPackager::Process: zipWrapper AddFileOrDirectoryToZip failed!");
459             return false;
460         }
461         zipWrapper_.SetZipLevel(ZipLevel::ZIP_LEVEL_DEFAULT);
462     }
463     return true;
464 }
465 
CompressOtherFiles()466 bool AppPackager::CompressOtherFiles()
467 {
468     std::string moduleName;
469     std::map<std::string, std::string>::const_iterator it = parameterMap_.find(Constants::PARAM_ENTRYCARD_PATH);
470     if (it != parameterMap_.end() && !it->second.empty()) {
471         std::string entryCardPath = Constants::ENTRYCARD_NAME + Constants::LINUX_FILE_SEPARATOR +
472             moduleName + Constants::LINUX_FILE_SEPARATOR +
473             Constants::ENTRYCARD_BASE_NAME + Constants::LINUX_FILE_SEPARATOR +
474             Constants::ENTRYCARD_SNAPSHOT_NAME + Constants::LINUX_FILE_SEPARATOR;
475         for (auto itemFormattedEntryCardPath : formattedEntryCardPathList_) {
476             if (zipWrapper_.AddFileOrDirectoryToZip(itemFormattedEntryCardPath, entryCardPath +
477                 fs::path(itemFormattedEntryCardPath).filename().string()) !=
478                 ZipErrCode::ZIP_ERR_SUCCESS) {
479                 return false;
480             }
481         }
482     }
483     it = parameterMap_.find(Constants::PARAM_PACK_INFO_PATH);
484     if (it != parameterMap_.end()) {
485         if (zipWrapper_.AddFileOrDirectoryToZip(it->second, Constants::PACK_INFO) != ZipErrCode::ZIP_ERR_SUCCESS) {
486             return false;
487         }
488     }
489     it = parameterMap_.find(Constants::PARAM_SIGNATURE_PATH);
490     if (it != parameterMap_.end()) {
491         std::string zipPath = Constants::NULL_DIR_NAME;
492         zipPath = fs::path(it->second).filename().string();
493         if (zipWrapper_.AddFileOrDirectoryToZip(it->second, zipPath) != ZipErrCode::ZIP_ERR_SUCCESS) {
494             return false;
495         }
496     }
497     it = parameterMap_.find(Constants::PARAM_CERTIFICATE_PATH);
498     if (it != parameterMap_.end()) {
499         std::string zipPath = Constants::NULL_DIR_NAME;
500         zipPath = fs::path(it->second).filename().string();
501         if (zipWrapper_.AddFileOrDirectoryToZip(it->second, zipPath) != ZipErrCode::ZIP_ERR_SUCCESS) {
502             return false;
503         }
504     }
505     return true;
506 }
507 
CompressAppMode()508 bool AppPackager::CompressAppMode()
509 {
510     std::string outPath;
511     if (parameterMap_.find(Constants::PARAM_OUT_PATH) != parameterMap_.end()) {
512         outPath = parameterMap_.at(Constants::PARAM_OUT_PATH);
513     }
514     zipWrapper_.Open(outPath);
515     if (!zipWrapper_.IsOpen()) {
516         LOGE("AppPackager::CompressAppMode: zipWrapper Open failed!");
517         return ERR_INVALID_VALUE;
518     }
519     if (!PrepareDirectoriesAndFiles(outPath)) {
520         return false;
521     }
522     if (!CompressOtherFiles()) {
523         return false;
524     }
525     std::map<std::string, std::string>::const_iterator it = parameterMap_.find(Constants::PARAM_PACK_RES_PATH);
526     if (it != parameterMap_.end()) {
527         std::string zipPath = Constants::NULL_DIR_NAME;
528         zipPath = fs::path(it->second).filename().string();
529         if (zipWrapper_.AddFileOrDirectoryToZip(it->second, zipPath) != ZipErrCode::ZIP_ERR_SUCCESS) {
530             return false;
531         }
532     }
533     zipWrapper_.Close();
534     return true;
535 }
536 } // namespace AppPackingTool
537 } // namespace OHOS