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_callback_v9.h"
17 
18 #include <optional>
19 #include <uv.h>
20 
21 #include "iam_logger.h"
22 
23 #define LOG_TAG "USER_AUTH_NAPI"
24 
25 namespace OHOS {
26 namespace UserIam {
27 namespace UserAuth {
28 namespace {
29 struct ResultCallbackV9Holder {
30     std::shared_ptr<UserAuthCallbackV9> callback {nullptr};
31     int32_t result {0};
32     std::vector<uint8_t> token {};
33     std::optional<int32_t> remainTimes {std::nullopt};
34     std::optional<int32_t> freezingTime {std::nullopt};
35     napi_env env;
36 };
37 
38 struct AcquireCallbackV9Holder {
39     std::shared_ptr<UserAuthCallbackV9> callback {nullptr};
40     int32_t module {0};
41     uint32_t acquireInfo {0};
42     napi_env env;
43 };
44 
DestoryResultWork(uv_work_t * work)45 void DestoryResultWork(uv_work_t *work)
46 {
47     if (work == nullptr) {
48         return;
49     }
50     if (work->data != nullptr) {
51         delete (reinterpret_cast<ResultCallbackV9Holder *>(work->data));
52     }
53     delete work;
54 }
55 
DestoryAcquireWork(uv_work_t * work)56 void DestoryAcquireWork(uv_work_t *work)
57 {
58     if (work == nullptr) {
59         return;
60     }
61     if (work->data != nullptr) {
62         delete (reinterpret_cast<AcquireCallbackV9Holder *>(work->data));
63     }
64     delete work;
65 }
66 
OnResultV9Work(uv_work_t * work,int status)67 void OnResultV9Work(uv_work_t *work, int status)
68 {
69     IAM_LOGI("start");
70     if (work == nullptr) {
71         IAM_LOGE("work is null");
72         return;
73     }
74     ResultCallbackV9Holder *resultHolder = reinterpret_cast<ResultCallbackV9Holder *>(work->data);
75     if (resultHolder == nullptr || resultHolder->callback == nullptr) {
76         IAM_LOGE("resultHolder is invalid");
77         DestoryResultWork(work);
78         return;
79     }
80     napi_handle_scope scope = nullptr;
81     napi_open_handle_scope(resultHolder->env, &scope);
82     if (scope == nullptr) {
83         IAM_LOGE("scope is invalid");
84         DestoryResultWork(work);
85         return;
86     }
87     napi_status ret = resultHolder->callback->DoResultCallback(resultHolder->result, resultHolder->token,
88         resultHolder->remainTimes, resultHolder->freezingTime);
89     if (ret != napi_ok) {
90         IAM_LOGE("DoResultCallback fail %{public}d", ret);
91         napi_close_handle_scope(resultHolder->env, scope);
92         DestoryResultWork(work);
93         return;
94     }
95     napi_close_handle_scope(resultHolder->env, scope);
96     DestoryResultWork(work);
97 }
98 
OnAcquireV9Work(uv_work_t * work,int status)99 void OnAcquireV9Work(uv_work_t *work, int status)
100 {
101     IAM_LOGI("start");
102     if (work == nullptr) {
103         IAM_LOGE("work is null");
104         return;
105     }
106     AcquireCallbackV9Holder *acquireHolder = reinterpret_cast<AcquireCallbackV9Holder *>(work->data);
107     if (acquireHolder == nullptr || acquireHolder->callback == nullptr) {
108         IAM_LOGE("acquireHolder is invalid");
109         DestoryAcquireWork(work);
110         return;
111     }
112     napi_handle_scope scope = nullptr;
113     napi_open_handle_scope(acquireHolder->env, &scope);
114     if (scope == nullptr) {
115         IAM_LOGE("scope is invalid");
116         DestoryAcquireWork(work);
117         return;
118     }
119     napi_status ret = acquireHolder->callback->DoAcquireCallback(acquireHolder->module, acquireHolder->acquireInfo);
120     if (ret != napi_ok) {
121         IAM_LOGE("DoAcquireCallback fail %{public}d", ret);
122         napi_close_handle_scope(acquireHolder->env, scope);
123         DestoryAcquireWork(work);
124         return;
125     }
126     napi_close_handle_scope(acquireHolder->env, scope);
127     DestoryAcquireWork(work);
128 }
129 }
130 
UserAuthCallbackV9(napi_env env)131 UserAuthCallbackV9::UserAuthCallbackV9(napi_env env) : env_(env)
132 {
133     if (env_ == nullptr) {
134         IAM_LOGE("UserAuthCallbackV9 get null env");
135     }
136 }
137 
~UserAuthCallbackV9()138 UserAuthCallbackV9::~UserAuthCallbackV9()
139 {
140 }
141 
SetResultCallback(const std::shared_ptr<JsRefHolder> & resultCallback)142 void UserAuthCallbackV9::SetResultCallback(const std::shared_ptr<JsRefHolder> &resultCallback)
143 {
144     std::lock_guard<std::mutex> guard(mutex_);
145     resultCallback_ = resultCallback;
146 }
147 
ClearResultCallback()148 void UserAuthCallbackV9::ClearResultCallback()
149 {
150     std::lock_guard<std::mutex> guard(mutex_);
151     resultCallback_ = nullptr;
152 }
153 
SetAcquireCallback(const std::shared_ptr<JsRefHolder> & acquireCallback)154 void UserAuthCallbackV9::SetAcquireCallback(const std::shared_ptr<JsRefHolder> &acquireCallback)
155 {
156     std::lock_guard<std::mutex> guard(mutex_);
157     acquireCallback_ = acquireCallback;
158 }
159 
ClearAcquireCallback()160 void UserAuthCallbackV9::ClearAcquireCallback()
161 {
162     std::lock_guard<std::mutex> guard(mutex_);
163     acquireCallback_ = nullptr;
164 }
165 
GetResultCallback()166 std::shared_ptr<JsRefHolder> UserAuthCallbackV9::GetResultCallback()
167 {
168     std::lock_guard<std::mutex> guard(mutex_);
169     return resultCallback_;
170 }
171 
GetAcquireCallback()172 std::shared_ptr<JsRefHolder> UserAuthCallbackV9::GetAcquireCallback()
173 {
174     std::lock_guard<std::mutex> guard(mutex_);
175     return acquireCallback_;
176 }
177 
DoResultCallback(int32_t result,const std::vector<uint8_t> & token,std::optional<int32_t> & remainTimes,std::optional<int32_t> & freezingTime)178 napi_status UserAuthCallbackV9::DoResultCallback(int32_t result, const std::vector<uint8_t> &token,
179     std::optional<int32_t> &remainTimes, std::optional<int32_t> &freezingTime)
180 {
181     auto resultCallback = GetResultCallback();
182     if (resultCallback == nullptr) {
183         return napi_ok;
184     }
185     IAM_LOGI("start");
186     napi_value eventInfo;
187     napi_status ret = napi_create_object(env_, &eventInfo);
188     if (ret != napi_ok) {
189         IAM_LOGE("napi_create_object failed %{public}d", ret);
190         return ret;
191     }
192     ret = UserAuthNapiHelper::SetInt32Property(env_, eventInfo, "result", result);
193     if (ret != napi_ok) {
194         IAM_LOGE("napi_create_int32 failed %{public}d", ret);
195         return ret;
196     }
197     ret = UserAuthNapiHelper::SetUint8ArrayProperty(env_, eventInfo, "token", token);
198     if (ret != napi_ok) {
199         IAM_LOGE("SetUint8ArrayProperty failed %{public}d", ret);
200         return ret;
201     }
202 
203     if (remainTimes.has_value()) {
204         ret = UserAuthNapiHelper::SetInt32Property(env_, eventInfo, "remainAttempts", remainTimes.value());
205         if (ret != napi_ok) {
206             IAM_LOGE("SetInt32Property failed %{public}d", ret);
207             return ret;
208         }
209     }
210 
211     if (freezingTime.has_value()) {
212         ret = UserAuthNapiHelper::SetInt32Property(env_, eventInfo, "lockoutDuration", freezingTime.value());
213         if (ret != napi_ok) {
214             IAM_LOGE("SetInt32Property failed %{public}d", ret);
215             return ret;
216         }
217     }
218 
219     return UserAuthNapiHelper::CallVoidNapiFunc(env_, resultCallback->Get(), ARGS_ONE, &eventInfo);
220 }
221 
DoAcquireCallback(int32_t module,uint32_t acquireInfo)222 napi_status UserAuthCallbackV9::DoAcquireCallback(int32_t module, uint32_t acquireInfo)
223 {
224     auto acquireCallback = GetAcquireCallback();
225     if (acquireCallback == nullptr) {
226         return napi_ok;
227     }
228     IAM_LOGI("start");
229     napi_value eventInfo;
230     napi_status ret = napi_create_object(env_, &eventInfo);
231     if (ret != napi_ok) {
232         IAM_LOGE("napi_create_object failed %{public}d", ret);
233         return ret;
234     }
235     ret = UserAuthNapiHelper::SetInt32Property(env_, eventInfo, "module", module);
236     if (ret != napi_ok) {
237         IAM_LOGE("napi_create_int32 failed %{public}d", ret);
238         return ret;
239     }
240     ret = UserAuthNapiHelper::SetUint32Property(env_, eventInfo, "tip", acquireInfo);
241     if (ret != napi_ok) {
242         IAM_LOGE("SetUint32Property failed %{public}d", ret);
243         return ret;
244     }
245     return UserAuthNapiHelper::CallVoidNapiFunc(env_, acquireCallback->Get(), ARGS_ONE, &eventInfo);
246 }
247 
OnAcquireInfo(int32_t module,uint32_t acquireInfo,const UserIam::UserAuth::Attributes & extraInfo)248 void UserAuthCallbackV9::OnAcquireInfo(int32_t module, uint32_t acquireInfo,
249     const UserIam::UserAuth::Attributes &extraInfo)
250 {
251     IAM_LOGI("start module:%{public}d acquireInfo:%{public}u", module, acquireInfo);
252     uv_loop_s *loop;
253     napi_status napiStatus = napi_get_uv_event_loop(env_, &loop);
254     if (napiStatus != napi_ok || loop == nullptr) {
255         IAM_LOGE("napi_get_uv_event_loop fail");
256         return;
257     }
258     uv_work_t *work = new (std::nothrow) uv_work_t;
259     if (work == nullptr) {
260         IAM_LOGE("work is null");
261         return;
262     }
263     AcquireCallbackV9Holder *acquireHolder = new (std::nothrow) AcquireCallbackV9Holder();
264     if (acquireHolder == nullptr) {
265         IAM_LOGE("acquireHolder is null");
266         delete work;
267         return;
268     }
269     acquireHolder->callback = shared_from_this();
270     acquireHolder->module = module;
271     acquireHolder->acquireInfo = acquireInfo;
272     acquireHolder->env = env_;
273     work->data = reinterpret_cast<void *>(acquireHolder);
274     if (uv_queue_work_with_qos(loop, work, [](uv_work_t *work) {}, OnAcquireV9Work, uv_qos_user_initiated) != 0) {
275         IAM_LOGE("uv_qos_user_initiated fail");
276         DestoryAcquireWork(work);
277     }
278 }
279 
OnResult(int32_t result,const Attributes & extraInfo)280 void UserAuthCallbackV9::OnResult(int32_t result, const Attributes &extraInfo)
281 {
282     IAM_LOGI("start, result:%{public}d", result);
283     uv_loop_s *loop;
284     napi_status napiStatus = napi_get_uv_event_loop(env_, &loop);
285     if (napiStatus != napi_ok || loop == nullptr) {
286         IAM_LOGE("napi_get_uv_event_loop fail");
287         return;
288     }
289     uv_work_t *work = new (std::nothrow) uv_work_t;
290     if (work == nullptr) {
291         IAM_LOGE("work is null");
292         return;
293     }
294     ResultCallbackV9Holder *resultHolder = new (std::nothrow) ResultCallbackV9Holder();
295     if (resultHolder == nullptr) {
296         IAM_LOGE("resultHolder is null");
297         delete work;
298         return;
299     }
300     resultHolder->callback = shared_from_this();
301     resultHolder->result = UserAuthNapiHelper::GetResultCodeV9(result);
302     resultHolder->env = env_;
303     if (!extraInfo.GetUint8ArrayValue(Attributes::ATTR_SIGNATURE, resultHolder->token)) {
304         IAM_LOGE("ATTR_SIGNATURE is null");
305     }
306 
307     int32_t remainTimes = 0;
308     if (extraInfo.GetInt32Value(Attributes::ATTR_REMAIN_TIMES, remainTimes)) {
309         resultHolder->remainTimes = remainTimes;
310     } else {
311         IAM_LOGE("ATTR_REMAIN_TIMES is null");
312     }
313 
314     int32_t freezingTime = INT32_MAX;
315     if (extraInfo.GetInt32Value(Attributes::ATTR_FREEZING_TIME, freezingTime)) {
316         resultHolder->freezingTime = freezingTime;
317     } else {
318         IAM_LOGE("ATTR_FREEZING_TIME is null");
319     }
320 
321     work->data = reinterpret_cast<void *>(resultHolder);
322     if (uv_queue_work_with_qos(loop, work, [](uv_work_t *work) {}, OnResultV9Work, uv_qos_user_initiated) != 0) {
323         IAM_LOGE("uv_queue_work_with_qos fail");
324         DestoryResultWork(work);
325     }
326 }
327 } // namespace UserAuth
328 } // namespace UserIam
329 } // namespace OHOS
330