• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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