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