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