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 "user_auth_impl.h"
17 
18 #include <map>
19 
20 #include "securec.h"
21 
22 #include "iam_logger.h"
23 #include "iam_para2str.h"
24 #include "iam_ptr.h"
25 
26 #include "user_auth_napi_helper.h"
27 #include "user_auth_callback_v6.h"
28 #include "user_auth_callback_v8.h"
29 #include "user_auth_client_impl.h"
30 
31 #define LOG_TAG "USER_AUTH_NAPI"
32 
33 namespace OHOS {
34 namespace UserIam {
35 namespace UserAuth {
GetVersion(napi_env env,napi_callback_info info)36 napi_value UserAuthImpl::GetVersion(napi_env env, napi_callback_info info)
37 {
38     int32_t version;
39     int32_t result = UserAuthClientImpl::Instance().GetVersion(version);
40     if (result != SUCCESS) {
41         IAM_LOGE("result = %{public}d", result);
42         version = 0;
43     }
44     IAM_LOGI("version = %{public}d", version);
45     napi_value jsVersion;
46     NAPI_CALL(env, napi_create_int32(env, version, &jsVersion));
47     return jsVersion;
48 }
49 
GetAvailableStatus(napi_env env,napi_callback_info info)50 napi_value UserAuthImpl::GetAvailableStatus(napi_env env, napi_callback_info info)
51 {
52     napi_value argv[ARGS_TWO] = {nullptr};
53     size_t argc = ARGS_TWO;
54     napi_value result;
55     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
56     if (argc != ARGS_TWO) {
57         IAM_LOGE("parms error");
58         NAPI_CALL(env, napi_create_int32(env, INVALID_PARAMETERS, &result));
59         return result;
60     }
61     int32_t type;
62     NAPI_CALL(env, napi_get_value_int32(env, argv[PARAM0], &type));
63     int32_t level;
64     NAPI_CALL(env, napi_get_value_int32(env, argv[PARAM1], &level));
65     AuthType authType = AuthType(type);
66     AuthTrustLevel authTrustLevel = AuthTrustLevel(level);
67     ResultCode checkRet = CheckAuthTypeAndAuthTrustLevel(authType, authTrustLevel);
68     if (checkRet != SUCCESS) {
69         IAM_LOGE("CheckAuthTypeAndAuthTrsutLevel failed");
70         NAPI_CALL(env, napi_create_int32(env, checkRet, &result));
71         return result;
72     }
73     int32_t status = UserAuthClientImpl::Instance().GetNorthAvailableStatus(API_VERSION_8, authType, authTrustLevel);
74     IAM_LOGI("result = %{public}d", status);
75     NAPI_CALL(env, napi_create_int32(env, UserAuthNapiHelper::GetResultCodeV8(status), &result));
76     return result;
77 }
78 
Execute(napi_env env,napi_callback_info info)79 napi_value UserAuthImpl::Execute(napi_env env, napi_callback_info info)
80 {
81     IAM_LOGI("start");
82     size_t argc = ARGS_THREE;
83     napi_value argv[ARGS_THREE] = {nullptr};
84     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
85     napi_value retPromise = nullptr;
86     std::shared_ptr<JsRefHolder> callbackRef = nullptr;
87     napi_deferred promiseDeferred = nullptr;
88     if (argc == ARGS_THREE) {
89         callbackRef = Common::MakeShared<JsRefHolder>(env, argv[PARAM2]);
90         if (callbackRef == nullptr || !callbackRef->IsValid()) {
91             IAM_LOGE("make callback ref fail");
92             return nullptr;
93         }
94         NAPI_CALL(env, napi_get_null(env, &retPromise));
95     } else if (argc == ARGS_TWO) {
96         NAPI_CALL(env, napi_create_promise(env, &promiseDeferred, &retPromise));
97     } else {
98         IAM_LOGE("bad params");
99         return retPromise;
100     }
101     std::shared_ptr<UserAuthCallbackV6> callback =
102         Common::MakeShared<UserAuthCallbackV6>(env, callbackRef, promiseDeferred);
103     if (callback == nullptr) {
104         IAM_LOGE("callback is nullptr");
105         return nullptr;
106     }
107 
108     AuthType authType;
109     ResultCode resultCode;
110     NAPI_CALL(env, ParseExecuteAuthType(env, argv[PARAM0], authType, resultCode));
111     if (resultCode != ResultCode::SUCCESS) {
112         IAM_LOGE("ParseAuthType fail");
113         UserIam::UserAuth::Attributes extra;
114         callback->OnResult(resultCode, extra);
115         return retPromise;
116     }
117     AuthTrustLevel authTrustLevel;
118     NAPI_CALL(env, ParseExecuteSecureLevel(env, argv[PARAM1], authTrustLevel, resultCode));
119     if (resultCode != ResultCode::SUCCESS) {
120         IAM_LOGE("ParseExecuteSecureLevel fail");
121         UserIam::UserAuth::Attributes extra;
122         callback->OnResult(resultCode, extra);
123         return retPromise;
124     }
125 
126     std::vector<uint8_t> challenge;
127     UserAuthClientImpl::Instance().BeginNorthAuthentication(API_VERSION_6, challenge, FACE, authTrustLevel, callback);
128     return retPromise;
129 }
130 
ParseExecuteAuthType(napi_env env,napi_value value,AuthType & authType,ResultCode & resultCode)131 napi_status UserAuthImpl::ParseExecuteAuthType(napi_env env, napi_value value,
132     AuthType &authType, ResultCode &resultCode)
133 {
134     resultCode = ResultCode::GENERAL_ERROR;
135     static const size_t maxLen = 20;
136     char str[maxLen] = {0};
137     size_t len = maxLen;
138     napi_status result = UserAuthNapiHelper::GetStrValue(env, value, str, len);
139     if (result != napi_ok) {
140         IAM_LOGE("getStrValue fail");
141         return result;
142     }
143     static const char *authTypeAll = "ALL";
144     static const char *authTypeFaceOnly = "FACE_ONLY";
145     if (strcmp(str, authTypeAll) == 0) {
146         IAM_LOGE("type ALL not supported");
147         resultCode = ResultCode::TYPE_NOT_SUPPORT;
148         return napi_ok;
149     }
150     if (strcmp(str, authTypeFaceOnly) != 0) {
151         IAM_LOGE("type is invalid");
152         resultCode = ResultCode::INVALID_PARAMETERS;
153         return napi_ok;
154     }
155     resultCode = ResultCode::SUCCESS;
156     return napi_ok;
157 }
158 
ParseExecuteSecureLevel(napi_env env,napi_value value,AuthTrustLevel & authTrustLevel,ResultCode & resultCode)159 napi_status UserAuthImpl::ParseExecuteSecureLevel(napi_env env, napi_value value,
160     AuthTrustLevel &authTrustLevel, ResultCode &resultCode)
161 {
162     resultCode = ResultCode::GENERAL_ERROR;
163     static const size_t maxLen = 20;
164     char str[maxLen] = {0};
165     size_t len = maxLen;
166     napi_status result = UserAuthNapiHelper::GetStrValue(env, value, str, len);
167     if (result != napi_ok) {
168         IAM_LOGE("getStrValue fail");
169         return result;
170     }
171     static std::map<std::string, AuthTrustLevel> convertAuthTrustLevel = {
172         {"S1", ATL1},
173         {"S2", ATL2},
174         {"S3", ATL3},
175         {"S4", ATL4},
176     };
177     if (convertAuthTrustLevel.count(str) == 0) {
178         IAM_LOGE("trust level invalid");
179         resultCode = ResultCode::INVALID_PARAMETERS;
180         return napi_ok;
181     }
182     authTrustLevel = convertAuthTrustLevel[str];
183     resultCode = ResultCode::SUCCESS;
184     return napi_ok;
185 }
186 
Auth(napi_env env,napi_callback_info info)187 napi_value UserAuthImpl::Auth(napi_env env, napi_callback_info info)
188 {
189     IAM_LOGI("start");
190     size_t argc = ARGS_FOUR;
191     napi_value argv[ARGS_FOUR] = {nullptr};
192     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
193     if (argc != ARGS_FOUR) {
194         IAM_LOGE("parms error");
195         return nullptr;
196     }
197     std::vector<uint8_t> challenge;
198     if (UserAuthNapiHelper::GetUint8ArrayValue(env, argv[PARAM0], MAX_CHALLENG_LEN, challenge) != napi_ok) {
199         IAM_LOGE("challenge invalid, use null challenge");
200         challenge.clear();
201     }
202     int32_t authType;
203     NAPI_CALL(env, UserAuthNapiHelper::GetInt32Value(env, argv[PARAM1], authType));
204     int32_t authTrustLevel;
205     NAPI_CALL(env, UserAuthNapiHelper::GetInt32Value(env, argv[PARAM2], authTrustLevel));
206     NAPI_CALL(env, UserAuthNapiHelper::CheckNapiType(env, argv[PARAM3], napi_object));
207     napi_value onResultValue;
208     NAPI_CALL(env, napi_get_named_property(env, argv[PARAM3], "onResult", &onResultValue));
209     auto resultCallback = Common::MakeShared<JsRefHolder>(env, onResultValue);
210     napi_value onAcquireInfoValue;
211     NAPI_CALL(env, napi_get_named_property(env, argv[PARAM3], "onAcquireInfo", &onAcquireInfoValue));
212     auto acquireCallback = Common::MakeShared<JsRefHolder>(env, onAcquireInfoValue);
213     auto callback = Common::MakeShared<UserAuthCallbackV8>(env, resultCallback, acquireCallback);
214     if (callback == nullptr) {
215         IAM_LOGE("callback is nullptr");
216         return nullptr;
217     }
218     ResultCode checkRet = CheckAuthTypeAndAuthTrustLevel(AuthType(authType), AuthTrustLevel(authTrustLevel));
219     if (checkRet != SUCCESS) {
220         IAM_LOGE("CheckAuthTypeAndAuthTrsutLevel failed");
221         Attributes extraInfo;
222         callback->OnResult(checkRet, extraInfo);
223         napi_value key = UserAuthNapiHelper::Uint64ToNapiUint8Array(env, INVALID_CONTEXT_ID);
224         return key;
225     }
226     uint64_t result = UserAuthClientImpl::Instance().BeginNorthAuthentication(API_VERSION_8, challenge,
227         AuthType(authType), AuthTrustLevel(authTrustLevel), callback);
228     IAM_LOGI("result is %{public}s", GET_MASKED_STRING(result).c_str());
229     napi_value key = UserAuthNapiHelper::Uint64ToNapiUint8Array(env, result);
230     IAM_LOGI("end");
231     return key;
232 }
233 
CancelAuth(napi_env env,napi_callback_info info)234 napi_value UserAuthImpl::CancelAuth(napi_env env, napi_callback_info info)
235 {
236     size_t argc = ARGS_ONE;
237     napi_value argv[ARGS_ONE] = {nullptr};
238     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
239     if (argc != ARGS_ONE) {
240         IAM_LOGE("parms error");
241         return nullptr;
242     }
243     const size_t maxContextIdLen = 8;
244     std::vector<uint8_t> contextIdArray;
245     NAPI_CALL(env, UserAuthNapiHelper::GetUint8ArrayValue(env, argv[PARAM0], maxContextIdLen, contextIdArray));
246     uint64_t contextId;
247     if (memcpy_s(reinterpret_cast<void *>(&contextId), sizeof(contextId),
248         contextIdArray.data(), contextIdArray.size()) != EOK) {
249         IAM_LOGE("memcpy error");
250         return nullptr;
251     }
252     IAM_LOGI("contextId's low 16 bits is %{public}s", GET_MASKED_STRING(contextId).c_str());
253     if (contextId == 0) {
254         IAM_LOGE("invalid error");
255         return nullptr;
256     }
257     int32_t result = UserAuthClient::GetInstance().CancelAuthentication(contextId);
258     IAM_LOGI("result = %{public}d", result);
259     napi_value key;
260     NAPI_CALL(env, napi_create_int32(env, UserAuthNapiHelper::GetResultCodeV8(result), &key));
261     return key;
262 }
263 
CheckAuthTypeAndAuthTrustLevel(AuthType authType,AuthTrustLevel authTrustLevel)264 ResultCode UserAuthImpl::CheckAuthTypeAndAuthTrustLevel(AuthType authType, AuthTrustLevel authTrustLevel)
265 {
266     if (authType != FINGERPRINT && authType != FACE) {
267         IAM_LOGE("authType check fail:%{public}d", authType);
268         return TYPE_NOT_SUPPORT;
269     }
270     if (authTrustLevel != ATL1 && authTrustLevel != ATL2 && authTrustLevel != ATL3 && authTrustLevel != ATL4) {
271         IAM_LOGE("authTrustLevel check fail:%{public}d", authTrustLevel);
272         return TRUST_LEVEL_NOT_SUPPORT;
273     }
274     return SUCCESS;
275 }
276 } // namespace UserAuth
277 } // namespace UserIam
278 } // namespace OHOS
279