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>> ¶mInfos)
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