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_account_manager.h"
17 
18 #include <uv.h>
19 #include <memory>
20 #include "account_log_wrapper.h"
21 #include "domain_account_client.h"
22 #include "napi/native_api.h"
23 #include "napi/native_node_api.h"
24 #include "napi_account_common.h"
25 #include "napi_account_error.h"
26 #include "napi_common.h"
27 #include "napi_domain_account_common.h"
28 #include "napi_domain_auth_callback.h"
29 
30 namespace OHOS {
31 namespace AccountJsKit {
32 namespace {
33 const size_t ARG_SIZE_ONE = 1;
34 const size_t ARG_SIZE_TWO = 2;
35 const size_t ARG_SIZE_THREE = 3;
36 const size_t PARAM_ONE = 1;
37 const size_t PARAM_ZERO = 0;
38 }
39 
40 using namespace OHOS::AccountSA;
41 
InitDomainPluginExecEnv(napi_env env,uv_loop_s ** loop,uv_work_t ** work,JsDomainPluginParam ** param,ThreadLockInfo * lockInfo)42 static bool InitDomainPluginExecEnv(
43     napi_env env, uv_loop_s **loop, uv_work_t **work, JsDomainPluginParam **param, ThreadLockInfo *lockInfo)
44 {
45     if (!CreateExecEnv(env, loop, work)) {
46         return false;
47     }
48     *param = new (std::nothrow) JsDomainPluginParam(env);
49     if (*param == nullptr) {
50         ACCOUNT_LOGE("failed to create JsDomainPluginParam");
51         delete *work;
52         *work = nullptr;
53         return false;
54     }
55     (*param)->lockInfo = lockInfo;
56     (*work)->data = reinterpret_cast<void *>(*param);
57     return true;
58 }
59 
CreatePluginAsyncCallback(napi_env env,napi_callback callback,JsDomainPluginParam * param)60 static napi_value CreatePluginAsyncCallback(napi_env env, napi_callback callback, JsDomainPluginParam *param)
61 {
62     napi_value napiCallback = nullptr;
63     napi_status status = napi_create_function(env, "callback", NAPI_AUTO_LENGTH, callback, param, &napiCallback);
64     if (status != napi_ok) {
65         ACCOUNT_LOGE("failed to create js function");
66         return nullptr;
67     }
68     status = napi_wrap(env, napiCallback, param,
69         [](napi_env env, void *data, void *hint) {
70             ACCOUNT_LOGI("release JsDomainPluginParam");
71             delete reinterpret_cast<JsDomainPluginParam *>(data);
72         }, nullptr, nullptr);
73     if (status != napi_ok) {
74         ACCOUNT_LOGE("failed to wrap callback with JsDomainPluginParam");
75         return nullptr;
76     }
77     return napiCallback;
78 }
79 
GetPluginCallbackCommonParam(napi_env env,napi_callback_info cbInfo,JsDomainPluginParam ** param,BusinessError & error,napi_value * businessData)80 static bool GetPluginCallbackCommonParam(napi_env env, napi_callback_info cbInfo,
81     JsDomainPluginParam **param, BusinessError &error, napi_value *businessData)
82 {
83     size_t argc = ARG_SIZE_TWO;
84     napi_value argv[ARG_SIZE_TWO] = {nullptr};
85     void *data = nullptr;
86     NAPI_CALL_BASE(env, napi_get_cb_info(env, cbInfo, &argc, argv, nullptr, &data), false);
87     if (argc < ARG_SIZE_ONE) {
88         ACCOUNT_LOGE("the number of argument should be at least 1");
89         return false;
90     }
91     *param = reinterpret_cast<JsDomainPluginParam *>(data);
92     if ((*param == nullptr) || ((*param)->callback == nullptr)) {
93         ACCOUNT_LOGE("native callback is nullptr");
94         return false;
95     }
96     if (!ParseBusinessError(env, argv[0], error)) {
97         ACCOUNT_LOGE("ParseBussinessError failed");
98         return false;
99     }
100     if (argc == ARG_SIZE_TWO) {
101         *businessData = argv[1];
102     }
103     return true;
104 }
105 
CreateNapiDomainAccountInfo(napi_env env,const DomainAccountInfo & domainAccountInfo)106 static napi_value CreateNapiDomainAccountInfo(napi_env env, const DomainAccountInfo &domainAccountInfo)
107 {
108     napi_value napiInfo = nullptr;
109     NAPI_CALL(env, napi_create_object(env, &napiInfo));
110     napi_value napiName = nullptr;
111     NAPI_CALL(env, napi_create_string_utf8(env, domainAccountInfo.accountName_.c_str(), NAPI_AUTO_LENGTH, &napiName));
112     NAPI_CALL(env, napi_set_named_property(env, napiInfo, "accountName", napiName));
113     napi_value napiDomain = nullptr;
114     NAPI_CALL(env, napi_create_string_utf8(env, domainAccountInfo.domain_.c_str(), NAPI_AUTO_LENGTH, &napiDomain));
115     NAPI_CALL(env, napi_set_named_property(env, napiInfo, "domain", napiDomain));
116     napi_value napiAccountId = nullptr;
117     NAPI_CALL(
118         env, napi_create_string_utf8(env, domainAccountInfo.accountId_.c_str(), NAPI_AUTO_LENGTH, &napiAccountId));
119     NAPI_CALL(env, napi_set_named_property(env, napiInfo, "accountId", napiAccountId));
120     return napiInfo;
121 }
122 
CreateNapiGetAccessTokenOptions(const JsDomainPluginParam * param)123 static napi_value CreateNapiGetAccessTokenOptions(const JsDomainPluginParam *param)
124 {
125     napi_value napiOptions = nullptr;
126     NAPI_CALL(param->env, napi_create_object(param->env, &napiOptions));
127     napi_value napiDomainAccountInfo = CreateNapiDomainAccountInfo(param->env, param->domainAccountInfo);
128     NAPI_CALL(param->env, napi_set_named_property(param->env, napiOptions, "domainAccountInfo", napiDomainAccountInfo));
129     napi_value napiAccountToken = CreateUint8Array(param->env, param->authData.data(), param->authData.size());
130     NAPI_CALL(param->env, napi_set_named_property(param->env, napiOptions, "domainAccountToken", napiAccountToken));
131     napi_value napiParam = AppExecFwk::WrapWantParams(param->env, param->option.getTokenParams_);
132     NAPI_CALL(param->env, napi_set_named_property(param->env, napiOptions, "businessParams", napiParam));
133     napi_value napiUid = nullptr;
134     NAPI_CALL(param->env, napi_create_int32(param->env, param->option.callingUid_, &napiUid));
135     NAPI_CALL(param->env, napi_set_named_property(param->env, napiOptions, "callerUid", napiUid));
136     return napiOptions;
137 }
138 
CreateNapiDomainAuthCallback(napi_env env,const std::shared_ptr<DomainAccountCallback> & nativeCallback)139 static napi_value CreateNapiDomainAuthCallback(
140     napi_env env, const std::shared_ptr<DomainAccountCallback> &nativeCallback)
141 {
142     napi_value napiCallback = nullptr;
143     napi_value global = nullptr;
144     napi_get_global(env, &global);
145     if (global == nullptr) {
146         ACCOUNT_LOGE("failed to get napi global");
147         return napiCallback;
148     }
149     napi_value jsConstructor = nullptr;
150     napi_get_named_property(env, global, "DomainAuthCallback", &jsConstructor);
151     if (jsConstructor == nullptr) {
152         ACCOUNT_LOGE("jsConstructor is nullptr");
153         return napiCallback;
154     }
155     napi_new_instance(env, jsConstructor, 0, nullptr, &napiCallback);
156     auto domainAuthCallback = new (std::nothrow) NapiDomainAuthCallback(nativeCallback);
157     if (domainAuthCallback == nullptr) {
158         ACCOUNT_LOGE("failed to create NapiDomainAuthCallback");
159         return nullptr;
160     }
161     napi_status status = napi_wrap(env, napiCallback, domainAuthCallback,
162         [](napi_env env, void *data, void *hint) {
163             delete (reinterpret_cast<NapiDomainAuthCallback *>(data));
164         }, nullptr, nullptr);
165     if (status != napi_ok) {
166         ACCOUNT_LOGE("wrap js DomainAuthCallback and native callback failed");
167         delete domainAuthCallback;
168         return nullptr;
169     }
170     return napiCallback;
171 }
172 
ParseAuthStatusInfo(napi_env env,napi_value value,AuthStatusInfo & info)173 static bool ParseAuthStatusInfo(napi_env env, napi_value value, AuthStatusInfo &info)
174 {
175     napi_value napiRemainTimes = nullptr;
176     NAPI_CALL_BASE(env, napi_get_named_property(env, value, "remainTimes", &napiRemainTimes), false);
177     if (napiRemainTimes == nullptr) {
178         ACCOUNT_LOGE("remainTimes is undefined");
179         return false;
180     }
181     NAPI_CALL_BASE(env, napi_get_value_int32(env, napiRemainTimes, &info.remainingTimes), false);
182     napi_value napiFreezingTime = nullptr;
183     NAPI_CALL_BASE(env, napi_get_named_property(env, value, "freezingTime", &napiFreezingTime), false);
184     if (napiFreezingTime == nullptr) {
185         ACCOUNT_LOGE("freezingTime is undefined");
186         return false;
187     }
188     NAPI_CALL_BASE(env, napi_get_value_int32(env, napiFreezingTime, &info.freezingTime), false);
189     return true;
190 }
191 
ParseParamForUpdateAccountToken(napi_env env,napi_callback_info cbInfo,UpdateAccountTokenAsyncContext * asyncContext)192 static bool ParseParamForUpdateAccountToken(
193     napi_env env, napi_callback_info cbInfo, UpdateAccountTokenAsyncContext *asyncContext)
194 {
195     size_t argc = ARG_SIZE_THREE;
196     napi_value argv[ARG_SIZE_THREE] = {0};
197     napi_get_cb_info(env, cbInfo, &argc, argv, nullptr, nullptr);
198     if (argc < ARG_SIZE_TWO) {
199         ACCOUNT_LOGE("the parameter number for updating account token should be at least two");
200         std::string errMsg = "Parameter error. The number of parameters should be at least 2";
201         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
202         return false;
203     }
204     if (argc == ARG_SIZE_THREE) {
205         if (!GetCallbackProperty(env, argv[argc - 1], asyncContext->callbackRef, 1)) {
206             ACCOUNT_LOGE("failed to get callbackRef for updating account token");
207             std::string errMsg = "Parameter error. The type of \"callback\" must be function";
208             AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
209             return false;
210         }
211     }
212     if (!ParseDomainAccountInfo(env, argv[0], asyncContext->domainInfo)) {
213         ACCOUNT_LOGE("get domainInfo failed");
214         std::string errMsg = "Parameter error. The type of \"domainAccountInfo\" must be DomainAccountInfo";
215         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
216         return false;
217     }
218     if (ParseUint8TypedArrayToVector(env, argv[PARAM_ONE], asyncContext->token) != napi_ok) {
219         ACCOUNT_LOGE("get token failed");
220         std::string errMsg = "Parameter error. The type of \"token\" must be Uint8Array";
221         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
222         return false;
223     }
224     return true;
225 }
226 
ParseParamForIsAuthenticationExpired(napi_env env,napi_callback_info cbInfo,IsAuthenticationExpiredAsyncContext * asyncContext)227 static bool ParseParamForIsAuthenticationExpired(
228     napi_env env, napi_callback_info cbInfo, IsAuthenticationExpiredAsyncContext *asyncContext)
229 {
230     size_t argc = ARG_SIZE_ONE;
231     napi_value argv[ARG_SIZE_ONE] = {0};
232     napi_get_cb_info(env, cbInfo, &argc, argv, nullptr, nullptr);
233     if (argc < ARG_SIZE_ONE) {
234         ACCOUNT_LOGE("The number of parameters should be at least 1.");
235         std::string errMsg = "Parameter error. The number of parameters should be at least 1";
236         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
237         return false;
238     }
239     if (!ParseDomainAccountInfo(env, argv[PARAM_ZERO], asyncContext->domainInfo)) {
240         ACCOUNT_LOGE("Get domainInfo failed.");
241         std::string errMsg = "Parameter error. The type of \"domainAccountInfo\" must be DomainAccountInfo";
242         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
243         return false;
244     }
245     return true;
246 }
247 
ParseParamForGetAccessByAccount(napi_env env,const napi_value * argv,size_t argc,GetAccessTokenAsyncContext * asyncContext)248 static bool ParseParamForGetAccessByAccount(
249     napi_env env, const napi_value *argv, size_t argc, GetAccessTokenAsyncContext *asyncContext)
250 {
251     if ((argc == ARG_SIZE_THREE) && (!GetCallbackProperty(env, argv[argc - 1], asyncContext->callbackRef, 1))) {
252         ACCOUNT_LOGE("failed to get callbackRef for getting access token");
253         return false;
254     }
255     if (!AppExecFwk::UnwrapWantParams(env, argv[PARAM_ONE], asyncContext->getTokenParams)) {
256         ACCOUNT_LOGE("unwrapWantParams failed");
257         return false;
258     }
259     return true;
260 }
261 
ParseParamForGetAccessToken(napi_env env,napi_callback_info cbInfo,GetAccessTokenAsyncContext * asyncContext)262 static bool ParseParamForGetAccessToken(
263     napi_env env, napi_callback_info cbInfo, GetAccessTokenAsyncContext *asyncContext)
264 {
265     size_t argc = ARG_SIZE_THREE;
266     napi_value argv[ARG_SIZE_THREE] = {0};
267     napi_get_cb_info(env, cbInfo, &argc, argv, nullptr, nullptr);
268     if (argc < ARG_SIZE_ONE) {
269         std::string errMsg = "Parameter error. The number of parameters should be at least 1";
270         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
271         return false;
272     }
273     if (ParseDomainAccountInfo(env, argv[0], asyncContext->domainInfo)) {
274         return ParseParamForGetAccessByAccount(env, argv, argc, asyncContext);
275     }
276     if ((argc == ARG_SIZE_TWO) && (!GetCallbackProperty(env, argv[argc - 1], asyncContext->callbackRef, 1))) {
277         ACCOUNT_LOGE("failed to get callbackRef for getting access token");
278         std::string errMsg = "Parameter error. The type of \"callback\" must be function";
279         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
280         return false;
281     }
282     if (!AppExecFwk::UnwrapWantParams(env, argv[0], asyncContext->getTokenParams)) {
283         ACCOUNT_LOGE("unwrapWantParams failed");
284         std::string errMsg = "Parameter error. The type of \"businessParams\" must be Record";
285         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
286         return false;
287     }
288     return true;
289 }
290 
GetDomainAccountInfoCallback(napi_env env,napi_callback_info cbInfo)291 static napi_value GetDomainAccountInfoCallback(napi_env env, napi_callback_info cbInfo)
292 {
293     ACCOUNT_LOGI("GetDomainAccountInfoCallback enter");
294     JsDomainPluginParam *param = nullptr;
295     BusinessError error;
296     napi_value businessData = nullptr;
297     if (!GetPluginCallbackCommonParam(env, cbInfo, &param, error, &businessData)) {
298         AccountNapiThrow(env, ERR_JS_INVALID_PARAMETER, true);
299         return nullptr;
300     }
301     DomainAccountInfo info;
302     if ((error.code == 0) && (!ParseDomainAccountInfo(env, businessData, info))) {
303         ACCOUNT_LOGE("ParseDomainAccountInfo failed");
304         AccountNapiThrow(env, ERR_JS_INVALID_PARAMETER, true);
305         return nullptr;
306     }
307     AAFwk::WantParams getAccountInfoParams;
308     if (!AppExecFwk::UnwrapWantParams(env, businessData, getAccountInfoParams)) {
309         ACCOUNT_LOGE("unwrapWantParams failed");
310         return nullptr;
311     }
312     Parcel parcel;
313     if (!getAccountInfoParams.Marshalling(parcel)) {
314         ACCOUNT_LOGE("info Marshalling failed");
315         AccountNapiThrow(env, ERR_JS_SYSTEM_SERVICE_EXCEPTION, true);
316         return nullptr;
317     }
318     param->callback->OnResult(error.code, parcel);
319     return nullptr;
320 }
321 
CreatePluginAccountInfoOptions(const JsDomainPluginParam * param)322 static napi_value CreatePluginAccountInfoOptions(const JsDomainPluginParam *param)
323 {
324     napi_value napiOptions = nullptr;
325     NAPI_CALL(param->env, napi_create_object(param->env, &napiOptions));
326     napi_value napiName = nullptr;
327     NAPI_CALL(param->env, napi_create_string_utf8(
328         param->env, param->domainAccountInfo.accountName_.c_str(), NAPI_AUTO_LENGTH, &napiName));
329     NAPI_CALL(param->env, napi_set_named_property(param->env, napiOptions, "accountName", napiName));
330     napi_value napiDomain = nullptr;
331     NAPI_CALL(param->env,
332         napi_create_string_utf8(param->env, param->domainAccountInfo.domain_.c_str(), NAPI_AUTO_LENGTH, &napiDomain));
333     NAPI_CALL(param->env, napi_set_named_property(param->env, napiOptions, "domain", napiDomain));
334     napi_value napiCallingUid = nullptr;
335     NAPI_CALL(param->env, napi_create_int32(param->env, param->callingUid, &napiCallingUid));
336     NAPI_CALL(param->env, napi_set_named_property(param->env, napiOptions, "callerUid", napiCallingUid));
337     return napiOptions;
338 }
339 
GetDomainAccountInfoWork(uv_work_t * work,int status)340 static void GetDomainAccountInfoWork(uv_work_t *work, int status)
341 {
342     std::unique_ptr<uv_work_t> workPtr(work);
343     napi_handle_scope scope = nullptr;
344     if (!InitUvWorkCallbackEnv(work, scope)) {
345         return;
346     }
347     JsDomainPluginParam *param = reinterpret_cast<JsDomainPluginParam *>(work->data);
348     napi_value napiCallback = CreatePluginAsyncCallback(param->env, GetDomainAccountInfoCallback, param);
349     napi_value getDomainAccountInfoPLuginOptions = CreatePluginAccountInfoOptions(param);
350     napi_value argv[] = {getDomainAccountInfoPLuginOptions, napiCallback};
351     NapiCallVoidFunction(param->env, argv, ARG_SIZE_TWO, param->func);
352     std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
353     param->lockInfo->count--;
354     param->lockInfo->condition.notify_all();
355     napi_close_handle_scope(param->env, scope);
356     if (napiCallback == nullptr) {
357         delete param;
358     }
359 }
360 
OnAccountBoundCallback(napi_env env,napi_callback_info cbInfo)361 static napi_value OnAccountBoundCallback(napi_env env, napi_callback_info cbInfo)
362 {
363     ACCOUNT_LOGI("OnAccountBoundCallback enter");
364     JsDomainPluginParam *param = nullptr;
365     BusinessError error;
366     napi_value businessData = nullptr;
367     if (!GetPluginCallbackCommonParam(env, cbInfo, &param, error, &businessData)) {
368         AccountNapiThrow(env, ERR_JS_INVALID_PARAMETER, true);
369         return nullptr;
370     }
371     DomainAccountInfo info;
372     Parcel parcel;
373     if (!info.Marshalling(parcel)) {
374         ACCOUNT_LOGE("info Marshalling failed");
375         AccountNapiThrow(env, ERR_JS_SYSTEM_SERVICE_EXCEPTION, true);
376         return nullptr;
377     }
378     if (error.code != 0) {
379         ACCOUNT_LOGI("bind or unbind error, code: %{public}d", error.code);
380     }
381     param->callback->OnResult(error.code, parcel);
382     return nullptr;
383 }
384 
OnAccountBoundWork(uv_work_t * work,int status)385 static void OnAccountBoundWork(uv_work_t *work, int status)
386 {
387     std::unique_ptr<uv_work_t> workPtr(work);
388     napi_handle_scope scope = nullptr;
389     if (!InitUvWorkCallbackEnv(work, scope)) {
390         return;
391     }
392     JsDomainPluginParam *param = reinterpret_cast<JsDomainPluginParam *>(work->data);
393     napi_value napiLocalId = nullptr;
394     napi_create_int32(param->env, param->userId, &napiLocalId);
395     napi_value napiDomainAccountInfo = CreateNapiDomainAccountInfo(param->env, param->domainAccountInfo);
396     napi_value napiCallback = CreatePluginAsyncCallback(param->env, OnAccountBoundCallback, param);
397     napi_value argv[] = {napiDomainAccountInfo, napiLocalId, napiCallback};
398     NapiCallVoidFunction(param->env, argv, ARG_SIZE_THREE, param->func);
399     std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
400     param->lockInfo->count--;
401     param->lockInfo->condition.notify_all();
402     napi_close_handle_scope(param->env, scope);
403     if (napiCallback == nullptr) {
404         delete param;
405     }
406 }
407 
OnAccountUnBoundWork(uv_work_t * work,int status)408 static void OnAccountUnBoundWork(uv_work_t *work, int status)
409 {
410     std::unique_ptr<uv_work_t> workPtr(work);
411     napi_handle_scope scope = nullptr;
412     if (!InitUvWorkCallbackEnv(work, scope)) {
413         return;
414     }
415     JsDomainPluginParam *param = reinterpret_cast<JsDomainPluginParam *>(work->data);
416     napi_value napiDomainAccountInfo = CreateNapiDomainAccountInfo(param->env, param->domainAccountInfo);
417     napi_value napiCallback = CreatePluginAsyncCallback(param->env, OnAccountBoundCallback, param);
418     napi_value argv[] = {napiDomainAccountInfo, napiCallback};
419     NapiCallVoidFunction(param->env, argv, ARG_SIZE_TWO, param->func);
420     std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
421     param->lockInfo->count--;
422     param->lockInfo->condition.notify_all();
423     napi_close_handle_scope(param->env, scope);
424     if (napiCallback == nullptr) {
425         delete param;
426     }
427 }
428 
GetAuthStatusInfoCallback(napi_env env,napi_callback_info cbInfo)429 static napi_value GetAuthStatusInfoCallback(napi_env env, napi_callback_info cbInfo)
430 {
431     ACCOUNT_LOGI("GetAuthStatusInfoCallback enter");
432     JsDomainPluginParam *param = nullptr;
433     BusinessError error;
434     napi_value businessData = nullptr;
435     if (!GetPluginCallbackCommonParam(env, cbInfo, &param, error, &businessData)) {
436         AccountNapiThrow(env, ERR_JS_INVALID_PARAMETER, true);
437         return nullptr;
438     }
439     AuthStatusInfo info;
440     if ((error.code == 0) && (!ParseAuthStatusInfo(env, businessData, info))) {
441         ACCOUNT_LOGE("failed to parse AuthStatusInfo");
442         AccountNapiThrow(env, ERR_JS_INVALID_PARAMETER, true);
443         return nullptr;
444     }
445     Parcel parcel;
446     if (!info.Marshalling(parcel)) {
447         ACCOUNT_LOGE("fail to marshalling AuthStatusInfo");
448         AccountNapiThrow(env, ERR_JS_SYSTEM_SERVICE_EXCEPTION, true);
449         return nullptr;
450     }
451     param->callback->OnResult(error.code, parcel);
452     return nullptr;
453 }
454 
GetAccessTokenCallback(napi_env env,napi_callback_info cbInfo)455 static napi_value GetAccessTokenCallback(napi_env env, napi_callback_info cbInfo)
456 {
457     ACCOUNT_LOGI("GetAccessTokenCallback enter");
458     JsDomainPluginParam *param = nullptr;
459     BusinessError error;
460     napi_value businessData = nullptr;
461     if (!GetPluginCallbackCommonParam(env, cbInfo, &param, error, &businessData)) {
462         AccountNapiThrow(env, ERR_JS_SYSTEM_SERVICE_EXCEPTION, true);
463         return nullptr;
464     }
465     std::vector<uint8_t> accessToken;
466     if ((error.code == 0) && (ParseUint8TypedArrayToVector(env, businessData, accessToken) != napi_ok)) {
467         ACCOUNT_LOGE("Parse access token failed");
468         AccountNapiThrow(env, ERR_JS_SYSTEM_SERVICE_EXCEPTION, true);
469         return nullptr;
470     }
471     Parcel parcel;
472     if (!parcel.WriteUInt8Vector(accessToken)) {
473         ACCOUNT_LOGE("failed to write accessToken");
474         AccountNapiThrow(env, ERR_JS_SYSTEM_SERVICE_EXCEPTION, true);
475         return nullptr;
476     }
477     param->callback->OnResult(error.code, parcel);
478     return nullptr;
479 }
480 
IsUserTokenValidCallback(napi_env env,napi_callback_info cbInfo)481 static napi_value IsUserTokenValidCallback(napi_env env, napi_callback_info cbInfo)
482 {
483     ACCOUNT_LOGI("IsUserTokenValidCallback enter");
484     JsDomainPluginParam *param = nullptr;
485     BusinessError error;
486     napi_value businessData = nullptr;
487     if (!GetPluginCallbackCommonParam(env, cbInfo, &param, error, &businessData)) {
488         AccountNapiThrow(env, ERR_JS_SYSTEM_SERVICE_EXCEPTION, true);
489         return nullptr;
490     }
491     bool isTokenValid = false;
492     if ((error.code == 0) && (!GetBoolProperty(env, businessData, isTokenValid))) {
493         ACCOUNT_LOGE("Parse access token failed");
494         AccountNapiThrow(env, ERR_JS_SYSTEM_SERVICE_EXCEPTION, true);
495         return nullptr;
496     }
497     Parcel parcel;
498     if (!parcel.WriteBool(isTokenValid)) {
499         ACCOUNT_LOGE("failed to write accessToken");
500         AccountNapiThrow(env, ERR_JS_SYSTEM_SERVICE_EXCEPTION, true);
501         return nullptr;
502     }
503     param->callback->OnResult(error.code, parcel);
504     return nullptr;
505 }
506 
GetAccessTokenWork(uv_work_t * work,int status)507 static void GetAccessTokenWork(uv_work_t *work, int status)
508 {
509     std::unique_ptr<uv_work_t> workPtr(work);
510     napi_handle_scope scope = nullptr;
511     if (!InitUvWorkCallbackEnv(work, scope)) {
512         return;
513     }
514     JsDomainPluginParam *param = reinterpret_cast<JsDomainPluginParam *>(work->data);
515     napi_value napiCallback = CreatePluginAsyncCallback(param->env, GetAccessTokenCallback, param);
516     napi_value napiOptions = CreateNapiGetAccessTokenOptions(param);
517     napi_value argv[] = {napiOptions, napiCallback};
518     NapiCallVoidFunction(param->env, argv, ARG_SIZE_TWO, param->func);
519     std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
520     param->lockInfo->count--;
521     param->lockInfo->condition.notify_all();
522     napi_close_handle_scope(param->env, scope);
523     if (napiCallback == nullptr) {
524         delete param;
525     }
526 }
527 
IsUserTokenValidWork(uv_work_t * work,int status)528 static void IsUserTokenValidWork(uv_work_t *work, int status)
529 {
530     std::unique_ptr<uv_work_t> workPtr(work);
531     napi_handle_scope scope = nullptr;
532     if (!InitUvWorkCallbackEnv(work, scope)) {
533         return;
534     }
535     JsDomainPluginParam *param = reinterpret_cast<JsDomainPluginParam *>(work->data);
536     napi_value napiCallback = CreatePluginAsyncCallback(param->env, IsUserTokenValidCallback, param);
537     napi_value napiDomainAccountInfo = CreateNapiDomainAccountInfo(param->env, param->domainAccountInfo);
538     napi_value napiUserToken = CreateUint8Array(param->env, param->authData.data(), param->authData.size());
539     napi_value argv[] = {napiDomainAccountInfo, napiUserToken, napiCallback};
540     NapiCallVoidFunction(param->env, argv, ARG_SIZE_THREE, param->func);
541     std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
542     param->lockInfo->count--;
543     param->lockInfo->condition.notify_all();
544     napi_close_handle_scope(param->env, scope);
545     if (napiCallback == nullptr) {
546         delete param;
547     }
548 }
549 
GetAuthStatusInfoWork(uv_work_t * work,int status)550 static void GetAuthStatusInfoWork(uv_work_t *work, int status)
551 {
552     std::unique_ptr<uv_work_t> workPtr(work);
553     napi_handle_scope scope = nullptr;
554     if (!InitUvWorkCallbackEnv(work, scope)) {
555         return;
556     }
557     JsDomainPluginParam *param = reinterpret_cast<JsDomainPluginParam *>(work->data);
558     napi_value napiDomainAccountInfo = CreateNapiDomainAccountInfo(param->env, param->domainAccountInfo);
559     napi_value napiCallback = CreatePluginAsyncCallback(param->env, GetAuthStatusInfoCallback, param);
560     napi_value argv[] = {napiDomainAccountInfo, napiCallback};
561     NapiCallVoidFunction(param->env, argv, ARG_SIZE_TWO, param->func);
562     std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
563     param->lockInfo->count--;
564     param->lockInfo->condition.notify_all();
565     napi_close_handle_scope(param->env, scope);
566     if (napiCallback == nullptr) {
567         delete param;
568     }
569 }
570 
NapiDomainAccountPlugin(napi_env env,const JsDomainPlugin & jsPlugin)571 NapiDomainAccountPlugin::NapiDomainAccountPlugin(napi_env env, const JsDomainPlugin &jsPlugin)
572     : env_(env), jsPlugin_(jsPlugin)
573 {}
574 
~NapiDomainAccountPlugin()575 NapiDomainAccountPlugin::~NapiDomainAccountPlugin()
576 {
577     std::unique_lock<std::mutex> lock(lockInfo_.mutex);
578     lockInfo_.condition.wait(lock, [this] { return this->lockInfo_.count == 0; });
579     lockInfo_.count--;
580     if (env_ == nullptr) {
581         return;
582     }
583     ReleaseNapiRefAsync(env_, jsPlugin_.auth);
584     jsPlugin_.auth = nullptr;
585     ReleaseNapiRefAsync(env_, jsPlugin_.authWithPopup);
586     jsPlugin_.authWithPopup = nullptr;
587     ReleaseNapiRefAsync(env_, jsPlugin_.authWithToken);
588     jsPlugin_.authWithToken = nullptr;
589     ReleaseNapiRefAsync(env_, jsPlugin_.getAuthStatusInfo);
590     jsPlugin_.getAuthStatusInfo = nullptr;
591     ReleaseNapiRefAsync(env_, jsPlugin_.getDomainAccountInfo);
592     jsPlugin_.getDomainAccountInfo = nullptr;
593     ReleaseNapiRefAsync(env_, jsPlugin_.onAccountBound);
594     jsPlugin_.onAccountBound = nullptr;
595     ReleaseNapiRefAsync(env_, jsPlugin_.onAccountUnbound);
596     jsPlugin_.onAccountUnbound = nullptr;
597     ReleaseNapiRefAsync(env_, jsPlugin_.isAccountTokenValid);
598     jsPlugin_.isAccountTokenValid = nullptr;
599     ReleaseNapiRefAsync(env_, jsPlugin_.getAccessToken);
600     jsPlugin_.getAccessToken = nullptr;
601 }
602 
AuthCommonWork(uv_work_t * work,int status)603 static void AuthCommonWork(uv_work_t *work, int status)
604 {
605     std::unique_ptr<uv_work_t> workPtr(work);
606     napi_handle_scope scope = nullptr;
607     if (!InitUvWorkCallbackEnv(work, scope)) {
608         return;
609     }
610     JsDomainPluginParam *param = reinterpret_cast<JsDomainPluginParam *>(work->data);
611     int argc = 0;
612     napi_value argv[ARG_SIZE_THREE] = {0};
613     argv[argc++] = CreateNapiDomainAccountInfo(param->env, param->domainAccountInfo);
614     if (param->authMode != AUTH_WITH_POPUP_MODE) {
615         argv[argc++] = CreateUint8Array(param->env, param->authData.data(), param->authData.size());
616     }
617     argv[argc++] = CreateNapiDomainAuthCallback(param->env, param->callback);
618     NapiCallVoidFunction(param->env, argv, argc, param->func);
619     std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
620     param->lockInfo->count--;
621     param->lockInfo->condition.notify_all();
622     napi_close_handle_scope(param->env, scope);
623     delete param;
624 }
625 
AuthCommon(AccountSA::AuthMode authMode,const AccountSA::DomainAccountInfo & info,const std::vector<uint8_t> & authData,const std::shared_ptr<AccountSA::DomainAccountCallback> & callback)626 void NapiDomainAccountPlugin::AuthCommon(AccountSA::AuthMode authMode, const AccountSA::DomainAccountInfo &info,
627     const std::vector<uint8_t> &authData, const std::shared_ptr<AccountSA::DomainAccountCallback> &callback)
628 {
629     std::unique_lock<std::mutex> lock(lockInfo_.mutex);
630     if (lockInfo_.count < 0) {
631         ACCOUNT_LOGE("the plugin has been released");
632         return;
633     }
634     uv_loop_s *loop = nullptr;
635     uv_work_t *work = nullptr;
636     JsDomainPluginParam *param = nullptr;
637     if (!InitDomainPluginExecEnv(env_, &loop, &work, &param, &lockInfo_)) {
638         ACCOUNT_LOGE("failed to init domain plugin execution environment");
639         return;
640     }
641     switch (authMode) {
642         case AUTH_WITH_CREDENTIAL_MODE:
643             param->func = jsPlugin_.auth;
644             break;
645         case AUTH_WITH_POPUP_MODE:
646             param->func = jsPlugin_.authWithPopup;
647             break;
648         case AUTH_WITH_TOKEN_MODE:
649             param->func = jsPlugin_.authWithToken;
650             break;
651         default:
652             break;
653     }
654     if (param->func == nullptr) {
655         ACCOUNT_LOGE("func is nullptr");
656         delete work;
657         delete param;
658         return;
659     }
660     param->callback = callback;
661     param->domainAccountInfo = info;
662     param->authMode = authMode;
663     param->authData = authData;
664     int errCode = uv_queue_work_with_qos(loop, work, [](uv_work_t *work) {}, AuthCommonWork, uv_qos_user_initiated);
665     if (errCode != 0) {
666         ACCOUNT_LOGE("failed to uv_queue_work_with_qos, errCode: %{public}d", errCode);
667         delete param;
668         delete work;
669         return;
670     }
671     lockInfo_.count++;
672 }
673 
Auth(const DomainAccountInfo & info,const std::vector<uint8_t> & credential,const std::shared_ptr<DomainAccountCallback> & callback)674 void NapiDomainAccountPlugin::Auth(const DomainAccountInfo &info, const std::vector<uint8_t> &credential,
675     const std::shared_ptr<DomainAccountCallback> &callback)
676 {
677     AuthCommon(AUTH_WITH_CREDENTIAL_MODE, info, credential, callback);
678 }
679 
AuthWithPopup(const DomainAccountInfo & info,const std::shared_ptr<DomainAccountCallback> & callback)680 void NapiDomainAccountPlugin::AuthWithPopup(
681     const DomainAccountInfo &info, const std::shared_ptr<DomainAccountCallback> &callback)
682 {
683     AuthCommon(AUTH_WITH_POPUP_MODE, info, {}, callback);
684 }
685 
AuthWithToken(const DomainAccountInfo & info,const std::vector<uint8_t> & token,const std::shared_ptr<DomainAccountCallback> & callback)686 void NapiDomainAccountPlugin::AuthWithToken(const DomainAccountInfo &info, const std::vector<uint8_t> &token,
687     const std::shared_ptr<DomainAccountCallback> &callback)
688 {
689     AuthCommon(AUTH_WITH_TOKEN_MODE, info, token, callback);
690 }
691 
GetAuthStatusInfo(const DomainAccountInfo & info,const std::shared_ptr<DomainAccountCallback> & callback)692 void NapiDomainAccountPlugin::GetAuthStatusInfo(
693     const DomainAccountInfo &info, const std::shared_ptr<DomainAccountCallback> &callback)
694 {
695     std::unique_lock<std::mutex> lock(lockInfo_.mutex);
696     if (lockInfo_.count < 0) {
697         ACCOUNT_LOGE("the plugin has been released");
698         return;
699     }
700     if (jsPlugin_.getAuthStatusInfo == nullptr) {
701         ACCOUNT_LOGE("getAuthStatusInfo function of the js plugin is undefined");
702         return;
703     }
704     uv_loop_s *loop = nullptr;
705     uv_work_t *work = nullptr;
706     JsDomainPluginParam *param = nullptr;
707     if (!InitDomainPluginExecEnv(env_, &loop, &work, &param, &lockInfo_)) {
708         ACCOUNT_LOGE("failed to init domain plugin execution environment");
709         return;
710     }
711     param->func = jsPlugin_.getAuthStatusInfo;
712     param->domainAccountInfo = info;
713     param->callback = callback;
714     int errCode = uv_queue_work_with_qos(
715         loop, work, [](uv_work_t *work) {}, GetAuthStatusInfoWork, uv_qos_default);
716     if (errCode != 0) {
717         ACCOUNT_LOGE("failed to uv_queue_work_with_qos, errCode: %{public}d", errCode);
718         delete param;
719         delete work;
720         return;
721     }
722     lockInfo_.count++;
723 }
724 
OnAccountBound(const DomainAccountInfo & info,const int32_t localId,const std::shared_ptr<AccountSA::DomainAccountCallback> & callback)725 void NapiDomainAccountPlugin::OnAccountBound(const DomainAccountInfo &info, const int32_t localId,
726     const std::shared_ptr<AccountSA::DomainAccountCallback> &callback)
727 {
728     std::unique_lock<std::mutex> lock(lockInfo_.mutex);
729     if (lockInfo_.count < 0) {
730         ACCOUNT_LOGE("the plugin has been released");
731         return;
732     }
733     if (jsPlugin_.onAccountBound == nullptr) {
734         ACCOUNT_LOGE("OnAccountBound function of the js plugin is undefined");
735         return;
736     }
737     uv_loop_s *loop = nullptr;
738     uv_work_t *work = nullptr;
739     JsDomainPluginParam *param = nullptr;
740     if (!InitDomainPluginExecEnv(env_, &loop, &work, &param, &lockInfo_)) {
741         ACCOUNT_LOGE("failed to init domain plugin execution environment");
742         return;
743     }
744     param->domainAccountInfo = info;
745     param->func = jsPlugin_.onAccountBound;
746     param->callback = callback;
747     param->userId = localId;
748     int errCode = uv_queue_work_with_qos(loop, work, [](uv_work_t *work) {}, OnAccountBoundWork, uv_qos_default);
749     if (errCode != 0) {
750         ACCOUNT_LOGE("failed to uv_queue_work_with_qos, errCode: %{public}d", errCode);
751         delete work;
752         delete param;
753         return;
754     }
755     lockInfo_.count++;
756 }
757 
OnAccountUnBound(const DomainAccountInfo & info,const std::shared_ptr<AccountSA::DomainAccountCallback> & callback)758 void NapiDomainAccountPlugin::OnAccountUnBound(const DomainAccountInfo &info,
759     const std::shared_ptr<AccountSA::DomainAccountCallback> &callback)
760 {
761     std::unique_lock<std::mutex> lock(lockInfo_.mutex);
762     if (lockInfo_.count < 0) {
763         ACCOUNT_LOGE("the plugin has been released");
764         return;
765     }
766     if (jsPlugin_.onAccountUnbound == nullptr) {
767         ACCOUNT_LOGE("OnAccountUnBound function of the js plugin is undefined");
768         return;
769     }
770     uv_loop_s *loop = nullptr;
771     uv_work_t *work = nullptr;
772     JsDomainPluginParam *param = nullptr;
773     if (!InitDomainPluginExecEnv(env_, &loop, &work, &param, &lockInfo_)) {
774         ACCOUNT_LOGE("failed to init domain plugin execution environment");
775         return;
776     }
777     param->domainAccountInfo = info;
778     param->func = jsPlugin_.onAccountUnbound;
779     param->callback = callback;
780     int errCode = uv_queue_work_with_qos(
781         loop, work, [](uv_work_t *work) {}, OnAccountUnBoundWork, uv_qos_default);
782     if (errCode != 0) {
783         ACCOUNT_LOGE("failed to uv_queue_work_with_qos, errCode: %{public}d", errCode);
784         delete work;
785         delete param;
786         return;
787     }
788     lockInfo_.count++;
789 }
790 
GetDomainAccountInfo(const GetDomainAccountInfoOptions & options,const std::shared_ptr<AccountSA::DomainAccountCallback> & callback)791 void NapiDomainAccountPlugin::GetDomainAccountInfo(const GetDomainAccountInfoOptions &options,
792     const std::shared_ptr<AccountSA::DomainAccountCallback> &callback)
793 {
794     std::unique_lock<std::mutex> lock(lockInfo_.mutex);
795     if (lockInfo_.count < 0) {
796         ACCOUNT_LOGE("the plugin has been released");
797         return;
798     }
799     if (jsPlugin_.getDomainAccountInfo == nullptr) {
800         ACCOUNT_LOGE("GetDomainAccountInfo function of the js plugin is undefined");
801         return;
802     }
803     uv_loop_s *loop = nullptr;
804     uv_work_t *work = nullptr;
805     JsDomainPluginParam *param = nullptr;
806     if (!InitDomainPluginExecEnv(env_, &loop, &work, &param, &lockInfo_)) {
807         ACCOUNT_LOGE("failed to init domain plugin execution environment");
808         return;
809     }
810     param->domainAccountInfo = options.accountInfo;
811     param->callingUid = options.callingUid;
812     param->callback = callback;
813     param->func = jsPlugin_.getDomainAccountInfo;
814     int errCode = uv_queue_work_with_qos(
815         loop, work, [](uv_work_t *work) {}, GetDomainAccountInfoWork, uv_qos_default);
816     if (errCode != 0) {
817         ACCOUNT_LOGE("failed to uv_queue_work_with_qos, errCode: %{public}d", errCode);
818         delete work;
819         delete param;
820         return;
821     }
822     lockInfo_.count++;
823 }
824 
IsAccountTokenValid(const DomainAccountInfo & info,const std::vector<uint8_t> & token,const std::shared_ptr<DomainAccountCallback> & callback)825 void NapiDomainAccountPlugin::IsAccountTokenValid(const DomainAccountInfo &info, const std::vector<uint8_t> &token,
826     const std::shared_ptr<DomainAccountCallback> &callback)
827 {
828     std::unique_lock<std::mutex> lock(lockInfo_.mutex);
829     if (lockInfo_.count < 0) {
830         ACCOUNT_LOGE("the plugin has been released");
831         return;
832     }
833     if (jsPlugin_.isAccountTokenValid == nullptr) {
834         ACCOUNT_LOGE("isUserTokenValid function of the js plugin is undefined");
835         return;
836     }
837     uv_loop_s *loop = nullptr;
838     uv_work_t *work = nullptr;
839     JsDomainPluginParam *param = nullptr;
840     if (!InitDomainPluginExecEnv(env_, &loop, &work, &param, &lockInfo_)) {
841         ACCOUNT_LOGE("failed to init domain plugin execution environment");
842         return;
843     }
844     param->callback = callback;
845     param->authData = token;
846     param->domainAccountInfo = info;
847     param->func = jsPlugin_.isAccountTokenValid;
848     int errCode = uv_queue_work_with_qos(
849         loop, work, [](uv_work_t *work) {}, IsUserTokenValidWork, uv_qos_default);
850     if (errCode != 0) {
851         ACCOUNT_LOGE("failed to uv_queue_work_with_qos, errCode: %{public}d", errCode);
852         delete work;
853         delete param;
854         return;
855     }
856     lockInfo_.count++;
857 }
858 
GetAccessToken(const AccountSA::DomainAccountInfo & domainInfo,const std::vector<uint8_t> & accountToken,const AccountSA::GetAccessTokenOptions & option,const std::shared_ptr<AccountSA::DomainAccountCallback> & callback)859 void NapiDomainAccountPlugin::GetAccessToken(const AccountSA::DomainAccountInfo &domainInfo,
860     const std::vector<uint8_t> &accountToken, const AccountSA::GetAccessTokenOptions &option,
861     const std::shared_ptr<AccountSA::DomainAccountCallback> &callback)
862 {
863     std::unique_lock<std::mutex> lock(lockInfo_.mutex);
864     if (lockInfo_.count < 0) {
865         ACCOUNT_LOGE("the plugin has been released");
866         return;
867     }
868     if (jsPlugin_.getAccessToken == nullptr) {
869         ACCOUNT_LOGE("getAccessToken function of the js plugin is undefined");
870         return;
871     }
872     uv_loop_s *loop = nullptr;
873     uv_work_t *work = nullptr;
874     JsDomainPluginParam *param = nullptr;
875     if (!InitDomainPluginExecEnv(env_, &loop, &work, &param, &lockInfo_)) {
876         ACCOUNT_LOGE("failed to init domain plugin execution environment");
877         return;
878     }
879     param->domainAccountInfo = domainInfo;
880     param->callback = callback;
881     param->authData = accountToken;
882     param->option = option;
883     param->func = jsPlugin_.getAccessToken;
884     int errCode = uv_queue_work_with_qos(
885         loop, work, [](uv_work_t *work) {}, GetAccessTokenWork, uv_qos_default);
886     if (errCode != 0) {
887         ACCOUNT_LOGE("failed to uv_queue_work_with_qos, errCode: %{public}d", errCode);
888         delete work;
889         delete param;
890         return;
891     }
892     lockInfo_.count++;
893 }
894 
Init(napi_env env,napi_value exports)895 napi_value NapiDomainAccountManager::Init(napi_env env, napi_value exports)
896 {
897     napi_property_descriptor properties[] = {
898         DECLARE_NAPI_STATIC_FUNCTION("registerPlugin", RegisterPlugin),
899         DECLARE_NAPI_STATIC_FUNCTION("unregisterPlugin", UnregisterPlugin),
900         DECLARE_NAPI_STATIC_FUNCTION("auth", Auth),
901         DECLARE_NAPI_STATIC_FUNCTION("authWithPopup", AuthWithPopup),
902         DECLARE_NAPI_STATIC_FUNCTION("hasAccount", HasAccount),
903         DECLARE_NAPI_STATIC_FUNCTION("updateAccountToken", UpdateAccountToken),
904         DECLARE_NAPI_STATIC_FUNCTION("isAuthenticationExpired", IsAuthenticationExpired),
905         DECLARE_NAPI_STATIC_FUNCTION("getAccessToken", GetAccessToken),
906         DECLARE_NAPI_STATIC_FUNCTION("getAccountInfo", GetDomainAccountInfo),
907         DECLARE_NAPI_STATIC_FUNCTION("updateAccountInfo", UpdateAccountInfo),
908         DECLARE_NAPI_FUNCTION("registerPlugin", RegisterPlugin),
909         DECLARE_NAPI_FUNCTION("unregisterPlugin", UnregisterPlugin),
910         DECLARE_NAPI_FUNCTION("hasAccount", HasAccount),
911         DECLARE_NAPI_FUNCTION("updateAccountToken", UpdateAccountToken),
912         DECLARE_NAPI_FUNCTION("getAccessToken", GetAccessToken)
913     };
914     std::string className = "DomainAccountManager";
915     napi_value constructor = nullptr;
916     NAPI_CALL(env, napi_define_class(env, className.c_str(), className.length(), JsConstructor,
917         nullptr, sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor));
918     NAPI_ASSERT(env, constructor != nullptr, "define js class DomainAccountManager failed");
919     napi_status status = napi_set_named_property(env, exports, className.c_str(), constructor);
920     NAPI_ASSERT(env, status == napi_ok, "set constructor to exports failed");
921     napi_value global = nullptr;
922     status = napi_get_global(env, &global);
923     NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
924     status = napi_set_named_property(env, global, className.c_str(), constructor);
925     NAPI_ASSERT(env, status == napi_ok, "set constructor to global failed");
926     return exports;
927 }
928 
JsConstructor(napi_env env,napi_callback_info cbInfo)929 napi_value NapiDomainAccountManager::JsConstructor(napi_env env, napi_callback_info cbInfo)
930 {
931     napi_value thisVar = nullptr;
932     NAPI_CALL(env, napi_get_cb_info(env, cbInfo, nullptr, nullptr, &thisVar, nullptr));
933     return thisVar;
934 }
935 
ParseContextForRegisterPlugin(napi_env env,napi_callback_info cbInfo,JsDomainPlugin & jsPlugin)936 static bool ParseContextForRegisterPlugin(napi_env env, napi_callback_info cbInfo, JsDomainPlugin &jsPlugin)
937 {
938     size_t argc = ARG_SIZE_ONE;
939     napi_value argv[ARG_SIZE_ONE] = {nullptr};
940     NAPI_CALL_BASE(env, napi_get_cb_info(env, cbInfo, &argc, argv, nullptr, nullptr), false);
941     if (argc != ARG_SIZE_ONE) {
942         ACCOUNT_LOGE("the number of parameter must be one, but got %{public}zu", argc);
943         return false;
944     }
945     if (!GetNamedJsFunction(env, argv[0], "getAuthStatusInfo", jsPlugin.getAuthStatusInfo)) {
946         ACCOUNT_LOGE("fail to parse getAuthStatusInfo function");
947         return false;
948     }
949     if (!GetNamedJsFunction(env, argv[0], "auth", jsPlugin.auth)) {
950         ACCOUNT_LOGE("fail to parse getAuthStatusInfo function");
951         return false;
952     }
953     if (!GetNamedJsFunction(env, argv[0], "authWithPopup", jsPlugin.authWithPopup)) {
954         ACCOUNT_LOGE("fail to parse getAuthStatusInfo function");
955         return false;
956     }
957     if (!GetNamedJsFunction(env, argv[0], "authWithToken", jsPlugin.authWithToken)) {
958         ACCOUNT_LOGE("fail to parse getAuthStatusInfo function");
959         return false;
960     }
961     if (!GetNamedJsFunction(env, argv[0], "bindAccount", jsPlugin.onAccountBound)) {
962         ACCOUNT_LOGE("fail to parse onAccountBound function");
963         return false;
964     }
965     if (!GetNamedJsFunction(env, argv[0], "unbindAccount", jsPlugin.onAccountUnbound)) {
966         ACCOUNT_LOGE("fail to parse onAccountUnbound function");
967         return false;
968     }
969     if (!GetNamedJsFunction(env, argv[0], "getAccountInfo", jsPlugin.getDomainAccountInfo)) {
970         ACCOUNT_LOGE("fail to parse getDomainAccountInfo function");
971         return false;
972     }
973     if (!GetNamedJsFunction(env, argv[0], "isAccountTokenValid", jsPlugin.isAccountTokenValid)) {
974         ACCOUNT_LOGE("fail to parse isUserTokenValid function");
975         return false;
976     }
977     if (!GetNamedJsFunction(env, argv[0], "getAccessToken", jsPlugin.getAccessToken)) {
978         ACCOUNT_LOGE("fail to parse getAccessToken function");
979         return false;
980     }
981     return true;
982 }
983 
RegisterPlugin(napi_env env,napi_callback_info cbInfo)984 napi_value NapiDomainAccountManager::RegisterPlugin(napi_env env, napi_callback_info cbInfo)
985 {
986     JsDomainPlugin jsPlugin;
987     if (!ParseContextForRegisterPlugin(env, cbInfo, jsPlugin)) {
988         std::string errMsg = "Parameter error. The type of \"plugin\" must be DomainPlugin";
989         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
990         return nullptr;
991     }
992     auto plugin = std::make_shared<NapiDomainAccountPlugin>(env, jsPlugin);
993     int32_t errCode = DomainAccountClient::GetInstance().RegisterPlugin(plugin);
994     if (errCode != ERR_OK) {
995         ACCOUNT_LOGE("failed to register plugin, errCode=%{public}d", errCode);
996         AccountNapiThrow(env, errCode, true);
997     }
998     return nullptr;
999 }
1000 
ParseParamForHasDomainAccount(napi_env env,napi_callback_info cbInfo,HasDomainAccountAsyncContext * asyncContext)1001 static bool ParseParamForHasDomainAccount(
1002     napi_env env, napi_callback_info cbInfo, HasDomainAccountAsyncContext *asyncContext)
1003 {
1004     size_t argc = ARG_SIZE_TWO;
1005     napi_value argv[ARG_SIZE_TWO] = {0};
1006     napi_get_cb_info(env, cbInfo, &argc, argv, nullptr, nullptr);
1007     if (argc < ARG_SIZE_ONE) {
1008         ACCOUNT_LOGE("paramter number should be at least one");
1009         std::string errMsg = "Parameter error. The number of parameters should be at least 1";
1010         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
1011         return false;
1012     }
1013     if (argc == ARG_SIZE_TWO) {
1014         if (!GetCallbackProperty(env, argv[argc - 1], asyncContext->callbackRef, 1)) {
1015             ACCOUNT_LOGE("Get callbackRef failed");
1016             std::string errMsg = "Parameter error. The type of \"callback\" must be function";
1017             AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
1018             return false;
1019         }
1020     }
1021     if (!ParseDomainAccountInfo(env, argv[0], asyncContext->domainInfo)) {
1022         ACCOUNT_LOGE("get domainInfo failed");
1023         std::string errMsg = "Parameter error. The type of \"domainAccountInfo\" must be DomainAccountInfo";
1024         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
1025         return false;
1026     }
1027     return true;
1028 }
1029 
UnregisterPlugin(napi_env env,napi_callback_info cbInfo)1030 napi_value NapiDomainAccountManager::UnregisterPlugin(napi_env env, napi_callback_info cbInfo)
1031 {
1032     int32_t errCode = DomainAccountClient::GetInstance().UnregisterPlugin();
1033     if (errCode != ERR_OK) {
1034         ACCOUNT_LOGE("failed to unregister plugin, errCode=%{public}d", errCode);
1035         AccountNapiThrow(env, errCode, true);
1036     }
1037     return nullptr;
1038 }
1039 
ParseContextForAuth(napi_env env,napi_callback_info cbInfo,JsDomainPluginParam & authContext)1040 static bool ParseContextForAuth(napi_env env, napi_callback_info cbInfo, JsDomainPluginParam &authContext)
1041 {
1042     size_t argc = ARG_SIZE_THREE;
1043     napi_value argv[ARG_SIZE_THREE] = {nullptr};
1044     NAPI_CALL_BASE(env, napi_get_cb_info(env, cbInfo, &argc, argv, nullptr, nullptr), false);
1045     if (argc != ARG_SIZE_THREE) {
1046         ACCOUNT_LOGE("the number of parameter must be one, but got %{public}zu", argc);
1047         std::string errMsg = "Parameter error. The number of parameters should be at least 3";
1048         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
1049         return false;
1050     }
1051     int index = 0;
1052     if (!ParseDomainAccountInfo(env, argv[index++], authContext.domainAccountInfo)) {
1053         ACCOUNT_LOGE("get domainInfo failed");
1054         std::string errMsg = "Parameter error. The type of \"domainAccountInfo\" must be DomainAccountInfo";
1055         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
1056         return false;
1057     }
1058     if (ParseUint8TypedArrayToVector(env, argv[index++], authContext.authData) != napi_ok) {
1059         ACCOUNT_LOGE("get credential failed");
1060         std::string errMsg = "Parameter error. The type of \"credential\" must be Uint8Array";
1061         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
1062         return false;
1063     }
1064     if (!GetNamedJsFunction(env, argv[index++], "onResult", authContext.callbackRef)) {
1065         ACCOUNT_LOGE("get callback failed");
1066         std::string errMsg = "Parameter error. The type of \"callback\" must be IUserAuthCallback";
1067         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
1068         return false;
1069     }
1070     return true;
1071 }
1072 
AuthCompletedCallback(napi_env env,napi_status status,void * data)1073 void AuthCompletedCallback(napi_env env, napi_status status, void *data)
1074 {
1075     delete reinterpret_cast<JsDomainPluginParam *>(data);
1076 }
1077 
Auth(napi_env env,napi_callback_info cbInfo)1078 napi_value NapiDomainAccountManager::Auth(napi_env env, napi_callback_info cbInfo)
1079 {
1080     auto authContext = std::make_unique<JsDomainPluginParam>(env);
1081     if (!ParseContextForAuth(env, cbInfo, *authContext)) {
1082         return nullptr;
1083     }
1084     napi_value resource = nullptr;
1085     NAPI_CALL(env, napi_create_string_utf8(env, "Auth", NAPI_AUTO_LENGTH, &resource));
1086     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
1087         [](napi_env env, void *data) {
1088             JsDomainPluginParam *param = reinterpret_cast<JsDomainPluginParam *>(data);
1089             auto jsCallback = std::make_shared<JsDomainAccountAuthCallback>(env, param->callbackRef);
1090             auto callback = std::make_shared<NapiDomainAccountCallback>(env, jsCallback);
1091             param->callbackRef = nullptr;
1092             param->errCode = DomainAccountClient::GetInstance().Auth(
1093                 param->domainAccountInfo, param->authData, callback);
1094             if (param->errCode != ERR_OK) {
1095                 Parcel emptyParcel;
1096                 AccountSA::DomainAuthResult emptyResult;
1097                 if (!emptyResult.Marshalling(emptyParcel)) {
1098                     ACCOUNT_LOGE("authResult Marshalling failed");
1099                     return;
1100                 }
1101                 callback->OnResult(ConvertToJSErrCode(param->errCode), emptyParcel);
1102             }
1103         },
1104         AuthCompletedCallback,
1105         reinterpret_cast<void *>(authContext.get()), &authContext->work));
1106     NAPI_CALL(env, napi_queue_async_work_with_qos(env, authContext->work, napi_qos_user_initiated));
1107     authContext.release();
1108     return nullptr;
1109 }
1110 
ParseContextForAuthWithPopup(napi_env env,napi_callback_info cbInfo,JsDomainPluginParam & authWithPopupContext)1111 static bool ParseContextForAuthWithPopup(
1112     napi_env env, napi_callback_info cbInfo, JsDomainPluginParam &authWithPopupContext)
1113 {
1114     size_t argc = ARG_SIZE_TWO;
1115     napi_value argv[ARG_SIZE_TWO] = {nullptr};
1116     NAPI_CALL_BASE(env, napi_get_cb_info(env, cbInfo, &argc, argv, nullptr, nullptr), false);
1117     if (argc < ARG_SIZE_ONE) {
1118         ACCOUNT_LOGE("need input at least one parameter, but got %{public}zu", argc);
1119         std::string errMsg = "Parameter error. The number of parameters should be at least 1";
1120         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
1121         return false;
1122     }
1123     if (!GetNamedJsFunction(env, argv[argc - 1], "onResult", authWithPopupContext.callbackRef)) {
1124         ACCOUNT_LOGE("get callback failed");
1125         std::string errMsg = "Parameter error. The type of \"callback\" must be function";
1126         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
1127         return false;
1128     }
1129     if (argc == ARG_SIZE_TWO) {
1130         napi_valuetype valueType = napi_undefined;
1131         napi_typeof(env, argv[0], &valueType);
1132         if ((valueType == napi_undefined) || (valueType == napi_null)) {
1133             ACCOUNT_LOGI("the userId is undefined or null");
1134         } else {
1135             if (!GetIntProperty(env, argv[0], authWithPopupContext.userId)) {
1136                 std::string errMsg = "Parameter error. The type of \"localId\" must be number";
1137                 AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
1138                 ACCOUNT_LOGE("get id failed");
1139                 return false;
1140             }
1141         }
1142     }
1143     return true;
1144 }
1145 
GetAccessTokenExecuteCB(napi_env env,void * data)1146 static void GetAccessTokenExecuteCB(napi_env env, void *data)
1147 {
1148     GetAccessTokenAsyncContext *asyncContext = reinterpret_cast<GetAccessTokenAsyncContext *>(data);
1149     auto callback =
1150         std::make_shared<NapiGetAccessTokenCallback>(env, asyncContext->callbackRef, asyncContext->deferred);
1151     asyncContext->errCode = DomainAccountClient::GetInstance().GetAccessToken(
1152         asyncContext->domainInfo, asyncContext->getTokenParams, callback);
1153     if (asyncContext->errCode != ERR_OK) {
1154         std::vector<uint8_t> accessToken;
1155         callback->OnResult(asyncContext->errCode, accessToken);
1156     }
1157     asyncContext->callbackRef = nullptr;
1158 }
1159 
GetAccessTokenCompleteCB(napi_env env,napi_status status,void * data)1160 static void GetAccessTokenCompleteCB(napi_env env, napi_status status, void *data)
1161 {
1162     delete reinterpret_cast<GetAccessTokenAsyncContext *>(data);
1163 }
1164 
GetAccessTokenCompleteWork(uv_work_t * work,int status)1165 static void GetAccessTokenCompleteWork(uv_work_t *work, int status)
1166 {
1167     std::unique_ptr<uv_work_t> workPtr(work);
1168     napi_handle_scope scope = nullptr;
1169     if (!InitUvWorkCallbackEnv(work, scope)) {
1170         if ((work != nullptr) && (work->data != nullptr)) {
1171             delete reinterpret_cast<GetAccessTokenAsyncContext *>(work->data);
1172         }
1173         return;
1174     }
1175     GetAccessTokenAsyncContext *asyncContext = reinterpret_cast<GetAccessTokenAsyncContext *>(work->data);
1176     napi_value errJs = nullptr;
1177     napi_value dataJs = nullptr;
1178     if (asyncContext->errCode == ERR_OK) {
1179         dataJs =
1180             CreateUint8Array(asyncContext->env, asyncContext->accessToken.data(), asyncContext->accessToken.size());
1181     } else {
1182         errJs = GenerateBusinessError(asyncContext->env, asyncContext->errCode);
1183     }
1184     ReturnCallbackOrPromise(asyncContext->env, asyncContext, errJs, dataJs);
1185     napi_close_handle_scope(asyncContext->env, scope);
1186     delete asyncContext;
1187 }
1188 
AuthWithPopup(napi_env env,napi_callback_info cbInfo)1189 napi_value NapiDomainAccountManager::AuthWithPopup(napi_env env, napi_callback_info cbInfo)
1190 {
1191     auto authWithPopupContext = std::make_unique<JsDomainPluginParam>(env);
1192     if (!ParseContextForAuthWithPopup(env, cbInfo, *authWithPopupContext)) {
1193         return nullptr;
1194     }
1195     napi_value resource = nullptr;
1196     NAPI_CALL(env, napi_create_string_utf8(env, "AuthWithPopup", NAPI_AUTO_LENGTH, &resource));
1197     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
1198         [](napi_env env, void *data) {
1199             JsDomainPluginParam *param = reinterpret_cast<JsDomainPluginParam *>(data);
1200             auto jsCallback = std::make_shared<JsDomainAccountAuthCallback>(env, param->callbackRef);
1201             auto callback = std::make_shared<NapiDomainAccountCallback>(env, jsCallback);
1202             param->callbackRef = nullptr;
1203             param->errCode = DomainAccountClient::GetInstance().AuthWithPopup(param->userId, callback);
1204             if (param->errCode != ERR_OK) {
1205                 Parcel emptyParcel;
1206                 AccountSA::DomainAuthResult emptyResult;
1207                 if (!emptyResult.Marshalling(emptyParcel)) {
1208                     ACCOUNT_LOGE("authResult Marshalling failed");
1209                     return;
1210                 }
1211                 callback->OnResult(ConvertToJSErrCode(param->errCode), emptyParcel);
1212             }
1213         },
1214         AuthCompletedCallback,
1215         reinterpret_cast<void *>(authWithPopupContext.get()), &authWithPopupContext->work));
1216     NAPI_CALL(env, napi_queue_async_work_with_qos(env, authWithPopupContext->work, napi_qos_user_initiated));
1217     authWithPopupContext.release();
1218     return nullptr;
1219 }
1220 
HasDomainAccountCompletedWork(uv_work_t * work,int status)1221 static void HasDomainAccountCompletedWork(uv_work_t *work, int status)
1222 {
1223     std::unique_ptr<uv_work_t> workPtr(work);
1224     napi_handle_scope scope = nullptr;
1225     if (!InitUvWorkCallbackEnv(work, scope)) {
1226         return;
1227     }
1228     HasDomainAccountAsyncContext *asyncContext = reinterpret_cast<HasDomainAccountAsyncContext *>(work->data);
1229     napi_value errJs = nullptr;
1230     napi_value dataJs = nullptr;
1231     if (asyncContext->errCode == ERR_OK) {
1232         napi_get_boolean(asyncContext->env, asyncContext->isHasDomainAccount, &dataJs);
1233     } else {
1234         errJs = GenerateBusinessError(asyncContext->env, asyncContext->errCode);
1235     }
1236     ReturnCallbackOrPromise(asyncContext->env, asyncContext, errJs, dataJs);
1237     napi_close_handle_scope(asyncContext->env, scope);
1238     delete asyncContext;
1239 }
1240 
NapiHasDomainInfoCallback(napi_env env,napi_ref callbackRef,napi_deferred deferred)1241 NapiHasDomainInfoCallback::NapiHasDomainInfoCallback(napi_env env, napi_ref callbackRef, napi_deferred deferred)
1242     : env_(env), callbackRef_(callbackRef), deferred_(deferred)
1243 {}
1244 
OnResult(const int32_t errCode,Parcel & parcel)1245 void NapiHasDomainInfoCallback::OnResult(const int32_t errCode, Parcel &parcel)
1246 {
1247     std::unique_lock<std::mutex> lock(lockInfo_.mutex);
1248     if ((callbackRef_ == nullptr) && (deferred_ == nullptr)) {
1249         ACCOUNT_LOGE("js callback is nullptr");
1250         return;
1251     }
1252     uv_loop_s *loop = nullptr;
1253     uv_work_t *work = nullptr;
1254     if (!CreateExecEnv(env_, &loop, &work)) {
1255         ACCOUNT_LOGE("failed to init domain plugin execution environment");
1256         return;
1257     }
1258     auto *asyncContext = new (std::nothrow) HasDomainAccountAsyncContext(env_);
1259     if (asyncContext == nullptr) {
1260         delete work;
1261         return;
1262     }
1263     if (errCode == ERR_OK) {
1264         parcel.ReadBool(asyncContext->isHasDomainAccount);
1265     }
1266     asyncContext->errCode = errCode;
1267     asyncContext->callbackRef = callbackRef_;
1268     asyncContext->deferred = deferred_;
1269     work->data = reinterpret_cast<void *>(asyncContext);
1270     int resultCode = uv_queue_work_with_qos(
1271         loop, work, [](uv_work_t *work) {}, HasDomainAccountCompletedWork, uv_qos_default);
1272     if (resultCode != 0) {
1273         ACCOUNT_LOGE("failed to uv_queue_work_with_qos, errCode: %{public}d", errCode);
1274         delete asyncContext;
1275         delete work;
1276         return;
1277     }
1278     callbackRef_ = nullptr;
1279     deferred_ = nullptr;
1280 }
1281 
NapiGetAccessTokenCallback(napi_env env,napi_ref callbackRef,napi_deferred deferred)1282 NapiGetAccessTokenCallback::NapiGetAccessTokenCallback(napi_env env, napi_ref callbackRef, napi_deferred deferred)
1283     : env_(env), callbackRef_(callbackRef), deferred_(deferred)
1284 {}
1285 
OnResult(const int32_t errCode,const std::vector<uint8_t> & accessToken)1286 void NapiGetAccessTokenCallback::OnResult(const int32_t errCode, const std::vector<uint8_t> &accessToken)
1287 {
1288     std::unique_lock<std::mutex> lock(lockInfo_.mutex);
1289     if ((callbackRef_ == nullptr) && (deferred_ == nullptr)) {
1290         ACCOUNT_LOGE("js callback is nullptr");
1291         return;
1292     }
1293     uv_loop_s *loop = nullptr;
1294     uv_work_t *work = nullptr;
1295     if (!CreateExecEnv(env_, &loop, &work)) {
1296         ACCOUNT_LOGE("failed to init domain plugin execution environment");
1297         return;
1298     }
1299     auto *asyncContext = new (std::nothrow) GetAccessTokenAsyncContext(env_);
1300     if (asyncContext == nullptr) {
1301         delete work;
1302         return;
1303     }
1304     asyncContext->errCode = errCode;
1305     asyncContext->accessToken = accessToken;
1306     asyncContext->callbackRef = callbackRef_;
1307     asyncContext->deferred = deferred_;
1308     work->data = reinterpret_cast<void *>(asyncContext);
1309     int resultCode = uv_queue_work_with_qos(
1310         loop, work, [](uv_work_t *work) {}, GetAccessTokenCompleteWork, uv_qos_default);
1311     if (resultCode != 0) {
1312         ACCOUNT_LOGE("failed to uv_queue_work_with_qos, errCode: %{public}d", errCode);
1313         delete asyncContext;
1314         delete work;
1315         return;
1316     }
1317     callbackRef_ = nullptr;
1318     deferred_ = nullptr;
1319 }
1320 
HasDomainAccountCompleteCB(napi_env env,napi_status status,void * data)1321 static void HasDomainAccountCompleteCB(napi_env env, napi_status status, void *data)
1322 {
1323     delete reinterpret_cast<HasDomainAccountAsyncContext *>(data);
1324 }
1325 
HasDomainAccountExecuteCB(napi_env env,void * data)1326 static void HasDomainAccountExecuteCB(napi_env env, void *data)
1327 {
1328     HasDomainAccountAsyncContext *asyncContext = reinterpret_cast<HasDomainAccountAsyncContext *>(data);
1329     auto callback = std::make_shared<NapiHasDomainInfoCallback>(env, asyncContext->callbackRef, asyncContext->deferred);
1330     asyncContext->errCode = DomainAccountClient::GetInstance().HasAccount(asyncContext->domainInfo, callback);
1331     if (asyncContext->errCode != ERR_OK) {
1332         Parcel emptyParcel;
1333         callback->OnResult(asyncContext->errCode, emptyParcel);
1334     }
1335     asyncContext->callbackRef = nullptr;
1336 }
1337 
UpdateAccountTokenExecuteCB(napi_env env,void * data)1338 static void UpdateAccountTokenExecuteCB(napi_env env, void *data)
1339 {
1340     UpdateAccountTokenAsyncContext *asyncContext = reinterpret_cast<UpdateAccountTokenAsyncContext *>(data);
1341     asyncContext->errCode =
1342         DomainAccountClient::GetInstance().UpdateAccountToken(asyncContext->domainInfo, asyncContext->token);
1343 }
1344 
UpdateAccountTokenCompletedCB(napi_env env,napi_status status,void * data)1345 static void UpdateAccountTokenCompletedCB(napi_env env, napi_status status, void *data)
1346 {
1347     UpdateAccountTokenAsyncContext *asyncContext = reinterpret_cast<UpdateAccountTokenAsyncContext *>(data);
1348     napi_value errJs = nullptr;
1349     napi_value dataJs = nullptr;
1350     if (asyncContext->errCode != ERR_OK) {
1351         errJs = GenerateBusinessError(asyncContext->env, asyncContext->errCode);
1352     } else {
1353         napi_get_null(asyncContext->env, &dataJs);
1354     }
1355     ProcessCallbackOrPromise(env, asyncContext, errJs, dataJs);
1356     delete asyncContext;
1357 }
1358 
UpdateAccountToken(napi_env env,napi_callback_info cbInfo)1359 napi_value NapiDomainAccountManager::UpdateAccountToken(napi_env env, napi_callback_info cbInfo)
1360 {
1361     auto context = std::make_unique<UpdateAccountTokenAsyncContext>(env);
1362     if (!ParseParamForUpdateAccountToken(env, cbInfo, context.get())) {
1363         return nullptr;
1364     }
1365     napi_value result = nullptr;
1366     if (context->callbackRef == nullptr) {
1367         NAPI_CALL(env, napi_create_promise(env, &context->deferred, &result));
1368     }
1369     napi_value resource = nullptr;
1370     NAPI_CALL(env, napi_create_string_utf8(env, "updateAccountToken", NAPI_AUTO_LENGTH, &resource));
1371     NAPI_CALL(env, napi_create_async_work(env,
1372         nullptr,
1373         resource,
1374         UpdateAccountTokenExecuteCB,
1375         UpdateAccountTokenCompletedCB,
1376         reinterpret_cast<void *>(context.get()),
1377         &context->work));
1378     NAPI_CALL(env, napi_queue_async_work_with_qos(env, context->work, napi_qos_default));
1379     context.release();
1380     return result;
1381 }
1382 
IsAuthenticationExpiredExecuteCB(napi_env env,void * data)1383 static void IsAuthenticationExpiredExecuteCB(napi_env env, void *data)
1384 {
1385     IsAuthenticationExpiredAsyncContext *asyncContext = reinterpret_cast<IsAuthenticationExpiredAsyncContext *>(data);
1386     asyncContext->errCode =
1387         DomainAccountClient::GetInstance().IsAuthenticationExpired(asyncContext->domainInfo, asyncContext->isExpired);
1388 }
1389 
IsAuthenticationExpiredCompletedCB(napi_env env,napi_status status,void * data)1390 static void IsAuthenticationExpiredCompletedCB(napi_env env, napi_status status, void *data)
1391 {
1392     IsAuthenticationExpiredAsyncContext *asyncContext = reinterpret_cast<IsAuthenticationExpiredAsyncContext *>(data);
1393     std::unique_ptr<IsAuthenticationExpiredAsyncContext> asyncContextPtr{asyncContext};
1394     napi_value errJs = nullptr;
1395     napi_value dataJs = nullptr;
1396     if (asyncContext->errCode == ERR_OK) {
1397         NAPI_CALL_RETURN_VOID(env, napi_get_null(env, &errJs));
1398         NAPI_CALL_RETURN_VOID(env, napi_get_boolean(env, asyncContext->isExpired, &dataJs));
1399     } else {
1400         errJs = GenerateBusinessError(env, asyncContext->errCode);
1401         NAPI_CALL_RETURN_VOID(env, napi_get_null(env, &dataJs));
1402     }
1403     ProcessCallbackOrPromise(env, asyncContext, errJs, dataJs);
1404 }
1405 
IsAuthenticationExpired(napi_env env,napi_callback_info cbInfo)1406 napi_value NapiDomainAccountManager::IsAuthenticationExpired(napi_env env, napi_callback_info cbInfo)
1407 {
1408     auto asyncContextPtr = std::make_unique<IsAuthenticationExpiredAsyncContext>(env);
1409     if (!ParseParamForIsAuthenticationExpired(env, cbInfo, asyncContextPtr.get())) {
1410         return nullptr;
1411     }
1412     napi_value result = nullptr;
1413     NAPI_CALL(env, napi_create_promise(env, &asyncContextPtr->deferred, &result));
1414 
1415     napi_value resource = nullptr;
1416     NAPI_CALL(env, napi_create_string_utf8(env, "IsAuthenticationExpired", NAPI_AUTO_LENGTH, &resource));
1417     NAPI_CALL(env, napi_create_async_work(env,
1418         nullptr,
1419         resource,
1420         IsAuthenticationExpiredExecuteCB,
1421         IsAuthenticationExpiredCompletedCB,
1422         reinterpret_cast<void *>(asyncContextPtr.get()),
1423         &asyncContextPtr->work));
1424     NAPI_CALL(env, napi_queue_async_work_with_qos(env, asyncContextPtr->work, napi_qos_default));
1425     asyncContextPtr.release();
1426     return result;
1427 }
1428 
GetAccessToken(napi_env env,napi_callback_info cbInfo)1429 napi_value NapiDomainAccountManager::GetAccessToken(napi_env env, napi_callback_info cbInfo)
1430 {
1431     auto context = std::make_unique<GetAccessTokenAsyncContext>(env);
1432     if (!ParseParamForGetAccessToken(env, cbInfo, context.get())) {
1433         return nullptr;
1434     }
1435     napi_value result = nullptr;
1436     if (context->callbackRef == nullptr) {
1437         NAPI_CALL(env, napi_create_promise(env, &context->deferred, &result));
1438     }
1439     napi_value resource = nullptr;
1440     NAPI_CALL(env, napi_create_string_utf8(env, "getAccessToken", NAPI_AUTO_LENGTH, &resource));
1441     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
1442         GetAccessTokenExecuteCB, GetAccessTokenCompleteCB,
1443         reinterpret_cast<void *>(context.get()), &context->work));
1444     NAPI_CALL(env, napi_queue_async_work_with_qos(env, context->work, napi_qos_default));
1445     context.release();
1446     return result;
1447 }
1448 
HasAccount(napi_env env,napi_callback_info cbInfo)1449 napi_value NapiDomainAccountManager::HasAccount(napi_env env, napi_callback_info cbInfo)
1450 {
1451     auto context = std::make_unique<HasDomainAccountAsyncContext>(env);
1452     if (!ParseParamForHasDomainAccount(env, cbInfo, context.get())) {
1453         return nullptr;
1454     }
1455     napi_value result = nullptr;
1456     if (context->callbackRef == nullptr) {
1457         NAPI_CALL(env, napi_create_promise(env, &context->deferred, &result));
1458     }
1459     napi_value resource = nullptr;
1460     NAPI_CALL(env, napi_create_string_utf8(env, "hasAccount", NAPI_AUTO_LENGTH, &resource));
1461     NAPI_CALL(env, napi_create_async_work(env,
1462         nullptr,
1463         resource,
1464         HasDomainAccountExecuteCB,
1465         HasDomainAccountCompleteCB,
1466         reinterpret_cast<void *>(context.get()),
1467         &context->work));
1468     NAPI_CALL(env, napi_queue_async_work_with_qos(env, context->work, napi_qos_default));
1469     context.release();
1470     return result;
1471 }
1472 
ParseGetDomainAccountInfoOptions(napi_env env,napi_value object,DomainAccountInfo & info)1473 static bool ParseGetDomainAccountInfoOptions(napi_env env, napi_value object, DomainAccountInfo &info)
1474 {
1475     napi_valuetype type = napi_undefined;
1476     napi_typeof(env, object, &type);
1477     if (type != napi_object) {
1478         ACCOUNT_LOGE("Value is not an object.");
1479         return false;
1480     }
1481     if (!GetStringPropertyByKey(env, object, "accountName", info.accountName_)) {
1482         ACCOUNT_LOGE("get domainInfo's accountName failed");
1483         return false;
1484     }
1485     bool hasProp = false;
1486     napi_has_named_property(env, object, "domain", &hasProp);
1487     if (hasProp) {
1488         napi_value value = nullptr;
1489         napi_get_named_property(env, object, "domain", &value);
1490         napi_valuetype valueType = napi_undefined;
1491         napi_typeof(env, value, &valueType);
1492         if ((valueType == napi_undefined) || (valueType == napi_null)) {
1493             ACCOUNT_LOGI("the accountId is undefined or null");
1494         } else if (!GetStringPropertyByKey(env, object, "domain", info.domain_)) {
1495             ACCOUNT_LOGE("get domainInfo's domain failed");
1496             return false;
1497         }
1498     }
1499     return true;
1500 }
1501 
ParseParamForGetAccountInfo(napi_env env,napi_callback_info cbInfo,GetAccountInfoAsyncContext * asyncContext)1502 static bool ParseParamForGetAccountInfo(
1503     napi_env env, napi_callback_info cbInfo, GetAccountInfoAsyncContext *asyncContext)
1504 {
1505     size_t argc = ARG_SIZE_TWO;
1506     napi_value argv[ARG_SIZE_TWO] = {0};
1507     napi_get_cb_info(env, cbInfo, &argc, argv, nullptr, nullptr);
1508     if (argc < ARG_SIZE_ONE) {
1509         ACCOUNT_LOGE("the parameter of number should be at least one");
1510         std::string errMsg = "Parameter error. The number of parameters should be at least 1";
1511         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
1512         return false;
1513     }
1514     if (argc == ARG_SIZE_TWO) {
1515         if (!GetCallbackProperty(env, argv[argc - 1], asyncContext->callbackRef, 1)) {
1516             ACCOUNT_LOGE("Get callbackRef failed");
1517             std::string errMsg = "Parameter error. The type of \"callback\" must be function";
1518             AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
1519             return false;
1520         }
1521     }
1522     if (!ParseGetDomainAccountInfoOptions(env, argv[0], asyncContext->domainInfo)) {
1523         ACCOUNT_LOGE("get domainInfo failed");
1524         std::string errMsg = "Parameter error. The type of \"options\" must be GetDomainAccountInfoOptions";
1525         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
1526         return false;
1527     }
1528     return true;
1529 }
1530 
GetAccountInfoCompleteWork(uv_work_t * work,int status)1531 static void GetAccountInfoCompleteWork(uv_work_t *work, int status)
1532 {
1533     std::unique_ptr<uv_work_t> workPtr(work);
1534     napi_handle_scope scope = nullptr;
1535     if (!InitUvWorkCallbackEnv(work, scope)) {
1536         if ((work != nullptr) && (work->data != nullptr)) {
1537             delete reinterpret_cast<GetAccountInfoAsyncContext *>(work->data);
1538         }
1539         return;
1540     }
1541     GetAccountInfoAsyncContext *asyncContext = reinterpret_cast<GetAccountInfoAsyncContext *>(work->data);
1542     napi_value errJs = nullptr;
1543     napi_value dataJs = nullptr;
1544     if (asyncContext->errCode == ERR_OK) {
1545         dataJs = AppExecFwk::WrapWantParams(asyncContext->env, asyncContext->getAccountInfoParams);
1546     } else {
1547         errJs = GenerateBusinessError(asyncContext->env, asyncContext->errCode);
1548     }
1549     ReturnCallbackOrPromise(asyncContext->env, asyncContext, errJs, dataJs);
1550     napi_close_handle_scope(asyncContext->env, scope);
1551     delete asyncContext;
1552 }
1553 
NapiGetAccountInfoCallback(napi_env env,napi_ref callbackRef,napi_deferred deferred)1554 NapiGetAccountInfoCallback::NapiGetAccountInfoCallback(napi_env env, napi_ref callbackRef, napi_deferred deferred)
1555     : env_(env), callbackRef_(callbackRef), deferred_(deferred)
1556 {}
1557 
OnResult(int32_t errCode,Parcel & parcel)1558 void NapiGetAccountInfoCallback::OnResult(int32_t errCode, Parcel &parcel)
1559 {
1560     std::unique_lock<std::mutex> lock(lockInfo_.mutex);
1561     if ((callbackRef_ == nullptr) && (deferred_ == nullptr)) {
1562         ACCOUNT_LOGE("js callback is nullptr");
1563         return;
1564     }
1565     uv_loop_s *loop = nullptr;
1566     uv_work_t *work = nullptr;
1567     if (!CreateExecEnv(env_, &loop, &work)) {
1568         ACCOUNT_LOGE("failed to init domain plugin execution environment");
1569         return;
1570     }
1571     auto *asyncContext = new (std::nothrow) GetAccountInfoAsyncContext(env_);
1572     if (asyncContext == nullptr) {
1573         delete work;
1574         return;
1575     }
1576     if (errCode == ERR_OK) {
1577         std::shared_ptr<AAFwk::WantParams> parameters(AAFwk::WantParams::Unmarshalling(parcel));
1578         if (parameters == nullptr) {
1579             ACCOUNT_LOGE("Parameters unmarshalling error");
1580             errCode = ERR_ACCOUNT_COMMON_READ_PARCEL_ERROR;
1581         } else {
1582             asyncContext->getAccountInfoParams = *parameters;
1583         }
1584     }
1585     asyncContext->errCode = errCode;
1586     asyncContext->callbackRef = callbackRef_;
1587     asyncContext->deferred = deferred_;
1588     work->data = reinterpret_cast<void *>(asyncContext);
1589     int resultCode = uv_queue_work(
1590         loop, work, [](uv_work_t *work) {}, GetAccountInfoCompleteWork);
1591     if (resultCode != 0) {
1592         ACCOUNT_LOGE("failed to uv_queue_work, errCode: %{public}d", errCode);
1593         delete asyncContext;
1594         delete work;
1595         return;
1596     }
1597     callbackRef_ = nullptr;
1598     deferred_ = nullptr;
1599 }
1600 
GetAccountInfoExecuteCB(napi_env env,void * data)1601 static void GetAccountInfoExecuteCB(napi_env env, void *data)
1602 {
1603     GetAccountInfoAsyncContext *asyncContext = reinterpret_cast<GetAccountInfoAsyncContext *>(data);
1604     auto callback =
1605         std::make_shared<NapiGetAccountInfoCallback>(env, asyncContext->callbackRef, asyncContext->deferred);
1606     asyncContext->errCode = DomainAccountClient::GetInstance().GetDomainAccountInfo(asyncContext->domainInfo, callback);
1607     if (asyncContext->errCode != ERR_OK) {
1608         Parcel emptyParcel;
1609         callback->OnResult(asyncContext->errCode, emptyParcel);
1610     }
1611     asyncContext->callbackRef = nullptr;
1612 }
1613 
GetAccountInfoCompleteCB(napi_env env,napi_status status,void * data)1614 static void GetAccountInfoCompleteCB(napi_env env, napi_status status, void *data)
1615 {
1616     delete reinterpret_cast<GetAccountInfoAsyncContext *>(data);
1617 }
1618 
GetDomainAccountInfo(napi_env env,napi_callback_info cbInfo)1619 napi_value NapiDomainAccountManager::GetDomainAccountInfo(napi_env env, napi_callback_info cbInfo)
1620 {
1621     auto context = std::make_unique<GetAccountInfoAsyncContext>(env);
1622     if (!ParseParamForGetAccountInfo(env, cbInfo, context.get())) {
1623         return nullptr;
1624     }
1625     napi_value result = nullptr;
1626     if (context->callbackRef == nullptr) {
1627         NAPI_CALL(env, napi_create_promise(env, &context->deferred, &result));
1628     }
1629     napi_value resource = nullptr;
1630     NAPI_CALL(env, napi_create_string_utf8(env, "getAccountInfo", NAPI_AUTO_LENGTH, &resource));
1631     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
1632         GetAccountInfoExecuteCB, GetAccountInfoCompleteCB,
1633         reinterpret_cast<void *>(context.get()), &context->work));
1634     NAPI_CALL(env, napi_queue_async_work_with_qos(env, context->work, napi_qos_default));
1635     context.release();
1636     return result;
1637 }
1638 
ParseParamForUpdateAccountInfo(napi_env env,napi_callback_info cbInfo,UpdateAccountInfoAsyncContext * asyncContext)1639 static bool ParseParamForUpdateAccountInfo(
1640     napi_env env, napi_callback_info cbInfo, UpdateAccountInfoAsyncContext *asyncContext)
1641 {
1642     size_t argc = ARG_SIZE_TWO;
1643     napi_value argv[ARG_SIZE_TWO] = {0};
1644     napi_get_cb_info(env, cbInfo, &argc, argv, nullptr, nullptr);
1645     if (argc != ARG_SIZE_TWO) {
1646         ACCOUNT_LOGE("The parameter of number should be two");
1647         std::string errMsg = "Parameter error. The number of parameters should be at least 2";
1648         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
1649         return false;
1650     }
1651     if (!ParseDomainAccountInfo(env, argv[0], asyncContext->oldAccountInfo)) {
1652         ACCOUNT_LOGE("Get oldAccountInfo failed");
1653         std::string errMsg = "Parameter error. The type of \"oldAccountInfo\" must be DomainAccountInfo";
1654         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
1655         return false;
1656     }
1657     if (!ParseDomainAccountInfo(env, argv[1], asyncContext->newAccountInfo)) {
1658         ACCOUNT_LOGE("Get newAccountInfo failed");
1659         std::string errMsg = "Parameter error. The type of \"newAccountInfo\" must be DomainAccountInfo";
1660         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, true);
1661         return false;
1662     }
1663     return true;
1664 }
1665 
UpdateAccountInfoExecuteCB(napi_env env,void * data)1666 static void UpdateAccountInfoExecuteCB(napi_env env, void *data)
1667 {
1668     UpdateAccountInfoAsyncContext *asyncContext = reinterpret_cast<UpdateAccountInfoAsyncContext *>(data);
1669     asyncContext->errCode = DomainAccountClient::GetInstance().UpdateAccountInfo(
1670         asyncContext->oldAccountInfo, asyncContext->newAccountInfo);
1671 }
1672 
UpdateAccountInfoCompleteCB(napi_env env,napi_status status,void * data)1673 static void UpdateAccountInfoCompleteCB(napi_env env, napi_status status, void *data)
1674 {
1675     UpdateAccountInfoAsyncContext *asyncContext = reinterpret_cast<UpdateAccountInfoAsyncContext *>(data);
1676     napi_value errJs = nullptr;
1677     napi_value dataJs = nullptr;
1678     if (asyncContext->errCode != ERR_OK) {
1679         errJs = GenerateBusinessError(asyncContext->env, asyncContext->errCode);
1680     } else {
1681         napi_get_null(asyncContext->env, &dataJs);
1682     }
1683     ProcessCallbackOrPromise(env, asyncContext, errJs, dataJs);
1684     delete asyncContext;
1685 }
1686 
UpdateAccountInfo(napi_env env,napi_callback_info cbInfo)1687 napi_value NapiDomainAccountManager::UpdateAccountInfo(napi_env env, napi_callback_info cbInfo)
1688 {
1689     auto context = std::make_unique<UpdateAccountInfoAsyncContext>(env);
1690     if (!ParseParamForUpdateAccountInfo(env, cbInfo, context.get())) {
1691         return nullptr;
1692     }
1693     napi_value result = nullptr;
1694     NAPI_CALL(env, napi_create_promise(env, &context->deferred, &result));
1695     napi_value resource = nullptr;
1696     NAPI_CALL(env, napi_create_string_utf8(env, "UpdateAccountInfo", NAPI_AUTO_LENGTH, &resource));
1697     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
1698         UpdateAccountInfoExecuteCB, UpdateAccountInfoCompleteCB,
1699         reinterpret_cast<void *>(context.get()), &context->work));
1700     NAPI_CALL(env, napi_queue_async_work_with_qos(env, context->work, napi_qos_default));
1701     context.release();
1702     return result;
1703 }
1704 }  // namespace AccountJsKit
1705 }  // namespace OHOS
1706