1 /*
2 * Copyright (c) 2022 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_account_common.h"
17
18 #include "account_log_wrapper.h"
19 #include "js_native_api.h"
20 #include "js_native_api_types.h"
21 #include "napi_account_error.h"
22 #include "napi/native_api.h"
23 #include "napi/native_common.h"
24 #include "napi/native_node_api.h"
25 #include "securec.h"
26
27 namespace OHOS {
28 namespace AccountJsKit {
29 namespace {
30 constexpr int32_t BUSINESS_ERROR_ARG_SIZE = 2;
31 }
32
33 using namespace AccountSA;
34
ProcessCallbackOrPromise(napi_env env,const CommonAsyncContext * asyncContext,napi_value err,napi_value data)35 void ProcessCallbackOrPromise(napi_env env, const CommonAsyncContext *asyncContext, napi_value err, napi_value data)
36 {
37 napi_value args[BUSINESS_ERROR_ARG_SIZE] = {0};
38 if (asyncContext->errCode == ERR_OK) {
39 napi_get_null(env, &args[0]);
40 args[1] = data;
41 } else {
42 napi_get_null(env, &args[1]);
43 args[0] = err;
44 }
45 if (asyncContext->deferred) {
46 if (asyncContext->errCode == ERR_OK) {
47 napi_resolve_deferred(env, asyncContext->deferred, args[1]);
48 } else {
49 napi_reject_deferred(env, asyncContext->deferred, args[0]);
50 }
51 } else {
52 napi_value callback = nullptr;
53 napi_get_reference_value(env, asyncContext->callbackRef, &callback);
54 napi_value returnVal = nullptr;
55 napi_call_function(env, nullptr, callback, BUSINESS_ERROR_ARG_SIZE, &args[0], &returnVal);
56 if (asyncContext->callbackRef != nullptr) {
57 napi_delete_reference(env, asyncContext->callbackRef);
58 }
59 }
60 }
61
NapiCallVoidFunction(napi_env env,napi_value * argv,size_t argc,napi_ref funcRef)62 void NapiCallVoidFunction(napi_env env, napi_value *argv, size_t argc, napi_ref funcRef)
63 {
64 napi_value undefined = nullptr;
65 NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined));
66 napi_value returnVal;
67 napi_value func = nullptr;
68 NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, funcRef, &func));
69 napi_call_function(env, undefined, func, argc, argv, &returnVal);
70 }
71
InitUvWorkCallbackEnv(uv_work_t * work,napi_handle_scope & scope)72 bool InitUvWorkCallbackEnv(uv_work_t *work, napi_handle_scope &scope)
73 {
74 if (work == nullptr) {
75 ACCOUNT_LOGE("work is nullptr");
76 return false;
77 }
78 if (work->data == nullptr) {
79 ACCOUNT_LOGE("data is nullptr");
80 return false;
81 }
82 CommonAsyncContext *data = reinterpret_cast<CommonAsyncContext *>(work->data);
83 napi_open_handle_scope(data->env, &scope);
84 if (scope == nullptr) {
85 ACCOUNT_LOGE("fail to open scope");
86 return false;
87 }
88 return true;
89 }
90
ReleaseNapiRefAsync(napi_env env,napi_ref napiRef)91 void ReleaseNapiRefAsync(napi_env env, napi_ref napiRef)
92 {
93 ReleaseNapiRefArray(env, {napiRef});
94 }
95
ReleaseNapiRefArray(napi_env env,const std::vector<napi_ref> & napiRefVec)96 void ReleaseNapiRefArray(napi_env env, const std::vector<napi_ref> &napiRefVec)
97 {
98 if (env == nullptr) {
99 ACCOUNT_LOGE("invalid env");
100 return;
101 }
102 std::unique_ptr<uv_work_t> work = std::make_unique<uv_work_t>();
103 std::unique_ptr<NapiRefArrayContext> context = std::make_unique<NapiRefArrayContext>();
104 uv_loop_s *loop = nullptr;
105 napi_get_uv_event_loop(env, &loop);
106 if ((loop == nullptr) || (work == nullptr) || (context == nullptr)) {
107 ACCOUNT_LOGE("fail to init execution environment");
108 return;
109 }
110 context->env = env;
111 context->napiRefVec = napiRefVec;
112 work->data = reinterpret_cast<void *>(context.get());
113 NAPI_CALL_RETURN_VOID(env, uv_queue_work(loop, work.get(), [] (uv_work_t *work) {},
114 [] (uv_work_t *work, int status) {
115 if (work == nullptr) {
116 ACCOUNT_LOGE("work is nullptr");
117 return;
118 }
119 auto context = reinterpret_cast<NapiRefArrayContext *>(work->data);
120 if (context == nullptr) {
121 ACCOUNT_LOGE("context is nullptr");
122 delete work;
123 return;
124 }
125 for (auto &napiRef : context->napiRefVec) {
126 if (napiRef != nullptr) {
127 napi_delete_reference(context->env, napiRef);
128 }
129 }
130 delete context;
131 delete work;
132 }));
133 context.release();
134 work.release();
135 }
136
GetIntProperty(napi_env env,napi_value obj,int32_t & property)137 bool GetIntProperty(napi_env env, napi_value obj, int32_t &property)
138 {
139 napi_valuetype valueType = napi_undefined;
140 NAPI_CALL_BASE(env, napi_typeof(env, obj, &valueType), false);
141 if (valueType != napi_number) {
142 return false;
143 }
144
145 NAPI_CALL_BASE(env, napi_get_value_int32(env, obj, &property), false);
146 return true;
147 }
148
GetLongIntProperty(napi_env env,napi_value obj,int64_t & property)149 bool GetLongIntProperty(napi_env env, napi_value obj, int64_t &property)
150 {
151 napi_valuetype valueType = napi_undefined;
152 NAPI_CALL_BASE(env, napi_typeof(env, obj, &valueType), false);
153 if (valueType != napi_number) {
154 return false;
155 }
156
157 NAPI_CALL_BASE(env, napi_get_value_int64(env, obj, &property), false);
158 return true;
159 }
160
GetBoolProperty(napi_env env,napi_value obj,bool & property)161 bool GetBoolProperty(napi_env env, napi_value obj, bool &property)
162 {
163 napi_valuetype valueType = napi_undefined;
164 NAPI_CALL_BASE(env, napi_typeof(env, obj, &valueType), false);
165 if (valueType != napi_boolean) {
166 return false;
167 }
168 NAPI_CALL_BASE(env, napi_get_value_bool(env, obj, &property), false);
169 return true;
170 }
171
GetStringProperty(napi_env env,napi_value obj,std::string & property)172 bool GetStringProperty(napi_env env, napi_value obj, std::string &property)
173 {
174 napi_valuetype valuetype = napi_undefined;
175 NAPI_CALL_BASE(env, napi_typeof(env, obj, &valuetype), false);
176 if (valuetype != napi_string) {
177 return false;
178 }
179
180 size_t propLen;
181 NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, obj, nullptr, 0, &propLen), false);
182 property.reserve(propLen + 1);
183 property.resize(propLen);
184 NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, obj, property.data(), propLen + 1, &propLen), false);
185 return true;
186 }
187
GetStringArrayProperty(napi_env env,napi_value obj,std::vector<std::string> & property,bool allowEmpty)188 bool GetStringArrayProperty(napi_env env, napi_value obj, std::vector<std::string> &property, bool allowEmpty)
189 {
190 bool isArray = false;
191 NAPI_CALL_BASE(env, napi_is_array(env, obj, &isArray), false);
192 if (!isArray) {
193 return false;
194 }
195 uint32_t length = 0;
196 NAPI_CALL_BASE(env, napi_get_array_length(env, obj, &length), false);
197 if (!allowEmpty && (length == 0)) {
198 return false;
199 }
200
201 for (size_t i = 0; i < length; i++) {
202 napi_value strJs = nullptr;
203 NAPI_CALL_BASE(env, napi_get_element(env, obj, i, &strJs), false);
204 std::string str;
205 if (!GetStringProperty(env, strJs, str)) {
206 return false;
207 }
208 property.emplace_back(str);
209 }
210 return true;
211 }
212
GetCallbackProperty(napi_env env,napi_value obj,napi_ref & property,int argNum)213 bool GetCallbackProperty(napi_env env, napi_value obj, napi_ref &property, int argNum)
214 {
215 napi_valuetype valueType = napi_undefined;
216 NAPI_CALL_BASE(env, napi_typeof(env, obj, &valueType), false);
217 if (valueType != napi_function) {
218 return false;
219 }
220 NAPI_CALL_BASE(env, napi_create_reference(env, obj, argNum, &property), false);
221 return true;
222 }
223
GetStringPropertyByKey(napi_env env,napi_value obj,const std::string & propertyName,std::string & property)224 bool GetStringPropertyByKey(napi_env env, napi_value obj, const std::string &propertyName, std::string &property)
225 {
226 napi_value value = nullptr;
227 NAPI_CALL_BASE(env, napi_get_named_property(env, obj, propertyName.c_str(), &value), false);
228
229 return GetStringProperty(env, value, property);
230 }
231
GetOptionalStringPropertyByKey(napi_env env,napi_value obj,const std::string & propertyName,std::string & property)232 bool GetOptionalStringPropertyByKey(napi_env env, napi_value obj, const std::string &propertyName,
233 std::string &property)
234 {
235 bool hasProp = false;
236 napi_has_named_property(env, obj, propertyName.c_str(), &hasProp);
237 if (!hasProp) {
238 return true;
239 }
240
241 return GetStringPropertyByKey(env, obj, propertyName, property);
242 }
243
CreateStringArray(napi_env env,const std::vector<std::string> & strVec)244 napi_value CreateStringArray(napi_env env, const std::vector<std::string> &strVec)
245 {
246 napi_value result = nullptr;
247 napi_create_array(env, &result);
248 for (size_t i = 0; i < strVec.size(); ++i) {
249 napi_value value = nullptr;
250 napi_create_string_utf8(env, strVec[i].c_str(), NAPI_AUTO_LENGTH, &value);
251 napi_set_element(env, result, i, value);
252 }
253 return result;
254 }
255
CreateUint8Array(napi_env env,const uint8_t * srcData,size_t length)256 napi_value CreateUint8Array(napi_env env, const uint8_t *srcData, size_t length)
257 {
258 napi_value result = nullptr;
259 void* dstData = nullptr;
260 napi_value napiArr = nullptr;
261 NAPI_CALL(env, napi_create_arraybuffer(env, length, &dstData, &napiArr));
262 if ((length > 0) && (memcpy_s(dstData, length, srcData, length) != EOK)) {
263 return result;
264 }
265 NAPI_CALL(env, napi_create_typedarray(env, napi_uint8_array, length, napiArr, 0, &result));
266 return result;
267 }
268
ParseUint8TypedArray(napi_env env,napi_value value,uint8_t ** data,size_t * length)269 napi_status ParseUint8TypedArray(napi_env env, napi_value value, uint8_t **data, size_t *length)
270 {
271 *data = nullptr;
272 *length = 0;
273 bool isTypedArray = false;
274 napi_is_typedarray(env, value, &isTypedArray);
275 if (!isTypedArray) {
276 ACCOUNT_LOGE("invalid uint8 array");
277 return napi_ok;
278 }
279 napi_typedarray_type arrayType;
280 napi_value buffer = nullptr;
281 size_t offset = 0;
282 napi_get_typedarray_info(env, value, &arrayType, length, reinterpret_cast<void **>(data), &buffer, &offset);
283 if (arrayType != napi_uint8_array) {
284 ACCOUNT_LOGE("invalid uint8 array");
285 *data = nullptr;
286 *length = 0;
287 }
288 return napi_ok;
289 }
290
ParseUint8TypedArrayToVector(napi_env env,napi_value value,std::vector<uint8_t> & vec)291 napi_status ParseUint8TypedArrayToVector(napi_env env, napi_value value, std::vector<uint8_t> &vec)
292 {
293 uint8_t *data = nullptr;
294 size_t length = 0;
295 napi_status status = ParseUint8TypedArray(env, value, &data, &length);
296 if (status != napi_ok) {
297 ACCOUNT_LOGE("failed to ParseUint8TypedArray");
298 return status;
299 }
300 vec.assign(data, data + length);
301 return napi_ok;
302 }
303
ParseUint8TypedArrayToUint64(napi_env env,napi_value value,uint64_t & result)304 napi_status ParseUint8TypedArrayToUint64(napi_env env, napi_value value, uint64_t &result)
305 {
306 uint8_t *data = nullptr;
307 size_t length = 0;
308 napi_status status = ParseUint8TypedArray(env, value, &data, &length);
309 if (status != napi_ok) {
310 ACCOUNT_LOGE("failed to ParseUint8TypedArray");
311 return status;
312 }
313 if (data == nullptr) {
314 result = 0;
315 return napi_invalid_arg;
316 }
317 if (length != sizeof(uint64_t)) {
318 ACCOUNT_LOGE("failed to convert to uint64_t value");
319 return napi_invalid_arg;
320 }
321 result = *(reinterpret_cast<uint64_t *>(data));
322 return napi_ok;
323 }
324 } // namespace AccountJsKit
325 } // namespace OHOS