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