• 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 "packager.h"
17 
18 #include <filesystem>
19 #include <fstream>
20 #include <random>
21 #include <sstream>
22 #include <string>
23 #include <unordered_set>
24 
25 #include "json/json_utils.h"
26 #include "log.h"
27 #include "utils.h"
28 #include "zip_utils.h"
29 
30 namespace OHOS {
31 namespace AppPackingTool {
32 namespace {
33 const std::string EN_US_UTF_8 = "en_US.UTF-8";
34 }
35 
Packager(const std::map<std::string,std::string> & parameterMap,std::string & resultReceiver)36 Packager::Packager(const std::map<std::string, std::string> &parameterMap, std::string &resultReceiver)
37     : parameterMap_(parameterMap), resultReceiver_(resultReceiver)
38 {}
39 
~Packager()40 Packager::~Packager()
41 {}
42 
MakePackage()43 int32_t Packager::MakePackage()
44 {
45     int32_t ret = ERR_OK;
46     ret = InitAllowedParam();
47     if (ret != ERR_OK) {
48         LOGE("InitAllowedParam err");
49         return ret;
50     }
51 
52     ret = PreProcess();
53     if (ret != ERR_OK) {
54         LOGE("PreProcess err");
55         return ret;
56     }
57     ret = Process();
58     if (ret != ERR_OK) {
59         LOGE("Process err");
60         return ret;
61     }
62 
63     ret = PostProcess();
64     if (ret != ERR_OK) {
65         LOGE("PostProcess err");
66         return ret;
67     }
68     return ret;
69 }
70 
PreProcess()71 int32_t Packager::PreProcess()
72 {
73     resultReceiver_.append("do PreProcess\n");
74     return ERR_OK;
75 }
76 
Process()77 int32_t Packager::Process()
78 {
79     resultReceiver_.append("do Process\n");
80     return ERR_OK;
81 }
82 
PostProcess()83 int32_t Packager::PostProcess()
84 {
85     resultReceiver_.append("do PostProcess\n");
86     return ERR_OK;
87 }
88 
CheckForceFlag()89 bool Packager::CheckForceFlag()
90 {
91     auto it = parameterMap_.find(Constants::PARAM_FORCE);
92     if (it != parameterMap_.end() && it->second != "false" && it->second != "true") {
93         LOGE("Packager::commandVerify forceRewrite is invalid.");
94         return false;
95     }
96     return true;
97 }
98 
IsPathValid(const std::string & path,const bool & isFile,const std::string suffix)99 bool Packager::IsPathValid(const std::string &path, const bool &isFile, const std::string suffix)
100 {
101     if (isFile && fs::is_regular_file(path)) {
102         std::string name = fs::path(path).filename();
103         std::locale englishLocale(EN_US_UTF_8);
104         std::transform(name.begin(), name.end(), name.begin(),
105                        [&englishLocale](unsigned char c) { return std::tolower(c); });
106         if (Utils::EndsWith(name, suffix)) {
107             return true;
108         }
109     }
110     return (!isFile) && fs::is_directory(path);
111 }
112 
SplitDirList(const std::string & dirList,std::list<std::string> & fileList)113 bool Packager::SplitDirList(const std::string &dirList, std::list<std::string> &fileList)
114 {
115     std::list<std::string> pathList;
116     RemoveDuplicatePath(dirList, pathList);
117     for (const std::string &pathItem : pathList) {
118         std::string formattedPathItem;
119         if (!Utils::GetFormattedPath(pathItem, formattedPathItem)) {
120             LOGE("GetFormattedPath failed for %s", pathItem.c_str());
121             return false;
122         };
123         if (!IsPathValid(formattedPathItem, false)) {
124             return false;
125         }
126         fileList.push_back(formattedPathItem);
127     }
128     return true;
129 }
130 
RemoveDuplicatePath(const std::string & path,std::list<std::string> & pathList)131 void Packager::RemoveDuplicatePath(const std::string &path, std::list<std::string> &pathList)
132 {
133     std::string pathItem;
134     std::istringstream pathStream(path);
135     while (std::getline(pathStream, pathItem, Constants::COMMA_SPLIT)) {
136         pathList.push_back(pathItem);
137     }
138     std::unordered_set<std::string> uniqueTokens(pathList.begin(), pathList.end());
139     pathList.assign(uniqueTokens.begin(), uniqueTokens.end());
140 }
141 
CompatibleProcess(const std::string & inputPath,std::list<std::string> & fileList,const std::string & suffix)142 bool Packager::CompatibleProcess(const std::string &inputPath, std::list<std::string> &fileList,
143     const std::string &suffix)
144 {
145     if (IsPathValid(inputPath, false)) {
146         for (const auto& fileItem : fs::recursive_directory_iterator(inputPath)) {
147             std::string name = fileItem.path().filename();
148             std::locale englishLocale(EN_US_UTF_8);
149             std::transform(name.begin(), name.end(), name.begin(),
150                  [&englishLocale](unsigned char c) { return std::tolower(c); });
151             if (Utils::EndsWith(name, suffix)) {
152                 fileList.push_back(fileItem.path().string());
153             }
154         }
155         return true;
156     } else {
157         std::string formattedPathItem;
158         std::list<std::string> pathList;
159         RemoveDuplicatePath(inputPath, pathList);
160         for (std::string pathItem : pathList) {
161             if (!Utils::GetFormattedPath(pathItem, formattedPathItem)) {
162                 LOGE("GetFormattedPath failed for %s", pathItem.c_str());
163                 return false;
164             };
165             if (!IsPathValid(formattedPathItem, true, suffix)) {
166                 return false;
167             }
168             fileList.push_back(formattedPathItem);
169         }
170         return true;
171     }
172 }
173 
CompatibleProcess(const std::string & inputPath,std::list<std::string> & fileList,const std::string & suffix,const std::string & extraSuffix)174 bool Packager::CompatibleProcess(const std::string &inputPath, std::list<std::string> &fileList,
175     const std::string &suffix, const std::string &extraSuffix)
176 {
177     if (IsPathValid(inputPath, false)) {
178         for (const auto& fileItem : fs::recursive_directory_iterator(inputPath)) {
179             std::string name = fileItem.path().filename();
180             std::locale englishLocale(EN_US_UTF_8);
181             std::transform(name.begin(), name.end(), name.begin(),
182                  [&englishLocale](unsigned char c) { return std::tolower(c); });
183             if (Utils::EndsWith(name, suffix) || Utils::EndsWith(name, extraSuffix)) {
184                 fileList.push_back(fileItem.path().string());
185             }
186         }
187         return true;
188     } else {
189         std::string formattedPathItem;
190         std::list<std::string> pathList;
191         RemoveDuplicatePath(inputPath, pathList);
192         for (std::string pathItem : pathList) {
193             if (!Utils::GetFormattedPath(pathItem, formattedPathItem)) {
194                 LOGE("GetFormattedPath failed for %s", pathItem.c_str());
195                 return false;
196             };
197             if (!IsPathValid(formattedPathItem, true, suffix) &&
198                 !IsPathValid(formattedPathItem, true, extraSuffix)) {
199                 return false;
200             }
201             fileList.push_back(formattedPathItem);
202         }
203         return true;
204     }
205 }
206 
IsOutPathValid(const std::string & outPath,const std::string & forceRewrite,const std::string & suffix)207 bool Packager::IsOutPathValid(const std::string &outPath, const std::string &forceRewrite, const std::string &suffix)
208 {
209     fs::path filePath(outPath);
210 
211     if ("false" == forceRewrite && fs::exists(filePath)) {
212         LOGE("Packager::isOutPathValid out file already existed.");
213         return false;
214     }
215 
216     if (suffix == Constants::HAP_SUFFIX) {
217         if (!Utils::EndsWith(filePath.filename().string(), Constants::HAP_SUFFIX)) {
218             LOGE("Packager::isOutPathValid out-path must end with .hap.");
219             return false;
220         } else {
221             return true;
222         }
223     } else if (suffix == Constants::HAR_SUFFIX) {
224         if (!Utils::EndsWith(filePath.filename().string(), Constants::HAR_SUFFIX)) {
225             LOGE("Packager::isOutPathValid out-path must end with .har.");
226             return false;
227         } else {
228             return true;
229         }
230     } else if (suffix == Constants::APP_SUFFIX) {
231         if (!Utils::EndsWith(filePath.filename().string(), Constants::APP_SUFFIX)) {
232             LOGE("Packager::isOutPathValid out-path must end with .app.");
233             return false;
234         } else {
235             return true;
236         }
237     } else if (suffix == Constants::RES_SUFFIX) {
238         if (!Utils::EndsWith(filePath.filename().string(), Constants::RES_SUFFIX)) {
239             LOGE("Packager::isOutPathValid out-path must end with .res.");
240             return false;
241         } else {
242             return true;
243         }
244     } else if (suffix == Constants::HSP_SUFFIX) {
245         if (!Utils::EndsWith(filePath.filename().string(), Constants::HSP_SUFFIX)) {
246             LOGE("Packager::isOutPathValid out-path must end with .hsp.");
247             return false;
248         } else {
249             return true;
250         }
251     }
252     return false;
253 }
254 
SetGenerateBuildHash(std::string & jsonPath,bool & generateBuildHash,bool & buildHashFinish)255 bool Packager::SetGenerateBuildHash(std::string &jsonPath, bool &generateBuildHash, bool &buildHashFinish)
256 {
257     if (!fs::exists(jsonPath)) {
258         LOGE("Packager::setGenerateBuildHash failed for json file not exist");
259         return false;
260     }
261     ModuleJson moduleJson;
262     moduleJson.ParseFromFile(jsonPath);
263 
264     if (buildHashFinish || !moduleJson.GetGenerateBuildHash(generateBuildHash)) {
265         return true;
266     }
267 
268     if (!CopyFileToTempDir(jsonPath)) {
269         return false;
270     }
271 
272     if (!fs::exists(jsonPath)) {
273         LOGE("Packager::setGenerateBuildHash failed for json file not exist");
274         return false;
275     }
276 
277     ModuleJson moduleJsonTemp;
278     moduleJsonTemp.ParseFromFile(jsonPath);
279     if (!moduleJsonTemp.GetGenerateBuildHash(generateBuildHash)) {
280         LOGE("ModuleJson::GetGenerateBuildHash failed");
281         return false;
282     }
283 
284     if (!moduleJsonTemp.RemoveGenerateBuildHash()) {
285         LOGE("ModuleJson::RemoveGenerateBuildHash failed");
286         return false;
287     }
288 
289     std::string prettyJsonString = moduleJsonTemp.ToString();
290     if (prettyJsonString.empty()) {
291         LOGE("ModuleJson::ToString failed");
292         return false;
293     }
294 
295     std::string realJsonPath;
296     if (!Utils::GetRealPath(jsonPath, realJsonPath)) {
297         LOGE("get real json Path failed! jsonPath=%s", jsonPath.c_str());
298         return false;
299     }
300     std::ofstream outFile(realJsonPath);
301     if (outFile.is_open()) {
302         outFile << prettyJsonString.c_str();
303         outFile.close();
304     } else {
305         LOGE("Failed to open file for writing");
306         return false;
307     }
308     return true;
309 }
310 
CopyFileToTempDir(std::string & jsonPath)311 bool Packager::CopyFileToTempDir(std::string &jsonPath)
312 {
313     if (!fs::exists(jsonPath)) {
314         LOGE("Packager::copyFileToTempDir failed for json file not found.");
315         return false;
316     }
317     fs::path oldFileParent = fs::path(jsonPath).parent_path();
318     std::string tempDir = Constants::COMPRESSOR_TEMP_DIR + fs::path::preferred_separator + Utils::GenerateUUID();
319     fs::path tempDirFs(tempDir);
320     tempDir = oldFileParent.string() + fs::path::preferred_separator + tempDirFs.string();
321     fs::create_directories(tempDir);
322     fs::path fileName = JsonUtils::IsModuleJson(jsonPath) ? Constants::MODULE_JSON : Constants::CONFIG_JSON;
323     std::string tempPath = tempDir + fs::path::preferred_separator + fileName.string();
324     if (!Utils::CopyFile(jsonPath, tempPath)) {
325         return false;
326     }
327     jsonPath = tempPath;
328     return true;
329 }
330 
BuildHash(bool & buildHashFinish,const bool & generateBuildHash,const std::map<std::string,std::string> & parameterMap,const std::string & jsonPath)331 bool Packager::BuildHash(bool &buildHashFinish, const bool &generateBuildHash,
332     const std::map<std::string, std::string> &parameterMap, const std::string &jsonPath)
333 {
334     if (buildHashFinish || !generateBuildHash) {
335         return true;
336     }
337     std::map<std::string, std::string>::const_iterator it = parameterMap.find(Constants::PARAM_OUT_PATH);
338     if (it == parameterMap.end()) {
339         LOGE("out-path not found");
340         return false;
341     }
342     std::string filePath = it->second;
343     std::string hash = Utils::GetSha256File(filePath);
344     return PutBuildHash(jsonPath, hash, buildHashFinish);
345 }
346 
PutBuildHash(const std::string & jsonPath,const std::string & hash,bool & buildHashFinish)347 bool Packager::PutBuildHash(const std::string &jsonPath, const std::string &hash, bool &buildHashFinish)
348 {
349     if (buildHashFinish) {
350         return true;
351     }
352 
353     ModuleJson moduleJson;
354     moduleJson.ParseFromFile(jsonPath);
355     moduleJson.SetBuildHash(hash);
356     std::string prettyJsonString = moduleJson.ToString();
357     if (prettyJsonString.empty()) {
358         LOGE("ModuleJson::ToString failed");
359         return false;
360     }
361 
362     std::string realJsonPath;
363     if (!Utils::GetRealPath(jsonPath, realJsonPath)) {
364         LOGE("get real json path failed! jsonFile=%s", jsonPath.c_str());
365         return false;
366     }
367     std::ofstream outFile(realJsonPath);
368     if (outFile.is_open()) {
369         outFile << prettyJsonString.c_str();
370         outFile.close();
371     } else {
372         LOGE("Failed to open file for writing");
373         return false;
374     }
375 
376     buildHashFinish = true;
377     return true;
378 }
379 
IsModuleHap(const std::string & hapPath)380 bool Packager::IsModuleHap(const std::string& hapPath)
381 {
382     if (!Utils::EndsWith(hapPath, Constants::HAP_SUFFIX)) {
383         return false;
384     }
385     if (!ZipUtils::IsFileExistsInZip(hapPath, Constants::MODULE_JSON)) {
386         return false;
387     }
388     return true;
389 }
390 
CompressPackinfoIntoHap(const std::string & hapPathItem,const std::string & unzipPathString,const std::string & outPathString,const std::string & packInfoPath)391 void Packager::CompressPackinfoIntoHap(const std::string& hapPathItem, const std::string& unzipPathString,
392     const std::string& outPathString, const std::string& packInfoPath)
393 {
394     if (!fs::exists(fs::path(unzipPathString))) {
395         fs::create_directory(fs::path(unzipPathString));
396     }
397     ZipUtils::Unzip(hapPathItem, unzipPathString);
398     for (const auto& entry : fs::directory_iterator(unzipPathString)) {
399         if (entry.path().filename() == Constants::PACK_INFO) {
400             fs::remove(entry.path());
401         }
402     }
403 
404     std::string realPackInfoPath;
405     if (!Utils::GetRealPath(packInfoPath, realPackInfoPath)) {
406         LOGE("get real pack info path failed! packInfoPath=%s", packInfoPath.c_str());
407         return;
408     }
409     std::string destFilePath = unzipPathString + fs::path::preferred_separator + Constants::PACK_INFO;
410     std::string realDestFilePath;
411     if (!Utils::GetRealPathOfNoneExistFile(destFilePath, realDestFilePath)) {
412         LOGE("get real dest file path failed! destFilePath=%s", destFilePath.c_str());
413         return;
414     }
415     std::ifstream packInfoFile(realPackInfoPath, std::ios::binary);
416     std::ofstream destFile(realDestFilePath, std::ios::binary | std::ios::trunc);
417     destFile << packInfoFile.rdbuf();
418     destFile.close();
419     packInfoFile.close();
420     ZipUtils::Zip(unzipPathString, outPathString);
421     if (fs::exists(fs::path(unzipPathString))) {
422         fs::remove_all(fs::path(unzipPathString));
423     }
424 }
425 
IsOutDirectoryValid()426 bool Packager::IsOutDirectoryValid()
427 {
428     auto it = parameterMap_.find(Constants::PARAM_OUT_PATH);
429     if (it == parameterMap_.end()) {
430         LOGE("Validate out-path is empty");
431         return false;
432     } else if (!Utils::IsDirectory(it->second)) {
433         LOGE("Validate out-path is not a directory.");
434         return false;
435     }
436     return true;
437 }
438 } // namespace AppPackingTool
439 } // namespace OHOS