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> ¶meterMap, 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