• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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 "user_auth_napi_helper.h"
17 
18 #include <cinttypes>
19 #include <uv.h>
20 
21 #include "securec.h"
22 
23 #include "napi/native_api.h"
24 #include "napi/native_common.h"
25 #include "napi/native_node_api.h"
26 
27 #include "iam_logger.h"
28 #include "iam_ptr.h"
29 #include "user_auth_helper.h"
30 
31 #define LOG_TAG "USER_AUTH_NAPI"
32 
33 namespace OHOS {
34 namespace UserIam {
35 namespace UserAuth {
36 namespace {
37 static constexpr const int MAX_STRING_LENGTH = 65536;
38 struct DeleteRefHolder {
39     napi_env env {nullptr};
40     napi_ref ref {nullptr};
41 };
42 }
43 
JsRefHolder(napi_env env,napi_value value)44 JsRefHolder::JsRefHolder(napi_env env, napi_value value)
45 {
46     if (env == nullptr || value == nullptr) {
47         IAM_LOGE("get null ptr");
48         return;
49     }
50     napi_status ret = UserAuthNapiHelper::GetFunctionRef(env, value, ref_);
51     if (ret != napi_ok) {
52         IAM_LOGE("GetFunctionRef fail %{public}d", ret);
53         ref_ = nullptr;
54         return;
55     }
56     env_ = env;
57 }
58 
~JsRefHolder()59 JsRefHolder::~JsRefHolder()
60 {
61     if (!IsValid()) {
62         IAM_LOGI("invalid");
63         return;
64     }
65     IAM_LOGD("delete reference");
66     uv_loop_s *loop = nullptr;
67     napi_status napiStatus = napi_get_uv_event_loop(env_, &loop);
68     if (napiStatus != napi_ok || loop == nullptr) {
69         IAM_LOGE("napi_get_uv_event_loop fail");
70         return;
71     }
72     std::shared_ptr<DeleteRefHolder> deleteRefHolder = Common::MakeShared<DeleteRefHolder>();
73     if (deleteRefHolder == nullptr) {
74         IAM_LOGE("deleteRefHolder is null");
75         return;
76     }
77     deleteRefHolder->env = env_;
78     deleteRefHolder->ref = ref_;
79     auto task = [deleteRefHolder] () {
80         IAM_LOGI("start");
81         if (deleteRefHolder == nullptr) {
82             IAM_LOGE("deleteRefHolder is invalid");
83             return;
84         }
85         napi_status ret = napi_delete_reference(deleteRefHolder->env, deleteRefHolder->ref);
86         if (ret != napi_ok) {
87             IAM_LOGE("napi_delete_reference fail %{public}d", ret);
88             return;
89         }
90     };
91     if (napi_status::napi_ok != napi_send_event(env_, task, napi_eprio_immediate)) {
92         IAM_LOGE("napi_send_event: Failed to SendEvent");
93     }
94 }
95 
IsValid() const96 bool JsRefHolder::IsValid() const
97 {
98     return (env_ != nullptr && ref_ != nullptr);
99 }
100 
Get() const101 napi_ref JsRefHolder::Get() const
102 {
103     return ref_;
104 }
105 
GetResultCodeV8(int32_t result)106 int32_t UserAuthNapiHelper::GetResultCodeV8(int32_t result)
107 {
108     if (result == CHECK_PERMISSION_FAILED) {
109         return static_cast<int32_t>(UserAuthResultCode::OHOS_CHECK_PERMISSION_FAILED);
110     }
111     if (result == PIN_EXPIRED) {
112         return GENERAL_ERROR;
113     }
114     if ((result < SUCCESS) || (result > NOT_ENROLLED)) {
115         return GENERAL_ERROR;
116     }
117     return result;
118 }
119 
GetResultCodeV9(int32_t result)120 int32_t UserAuthNapiHelper::GetResultCodeV9(int32_t result)
121 {
122     if (result == CHECK_PERMISSION_FAILED) {
123         return static_cast<int32_t>(UserAuthResultCode::OHOS_CHECK_PERMISSION_FAILED);
124     }
125     if (result == INVALID_PARAMETERS) {
126         return static_cast<int32_t>(UserAuthResultCode::OHOS_INVALID_PARAM);
127     }
128     if (result == PIN_EXPIRED) {
129         return static_cast<int32_t>(UserAuthResultCode::GENERAL_ERROR);
130     }
131     if (result > (INT32_MAX - static_cast<int32_t>(UserAuthResultCode::RESULT_CODE_V9_MIN))) {
132         return static_cast<int32_t>(UserAuthResultCode::GENERAL_ERROR);
133     }
134     int32_t resultCodeV9 = result + static_cast<int32_t>(UserAuthResultCode::RESULT_CODE_V9_MIN);
135     if (resultCodeV9 >= static_cast<int32_t>(UserAuthResultCode::RESULT_CODE_V9_MIN) &&
136         resultCodeV9 <= static_cast<int32_t>(UserAuthResultCode::RESULT_CODE_V9_MAX)) {
137         return resultCodeV9;
138     }
139     return static_cast<int32_t>(UserAuthResultCode::GENERAL_ERROR);
140 }
141 
GenerateBusinessErrorV9(napi_env env,UserAuthResultCode result)142 napi_value UserAuthNapiHelper::GenerateBusinessErrorV9(napi_env env, UserAuthResultCode result)
143 {
144     napi_value code;
145     std::string msgStr;
146     auto res = g_resultV92Str.find(result);
147     if (res == g_resultV92Str.end()) {
148         IAM_LOGE("result %{public}d not found", static_cast<int32_t>(result));
149         msgStr = g_resultV92Str.at(UserAuthResultCode::GENERAL_ERROR);
150         NAPI_CALL(env, napi_create_int32(env, static_cast<int32_t>(UserAuthResultCode::GENERAL_ERROR), &code));
151     } else {
152         msgStr = res->second;
153         NAPI_CALL(env, napi_create_int32(env, static_cast<int32_t>(result), &code));
154     }
155     IAM_LOGI("get msg %{public}s", msgStr.c_str());
156 
157     napi_value msg;
158     NAPI_CALL(env, napi_create_string_utf8(env, msgStr.c_str(), NAPI_AUTO_LENGTH, &msg));
159 
160     napi_value businessError;
161     NAPI_CALL(env, napi_create_error(env, nullptr, msg, &businessError));
162     NAPI_CALL(env, napi_set_named_property(env, businessError, "code", code));
163 
164     return businessError;
165 }
166 
GenerateErrorMsg(napi_env env,UserAuthResultCode result,std::string errorMsg)167 napi_value UserAuthNapiHelper::GenerateErrorMsg(napi_env env, UserAuthResultCode result, std::string errorMsg)
168 {
169     napi_value code;
170     std::string msgStr;
171     auto res = g_resultV92Str.find(result);
172     if (res == g_resultV92Str.end()) {
173         IAM_LOGE("result %{public}d not found", static_cast<int32_t>(result));
174         msgStr = g_resultV92Str.at(UserAuthResultCode::GENERAL_ERROR);
175         NAPI_CALL(env, napi_create_int32(env, static_cast<int32_t>(UserAuthResultCode::GENERAL_ERROR), &code));
176     } else {
177         msgStr = errorMsg;
178         NAPI_CALL(env, napi_create_int32(env, static_cast<int32_t>(result), &code));
179     }
180     IAM_LOGI("error msg %{public}s", msgStr.c_str());
181 
182     napi_value msg;
183     NAPI_CALL(env, napi_create_string_utf8(env, msgStr.c_str(), NAPI_AUTO_LENGTH, &msg));
184 
185     napi_value businessError;
186     NAPI_CALL(env, napi_create_error(env, nullptr, msg, &businessError));
187     NAPI_CALL(env, napi_set_named_property(env, businessError, "code", code));
188 
189     return businessError;
190 }
191 
ThrowErrorMsg(napi_env env,UserAuthResultCode errorCode,std::string errorMsg)192 UserAuthResultCode UserAuthNapiHelper::ThrowErrorMsg(napi_env env, UserAuthResultCode errorCode, std::string errorMsg)
193 {
194     napi_throw(env, UserAuthNapiHelper::GenerateErrorMsg(env, errorCode, errorMsg));
195     return errorCode;
196 }
197 
CheckNapiType(napi_env env,napi_value value,napi_valuetype type)198 napi_status UserAuthNapiHelper::CheckNapiType(napi_env env, napi_value value, napi_valuetype type)
199 {
200     napi_valuetype valuetype;
201     napi_status result = napi_typeof(env, value, &valuetype);
202     if (result != napi_ok) {
203         IAM_LOGE("napi_typeof fail");
204         return result;
205     }
206     if (valuetype != type) {
207         IAM_LOGE("check valuetype fail");
208         return napi_generic_failure;
209     }
210     return napi_ok;
211 }
212 
GetBoolValue(napi_env env,napi_value value,bool & out)213 napi_status UserAuthNapiHelper::GetBoolValue(napi_env env, napi_value value, bool &out)
214 {
215     napi_status result = CheckNapiType(env, value, napi_boolean);
216     if (result != napi_ok) {
217         IAM_LOGE("CheckNapiType fail");
218         return result;
219     }
220     result = napi_get_value_bool(env, value, &out);
221     if (result != napi_ok) {
222         IAM_LOGE("napi_get_value_bool fail");
223     }
224     return result;
225 }
226 
GetInt32Value(napi_env env,napi_value value,int32_t & out)227 napi_status UserAuthNapiHelper::GetInt32Value(napi_env env, napi_value value, int32_t &out)
228 {
229     napi_status result = CheckNapiType(env, value, napi_number);
230     if (result != napi_ok) {
231         IAM_LOGE("CheckNapiType fail");
232         return result;
233     }
234     result = napi_get_value_int32(env, value, &out);
235     if (result != napi_ok) {
236         IAM_LOGE("napi_get_value_int32 fail");
237     }
238     return result;
239 }
240 
GetUint32Value(napi_env env,napi_value value,uint32_t & out)241 napi_status UserAuthNapiHelper::GetUint32Value(napi_env env, napi_value value, uint32_t &out)
242 {
243     napi_status result = CheckNapiType(env, value, napi_number);
244     if (result != napi_ok) {
245         IAM_LOGE("CheckNapiType fail");
246         return result;
247     }
248     result = napi_get_value_uint32(env, value, &out);
249     if (result != napi_ok) {
250         IAM_LOGE("napi_get_value_uint32 fail");
251     }
252     return result;
253 }
254 
GetStrValue(napi_env env,napi_value value,char * out,size_t & len)255 napi_status UserAuthNapiHelper::GetStrValue(napi_env env, napi_value value, char *out, size_t &len)
256 {
257     if (out == nullptr) {
258         IAM_LOGE("invalid out parameter");
259         return napi_invalid_arg;
260     }
261     napi_status result = CheckNapiType(env, value, napi_string);
262     if (result != napi_ok) {
263         IAM_LOGE("CheckNapiType fail");
264         return result;
265     }
266     size_t maxLen = len;
267     result = napi_get_value_string_utf8(env, value, out, maxLen, &len);
268     if (result != napi_ok) {
269         IAM_LOGE("napi_get_value_string_utf8 fail");
270     }
271     if (maxLen > 0) {
272         out[maxLen - 1] = '\0';
273     }
274     return result;
275 }
276 
GetFunctionRef(napi_env env,napi_value value,napi_ref & ref)277 napi_status UserAuthNapiHelper::GetFunctionRef(napi_env env, napi_value value, napi_ref &ref)
278 {
279     napi_status result = CheckNapiType(env, value, napi_function);
280     if (result != napi_ok) {
281         IAM_LOGE("CheckNapiType fail");
282         return result;
283     }
284     result = napi_create_reference(env, value, 1, &ref);
285     if (result != napi_ok) {
286         IAM_LOGE("napi_create_reference fail");
287     }
288     return result;
289 }
290 
GetUint8ArrayValue(napi_env env,napi_value value,size_t limitLen,std::vector<uint8_t> & array)291 napi_status UserAuthNapiHelper::GetUint8ArrayValue(napi_env env, napi_value value,
292     size_t limitLen, std::vector<uint8_t> &array)
293 {
294     bool isTypedarray;
295     napi_status result = napi_is_typedarray(env, value, &isTypedarray);
296     if (result != napi_ok) {
297         IAM_LOGE("napi_is_typedarray fail");
298         return result;
299     }
300     if (!isTypedarray) {
301         IAM_LOGE("value is not typedarray");
302         return napi_array_expected;
303     }
304     napi_typedarray_type type;
305     size_t length;
306     void *data;
307     napi_value buffer;
308     size_t offset;
309     result = napi_get_typedarray_info(env, value, &type, &length, &data, &buffer, &offset);
310     if (result != napi_ok) {
311         IAM_LOGE("napi_get_typedarray_info fail");
312         return result;
313     }
314     if (type != napi_uint8_array) {
315         IAM_LOGE("value is not napi_uint8_array");
316         return napi_invalid_arg;
317     }
318     if (length > limitLen) {
319         IAM_LOGE("array length reach limit");
320         return napi_generic_failure;
321     }
322     array.resize(length);
323     if (memcpy_s(array.data(), length, data, length) != EOK) {
324         IAM_LOGE("memcpy_s fail");
325         return napi_generic_failure;
326     }
327     return result;
328 }
329 
Uint64ToNapiUint8Array(napi_env env,uint64_t value)330 napi_value UserAuthNapiHelper::Uint64ToNapiUint8Array(napi_env env, uint64_t value)
331 {
332     void *data = nullptr;
333     napi_value arraybuffer = nullptr;
334     size_t length = sizeof(value);
335     NAPI_CALL(env, napi_create_arraybuffer(env, length, &data, &arraybuffer));
336     if (memcpy_s(data, length, reinterpret_cast<const void *>(&value), length) != EOK) {
337         IAM_LOGE("memcpy_s fail");
338         return nullptr;
339     }
340     napi_value result = nullptr;
341     NAPI_CALL(env, napi_create_typedarray(env, napi_uint8_array, length, arraybuffer, 0, &result));
342     return result;
343 }
344 
Uint8VectorToNapiUint8Array(napi_env env,std::vector<uint8_t> & value)345 napi_value UserAuthNapiHelper::Uint8VectorToNapiUint8Array(napi_env env,  std::vector<uint8_t> &value)
346 {
347     void *data = nullptr;
348     napi_value arraybuffer = nullptr;
349     size_t length = value.size();
350     NAPI_CALL(env, napi_create_arraybuffer(env, length, &data, &arraybuffer));
351     if (memcpy_s(data, length, reinterpret_cast<const void *>(value.data()), length) != EOK) {
352         IAM_LOGE("memcpy_s fail");
353         return nullptr;
354     }
355     napi_value result = nullptr;
356     NAPI_CALL(env, napi_create_typedarray(env, napi_uint8_array, length, arraybuffer, 0, &result));
357     return result;
358 }
359 
CallVoidNapiFunc(napi_env env,napi_ref funcRef,size_t argc,const napi_value * argv)360 napi_status UserAuthNapiHelper::CallVoidNapiFunc(napi_env env, napi_ref funcRef, size_t argc, const napi_value *argv)
361 {
362     napi_value funcVal;
363     napi_status ret = napi_get_reference_value(env, funcRef, &funcVal);
364     if (ret != napi_ok) {
365         IAM_LOGE("napi_get_reference_value failed %{public}d", ret);
366         return ret;
367     }
368     napi_value undefined;
369     ret = napi_get_undefined(env, &undefined);
370     if (ret != napi_ok) {
371         IAM_LOGE("napi_get_undefined failed %{public}d", ret);
372         return ret;
373     }
374     napi_value callResult;
375     ret = napi_call_function(env, undefined, funcVal, argc, argv, &callResult);
376     if (ret != napi_ok) {
377         IAM_LOGE("napi_call_function failed %{public}d", ret);
378     }
379     return ret;
380 }
381 
SetInt32Property(napi_env env,napi_value obj,const char * name,int32_t value)382 napi_status UserAuthNapiHelper::SetInt32Property(napi_env env, napi_value obj, const char *name, int32_t value)
383 {
384     napi_value napiValue = nullptr;
385     napi_status ret = napi_create_int32(env, value, &napiValue);
386     if (ret != napi_ok) {
387         IAM_LOGE("napi_create_int32 failed %{public}d", ret);
388         return ret;
389     }
390     ret = napi_set_named_property(env, obj, name, napiValue);
391     if (ret != napi_ok) {
392         IAM_LOGE("napi_set_named_property failed %{public}d", ret);
393     }
394     return ret;
395 }
396 
SetUint32Property(napi_env env,napi_value obj,const char * name,uint32_t value)397 napi_status UserAuthNapiHelper::SetUint32Property(napi_env env, napi_value obj, const char *name, uint32_t value)
398 {
399     napi_value napiValue = nullptr;
400     napi_status ret = napi_create_uint32(env, value, &napiValue);
401     if (ret != napi_ok) {
402         IAM_LOGE("napi_create_uint32 failed %{public}d", ret);
403         return ret;
404     }
405     ret = napi_set_named_property(env, obj, name, napiValue);
406     if (ret != napi_ok) {
407         IAM_LOGE("napi_set_named_property failed %{public}d", ret);
408     }
409     return ret;
410 }
411 
SetUint8ArrayProperty(napi_env env,napi_value obj,const char * name,const std::vector<uint8_t> & value)412 napi_status UserAuthNapiHelper::SetUint8ArrayProperty(napi_env env,
413     napi_value obj, const char *name, const std::vector<uint8_t> &value)
414 {
415     size_t size = value.size();
416     void *data;
417     napi_value buffer;
418     napi_status ret = napi_create_arraybuffer(env, size, &data, &buffer);
419     if (ret != napi_ok) {
420         IAM_LOGE("napi_create_arraybuffer failed %{public}d", ret);
421         return ret;
422     }
423     if (size != 0) {
424         if (memcpy_s(data, size, value.data(), value.size()) != EOK) {
425             IAM_LOGE("memcpy_s failed");
426             return napi_generic_failure;
427         }
428     }
429     napi_value napiValue;
430     ret = napi_create_typedarray(env, napi_uint8_array, size, buffer, 0, &napiValue);
431     if (ret != napi_ok) {
432         IAM_LOGE("napi_create_typedarray failed %{public}d", ret);
433         return ret;
434     }
435     ret = napi_set_named_property(env, obj, name, napiValue);
436     if (ret != napi_ok) {
437         IAM_LOGE("napi_set_named_property failed %{public}d", ret);
438     }
439     return ret;
440 }
441 
SetEnrolledStateProperty(napi_env env,napi_value obj,const char * name,EnrolledState & value)442 napi_status UserAuthNapiHelper::SetEnrolledStateProperty(napi_env env, napi_value obj,
443     const char *name, EnrolledState &value)
444 {
445     napi_value napiValue = nullptr;
446     napi_status ret = napi_create_object(env, &napiValue);
447     if (ret != napi_ok) {
448         IAM_LOGE("napi_create_object failed %{public}d", ret);
449         return ret;
450     }
451     int32_t credentialDigest = static_cast<int32_t>(value.credentialDigest);
452     int32_t credentialCount = static_cast<int32_t>(value.credentialCount);
453     IAM_LOGI("get enrolled state success, credentialDigest = %{public}d, credentialCount = %{public}d",
454         credentialDigest, credentialCount);
455     ret = UserAuthNapiHelper::SetInt32Property(env, napiValue, "credentialDigest", credentialDigest);
456     if (ret != napi_ok) {
457         IAM_LOGE("napi_create_int32 failed %{public}d", ret);
458         return ret;
459     }
460     ret = UserAuthNapiHelper::SetInt32Property(env, napiValue, "credentialCount", credentialCount);
461     if (ret != napi_ok) {
462         IAM_LOGE("napi_create_int32 failed %{public}d", ret);
463         return ret;
464     }
465     ret = napi_set_named_property(env, obj, name, napiValue);
466     if (ret != napi_ok) {
467         IAM_LOGE("napi_set_named_property failed %{public}d", ret);
468     }
469     return ret;
470 }
471 
GetNamedProperty(napi_env env,napi_value object,const std::string & propertyName)472 napi_value UserAuthNapiHelper::GetNamedProperty(napi_env env, napi_value object, const std::string &propertyName)
473 {
474     napi_value value = nullptr;
475     bool hasProperty = false;
476     NAPI_CALL(env, napi_has_named_property(env, object, propertyName.c_str(), &hasProperty));
477     if (!hasProperty) {
478         return value;
479     }
480     NAPI_CALL(env, napi_get_named_property(env, object, propertyName.c_str(), &value));
481     return value;
482 }
483 
GetStringFromValueUtf8(napi_env env,napi_value value)484 std::string UserAuthNapiHelper::GetStringFromValueUtf8(napi_env env, napi_value value)
485 {
486     if (CheckNapiType(env, value, napi_string) != napi_ok) {
487         return "";
488     }
489     std::string result;
490     std::vector<char> str(MAX_STRING_LENGTH + 1, '\0');
491     size_t length = 0;
492     NAPI_CALL(env, napi_get_value_string_utf8(env, value, &str[0], MAX_STRING_LENGTH, &length));
493     if (length > 0) {
494         return result.append(&str[0], length);
495     }
496     return result;
497 }
498 
HasNamedProperty(napi_env env,napi_value object,const std::string & propertyName)499 bool UserAuthNapiHelper::HasNamedProperty(napi_env env, napi_value object, const std::string &propertyName)
500 {
501     bool hasProperty = false;
502     NAPI_CALL_BASE(env, napi_has_named_property(env, object, propertyName.c_str(), &hasProperty), false);
503     return hasProperty;
504 }
505 
GetStringPropertyUtf8(napi_env env,napi_value object,const std::string & propertyName)506 std::string UserAuthNapiHelper::GetStringPropertyUtf8(napi_env env, napi_value object, const std::string &propertyName)
507 {
508     napi_value value = GetNamedProperty(env, object, propertyName);
509     napi_status result = CheckNapiType(env, value, napi_string);
510     if (result != napi_ok) {
511         return "";
512     }
513     return GetStringFromValueUtf8(env, value);
514 }
515 
SetStringPropertyUtf8(napi_env env,napi_value object,const std::string & name,const std::string & value)516 bool UserAuthNapiHelper::SetStringPropertyUtf8(
517     napi_env env, napi_value object, const std::string &name, const std::string &value)
518 {
519     napi_value jsValue = nullptr;
520     if (napi_create_string_utf8(env, value.c_str(), strlen(value.c_str()), &jsValue) != napi_ok) {
521         IAM_LOGE("get string error");
522         return false;
523     }
524     napi_valuetype valueType = napi_undefined;
525     NAPI_CALL_BASE(env, napi_typeof(env, jsValue, &valueType), napi_undefined);
526     napi_set_named_property(env, object, name.c_str(), jsValue);
527     return true;
528 }
529 
GetInt32Array(napi_env env,napi_value obj,std::vector<uint32_t> vec)530 bool UserAuthNapiHelper::GetInt32Array(napi_env env, napi_value obj, std::vector<uint32_t> vec)
531 {
532     vec.clear();
533     uint32_t len;
534     napi_get_array_length(env, obj, &len);
535     IAM_LOGI("GetInt32Array length: %{public}d", len);
536     for (uint32_t index = 0; index < len; index++) {
537         napi_value value;
538         uint32_t getValue;
539         NAPI_CALL_BASE(env, napi_get_element(env, obj, index, &value), napi_undefined);
540         NAPI_CALL_BASE(env, napi_get_value_uint32(env, value, &getValue), napi_undefined);
541         IAM_LOGI("vec[%{public}d]: %{public}d", index, len);
542         vec.emplace_back(getValue);
543     }
544     return true;
545 }
546 
CheckAuthType(int32_t authType)547 bool UserAuthNapiHelper::CheckAuthType(int32_t authType)
548 {
549     if (authType != AuthType::FACE && authType != AuthType::FINGERPRINT) {
550         IAM_LOGE("authType check fail:%{public}d", authType);
551         return false;
552     }
553     return true;
554 }
555 } // namespace UserAuth
556 } // namespace UserIam
557 } // namespace OHOS