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