• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "permission_record_manager_napi.h"
16 #include <cinttypes>
17 #include <vector>
18 #include "privacy_kit.h"
19 #include "accesstoken_log.h"
20 #include "napi_context_common.h"
21 #include "napi_common.h"
22 #include "napi_error.h"
23 #include "napi/native_api.h"
24 #include "napi/native_node_api.h"
25 #include "privacy_error.h"
26 
27 namespace OHOS {
28 namespace Security {
29 namespace AccessToken {
30 std::mutex g_lockForPermActiveChangeSubscribers;
31 std::vector<RegisterPermActiveChangeContext*> g_permActiveChangeSubscribers;
32 static constexpr size_t MAX_CALLBACK_SIZE = 200;
33 static constexpr int32_t ADD_PERMISSION_RECORD_MAX_PARAMS = 5;
34 static constexpr int32_t GET_PERMISSION_RECORD_MAX_PARAMS = 2;
35 static constexpr int32_t ON_OFF_MAX_PARAMS = 3;
36 static constexpr int32_t START_STOP_MAX_PARAMS = 3;
37 
38 namespace {
39 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, SECURITY_DOMAIN_PRIVACY, "PermissionRecordManagerNapi"};
40 } // namespace
41 
GetJsErrorCode(uint32_t errCode)42 static int32_t GetJsErrorCode(uint32_t errCode)
43 {
44     int32_t jsCode = JS_OK;
45     switch (errCode) {
46         case ERR_PARAM_INVALID:
47             jsCode = JS_ERROR_PARAM_INVALID;
48             break;
49         case ERR_NOT_SYSTEM_APP:
50             jsCode = JS_ERROR_NOT_SYSTEM_APP;
51             break;
52         case ERR_SERVICE_ABNORMAL:
53         case ERR_READ_PARCEL_FAILED:
54         case ERR_WRITE_PARCEL_FAILED:
55         case ERR_IPC_PARCEL_FAILED:
56         case ERR_MALLOC_FAILED:
57             jsCode = JS_ERROR_SERVICE_NOT_RUNNING;
58             break;
59         case ERR_TOKENID_NOT_EXIST:
60             jsCode = JS_ERROR_TOKENID_NOT_EXIST;
61             break;
62         case ERR_PERMISSION_NOT_EXIST:
63             jsCode = JS_ERROR_PERMISSION_NOT_EXIST;
64             break;
65         case ERR_CALLBACK_ALREADY_EXIST:
66         case ERR_CALLBACK_NOT_EXIST:
67         case ERR_PERMISSION_ALREADY_START_USING:
68         case ERR_PERMISSION_NOT_START_USING:
69             jsCode = JS_ERROR_NOT_USE_TOGETHER;
70             break;
71         case ERR_CALLBACKS_EXCEED_LIMITATION:
72             jsCode = JS_ERROR_REGISTERS_EXCEED_LIMITATION;
73             break;
74         case ERR_PERMISSION_DENIED:
75             jsCode = JS_ERROR_PERMISSION_DENIED;
76             break;
77         default:
78             break;
79     }
80     ACCESSTOKEN_LOG_DEBUG(LABEL, "GetJsErrorCode nativeCode(%{public}d) jsCode(%{public}d).", errCode, jsCode);
81     return jsCode;
82 }
83 
ParamResolveErrorThrow(const napi_env & env,const std::string & param,const std::string & type)84 static void ParamResolveErrorThrow(const napi_env& env, const std::string& param, const std::string& type)
85 {
86     std::string errMsg = GetParamErrorMsg(param, type);
87     NAPI_CALL_RETURN_VOID(env, napi_throw(env, GenerateBusinessError(env, JS_ERROR_PARAM_ILLEGAL, errMsg)));
88 }
89 
ReturnPromiseResult(napi_env env,const RecordManagerAsyncContext & context,napi_value result)90 static void ReturnPromiseResult(napi_env env, const RecordManagerAsyncContext& context, napi_value result)
91 {
92     if (context.retCode != RET_SUCCESS) {
93         int32_t jsCode = GetJsErrorCode(context.retCode);
94         napi_value businessError = GenerateBusinessError(env, jsCode, GetErrorMessage(jsCode));
95         NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, context.deferred, businessError));
96     } else {
97         NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, context.deferred, result));
98     }
99 }
100 
ReturnCallbackResult(napi_env env,const RecordManagerAsyncContext & context,napi_value result)101 static void ReturnCallbackResult(napi_env env, const RecordManagerAsyncContext& context, napi_value result)
102 {
103     napi_value businessError = GetNapiNull(env);
104     if (context.retCode != RET_SUCCESS) {
105         int32_t jsCode = GetJsErrorCode(context.retCode);
106         businessError = GenerateBusinessError(env, jsCode, GetErrorMessage(jsCode));
107     }
108     napi_value results[ASYNC_CALL_BACK_VALUES_NUM] = { businessError, result };
109 
110     napi_value callback = nullptr;
111     napi_value thisValue = nullptr;
112     napi_value thatValue = nullptr;
113     NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &thisValue));
114     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 0, &thatValue));
115     NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, context.callbackRef, &callback));
116     NAPI_CALL_RETURN_VOID(env,
117         napi_call_function(env, thisValue, callback, ASYNC_CALL_BACK_VALUES_NUM, results, &thatValue));
118 }
119 
ParseAddPermissionRecord(const napi_env env,const napi_callback_info info,RecordManagerAsyncContext & asyncContext)120 static bool ParseAddPermissionRecord(
121     const napi_env env, const napi_callback_info info, RecordManagerAsyncContext& asyncContext)
122 {
123     size_t argc = ADD_PERMISSION_RECORD_MAX_PARAMS;
124     napi_value argv[ADD_PERMISSION_RECORD_MAX_PARAMS] = { nullptr };
125     napi_value thisVar = nullptr;
126     void* data = nullptr;
127 
128     NAPI_CALL_BASE(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data), false);
129     if (argc < ADD_PERMISSION_RECORD_MAX_PARAMS - 1) {
130         NAPI_CALL_BASE(env,
131             napi_throw(env, GenerateBusinessError(env, JS_ERROR_PARAM_ILLEGAL, "Parameter is missing.")), false);
132         return false;
133     }
134 
135     asyncContext.env = env;
136     // 0: the first parameter of argv
137     if (!ParseUint32(env, argv[0], asyncContext.tokenId)) {
138         ParamResolveErrorThrow(env, "tokenID", "number");
139         return false;
140     }
141 
142     // 1: the second parameter of argv
143     if (!ParseString(env, argv[1], asyncContext.permissionName)) {
144         ParamResolveErrorThrow(env, "permissionName", "string");
145         return false;
146     }
147 
148     // 2: the third parameter of argv
149     if (!ParseInt32(env, argv[2], asyncContext.successCount)) {
150         ParamResolveErrorThrow(env, "successCount", "number");
151         return false;
152     }
153 
154     // 3: the fourth parameter of argv
155     if (!ParseInt32(env, argv[3], asyncContext.failCount)) {
156         ParamResolveErrorThrow(env, "failCount", "number");
157         return false;
158     }
159     if (argc == ADD_PERMISSION_RECORD_MAX_PARAMS) {
160         // 4: : the fifth parameter of argv
161         if (!IsUndefinedOrNull(env, argv[4]) && !ParseCallback(env, argv[4], asyncContext.callbackRef)) {
162             ParamResolveErrorThrow(env, "callback", "AsyncCallback");
163             return false;
164         }
165     }
166     return true;
167 }
168 
ParseStartAndStopUsingPermission(const napi_env env,const napi_callback_info info,RecordManagerAsyncContext & asyncContext)169 static bool ParseStartAndStopUsingPermission(
170     const napi_env env, const napi_callback_info info, RecordManagerAsyncContext& asyncContext)
171 {
172     size_t argc = START_STOP_MAX_PARAMS;
173     napi_value argv[START_STOP_MAX_PARAMS] = { nullptr };
174     napi_value thisVar = nullptr;
175     void* data = nullptr;
176 
177     NAPI_CALL_BASE(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data), false);
178     if (argc < START_STOP_MAX_PARAMS - 1) {
179         NAPI_CALL_BASE(env,
180             napi_throw(env, GenerateBusinessError(env, JS_ERROR_PARAM_ILLEGAL, "Parameter is missing.")), false);
181         return false;
182     }
183 
184     asyncContext.env = env;
185     // 0: the first parameter of argv
186     if (!ParseUint32(env, argv[0], asyncContext.tokenId)) {
187         ParamResolveErrorThrow(env, "tokenId", "number");
188         return false;
189     }
190 
191     // 1: the second parameter of argv
192     if (!ParseString(env, argv[1], asyncContext.permissionName)) {
193         ParamResolveErrorThrow(env, "permissionName", "string");
194         return false;
195     }
196     if (argc == START_STOP_MAX_PARAMS) {
197         // 2: the third parameter of argv
198         if (!IsUndefinedOrNull(env, argv[2]) && !ParseCallback(env, argv[2], asyncContext.callbackRef)) {
199             ParamResolveErrorThrow(env, "callback", "AsyncCallback");
200             return false;
201         }
202     }
203     return true;
204 }
205 
ConvertDetailUsedRecord(napi_env env,napi_value value,const UsedRecordDetail & detailRecord)206 static void ConvertDetailUsedRecord(napi_env env, napi_value value, const UsedRecordDetail& detailRecord)
207 {
208     napi_value nStatus;
209     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, detailRecord.status, &nStatus));
210     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "status", nStatus));
211 
212     napi_value nTimestamp;
213     NAPI_CALL_RETURN_VOID(env, napi_create_int64(env, detailRecord.timestamp, &nTimestamp));
214     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "timestamp", nTimestamp));
215 
216     napi_value nAccessDuration;
217     NAPI_CALL_RETURN_VOID(env, napi_create_int64(env, detailRecord.accessDuration, &nAccessDuration));
218     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "accessDuration", nAccessDuration));
219 }
220 
ConvertPermissionUsedRecord(napi_env env,napi_value value,const PermissionUsedRecord & permissionRecord)221 static void ConvertPermissionUsedRecord(napi_env env, napi_value value, const PermissionUsedRecord& permissionRecord)
222 {
223     napi_value nPermissionName;
224     NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env,
225         permissionRecord.permissionName.c_str(), NAPI_AUTO_LENGTH, &nPermissionName));
226     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "permissionName", nPermissionName));
227 
228     napi_value nAccessCount;
229     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, permissionRecord.accessCount, &nAccessCount));
230     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "accessCount", nAccessCount));
231 
232     napi_value nRejectCount;
233     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, permissionRecord.rejectCount, &nRejectCount));
234     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "rejectCount", nRejectCount));
235 
236     napi_value nLastAccessTime;
237     NAPI_CALL_RETURN_VOID(env, napi_create_int64(env, permissionRecord.lastAccessTime, &nLastAccessTime));
238     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "lastAccessTime", nLastAccessTime));
239 
240     napi_value nLastRejectTime;
241     NAPI_CALL_RETURN_VOID(env, napi_create_int64(env, permissionRecord.lastRejectTime, &nLastRejectTime));
242     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "lastRejectTime", nLastRejectTime));
243 
244     napi_value nLastAccessDuration;
245     NAPI_CALL_RETURN_VOID(env, napi_create_int64(env, permissionRecord.lastAccessDuration, &nLastAccessDuration));
246     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "lastAccessDuration", nLastAccessDuration));
247 
248     size_t index = 0;
249     napi_value objAccessRecords;
250     NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &objAccessRecords));
251     for (const auto& accRecord : permissionRecord.accessRecords) {
252         napi_value objAccessRecord;
253         NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &objAccessRecord));
254         ConvertDetailUsedRecord(env, objAccessRecord, accRecord);
255         NAPI_CALL_RETURN_VOID(env, napi_set_element(env, objAccessRecords, index, objAccessRecord));
256         index++;
257     }
258     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "accessRecords", objAccessRecords));
259 
260     index = 0;
261     napi_value objRejectRecords;
262     NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &objRejectRecords));
263     for (const auto& rejRecord : permissionRecord.rejectRecords) {
264         napi_value objRejectRecord;
265         NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &objRejectRecord));
266         ConvertDetailUsedRecord(env, objRejectRecord, rejRecord);
267         NAPI_CALL_RETURN_VOID(env, napi_set_element(env, objRejectRecords, index, objRejectRecord));
268         index++;
269     }
270     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "rejectRecords", objRejectRecords));
271 }
272 
ConvertBundleUsedRecord(napi_env env,napi_value value,const BundleUsedRecord & bundleRecord)273 static void ConvertBundleUsedRecord(napi_env env, napi_value value, const BundleUsedRecord& bundleRecord)
274 {
275     napi_value nTokenId;
276     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, bundleRecord.tokenId, &nTokenId));
277     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "tokenId", nTokenId));
278 
279     napi_value nIsRemote;
280     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, bundleRecord.isRemote, &nIsRemote));
281     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "isRemote", nIsRemote));
282 
283     napi_value nDeviceId;
284     NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env,
285         bundleRecord.deviceId.c_str(), NAPI_AUTO_LENGTH, &nDeviceId));
286     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "deviceId", nDeviceId));
287 
288     napi_value nBundleName;
289     NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env,
290         bundleRecord.bundleName.c_str(), NAPI_AUTO_LENGTH, &nBundleName));
291     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "bundleName", nBundleName));
292     size_t index = 0;
293     napi_value objPermissionRecords;
294     NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &objPermissionRecords));
295     for (const auto& permRecord : bundleRecord.permissionRecords) {
296         napi_value objPermissionRecord;
297         NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &objPermissionRecord));
298         ConvertPermissionUsedRecord(env, objPermissionRecord, permRecord);
299         NAPI_CALL_RETURN_VOID(env, napi_set_element(env, objPermissionRecords, index, objPermissionRecord));
300         index++;
301     }
302     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "permissionRecords", objPermissionRecords));
303 }
304 
ProcessRecordResult(napi_env env,napi_value value,const PermissionUsedResult & result)305 static void ProcessRecordResult(napi_env env, napi_value value, const PermissionUsedResult& result)
306 {
307     napi_value nBeginTimestamp;
308     NAPI_CALL_RETURN_VOID(env, napi_create_int64(env, result.beginTimeMillis, &nBeginTimestamp));
309     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "beginTime", nBeginTimestamp));
310 
311     napi_value nEndTimestamp;
312     NAPI_CALL_RETURN_VOID(env, napi_create_int64(env, result.endTimeMillis, &nEndTimestamp));
313     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "endTime", nEndTimestamp));
314 
315     size_t index = 0;
316     napi_value objBundleRecords;
317     NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &objBundleRecords));
318     for (const auto& bundleRecord : result.bundleRecords) {
319         napi_value objBundleRecord;
320         NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &objBundleRecord));
321         ConvertBundleUsedRecord(env, objBundleRecord, bundleRecord);
322         NAPI_CALL_RETURN_VOID(env, napi_set_element(env, objBundleRecords, index, objBundleRecord));
323         index++;
324     }
325     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "bundleRecords", objBundleRecords));
326 }
327 
ParseRequest(const napi_env & env,const napi_value & value,PermissionUsedRequest & request)328 static bool ParseRequest(const napi_env& env, const napi_value& value, PermissionUsedRequest& request)
329 {
330     napi_value property = nullptr;
331     if (IsNeedParseProperty(env, value, "tokenId", property) && !ParseUint32(env, property, request.tokenId)) {
332         ParamResolveErrorThrow(env, "request:tokenId", "number");
333         return false;
334     }
335 
336     if (IsNeedParseProperty(env, value, "isRemote", property) && !ParseBool(env, property, request.isRemote)) {
337         ParamResolveErrorThrow(env, "request:isRemote", "boolean");
338         return false;
339     }
340 
341     if (IsNeedParseProperty(env, value, "deviceId", property) && !ParseString(env, property, request.deviceId)) {
342         ParamResolveErrorThrow(env, "request:deviceId", "string");
343         return false;
344     }
345 
346     if (IsNeedParseProperty(env, value, "bundleName", property) && !ParseString(env, property, request.bundleName)) {
347         ParamResolveErrorThrow(env, "request:bundleName", "string");
348         return false;
349     }
350 
351     if (IsNeedParseProperty(env, value, "beginTime", property) && !ParseInt64(env, property, request.beginTimeMillis)) {
352         ParamResolveErrorThrow(env, "request:beginTime", "number");
353         return false;
354     }
355 
356     if (IsNeedParseProperty(env, value, "endTime", property) && !ParseInt64(env, property, request.endTimeMillis)) {
357         ParamResolveErrorThrow(env, "request:endTime", "number");
358         return false;
359     }
360 
361     if (IsNeedParseProperty(env, value, "permissionNames", property) &&
362         !ParseStringArray(env, property, request.permissionList)) {
363         ParamResolveErrorThrow(env, "request:permissionNames", "Array<string>");
364         return false;
365     }
366 
367     property = nullptr;
368     NAPI_CALL_BASE(env, napi_get_named_property(env, value, "flag", &property), false);
369     int32_t flag;
370     if (!ParseInt32(env, property, flag)) {
371         ParamResolveErrorThrow(env, "request:flag", "number");
372         return false;
373     }
374     request.flag = static_cast<PermissionUsageFlagEnum>(flag);
375     return true;
376 }
377 
ParseGetPermissionUsedRecords(const napi_env env,const napi_callback_info info,RecordManagerAsyncContext & asyncContext)378 static bool ParseGetPermissionUsedRecords(
379     const napi_env env, const napi_callback_info info, RecordManagerAsyncContext& asyncContext)
380 {
381     size_t argc = GET_PERMISSION_RECORD_MAX_PARAMS;
382     napi_value argv[GET_PERMISSION_RECORD_MAX_PARAMS] = { nullptr };
383     napi_value thisVar = nullptr;
384     void* data = nullptr;
385     NAPI_CALL_BASE(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data), false);
386     if (argc < GET_PERMISSION_RECORD_MAX_PARAMS - 1) {
387         NAPI_CALL_BASE(env,
388             napi_throw(env, GenerateBusinessError(env, JS_ERROR_PARAM_ILLEGAL, "Parameter is missing.")), false);
389         return false;
390     }
391 
392     asyncContext.env = env;
393 
394     // 0: the first parameter of argv
395     if (!CheckType(env, argv[0], napi_object)) {
396         ParamResolveErrorThrow(env, "request", "PermissionUsedRequest");
397         return false;
398     }
399     if (!ParseRequest(env, argv[0], asyncContext.request)) {
400         return false;
401     }
402 
403     if (argc == GET_PERMISSION_RECORD_MAX_PARAMS) {
404         // 1: the second parameter of argv
405         if (!IsUndefinedOrNull(env, argv[1]) && !ParseCallback(env, argv[1], asyncContext.callbackRef)) {
406             ParamResolveErrorThrow(env, "callback", "AsyncCallback");
407             return false;
408         }
409     }
410     return true;
411 }
412 
AddPermissionUsedRecordExecute(napi_env env,void * data)413 static void AddPermissionUsedRecordExecute(napi_env env, void* data)
414 {
415     ACCESSTOKEN_LOG_DEBUG(LABEL, "AddPermissionUsedRecord execute.");
416     RecordManagerAsyncContext* asyncContext = reinterpret_cast<RecordManagerAsyncContext*>(data);
417     if (asyncContext == nullptr) {
418         return;
419     }
420 
421     asyncContext->retCode = PrivacyKit::AddPermissionUsedRecord(asyncContext->tokenId,
422         asyncContext->permissionName, asyncContext->successCount, asyncContext->failCount);
423 }
424 
AddPermissionUsedRecordComplete(napi_env env,napi_status status,void * data)425 static void AddPermissionUsedRecordComplete(napi_env env, napi_status status, void* data)
426 {
427     ACCESSTOKEN_LOG_DEBUG(LABEL, "AddPermissionUsedRecord complete.");
428     RecordManagerAsyncContext* asyncContext = reinterpret_cast<RecordManagerAsyncContext*>(data);
429     std::unique_ptr<RecordManagerAsyncContext> callbackPtr {asyncContext};
430 
431     napi_value result = GetNapiNull(env);
432     if (asyncContext->deferred != nullptr) {
433         ReturnPromiseResult(env, *asyncContext, result);
434     } else {
435         ReturnCallbackResult(env, *asyncContext, result);
436     }
437 }
438 
AddPermissionUsedRecord(napi_env env,napi_callback_info cbinfo)439 napi_value AddPermissionUsedRecord(napi_env env, napi_callback_info cbinfo)
440 {
441     ACCESSTOKEN_LOG_DEBUG(LABEL, "AddPermissionUsedRecord begin.");
442 
443     auto *asyncContext = new (std::nothrow) RecordManagerAsyncContext(env);
444     if (asyncContext == nullptr) {
445         ACCESSTOKEN_LOG_ERROR(LABEL, "new struct fail.");
446         return nullptr;
447     }
448 
449     std::unique_ptr<RecordManagerAsyncContext> callbackPtr {asyncContext};
450     if (!ParseAddPermissionRecord(env, cbinfo, *asyncContext)) {
451         return nullptr;
452     }
453 
454     napi_value result = nullptr;
455     if (asyncContext->callbackRef == nullptr) {
456         NAPI_CALL(env, napi_create_promise(env, &(asyncContext->deferred), &result));
457     } else {
458         NAPI_CALL(env, napi_get_undefined(env, &result));
459     }
460 
461     napi_value resource = nullptr;
462     NAPI_CALL(env, napi_create_string_utf8(env, "AddPermissionUsedRecord", NAPI_AUTO_LENGTH, &resource));
463 
464     NAPI_CALL(env, napi_create_async_work(env,
465         nullptr,
466         resource,
467         AddPermissionUsedRecordExecute,
468         AddPermissionUsedRecordComplete,
469         reinterpret_cast<void *>(asyncContext),
470         &(asyncContext->asyncWork)));
471     NAPI_CALL(env, napi_queue_async_work_with_qos(env, asyncContext->asyncWork, napi_qos_default));
472     callbackPtr.release();
473     return result;
474 }
475 
StartUsingPermissionExecute(napi_env env,void * data)476 static void StartUsingPermissionExecute(napi_env env, void* data)
477 {
478     ACCESSTOKEN_LOG_DEBUG(LABEL, "StartUsingPermission execute.");
479     RecordManagerAsyncContext* asyncContext = reinterpret_cast<RecordManagerAsyncContext*>(data);
480     if (asyncContext == nullptr) {
481         return;
482     }
483 
484     asyncContext->retCode = PrivacyKit::StartUsingPermission(asyncContext->tokenId,
485         asyncContext->permissionName);
486 }
487 
StartUsingPermissionComplete(napi_env env,napi_status status,void * data)488 static void StartUsingPermissionComplete(napi_env env, napi_status status, void* data)
489 {
490     ACCESSTOKEN_LOG_DEBUG(LABEL, "StartUsingPermission complete.");
491     RecordManagerAsyncContext* asyncContext = reinterpret_cast<RecordManagerAsyncContext*>(data);
492     std::unique_ptr<RecordManagerAsyncContext> callbackPtr{asyncContext};
493 
494     napi_value result = GetNapiNull(env);
495     if (asyncContext->deferred != nullptr) {
496         ReturnPromiseResult(env, *asyncContext, result);
497     } else {
498         ReturnCallbackResult(env, *asyncContext, result);
499     }
500 }
501 
StartUsingPermission(napi_env env,napi_callback_info cbinfo)502 napi_value StartUsingPermission(napi_env env, napi_callback_info cbinfo)
503 {
504     ACCESSTOKEN_LOG_DEBUG(LABEL, "StartUsingPermission begin.");
505     auto *asyncContext = new (std::nothrow) RecordManagerAsyncContext(env);
506     if (asyncContext == nullptr) {
507         ACCESSTOKEN_LOG_ERROR(LABEL, "new struct fail.");
508         return nullptr;
509     }
510 
511     std::unique_ptr<RecordManagerAsyncContext> callbackPtr {asyncContext};
512     if (!ParseStartAndStopUsingPermission(env, cbinfo, *asyncContext)) {
513         return nullptr;
514     }
515 
516     napi_value result = nullptr;
517     if (asyncContext->callbackRef == nullptr) {
518         NAPI_CALL(env, napi_create_promise(env, &(asyncContext->deferred), &result));
519     } else {
520         NAPI_CALL(env, napi_get_undefined(env, &result));
521     }
522 
523     napi_value resource = nullptr;
524     NAPI_CALL(env, napi_create_string_utf8(env, "StartUsingPermission", NAPI_AUTO_LENGTH, &resource));
525 
526     NAPI_CALL(env, napi_create_async_work(env,
527         nullptr,
528         resource,
529         StartUsingPermissionExecute,
530         StartUsingPermissionComplete,
531         reinterpret_cast<void *>(asyncContext),
532         &(asyncContext->asyncWork)));
533     NAPI_CALL(env, napi_queue_async_work_with_qos(env, asyncContext->asyncWork, napi_qos_default));
534     callbackPtr.release();
535     return result;
536 }
537 
StopUsingPermissionExecute(napi_env env,void * data)538 static void StopUsingPermissionExecute(napi_env env, void* data)
539 {
540     ACCESSTOKEN_LOG_DEBUG(LABEL, "StopUsingPermission execute.");
541     RecordManagerAsyncContext* asyncContext = reinterpret_cast<RecordManagerAsyncContext*>(data);
542     if (asyncContext == nullptr) {
543         return;
544     }
545 
546     asyncContext->retCode = PrivacyKit::StopUsingPermission(asyncContext->tokenId,
547         asyncContext->permissionName);
548 }
549 
StopUsingPermissionComplete(napi_env env,napi_status status,void * data)550 static void StopUsingPermissionComplete(napi_env env, napi_status status, void* data)
551 {
552     ACCESSTOKEN_LOG_DEBUG(LABEL, "StopUsingPermission complete.");
553     RecordManagerAsyncContext* asyncContext = reinterpret_cast<RecordManagerAsyncContext*>(data);
554     std::unique_ptr<RecordManagerAsyncContext> callbackPtr{asyncContext};
555 
556     napi_value result = GetNapiNull(env);
557     if (asyncContext->deferred != nullptr) {
558         ReturnPromiseResult(env, *asyncContext, result);
559     } else {
560         ReturnCallbackResult(env, *asyncContext, result);
561     }
562 }
563 
StopUsingPermission(napi_env env,napi_callback_info cbinfo)564 napi_value StopUsingPermission(napi_env env, napi_callback_info cbinfo)
565 {
566     ACCESSTOKEN_LOG_DEBUG(LABEL, "StopUsingPermission begin.");
567 
568     auto *asyncContext = new (std::nothrow) RecordManagerAsyncContext(env);
569     if (asyncContext == nullptr) {
570         ACCESSTOKEN_LOG_ERROR(LABEL, "new struct fail.");
571         return nullptr;
572     }
573 
574     std::unique_ptr<RecordManagerAsyncContext> callbackPtr {asyncContext};
575     if (!ParseStartAndStopUsingPermission(env, cbinfo, *asyncContext)) {
576         return nullptr;
577     }
578 
579     napi_value result = nullptr;
580     if (asyncContext->callbackRef == nullptr) {
581         NAPI_CALL(env, napi_create_promise(env, &(asyncContext->deferred), &result));
582     } else {
583         NAPI_CALL(env, napi_get_undefined(env, &result));
584     }
585 
586     napi_value resource = nullptr;
587     NAPI_CALL(env, napi_create_string_utf8(env, "StopUsingPermission", NAPI_AUTO_LENGTH, &resource));
588 
589     NAPI_CALL(env, napi_create_async_work(env,
590         nullptr,
591         resource,
592         StopUsingPermissionExecute,
593         StopUsingPermissionComplete,
594         reinterpret_cast<void *>(asyncContext),
595         &(asyncContext->asyncWork)));
596     NAPI_CALL(env, napi_queue_async_work_with_qos(env, asyncContext->asyncWork, napi_qos_default));
597     callbackPtr.release();
598     return result;
599 }
600 
GetPermissionUsedRecordsExecute(napi_env env,void * data)601 static void GetPermissionUsedRecordsExecute(napi_env env, void* data)
602 {
603     ACCESSTOKEN_LOG_DEBUG(LABEL, "GetPermissionUsedRecords execute.");
604     RecordManagerAsyncContext* asyncContext = reinterpret_cast<RecordManagerAsyncContext*>(data);
605     if (asyncContext == nullptr) {
606         return;
607     }
608 
609     asyncContext->retCode = PrivacyKit::GetPermissionUsedRecords(asyncContext->request, asyncContext->result);
610 }
611 
GetPermissionUsedRecordsComplete(napi_env env,napi_status status,void * data)612 static void GetPermissionUsedRecordsComplete(napi_env env, napi_status status, void* data)
613 {
614     ACCESSTOKEN_LOG_DEBUG(LABEL, "GetPermissionUsedRecords complete.");
615     RecordManagerAsyncContext* asyncContext = reinterpret_cast<RecordManagerAsyncContext*>(data);
616     std::unique_ptr<RecordManagerAsyncContext> callbackPtr{asyncContext};
617 
618     napi_value result = GetNapiNull(env);
619     NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &result));
620     ProcessRecordResult(env, result, asyncContext->result);
621     if (asyncContext->deferred != nullptr) {
622         ReturnPromiseResult(env, *asyncContext, result);
623     } else {
624         ReturnCallbackResult(env, *asyncContext, result);
625     }
626 }
627 
GetPermissionUsedRecords(napi_env env,napi_callback_info cbinfo)628 napi_value GetPermissionUsedRecords(napi_env env, napi_callback_info cbinfo)
629 {
630     ACCESSTOKEN_LOG_DEBUG(LABEL, "GetPermissionUsedRecords begin.");
631     auto *asyncContext = new (std::nothrow) RecordManagerAsyncContext(env);
632     if (asyncContext == nullptr) {
633         ACCESSTOKEN_LOG_ERROR(LABEL, "new struct fail.");
634         return nullptr;
635     }
636 
637     std::unique_ptr<RecordManagerAsyncContext> callbackPtr {asyncContext};
638     if (!ParseGetPermissionUsedRecords(env, cbinfo, *asyncContext)) {
639         return nullptr;
640     }
641 
642     napi_value result = nullptr;
643     if (asyncContext->callbackRef == nullptr) {
644         NAPI_CALL(env, napi_create_promise(env, &(asyncContext->deferred), &result));
645     } else {
646         NAPI_CALL(env, napi_get_undefined(env, &result));
647     }
648 
649     napi_value resource = nullptr;
650     NAPI_CALL(env, napi_create_string_utf8(env, "GetPermissionUsedRecords", NAPI_AUTO_LENGTH, &resource));
651 
652     NAPI_CALL(env, napi_create_async_work(env,
653         nullptr,
654         resource,
655         GetPermissionUsedRecordsExecute,
656         GetPermissionUsedRecordsComplete,
657         reinterpret_cast<void *>(asyncContext),
658         &(asyncContext->asyncWork)));
659     NAPI_CALL(env, napi_queue_async_work_with_qos(env, asyncContext->asyncWork, napi_qos_default));
660     callbackPtr.release();
661     return result;
662 }
663 
ParseInputToRegister(const napi_env env,const napi_callback_info cbInfo,RegisterPermActiveChangeContext & registerPermActiveChangeContext)664 static bool ParseInputToRegister(const napi_env env, const napi_callback_info cbInfo,
665     RegisterPermActiveChangeContext& registerPermActiveChangeContext)
666 {
667     size_t argc = ON_OFF_MAX_PARAMS;
668     napi_value argv[ON_OFF_MAX_PARAMS] = {nullptr};
669     napi_value thisVar = nullptr;
670     napi_ref callback = nullptr;
671     NAPI_CALL_BASE(env, napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, nullptr), false);
672     if (argc < ON_OFF_MAX_PARAMS) {
673         NAPI_CALL_BASE(
674             env, napi_throw(env, GenerateBusinessError(env, JS_ERROR_PARAM_ILLEGAL, "Parameter is missing.")), false);
675         return false;
676     }
677 
678     std::string type;
679     // 0: the first parameter of argv
680     if (!ParseString(env, argv[0], type)) {
681         ParamResolveErrorThrow(env, "type", "string");
682         return false;
683     }
684     std::vector<std::string> permList;
685     // 1: the second parameter of argv
686     if (!ParseStringArray(env, argv[1], permList)) {
687         ParamResolveErrorThrow(env, "permList", "Array<string>");
688         return false;
689     }
690     std::sort(permList.begin(), permList.end());
691     // 2: the third parameter of argv
692     if (!ParseCallback(env, argv[2], callback)) {
693         ParamResolveErrorThrow(env, "callback", "AsyncCallback");
694         return false;
695     }
696     registerPermActiveChangeContext.env = env;
697     registerPermActiveChangeContext.callbackRef = callback;
698     registerPermActiveChangeContext.type = type;
699     registerPermActiveChangeContext.subscriber = std::make_shared<PermActiveStatusPtr>(permList);
700     registerPermActiveChangeContext.subscriber->SetEnv(env);
701     registerPermActiveChangeContext.subscriber->SetCallbackRef(callback);
702     return true;
703 }
704 
ParseInputToUnregister(const napi_env env,const napi_callback_info cbInfo,UnregisterPermActiveChangeContext & unregisterPermActiveChangeContext)705 static bool ParseInputToUnregister(const napi_env env, const napi_callback_info cbInfo,
706     UnregisterPermActiveChangeContext& unregisterPermActiveChangeContext)
707 {
708     size_t argc = ON_OFF_MAX_PARAMS;
709     napi_value argv[ON_OFF_MAX_PARAMS] = {nullptr};
710     napi_value thisVar = nullptr;
711     napi_ref callback = nullptr;
712     NAPI_CALL_BASE(env, napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, nullptr), false);
713     if (argc < ON_OFF_MAX_PARAMS - 1) {
714         NAPI_CALL_BASE(
715             env, napi_throw(env, GenerateBusinessError(env, JS_ERROR_PARAM_ILLEGAL, "Parameter is missing.")), false);
716         return false;
717     }
718 
719     std::string type;
720     // 0: the first parameter of argv
721     if (!ParseString(env, argv[0], type)) {
722         ParamResolveErrorThrow(env, "permList", "Array<string>");
723         return false;
724     }
725     // 1: the second parameter of argv
726     std::vector<std::string> permList;
727     if (!ParseStringArray(env, argv[1], permList)) {
728         ParamResolveErrorThrow(env, "permList", "Array<string>");
729         return false;
730     }
731     std::sort(permList.begin(), permList.end());
732     if (argc == ON_OFF_MAX_PARAMS) {
733         // 2: the first parameter of argv
734         if (!ParseCallback(env, argv[2], callback)) {
735             ParamResolveErrorThrow(env, "callback", "AsyncCallback");
736             return false;
737         }
738     }
739     unregisterPermActiveChangeContext.env = env;
740     unregisterPermActiveChangeContext.callbackRef = callback;
741     unregisterPermActiveChangeContext.type = type;
742     unregisterPermActiveChangeContext.permList = permList;
743     return true;
744 }
745 
IsExistRegister(const PermActiveChangeContext * permActiveChangeContext)746 static bool IsExistRegister(const PermActiveChangeContext* permActiveChangeContext)
747 {
748     std::vector<std::string> targetPermList;
749     permActiveChangeContext->subscriber->GetPermList(targetPermList);
750     std::lock_guard<std::mutex> lock(g_lockForPermActiveChangeSubscribers);
751     for (const auto& item : g_permActiveChangeSubscribers) {
752         std::vector<std::string> permList;
753         item->subscriber->GetPermList(permList);
754         bool hasPermIntersection = false;
755         // Special cases:
756         // 1.Have registered full, and then register some
757         // 2.Have registered some, then register full
758         if (permList.empty() || targetPermList.empty()) {
759             hasPermIntersection = true;
760         }
761         for (const auto& PermItem : targetPermList) {
762             if (hasPermIntersection) {
763                 break;
764             }
765             auto iter = std::find(permList.begin(), permList.end(), PermItem);
766             if (iter != permList.end()) {
767                 hasPermIntersection = true;
768             }
769         }
770         if (hasPermIntersection &&
771             CompareCallbackRef(permActiveChangeContext->env, item->callbackRef, permActiveChangeContext->callbackRef)) {
772             return true;
773         }
774     }
775     return false;
776 }
777 
DeleteRegisterInVector(PermActiveChangeContext * permActiveChangeContext)778 static void DeleteRegisterInVector(PermActiveChangeContext* permActiveChangeContext)
779 {
780     std::vector<std::string> targetPermList;
781     permActiveChangeContext->subscriber->GetPermList(targetPermList);
782     std::lock_guard<std::mutex> lock(g_lockForPermActiveChangeSubscribers);
783     auto item = g_permActiveChangeSubscribers.begin();
784     while (item != g_permActiveChangeSubscribers.end()) {
785         std::vector<std::string> permList;
786         (*item)->subscriber->GetPermList(permList);
787         if ((permList == targetPermList) &&
788             CompareCallbackRef(permActiveChangeContext->env, (*item)->callbackRef,
789             permActiveChangeContext->callbackRef)) {
790             delete *item;
791             *item = nullptr;
792             g_permActiveChangeSubscribers.erase(item);
793             return;
794         } else {
795             ++item;
796         }
797     }
798 }
799 
FindAndGetSubscriber(UnregisterPermActiveChangeContext * unregisterPermActiveChangeContext,std::vector<RegisterPermActiveChangeContext * > & batchPermActiveChangeSubscribers)800 static bool FindAndGetSubscriber(UnregisterPermActiveChangeContext* unregisterPermActiveChangeContext,
801     std::vector<RegisterPermActiveChangeContext*>& batchPermActiveChangeSubscribers)
802 {
803     std::vector<std::string> targetPermList = unregisterPermActiveChangeContext->permList;
804     std::lock_guard<std::mutex> lock(g_lockForPermActiveChangeSubscribers);
805     bool callbackEqual;
806     napi_ref callbackRef = unregisterPermActiveChangeContext->callbackRef;
807     for (const auto& item : g_permActiveChangeSubscribers) {
808         std::vector<std::string> permList;
809         item->subscriber->GetPermList(permList);
810         // targetCallback == nullptr, Unsubscribe from all callbacks under the same permList
811         // targetCallback != nullptr, unregister the subscriber with same permList and callback
812         if (callbackRef == nullptr) {
813             callbackEqual = true;
814         } else {
815             callbackEqual = CompareCallbackRef(unregisterPermActiveChangeContext->env, item->callbackRef, callbackRef);
816         }
817 
818         if ((permList == targetPermList) && callbackEqual) {
819             batchPermActiveChangeSubscribers.emplace_back(item);
820             if (callbackRef != nullptr) {
821                 return true;
822             }
823         }
824     }
825     if (!batchPermActiveChangeSubscribers.empty()) {
826         return true;
827     }
828     return false;
829 }
830 
RegisterPermActiveChangeCallback(napi_env env,napi_callback_info cbInfo)831 napi_value RegisterPermActiveChangeCallback(napi_env env, napi_callback_info cbInfo)
832 {
833     RegisterPermActiveChangeContext* registerPermActiveChangeContext =
834         new (std::nothrow) RegisterPermActiveChangeContext();
835     if (registerPermActiveChangeContext == nullptr) {
836         ACCESSTOKEN_LOG_ERROR(LABEL, "insufficient memory for registerPermActiveChangeContext!");
837         return nullptr;
838     }
839     std::unique_ptr<RegisterPermActiveChangeContext> callbackPtr {registerPermActiveChangeContext};
840     if (!ParseInputToRegister(env, cbInfo, *registerPermActiveChangeContext)) {
841         return nullptr;
842     }
843     if (IsExistRegister(registerPermActiveChangeContext)) {
844         ACCESSTOKEN_LOG_ERROR(LABEL, "Subscribe failed. The current subscriber has been existed");
845         std::string errMsg = GetErrorMessage(JsErrorCode::JS_ERROR_PARAM_INVALID);
846         NAPI_CALL(env, napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_INVALID, errMsg)));
847         return nullptr;
848     }
849     int32_t result = PrivacyKit::RegisterPermActiveStatusCallback(registerPermActiveChangeContext->subscriber);
850     if (result != RET_SUCCESS) {
851         ACCESSTOKEN_LOG_ERROR(LABEL, "RegisterPermActiveStatusCallback failed");
852         int32_t jsCode = GetJsErrorCode(result);
853         std::string errMsg = GetErrorMessage(jsCode);
854         NAPI_CALL(env, napi_throw(env, GenerateBusinessError(env, jsCode, errMsg)));
855         return nullptr;
856     }
857     {
858         std::lock_guard<std::mutex> lock(g_lockForPermActiveChangeSubscribers);
859         if (g_permActiveChangeSubscribers.size() >= MAX_CALLBACK_SIZE) {
860             ACCESSTOKEN_LOG_ERROR(LABEL, "subscribers size has reached max value");
861             return nullptr;
862         }
863         g_permActiveChangeSubscribers.emplace_back(registerPermActiveChangeContext);
864     }
865     callbackPtr.release();
866     return nullptr;
867 }
868 
UnregisterPermActiveChangeCallback(napi_env env,napi_callback_info cbInfo)869 napi_value UnregisterPermActiveChangeCallback(napi_env env, napi_callback_info cbInfo)
870 {
871     UnregisterPermActiveChangeContext* unregisterPermActiveChangeContext =
872         new (std::nothrow) UnregisterPermActiveChangeContext();
873     if (unregisterPermActiveChangeContext == nullptr) {
874         ACCESSTOKEN_LOG_ERROR(LABEL, "insufficient memory for unregisterPermActiveChangeContext!");
875         return nullptr;
876     }
877     std::unique_ptr<UnregisterPermActiveChangeContext> callbackPtr {unregisterPermActiveChangeContext};
878     if (!ParseInputToUnregister(env, cbInfo, *unregisterPermActiveChangeContext)) {
879         return nullptr;
880     }
881     std::vector<RegisterPermActiveChangeContext*> batchPermActiveChangeSubscribers;
882     if (!FindAndGetSubscriber(unregisterPermActiveChangeContext, batchPermActiveChangeSubscribers)) {
883         ACCESSTOKEN_LOG_ERROR(LABEL, "Unsubscribe failed. The current subscriber does not exist");
884         std::string errMsg = GetErrorMessage(JsErrorCode::JS_ERROR_PARAM_INVALID);
885         NAPI_CALL(env, napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_INVALID, errMsg)));
886         return nullptr;
887     }
888     for (const auto& item : batchPermActiveChangeSubscribers) {
889         int32_t result = PrivacyKit::UnRegisterPermActiveStatusCallback(item->subscriber);
890         if (result == RET_SUCCESS) {
891             DeleteRegisterInVector(item);
892         } else {
893             ACCESSTOKEN_LOG_ERROR(LABEL, "UnregisterPermActiveChangeCompleted failed");
894             int32_t jsCode = GetJsErrorCode(result);
895             std::string errMsg = GetErrorMessage(jsCode);
896             NAPI_CALL(env, napi_throw(env, GenerateBusinessError(env, jsCode, errMsg)));
897         }
898     }
899     return nullptr;
900 }
901 }  // namespace AccessToken
902 }  // namespace Security
903 }  // namespace OHOS