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 "napi_common_utils.h"
17 
18 #include "accesstoken_kit.h"
19 #include "access_token.h"
20 #include "ipc_skeleton.h"
21 
22 #include "napi/native_common.h"
23 #include "node_api.h"
24 
25 #include "tokenid_kit.h"
26 #include "update_define.h"
27 
28 namespace OHOS::UpdateEngine {
29 constexpr int32_t STRING_MAX_LENGTH = 81920;
30 
GetInt32(napi_env env,napi_value arg,const std::string & attrName,int32_t & intValue)31 int32_t NapiCommonUtils::GetInt32(napi_env env, napi_value arg, const std::string &attrName, int32_t &intValue)
32 {
33     bool result = false;
34     napi_status status = napi_has_named_property(env, arg, attrName.c_str(), &result);
35     if (result && (status == napi_ok)) {
36         napi_value value = nullptr;
37         napi_get_named_property(env, arg, attrName.c_str(), &value);
38         napi_get_value_int32(env, value, &intValue);
39         return CAST_INT(ClientStatus::CLIENT_SUCCESS);
40     }
41     return CAST_INT(ClientStatus::CLIENT_FAIL);
42 }
43 
GetInt32(napi_env env,napi_value arg,int32_t & intValue)44 int32_t NapiCommonUtils::GetInt32(napi_env env, napi_value arg, int32_t &intValue)
45 {
46     napi_valuetype valueType;
47     napi_status status = napi_typeof(env, arg, &valueType);
48     PARAM_CHECK(status == napi_ok && valueType == napi_number,
49         return CAST_INT(ClientStatus::CLIENT_INVALID_TYPE), "invalid type");
50     napi_get_value_int32(env, arg, &intValue);
51     PARAM_CHECK(status == napi_ok, return CAST_INT(ClientStatus::CLIENT_INVALID_TYPE), "Error get GetInt32");
52     return CAST_INT(ClientStatus::CLIENT_SUCCESS);
53 }
54 
GetUInt32(napi_env env,napi_value arg,uint32_t & uintValue)55 int32_t NapiCommonUtils::GetUInt32(napi_env env, napi_value arg, uint32_t &uintValue)
56 {
57     napi_valuetype valueType;
58     napi_status status = napi_typeof(env, arg, &valueType);
59     PARAM_CHECK(status == napi_ok && valueType == napi_number,
60         return CAST_INT(ClientStatus::CLIENT_INVALID_TYPE), "invalid type");
61     napi_get_value_uint32(env, arg, &uintValue);
62     PARAM_CHECK(status == napi_ok, return CAST_INT(ClientStatus::CLIENT_INVALID_TYPE), "Error get GetUInt32");
63     return CAST_INT(ClientStatus::CLIENT_SUCCESS);
64 }
65 
GetBool(napi_env env,napi_value arg,const std::string & attrName,bool & value)66 int32_t NapiCommonUtils::GetBool(napi_env env, napi_value arg, const std::string &attrName, bool &value)
67 {
68     bool result = false;
69     napi_status status = napi_has_named_property(env, arg, attrName.c_str(), &result);
70     if (result && (status == napi_ok)) {
71         napi_value obj = nullptr;
72         napi_get_named_property(env, arg, attrName.c_str(), &obj);
73         napi_get_value_bool(env, obj, &value);
74         return CAST_INT(ClientStatus::CLIENT_SUCCESS);
75     }
76     return CAST_INT(ClientStatus::CLIENT_FAIL);
77 }
78 
GetString(napi_env env,napi_value arg,const std::string & attrName,std::string & strValue)79 int32_t NapiCommonUtils::GetString(napi_env env, napi_value arg, const std::string &attrName, std::string &strValue)
80 {
81     bool result = false;
82     napi_status status = napi_has_named_property(env, arg, attrName.c_str(), &result);
83     if (result && (status == napi_ok)) {
84         napi_value value = nullptr;
85         napi_get_named_property(env, arg, attrName.c_str(), &value);
86         return GetString(env, value, strValue);
87     }
88     return CAST_INT(ClientStatus::CLIENT_FAIL);
89 }
90 
GetString(napi_env env,napi_value arg,std::string & strValue)91 int32_t NapiCommonUtils::GetString(napi_env env, napi_value arg, std::string &strValue)
92 {
93     napi_valuetype valuetype;
94     napi_status status = napi_typeof(env, arg, &valuetype);
95     PARAM_CHECK(status == napi_ok, return CAST_INT(ClientStatus::CLIENT_FAIL), "Failed to napi_typeof");
96     PARAM_CHECK(valuetype == napi_string, return CAST_INT(ClientStatus::CLIENT_INVALID_TYPE), "Invalid type");
97 
98     std::vector<char> buff(STRING_MAX_LENGTH);
99     size_t copied;
100     status = napi_get_value_string_utf8(env, arg, static_cast<char*>(buff.data()), STRING_MAX_LENGTH, &copied);
101     PARAM_CHECK(status == napi_ok, return CAST_INT(ClientStatus::CLIENT_INVALID_TYPE), "Error get string");
102     strValue.assign(buff.data(), copied);
103     return CAST_INT(ClientStatus::CLIENT_SUCCESS);
104 }
105 
SetString(napi_env env,napi_value arg,const std::string & attrName,const std::string & string)106 int32_t NapiCommonUtils::SetString(napi_env env, napi_value arg, const std::string &attrName, const std::string &string)
107 {
108     napi_value value = nullptr;
109     napi_create_string_utf8(env, string.c_str(), string.length(), &value);
110     napi_set_named_property(env, arg, attrName.c_str(), value);
111     return CAST_INT(ClientStatus::CLIENT_SUCCESS);
112 }
113 
SetUint32(napi_env env,napi_value arg,const std::string & attrName,uint32_t intValue)114 int32_t NapiCommonUtils::SetUint32(napi_env env, napi_value arg, const std::string &attrName, uint32_t intValue)
115 {
116     napi_value infoStatus = nullptr;
117     napi_create_uint32(env, intValue, &infoStatus);
118     napi_set_named_property(env, arg, attrName.c_str(), infoStatus);
119     return CAST_INT(ClientStatus::CLIENT_SUCCESS);
120 }
121 
SetInt32(napi_env env,napi_value arg,const std::string & attrName,int32_t intValue)122 int32_t NapiCommonUtils::SetInt32(napi_env env, napi_value arg, const std::string &attrName, int32_t intValue)
123 {
124     napi_value infoStatus = nullptr;
125     napi_create_int32(env, intValue, &infoStatus);
126     napi_set_named_property(env, arg, attrName.c_str(), infoStatus);
127     return CAST_INT(ClientStatus::CLIENT_SUCCESS);
128 }
129 
SetInt64(napi_env env,napi_value arg,const std::string & attrName,int64_t intValue)130 int32_t NapiCommonUtils::SetInt64(napi_env env, napi_value arg, const std::string &attrName, int64_t intValue)
131 {
132     napi_value infoStatus = nullptr;
133     napi_create_int64(env, intValue, &infoStatus);
134     napi_set_named_property(env, arg, attrName.c_str(), infoStatus);
135     return CAST_INT(ClientStatus::CLIENT_SUCCESS);
136 }
137 
SetBool(napi_env env,napi_value arg,const std::string & attrName,bool value)138 int32_t NapiCommonUtils::SetBool(napi_env env, napi_value arg, const std::string &attrName, bool value)
139 {
140     napi_value infoStatus = nullptr;
141     napi_get_boolean(env, value, &infoStatus);
142     napi_set_named_property(env, arg, attrName.c_str(), infoStatus);
143     return CAST_INT(ClientStatus::CLIENT_SUCCESS);
144 }
145 
IsTypeOf(napi_env env,napi_value arg,napi_valuetype type)146 ClientStatus NapiCommonUtils::IsTypeOf(napi_env env, napi_value arg, napi_valuetype type)
147 {
148     napi_valuetype valueType;
149     napi_status status = napi_typeof(env, arg, &valueType);
150     PARAM_CHECK(status == napi_ok, return ClientStatus::CLIENT_FAIL, "Failed to napi_typeof");
151     PARAM_CHECK(valueType == type, return ClientStatus::CLIENT_INVALID_TYPE, "Not same napi type");
152     return ClientStatus::CLIENT_SUCCESS;
153 }
154 
CreateReference(napi_env env,napi_value arg,uint32_t refcount,napi_ref & reference)155 ClientStatus NapiCommonUtils::CreateReference(napi_env env, napi_value arg, uint32_t refcount, napi_ref &reference)
156 {
157     napi_status status = napi_create_reference(env, arg, refcount, &reference);
158     PARAM_CHECK(status == napi_ok, return ClientStatus::CLIENT_FAIL, "Failed to create reference");
159     return ClientStatus::CLIENT_SUCCESS;
160 }
161 
CreateUint32(napi_env env,uint32_t code)162 napi_value NapiCommonUtils::CreateUint32(napi_env env, uint32_t code)
163 {
164     napi_value value = nullptr;
165     if (napi_create_uint32(env, code, &value) != napi_ok) {
166         return nullptr;
167     }
168     return value;
169 }
170 
CreateStringUtf8(napi_env env,const std::string & str)171 napi_value NapiCommonUtils::CreateStringUtf8(napi_env env, const std::string &str)
172 {
173     napi_value value = nullptr;
174     if (napi_create_string_utf8(env, str.c_str(), strlen(str.c_str()), &value) != napi_ok) {
175         return nullptr;
176     }
177     return value;
178 }
179 
CreateProperty(napi_env env,napi_value exports,const std::string & name,const std::vector<std::pair<std::string,napi_value>> & properties)180 void NapiCommonUtils::CreateProperty(napi_env env, napi_value exports, const std::string &name,
181     const std::vector<std::pair<std::string, napi_value>> &properties)
182 {
183     napi_value object = nullptr;
184     napi_status status = napi_create_object(env, &object);
185     if (status != napi_ok) {
186         ENGINE_LOGE("CreateObject, napi_create_object fail");
187     }
188     if (object == nullptr) {
189         return;
190     }
191     size_t size = properties.size();
192     napi_property_descriptor descriptors[size];
193     for (size_t pos = 0; pos < size; pos++) {
194         if (properties[pos].first.empty()) {
195             continue;
196         }
197         descriptors[pos] = DECLARE_NAPI_STATIC_PROPERTY(properties[pos].first.c_str(), properties[pos].second);
198     }
199     status = napi_define_properties(env, object, size, descriptors);
200     if (status != napi_ok) {
201         ENGINE_LOGE("DefineProperties, napi_define_properties fail");
202     }
203 
204     status = napi_set_named_property(env, exports, name.c_str(), object);
205     if (status != napi_ok) {
206         ENGINE_LOGE("CreateProperty, napi_set_named_property fail");
207     }
208 }
209 
NapiThrowParamError(napi_env env,std::vector<std::pair<std::string,std::string>> & paramInfos)210 void NapiCommonUtils::NapiThrowParamError(
211     napi_env env, std::vector<std::pair<std::string, std::string>> &paramInfos)
212 {
213     BusinessError businessError;
214     CallResult errCode = CallResult::PARAM_ERR;
215     std::string errMsg = "BusinessError " + std::to_string(CAST_INT(errCode))
216         .append(": Parameter error. The type of { ").append(GetParamNames(paramInfos)).append(" }")
217         .append("must be { ").append(GetParamTypes(paramInfos)).append(" }.");
218     businessError.Build(errCode, errMsg);
219     napi_value msg = BuildThrowError(env, businessError);
220     napi_status status = napi_throw(env, msg);
221     PARAM_CHECK(status == napi_ok, return, "Failed to napi_throw %{public}d", CAST_INT(status));
222 }
223 
NapiThrowNotSystemAppError(napi_env env)224 void NapiCommonUtils::NapiThrowNotSystemAppError(napi_env env)
225 {
226     BusinessError businessError;
227     CallResult errCode = CallResult::NOT_SYSTEM_APP;
228     std::string errMsg = "BusinessError " + std::to_string(CAST_INT(errCode))
229         .append(": Permission verification failed. A non-system application calls a system API.");
230     businessError.Build(errCode, errMsg);
231     napi_value msg = BuildThrowError(env, businessError);
232     napi_status status = napi_throw(env, msg);
233     PARAM_CHECK(status == napi_ok, return, "Failed to napi_throw %{public}d", CAST_INT(status));
234 }
235 
NapiThrowPermissionError(napi_env env)236 void NapiCommonUtils::NapiThrowPermissionError(napi_env env)
237 {
238     BusinessError businessError;
239     CallResult errCode = CallResult::APP_NOT_GRANTED;
240     std::string errMsg = "BusinessError " + std::to_string(CAST_INT(errCode))
241         .append(": Permission not granted.");
242     businessError.Build(errCode, errMsg);
243     napi_value msg = BuildThrowError(env, businessError);
244     napi_status status = napi_throw(env, msg);
245     PARAM_CHECK(status == napi_ok, return, "Failed to napi_throw %{public}d", CAST_INT(status));
246 }
247 
IsPermissionGranted(const std::string & permission)248 bool NapiCommonUtils::IsPermissionGranted(const std::string &permission)
249 {
250     OHOS::Security::AccessToken::AccessTokenID callerToken = IPCSkeleton::GetCallingTokenID();
251     int verifyResult = Security::AccessToken::AccessTokenKit::VerifyAccessToken(callerToken, permission);
252     bool isPermissionGranted = verifyResult == Security::AccessToken::PERMISSION_GRANTED;
253     if (!isPermissionGranted) {
254         ENGINE_LOGE("permission %{public}s not granted", permission.c_str());
255     }
256     return isPermissionGranted;
257 }
258 
IsCallerValid()259 bool NapiCommonUtils::IsCallerValid()
260 {
261     OHOS::Security::AccessToken::AccessTokenID callerToken = IPCSkeleton::GetCallingTokenID();
262     auto callerTokenType = OHOS::Security::AccessToken::AccessTokenKit::GetTokenType(callerToken);
263     switch (callerTokenType) {
264         case OHOS::Security::AccessToken::TypeATokenTypeEnum::TOKEN_HAP: {
265             uint64_t callerFullTokenID = IPCSkeleton::GetCallingFullTokenID();
266             // hap进程只允许系统应用调用
267             return OHOS::Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(callerFullTokenID);
268         }
269         default:
270             // 其他情况调用予以禁止
271             return false;
272     }
273 }
274 
GetParamNames(std::vector<std::pair<std::string,std::string>> & strVector)275 std::string NapiCommonUtils::GetParamNames(std::vector<std::pair<std::string, std::string>> &strVector)
276 {
277     return ConvertVectorToStr(strVector, true);
278 }
279 
GetParamTypes(std::vector<std::pair<std::string,std::string>> & strVector)280 std::string NapiCommonUtils::GetParamTypes(std::vector<std::pair<std::string, std::string>> &strVector)
281 {
282     return ConvertVectorToStr(strVector, false);
283 }
284 
ConvertVectorToStr(std::vector<std::pair<std::string,std::string>> & strVector,bool isFirst)285 std::string NapiCommonUtils::ConvertVectorToStr(std::vector<std::pair<std::string, std::string>> &strVector,
286     bool isFirst)
287 {
288     std::string strValue;
289     for (auto &str : strVector) {
290         if (!strValue.empty()) {
291             strValue.append(", ");
292         }
293         if (isFirst) {
294             strValue.append(str.first);
295         } else {
296             strValue.append(str.second);
297         }
298     }
299     return strValue;
300 }
301 
BuildThrowError(napi_env env,const BusinessError & businessError)302 napi_value NapiCommonUtils::BuildThrowError(napi_env env, const BusinessError &businessError)
303 {
304     napi_value message = nullptr;
305     napi_create_string_utf8(env, businessError.message.c_str(), NAPI_AUTO_LENGTH, &message);
306     napi_value error = nullptr;
307     napi_status status = napi_create_error(env, nullptr, message, &error);
308     PARAM_CHECK(status == napi_ok, return nullptr, "Failed to create napi_create_object %{public}d",
309         CAST_INT(status));
310 
311     SetInt32(env, error, "code", ConvertToErrorCode(businessError.errorNum));
312     SetString(env, error, "message", businessError.message);
313     BuildErrorMessages(env, error, "data", businessError.data);
314     return error;
315 }
316 
BuildBusinessError(napi_env env,napi_value & obj,const BusinessError & businessError)317 int32_t NapiCommonUtils::BuildBusinessError(napi_env env, napi_value &obj, const BusinessError &businessError)
318 {
319     if (businessError.errorNum == CallResult::SUCCESS) {
320         // success, no need to set businessError
321         return CAST_INT(ClientStatus::CLIENT_SUCCESS);
322     }
323     napi_status status = napi_create_object(env, &obj);
324     PARAM_CHECK(status == napi_ok, return CAST_INT(ClientStatus::CLIENT_INVALID_TYPE),
325         "Failed to create napi_create_object %{public}d", CAST_INT(status));
326 
327     SetString(env, obj, "message", businessError.message);
328     SetInt32(env, obj, "code", ConvertToErrorCode(businessError.errorNum));
329     BuildErrorMessages(env, obj, "data", businessError.data);
330     return CAST_INT(ClientStatus::CLIENT_SUCCESS);
331 }
332 
ConvertToErrorCode(CallResult callResult)333 int32_t NapiCommonUtils::ConvertToErrorCode(CallResult callResult)
334 {
335     if (IsCommonError(callResult) || callResult == CallResult::SUCCESS) {
336         return CAST_INT(callResult);
337     } else {
338         return COMPONENT_ERR + CAST_INT(callResult);
339     }
340 }
341 
BuildCallFuncResult(napi_env env,const BusinessError & businessError)342 napi_value NapiCommonUtils::BuildCallFuncResult(napi_env env, const BusinessError &businessError)
343 {
344     napi_value obj;
345     napi_status status = napi_create_object(env, &obj);
346     PARAM_CHECK(status == napi_ok, return obj, "Failed to create napi_create_object %{public}d", CAST_INT(status));
347     napi_get_boolean(env, businessError.errorNum == CallResult::SUCCESS, &obj);
348     return obj;
349 }
350 
IsCommonError(CallResult callResult)351 bool NapiCommonUtils::IsCommonError(CallResult callResult)
352 {
353     return callResult == CallResult::UN_SUPPORT || callResult == CallResult::NOT_SYSTEM_APP ||
354         callResult == CallResult::APP_NOT_GRANTED || callResult == CallResult::PARAM_ERR;
355 }
356 
BuildErrorMessages(napi_env env,napi_value & obj,const std::string & name,const std::vector<ErrorMessage> & errorMessages)357 void NapiCommonUtils::BuildErrorMessages(napi_env env, napi_value &obj, const std::string &name,
358     const std::vector<ErrorMessage> &errorMessages)
359 {
360     size_t validErrorMsgCount = GetValidDataCount(errorMessages);
361     if (validErrorMsgCount == 0) {
362         return;
363     }
364 
365     napi_value napiErrorMessages;
366     napi_create_array_with_length(env, validErrorMsgCount, &napiErrorMessages);
367     size_t index = 0;
368     for (size_t i = 0; (i < errorMessages.size()) && (index < validErrorMsgCount); i++) {
369         if (errorMessages[i].errorCode != 0) {
370             napi_value napiErrorMessage;
371             napi_create_object(env, &napiErrorMessage);
372             SetInt32(env, napiErrorMessage, "errorCode", errorMessages[i].errorCode);
373             SetString(env, napiErrorMessage, "errorMessage", errorMessages[i].errorMessage);
374             napi_set_element(env, napiErrorMessages, index, napiErrorMessage);
375             index++;
376         }
377     }
378     napi_set_named_property(env, obj, name.c_str(), napiErrorMessages);
379 }
380 
GetValidDataCount(const std::vector<ErrorMessage> & list)381 size_t NapiCommonUtils::GetValidDataCount(const std::vector<ErrorMessage> &list)
382 {
383     size_t validDataCount = 0;
384     for (const auto &errorMessage : list) {
385         if (errorMessage.errorCode != 0) {
386             validDataCount++;
387         }
388     }
389     return validDataCount;
390 }
391 
CheckNapiObjectType(napi_env env,const napi_value & arg)392 ClientStatus NapiCommonUtils::CheckNapiObjectType(napi_env env, const napi_value &arg)
393 {
394     napi_valuetype type = napi_undefined;
395     napi_status status = napi_typeof(env, arg, &type);
396     PARAM_CHECK(status == napi_ok, return ClientStatus::CLIENT_INVALID_TYPE, "Invalid argc %{public}d",
397         static_cast<int32_t>(status));
398     PARAM_CHECK(type == napi_object, return ClientStatus::CLIENT_INVALID_TYPE, "Invalid argc %{public}d",
399         static_cast<int32_t>(type))
400     return ClientStatus::CLIENT_SUCCESS;
401 }
402 } // namespace OHOS::UpdateEngine