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