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