1 /*
2  * Copyright (c) 2021-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 "bundle_parser.h"
17 
18 #include <fstream>
19 #include <sstream>
20 
21 #include "bundle_profile.h"
22 #include "default_permission_profile.h"
23 #include "module_profile.h"
24 #include "pre_bundle_profile.h"
25 #include "rpcid_decode/syscap_tool.h"
26 #include "securec.h"
27 
28 namespace OHOS {
29 namespace AppExecFwk {
30 namespace {
31 const std::string INSTALL_ABILITY_CONFIGS = "install_ability_configs";
32 constexpr const char* BUNDLE_PACKFILE_NAME = "pack.info";
33 constexpr const char* SYSCAP_NAME = "rpcid.sc";
34 static const std::string ROUTER_MAP = "routerMap";
35 static const std::string ROUTER_MAP_DATA = "data";
36 static const std::string ROUTER_ITEM_KEY_CUSTOM_DATA = "customData";
37 static const size_t DATA_MAX_LENGTH = 4096;
38 const char* NO_DISABLING_CONFIG_KEY = "residentProcessInExtremeMemory";
39 const char* NO_DISABLING_KEY_BUNDLE_NAME = "bundleName";
40 
ParseStr(const char * buf,const int itemLen,int totalLen,std::vector<std::string> & sysCaps)41 bool ParseStr(const char *buf, const int itemLen, int totalLen, std::vector<std::string> &sysCaps)
42 {
43     APP_LOGD("Parse rpcid output start, itemLen:%{public}d  totalLen:%{public}d", itemLen, totalLen);
44     if (buf == nullptr || itemLen <= 0 || totalLen <= 0) {
45         APP_LOGE("param invalid");
46         return false;
47     }
48 
49     int index = 0;
50     while (index + itemLen <= totalLen) {
51         char item[itemLen];
52         if (strncpy_s(item, sizeof(item), buf + index, itemLen) != 0) {
53             APP_LOGE("Parse rpcid failed due to strncpy_s error");
54             return false;
55         }
56 
57         sysCaps.emplace_back((std::string)item, 0, itemLen);
58         index += itemLen;
59     }
60 
61     return true;
62 }
63 } // namespace
64 
ReadFileIntoJson(const std::string & filePath,nlohmann::json & jsonBuf)65 bool BundleParser::ReadFileIntoJson(const std::string &filePath, nlohmann::json &jsonBuf)
66 {
67     if (access(filePath.c_str(), F_OK) != 0) {
68         APP_LOGD("access file %{public}s failed, error: %{public}s", filePath.c_str(), strerror(errno));
69         return false;
70     }
71 
72     std::fstream in;
73     char errBuf[256];
74     errBuf[0] = '\0';
75     in.open(filePath, std::ios_base::in);
76     if (!in.is_open()) {
77         strerror_r(errno, errBuf, sizeof(errBuf));
78         APP_LOGE("file open failed due to %{public}s, errno:%{public}d", errBuf, errno);
79         return false;
80     }
81 
82     in.seekg(0, std::ios::end);
83     int64_t size = in.tellg();
84     if (size <= 0) {
85         APP_LOGE("file empty, errno:%{public}d", errno);
86         in.close();
87         return false;
88     }
89 
90     in.seekg(0, std::ios::beg);
91     jsonBuf = nlohmann::json::parse(in, nullptr, false);
92     in.close();
93     if (jsonBuf.is_discarded()) {
94         APP_LOGE("bad profile file");
95         return false;
96     }
97 
98     return true;
99 }
100 
Parse(const std::string & pathName,InnerBundleInfo & innerBundleInfo) const101 ErrCode BundleParser::Parse(
102     const std::string &pathName,
103     InnerBundleInfo &innerBundleInfo) const
104 {
105     APP_LOGD("parse from %{private}s", pathName.c_str());
106     BundleExtractor bundleExtractor(pathName);
107     if (!bundleExtractor.Init()) {
108         APP_LOGE("bundle extractor init failed");
109         return ERR_APPEXECFWK_PARSE_UNEXPECTED;
110     }
111 
112     // to extract config.json
113     std::ostringstream outStream;
114     if (!bundleExtractor.ExtractProfile(outStream)) {
115         APP_LOGE("extract profile file failed");
116         return ERR_APPEXECFWK_PARSE_NO_PROFILE;
117     }
118 
119     if (bundleExtractor.IsNewVersion()) {
120         APP_LOGD("module.json transform to InnerBundleInfo");
121         innerBundleInfo.SetIsNewVersion(true);
122         ModuleProfile moduleProfile;
123         return moduleProfile.TransformTo(
124             outStream, bundleExtractor, innerBundleInfo);
125     }
126     APP_LOGD("config.json transform to InnerBundleInfo");
127     innerBundleInfo.SetIsNewVersion(false);
128     BundleProfile bundleProfile;
129     ErrCode ret = bundleProfile.TransformTo(
130         outStream, bundleExtractor, innerBundleInfo);
131     if (ret != ERR_OK) {
132         APP_LOGE("transform stream to innerBundleInfo failed %{public}d", ret);
133         return ret;
134     }
135     auto& abilityInfos = innerBundleInfo.FetchAbilityInfos();
136     for (auto& info : abilityInfos) {
137         info.second.isStageBasedModel = bundleExtractor.IsStageBasedModel(info.second.name);
138         auto iter = innerBundleInfo.FetchInnerModuleInfos().find(info.second.package);
139         if (iter != innerBundleInfo.FetchInnerModuleInfos().end()) {
140             iter->second.isStageBasedModel = info.second.isStageBasedModel;
141         }
142     }
143 
144     return ERR_OK;
145 }
146 
ParsePackInfo(const std::string & pathName,BundlePackInfo & bundlePackInfo) const147 ErrCode BundleParser::ParsePackInfo(const std::string &pathName, BundlePackInfo &bundlePackInfo) const
148 {
149     APP_LOGD("parse from %{private}s", pathName.c_str());
150     BundleExtractor bundleExtractor(pathName);
151     if (!bundleExtractor.Init()) {
152         APP_LOGE("bundle extractor init failed");
153         return ERR_APPEXECFWK_PARSE_UNEXPECTED;
154     }
155 
156     // to extract pack.info
157     if (!bundleExtractor.HasEntry(BUNDLE_PACKFILE_NAME)) {
158         APP_LOGW("cannot find pack.info in the hap file");
159         return ERR_OK;
160     }
161     std::ostringstream outStreamForPackInfo;
162     if (!bundleExtractor.ExtractPackFile(outStreamForPackInfo)) {
163         APP_LOGE("extract profile file failed");
164         return ERR_APPEXECFWK_PARSE_NO_PROFILE;
165     }
166     BundleProfile bundleProfile;
167     ErrCode ret = bundleProfile.TransformTo(outStreamForPackInfo, bundlePackInfo);
168     if (ret != ERR_OK) {
169         APP_LOGE("transform stream to bundlePackinfo failed %{public}d", ret);
170         return ret;
171     }
172     return ERR_OK;
173 }
174 
ParseSysCap(const std::string & pathName,std::vector<std::string> & sysCaps) const175 ErrCode BundleParser::ParseSysCap(const std::string &pathName, std::vector<std::string> &sysCaps) const
176 {
177     APP_LOGD("Parse sysCaps from %{private}s", pathName.c_str());
178     BundleExtractor bundleExtractor(pathName);
179     if (!bundleExtractor.Init()) {
180         APP_LOGE("Bundle extractor init failed");
181         return ERR_APPEXECFWK_PARSE_UNEXPECTED;
182     }
183 
184     if (!bundleExtractor.HasEntry(SYSCAP_NAME)) {
185         APP_LOGD("Rpcid.sc is not exist, and do not need verification sysCaps");
186         return ERR_OK;
187     }
188 
189     std::stringstream rpcidStream;
190     if (!bundleExtractor.ExtractByName(SYSCAP_NAME, rpcidStream)) {
191         APP_LOGE("Extract rpcid file failed");
192         return ERR_APPEXECFWK_PARSE_RPCID_FAILED;
193     }
194 
195     int32_t rpcidLen = rpcidStream.tellp();
196     if (rpcidLen < 0) {
197         return ERR_APPEXECFWK_PARSE_UNEXPECTED;
198     }
199     char rpcidBuf[rpcidLen];
200     rpcidStream.read(rpcidBuf, rpcidLen);
201     uint32_t outLen;
202     char *outBuffer;
203     int result = RPCIDStreamDecodeToBuffer(rpcidBuf, rpcidLen, &outBuffer, &outLen);
204     if (result != 0) {
205         APP_LOGE("Decode syscaps failed");
206         return ERR_APPEXECFWK_PARSE_RPCID_FAILED;
207     }
208 
209     if (!ParseStr(outBuffer, SINGLE_SYSCAP_LENGTH, outLen, sysCaps)) {
210         APP_LOGE("Parse syscaps str failed");
211         free(outBuffer);
212         return ERR_APPEXECFWK_PARSE_RPCID_FAILED;
213     }
214 
215     APP_LOGD("Parse sysCaps str success");
216     free(outBuffer);
217     return ERR_OK;
218 }
219 
ParsePreInstallConfig(const std::string & configFile,std::set<PreScanInfo> & scanInfos) const220 ErrCode BundleParser::ParsePreInstallConfig(
221     const std::string &configFile, std::set<PreScanInfo> &scanInfos) const
222 {
223     APP_LOGD("Parse preInstallConfig from %{public}s", configFile.c_str());
224     nlohmann::json jsonBuf;
225     if (!ReadFileIntoJson(configFile, jsonBuf)) {
226         return ERR_APPEXECFWK_PARSE_FILE_FAILED;
227     }
228 
229     PreBundleProfile preBundleProfile;
230     return preBundleProfile.TransformTo(jsonBuf, scanInfos);
231 }
232 
ParsePreUnInstallConfig(const std::string & configFile,std::set<std::string> & uninstallList) const233 ErrCode BundleParser::ParsePreUnInstallConfig(
234     const std::string &configFile,
235     std::set<std::string> &uninstallList) const
236 {
237     APP_LOGD("Parse PreUnInstallConfig from %{public}s", configFile.c_str());
238     nlohmann::json jsonBuf;
239     if (!ReadFileIntoJson(configFile, jsonBuf)) {
240         return ERR_APPEXECFWK_PARSE_FILE_FAILED;
241     }
242 
243     PreBundleProfile preBundleProfile;
244     return preBundleProfile.TransformTo(jsonBuf, uninstallList);
245 }
246 
ParsePreInstallAbilityConfig(const std::string & configFile,std::set<PreBundleConfigInfo> & preBundleConfigInfos) const247 ErrCode BundleParser::ParsePreInstallAbilityConfig(
248     const std::string &configFile, std::set<PreBundleConfigInfo> &preBundleConfigInfos) const
249 {
250     APP_LOGD("Parse PreInstallAbilityConfig from %{public}s", configFile.c_str());
251     nlohmann::json jsonBuf;
252     if (!ReadFileIntoJson(configFile, jsonBuf)) {
253         return ERR_APPEXECFWK_PARSE_FILE_FAILED;
254     }
255 
256     PreBundleProfile preBundleProfile;
257     return preBundleProfile.TransformTo(jsonBuf, preBundleConfigInfos);
258 }
259 
ParseDefaultPermission(const std::string & permissionFile,std::set<DefaultPermission> & defaultPermissions) const260 ErrCode BundleParser::ParseDefaultPermission(
261     const std::string &permissionFile, std::set<DefaultPermission> &defaultPermissions) const
262 {
263     APP_LOGD("Parse DefaultPermission from %{private}s", permissionFile.c_str());
264     nlohmann::json jsonBuf;
265     if (!ReadFileIntoJson(permissionFile, jsonBuf)) {
266         return ERR_APPEXECFWK_PARSE_FILE_FAILED;
267     }
268 
269     DefaultPermissionProfile profile;
270     return profile.TransformTo(jsonBuf, defaultPermissions);
271 }
272 
ParseExtTypeConfig(const std::string & configFile,std::set<std::string> & extensionTypeList) const273 ErrCode BundleParser::ParseExtTypeConfig(
274     const std::string &configFile, std::set<std::string> &extensionTypeList) const
275 {
276     nlohmann::json jsonBuf;
277     if (!ReadFileIntoJson(configFile, jsonBuf)) {
278         return ERR_APPEXECFWK_PARSE_FILE_FAILED;
279     }
280 
281     PreBundleProfile preBundleProfile;
282     return preBundleProfile.TransformJsonToExtensionTypeList(jsonBuf, extensionTypeList);
283 }
284 
CheckRouterData(nlohmann::json data) const285 bool BundleParser::CheckRouterData(nlohmann::json data) const
286 {
287     if (data.find(ROUTER_MAP_DATA) == data.end()) {
288         APP_LOGW("data is not existed");
289         return false;
290     }
291     if (!data.at(ROUTER_MAP_DATA).is_object()) {
292         APP_LOGW("data is not a json object");
293         return false;
294     }
295     for (nlohmann::json::iterator kt = data.at(ROUTER_MAP_DATA).begin(); kt != data.at(ROUTER_MAP_DATA).end(); ++kt) {
296         // check every value is string
297         if (!kt.value().is_string()) {
298             APP_LOGW("Error: Value in data object for key %{public}s must be a string", kt.key().c_str());
299             return false;
300         }
301     }
302     return true;
303 }
304 
ParseRouterArray(const std::string & jsonString,std::vector<RouterItem> & routerArray) const305 ErrCode BundleParser::ParseRouterArray(
306     const std::string &jsonString, std::vector<RouterItem> &routerArray) const
307 {
308     if (jsonString.empty()) {
309         APP_LOGE("jsonString is empty");
310         return ERR_APPEXECFWK_PARSE_NO_PROFILE;
311     }
312     APP_LOGD("Parse RouterItem from %{private}s", jsonString.c_str());
313     nlohmann::json jsonBuf = nlohmann::json::parse(jsonString, nullptr, false);
314     if (jsonBuf.is_discarded()) {
315         APP_LOGE("json file %{private}s discarded", jsonString.c_str());
316         return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
317     }
318     if (jsonBuf.find(ROUTER_MAP) == jsonBuf.end()) {
319         APP_LOGE("routerMap no exist");
320         return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
321     }
322     nlohmann::json routerJson = jsonBuf.at(ROUTER_MAP);
323     if (!routerJson.is_array()) {
324         APP_LOGE("json under routerMap is not a json array");
325         return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
326     }
327 
328     for (const auto &object : routerJson) {
329         if (!object.is_object()) {
330             return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
331         }
332         RouterItem routerItem;
333         if (object.count(ROUTER_MAP_DATA) > 0 && !CheckRouterData(object)) {
334             APP_LOGW("check data type failed");
335             continue;
336         }
337         from_json(object, routerItem);
338         if (object.find(ROUTER_ITEM_KEY_CUSTOM_DATA) != object.end()) {
339             if (object[ROUTER_ITEM_KEY_CUSTOM_DATA].dump().size() <= DATA_MAX_LENGTH) {
340                 routerItem.customData = object[ROUTER_ITEM_KEY_CUSTOM_DATA].dump();
341             } else {
342                 APP_LOGE("customData in routerMap profile is too long");
343             }
344         }
345         routerArray.emplace_back(routerItem);
346     }
347     return ERR_OK;
348 }
349 
ParseNoDisablingList(const std::string & configPath,std::vector<std::string> & noDisablingList)350 ErrCode BundleParser::ParseNoDisablingList(const std::string &configPath, std::vector<std::string> &noDisablingList)
351 {
352     nlohmann::json object;
353     if (!ReadFileIntoJson(configPath, object)) {
354         return ERR_APPEXECFWK_INSTALL_FAILED_PROFILE_PARSE_FAIL;
355     }
356     if (!object.contains(NO_DISABLING_CONFIG_KEY) || !object.at(NO_DISABLING_CONFIG_KEY).is_array()) {
357         APP_LOGE("no disabling config not existed");
358         return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
359     }
360     for (auto &item : object.at(NO_DISABLING_CONFIG_KEY).items()) {
361         const nlohmann::json& jsonObject = item.value();
362         if (jsonObject.contains(NO_DISABLING_KEY_BUNDLE_NAME) &&
363             jsonObject.at(NO_DISABLING_KEY_BUNDLE_NAME).is_string()) {
364             std::string bundleName = jsonObject.at(NO_DISABLING_KEY_BUNDLE_NAME).get<std::string>();
365             noDisablingList.emplace_back(bundleName);
366         }
367     }
368     return ERR_OK;
369 }
370 }  // namespace AppExecFwk
371 }  // namespace OHOS
372