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