1 /*
2 * Copyright (c) 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 "napi_domain_auth_callback.h"
17
18 #include <uv.h>
19 #include "account_error_no.h"
20 #include "account_log_wrapper.h"
21 #include "napi/native_api.h"
22 #include "napi/native_node_api.h"
23 #include "napi_account_common.h"
24 #include "napi_account_error.h"
25
26 namespace OHOS {
27 namespace AccountJsKit {
28 namespace {
29 const size_t ARGS_SIZE_TWO = 2;
30 }
31 using namespace AccountSA;
32
NapiDomainAuthCallback(const std::shared_ptr<DomainAccountCallback> & callback)33 NapiDomainAuthCallback::NapiDomainAuthCallback(const std::shared_ptr<DomainAccountCallback> &callback)
34 : callback_(callback)
35 {}
36
~NapiDomainAuthCallback()37 NapiDomainAuthCallback::~NapiDomainAuthCallback()
38 {}
39
GetDomainAuthCallback()40 std::shared_ptr<DomainAccountCallback> NapiDomainAuthCallback::GetDomainAuthCallback()
41 {
42 return callback_;
43 }
44
Init(napi_env env,napi_value exports)45 napi_value NapiDomainAuthCallback::Init(napi_env env, napi_value exports)
46 {
47 napi_property_descriptor properties[] = {
48 DECLARE_NAPI_FUNCTION("onResult", JsOnResult),
49 };
50 const std::string className = "DomainAuthCallback";
51 napi_value constructor = nullptr;
52 NAPI_CALL(env, napi_define_class(env, className.c_str(), className.length(), JsConstructor, nullptr,
53 sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor));
54 NAPI_ASSERT(env, constructor != nullptr, "define js class DomainAuthCallback failed");
55 napi_status status = napi_set_named_property(env, exports, className.c_str(), constructor);
56 NAPI_ASSERT(env, status == napi_ok, "set property DomainAuthCallback to exports failed");
57 napi_value global = nullptr;
58 status = napi_get_global(env, &global);
59 NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
60 status = napi_set_named_property(env, global, className.c_str(), constructor);
61 NAPI_ASSERT(env, status == napi_ok, "set constructor to global failed");
62 return exports;
63 }
64
ParseDoaminAuthResult(napi_env env,napi_value value,DomainAuthResult & authResult)65 static bool ParseDoaminAuthResult(napi_env env, napi_value value, DomainAuthResult &authResult)
66 {
67 bool hasProp = false;
68 napi_has_named_property(env, value, "token", &hasProp);
69 if (hasProp) {
70 napi_value napiToken = nullptr;
71 napi_get_named_property(env, value, "token", &napiToken);
72 if (ParseUint8TypedArrayToVector(env, napiToken, authResult.token) != napi_ok) {
73 ACCOUNT_LOGE("failed to parse token");
74 return false;
75 }
76 }
77 hasProp = false;
78 napi_has_named_property(env, value, "remainTimes", &hasProp);
79 if (hasProp) {
80 napi_value napiRemainTimes = nullptr;
81 napi_get_named_property(env, value, "remainTimes", &napiRemainTimes);
82 if (!GetIntProperty(env, napiRemainTimes, authResult.authStatusInfo.remainingTimes)) {
83 ACCOUNT_LOGE("failed to parse remainTimes");
84 return false;
85 }
86 } else {
87 authResult.authStatusInfo.remainingTimes = -1;
88 }
89 hasProp = false;
90 napi_has_named_property(env, value, "freezingTime", &hasProp);
91 if (hasProp) {
92 napi_value napiFreezingTime = nullptr;
93 napi_get_named_property(env, value, "freezingTime", &napiFreezingTime);
94 if (!GetIntProperty(env, napiFreezingTime, authResult.authStatusInfo.freezingTime)) {
95 ACCOUNT_LOGE("failed to parse freezingTime");
96 return false;
97 }
98 } else {
99 authResult.authStatusInfo.freezingTime = -1;
100 }
101 return true;
102 }
103
ParseContextForOnResult(napi_env env,napi_callback_info cbInfo,CallbackParam * param)104 static bool ParseContextForOnResult(napi_env env, napi_callback_info cbInfo, CallbackParam *param)
105 {
106 size_t argc = ARGS_SIZE_TWO;
107 napi_value argv[ARGS_SIZE_TWO] = {0};
108 napi_value thisVar = nullptr;
109 napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, nullptr);
110 if (argc != ARGS_SIZE_TWO) {
111 ACCOUNT_LOGE("the number of parameter should be two");
112 return false;
113 }
114 NapiDomainAuthCallback *napiCallback = nullptr;
115 napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCallback));
116 if (napiCallback == nullptr) {
117 ACCOUNT_LOGE("the napi callback is nullptr");
118 return false;
119 }
120 param->callback = napiCallback->GetDomainAuthCallback();
121 NAPI_CALL_BASE(env, napi_get_value_int32(env, argv[0], &(param->errCode)), false);
122 return ParseDoaminAuthResult(env, argv[1], param->authResult);
123 }
124
JsOnResult(napi_env env,napi_callback_info cbInfo)125 napi_value NapiDomainAuthCallback::JsOnResult(napi_env env, napi_callback_info cbInfo)
126 {
127 auto *param = new (std::nothrow) CallbackParam(env);
128 if (param == nullptr) {
129 ACCOUNT_LOGE("insufficient memory for param!");
130 return nullptr;
131 }
132 std::unique_ptr<CallbackParam> paramPtr(param);
133 if (!ParseContextForOnResult(env, cbInfo, param)) {
134 std::string errMsg = "fail to parse onResult parameters";
135 AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
136 return nullptr;
137 }
138 napi_value resourceName = nullptr;
139 NAPI_CALL(env, napi_create_string_latin1(env, "JsOnResult", NAPI_AUTO_LENGTH, &resourceName));
140 NAPI_CALL(env, napi_create_async_work(env, nullptr, resourceName,
141 [](napi_env env, void *data) {
142 if (data == nullptr) {
143 ACCOUNT_LOGE("data is nullptr");
144 return;
145 }
146 CallbackParam *param = reinterpret_cast<CallbackParam *>(data);
147 if (param->callback == nullptr) {
148 ACCOUNT_LOGE("callback is nullptr");
149 return;
150 }
151 Parcel parcel;
152 if (!param->authResult.Marshalling(parcel)) {
153 ACCOUNT_LOGE("authResult Marshalling failed");
154 return;
155 }
156 param->callback->OnResult(param->errCode, parcel);
157 },
158 [](napi_env env, napi_status status, void *data) {
159 delete reinterpret_cast<CallbackParam *>(data);
160 },
161 reinterpret_cast<void *>(param), ¶m->work));
162 NAPI_CALL(env, napi_queue_async_work_with_qos(env, param->work, napi_qos_user_initiated));
163 paramPtr.release();
164 return nullptr;
165 }
166
JsConstructor(napi_env env,napi_callback_info info)167 napi_value NapiDomainAuthCallback::JsConstructor(napi_env env, napi_callback_info info)
168 {
169 napi_value thisVar = nullptr;
170 size_t argc = 1;
171 napi_value argv[1] = { nullptr };
172 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
173 NAPI_ASSERT(env, status == napi_ok, "napi get callback info failed");
174 return thisVar;
175 }
176
NapiDomainAccountCallback(napi_env env,std::shared_ptr<JsDomainAccountAuthCallback> & callback)177 NapiDomainAccountCallback::NapiDomainAccountCallback(napi_env env,
178 std::shared_ptr<JsDomainAccountAuthCallback> &callback) : env_(env), callback_(callback)
179 {}
180
~NapiDomainAccountCallback()181 NapiDomainAccountCallback::~NapiDomainAccountCallback()
182 {}
183
DomainAuthResultWork(uv_work_t * work,int status)184 static void DomainAuthResultWork(uv_work_t *work, int status)
185 {
186 std::unique_ptr<uv_work_t> workPtr(work);
187 napi_handle_scope scope = nullptr;
188 if (!InitUvWorkCallbackEnv(work, scope)) {
189 return;
190 }
191 std::unique_ptr<DomainAccountAuthCallbackParam> param(
192 reinterpret_cast<DomainAccountAuthCallbackParam *>(work->data));
193 napi_value argv[ARGS_SIZE_TWO] = {nullptr};
194 napi_create_int32(param->env, param->errCode, &argv[0]);
195 argv[1] = CreateAuthResult(param->env, param->authResult.token,
196 param->authResult.authStatusInfo.remainingTimes, param->authResult.authStatusInfo.freezingTime);
197 NapiCallVoidFunction(param->env, argv, ARGS_SIZE_TWO, param->callback->onResult);
198 napi_close_handle_scope(param->env, scope);
199 }
200
OnResult(const int32_t errCode,Parcel & parcel)201 void NapiDomainAccountCallback::OnResult(const int32_t errCode, Parcel &parcel)
202 {
203 std::lock_guard<std::mutex> lock(mutex_);
204 if (callback_->onResultCalled) {
205 ACCOUNT_LOGE("call twice is not allowed");
206 return;
207 }
208 callback_->onResultCalled = true;
209 std::unique_ptr<uv_work_t> work = std::make_unique<uv_work_t>();
210 std::unique_ptr<DomainAccountAuthCallbackParam> param =
211 std::make_unique<DomainAccountAuthCallbackParam>(env_);
212 uv_loop_s *loop = nullptr;
213 NAPI_CALL_RETURN_VOID(env_, napi_get_uv_event_loop(env_, &loop));
214 if (loop == nullptr || work == nullptr || param == nullptr) {
215 ACCOUNT_LOGE("fail for nullptr");
216 return;
217 }
218 param->errCode = errCode;
219 std::shared_ptr<DomainAuthResult> authResult(DomainAuthResult::Unmarshalling(parcel));
220 if (authResult == nullptr) {
221 ACCOUNT_LOGE("authResult is nullptr");
222 return;
223 }
224 param->authResult = (*authResult);
225 param->callback = callback_;
226 work->data = reinterpret_cast<void *>(param.get());
227 ErrCode ret = uv_queue_work_with_qos(
228 loop, work.get(), [] (uv_work_t *work) {}, DomainAuthResultWork, uv_qos_user_initiated);
229 if (ret != ERR_OK) {
230 ACCOUNT_LOGE("fail to queue work");
231 return;
232 }
233 work.release();
234 param.release();
235 }
236 } // namespace AccountJsKit
237 } // namespace OHOS
238