1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "security_guard_napi.h"
16 #include <future>
17 #include <unistd.h>
18 #include <syscall.h>
19 #include <unordered_map>
20 #include <map>
21 #include <algorithm>
22
23 #include "napi_request_data_manager.h"
24 #include "napi_security_event_querier.h"
25 #include "security_event.h"
26 #include "security_config_update_info.h"
27 #include "security_event_ruler.h"
28 #include "security_guard_define.h"
29 #include "security_guard_log.h"
30 #include "security_guard_sdk_adaptor.h"
31 #include "i_collector_subscriber.h"
32 #include "uv.h"
33
34 #include "securec.h"
35
36 using namespace OHOS::Security::SecurityGuard;
37 using namespace OHOS::Security::SecurityCollector;
38 constexpr std::int32_t ARGS_SIZE_ONE = 1;
39 constexpr std::int32_t ARGS_SIZE_THREE = 3;
40 constexpr int PARAMZERO = 0;
41 constexpr int PARAMONE = 1;
42 constexpr char NAPI_EVENT_EVENT_ID_ATTR[] = "eventId";
43 constexpr char NAPI_EVENT_VERSION_ATTR[] = "version";
44 constexpr char NAPI_EVENT_CONTENT_ATTR[] = "content";
45
46 constexpr int NAPI_START_COLLECTOR_ARGS_CNT = 2;
47 constexpr int NAPI_STOP_COLLECTOR_ARGS_CNT = 1;
48 constexpr int NAPI_REPORT_EVENT_INFO_ARGS_CNT = 1;
49 constexpr int NAPI_UPDATE_POLICY_FILE_ARGS_CNT = 1;
50 constexpr int NAPI_GET_MODEL_RESULT_ARGS_CNT = 1;
51 constexpr int NAPI_QUERY_SECURITY_EVENT_ARGS_CNT = 2;
52
53 constexpr int TIME_MAX_LEN = 15;
54
55 using NAPI_QUERIER_PAIR = std::pair<pid_t, std::shared_ptr<NapiSecurityEventQuerier>>;
56 static std::unordered_map<napi_ref, NAPI_QUERIER_PAIR> queriers;
57 static std::mutex g_subscribeMutex;
58 static std::mutex g_queryMutex;
59 std::map<napi_env, std::vector<SubscribeCBInfo *>> g_subscribers;
60
61 static const std::unordered_map<int32_t, std::pair<int32_t, std::string>> g_errorStringMap = {
62 { SUCCESS, { JS_ERR_SUCCESS, "The operation was successful" }},
63 { NO_PERMISSION, { JS_ERR_NO_PERMISSION, "check permission fail"} },
64 { BAD_PARAM, { JS_ERR_BAD_PARAM, "Parameter error, please make sure using the correct value"} },
65 { NO_SYSTEMCALL, { JS_ERR_NO_SYSTEMCALL, "non-system application uses the system API"} },
66 };
67
ConvertToJsErrMsg(int32_t code)68 static std::string ConvertToJsErrMsg(int32_t code)
69 {
70 auto iter = g_errorStringMap.find(code);
71 if (iter != g_errorStringMap.end()) {
72 return iter->second.second;
73 } else {
74 return "Unknown error, please reboot your device and try again";
75 }
76 }
77
ConvertToJsErrCode(int32_t code)78 static int32_t ConvertToJsErrCode(int32_t code)
79 {
80 auto iter = g_errorStringMap.find(code);
81 if (iter != g_errorStringMap.end()) {
82 return iter->second.first;
83 } else {
84 return JS_ERR_SYS_ERR;
85 }
86 }
87
NapiCreateObject(const napi_env env)88 static napi_value NapiCreateObject(const napi_env env)
89 {
90 napi_value result = nullptr;
91 napi_status status = napi_create_object(env, &result);
92 if (status != napi_ok || result == nullptr) {
93 SGLOGE("failed to create napi value of object type.");
94 }
95 return result;
96 }
97
NapiCreateString(const napi_env env, const std::string &value)98 static napi_value NapiCreateString(const napi_env env, const std::string &value)
99 {
100 napi_value result = nullptr;
101 napi_status status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
102 SGLOGD("create napi value of string type, value is %{public}s.", value.c_str());
103 if (status != napi_ok || result == nullptr) {
104 SGLOGE("failed to create napi value of string type.");
105 }
106 return result;
107 }
108
NapiCreateInt64(const napi_env env, int64_t value)109 static napi_value NapiCreateInt64(const napi_env env, int64_t value)
110 {
111 napi_value result = nullptr;
112 napi_status status = napi_create_int64(env, value, &result);
113 SGLOGI("create napi value of int64 type, value is %{public}" PRId64, value);
114 if (status != napi_ok || result == nullptr) {
115 SGLOGE("failed to create napi value of int64 type.");
116 }
117 return result;
118 }
119
NapiCreateInt32(const napi_env env, int32_t value)120 static napi_value NapiCreateInt32(const napi_env env, int32_t value)
121 {
122 napi_value result = nullptr;
123 napi_status status = napi_create_int32(env, value, &result);
124 SGLOGD("create napi value of int32 type, value is %{public}d.", value);
125 if (status != napi_ok || result == nullptr) {
126 SGLOGE("failed to create napi value of int32 type.");
127 }
128 return result;
129 }
130
NapiCreateUint32(const napi_env env, uint32_t value)131 static napi_value NapiCreateUint32(const napi_env env, uint32_t value)
132 {
133 napi_value result = nullptr;
134 napi_status status = napi_create_uint32(env, value, &result);
135 SGLOGI("create napi value of uint32 type, value is %{public}u.", value);
136 if (status != napi_ok || result == nullptr) {
137 SGLOGE("failed to create napi value of uint32 type.");
138 }
139 return result;
140 }
141
GenerateBusinessError(napi_env env, int32_t code)142 static napi_value GenerateBusinessError(napi_env env, int32_t code)
143 {
144 napi_value result;
145 SGLOGD("GenerateBusinessError code:%{public}d", code);
146 if (code == SUCCESS) {
147 napi_get_undefined(env, &result);
148 } else {
149 int32_t jsErrCode = ConvertToJsErrCode(code);
150 napi_value errCode = NapiCreateInt32(env, jsErrCode);
151
152 std::string errMsgStr = ConvertToJsErrMsg(code);
153 napi_value errMsg = NapiCreateString(env, errMsgStr);
154
155 napi_create_error(env, nullptr, errMsg, &result);
156 napi_set_named_property(env, result, "code", errCode);
157 napi_set_named_property(env, result, "message", errMsg);
158 }
159 return result;
160 }
161
GenerateBusinessError(napi_env env, int32_t code, const std::string &msg)162 static napi_value GenerateBusinessError(napi_env env, int32_t code, const std::string &msg)
163 {
164 napi_value result;
165 SGLOGD("GenerateBusinessError code:%{public}d", code);
166 if (code == SUCCESS) {
167 napi_get_undefined(env, &result);
168 } else {
169 int32_t jsErrCode = ConvertToJsErrCode(code);
170 napi_value errCode = NapiCreateInt32(env, jsErrCode);
171 napi_value errMsg = NapiCreateString(env, msg);
172
173 napi_create_error(env, nullptr, errMsg, &result);
174 napi_set_named_property(env, result, "code", errCode);
175 napi_set_named_property(env, result, "message", errMsg);
176 }
177 return result;
178 }
179
ParseInt64(napi_env env, napi_value object, const std::string &key, int64_t &value)180 static napi_value ParseInt64(napi_env env, napi_value object, const std::string &key, int64_t &value)
181 {
182 napi_value result;
183 bool hasProperty = false;
184 NAPI_CALL(env, napi_has_named_property(env, object, key.c_str(), &hasProperty));
185 if (!hasProperty) {
186 std::string msg = "no such param" + key;
187 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, msg));
188 return nullptr;
189 }
190 NAPI_CALL(env, napi_get_named_property(env, object, key.c_str(), &result));
191 if (result == nullptr) {
192 SGLOGE("get %{public}s failed", key.c_str());
193 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, "get key failed."));
194 return nullptr;
195 }
196
197 napi_valuetype type;
198 NAPI_CALL(env, napi_typeof(env, result, &type));
199 if (type != napi_number) {
200 SGLOGE("type of param %{public}s is not number", key.c_str());
201 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, "type of param is not number."));
202 return nullptr;
203 }
204
205 NAPI_CALL(env, napi_get_value_int64(env, result, &value));
206 return NapiCreateInt64(env, ConvertToJsErrCode(SUCCESS));
207 }
208
ParseInt32(napi_env env, napi_value object, const std::string &key, int32_t &value)209 static napi_value ParseInt32(napi_env env, napi_value object, const std::string &key, int32_t &value)
210 {
211 napi_value result;
212 bool hasProperty = false;
213 NAPI_CALL(env, napi_has_named_property(env, object, key.c_str(), &hasProperty));
214 if (!hasProperty) {
215 std::string msg = "no such param" + key;
216 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, msg));
217 return nullptr;
218 }
219 NAPI_CALL(env, napi_get_named_property(env, object, key.c_str(), &result));
220 if (result == nullptr) {
221 SGLOGE("get %{public}s failed", key.c_str());
222 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, "get key failed."));
223 return nullptr;
224 }
225
226 napi_valuetype type;
227 NAPI_CALL(env, napi_typeof(env, result, &type));
228 if (type != napi_number) {
229 SGLOGE("type of param %{public}s is not number", key.c_str());
230 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, "type of param is not number."));
231 return nullptr;
232 }
233
234 NAPI_CALL(env, napi_get_value_int32(env, result, &value));
235 return NapiCreateInt32(env, ConvertToJsErrCode(SUCCESS));
236 }
237
GetString(napi_env env, napi_value object, const std::string &key, char *value, size_t &maxLen)238 static napi_value GetString(napi_env env, napi_value object, const std::string &key, char *value, size_t &maxLen)
239 {
240 napi_valuetype type;
241 NAPI_CALL(env, napi_typeof(env, object, &type));
242 if (type != napi_string) {
243 std::string msg = "param " + key + " is not string";
244 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, msg));
245 return nullptr;
246 }
247
248 size_t size = 0;
249 NAPI_CALL(env, napi_get_value_string_utf8(env, object, nullptr, 0, &size));
250 if (size >= maxLen) {
251 std::string msg = "param " + key + " is too long";
252 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, msg));
253 return nullptr;
254 }
255
256 maxLen = size + 1;
257 NAPI_CALL(env, napi_get_value_string_utf8(env, object, value, maxLen, &maxLen));
258 return NapiCreateInt32(env, SUCCESS);
259 }
260
ParseString(napi_env env, napi_value object, const std::string &key, char *value, size_t &maxLen)261 static napi_value ParseString(napi_env env, napi_value object, const std::string &key, char *value, size_t &maxLen)
262 {
263 napi_value result;
264 NAPI_CALL(env, napi_get_named_property(env, object, key.c_str(), &result));
265 if (result == nullptr) {
266 std::string msg = "param " + key + " is not found";
267 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, msg));
268 return nullptr;
269 }
270
271 return GetString(env, result, key, value, maxLen);
272 }
273
ParseEventInfo(napi_env env, napi_value object, ReportSecurityEventInfoContext *context)274 static napi_value ParseEventInfo(napi_env env, napi_value object, ReportSecurityEventInfoContext *context)
275 {
276 napi_valuetype type = napi_undefined;
277 NAPI_CALL(env, napi_typeof(env, object, &type));
278 if (type != napi_object) {
279 GenerateBusinessError(env, BAD_PARAM, "type of param eventInfo is not object");
280 return nullptr;
281 }
282
283 if (ParseInt64(env, object, "eventId", context->eventId) == nullptr) {
284 return nullptr;
285 }
286
287 char version[VERSION_MAX_LEN] = {0};
288 size_t len = VERSION_MAX_LEN;
289 if (ParseString(env, object, "version", version, len) == nullptr) {
290 return nullptr;
291 }
292 context->version = version;
293
294 char content[CONTENT_MAX_LEN] = {0};
295 len = CONTENT_MAX_LEN;
296 if (ParseString(env, object, "content", content, len) == nullptr) {
297 return nullptr;
298 }
299 context->content = content;
300 return NapiCreateInt32(env, SUCCESS);
301 }
302
NapiReportSecurityInfo(napi_env env, napi_callback_info info)303 static napi_value NapiReportSecurityInfo(napi_env env, napi_callback_info info)
304 {
305 size_t argc = NAPI_REPORT_EVENT_INFO_ARGS_CNT;
306 napi_value argv[NAPI_REPORT_EVENT_INFO_ARGS_CNT] = {nullptr};
307 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
308 if (argc != NAPI_REPORT_EVENT_INFO_ARGS_CNT) {
309 SGLOGE("report eventInfo arguments count is not expected");
310 napi_throw(env, GenerateBusinessError(env, BAD_PARAM));
311 return nullptr;
312 }
313
314 ReportSecurityEventInfoContext context = {};
315 napi_value ret = ParseEventInfo(env, argv[0], &context);
316 if (ret == nullptr) {
317 SGLOGE("report eventInfo parse error");
318 napi_throw(env, GenerateBusinessError(env, BAD_PARAM));
319 return nullptr;
320 }
321
322 auto eventInfo = std::make_shared<EventInfo>(context.eventId, context.version, context.content);
323 int32_t code = SecurityGuardSdkAdaptor::ReportSecurityInfo(eventInfo);
324 if (code != SUCCESS) {
325 SGLOGE("report eventInfo error, code=%{public}d", code);
326 napi_throw(env, GenerateBusinessError(env, code));
327 return nullptr;
328 }
329 return NapiCreateInt32(env, SUCCESS);
330 }
331
IsNum(const std::string &s)332 static bool IsNum(const std::string &s)
333 {
334 return std::all_of(s.begin(), s.end(), isdigit);
335 }
336
GetConditionsTime(napi_env env, napi_value object, const std::string &key, std::string &value)337 static napi_value GetConditionsTime(napi_env env, napi_value object, const std::string &key, std::string &value)
338 {
339 char time[TIME_MAX_LEN] = {0};
340 size_t len = TIME_MAX_LEN;
341 bool hasProperty = false;
342 NAPI_CALL(env, napi_has_named_property(env, object, key.c_str(), &hasProperty));
343 if (!hasProperty) {
344 SGLOGE("no %{public}s param", key.c_str());
345 return NapiCreateInt32(env, SUCCESS);
346 }
347 napi_value result;
348 NAPI_CALL(env, napi_get_named_property(env, object, key.c_str(), &result));
349 if (result == nullptr) {
350 SGLOGE("get %{public}s failed", key.c_str());
351 return nullptr;
352 }
353
354 result = GetString(env, result, key, time, len);
355 if (result == nullptr) {
356 SGLOGE("get %{public}s failed", key.c_str());
357 return nullptr;
358 }
359 value = time;
360 if (!IsNum(value) || value.length() != (TIME_MAX_LEN - 1)) {
361 SGLOGE("time invalid %{public}s", key.c_str());
362 return nullptr;
363 }
364 return NapiCreateInt32(env, SUCCESS);
365 }
366
RequestSecurityModelResultExecute(napi_env env, void *data)367 static void RequestSecurityModelResultExecute(napi_env env, void *data)
368 {
369 if (data == nullptr) {
370 return;
371 }
372 auto *context = static_cast<RequestSecurityModelResultContext *>(data);
373 auto promise = std::make_shared<std::promise<SecurityModel>>();
374 auto future = promise->get_future();
375 auto func = [promise] (const std::string &devId, uint32_t modelId, const std::string &result) mutable -> int32_t {
376 SecurityModel model = {
377 .devId = devId,
378 .modelId = modelId,
379 .result = result
380 };
381 promise->set_value(model);
382 return SUCCESS;
383 };
384 context->ret =
385 SecurityGuardSdkAdaptor::RequestSecurityModelResult(context->deviceId, context->modelId, context->param, func);
386 if (context->ret != SUCCESS) {
387 SGLOGE("RequestSecurityModelResultSync error, ret=%{public}d", context->ret);
388 return;
389 }
390 std::chrono::milliseconds span(TIMEOUT_REPLY);
391 if (future.wait_for(span) == std::future_status::timeout) {
392 SGLOGE("wait timeout");
393 context->ret = TIME_OUT;
394 return;
395 }
396 context->result = future.get();
397 }
398
GenerateSecurityModelResult(napi_env env, RequestSecurityModelResultContext *context)399 static napi_value GenerateSecurityModelResult(napi_env env, RequestSecurityModelResultContext *context)
400 {
401 napi_value ret = NapiCreateObject(env);
402 if (ret == nullptr) {
403 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, "napi create object error ."));
404 }
405 napi_value deviceId = NapiCreateString(env, context->result.devId.c_str());
406 napi_value modelId = NapiCreateUint32(env, context->result.modelId);
407 napi_value result = NapiCreateString(env, context->result.result.c_str());
408
409 napi_set_named_property(env, ret, NAPI_SECURITY_MODEL_RESULT_DEVICE_ID_ATTR, deviceId);
410 napi_set_named_property(env, ret, NAPI_SECURITY_MODEL_RESULT_MODEL_ID_ATTR, modelId);
411 napi_set_named_property(env, ret, NAPI_SECURITY_MODEL_RESULT_RESULT_ATTR, result);
412 return ret;
413 }
414
GenerateReturnValue(napi_env env, RequestSecurityModelResultContext *context)415 static napi_value GenerateReturnValue(napi_env env, RequestSecurityModelResultContext *context)
416 {
417 napi_value result;
418 if (context->ret == SUCCESS) {
419 result = GenerateSecurityModelResult(env, context);
420 } else {
421 napi_get_undefined(env, &result);
422 }
423 return result;
424 }
425
RequestSecurityModelResultComplete(napi_env env, napi_status status, void *data)426 static void RequestSecurityModelResultComplete(napi_env env, napi_status status, void *data)
427 {
428 if (data == nullptr) {
429 return;
430 }
431 auto *context = static_cast<RequestSecurityModelResultContext *>(data);
432 napi_value result[2] = {0};
433 result[0] = GenerateBusinessError(env, context->ret);
434 result[1] = GenerateReturnValue(env, context);
435 if (context->ref != nullptr) {
436 napi_value callbackfunc = nullptr;
437 napi_get_reference_value(env, context->ref, &callbackfunc);
438 napi_value returnVal;
439 napi_call_function(env, nullptr, callbackfunc, sizeof(result) / sizeof(result[0]), result, &returnVal);
440 napi_delete_reference(env, context->ref);
441 context->ref = nullptr;
442 } else {
443 if (context->ret == SUCCESS) {
444 napi_resolve_deferred(env, context->deferred, result[1]);
445 } else {
446 napi_reject_deferred(env, context->deferred, result[0]);
447 }
448 }
449 napi_delete_async_work(env, context->asyncWork);
450 delete context;
451 }
452
ParseModelId(napi_env env, const std::string &modelNameStr, uint32_t &modelId)453 static napi_value ParseModelId(napi_env env, const std::string &modelNameStr, uint32_t &modelId)
454 {
455 if (modelNameStr == "SecurityGuard_JailbreakCheck") {
456 modelId = ModelIdType::ROOT_SCAN_MODEL_ID;
457 } else if (modelNameStr == "SecurityGuard_IntegrityCheck") {
458 modelId = ModelIdType::DEVICE_COMPLETENESS_MODEL_ID;
459 } else if (modelNameStr == "SecurityGuard_SimulatorCheck") {
460 modelId = ModelIdType::PHYSICAL_MACHINE_DETECTION_MODEL_ID;
461 } else if (modelNameStr == "SecurityGuard_RiskFactorCheck") {
462 modelId = ModelIdType::SECURITY_RISK_FACTOR_MODEL_ID;
463 } else {
464 napi_throw(env, GenerateBusinessError(env, BAD_PARAM,
465 "Parameter error, please make sure using the correct model name"));
466 return nullptr;
467 }
468 return NapiCreateInt32(env, SUCCESS);
469 }
470
ParseOptionalString(napi_env env, napi_value object, const std::string &key, uint32_t maxLen)471 static std::string ParseOptionalString(napi_env env, napi_value object, const std::string &key, uint32_t maxLen)
472 {
473 bool hasProperty = false;
474 NAPI_CALL(env, napi_has_named_property(env, object, key.c_str(), &hasProperty));
475 if (!hasProperty) {
476 SGLOGE("no %{public}s param", key.c_str());
477 return "";
478 }
479 napi_value value = nullptr;
480 NAPI_CALL(env, napi_get_named_property(env, object, key.c_str(), &value));
481 if (value == nullptr) {
482 SGLOGE("get %{public}s failed", key.c_str());
483 return "";
484 }
485 size_t len = maxLen;
486 std::vector<char> str(len + 1, '\0');
487 napi_value result = GetString(env, value, key, str.data(), len);
488 if (result == nullptr) {
489 SGLOGE("get %{public}s failed", key.c_str());
490 return "";
491 }
492 return std::string{str.data()};
493 }
494
ParseModelRule(const napi_env &env, napi_value napiValue, ModelRule &modelRule)495 static bool ParseModelRule(const napi_env &env, napi_value napiValue, ModelRule &modelRule)
496 {
497 napi_valuetype type = napi_undefined;
498 NAPI_CALL_BASE(env, napi_typeof(env, napiValue, &type), false);
499 if (type != napi_object) {
500 std::string errMsg = "Parameter error. type of param ModelRule is not object.";
501 SGLOGE("Parameter error. type of param ModelRule is not object.");
502 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, errMsg));
503 return false;
504 }
505 char modelName[MODEL_NAME_MAX_LEN] = {0};
506 size_t len = MODEL_NAME_MAX_LEN;
507 if (ParseString(env, napiValue, "modelName", modelName, len) == nullptr) {
508 std::string errMsg = "Parameter error. type of param ModelRule.modelName is not string.";
509 SGLOGE("Parameter error. type of param ModelRule.modelName is not string.");
510 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, errMsg));
511 return false;
512 }
513 modelRule.modelName = std::string(modelName);
514 modelRule.param = ParseOptionalString(env, napiValue, "param", PARAM_MAX_LEN);
515 return true;
516 }
517
NapiGetModelResult(napi_env env, napi_callback_info info)518 static napi_value NapiGetModelResult(napi_env env, napi_callback_info info)
519 {
520 size_t argc = NAPI_GET_MODEL_RESULT_ARGS_CNT;
521 napi_value argv[NAPI_GET_MODEL_RESULT_ARGS_CNT] = {nullptr};
522 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
523 if (argc != NAPI_GET_MODEL_RESULT_ARGS_CNT) {
524 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, "arguments count is not expected"));
525 return nullptr;
526 }
527 uint32_t modelId = 0;
528 ModelRule modelRule = {};
529 if (!ParseModelRule(env, argv[0], modelRule)) {
530 return nullptr;
531 }
532 if (ParseModelId(env, modelRule.modelName, modelId) == nullptr) {
533 return nullptr;
534 }
535
536 RequestSecurityModelResultContext *context = new (std::nothrow) RequestSecurityModelResultContext();
537 if (context == nullptr) {
538 napi_throw(env, GenerateBusinessError(env, NULL_OBJECT, "context new failed, no memory left."));
539 return nullptr;
540 }
541 context->modelId = modelId;
542 context->param = modelRule.param;
543 napi_value promise = nullptr;
544 NAPI_CALL(env, napi_create_promise(env, &context->deferred, &promise));
545 napi_value resourceName = NapiCreateString(env, "NapiGetModelResult");
546 NAPI_CALL(env, napi_create_async_work(env, nullptr, resourceName, RequestSecurityModelResultExecute,
547 RequestSecurityModelResultComplete, static_cast<void *>(context), &context->asyncWork));
548 NAPI_CALL(env, napi_queue_async_work(env, context->asyncWork));
549 return promise;
550 }
551
ParsePolicyFileInfo(napi_env env, napi_value object, NapiSecurityPolicyFileInfo *context)552 static napi_value ParsePolicyFileInfo(napi_env env, napi_value object, NapiSecurityPolicyFileInfo *context)
553 {
554 napi_valuetype type = napi_undefined;
555 NAPI_CALL(env, napi_typeof(env, object, &type));
556 if (type != napi_object) {
557 GenerateBusinessError(env, BAD_PARAM, "type of param eventInfo is not object");
558 return nullptr;
559 }
560
561 if (ParseInt32(env, object, "fd", context->fd) == nullptr) {
562 return nullptr;
563 }
564 char name[FILE_NAME_MAX_LEN] = {0};
565 size_t len = FILE_NAME_MAX_LEN;
566 if (ParseString(env, object, "name", name, len) == nullptr) {
567 return nullptr;
568 }
569 context->fileName = name;
570 return NapiCreateInt32(env, SUCCESS);
571 }
572
UpdatePolicyExecute(napi_env env, void *data)573 static void UpdatePolicyExecute(napi_env env, void *data)
574 {
575 if (data == nullptr) {
576 return;
577 }
578 auto *context = static_cast<NapiSecurityPolicyFileInfo *>(data);
579 SecurityConfigUpdateInfo policyInfo(context->fd, context->fileName);
580 context->ret = SecurityGuardSdkAdaptor::ConfigUpdate(policyInfo);
581 if (context->ret != SUCCESS) {
582 SGLOGE("update policy file error, code=%{public}d", context->ret);
583 return ;
584 }
585 }
586
UpdatePolicyComplete(napi_env env, napi_status status, void *data)587 static void UpdatePolicyComplete(napi_env env, napi_status status, void *data)
588 {
589 if (data == nullptr) {
590 return;
591 }
592 auto *context = static_cast<NapiSecurityPolicyFileInfo *>(data);
593 napi_value result {};
594 result = GenerateBusinessError(env, context->ret);
595 if (context->ret == SUCCESS) {
596 napi_resolve_deferred(env, context->deferred, result);
597 } else {
598 napi_reject_deferred(env, context->deferred, result);
599 }
600 napi_delete_async_work(env, context->asyncWork);
601 delete context;
602 }
603
NapiUpdatePolicyFile(napi_env env, napi_callback_info info)604 static napi_value NapiUpdatePolicyFile(napi_env env, napi_callback_info info)
605 {
606 size_t argc = NAPI_UPDATE_POLICY_FILE_ARGS_CNT;
607 napi_value argv[NAPI_UPDATE_POLICY_FILE_ARGS_CNT] = {nullptr};
608 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
609 if (argc != NAPI_UPDATE_POLICY_FILE_ARGS_CNT) {
610 SGLOGE("update policy file arg count is not expected");
611 std::string msg = "update policy arguments count is not expected";
612 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, msg));
613 return nullptr;
614 }
615
616 NapiSecurityPolicyFileInfo *context = new (std::nothrow) NapiSecurityPolicyFileInfo();
617 if (context == nullptr) {
618 napi_throw(env, GenerateBusinessError(env, NULL_OBJECT, "context new failed, no memory left."));
619 return nullptr;
620 }
621 napi_value ret = ParsePolicyFileInfo(env, argv[0], context);
622 if (ret == nullptr) {
623 SGLOGE("policy file parse error");
624 delete context;
625 napi_throw(env, GenerateBusinessError(env, BAD_PARAM));
626 return nullptr;
627 }
628
629 napi_value promise = nullptr;
630 NAPI_CALL(env, napi_create_promise(env, &context->deferred, &promise));
631 napi_value resourceName = NapiCreateString(env, "NapiUpdatePolicyFile");
632 NAPI_CALL(env, napi_create_async_work(env, nullptr, resourceName, UpdatePolicyExecute,
633 UpdatePolicyComplete, static_cast<void *>(context), &context->asyncWork));
634 NAPI_CALL(env, napi_queue_async_work(env, context->asyncWork));
635
636 return promise;
637 }
638
ParseEventForNotifyCollector(napi_env env, napi_value object, OHOS::Security::SecurityCollector::Event &event)639 static bool ParseEventForNotifyCollector(napi_env env, napi_value object,
640 OHOS::Security::SecurityCollector::Event &event)
641 {
642 napi_valuetype type = napi_undefined;
643 NAPI_CALL_BASE(env, napi_typeof(env, object, &type), false);
644 if (type != napi_object) {
645 SGLOGE("type of param event is not object");
646 return false;
647 }
648 int64_t eventId = 0;
649 if (ParseInt64(env, object, "eventId", eventId) == nullptr) {
650 return false;
651 }
652
653 event.eventId = eventId;
654 event.version = ParseOptionalString(env, object, "version", VERSION_MAX_LEN);
655 event.content = ParseOptionalString(env, object, "content", CONTENT_MAX_LEN);
656 event.extra = ParseOptionalString(env, object, "param", EXTRA_MAX_LEN);
657 SGLOGI("param extra end");
658 return true;
659 }
660
NapiStartSecurityEventCollector(napi_env env, napi_callback_info info)661 static napi_value NapiStartSecurityEventCollector(napi_env env, napi_callback_info info)
662 {
663 SGLOGD("in NapiStartSecurityEventCollector");
664 size_t argc = NAPI_START_COLLECTOR_ARGS_CNT;
665 napi_value argv[NAPI_START_COLLECTOR_ARGS_CNT] = {nullptr};
666 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
667 if (argc != NAPI_START_COLLECTOR_ARGS_CNT && argc != NAPI_START_COLLECTOR_ARGS_CNT - 1) {
668 SGLOGE("notify arguments count is not expected");
669 napi_throw(env, GenerateBusinessError(env, BAD_PARAM));
670 return nullptr;
671 }
672
673 OHOS::Security::SecurityCollector::Event event{};
674 if (!ParseEventForNotifyCollector(env, argv[0], event)) {
675 SGLOGE("notify context parse error");
676 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, "param event error"));
677 return nullptr;
678 }
679 NotifyCollectorContext context{event, -1};
680
681 if (argc == NAPI_START_COLLECTOR_ARGS_CNT) {
682 napi_valuetype type;
683 NAPI_CALL(env, napi_typeof(env, argv[1], &type));
684 if (type != napi_number) {
685 SGLOGE("type of param is not number");
686 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, "param not number"));
687 return nullptr;
688 }
689 int64_t duration = -1;
690 napi_get_value_int64(env, argv[1], &duration);
691 if (duration <= 0) {
692 SGLOGE("duration of param is invalid");
693 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, "param invalid"));
694 return nullptr;
695 }
696 context.duration = duration;
697 }
698
699 int32_t code = SecurityGuardSdkAdaptor::StartCollector(context.event, context.duration);
700 if (code != SUCCESS) {
701 SGLOGE("notify error, code=%{public}d", code);
702 napi_throw(env, GenerateBusinessError(env, code));
703 }
704 return NapiCreateInt32(env, ConvertToJsErrCode(code));
705 }
706
NapiStopSecurityEventCollector(napi_env env, napi_callback_info info)707 static napi_value NapiStopSecurityEventCollector(napi_env env, napi_callback_info info)
708 {
709 SGLOGD("in NapiStopSecurityEventCollector");
710 size_t argc = NAPI_STOP_COLLECTOR_ARGS_CNT;
711 napi_value argv[NAPI_STOP_COLLECTOR_ARGS_CNT] = {nullptr};
712 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
713 if (argc != NAPI_STOP_COLLECTOR_ARGS_CNT) {
714 SGLOGE("notify arguments count is not expected");
715 napi_throw(env, GenerateBusinessError(env, BAD_PARAM));
716 return nullptr;
717 }
718
719 OHOS::Security::SecurityCollector::Event event{};
720 if (!ParseEventForNotifyCollector(env, argv[0], event)) {
721 SGLOGE("notify context parse error");
722 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, "param event error"));
723 return nullptr;
724 }
725
726 int32_t code = SecurityGuardSdkAdaptor::StopCollector(event);
727 if (code != SUCCESS) {
728 SGLOGE("notify error, code=%{public}d", code);
729 napi_throw(env, GenerateBusinessError(env, code));
730 }
731 return NapiCreateInt32(env, ConvertToJsErrCode(code));
732 }
733
GetValueType(const napi_env env, const napi_value& value)734 static napi_valuetype GetValueType(const napi_env env, const napi_value& value)
735 {
736 napi_valuetype valueType = napi_undefined;
737 napi_status ret = napi_typeof(env, value, &valueType);
738 if (ret != napi_ok) {
739 SGLOGE("failed to parse the type of napi value.");
740 }
741 return valueType;
742 }
743
IsValueTypeValid(const napi_env env, const napi_value& object, const napi_valuetype typeName)744 static bool IsValueTypeValid(const napi_env env, const napi_value& object,
745 const napi_valuetype typeName)
746 {
747 napi_valuetype valueType = GetValueType(env, object);
748 if (valueType != typeName) {
749 SGLOGE("napi value type not match: valueType=%{public}d, typeName=%{public}d.", valueType, typeName);
750 return false;
751 }
752 return true;
753 }
754
CheckValueIsArray(const napi_env env, const napi_value& object)755 static bool CheckValueIsArray(const napi_env env, const napi_value& object)
756 {
757 if (!IsValueTypeValid(env, object, napi_valuetype::napi_object)) {
758 return false;
759 }
760 bool isArray = false;
761 napi_status ret = napi_is_array(env, object, &isArray);
762 if (ret != napi_ok) {
763 SGLOGE("failed to check array napi value.");
764 }
765 return isArray;
766 }
767
ParseSecurityEventRuler(const napi_env env, const napi_value& object)768 static SecurityEventRuler ParseSecurityEventRuler(const napi_env env, const napi_value& object)
769 {
770 SecurityEventRuler rule {};
771 if (!IsValueTypeValid(env, object, napi_valuetype::napi_object)) {
772 return rule;
773 }
774 napi_value result = nullptr;
775 int64_t eventId = 0;
776 result = ParseInt64(env, object, "eventId", eventId);
777 if (result == nullptr) {
778 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, "Parameter error. The eventId error."));
779 SGLOGE("get conditions beginTime error");
780 return rule;
781 }
782
783 std::string beginTime = "";
784 result = GetConditionsTime(env, object, "beginTime", beginTime);
785 if (result == nullptr) {
786 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, "Parameter error. The beginTime error."));
787 SGLOGE("get conditions beginTime error");
788 return rule;
789 }
790
791 std::string endTime = "";
792 result = GetConditionsTime(env, object, "endTime", endTime);
793 if (result == nullptr) {
794 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, "Parameter error. The endTime error."));
795 SGLOGE("get conditions endTime error");
796 return rule;
797 }
798 if (!beginTime.empty() && !endTime.empty() && beginTime > endTime) {
799 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, "Parameter error. The time matching error."));
800 SGLOGE("Time matching error");
801 return rule;
802 }
803
804 std::string param = ParseOptionalString(env, object, "param", EXTRA_MAX_LEN);
805 return { eventId, beginTime, endTime, param };
806 }
807
ParseSecurityEventRulers(const napi_env env, napi_value& object, std::vector<SecurityEventRuler>& rulers)808 static int32_t ParseSecurityEventRulers(const napi_env env, napi_value& object, std::vector<SecurityEventRuler>& rulers)
809 {
810 if (!CheckValueIsArray(env, object)) {
811 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, "Parameter error. The type of rulers must be array."));
812 return BAD_PARAM;
813 }
814 uint32_t len = 0;
815 napi_status status = napi_get_array_length(env, object, &len);
816 if (status != napi_ok) {
817 return BAD_PARAM;
818 }
819 napi_value element;
820 for (uint32_t i = 0; i < len; i++) {
821 status = napi_get_element(env, object, i, &element);
822 if (status != napi_ok) {
823 return BAD_PARAM;
824 }
825 if (IsValueTypeValid(env, element, napi_valuetype::napi_object)) {
826 auto ruler = ParseSecurityEventRuler(env, element);
827 rulers.emplace_back(ruler);
828 }
829 }
830 return SUCCESS;
831 }
832
833 template<typename T>
CompareAndReturnCacheItem( const napi_env env, napi_value& standard, std::unordered_map<napi_ref, std::pair<pid_t, std::shared_ptr<T>>>& resources)834 static typename std::unordered_map<napi_ref, std::pair<pid_t, std::shared_ptr<T>>>::iterator CompareAndReturnCacheItem(
835 const napi_env env, napi_value& standard,
836 std::unordered_map<napi_ref, std::pair<pid_t, std::shared_ptr<T>>>& resources)
837 {
838 bool found = false;
839 napi_status status;
840 auto iter = resources.begin();
841 for (; iter != resources.end(); iter++) {
842 if (iter->second.first != syscall(SYS_gettid)) { // avoid error caused by vm run in multi-thread
843 continue;
844 }
845 napi_value val = nullptr;
846 status = napi_get_reference_value(env, iter->first, &val);
847 if (status != napi_ok) {
848 continue;
849 }
850 status = napi_strict_equals(env, standard, val, &found);
851 if (status != napi_ok) {
852 continue;
853 }
854 if (found) {
855 break;
856 }
857 }
858 return iter;
859 }
860
NapiQuerySecurityEvent(napi_env env, napi_callback_info info)861 static napi_value NapiQuerySecurityEvent(napi_env env, napi_callback_info info)
862 {
863 size_t argc = NAPI_QUERY_SECURITY_EVENT_ARGS_CNT;
864 napi_value argv[NAPI_QUERY_SECURITY_EVENT_ARGS_CNT] = {nullptr};
865 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
866 if (argc != NAPI_QUERY_SECURITY_EVENT_ARGS_CNT) {
867 SGLOGE("query arguments count is not expected");
868 napi_throw(env, GenerateBusinessError(env, BAD_PARAM));
869 return nullptr;
870 }
871 size_t index = 0;
872 std::vector<SecurityEventRuler> rules;
873 if (auto ret = ParseSecurityEventRulers(env, argv[index++], rules); ret != SUCCESS) {
874 SGLOGE("failed to parse query rules, result code is %{public}d.", ret);
875 return nullptr;
876 }
877 if (IsValueTypeValid(env, argv[index], napi_valuetype::napi_null) ||
878 IsValueTypeValid(env, argv[index], napi_valuetype::napi_undefined)) {
879 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, "Parameter error. The type of must querier be Querier."));
880 SGLOGE("querier is null or undefined.");
881 return nullptr;
882 }
883 auto context = new (std::nothrow) QuerySecurityEventContext;
884 if (context == nullptr) {
885 return nullptr;
886 }
887 context->env = env;
888 context->threadId = getproctid();
889 napi_create_reference(env, argv[index], 1, &context->ref);
890 auto querier = std::make_shared<NapiSecurityEventQuerier>(context, [] (const napi_env env, const napi_ref ref) {
891 napi_value querier = nullptr;
892 napi_get_reference_value(env, ref, &querier);
893 auto iter = CompareAndReturnCacheItem<NapiSecurityEventQuerier>(env, querier, queriers);
894 if (iter != queriers.end()) {
895 std::unique_lock<std::mutex> lock(g_queryMutex);
896 queriers.erase(iter->first);
897 NapiRequestDataManager::GetInstance().DelDataCallback(env);
898 }
899 SGLOGI("NapiSecurityEventQuerier OnFinsh Callback end.");
900 });
901 int32_t code = SecurityGuardSdkAdaptor::QuerySecurityEvent(rules, querier);
902 if (code != SUCCESS) {
903 SGLOGE("query error, code=%{public}d", code);
904 napi_throw(env, GenerateBusinessError(env, code));
905 }
906 std::unique_lock<std::mutex> lock(g_queryMutex);
907 queriers[context->ref] = std::make_pair(context->threadId, querier);
908 NapiRequestDataManager::GetInstance().AddDataCallback(env);
909 SGLOGI("NapiQuerySecurityEvent end.");
910 return nullptr;
911 }
912
GetCallbackProperty(napi_env env, napi_value obj, napi_ref &property, int argNum)913 static bool GetCallbackProperty(napi_env env, napi_value obj, napi_ref &property, int argNum)
914 {
915 napi_valuetype valueType = napi_undefined;
916 NAPI_CALL_BASE(env, napi_typeof(env, obj, &valueType), false);
917 if ((valueType == napi_undefined) || (valueType == napi_null)) {
918 SGLOGI("the callback is undefined or null");
919 return false;
920 } else if (valueType == napi_function) {
921 NAPI_CALL_BASE(env, napi_create_reference(env, obj, argNum, &property), false);
922 return true;
923 }
924 SGLOGE("the callback is not a napi_function");
925 return false;
926 }
927
GetStringProperty(napi_env env, napi_value obj, std::string &property)928 static bool GetStringProperty(napi_env env, napi_value obj, std::string &property)
929 {
930 napi_valuetype valuetype = napi_undefined;
931 NAPI_CALL_BASE(env, napi_typeof(env, obj, &valuetype), false);
932 if (valuetype != napi_string) {
933 return false;
934 }
935
936 size_t propLen;
937 NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, obj, nullptr, 0, &propLen), false);
938 if (propLen > ALL_PROPERTY_MAX_LEN) {
939 SGLOGE("Parameter error. param is too long");
940 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, "Parameter error. param is too long"));
941 return false;
942 }
943 property.reserve(propLen + 1);
944 property.resize(propLen);
945 NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, obj, property.data(), propLen + 1, &propLen), false);
946 return true;
947 }
948
WrapVoidToJS(napi_env env)949 static napi_value WrapVoidToJS(napi_env env)
950 {
951 napi_value result = nullptr;
952 NAPI_CALL(env, napi_get_null(env, &result));
953 return result;
954 }
955
ParseAuditEventInfo(const napi_env &env, napi_value napi, SubscribeEventInfo &eventInfo)956 static napi_value ParseAuditEventInfo(const napi_env &env, napi_value napi, SubscribeEventInfo &eventInfo)
957 {
958 napi_valuetype type = napi_undefined;
959 NAPI_CALL_BASE(env, napi_typeof(env, napi, &type), nullptr);
960 if (type != napi_object) {
961 std::string errMsg = "Parameter error. type of param AuditEventInfo is not object.";
962 SGLOGE("Parameter error. type of param AuditEventInfo is not object.");
963 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, errMsg));
964 return nullptr;
965 }
966 int64_t eventId = 0;
967 if (ParseInt64(env, napi, "eventId", eventId) == nullptr) {
968 std::string errMsg = "Parameter error. type of param AuditEventInfo.eventId is not number.";
969 SGLOGE("Parameter error. type of param AuditEventInfo.eventId is not number.");
970 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, errMsg));
971 return nullptr;
972 }
973 eventInfo.eventId = eventId;
974 return NapiCreateInt64(env, ConvertToJsErrCode(SUCCESS));
975 }
976
ParseSubscribeForEventOccur(const napi_env &env, const std::string &type, SubscribeCBInfo *info, napi_value napiValue)977 static bool ParseSubscribeForEventOccur(const napi_env &env, const std::string &type,
978 SubscribeCBInfo *info, napi_value napiValue)
979 {
980 if (type != "securityEventOccur") {
981 std::string errMsg = "Parameter error. The param of type must be securityEventOccur.";
982 SGLOGE("Parameter error. The param of type must be securityEventOccur.");
983 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, errMsg));
984 return false;
985 }
986 SubscribeEventInfo eventInfo;
987 if (ParseAuditEventInfo(env, napiValue, eventInfo) == nullptr) {
988 return false;
989 }
990 info->events.eventId = eventInfo.eventId;
991 return true;
992 }
993
ParseSubscribeParam(const napi_env &env, napi_callback_info cbInfo, SubscribeCBInfo *info, napi_value *thisVar)994 static bool ParseSubscribeParam(const napi_env &env, napi_callback_info cbInfo, SubscribeCBInfo *info,
995 napi_value *thisVar)
996 {
997 size_t argc = ARGS_SIZE_THREE;
998 napi_value argv[ARGS_SIZE_THREE] = {nullptr};
999 napi_get_cb_info(env, cbInfo, &argc, argv, thisVar, NULL);
1000 if (argc != ARGS_SIZE_THREE) {
1001 SGLOGE("Parameter error. The parameters number must be three");
1002 std::string errMsg = "Parameter error. The parameters number must be three";
1003 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, errMsg));
1004 return false;
1005 }
1006 if (!GetCallbackProperty(env, argv[argc - 1], info->callbackRef, 1)) {
1007 SGLOGE("Get callbackRef failed");
1008 std::string errMsg = "Parameter error. The type of arg " + std::to_string(argc) + " must be function";
1009 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, errMsg));
1010 return false;
1011 }
1012 std::string type;
1013 if (!GetStringProperty(env, argv[PARAMZERO], type)) {
1014 SGLOGE("Get type failed");
1015 std::string errMsg = "The type of arg 1 must be string";
1016 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, errMsg));
1017 return false;
1018 }
1019 return ParseSubscribeForEventOccur(env, type, info, argv[PARAMONE]);
1020 }
1021
IsCurrentThread(std::thread::id threadId)1022 static bool IsCurrentThread(std::thread::id threadId)
1023 {
1024 std::thread::id currentThread = std::this_thread::get_id();
1025 if (threadId != currentThread) {
1026 SGLOGE("napi_ref can not be compared,different threadId");
1027 return false;
1028 }
1029 return true;
1030 }
1031
CompareOnAndOffRef(const napi_env env, napi_ref subscriberRef, napi_ref unsubscriberRef, std::thread::id threadId)1032 static bool CompareOnAndOffRef(const napi_env env, napi_ref subscriberRef, napi_ref unsubscriberRef,
1033 std::thread::id threadId)
1034 {
1035 if (!IsCurrentThread(threadId)) {
1036 return false;
1037 }
1038 napi_value subscriberCallback;
1039 napi_get_reference_value(env, subscriberRef, &subscriberCallback);
1040 napi_value unsubscriberCallback;
1041 napi_get_reference_value(env, unsubscriberRef, &unsubscriberCallback);
1042 bool result = false;
1043 napi_strict_equals(env, subscriberCallback, unsubscriberCallback, &result);
1044 return result;
1045 }
1046
IsSubscribeInMap(napi_env env, SubscribeCBInfo *info)1047 static bool IsSubscribeInMap(napi_env env, SubscribeCBInfo *info)
1048 {
1049 std::lock_guard<std::mutex> lock(g_subscribeMutex);
1050 auto subscribe = g_subscribers.find(env);
1051 if (subscribe == g_subscribers.end()) {
1052 return false;
1053 }
1054 auto it = subscribe->second.begin();
1055 while (it != subscribe->second.end()) {
1056 if (CompareOnAndOffRef(env, (*it)->callbackRef, info->callbackRef, (*it)->threadId)) {
1057 return true;
1058 }
1059 it++;
1060 }
1061 return false;
1062 }
1063
ParseUnsubscriberAuditEventInfo(const napi_env &env, napi_value napi)1064 static napi_value ParseUnsubscriberAuditEventInfo(const napi_env &env, napi_value napi)
1065 {
1066 napi_valuetype type = napi_undefined;
1067 NAPI_CALL_BASE(env, napi_typeof(env, napi, &type), nullptr);
1068 if (type != napi_object) {
1069 std::string errMsg = "Parameter error. type of param AuditEventInfo is not object.";
1070 SGLOGE("Parameter error. type of param AuditEventInfo is not object.");
1071 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, errMsg));
1072 return nullptr;
1073 }
1074 int64_t eventId = 0;
1075 if (ParseInt64(env, napi, "eventId", eventId) == nullptr) {
1076 std::string errMsg = "Parameter error. type of param AuditEventInfo.eventId is not number.";
1077 SGLOGE("Parameter error. type of param AuditEventInfo.eventId is not number.");
1078 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, errMsg));
1079 return nullptr;
1080 }
1081 return NapiCreateInt64(env, ConvertToJsErrCode(SUCCESS));
1082 }
1083
ParseParaToUnsubscriber(const napi_env &env, napi_callback_info cbInfo, UnsubscribeCBInfo *asyncContext, napi_value *thisVar)1084 static bool ParseParaToUnsubscriber(const napi_env &env, napi_callback_info cbInfo, UnsubscribeCBInfo *asyncContext,
1085 napi_value *thisVar)
1086 {
1087 size_t argc = ARGS_SIZE_THREE;
1088 napi_value argv[ARGS_SIZE_THREE] = {nullptr};
1089 napi_get_cb_info(env, cbInfo, &argc, argv, thisVar, NULL);
1090 if (argc != ARGS_SIZE_THREE) {
1091 SGLOGE("Parameter error. The parameters number must be three");
1092 std::string errMsg = "Parameter error. The parameters number must be three";
1093 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, errMsg));
1094 return false;
1095 }
1096 if (!GetCallbackProperty(env, argv[argc - 1], asyncContext->callbackRef, 1)) {
1097 SGLOGE("Get callbackRef failed");
1098 std::string errMsg = "Parameter error. The type of arg " + std::to_string(argc) + " must be function";
1099 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, errMsg));
1100 return false;
1101 }
1102 std::string type;
1103 if (!GetStringProperty(env, argv[PARAMZERO], type)) {
1104 std::string errMsg = "Parameter error. The type of arg 1 must be string";
1105 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, errMsg));
1106 return false;
1107 }
1108 if (type != "securityEventOccur") {
1109 std::string errMsg = "Parameter error. arg 1 must be auditEventOccur";
1110 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, errMsg));
1111 return false;
1112 }
1113 if (ParseUnsubscriberAuditEventInfo(env, argv[PARAMONE]) == nullptr) {
1114 return false;
1115 }
1116 return true;
1117 }
1118
GenerateEvent(napi_env env, const NapiSecurityEvent &event)1119 static napi_value GenerateEvent(napi_env env, const NapiSecurityEvent &event)
1120 {
1121 napi_value ret = NapiCreateObject(env);
1122 if (ret == nullptr) {
1123 napi_throw(env, GenerateBusinessError(env, BAD_PARAM, "napi create object error ."));
1124 }
1125 napi_value eventId = NapiCreateInt64(env, event.eventId);
1126 napi_value version = NapiCreateString(env, event.version);
1127 napi_value content = NapiCreateString(env, event.content);
1128
1129 napi_set_named_property(env, ret, NAPI_EVENT_EVENT_ID_ATTR, eventId);
1130 napi_set_named_property(env, ret, NAPI_EVENT_VERSION_ATTR, version);
1131 napi_set_named_property(env, ret, NAPI_EVENT_CONTENT_ATTR, content);
1132 return ret;
1133 }
1134
InitUvWorkCallbackEnv(CommonAsyncContext *data, napi_handle_scope *scope)1135 static bool InitUvWorkCallbackEnv(CommonAsyncContext *data, napi_handle_scope *scope)
1136 {
1137 if (data == nullptr) {
1138 SGLOGE("data is nullptr");
1139 return false;
1140 }
1141 napi_open_handle_scope(data->env, scope);
1142 if (scope == nullptr) {
1143 SGLOGE("fail to open scope");
1144 delete data;
1145 data = nullptr;
1146 return false;
1147 }
1148 return true;
1149 }
1150
UvQueueWorkOnSecEventsChanged(uv_work_t *work, int status)1151 static void UvQueueWorkOnSecEventsChanged(uv_work_t *work, int status)
1152 {
1153 SGLOGI("UvQueueWorkOnSecEventsChanged");
1154 if (work == nullptr) {
1155 SGLOGE("work is nullptr");
1156 return;
1157 }
1158 napi_handle_scope scope = nullptr;
1159 if (!InitUvWorkCallbackEnv(reinterpret_cast<CommonAsyncContext *>(work->data), &scope)) {
1160 return;
1161 }
1162 std::unique_ptr<SubscriberOAWorker> subscriberOAWorkerData(reinterpret_cast<SubscriberOAWorker *>(work->data));
1163 bool isFound = false;
1164 {
1165 std::lock_guard<std::mutex> lock(g_subscribeMutex);
1166 SubscriberPtr *subscriber = subscriberOAWorkerData->subscriber;
1167 for (auto subscriberInstance : g_subscribers) {
1168 isFound = std::any_of(subscriberInstance.second.begin(), subscriberInstance.second.end(),
1169 [subscriber](const SubscribeCBInfo *item) {
1170 return item->subscriber.get() == subscriber;
1171 });
1172 if (isFound) {
1173 SGLOGI("subscriber has been found.");
1174 break;
1175 }
1176 }
1177 }
1178 if (isFound) {
1179 napi_value result[ARGS_SIZE_ONE] = {nullptr};
1180 result[PARAMZERO] = GenerateEvent(subscriberOAWorkerData->env, subscriberOAWorkerData->event);
1181 napi_value undefined = nullptr;
1182 napi_get_undefined(subscriberOAWorkerData->env, &undefined);
1183 napi_value callback = nullptr;
1184 napi_get_reference_value(subscriberOAWorkerData->env, subscriberOAWorkerData->ref, &callback);
1185 napi_value resultOut = nullptr;
1186 napi_status ok = napi_call_function(subscriberOAWorkerData->env, undefined, callback, ARGS_SIZE_ONE,
1187 &result[0], &resultOut);
1188 SGLOGI("isOk=%{public}d", ok);
1189 }
1190 napi_close_handle_scope(subscriberOAWorkerData->env, scope);
1191 }
1192
OnNotifyEvent(const Event &event, napi_env env, napi_ref ref, SubscriberPtr *subscriber)1193 static int32_t OnNotifyEvent(const Event &event, napi_env env, napi_ref ref, SubscriberPtr *subscriber)
1194 {
1195 SGLOGI("OnNotify");
1196 uv_loop_s *loop = nullptr;
1197 napi_get_uv_event_loop(env, &loop);
1198 if (loop == nullptr) {
1199 SGLOGE("loop instance is nullptr");
1200 return -1;
1201 }
1202 uv_work_t *work = new (std::nothrow) uv_work_t;
1203 if (work == nullptr) {
1204 SGLOGE("insufficient memory for work!");
1205 return -1;
1206 }
1207
1208 SubscriberOAWorker *subscriberOAWorker = new (std::nothrow) SubscriberOAWorker();
1209
1210 if (subscriberOAWorker == nullptr) {
1211 SGLOGE("insufficient memory for SubscriberAccountsWorker!");
1212 delete work;
1213 return -1;
1214 }
1215
1216 subscriberOAWorker->event.eventId = event.eventId;
1217 subscriberOAWorker->event.version = event.version;
1218 subscriberOAWorker->event.content = event.content;
1219 subscriberOAWorker->event.timestamp = event.timestamp;
1220 subscriberOAWorker->env = env;
1221 subscriberOAWorker->ref = ref;
1222 subscriberOAWorker->subscriber = subscriber;
1223 work->data = reinterpret_cast<void *>(subscriberOAWorker);
1224 uv_queue_work_with_qos(loop, work, [](uv_work_t *work) {
1225 SGLOGD("UvQueueWorkOnSecEventsChanged...");
1226 }, UvQueueWorkOnSecEventsChanged, uv_qos_default);
1227 return 0;
1228 }
1229
1230 class SubscriberPtr : public ICollectorSubscriber {
1231 public:
SubscriberPtr(const Event &event)1232 explicit SubscriberPtr(const Event &event) : ICollectorSubscriber(event) {};
1233 ~SubscriberPtr() override = default;
1234
1235 int32_t OnNotify(const Event &event) override
1236 {
1237 if (OnNotifyEvent(event, env_, ref_, this) != 0) {
1238 return -1;
1239 }
1240 return 0;
1241 };
SetEnv(const napi_env &env)1242 void SetEnv(const napi_env &env) { env_ = env; }
SetCallbackRef(const napi_ref &ref)1243 void SetCallbackRef(const napi_ref &ref) { ref_ = ref; }
1244 private:
1245 napi_env env_ = nullptr;
1246 napi_ref ref_ = nullptr;
1247 };
1248
Subscribe(napi_env env, napi_callback_info cbInfo)1249 static napi_value Subscribe(napi_env env, napi_callback_info cbInfo)
1250 {
1251 SubscribeCBInfo *info = new (std::nothrow) SubscribeCBInfo(env, std::this_thread::get_id());
1252 if (info == nullptr) {
1253 napi_throw(env, GenerateBusinessError(env, NULL_OBJECT, "No memory!"));
1254 return nullptr;
1255 }
1256
1257 napi_value thisVar = nullptr;
1258 if (!ParseSubscribeParam(env, cbInfo, info, &thisVar)) {
1259 delete info;
1260 SGLOGE("Parse subscribe failed");
1261 return nullptr;
1262 }
1263 info->subscriber = std::make_shared<SubscriberPtr>(info->events);
1264 info->subscriber->SetEnv(env);
1265 info->subscriber->SetCallbackRef(info->callbackRef);
1266 if (IsSubscribeInMap(env, info)) {
1267 delete info;
1268 return WrapVoidToJS(env);
1269 }
1270 int32_t errCode = SecurityGuardSdkAdaptor::Subscribe(info->subscriber);
1271 if (errCode != 0) {
1272 delete info;
1273 napi_throw(env, GenerateBusinessError(env, errCode, "Subscribe failed!"));
1274 return WrapVoidToJS(env);
1275 } else {
1276 std::lock_guard<std::mutex> lock(g_subscribeMutex);
1277 g_subscribers[env].emplace_back(info);
1278 }
1279 return WrapVoidToJS(env);
1280 }
1281
UnsubscribeSync(napi_env env, UnsubscribeCBInfo *unsubscribeCBInfo)1282 static void UnsubscribeSync(napi_env env, UnsubscribeCBInfo *unsubscribeCBInfo)
1283 {
1284 std::lock_guard<std::mutex> lock(g_subscribeMutex);
1285 auto subscribe = g_subscribers.find(env);
1286 if (subscribe == g_subscribers.end()) {
1287 return;
1288 }
1289 auto item = subscribe->second.begin();
1290 while (item != subscribe->second.end()) {
1291 if ((unsubscribeCBInfo->callbackRef != nullptr) &&
1292 (!CompareOnAndOffRef(env, (*item)->callbackRef, unsubscribeCBInfo->callbackRef, (*item)->threadId))) {
1293 item++;
1294 continue;
1295 }
1296 int errCode = SecurityGuardSdkAdaptor::Unsubscribe((*item)->subscriber);
1297 if (errCode != 0) {
1298 std::string errMsg = "unsubscrube failed";
1299 napi_throw(env, GenerateBusinessError(env, errCode, errMsg));
1300 return;
1301 }
1302 delete (*item);
1303 item = subscribe->second.erase(item);
1304 if (unsubscribeCBInfo->callbackRef != nullptr) {
1305 break;
1306 }
1307 }
1308 if (subscribe->second.empty()) {
1309 g_subscribers.erase(subscribe->first);
1310 }
1311 }
1312
Unsubscribe(napi_env env, napi_callback_info cbInfo)1313 static napi_value Unsubscribe(napi_env env, napi_callback_info cbInfo)
1314 {
1315 UnsubscribeCBInfo *unsubscribeCBInfo = new (std::nothrow) UnsubscribeCBInfo(env, std::this_thread::get_id());
1316 if (unsubscribeCBInfo == nullptr) {
1317 SGLOGE("insufficient memory for unsubscribeCBInfo!");
1318 napi_throw(env, GenerateBusinessError(env, NULL_OBJECT, "No memory!"));
1319 return WrapVoidToJS(env);
1320 }
1321 unsubscribeCBInfo->callbackRef = nullptr;
1322 unsubscribeCBInfo->throwErr = true;
1323
1324 napi_value thisVar = nullptr;
1325
1326 if (!ParseParaToUnsubscriber(env, cbInfo, unsubscribeCBInfo, &thisVar)) {
1327 delete unsubscribeCBInfo;
1328 SGLOGE("Parse unsubscribe failed");
1329 return nullptr;
1330 }
1331
1332 UnsubscribeSync(env, unsubscribeCBInfo);
1333 SGLOGI("UnsubscribeSync success");
1334 delete unsubscribeCBInfo;
1335 return WrapVoidToJS(env);
1336 }
1337
1338 EXTERN_C_START
SecurityGuardNapiRegister(napi_env env, napi_value exports)1339 static napi_value SecurityGuardNapiRegister(napi_env env, napi_value exports)
1340 {
1341 napi_property_descriptor desc[] = {
1342 DECLARE_NAPI_FUNCTION("startSecurityEventCollector", NapiStartSecurityEventCollector),
1343 DECLARE_NAPI_FUNCTION("stopSecurityEventCollector", NapiStopSecurityEventCollector),
1344 DECLARE_NAPI_FUNCTION("querySecurityEvent", NapiQuerySecurityEvent),
1345 DECLARE_NAPI_FUNCTION("reportSecurityEvent", NapiReportSecurityInfo),
1346 DECLARE_NAPI_FUNCTION("on", Subscribe),
1347 DECLARE_NAPI_FUNCTION("off", Unsubscribe),
1348 DECLARE_NAPI_FUNCTION("getModelResult", NapiGetModelResult),
1349 DECLARE_NAPI_FUNCTION("updatePolicyFile", NapiUpdatePolicyFile),
1350 };
1351 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
1352 return exports;
1353 }
1354 EXTERN_C_END
1355
1356 static napi_module g_module = {
1357 .nm_version = 1,
1358 .nm_flags = 0,
1359 .nm_filename = nullptr,
1360 .nm_register_func = SecurityGuardNapiRegister,
1361 .nm_modname = "security.securityGuard",
1362 .nm_priv = reinterpret_cast<void *>(0),
1363 .reserved = { 0 },
1364 };
1365
RegisterModule(void)1366 extern "C" __attribute__((constructor)) void RegisterModule(void)
1367 {
1368 napi_module_register(&g_module);
1369 }