• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 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 #include "ipc_skeleton.h"
16 #include "napi_account_common.h"
17 
18 #include "account_log_wrapper.h"
19 #include "ipc_skeleton.h"
20 #include "js_native_api.h"
21 #include "js_native_api_types.h"
22 #include "napi_account_error.h"
23 #include "napi/native_api.h"
24 #include "napi/native_common.h"
25 #include "napi/native_node_api.h"
26 #include "securec.h"
27 #include "tokenid_kit.h"
28 
29 namespace OHOS {
30 namespace AccountJsKit {
31 namespace {
32 constexpr int32_t BUSINESS_ERROR_ARG_SIZE = 2;
33 const char BUSINESS_ERROR_CODE_NAME[] = "code";
34 const char BUSINESS_ERROR_DATA_NAME[] = "data";
35 }
36 
37 using namespace AccountSA;
38 
~CommonAsyncContext()39 CommonAsyncContext::~CommonAsyncContext()
40 {
41     if (env == nullptr) {
42         return;
43     }
44     if (callbackRef != nullptr) {
45         napi_delete_reference(env, callbackRef);
46         callbackRef = nullptr;
47     }
48     if (work != nullptr) {
49         napi_delete_async_work(env, work);
50         work = nullptr;
51     }
52 }
53 
CreateExecEnv(napi_env env,uv_loop_s ** loop,uv_work_t ** work)54 bool CreateExecEnv(napi_env env, uv_loop_s **loop, uv_work_t **work)
55 {
56     *loop = nullptr;
57     napi_get_uv_event_loop(env, loop);
58     if (*loop == nullptr) {
59         ACCOUNT_LOGE("failed to get uv event loop");
60         return false;
61     }
62     *work = new (std::nothrow) uv_work_t;
63     if (*work == nullptr) {
64         ACCOUNT_LOGE("failed to create uv_work_t");
65         return false;
66     }
67     return true;
68 }
69 
ProcessCallbackOrPromise(napi_env env,const CommonAsyncContext * asyncContext,napi_value err,napi_value data)70 void ProcessCallbackOrPromise(napi_env env, const CommonAsyncContext *asyncContext, napi_value err, napi_value data)
71 {
72     napi_value args[BUSINESS_ERROR_ARG_SIZE] = {0};
73     if (asyncContext->errCode == ERR_OK) {
74         napi_get_null(env, &args[0]);
75         args[1] = data;
76     } else {
77         napi_get_null(env, &args[1]);
78         args[0] = err;
79     }
80     if (asyncContext->deferred) {
81         if (asyncContext->errCode == ERR_OK) {
82             napi_resolve_deferred(env, asyncContext->deferred, args[1]);
83         } else {
84             napi_reject_deferred(env, asyncContext->deferred, args[0]);
85         }
86     } else {
87         NapiCallVoidFunction(env, args, BUSINESS_ERROR_ARG_SIZE, asyncContext->callbackRef);
88     }
89 }
90 
ReturnCallbackOrPromise(napi_env env,const CommonAsyncContext * asyncContext,napi_value err,napi_value data)91 void ReturnCallbackOrPromise(napi_env env, const CommonAsyncContext *asyncContext, napi_value err, napi_value data)
92 {
93     napi_value args[BUSINESS_ERROR_ARG_SIZE] = {err, data};
94     if (asyncContext->errCode == ERR_OK) {
95         NAPI_CALL_RETURN_VOID(env, napi_get_null(env, &args[0]));
96     } else {
97         NAPI_CALL_RETURN_VOID(env, napi_get_null(env, &args[1]));
98     }
99     if (asyncContext->deferred != nullptr) {
100         if (asyncContext->errCode == ERR_OK) {
101             NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, asyncContext->deferred, args[1]));
102         } else {
103             NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, asyncContext->deferred, args[0]));
104         }
105         return;
106     }
107     if (asyncContext->callbackRef != nullptr) {
108         NapiCallVoidFunction(env, args, BUSINESS_ERROR_ARG_SIZE, asyncContext->callbackRef);
109     }
110 }
111 
GetIntProperty(napi_env env,napi_value obj,int32_t & property)112 bool GetIntProperty(napi_env env, napi_value obj, int32_t &property)
113 {
114     napi_valuetype valueType = napi_undefined;
115     NAPI_CALL_BASE(env, napi_typeof(env, obj, &valueType), false);
116     if (valueType != napi_number) {
117         return false;
118     }
119 
120     NAPI_CALL_BASE(env, napi_get_value_int32(env, obj, &property), false);
121     return true;
122 }
123 
GetLongIntProperty(napi_env env,napi_value obj,int64_t & property)124 bool GetLongIntProperty(napi_env env, napi_value obj, int64_t &property)
125 {
126     napi_valuetype valueType = napi_undefined;
127     NAPI_CALL_BASE(env, napi_typeof(env, obj, &valueType), false);
128     if (valueType != napi_number) {
129         return false;
130     }
131 
132     NAPI_CALL_BASE(env, napi_get_value_int64(env, obj, &property), false);
133     return true;
134 }
135 
GetBoolProperty(napi_env env,napi_value obj,bool & property)136 bool GetBoolProperty(napi_env env, napi_value obj, bool &property)
137 {
138     napi_valuetype valueType = napi_undefined;
139     NAPI_CALL_BASE(env, napi_typeof(env, obj, &valueType), false);
140     if (valueType != napi_boolean) {
141         return false;
142     }
143     NAPI_CALL_BASE(env, napi_get_value_bool(env, obj, &property), false);
144     return true;
145 }
146 
GetStringProperty(napi_env env,napi_value obj,std::string & property)147 bool GetStringProperty(napi_env env, napi_value obj, std::string &property)
148 {
149     napi_valuetype valuetype = napi_undefined;
150     NAPI_CALL_BASE(env, napi_typeof(env, obj, &valuetype), false);
151     if (valuetype != napi_string) {
152         return false;
153     }
154 
155     size_t propLen;
156     NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, obj, nullptr, 0, &propLen), false);
157     property.reserve(propLen + 1);
158     property.resize(propLen);
159     NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, obj, property.data(), propLen + 1, &propLen), false);
160     return true;
161 }
162 
GetStringArrayProperty(napi_env env,napi_value obj,std::vector<std::string> & property,bool allowEmpty)163 bool GetStringArrayProperty(napi_env env, napi_value obj, std::vector<std::string> &property, bool allowEmpty)
164 {
165     bool isArray = false;
166     NAPI_CALL_BASE(env, napi_is_array(env, obj, &isArray), false);
167     if (!isArray) {
168         return false;
169     }
170     uint32_t length = 0;
171     NAPI_CALL_BASE(env, napi_get_array_length(env, obj, &length), false);
172     if (!allowEmpty && (length == 0)) {
173         return false;
174     }
175 
176     for (size_t i = 0; i < length; i++) {
177         napi_value strJs = nullptr;
178         NAPI_CALL_BASE(env, napi_get_element(env, obj, i, &strJs), false);
179         std::string str;
180         if (!GetStringProperty(env, strJs, str)) {
181             return false;
182         }
183         property.emplace_back(str);
184     }
185     return true;
186 }
187 
GetCallbackProperty(napi_env env,napi_value obj,napi_ref & property,int argNum)188 bool GetCallbackProperty(napi_env env, napi_value obj, napi_ref &property, int argNum)
189 {
190     napi_valuetype valueType = napi_undefined;
191     NAPI_CALL_BASE(env, napi_typeof(env, obj, &valueType), false);
192     if (valueType != napi_function) {
193         return false;
194     }
195     NAPI_CALL_BASE(env, napi_create_reference(env, obj, argNum, &property), false);
196     return true;
197 }
198 
GetStringPropertyByKey(napi_env env,napi_value obj,const std::string & propertyName,std::string & property)199 bool GetStringPropertyByKey(napi_env env, napi_value obj, const std::string &propertyName, std::string &property)
200 {
201     napi_value value = nullptr;
202     NAPI_CALL_BASE(env, napi_get_named_property(env, obj, propertyName.c_str(), &value), false);
203 
204     return GetStringProperty(env, value, property);
205 }
206 
GetOptionalStringPropertyByKey(napi_env env,napi_value obj,const std::string & propertyName,std::string & property)207 bool GetOptionalStringPropertyByKey(napi_env env, napi_value obj, const std::string &propertyName,
208     std::string &property)
209 {
210     bool hasProp = false;
211     napi_has_named_property(env, obj, propertyName.c_str(), &hasProp);
212     if (!hasProp) {
213         return true;
214     }
215     napi_value value = nullptr;
216     NAPI_CALL_BASE(env, napi_get_named_property(env, obj, propertyName.c_str(), &value), false);
217     napi_valuetype valuetype = napi_undefined;
218     NAPI_CALL_BASE(env, napi_typeof(env, value, &valuetype), false);
219     if ((valuetype == napi_undefined) || (valuetype == napi_null)) {
220         ACCOUNT_LOGI("this key's value is undefined or null");
221         return true;
222     }
223     return GetStringProperty(env, value, property);
224 }
225 
CompareOnAndOffRef(const napi_env env,napi_ref subscriberRef,napi_ref unsubscriberRef)226 bool CompareOnAndOffRef(const napi_env env, napi_ref subscriberRef, napi_ref unsubscriberRef)
227 {
228     napi_value subscriberCallback;
229     napi_get_reference_value(env, subscriberRef, &subscriberCallback);
230     napi_value unsubscriberCallback;
231     napi_get_reference_value(env, unsubscriberRef, &unsubscriberCallback);
232     bool result = false;
233     napi_strict_equals(env, subscriberCallback, unsubscriberCallback, &result);
234     return result;
235 }
236 
IsSystemApp(napi_env env)237 bool IsSystemApp(napi_env env)
238 {
239     uint64_t tokenId = IPCSkeleton::GetSelfTokenID();
240     bool isSystemApp = Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(tokenId);
241     if (!isSystemApp) {
242         std::string errMsg = ConvertToJsErrMsg(ERR_JS_IS_NOT_SYSTEM_APP);
243         AccountNapiThrow(env, ERR_JS_IS_NOT_SYSTEM_APP, errMsg, true);
244         return false;
245     }
246     return true;
247 }
248 
CreateStringArray(napi_env env,const std::vector<std::string> & strVec)249 napi_value CreateStringArray(napi_env env, const std::vector<std::string> &strVec)
250 {
251     napi_value result = nullptr;
252     napi_create_array(env, &result);
253     for (size_t i = 0; i < strVec.size(); ++i) {
254         napi_value value = nullptr;
255         napi_create_string_utf8(env, strVec[i].c_str(), NAPI_AUTO_LENGTH, &value);
256         napi_set_element(env, result, i, value);
257     }
258     return result;
259 }
CreateUint8Array(napi_env env,const uint8_t * srcData,size_t length)260 napi_value CreateUint8Array(napi_env env, const uint8_t *srcData, size_t length)
261 {
262     napi_value result = nullptr;
263     void* dstData = nullptr;
264     napi_value napiArr = nullptr;
265     NAPI_CALL(env, napi_create_arraybuffer(env, length, &dstData, &napiArr));
266     if ((length > 0) && (memcpy_s(dstData, length, srcData, length) != EOK)) {
267         return result;
268     }
269     NAPI_CALL(env, napi_create_typedarray(env, napi_uint8_array, length, napiArr, 0, &result));
270     return result;
271 }
272 
ParseUint8TypedArray(napi_env env,napi_value value,uint8_t ** data,size_t * length)273 napi_status ParseUint8TypedArray(napi_env env, napi_value value, uint8_t **data, size_t *length)
274 {
275     *data = nullptr;
276     *length = 0;
277     bool isTypedArray = false;
278     napi_is_typedarray(env, value, &isTypedArray);
279     if (!isTypedArray) {
280         ACCOUNT_LOGE("invalid uint8 array");
281         return napi_ok;
282     }
283     napi_typedarray_type arrayType = static_cast<napi_typedarray_type>(-1);  // -1 indicates invalid type
284     napi_value buffer = nullptr;
285     size_t offset = 0;
286     napi_get_typedarray_info(env, value, &arrayType, length, reinterpret_cast<void **>(data), &buffer, &offset);
287     if (arrayType != napi_uint8_array) {
288         ACCOUNT_LOGE("invalid uint8 array");
289         *data = nullptr;
290         *length = 0;
291     }
292     return napi_ok;
293 }
294 
ParseUint8TypedArrayToVector(napi_env env,napi_value value,std::vector<uint8_t> & vec)295 napi_status ParseUint8TypedArrayToVector(napi_env env, napi_value value, std::vector<uint8_t> &vec)
296 {
297     uint8_t *data = nullptr;
298     size_t length = 0;
299     napi_status status = ParseUint8TypedArray(env, value, &data, &length);
300     if (status != napi_ok) {
301         ACCOUNT_LOGE("failed to ParseUint8TypedArray");
302         return status;
303     }
304     vec.assign(data, data + length);
305     return napi_ok;
306 }
307 
ParseUint8TypedArrayToUint64(napi_env env,napi_value value,uint64_t & result)308 napi_status ParseUint8TypedArrayToUint64(napi_env env, napi_value value, uint64_t &result)
309 {
310     uint8_t *data = nullptr;
311     size_t length = 0;
312     napi_status status = ParseUint8TypedArray(env, value, &data, &length);
313     if (status != napi_ok) {
314         ACCOUNT_LOGE("failed to ParseUint8TypedArray");
315         return status;
316     }
317     if (data == nullptr) {
318         result = 0;
319         return napi_invalid_arg;
320     }
321     if (length != sizeof(uint64_t)) {
322         ACCOUNT_LOGE("failed to convert to uint64_t value");
323         return napi_invalid_arg;
324     }
325     result = *(reinterpret_cast<uint64_t *>(data));
326     return napi_ok;
327 }
328 
ParseBusinessError(napi_env env,napi_value value,BusinessError & error)329 bool ParseBusinessError(napi_env env, napi_value value, BusinessError &error)
330 {
331     napi_valuetype valueType = napi_undefined;
332     NAPI_CALL_BASE(env, napi_typeof(env, value, &valueType), false);
333     if (valueType == napi_null || (valueType == napi_undefined)) {
334         error.code = 0;
335         return true;
336     }
337     napi_value napiCode = nullptr;
338     NAPI_CALL_BASE(env, napi_get_named_property(env, value, BUSINESS_ERROR_CODE_NAME, &napiCode), false);
339     if (napiCode == nullptr) {
340         ACCOUNT_LOGE("code is undefined");
341         return false;
342     }
343     NAPI_CALL_BASE(env, napi_get_value_int32(env, napiCode, &error.code), false);
344     bool hasData = false;
345     napi_has_named_property(env, value, BUSINESS_ERROR_DATA_NAME, &hasData);
346     if (hasData) {
347         napi_value napiData = nullptr;
348         napi_get_named_property(env, value, BUSINESS_ERROR_DATA_NAME, &napiData);
349         return GetStringProperty(env, napiData, error.data);
350     }
351     return true;
352 }
353 
GetNamedJsFunction(napi_env env,napi_value object,const std::string & name,napi_ref & callback)354 bool GetNamedJsFunction(napi_env env, napi_value object, const std::string &name, napi_ref &callback)
355 {
356     napi_valuetype valueType = napi_undefined;
357     NAPI_CALL_BASE(env, napi_typeof(env, object, &valueType), false);
358     if (valueType != napi_object) {
359         ACCOUNT_LOGE("invalid object");
360         return false;
361     }
362     napi_value result = nullptr;
363     NAPI_CALL_BASE(env, napi_get_named_property(env, object, name.c_str(), &result), false);
364     return GetCallbackProperty(env, result, callback, 1);
365 }
366 
NapiCallVoidFunction(napi_env env,napi_value * argv,size_t argc,napi_ref funcRef)367 void NapiCallVoidFunction(napi_env env, napi_value *argv, size_t argc, napi_ref funcRef)
368 {
369     napi_value undefined = nullptr;
370     NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined));
371     napi_value returnVal;
372     napi_value func = nullptr;
373     NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, funcRef, &func));
374     napi_call_function(env, undefined, func, argc, argv, &returnVal);
375 }
376 
CreateAuthResult(napi_env env,const std::vector<uint8_t> & token,int32_t remainTimes,int32_t freezingTime)377 napi_value CreateAuthResult(
378     napi_env env, const std::vector<uint8_t> &token, int32_t remainTimes, int32_t freezingTime)
379 {
380     napi_value object = nullptr;
381     NAPI_CALL(env, napi_create_object(env, &object));
382     if (remainTimes >= 0) {
383         napi_value napiRemainTimes = 0;
384         NAPI_CALL(env, napi_create_uint32(env, remainTimes, &napiRemainTimes));
385         NAPI_CALL(env, napi_set_named_property(env, object, "remainTimes", napiRemainTimes));
386     }
387     if (freezingTime >= 0) {
388         napi_value napiFreezingTimes = 0;
389         NAPI_CALL(env, napi_create_uint32(env, freezingTime, &napiFreezingTimes));
390         NAPI_CALL(env, napi_set_named_property(env, object, "freezingTime", napiFreezingTimes));
391     }
392     if (token.size() > 0) {
393         napi_value napiToken = CreateUint8Array(env, token.data(), token.size());
394         NAPI_CALL(env, napi_set_named_property(env, object, "token", napiToken));
395     }
396     return object;
397 }
398 
ReleaseNapiRefAsync(napi_env env,napi_ref napiRef)399 void ReleaseNapiRefAsync(napi_env env, napi_ref napiRef)
400 {
401     ReleaseNapiRefArray(env, {napiRef});
402 }
403 
ReleaseNapiRefArray(napi_env env,const std::vector<napi_ref> & napiRefVec)404 void ReleaseNapiRefArray(napi_env env, const std::vector<napi_ref> &napiRefVec)
405 {
406     if (env == nullptr) {
407         ACCOUNT_LOGE("invalid env");
408         return;
409     }
410     std::unique_ptr<uv_work_t> work = std::make_unique<uv_work_t>();
411     std::unique_ptr<NapiRefArrayContext> context = std::make_unique<NapiRefArrayContext>();
412     uv_loop_s *loop = nullptr;
413     napi_get_uv_event_loop(env, &loop);
414     if ((loop == nullptr) || (work == nullptr) || (context == nullptr)) {
415         ACCOUNT_LOGE("fail to init execution environment");
416         return;
417     }
418     context->env = env;
419     context->napiRefVec = napiRefVec;
420     work->data = reinterpret_cast<void *>(context.get());
421     NAPI_CALL_RETURN_VOID(env, uv_queue_work_with_qos(loop, work.get(), [] (uv_work_t *work) {},
422         [] (uv_work_t *work, int status) {
423             if (work == nullptr) {
424                 ACCOUNT_LOGE("work is nullptr");
425                 return;
426             }
427             auto context = reinterpret_cast<NapiRefArrayContext *>(work->data);
428             if (context == nullptr) {
429                 ACCOUNT_LOGE("context is nullptr");
430                 delete work;
431                 return;
432             }
433             for (auto &napiRef : context->napiRefVec) {
434                 if (napiRef != nullptr) {
435                     napi_delete_reference(context->env, napiRef);
436                 }
437             }
438             delete context;
439             delete work;
440         }, uv_qos_default));
441     context.release();
442     work.release();
443 }
444 
InitUvWorkCallbackEnv(uv_work_t * work,napi_handle_scope & scope)445 bool InitUvWorkCallbackEnv(uv_work_t *work, napi_handle_scope &scope)
446 {
447     if (work == nullptr) {
448         ACCOUNT_LOGE("work is nullptr");
449         return false;
450     }
451     if (work->data == nullptr) {
452         ACCOUNT_LOGE("data is nullptr");
453         return false;
454     }
455     CommonAsyncContext *data = reinterpret_cast<CommonAsyncContext *>(work->data);
456     napi_open_handle_scope(data->env, &scope);
457     if (scope == nullptr) {
458         ACCOUNT_LOGE("fail to open scope");
459         delete data;
460         work->data = nullptr;
461         return false;
462     }
463     return true;
464 }
465 } // namespace AccountJsKit
466 } // namespace OHOS