mirror of
https://github.com/vxcontrol/soldr-modules.git
synced 2026-07-01 12:47:17 -04:00
feat: change browser modules api and using css styles (classes) in the vue files
This commit is contained in:
+27
-429
@@ -37,8 +37,8 @@
|
||||
"reason",
|
||||
"version"
|
||||
],
|
||||
"last_module_update": "2022-10-26 00:00:00",
|
||||
"last_update": "2022-10-26 00:00:00"
|
||||
"last_module_update": "2022-12-08 00:00:00",
|
||||
"last_update": "2022-12-08 00:00:00"
|
||||
},
|
||||
{
|
||||
"group_id": "",
|
||||
@@ -66,8 +66,8 @@
|
||||
"fields": [
|
||||
"reason"
|
||||
],
|
||||
"last_module_update": "2022-10-26 00:00:00",
|
||||
"last_update": "2022-10-26 00:00:00"
|
||||
"last_module_update": "2022-12-08 00:00:00",
|
||||
"last_update": "2022-12-08 00:00:00"
|
||||
},
|
||||
{
|
||||
"group_id": "",
|
||||
@@ -96,8 +96,8 @@
|
||||
"actions": [],
|
||||
"events": [],
|
||||
"fields": [],
|
||||
"last_module_update": "2022-04-29 00:00:00",
|
||||
"last_update": "2022-04-29 00:00:00"
|
||||
"last_module_update": "2022-12-08 00:00:00",
|
||||
"last_update": "2022-12-08 00:00:00"
|
||||
},
|
||||
{
|
||||
"group_id": "",
|
||||
@@ -131,8 +131,8 @@
|
||||
"syslog_module_stopped"
|
||||
],
|
||||
"fields": [],
|
||||
"last_module_update": "2022-04-29 00:00:00",
|
||||
"last_update": "2022-04-29 00:00:00"
|
||||
"last_module_update": "2022-12-08 00:00:00",
|
||||
"last_update": "2022-12-08 00:00:00"
|
||||
},
|
||||
{
|
||||
"group_id": "",
|
||||
@@ -181,8 +181,8 @@
|
||||
"subject.fullpath",
|
||||
"subject.process.fullpath"
|
||||
],
|
||||
"last_module_update": "2022-04-29 00:00:00",
|
||||
"last_update": "2022-04-29 00:00:00"
|
||||
"last_module_update": "2022-12-08 00:00:00",
|
||||
"last_update": "2022-12-08 00:00:00"
|
||||
},
|
||||
{
|
||||
"group_id": "",
|
||||
@@ -249,8 +249,8 @@
|
||||
"subject.process.id",
|
||||
"subject.process.name"
|
||||
],
|
||||
"last_module_update": "2022-08-26 00:00:00",
|
||||
"last_update": "2022-06-26 00:00:00"
|
||||
"last_module_update": "2022-12-08 00:00:00",
|
||||
"last_update": "2022-12-08 00:00:00"
|
||||
},
|
||||
{
|
||||
"group_id": "",
|
||||
@@ -314,8 +314,8 @@
|
||||
"subject.process.fullpath",
|
||||
"subject.process.id"
|
||||
],
|
||||
"last_module_update": "2022-11-07 09:11:39",
|
||||
"last_update": "2022-11-07 09:11:39"
|
||||
"last_module_update": "2022-12-08 09:11:39",
|
||||
"last_update": "2022-12-08 09:11:39"
|
||||
},
|
||||
{
|
||||
"group_id": "",
|
||||
@@ -364,8 +364,8 @@
|
||||
"subject.fullpath",
|
||||
"subject.process.fullpath"
|
||||
],
|
||||
"last_module_update": "2022-09-30 00:00:00",
|
||||
"last_update": "2022-09-30 00:00:00"
|
||||
"last_module_update": "2022-12-08 00:00:00",
|
||||
"last_update": "2022-12-08 00:00:00"
|
||||
},
|
||||
{
|
||||
"group_id": "",
|
||||
@@ -385,113 +385,42 @@
|
||||
},
|
||||
"actions": [],
|
||||
"events": [
|
||||
"Auxiliary_SuspiciousWeightsTrojan_Linux_subject_a",
|
||||
"Local_Recon_by_Web_User",
|
||||
"Malware_Exploit_Elf_CVE_2019_14287_a",
|
||||
"Malware_Exploit_Elf_CVE_2021_4034_a",
|
||||
"Malware_Trojan_Linux_Generic_a",
|
||||
"Malware_Trojan_Spy_Linux_Generic_a",
|
||||
"Raw_Socket",
|
||||
"Reverse_Tunneling_via_SSH",
|
||||
"Suspicious_Create_File_Attribute_Hidden",
|
||||
"Suspicious_Create_File_Boot_Modification",
|
||||
"Suspicious_Create_File_Boot_RCScripts",
|
||||
"Suspicious_Create_File_Ldd_PreloadDynamicLibrary",
|
||||
"Suspicious_Create_File_Scheduler_At",
|
||||
"Suspicious_Create_File_Scheduler_Cron",
|
||||
"Suspicious_Create_File_Scheduler_SystemdTimer",
|
||||
"Suspicious_Create_File_Shell_Config",
|
||||
"Suspicious_Create_File_Ssh_AuthorizedKeys",
|
||||
"Suspicious_Create_File_Systemd_Service",
|
||||
"Suspicious_Create_File_Xdg_Autostart",
|
||||
"Suspicious_Create_Process_Chkconfig_DisableRCScripts",
|
||||
"Suspicious_Create_Process_Iptables_ModifyFirewall",
|
||||
"Suspicious_Create_Process_Service_Disable",
|
||||
"Suspicious_Create_Process_Setenforce_ModifySELinux",
|
||||
"Suspicious_Create_Process_Sudo_Bruteforce",
|
||||
"Suspicious_Create_Process_WipeData_Destruction",
|
||||
"Suspicious_Read_File_Email_Local",
|
||||
"Suspicious_Read_File_Fstab_Configuration",
|
||||
"Suspicious_Read_File_Passwd_CredentialsEnumeration",
|
||||
"Suspicious_Read_File_Polkit_Policy",
|
||||
"Suspicious_Read_File_Shadow_CredentialsDumping",
|
||||
"Suspicious_Read_System_BIOS_Reconnaissance",
|
||||
"Suspicious_Read_System_DMI_CheckVM",
|
||||
"Suspicious_Read_System_Kernel_ASLR",
|
||||
"Suspicious_Read_System_Kernel_PtraceScope",
|
||||
"Suspicious_Read_System_KeyState_Keylogger",
|
||||
"Suspicious_Read_System_PCI_GPU",
|
||||
"Suspicious_Read_System_PCI_USB",
|
||||
"Suspicious_Read_System_Proc_ARPSessions",
|
||||
"Suspicious_Read_System_Proc_BootCmdline",
|
||||
"Suspicious_Read_System_Proc_Modules",
|
||||
"Suspicious_Read_System_Proc_Route",
|
||||
"Suspicious_Read_System_Proc_SCSI",
|
||||
"Suspicious_Read_System_Proc_TCPSessions",
|
||||
"Suspicious_Write_Disk_Data_DirectAccess",
|
||||
"Suspicious_Write_File_PAM_Persistence",
|
||||
"Suspicious_Write_Process_Inject_Ptrace",
|
||||
"Tunneling_via_SSH",
|
||||
"Tunneling_via_SSHuttle_Client",
|
||||
"Tunneling_via_SSHuttle_Server"
|
||||
"Suspicious_Write_Process_Inject_Ptrace"
|
||||
],
|
||||
"fields": [
|
||||
"action",
|
||||
"alert.key",
|
||||
"category.generic",
|
||||
"category.high",
|
||||
"category.low",
|
||||
"correlation_name",
|
||||
"correlation_type",
|
||||
"event_src.asset",
|
||||
"event_src.host",
|
||||
"event_src.hostname",
|
||||
"event_src.id",
|
||||
"event_src.ip",
|
||||
"event_src.subsys",
|
||||
"event_src.title",
|
||||
"event_src.vendor",
|
||||
"importance",
|
||||
"incident.aggregation.key",
|
||||
"incident.aggregation.timeout",
|
||||
"incident.category",
|
||||
"incident.severity",
|
||||
"labels",
|
||||
"numfield1",
|
||||
"numfield2",
|
||||
"object",
|
||||
"object.account.group",
|
||||
"object.account.id",
|
||||
"object.account.name",
|
||||
"object.fullpath",
|
||||
"object.name",
|
||||
"object.path",
|
||||
"object.process.cmdline",
|
||||
"object.process.cwd",
|
||||
"object.process.fullpath",
|
||||
"object.process.id",
|
||||
"object.process.meta",
|
||||
"object.process.name",
|
||||
"object.process.parent.id",
|
||||
"object.process.path",
|
||||
"object.state",
|
||||
"object.value",
|
||||
"status",
|
||||
"subject",
|
||||
"subject.account.id",
|
||||
"subject.account.name",
|
||||
"subject.account.privileges",
|
||||
"subject.account.session_id",
|
||||
"subject.process.fullpath",
|
||||
"subject.process.id",
|
||||
"subject.process.meta",
|
||||
"subject.process.name",
|
||||
"subject.process.parent.id",
|
||||
"subject.process.path",
|
||||
"subject.type"
|
||||
"subject.process.path"
|
||||
],
|
||||
"last_module_update": "2022-11-07 12:52:12",
|
||||
"last_update": "2022-11-07 12:52:12"
|
||||
"last_module_update": "2022-12-08 12:52:12",
|
||||
"last_update": "2022-12-08 12:52:12"
|
||||
},
|
||||
{
|
||||
"group_id": "",
|
||||
@@ -511,379 +440,48 @@
|
||||
},
|
||||
"actions": [],
|
||||
"events": [
|
||||
"Abnormal_Directory_for_Process",
|
||||
"Abusing_CredSSP",
|
||||
"Access_System_Credential_files_via_cmdline",
|
||||
"Access_into_Sensitive_Files_via_Network_Share",
|
||||
"Accessibility_Feature_Tool_Abuse",
|
||||
"Account_Created_on_Local_System",
|
||||
"Account_Discovery",
|
||||
"Account_or_Group_discovery_via_SAM_R",
|
||||
"Add_new_user_in_commandline",
|
||||
"Alternate_Data_Stream",
|
||||
"Audit_XP_params_change",
|
||||
"Auxiliary_SuspiciousWeightsTrojan_Windows_subject_a",
|
||||
"Auxiliary_SuspiciousWeightsTrojan_Windows_subject_b",
|
||||
"BitsJob_Download_and_Run",
|
||||
"COM_object_persistence",
|
||||
"CVE_2021_41379_Subrule_Elevation_service_chain",
|
||||
"CVE_2021_41379_Subrule_Start_elevation",
|
||||
"CVE_2021_41379_exploitation",
|
||||
"CVE_2022_26500_26501_exploitation",
|
||||
"CVE_2022_26503_Subrule_1",
|
||||
"CVE_2022_26503_Subrule_2",
|
||||
"CVE_2022_26503_exploitation",
|
||||
"Client_Side_Execution_via_DCOM",
|
||||
"Clipboard_Access",
|
||||
"Clipboard_Access_Powershell",
|
||||
"Cmstp_AWL_Bypass",
|
||||
"Cobalt_Strike_Assembly",
|
||||
"Cobalt_Strike_Payload_Delivery_Check",
|
||||
"Cobalt_Strike_Pipe_from_AdminShare",
|
||||
"Cobalt_Strike_Process_Injection",
|
||||
"Cobalt_Strike_Psexec_Jump",
|
||||
"Cobalt_Strike_SMB_Beacon",
|
||||
"Cobalt_Strike_Service_Move",
|
||||
"Code_Execution_Via_JDK_Tools",
|
||||
"Command_Processor_Autorun_Modify",
|
||||
"Computer_object_ldap_request",
|
||||
"ControlPanel_AWL_Bypass",
|
||||
"Copy_Mimikatz_To_Share",
|
||||
"Credential_Access_to_Passwords_Storage",
|
||||
"Credential_Dump_in_Local_Registry",
|
||||
"Csc_AWL_Bypass",
|
||||
"DRSUAPI_User_Enumeration",
|
||||
"DSInternals_Usage",
|
||||
"Disable_Credential_Guard",
|
||||
"Disable_LSA_Protection",
|
||||
"Disable_Restricted_Admin_Mode",
|
||||
"Dnscmd_AWL_Bypass",
|
||||
"Domain_Controllers_Discovery",
|
||||
"Domain_Trust_Discovery",
|
||||
"Download_File_Through_Curl",
|
||||
"Download_File_Through_Windows_Defender",
|
||||
"Downloading_Remote_File_Via_Lolbas",
|
||||
"Empire_Stager",
|
||||
"Esentutil_Copy_File",
|
||||
"Execute_Encoded_Powershell",
|
||||
"Execute_Malicious_Command",
|
||||
"Execute_Malicious_Powershell_Cmdlet",
|
||||
"Execute_PSEXEC",
|
||||
"Execute_Suspicious_Command_via_cmd",
|
||||
"Failed_LSASS_Injection",
|
||||
"Fast_Create_and_Delete_Account",
|
||||
"Finger_AWL_Bypass",
|
||||
"Groups_And_Users_Enumeration",
|
||||
"Hidden_Scheduled_Task",
|
||||
"Hidden_Service_Create",
|
||||
"Hide_Account_from_Logon_Screen",
|
||||
"IEExec_AWL_Bypass",
|
||||
"Impacket_SMBEXEC",
|
||||
"Impacket_Secretsdump",
|
||||
"InstallUtil_AWL_Bypass",
|
||||
"Intercept_Creds_from_MSTSC",
|
||||
"Internal_Monologue_Attack",
|
||||
"KeePass_Keys_Extraction",
|
||||
"KeePass_Persistence",
|
||||
"Koadic_MSHTA_Stager",
|
||||
"Koadic_REGSVR32_Stager",
|
||||
"Koadic_Rundll32_Stager",
|
||||
"Koadic_WMIC_Stager",
|
||||
"LAPS_Enumeration",
|
||||
"LOLBin_Copying",
|
||||
"LSA_SSP_Change",
|
||||
"Lazagne_Usage",
|
||||
"Local_Pass_the_Hash",
|
||||
"Lsass_Dump_via_SilentProcessExit",
|
||||
"Lsass_SilentProcessExit_Keys",
|
||||
"MSBuild_AWL_Bypass",
|
||||
"MSHTA_AWL_Bypass",
|
||||
"MSXSL_AWL_Bypass",
|
||||
"Malicious_CHM_File",
|
||||
"Malicious_Office_Document",
|
||||
"Malware_Backdoor_Win32_Evilnum_a",
|
||||
"Malware_Backdoor_Win32_Havex_a",
|
||||
"Malware_Backdoor_Win32_NetWire_b",
|
||||
"Malware_Backdoor_Win32_Pteredo_a",
|
||||
"Malware_Backdoor_Win64_Throwback_b",
|
||||
"Malware_Exploit_Win32_CVE_2022_30190_a",
|
||||
"Malware_Exploit_Win32_PrintSpooler_a",
|
||||
"Malware_Hacktool_Win32_CrackMapExec_a",
|
||||
"Malware_Trojan_Dropper_MSOffice_Launcher_a",
|
||||
"Malware_Trojan_Dropper_Script_Generic_a",
|
||||
"Malware_Trojan_Dropper_Win32_Generic_k",
|
||||
"Malware_Trojan_Ransom_Win32_Generic_a",
|
||||
"Malware_Trojan_Ransom_Win32_Generic_b",
|
||||
"Malware_Trojan_Win32_Generic_a",
|
||||
"Malware_Trojan_Win32_Generic_o",
|
||||
"Malware_Trojan_Win32_Generic_s",
|
||||
"Malware_Trojan_Win32_Generic_t",
|
||||
"Mavinject_AWL_Bypass",
|
||||
"Metasploit_Payload",
|
||||
"Microsoft_Teams_AWL_Bypass",
|
||||
"Mimikatz_Command",
|
||||
"Msiexec_AWL_Bypass",
|
||||
"NetCat_Usage",
|
||||
"Network_Share_Discovery",
|
||||
"Odbcconf_AWL_Bypass",
|
||||
"Office_File_with_Macros",
|
||||
"Office_Normal_dotm_modification",
|
||||
"Office_XLL_modification",
|
||||
"Password_Policy_Discovery",
|
||||
"Pcalua_AWL_Bypass",
|
||||
"Permission_Groups_Discovery",
|
||||
"Persistence_Netsh_DLL",
|
||||
"Port_Forwarding_or_Tunneling",
|
||||
"Potential_Users_Or_Groups_Enumeration_Process",
|
||||
"Potential_domain_groups_and_users_enumeration_handle",
|
||||
"Potential_localgroups_and_administrators_enumeration_handle",
|
||||
"Powershell_Remoting",
|
||||
"Process_Discovery",
|
||||
"Proxy_Tools_Usage",
|
||||
"RDP_Session_Hijacking",
|
||||
"Reading_Registry_Objects",
|
||||
"RegAsm_or_RegSvcs_AWL_Bypass",
|
||||
"Registry_Winlogon_Helper",
|
||||
"Regsvr32_AWL_Bypass",
|
||||
"Remote_Admin_Share_Access",
|
||||
"Remote_Code_Execution_Via_AtSvc",
|
||||
"Remote_Connection_through_SMBEXEC_WinXP",
|
||||
"Remote_Copy_Credential_Dump_Artifact",
|
||||
"Remote_Copying_Malicious_File",
|
||||
"Remote_File_Download_Via_Certutil",
|
||||
"Remote_Password_Dump",
|
||||
"Remoting_Impacket_PsExec",
|
||||
"Remoting_SysInternals_PsExec",
|
||||
"Remoting_WMI",
|
||||
"Remoting_WinExec",
|
||||
"Remoting_Windows_Shell",
|
||||
"Remove_Access_To_Sensitive_Account",
|
||||
"Remove_Account_From_Sensitive_Group",
|
||||
"Rubeus_Usage",
|
||||
"RunAs_Subrule_Login",
|
||||
"RunAs_System_or_External_tools",
|
||||
"Run_Malicious_Msbuild_Project",
|
||||
"Run_whoami_as_System",
|
||||
"Rundll32_AWL_Bypass",
|
||||
"SPN_LDAP_requests",
|
||||
"Scheduled_Task_Was_Created_Or_Updated_Via_Schtasks",
|
||||
"Search_Stored_Credentials",
|
||||
"Service_Created_or_Modified",
|
||||
"Shadow_Copies_Deletion_with_Builtin_Tools",
|
||||
"Shadow_Key_Creation",
|
||||
"Shadow_Screen_save",
|
||||
"Shadow_Screen_saves_PowerShell",
|
||||
"SharpSploit_Usage",
|
||||
"SharpWMI_Usage",
|
||||
"Sharphound_Client_Side",
|
||||
"Sharphound_Server_Side",
|
||||
"SilentTrinity_Stager",
|
||||
"Sliver_Shell_Usage",
|
||||
"Software_Discovery",
|
||||
"Spoolsv_Priv_Escalation",
|
||||
"Stop_Important_Service",
|
||||
"Stop_Important_Service_registry",
|
||||
"Subrule_Sharphound_Client_Side",
|
||||
"Subrule_Sharphound_Server_Side",
|
||||
"Suspicious_Access_To_Users_Folder",
|
||||
"Suspicious_Child_from_Messenger_Process",
|
||||
"Suspicious_Create_File_FromBrowser_SuspiciousExtension",
|
||||
"Suspicious_Create_File_FromMessenger_SuspiciousExtension",
|
||||
"Suspicious_Create_File_PartitionMaster_DirectAccess",
|
||||
"Suspicious_Create_File_RawDisk_DirectAccess",
|
||||
"Suspicious_Create_Object_Account_Persistence",
|
||||
"Suspicious_Create_Process_At_Persistence",
|
||||
"Suspicious_Create_Process_BitsAdmin_RestrictionBypass",
|
||||
"Suspicious_Create_Process_Debugger_Inject",
|
||||
"Suspicious_Create_Process_DirectoryMock_UACBypass",
|
||||
"Suspicious_Create_Process_NetSh_NetShell",
|
||||
"Suspicious_Create_Process_Ping_SelfDelete",
|
||||
"Suspicious_Create_Process_RunScript_WScript",
|
||||
"Suspicious_Create_Process_Schtasks_Persistence",
|
||||
"Suspicious_Create_Process_TaskKill_TerminateProcess",
|
||||
"Suspicious_Create_Process_VSTOInstaller_OfficeAddIns",
|
||||
"Suspicious_Create_Process_VirtualInstance_Evasion",
|
||||
"Suspicious_Create_Process_WinDef_AddExclusion",
|
||||
"Suspicious_Create_Process_WinDef_ChangeSettings",
|
||||
"Suspicious_Create_Process_WithDebugger_Execution_Predetect_2_1",
|
||||
"Suspicious_Create_Process_WusaExtract_UACBypass",
|
||||
"Suspicious_Create_Registry_Key_SafeBoot",
|
||||
"Suspicious_Delete_Registry_Key_ETWProvider",
|
||||
"Suspicious_Delete_Registry_Key_RunAsPPL",
|
||||
"Suspicious_Delete_Registry_Key_SafeBoot",
|
||||
"Suspicious_Delete_Registry_Key_Service",
|
||||
"Suspicious_Delete_Registry_Key_TaskSD",
|
||||
"Suspicious_File_Created_by_Legal_Process",
|
||||
"Suspicious_Windows_Kernel_creating",
|
||||
"Suspicious_Wmic_Command",
|
||||
"Suspicious_Write_File_EfiSystemPartition_Persistence",
|
||||
"Suspicious_Write_File_USB_AirSpread",
|
||||
"Suspicious_Write_Process_Inject_CreateRemoteThread",
|
||||
"Suspicious_Write_Registry_Key_CPL",
|
||||
"Suspicious_Write_Registry_Key_ChangeDefaultFileAssociation",
|
||||
"Suspicious_Write_Registry_Key_ChangeFirewallPolicy",
|
||||
"Suspicious_Write_Registry_Key_ChangeRdpPort",
|
||||
"Suspicious_Write_Registry_Key_CredentialsDelegation",
|
||||
"Suspicious_Write_Registry_Key_DisableAppLaunch",
|
||||
"Suspicious_Write_Registry_Key_DisableTaskManager",
|
||||
"Suspicious_Write_Registry_Key_DisableUAC",
|
||||
"Suspicious_Write_Registry_Key_FlashConfigEnrollee",
|
||||
"Suspicious_Write_Registry_Key_ImagePath",
|
||||
"Suspicious_Write_Registry_Key_InjectAppCertDlls",
|
||||
"Suspicious_Write_Registry_Key_InjectAppInitDLLs",
|
||||
"Suspicious_Write_Registry_Key_InjectImageFileExecutionOptions",
|
||||
"Suspicious_Write_Registry_Key_InjectLoadAppInitDLLs",
|
||||
"Suspicious_Write_Registry_Key_InjectSilentProcessExit",
|
||||
"Suspicious_Write_Registry_Key_KillAntivirus",
|
||||
"Suspicious_Write_Process_Inject_ProcessTampering",
|
||||
"Suspicious_Write_Registry_Key_LsaComponents",
|
||||
"Suspicious_Write_Registry_Key_ModifyRdpSettings",
|
||||
"Suspicious_Write_Registry_Key_OfficeTemplate",
|
||||
"Suspicious_Write_Registry_Key_ProxyHijack",
|
||||
"Suspicious_Write_Registry_Key_SafeBoot",
|
||||
"Suspicious_Write_Registry_Key_ScreenSaver",
|
||||
"Suspicious_Write_Registry_Key_SvchostContextService",
|
||||
"Suspicious_Write_Registry_Key_TerminalContextService",
|
||||
"Suspicious_Write_Registry_Key_TimeProviders",
|
||||
"Suspicious_process_execution_sequence",
|
||||
"Sysmon_Driver_Unload",
|
||||
"System_Information_Discovery",
|
||||
"System_Network_Configuration_Discovery",
|
||||
"System_Network_Connections_Discovery",
|
||||
"System_Service_Discovery",
|
||||
"TikiTorch_Process_Injection",
|
||||
"Universal_Windows_Platform_Apps_Modify",
|
||||
"User_object_ldap_request",
|
||||
"Userinitmprlogonscript_Modify",
|
||||
"WDAC_Bypass_via_Dbgsrv",
|
||||
"WDigest_Enable",
|
||||
"WMI_Subscriptions",
|
||||
"WinAPI_Access_from_Powershell",
|
||||
"Windows_Accessibility_StickyKey_modification",
|
||||
"Windows_Autorun_Modification",
|
||||
"Windows_Defender_Disable",
|
||||
"Windows_Eventlog_cleaning",
|
||||
"Windows_Hacktool_Usage",
|
||||
"Windows_Malicious_service_registration",
|
||||
"Windows_Registry_sensitive_keys_modification",
|
||||
"Windows_Service_Installed",
|
||||
"Windows_Shadow_copy_removal",
|
||||
"Windows_WMI_event_consumer_registration",
|
||||
"Windows_WMI_event_subscription_removal",
|
||||
"Windows_firewall_enable_local_RDP",
|
||||
"XSL_Script_WMIC_Execution"
|
||||
"Suspicious_Write_Registry_Key_ScreenSaver"
|
||||
],
|
||||
"fields": [
|
||||
"action",
|
||||
"alert.context",
|
||||
"alert.key",
|
||||
"category.generic",
|
||||
"category.high",
|
||||
"category.low",
|
||||
"chain_id",
|
||||
"correlation_name",
|
||||
"correlation_type",
|
||||
"dst.asset",
|
||||
"dst.fqdn",
|
||||
"dst.host",
|
||||
"dst.hostname",
|
||||
"dst.ip",
|
||||
"dst.mac",
|
||||
"dst.port",
|
||||
"event_src.asset",
|
||||
"event_src.category",
|
||||
"event_src.fqdn",
|
||||
"event_src.host",
|
||||
"event_src.hostname",
|
||||
"event_src.ip",
|
||||
"event_src.rule",
|
||||
"event_src.subsys",
|
||||
"event_src.title",
|
||||
"event_src.vendor",
|
||||
"importance",
|
||||
"incident.aggregation.key",
|
||||
"incident.aggregation.time_window",
|
||||
"incident.aggregation.timeout",
|
||||
"incident.attacking_addresses",
|
||||
"incident.category",
|
||||
"incident.severity",
|
||||
"labels",
|
||||
"numfield1",
|
||||
"object",
|
||||
"object.account.domain",
|
||||
"object.account.fullname",
|
||||
"object.account.id",
|
||||
"object.account.name",
|
||||
"object.account.privileges",
|
||||
"object.account.session_id",
|
||||
"object.domain",
|
||||
"object.fullpath",
|
||||
"object.hash",
|
||||
"object.id",
|
||||
"object.name",
|
||||
"object.new_value",
|
||||
"object.path",
|
||||
"object.process.cmdline",
|
||||
"object.process.cwd",
|
||||
"object.process.fullpath",
|
||||
"object.process.guid",
|
||||
"object.process.hash",
|
||||
"object.process.id",
|
||||
"object.process.meta",
|
||||
"object.process.name",
|
||||
"object.process.original_name",
|
||||
"object.process.parent.cmdline",
|
||||
"object.process.parent.fullpath",
|
||||
"object.process.parent.guid",
|
||||
"object.process.parent.id",
|
||||
"object.process.parent.name",
|
||||
"object.process.parent.path",
|
||||
"object.process.path",
|
||||
"object.process.version",
|
||||
"object.property",
|
||||
"object.query",
|
||||
"object.state",
|
||||
"object.storage.fullpath",
|
||||
"object.storage.id",
|
||||
"object.storage.name",
|
||||
"object.storage.path",
|
||||
"object.type",
|
||||
"object.value",
|
||||
"object.vendor",
|
||||
"object.version",
|
||||
"reason",
|
||||
"src.asset",
|
||||
"src.fqdn",
|
||||
"src.host",
|
||||
"src.hostname",
|
||||
"src.ip",
|
||||
"src.mac",
|
||||
"src.port",
|
||||
"status",
|
||||
"subject",
|
||||
"subject.account.domain",
|
||||
"subject.account.fullname",
|
||||
"subject.account.id",
|
||||
"subject.account.name",
|
||||
"subject.account.privileges",
|
||||
"subject.account.session_id",
|
||||
"subject.name",
|
||||
"subject.process.cmdline",
|
||||
"subject.process.cwd",
|
||||
"subject.process.fullpath",
|
||||
"subject.process.guid",
|
||||
"subject.process.hash",
|
||||
"subject.process.id",
|
||||
"subject.process.meta",
|
||||
"subject.process.name",
|
||||
"subject.process.original_name",
|
||||
"subject.process.parent.id",
|
||||
"subject.process.path",
|
||||
"subject.process.version",
|
||||
"subject.type",
|
||||
"subject.version"
|
||||
"subject.process.path"
|
||||
],
|
||||
"last_module_update": "2022-10-26 00:00:00",
|
||||
"last_update": "2022-10-26 00:00:00"
|
||||
"last_module_update": "2022-12-08 00:00:00",
|
||||
"last_update": "2022-12-08 00:00:00"
|
||||
},
|
||||
{
|
||||
"group_id": "",
|
||||
@@ -913,7 +511,7 @@
|
||||
"fields": [
|
||||
"reason"
|
||||
],
|
||||
"last_module_update": "2022-11-02 00:00:00",
|
||||
"last_update": "2022-11-02 00:00:00"
|
||||
"last_module_update": "2022-12-08 00:00:00",
|
||||
"last_update": "2022-12-08 00:00:00"
|
||||
}
|
||||
]
|
||||
@@ -8,7 +8,7 @@ const name = "empty";
|
||||
|
||||
module.exports = {
|
||||
name,
|
||||
props: ["protoAPI", "hash", "module", "eventsAPI", "modulesAPI", "components", "viewMode"],
|
||||
props: ["protoAPI", "hash", "module", "api", "components", "viewMode"],
|
||||
data: () => ({
|
||||
})
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ const name = "empty";
|
||||
|
||||
module.exports = {
|
||||
name,
|
||||
props: ["protoAPI", "hash", "module", "eventsAPI", "modulesAPI", "components", "viewMode"],
|
||||
props: ["protoAPI", "hash", "module", "api", "components", "viewMode"],
|
||||
data: () => ({
|
||||
})
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ const name = "empty";
|
||||
|
||||
module.exports = {
|
||||
name,
|
||||
props: ["protoAPI", "hash", "module", "eventsAPI", "modulesAPI", "components", "viewMode"],
|
||||
props: ["protoAPI", "hash", "module", "api", "components", "viewMode"],
|
||||
data: () => ({
|
||||
})
|
||||
};
|
||||
|
||||
+126
-142
@@ -1,163 +1,147 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-tabs tab-position="left" v-model="leftTab">
|
||||
<el-tab-pane
|
||||
name="api"
|
||||
:label="locale[$i18n.locale]['api']"
|
||||
class="layout-fill overflow-hidden"
|
||||
v-if="viewMode === 'agent'"
|
||||
>
|
||||
<div id="exec_actions" class="layout-margin-xl limit-length">
|
||||
<el-select v-model="actionName" slot="prepend" :placeholder="locale[$i18n.locale]['actionSelectPl']">
|
||||
<el-option v-for="(id, idx) in module.info.actions"
|
||||
:label="module.locale.actions[id][$i18n.locale].title"
|
||||
:value="id"
|
||||
:key="idx"
|
||||
></el-option>
|
||||
</el-select>
|
||||
<div v-if="actionName">
|
||||
<div id="inp_actions"
|
||||
v-for="(id, idx) in module.current_action_config[actionName].fields"
|
||||
:key="idx">
|
||||
<el-input
|
||||
:placeholder="module.locale.fields[id][$i18n.locale].description"
|
||||
v-model="actionDataModel[id]">
|
||||
</el-input>
|
||||
<div>
|
||||
<div id="exec_actions" class="layout-margin-bottom-xl">
|
||||
<el-select v-model="actionName" slot="prepend" :placeholder="locale[$i18n.locale]['actionSelectPl']">
|
||||
<el-option v-for="(id, idx) in module.info.actions"
|
||||
:label="module.locale.actions[id][$i18n.locale].title"
|
||||
:value="id"
|
||||
:key="idx"
|
||||
></el-option>
|
||||
</el-select>
|
||||
<div v-if="actionName">
|
||||
<div id="inp_actions"
|
||||
v-for="(id, idx) in module.current_action_config[actionName].fields"
|
||||
:key="idx">
|
||||
<el-input
|
||||
:placeholder="module.locale.fields[id][$i18n.locale].description"
|
||||
v-model="actionDataModel[id]">
|
||||
</el-input>
|
||||
</div>
|
||||
<el-button @click="submitReqToExecAction" slot="append"
|
||||
>{{ locale[$i18n.locale]["buttonExecAction"] }}
|
||||
</el-button>
|
||||
</div>
|
||||
<el-button @click="submitReqToExecAction" slot="append"
|
||||
>{{ locale[$i18n.locale]["buttonExecAction"] }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-fill layout-row layout-row-column layout-row-between scrollable">
|
||||
<ul>
|
||||
<li :key="line" v-for="line in lines">{{ line }}</li>
|
||||
</ul>
|
||||
<div class="layout-column layout-align-space-between scrollable">
|
||||
<ul>
|
||||
<li :key="line" v-for="line in lines">{{ line }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const name = "responder";
|
||||
|
||||
module.exports = {
|
||||
name,
|
||||
props: ["protoAPI", "hash", "module", "eventsAPI", "modulesAPI", "components", "viewMode"],
|
||||
data: () => ({
|
||||
leftTab: undefined,
|
||||
connection: {},
|
||||
lines: [],
|
||||
actionName: undefined,
|
||||
actionDataModel: {},
|
||||
locale: {
|
||||
ru: {
|
||||
api: "Удаление файлов",
|
||||
buttonExecAction: "Выполнить действие",
|
||||
connected: "— подключение к серверу установлено",
|
||||
connError: "Не удалось подключиться к серверу",
|
||||
recvError: "Не удалось выполнить операцию",
|
||||
checkError: "Данные введены некорректно",
|
||||
actionError: "Выберите действие из списка",
|
||||
actionSelectPl: "Выбрать действие"
|
||||
},
|
||||
en: {
|
||||
api: "File remover",
|
||||
buttonExecAction: "Exec action",
|
||||
connected: "— connection to the server established",
|
||||
connError: "Failed to connect to the server",
|
||||
recvError: "Unable to perform the operation",
|
||||
checkError: "Data entered incorrectly",
|
||||
actionError: "Please choose action from list",
|
||||
actionSelectPl: "Select action"
|
||||
}
|
||||
}
|
||||
}),
|
||||
created() {
|
||||
if (this.viewMode === 'agent') {
|
||||
this.protoAPI.connect().then(
|
||||
connection => {
|
||||
const date = new Date().toLocaleTimeString();
|
||||
this.connection = connection;
|
||||
this.connection.subscribe(this.recvData, "data");
|
||||
this.$root.NotificationsService.success(`${date} ${this.locale[this.$i18n.locale]['connected']}`);
|
||||
},
|
||||
error => {
|
||||
this.$root.NotificationsService.error(this.locale[this.$i18n.locale]['connError']);
|
||||
console.log(error);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.leftTab = this.viewMode === 'agent' ? 'api' : undefined;
|
||||
},
|
||||
methods: {
|
||||
recvData(msg) {
|
||||
const date = new Date();
|
||||
const date_ms = date.toLocaleTimeString() + `.${date.getMilliseconds()}`;
|
||||
this.lines.push(
|
||||
`${date_ms} RECV DATA: ${new TextDecoder(
|
||||
"utf-8"
|
||||
).decode(msg.content.data)}`
|
||||
);
|
||||
},
|
||||
submitReqToExecAction() {
|
||||
const date = new Date();
|
||||
const date_ms = date.toLocaleTimeString() + `.${date.getMilliseconds()}`;
|
||||
if (!this.actionName) {
|
||||
this.$root.NotificationsService.error(this.locale[this.$i18n.locale]["actionError"]);
|
||||
return;
|
||||
}
|
||||
const defActCfg = this.module.default_action_config[this.actionName]
|
||||
if (typeof(defActCfg) !== "object" || !Array.isArray(defActCfg.fields) || defActCfg.fields.length === 0) {
|
||||
this.$root.NotificationsService.error(this.locale[this.$i18n.locale]["checkError"]);
|
||||
return;
|
||||
}
|
||||
let actionData = {};
|
||||
try {
|
||||
for (let fieldID in this.module.default_action_config[this.actionName].fields) {
|
||||
const fieldName = this.module.default_action_config[this.actionName].fields[fieldID];
|
||||
switch (this.module.fields_schema.properties[fieldName]["type"]) {
|
||||
case "number":
|
||||
actionData[fieldName] = parseInt(this.actionDataModel[fieldName], 10);
|
||||
break;
|
||||
case "string":
|
||||
actionData[fieldName] = this.actionDataModel[fieldName].toString();
|
||||
break;
|
||||
case "array":
|
||||
case "object":
|
||||
actionData[fieldName] = JSON.parse(this.actionDataModel[fieldName].toString());
|
||||
break;
|
||||
}
|
||||
if (!actionData[fieldName]) {
|
||||
throw "empty field value";
|
||||
}
|
||||
name,
|
||||
props: ["protoAPI", "hash", "module", "api", "components", "viewMode"],
|
||||
data: () => ({
|
||||
connection: {},
|
||||
lines: [],
|
||||
actionName: undefined,
|
||||
actionDataModel: {},
|
||||
locale: {
|
||||
ru: {
|
||||
buttonExecAction: "Выполнить действие",
|
||||
connected: "— подключение к серверу установлено",
|
||||
connError: "Не удалось подключиться к серверу",
|
||||
recvError: "Не удалось выполнить операцию",
|
||||
checkError: "Данные введены некорректно",
|
||||
actionError: "Выберите действие из списка",
|
||||
actionSelectPl: "Выбрать действие"
|
||||
},
|
||||
en: {
|
||||
buttonExecAction: "Exec action",
|
||||
connected: "— connection to the server established",
|
||||
connError: "Failed to connect to the server",
|
||||
recvError: "Unable to perform the operation",
|
||||
checkError: "Data entered incorrectly",
|
||||
actionError: "Please choose action from list",
|
||||
actionSelectPl: "Select action"
|
||||
}
|
||||
}
|
||||
}),
|
||||
created() {
|
||||
if (this.viewMode === 'agent') {
|
||||
this.protoAPI.connect().then(
|
||||
connection => {
|
||||
const date = new Date().toLocaleTimeString();
|
||||
this.connection = connection;
|
||||
this.connection.subscribe(this.recvData, "data");
|
||||
this.$root.NotificationsService.success(`${date} ${this.locale[this.$i18n.locale]['connected']}`);
|
||||
},
|
||||
error => {
|
||||
this.$root.NotificationsService.error(this.locale[this.$i18n.locale]['connError']);
|
||||
console.log(error);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
recvData(msg) {
|
||||
const date = new Date();
|
||||
const date_ms = date.toLocaleTimeString() + `.${date.getMilliseconds()}`;
|
||||
this.lines.push(
|
||||
`${date_ms} RECV DATA: ${new TextDecoder(
|
||||
"utf-8"
|
||||
).decode(msg.content.data)}`
|
||||
);
|
||||
},
|
||||
submitReqToExecAction() {
|
||||
const date = new Date();
|
||||
const date_ms = date.toLocaleTimeString() + `.${date.getMilliseconds()}`;
|
||||
if (!this.actionName) {
|
||||
this.$root.NotificationsService.error(this.locale[this.$i18n.locale]["actionError"]);
|
||||
return;
|
||||
}
|
||||
const defActCfg = this.module.default_action_config[this.actionName]
|
||||
if (typeof (defActCfg) !== "object" || !Array.isArray(defActCfg.fields) || defActCfg.fields.length === 0) {
|
||||
this.$root.NotificationsService.error(this.locale[this.$i18n.locale]["checkError"]);
|
||||
return;
|
||||
}
|
||||
let actionData = {};
|
||||
try {
|
||||
for (let fieldID in this.module.default_action_config[this.actionName].fields) {
|
||||
const fieldName = this.module.default_action_config[this.actionName].fields[fieldID];
|
||||
switch (this.module.fields_schema.properties[fieldName]["type"]) {
|
||||
case "number":
|
||||
actionData[fieldName] = parseInt(this.actionDataModel[fieldName], 10);
|
||||
break;
|
||||
case "string":
|
||||
actionData[fieldName] = this.actionDataModel[fieldName].toString();
|
||||
break;
|
||||
case "array":
|
||||
case "object":
|
||||
actionData[fieldName] = JSON.parse(this.actionDataModel[fieldName].toString());
|
||||
break;
|
||||
}
|
||||
if (!actionData[fieldName]) {
|
||||
throw "empty field value";
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
this.$root.NotificationsService.error(this.locale[this.$i18n.locale]["checkError"]);
|
||||
return;
|
||||
}
|
||||
let data = JSON.stringify({
|
||||
data: actionData,
|
||||
actions: [`${this.module.info.name}.${this.actionName}`]
|
||||
});
|
||||
this.lines.push(
|
||||
`${date_ms} SEND ACTION: ${data}`
|
||||
);
|
||||
this.connection.sendAction(data, this.actionName);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
this.$root.NotificationsService.error(this.locale[this.$i18n.locale]["checkError"]);
|
||||
return;
|
||||
}
|
||||
let data = JSON.stringify({
|
||||
data: actionData,
|
||||
actions: [`${this.module.info.name}.${this.actionName}`]
|
||||
});
|
||||
this.lines.push(
|
||||
`${date_ms} SEND ACTION: ${data}`
|
||||
);
|
||||
this.connection.sendAction(data, this.actionName);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#exec_actions .el-select, #inp_actions .el-input {
|
||||
#exec_actions .el-select, #inp_actions .el-input {
|
||||
max-width: 800px;
|
||||
min-width: 400px;
|
||||
width: 100%;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,342 +1,335 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-tabs tab-position="left" v-model="leftTab">
|
||||
<el-tab-pane
|
||||
name="api"
|
||||
:label="locale[$i18n.locale]['api']"
|
||||
class="layout-fill layout-column overflow-hidden"
|
||||
v-if="viewMode === 'agent'"
|
||||
>
|
||||
<div class="layout-margin-xl limit-length">
|
||||
<el-input :placeholder="locale[$i18n.locale]['filePl']" v-model="filepath">
|
||||
<el-button
|
||||
slot="append"
|
||||
icon="el-icon-s-promotion"
|
||||
class="flex-none"
|
||||
@click="submitReqToExecAction"
|
||||
>{{ locale[$i18n.locale]['buttonExecAction'] }}
|
||||
</el-button>
|
||||
</el-input>
|
||||
<div id="error" v-if="lastExecError" class="invalid-feedback">
|
||||
{{ lastExecError }}
|
||||
</div>
|
||||
<div>
|
||||
<div class="layout-margin-bottom-xl">
|
||||
<el-input :placeholder="locale[$i18n.locale]['filePl']" v-model="filepath">
|
||||
<el-button
|
||||
slot="append"
|
||||
icon="el-icon-s-promotion"
|
||||
class="flex-none"
|
||||
@click="submitReqToExecAction"
|
||||
>{{ locale[$i18n.locale]['buttonExecAction'] }}
|
||||
</el-button>
|
||||
</el-input>
|
||||
<div id="error" v-if="lastExecError" class="invalid-feedback">
|
||||
{{ lastExecError }}
|
||||
</div>
|
||||
</div>
|
||||
<div id="query">
|
||||
<el-input
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 3, maxRows: 8}"
|
||||
:placeholder="locale[$i18n.locale]['queryPl']"
|
||||
v-model="sqlQuery"
|
||||
@keyup.ctrl.enter.native="execSQL">
|
||||
</el-input>
|
||||
<div id="error" v-if="lastSqlError" class="invalid-feedback">
|
||||
{{ lastSqlError }}
|
||||
</div>
|
||||
<el-input
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 3, maxRows: 8}"
|
||||
:placeholder="locale[$i18n.locale]['queryPl']"
|
||||
v-model="sqlQuery"
|
||||
@keyup.ctrl.enter.native="execSQL">
|
||||
</el-input>
|
||||
<div id="error" v-if="lastSqlError" class="invalid-feedback">
|
||||
{{ lastSqlError }}
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<p class="layout-margin-xl buttons">
|
||||
<el-button type="primary" @click="execSQL" :disabled="!connection"
|
||||
>{{ locale[$i18n.locale]['buttonExec'] }}</el-button>
|
||||
<el-button @click="saveQuery"
|
||||
>{{ locale[$i18n.locale]['buttonSave'] }}</el-button>
|
||||
<el-button @click="loadQuery"
|
||||
>{{ locale[$i18n.locale]['buttonLoad'] }}</el-button>
|
||||
<el-button @click="resetFilters"
|
||||
>{{ locale[$i18n.locale]['buttonReset'] }}</el-button>
|
||||
<el-button type="primary" @click="execSQL" :disabled="!connection"
|
||||
>{{ locale[$i18n.locale]['buttonExec'] }}
|
||||
</el-button>
|
||||
<el-button @click="saveQuery"
|
||||
>{{ locale[$i18n.locale]['buttonSave'] }}
|
||||
</el-button>
|
||||
<el-button @click="loadQuery"
|
||||
>{{ locale[$i18n.locale]['buttonLoad'] }}
|
||||
</el-button>
|
||||
<el-button @click="resetFilters"
|
||||
>{{ locale[$i18n.locale]['buttonReset'] }}
|
||||
</el-button>
|
||||
</p>
|
||||
<div id="search">
|
||||
<el-input
|
||||
:placeholder="locale[$i18n.locale]['searchPl']"
|
||||
v-model="queryFilterText"
|
||||
class="input-with-select"
|
||||
>
|
||||
<el-select
|
||||
v-model="queryFilterField"
|
||||
slot="prepend"
|
||||
<el-input
|
||||
:placeholder="locale[$i18n.locale]['searchPl']"
|
||||
v-model="queryFilterText"
|
||||
class="input-with-select"
|
||||
>
|
||||
<el-option
|
||||
:label="locale[$i18n.locale]['allFields']"
|
||||
value="all"
|
||||
></el-option>
|
||||
<el-option
|
||||
v-for="(col, i) in queryColumns"
|
||||
:key="i"
|
||||
:label="col.prop"
|
||||
:value="col.prop"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-input>
|
||||
<el-select
|
||||
v-model="queryFilterField"
|
||||
slot="prepend"
|
||||
>
|
||||
<el-option
|
||||
:label="locale[$i18n.locale]['allFields']"
|
||||
value="all"
|
||||
></el-option>
|
||||
<el-option
|
||||
v-for="(col, i) in queryColumns"
|
||||
:key="i"
|
||||
:label="col.prop"
|
||||
:value="col.prop"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-input>
|
||||
</div>
|
||||
<br>
|
||||
<el-checkbox-group v-model="options" class="layout-margin-bottom-s">
|
||||
<el-checkbox
|
||||
:label="locale[$i18n.locale]['chgFixedFirst']"
|
||||
></el-checkbox>
|
||||
<el-checkbox
|
||||
:label="locale[$i18n.locale]['chgUseRegexp']"
|
||||
></el-checkbox>
|
||||
<el-checkbox-group v-model="options" class="layout-margin-bottom-m">
|
||||
<el-checkbox
|
||||
:label="locale[$i18n.locale]['chgFixedFirst']"
|
||||
></el-checkbox>
|
||||
<el-checkbox
|
||||
:label="locale[$i18n.locale]['chgUseRegexp']"
|
||||
></el-checkbox>
|
||||
</el-checkbox-group>
|
||||
<div ref="boxTable" style="flex-grow: 1">
|
||||
<el-table
|
||||
ref="resultTable"
|
||||
border
|
||||
style="position: absolute"
|
||||
:height="height"
|
||||
:data="queryDataFilter"
|
||||
>
|
||||
<el-table-column
|
||||
v-for="(col, i) in queryColumns"
|
||||
:key="i"
|
||||
:prop="col.prop"
|
||||
:label="col.prop"
|
||||
:width="col.width"
|
||||
:fixed="i === 0 && options.indexOf(locale[$i18n.locale]['chgFixedFirst']) !== -1"
|
||||
:filters="col.filters"
|
||||
:filter-method="filterHandler"
|
||||
sortable
|
||||
><template slot-scope="scope">{{scope.row[col.prop]}}</template></el-table-column>
|
||||
</el-table>
|
||||
<el-table
|
||||
ref="resultTable"
|
||||
border
|
||||
style="position: absolute"
|
||||
:height="height"
|
||||
:data="queryDataFilter"
|
||||
>
|
||||
<el-table-column
|
||||
v-for="(col, i) in queryColumns"
|
||||
:key="i"
|
||||
:prop="col.prop"
|
||||
:label="col.prop"
|
||||
:width="col.width"
|
||||
:fixed="i === 0 && options.indexOf(locale[$i18n.locale]['chgFixedFirst']) !== -1"
|
||||
:filters="col.filters"
|
||||
:filter-method="filterHandler"
|
||||
sortable
|
||||
>
|
||||
<template slot-scope="scope">{{ scope.row[col.prop] }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const name = "file_uploader";
|
||||
|
||||
module.exports = {
|
||||
name,
|
||||
props: ["protoAPI", "hash", "module", "eventsAPI", "modulesAPI", "components", "viewMode"],
|
||||
data: () => ({
|
||||
leftTab: undefined,
|
||||
height: 100,
|
||||
timerId: undefined,
|
||||
sqlQuery: `SELECT * FROM files ORDER BY id DESC;`,
|
||||
filepath: "",
|
||||
connection: undefined,
|
||||
queryColumns: [],
|
||||
queryData: [],
|
||||
options: [],
|
||||
lastSqlError: "",
|
||||
lastExecError: "",
|
||||
queryFilterText: "",
|
||||
queryFilterField: "all",
|
||||
nStdCol: 1.4,
|
||||
nPxChar: 9,
|
||||
nCharsPad: 7,
|
||||
locale: {
|
||||
ru: {
|
||||
api: "Отправка файлов",
|
||||
buttonExec: "Выполнить запрос",
|
||||
buttonSave: "Сохранить запрос",
|
||||
buttonLoad: "Загрузить изменения",
|
||||
buttonReset: "Сбросить фильтр",
|
||||
buttonExecAction: "Отправить файл",
|
||||
connected: "— подключение к серверу установлено",
|
||||
connAgentError: "Не удалось подключиться к агенту",
|
||||
connServerError: "Не удалось подключиться к серверу",
|
||||
fileCheckError: "Внутренняя ошибка сервера",
|
||||
fileNotFoundError: "Файл не найден или недоступен",
|
||||
fileSizeError: "Превышен максимальный размер файла",
|
||||
filePathError: "Путь к файлу задан некорректно",
|
||||
checkSuccess: "Файл отправлен во внешнюю систему",
|
||||
recvError: "Не удалось выполнить SQL-запрос",
|
||||
allFields: "Все",
|
||||
chgFixedFirst: "Закрепить первый столбец",
|
||||
chgUseRegexp: "Использовать регулярные выражения",
|
||||
rgAgentSide: "Выполнить на агенте",
|
||||
rgServerSide: "Выполнить на сервере",
|
||||
searchPl: "Поиск по файлам",
|
||||
queryPl: "SQL-запрос для выборки",
|
||||
filePl: "Путь к файлу"
|
||||
},
|
||||
en: {
|
||||
api: "File sender",
|
||||
buttonExec: "Execute query",
|
||||
buttonSave: "Save query",
|
||||
buttonLoad: "Load query",
|
||||
buttonReset: "Reset filter",
|
||||
buttonExecAction: "Send file",
|
||||
connected: "— connection to the server established",
|
||||
connAgentError: "Failed to connect to the agent",
|
||||
connServerError: "Failed to connect to the server",
|
||||
fileCheckError: "Server internal error",
|
||||
fileNotFoundError: "File not found or not available",
|
||||
fileSizeError: "File size exceeded",
|
||||
filePathError: "Invalid file path",
|
||||
checkSuccess: "File is sent to external system",
|
||||
recvError: "Failed to execute SQL query",
|
||||
allFields: "All",
|
||||
chgFixedFirst: "Fix first column",
|
||||
chgUseRegexp: "Use regexp",
|
||||
rgAgentSide: "Execute on agent side",
|
||||
rgServerSide: "Execute on server side",
|
||||
searchPl: "Search by file",
|
||||
queryPl: "SQL query for selection",
|
||||
filePl: "File path"
|
||||
}
|
||||
}
|
||||
}),
|
||||
created() {
|
||||
if (this.viewMode === 'agent') {
|
||||
window.addEventListener("resize", this.resizeTable);
|
||||
this.timerId = window.setInterval(this.resizeTable, 500);
|
||||
this.protoAPI.connect().then(
|
||||
connection => {
|
||||
const date = new Date().toLocaleTimeString();
|
||||
this.connection = connection;
|
||||
this.connection.subscribe(this.recvData, "data");
|
||||
this.$root.NotificationsService.success(`${date} ${this.locale[this.$i18n.locale]['connected']}`);
|
||||
},
|
||||
error => {
|
||||
this.lastSqlError = this.locale[this.$i18n.locale]['connServerError'];
|
||||
this.$root.NotificationsService.error(this.lastSqlError);
|
||||
console.log(error);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
if (this.viewMode === 'agent') {
|
||||
window.removeEventListener("resize", this.resizeTable);
|
||||
window.clearInterval(this.timerId);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.leftTab = this.viewMode === 'agent' ? 'api' : undefined;
|
||||
},
|
||||
computed: {
|
||||
queryDataFilter() {
|
||||
let re = null;
|
||||
try {
|
||||
re = new RegExp(this.queryFilterText);
|
||||
} catch {}
|
||||
const isRegex = re && this.options.indexOf(this.locale[this.$i18n.locale]['chgUseRegexp']) !== -1;
|
||||
const text = isRegex ? re : this.queryFilterText.toLowerCase();
|
||||
const search = (row, field) => {
|
||||
const fields = Object.keys(row).filter(key => key == field || field == "all");
|
||||
const match = (val) => isRegex ? val.match(text) : val.toLowerCase().includes(text);
|
||||
return fields.some(f => match((row[f] || "null").toString()));
|
||||
}
|
||||
return this.queryData.filter(row => !text || search(row, this.queryFilterField));
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
recvData(msg) {
|
||||
let data = new TextDecoder("utf-8").decode(msg.content.data);
|
||||
let result = JSON.parse(data);
|
||||
if (result.status === "error") {
|
||||
if (result.error == "connection_error") {
|
||||
this.lastSqlError = this.locale[this.$i18n.locale]['connAgentError'];
|
||||
this.$root.NotificationsService.error(this.lastSqlError);
|
||||
} else if (result.error == "internal_error") {
|
||||
this.lastExecError = this.locale[this.$i18n.locale]['fileCheckError'];
|
||||
this.$root.NotificationsService.error(this.lastExecError);
|
||||
} else if (result.error == "file_not_found") {
|
||||
this.lastExecError = this.locale[this.$i18n.locale]['fileNotFoundError'];
|
||||
this.$root.NotificationsService.error(this.lastExecError);
|
||||
} else if (result.error == "file_size_exceeded") {
|
||||
this.lastExecError = this.locale[this.$i18n.locale]['fileSizeError'];
|
||||
this.$root.NotificationsService.error(this.lastExecError);
|
||||
} else {
|
||||
this.lastSqlError = this.locale[this.$i18n.locale]['recvError']
|
||||
this.$root.NotificationsService.error(this.lastSqlError);
|
||||
this.lastSqlError += ": " + result.error;
|
||||
name,
|
||||
props: ["protoAPI", "hash", "module", "api", "components", "viewMode"],
|
||||
data: () => ({
|
||||
height: 100,
|
||||
timerId: undefined,
|
||||
sqlQuery: `SELECT * FROM files ORDER BY id DESC;`,
|
||||
filepath: "",
|
||||
connection: undefined,
|
||||
queryColumns: [],
|
||||
queryData: [],
|
||||
options: [],
|
||||
lastSqlError: "",
|
||||
lastExecError: "",
|
||||
queryFilterText: "",
|
||||
queryFilterField: "all",
|
||||
nStdCol: 1.4,
|
||||
nPxChar: 9,
|
||||
nCharsPad: 7,
|
||||
locale: {
|
||||
ru: {
|
||||
buttonExec: "Выполнить запрос",
|
||||
buttonSave: "Сохранить запрос",
|
||||
buttonLoad: "Загрузить изменения",
|
||||
buttonReset: "Сбросить фильтр",
|
||||
buttonExecAction: "Отправить файл",
|
||||
connected: "— подключение к серверу установлено",
|
||||
connAgentError: "Не удалось подключиться к агенту",
|
||||
connServerError: "Не удалось подключиться к серверу",
|
||||
fileCheckError: "Внутренняя ошибка сервера",
|
||||
fileNotFoundError: "Файл не найден или недоступен",
|
||||
fileSizeError: "Превышен максимальный размер файла",
|
||||
filePathError: "Путь к файлу задан некорректно",
|
||||
checkSuccess: "Файл отправлен во внешнюю систему",
|
||||
recvError: "Не удалось выполнить SQL-запрос",
|
||||
allFields: "Все",
|
||||
chgFixedFirst: "Закрепить первый столбец",
|
||||
chgUseRegexp: "Использовать регулярные выражения",
|
||||
rgAgentSide: "Выполнить на агенте",
|
||||
rgServerSide: "Выполнить на сервере",
|
||||
searchPl: "Поиск по файлам",
|
||||
queryPl: "SQL-запрос для выборки",
|
||||
filePl: "Путь к файлу"
|
||||
},
|
||||
en: {
|
||||
buttonExec: "Execute query",
|
||||
buttonSave: "Save query",
|
||||
buttonLoad: "Load query",
|
||||
buttonReset: "Reset filter",
|
||||
buttonExecAction: "Send file",
|
||||
connected: "— connection to the server established",
|
||||
connAgentError: "Failed to connect to the agent",
|
||||
connServerError: "Failed to connect to the server",
|
||||
fileCheckError: "Server internal error",
|
||||
fileNotFoundError: "File not found or not available",
|
||||
fileSizeError: "File size exceeded",
|
||||
filePathError: "Invalid file path",
|
||||
checkSuccess: "File is sent to external system",
|
||||
recvError: "Failed to execute SQL query",
|
||||
allFields: "All",
|
||||
chgFixedFirst: "Fix first column",
|
||||
chgUseRegexp: "Use regexp",
|
||||
rgAgentSide: "Execute on agent side",
|
||||
rgServerSide: "Execute on server side",
|
||||
searchPl: "Search by file",
|
||||
queryPl: "SQL query for selection",
|
||||
filePl: "File path"
|
||||
}
|
||||
}
|
||||
}),
|
||||
created() {
|
||||
if (this.viewMode === 'agent') {
|
||||
window.addEventListener("resize", this.resizeTable);
|
||||
this.timerId = window.setInterval(this.resizeTable, 500);
|
||||
this.protoAPI.connect().then(
|
||||
connection => {
|
||||
const date = new Date().toLocaleTimeString();
|
||||
this.connection = connection;
|
||||
this.connection.subscribe(this.recvData, "data");
|
||||
this.$root.NotificationsService.success(`${date} ${this.locale[this.$i18n.locale]['connected']}`);
|
||||
},
|
||||
error => {
|
||||
this.lastSqlError = this.locale[this.$i18n.locale]['connServerError'];
|
||||
this.$root.NotificationsService.error(this.lastSqlError);
|
||||
console.log(error);
|
||||
},
|
||||
);
|
||||
}
|
||||
} else if (result.type == "exec_sql_resp") {
|
||||
this.queryColumns = result.cols
|
||||
.map((c, i) => ({
|
||||
prop: c,
|
||||
width: this.getColWidth(result.rows
|
||||
.map(r => (r[i] || "null").toString().length), c.length),
|
||||
filters: result.rows
|
||||
.map(r => r[i])
|
||||
.sort()
|
||||
.filter((v, i, a) => a.indexOf(v) === i)
|
||||
.map(v => ({
|
||||
text: (v || "null").toString().substring(0, 40),
|
||||
value: v,
|
||||
})),
|
||||
}));
|
||||
this.queryData = result.rows.map((r) => r.reduce((a,x,i) => ({...a, [result.cols[i]]: x}), {}));
|
||||
this.resizeTable();
|
||||
} else if (result.type == "exec_upload_resp") {
|
||||
this.$root.NotificationsService.success(`${this.locale[this.$i18n.locale]['checkSuccess']}`);
|
||||
} else {
|
||||
console.log("received unknown message type from server", result)
|
||||
}
|
||||
},
|
||||
submitReqToExecAction() {
|
||||
this.lastExecError = "";
|
||||
let filepath = this.filepath.trim()
|
||||
if (filepath === "" || filepath.length > 256) {
|
||||
this.lastExecError = this.locale[this.$i18n.locale]['filePathError'];
|
||||
this.$root.NotificationsService.error(this.lastExecError);
|
||||
} else {
|
||||
let actionName = "fu_upload_object_file";
|
||||
let data = JSON.stringify({
|
||||
data: { "object.fullpath": filepath },
|
||||
actions: [`${this.module.info.name}.${actionName}`]
|
||||
});
|
||||
this.connection.sendAction(data, actionName);
|
||||
}
|
||||
destroyed() {
|
||||
if (this.viewMode === 'agent') {
|
||||
window.removeEventListener("resize", this.resizeTable);
|
||||
window.clearInterval(this.timerId);
|
||||
}
|
||||
},
|
||||
execSQL() {
|
||||
if (!this.connection) return;
|
||||
this.lastSqlError = "";
|
||||
this.queryFilterText = "";
|
||||
this.queryFilterField = "all";
|
||||
this.queryColumns = [];
|
||||
this.queryData = [];
|
||||
let data = JSON.stringify({
|
||||
type: "exec_sql_req",
|
||||
sql: this.sqlQuery,
|
||||
});
|
||||
this.connection.sendData(data);
|
||||
computed: {
|
||||
queryDataFilter() {
|
||||
let re = null;
|
||||
try {
|
||||
re = new RegExp(this.queryFilterText);
|
||||
} catch {
|
||||
}
|
||||
const isRegex = re && this.options.indexOf(this.locale[this.$i18n.locale]['chgUseRegexp']) !== -1;
|
||||
const text = isRegex ? re : this.queryFilterText.toLowerCase();
|
||||
const search = (row, field) => {
|
||||
const fields = Object.keys(row).filter(key => key == field || field == "all");
|
||||
const match = (val) => isRegex ? val.match(text) : val.toLowerCase().includes(text);
|
||||
return fields.some(f => match((row[f] || "null").toString()));
|
||||
}
|
||||
return this.queryData.filter(row => !text || search(row, this.queryFilterField));
|
||||
}
|
||||
},
|
||||
saveQuery() {
|
||||
localStorage.setItem("FileUploaderSqlQuery", this.sqlQuery);
|
||||
},
|
||||
loadQuery() {
|
||||
if (localStorage.getItem("FileUploaderSqlQuery")) {
|
||||
this.sqlQuery = localStorage.getItem("FileUploaderSqlQuery");
|
||||
this.queryData = [];
|
||||
this.execSQL();
|
||||
}
|
||||
},
|
||||
resizeTable() {
|
||||
this.height = this.$refs.boxTable.clientHeight;
|
||||
},
|
||||
getColWidth(array, min) {
|
||||
const n = array.length;
|
||||
if (n === 0) {
|
||||
return Math.floor(this.nPxChar * (this.nCharsPad + min));
|
||||
}
|
||||
const mean = array.reduce((a, b) => a + b) / n;
|
||||
return Math.floor(this.nPxChar * Math.max(
|
||||
this.nCharsPad + min, mean + this.nStdCol * Math.sqrt(array
|
||||
.map(x => Math.pow(x - mean, 2))
|
||||
.reduce((a, b) => a + b) / n))).toString();
|
||||
},
|
||||
filterHandler(value, row, column) {
|
||||
const property = column['property'];
|
||||
return row[property] === value;
|
||||
},
|
||||
resetFilters() {
|
||||
this.queryFilterText = "";
|
||||
this.queryFilterField = "all";
|
||||
this.$refs.resultTable.clearFilter();
|
||||
methods: {
|
||||
recvData(msg) {
|
||||
let data = new TextDecoder("utf-8").decode(msg.content.data);
|
||||
let result = JSON.parse(data);
|
||||
if (result.status === "error") {
|
||||
if (result.error == "connection_error") {
|
||||
this.lastSqlError = this.locale[this.$i18n.locale]['connAgentError'];
|
||||
this.$root.NotificationsService.error(this.lastSqlError);
|
||||
} else if (result.error == "internal_error") {
|
||||
this.lastExecError = this.locale[this.$i18n.locale]['fileCheckError'];
|
||||
this.$root.NotificationsService.error(this.lastExecError);
|
||||
} else if (result.error == "file_not_found") {
|
||||
this.lastExecError = this.locale[this.$i18n.locale]['fileNotFoundError'];
|
||||
this.$root.NotificationsService.error(this.lastExecError);
|
||||
} else if (result.error == "file_size_exceeded") {
|
||||
this.lastExecError = this.locale[this.$i18n.locale]['fileSizeError'];
|
||||
this.$root.NotificationsService.error(this.lastExecError);
|
||||
} else {
|
||||
this.lastSqlError = this.locale[this.$i18n.locale]['recvError']
|
||||
this.$root.NotificationsService.error(this.lastSqlError);
|
||||
this.lastSqlError += ": " + result.error;
|
||||
}
|
||||
} else if (result.type == "exec_sql_resp") {
|
||||
this.queryColumns = result.cols
|
||||
.map((c, i) => ({
|
||||
prop: c,
|
||||
width: this.getColWidth(result.rows
|
||||
.map(r => (r[i] || "null").toString().length), c.length),
|
||||
filters: result.rows
|
||||
.map(r => r[i])
|
||||
.sort()
|
||||
.filter((v, i, a) => a.indexOf(v) === i)
|
||||
.map(v => ({
|
||||
text: (v || "null").toString().substring(0, 40),
|
||||
value: v,
|
||||
})),
|
||||
}));
|
||||
this.queryData = result.rows.map((r) => r.reduce((a, x, i) => ({...a, [result.cols[i]]: x}), {}));
|
||||
this.resizeTable();
|
||||
} else if (result.type == "exec_upload_resp") {
|
||||
this.$root.NotificationsService.success(`${this.locale[this.$i18n.locale]['checkSuccess']}`);
|
||||
} else {
|
||||
console.log("received unknown message type from server", result)
|
||||
}
|
||||
},
|
||||
submitReqToExecAction() {
|
||||
this.lastExecError = "";
|
||||
let filepath = this.filepath.trim()
|
||||
if (filepath === "" || filepath.length > 256) {
|
||||
this.lastExecError = this.locale[this.$i18n.locale]['filePathError'];
|
||||
this.$root.NotificationsService.error(this.lastExecError);
|
||||
} else {
|
||||
let actionName = "fu_upload_object_file";
|
||||
let data = JSON.stringify({
|
||||
data: {"object.fullpath": filepath},
|
||||
actions: [`${this.module.info.name}.${actionName}`]
|
||||
});
|
||||
this.connection.sendAction(data, actionName);
|
||||
}
|
||||
},
|
||||
execSQL() {
|
||||
if (!this.connection) return;
|
||||
this.lastSqlError = "";
|
||||
this.queryFilterText = "";
|
||||
this.queryFilterField = "all";
|
||||
this.queryColumns = [];
|
||||
this.queryData = [];
|
||||
let data = JSON.stringify({
|
||||
type: "exec_sql_req",
|
||||
sql: this.sqlQuery,
|
||||
});
|
||||
this.connection.sendData(data);
|
||||
},
|
||||
saveQuery() {
|
||||
localStorage.setItem("FileUploaderSqlQuery", this.sqlQuery);
|
||||
},
|
||||
loadQuery() {
|
||||
if (localStorage.getItem("FileUploaderSqlQuery")) {
|
||||
this.sqlQuery = localStorage.getItem("FileUploaderSqlQuery");
|
||||
this.queryData = [];
|
||||
this.execSQL();
|
||||
}
|
||||
},
|
||||
resizeTable() {
|
||||
this.height = this.$refs.boxTable.clientHeight;
|
||||
},
|
||||
getColWidth(array, min) {
|
||||
const n = array.length;
|
||||
if (n === 0) {
|
||||
return Math.floor(this.nPxChar * (this.nCharsPad + min));
|
||||
}
|
||||
const mean = array.reduce((a, b) => a + b) / n;
|
||||
return Math.floor(this.nPxChar * Math.max(
|
||||
this.nCharsPad + min, mean + this.nStdCol * Math.sqrt(array
|
||||
.map(x => Math.pow(x - mean, 2))
|
||||
.reduce((a, b) => a + b) / n))).toString();
|
||||
},
|
||||
filterHandler(value, row, column) {
|
||||
const property = column['property'];
|
||||
return row[property] === value;
|
||||
},
|
||||
resetFilters() {
|
||||
this.queryFilterText = "";
|
||||
this.queryFilterField = "all";
|
||||
this.$refs.resultTable.clearFilter();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#search .el-select .el-input {
|
||||
#search .el-select .el-input {
|
||||
width: 110px;
|
||||
}
|
||||
.input-with-select .el-input-group__prepend {
|
||||
}
|
||||
|
||||
.input-with-select .el-input-group__prepend {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,173 +1,163 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-tabs tab-position="left" v-model="leftTab">
|
||||
<el-tab-pane
|
||||
name="code"
|
||||
:label="locale[$i18n.locale]['code']"
|
||||
class="layout-row layout-row-column overflow-hidden"
|
||||
v-if="viewMode === 'agent'"
|
||||
>
|
||||
<div>
|
||||
<div id="container" class="conteiner editor"></div>
|
||||
<p class="conteiner layout-margin-s">
|
||||
<el-button type="primary" @click="execCode"
|
||||
>{{ locale[$i18n.locale]['buttonExec'] }}</el-button>
|
||||
<el-button @click="saveSnippet"
|
||||
>{{ locale[$i18n.locale]['buttonSave'] }}</el-button>
|
||||
<el-button @click="loadSnippet"
|
||||
>{{ locale[$i18n.locale]['buttonLoad'] }}</el-button>
|
||||
<p class="conteiner layout-margin-m">
|
||||
<el-button type="primary" @click="execCode"
|
||||
>{{ locale[$i18n.locale]['buttonExec'] }}
|
||||
</el-button>
|
||||
<el-button @click="saveSnippet"
|
||||
>{{ locale[$i18n.locale]['buttonSave'] }}
|
||||
</el-button>
|
||||
<el-button @click="loadSnippet"
|
||||
>{{ locale[$i18n.locale]['buttonLoad'] }}
|
||||
</el-button>
|
||||
</p>
|
||||
<div class="conteiner layout-row layout-row-column overflow-hidden">
|
||||
<el-tabs
|
||||
v-model="bottomTab"
|
||||
class="layout-fill layout-row layout-row-column"
|
||||
>
|
||||
<el-tab-pane :label="locale[$i18n.locale]['output']" name="output">
|
||||
<div class="layout-fill layout-row layout-row-column layout-margin-bottom-s">
|
||||
<pre style="min-height: 30px">{{ response_out }}</pre>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="locale[$i18n.locale]['errors']" name="errors">
|
||||
<div class="layout-fill layout-row layout-row-column layout-margin-bottom-s">
|
||||
<pre style="min-height: 30px">{{ response_err }}</pre>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<div class="conteiner layout-column overflow-hidden">
|
||||
<el-tabs
|
||||
v-model="bottomTab"
|
||||
class="layout-fill layout-column"
|
||||
>
|
||||
<el-tab-pane :label="locale[$i18n.locale]['output']" name="output">
|
||||
<div class="layout-fill layout-column layout-margin-bottom-m">
|
||||
<pre style="min-height: 30px">{{ response_out }}</pre>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="locale[$i18n.locale]['errors']" name="errors">
|
||||
<div class="layout-fill layout-column layout-margin-bottom-m">
|
||||
<pre style="min-height: 30px">{{ response_err }}</pre>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const name = "lua_interpreter";
|
||||
|
||||
module.exports = {
|
||||
name,
|
||||
props: ["protoAPI", "hash", "module", "eventsAPI", "modulesAPI", "components", "viewMode"],
|
||||
data: () => ({
|
||||
name,
|
||||
leftTab: undefined,
|
||||
bottomTab: "output",
|
||||
connection: {},
|
||||
response_out: "",
|
||||
response_err: "",
|
||||
editor: null,
|
||||
locale: {
|
||||
ru: {
|
||||
code: "Редактор кода",
|
||||
buttonExec: "Выполнить",
|
||||
buttonSave: "Сохранить",
|
||||
buttonLoad: "Загрузить",
|
||||
output: "Результат",
|
||||
errors: "Ошибки",
|
||||
connected: "— подключение к серверу установлено",
|
||||
recvError: "Не удалось выполнить операцию"
|
||||
},
|
||||
en: {
|
||||
code: "Code editor",
|
||||
buttonExec: "Execute",
|
||||
buttonSave: "Save",
|
||||
buttonLoad: "Load",
|
||||
output: "Output",
|
||||
errors: "Errors",
|
||||
connected: "— connection to the server established",
|
||||
recvError: "Unable to perform the operation"
|
||||
}
|
||||
}
|
||||
}),
|
||||
created() {
|
||||
if (this.viewMode === 'agent') {
|
||||
this.protoAPI.connect().then(
|
||||
connection => {
|
||||
const date = new Date().toLocaleTimeString();
|
||||
this.connection = connection;
|
||||
this.connection.subscribe(this.recvData, "data");
|
||||
this.$root.NotificationsService.success(`${date} ${this.locale[this.$i18n.locale]['connected']}`);
|
||||
},
|
||||
error => console.log(error)
|
||||
);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.leftTab = this.viewMode === 'agent' ? 'code' : 'events';
|
||||
if (this.viewMode === 'agent') {
|
||||
this.$nextTick(() => {
|
||||
this.initEditor();
|
||||
});
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
recvData(msg) {
|
||||
let data = new TextDecoder("utf-8").decode(msg.content.data);
|
||||
let decoded_response = JSON.parse(data);
|
||||
if (decoded_response.output) {
|
||||
this.response_out = decoded_response.output;
|
||||
this.bottomTab = "output";
|
||||
}
|
||||
if (decoded_response.err) {
|
||||
this.response_err = decoded_response.err;
|
||||
this.bottomTab = "errors";
|
||||
this.$root.NotificationsService.error(this.locale[this.$i18n.locale]['recvError']);
|
||||
}
|
||||
props: ["protoAPI", "hash", "module", "api", "components", "viewMode"],
|
||||
data: () => ({
|
||||
name,
|
||||
bottomTab: "output",
|
||||
connection: {},
|
||||
response_out: "",
|
||||
response_err: "",
|
||||
editor: null,
|
||||
locale: {
|
||||
ru: {
|
||||
buttonExec: "Выполнить",
|
||||
buttonSave: "Сохранить",
|
||||
buttonLoad: "Загрузить",
|
||||
output: "Результат",
|
||||
errors: "Ошибки",
|
||||
connected: "— подключение к серверу установлено",
|
||||
recvError: "Не удалось выполнить операцию"
|
||||
},
|
||||
en: {
|
||||
buttonExec: "Execute",
|
||||
buttonSave: "Save",
|
||||
buttonLoad: "Load",
|
||||
output: "Output",
|
||||
errors: "Errors",
|
||||
connected: "— connection to the server established",
|
||||
recvError: "Unable to perform the operation"
|
||||
}
|
||||
}
|
||||
}),
|
||||
created() {
|
||||
if (this.viewMode === 'agent') {
|
||||
this.protoAPI.connect().then(
|
||||
connection => {
|
||||
const date = new Date().toLocaleTimeString();
|
||||
this.connection = connection;
|
||||
this.connection.subscribe(this.recvData, "data");
|
||||
this.$root.NotificationsService.success(`${date} ${this.locale[this.$i18n.locale]['connected']}`);
|
||||
},
|
||||
error => console.log(error)
|
||||
);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.viewMode === 'agent') {
|
||||
this.$nextTick(() => {
|
||||
this.initEditor();
|
||||
});
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
recvData(msg) {
|
||||
let data = new TextDecoder("utf-8").decode(msg.content.data);
|
||||
let decoded_response = JSON.parse(data);
|
||||
if (decoded_response.output) {
|
||||
this.response_out = decoded_response.output;
|
||||
this.bottomTab = "output";
|
||||
}
|
||||
if (decoded_response.err) {
|
||||
this.response_err = decoded_response.err;
|
||||
this.bottomTab = "errors";
|
||||
this.$root.NotificationsService.error(this.locale[this.$i18n.locale]['recvError']);
|
||||
}
|
||||
|
||||
if (decoded_response.status) {
|
||||
} else {
|
||||
if (decoded_response.ret) {
|
||||
this.response_err += decoded_response.ret;
|
||||
if (decoded_response.status) {
|
||||
} else {
|
||||
if (decoded_response.ret) {
|
||||
this.response_err += decoded_response.ret;
|
||||
}
|
||||
}
|
||||
},
|
||||
execCode() {
|
||||
this.response_out = "";
|
||||
this.response_err = "";
|
||||
const model = this.editor.getModel();
|
||||
const value = model.getValue();
|
||||
let safe_value = value.replace("\r", "\r");
|
||||
safe_value = safe_value.replace("\n", "\n");
|
||||
let data = JSON.stringify({type: "exec", code: safe_value});
|
||||
this.connection.sendData(data);
|
||||
},
|
||||
saveSnippet() {
|
||||
const model = this.editor.getModel();
|
||||
const value = model.getValue();
|
||||
localStorage.setItem("lastState", value);
|
||||
},
|
||||
loadSnippet() {
|
||||
const model = this.editor.getModel();
|
||||
if (localStorage.getItem("lastState")) {
|
||||
model.setValue(localStorage.getItem("lastState"));
|
||||
}
|
||||
},
|
||||
initEditor() {
|
||||
if (!this.editor) {
|
||||
let code = 'print("Hello world!")';
|
||||
if (localStorage.getItem("lastState")) {
|
||||
code = localStorage.getItem("lastState");
|
||||
}
|
||||
const cntr = document.getElementById("container");
|
||||
this.editor = this.components.monaco.editor.create(cntr, {
|
||||
value: code,
|
||||
language: "lua"
|
||||
});
|
||||
const KM = this.components.monaco.KeyMod;
|
||||
const KC = this.components.monaco.KeyCode;
|
||||
this.editor.addCommand(KM.CtrlCmd | KC.Enter, this.execCode);
|
||||
this.editor.addCommand(KM.CtrlCmd | KC.KEY_S, this.saveSnippet);
|
||||
this.editor.addCommand(KM.CtrlCmd | KC.KEY_O, this.loadSnippet);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
execCode() {
|
||||
this.response_out = "";
|
||||
this.response_err = "";
|
||||
const model = this.editor.getModel();
|
||||
const value = model.getValue();
|
||||
let safe_value = value.replace("\r", "\r");
|
||||
safe_value = safe_value.replace("\n", "\n");
|
||||
let data = JSON.stringify({ type: "exec", code: safe_value });
|
||||
this.connection.sendData(data);
|
||||
},
|
||||
saveSnippet() {
|
||||
const model = this.editor.getModel();
|
||||
const value = model.getValue();
|
||||
localStorage.setItem("lastState", value);
|
||||
},
|
||||
loadSnippet() {
|
||||
const model = this.editor.getModel();
|
||||
if (localStorage.getItem("lastState")) {
|
||||
model.setValue(localStorage.getItem("lastState"));
|
||||
}
|
||||
},
|
||||
initEditor() {
|
||||
if (!this.editor) {
|
||||
let code = 'print("Hello world!")';
|
||||
if (localStorage.getItem("lastState")) {
|
||||
code = localStorage.getItem("lastState");
|
||||
}
|
||||
const cntr = document.getElementById("container");
|
||||
this.editor = this.components.monaco.editor.create(cntr, {
|
||||
value: code,
|
||||
language: "lua"
|
||||
});
|
||||
const KM = this.components.monaco.KeyMod;
|
||||
const KC = this.components.monaco.KeyCode;
|
||||
this.editor.addCommand(KM.CtrlCmd | KC.Enter, this.execCode);
|
||||
this.editor.addCommand(KM.CtrlCmd | KC.KEY_S, this.saveSnippet);
|
||||
this.editor.addCommand(KM.CtrlCmd | KC.KEY_O, this.loadSnippet);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.editor {
|
||||
.editor {
|
||||
height: 415px;
|
||||
}
|
||||
}
|
||||
|
||||
.conteiner {
|
||||
.conteiner {
|
||||
min-width: 650px;
|
||||
max-width: 1200px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,163 +1,147 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-tabs tab-position="left" v-model="leftTab">
|
||||
<el-tab-pane
|
||||
name="api"
|
||||
:label="locale[$i18n.locale]['api']"
|
||||
class="layout-fill overflow-hidden"
|
||||
v-if="viewMode === 'agent'"
|
||||
>
|
||||
<div id="exec_actions" class="layout-margin-xl limit-length">
|
||||
<el-select v-model="actionName" slot="prepend" :placeholder="locale[$i18n.locale]['actionSelectPl']">
|
||||
<el-option v-for="(id, idx) in module.info.actions"
|
||||
:label="module.locale.actions[id][$i18n.locale].title"
|
||||
:value="id"
|
||||
:key="idx"
|
||||
></el-option>
|
||||
</el-select>
|
||||
<div v-if="actionName">
|
||||
<div id="inp_actions"
|
||||
v-for="(id, idx) in module.current_action_config[actionName].fields"
|
||||
:key="idx">
|
||||
<el-input
|
||||
:placeholder="module.locale.fields[id][$i18n.locale].description"
|
||||
v-model="actionDataModel[id]">
|
||||
</el-input>
|
||||
<div>
|
||||
<div id="exec_actions" class="layout-margin-bottom-xl">
|
||||
<el-select v-model="actionName" slot="prepend" :placeholder="locale[$i18n.locale]['actionSelectPl']">
|
||||
<el-option v-for="(id, idx) in module.info.actions"
|
||||
:label="module.locale.actions[id][$i18n.locale].title"
|
||||
:value="id"
|
||||
:key="idx"
|
||||
></el-option>
|
||||
</el-select>
|
||||
<div v-if="actionName">
|
||||
<div id="inp_actions"
|
||||
v-for="(id, idx) in module.current_action_config[actionName].fields"
|
||||
:key="idx">
|
||||
<el-input
|
||||
:placeholder="module.locale.fields[id][$i18n.locale].description"
|
||||
v-model="actionDataModel[id]">
|
||||
</el-input>
|
||||
</div>
|
||||
<el-button @click="submitReqToExecAction" slot="append"
|
||||
>{{ locale[$i18n.locale]["buttonExecAction"] }}
|
||||
</el-button>
|
||||
</div>
|
||||
<el-button @click="submitReqToExecAction" slot="append"
|
||||
>{{ locale[$i18n.locale]["buttonExecAction"] }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-fill layout-row layout-row-column layout-row-between scrollable">
|
||||
<ul>
|
||||
<li :key="line" v-for="line in lines">{{ line }}</li>
|
||||
</ul>
|
||||
<div class="layout-column layout-align-space-between scrollable">
|
||||
<ul>
|
||||
<li :key="line" v-for="line in lines">{{ line }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const name = "responder";
|
||||
|
||||
module.exports = {
|
||||
name,
|
||||
props: ["protoAPI", "hash", "module", "eventsAPI", "modulesAPI", "components", "viewMode"],
|
||||
data: () => ({
|
||||
leftTab: undefined,
|
||||
connection: {},
|
||||
lines: [],
|
||||
actionName: undefined,
|
||||
actionDataModel: {},
|
||||
locale: {
|
||||
ru: {
|
||||
api: "Завершение процессов",
|
||||
buttonExecAction: "Выполнить действие",
|
||||
connected: "— подключение к серверу установлено",
|
||||
connError: "Не удалось подключиться к серверу",
|
||||
recvError: "Не удалось выполнить операцию",
|
||||
checkError: "Данные введены некорректно",
|
||||
actionError: "Выберите действие из списка",
|
||||
actionSelectPl: "Выбрать действие"
|
||||
},
|
||||
en: {
|
||||
api: "Process terminator",
|
||||
buttonExecAction: "Exec action",
|
||||
connected: "— connection to the server established",
|
||||
connError: "Failed to connect to the server",
|
||||
recvError: "Unable to perform the operation",
|
||||
checkError: "Data entered incorrectly",
|
||||
actionError: "Please choose action from list",
|
||||
actionSelectPl: "Select action"
|
||||
}
|
||||
}
|
||||
}),
|
||||
created() {
|
||||
if (this.viewMode === 'agent') {
|
||||
this.protoAPI.connect().then(
|
||||
connection => {
|
||||
const date = new Date().toLocaleTimeString();
|
||||
this.connection = connection;
|
||||
this.connection.subscribe(this.recvData, "data");
|
||||
this.$root.NotificationsService.success(`${date} ${this.locale[this.$i18n.locale]['connected']}`);
|
||||
},
|
||||
error => {
|
||||
this.$root.NotificationsService.error(this.locale[this.$i18n.locale]['connError']);
|
||||
console.log(error);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.leftTab = this.viewMode === 'agent' ? 'api' : undefined;
|
||||
},
|
||||
methods: {
|
||||
recvData(msg) {
|
||||
const date = new Date();
|
||||
const date_ms = date.toLocaleTimeString() + `.${date.getMilliseconds()}`;
|
||||
this.lines.push(
|
||||
`${date_ms} RECV DATA: ${new TextDecoder(
|
||||
"utf-8"
|
||||
).decode(msg.content.data)}`
|
||||
);
|
||||
},
|
||||
submitReqToExecAction() {
|
||||
const date = new Date();
|
||||
const date_ms = date.toLocaleTimeString() + `.${date.getMilliseconds()}`;
|
||||
if (!this.actionName) {
|
||||
this.$root.NotificationsService.error(this.locale[this.$i18n.locale]["actionError"]);
|
||||
return;
|
||||
}
|
||||
const defActCfg = this.module.default_action_config[this.actionName]
|
||||
if (typeof(defActCfg) !== "object" || !Array.isArray(defActCfg.fields) || defActCfg.fields.length === 0) {
|
||||
this.$root.NotificationsService.error(this.locale[this.$i18n.locale]["checkError"]);
|
||||
return;
|
||||
}
|
||||
let actionData = {};
|
||||
try {
|
||||
for (let fieldID in this.module.default_action_config[this.actionName].fields) {
|
||||
const fieldName = this.module.default_action_config[this.actionName].fields[fieldID];
|
||||
switch (this.module.fields_schema.properties[fieldName]["type"]) {
|
||||
case "number":
|
||||
actionData[fieldName] = parseInt(this.actionDataModel[fieldName], 10);
|
||||
break;
|
||||
case "string":
|
||||
actionData[fieldName] = this.actionDataModel[fieldName].toString();
|
||||
break;
|
||||
case "array":
|
||||
case "object":
|
||||
actionData[fieldName] = JSON.parse(this.actionDataModel[fieldName].toString());
|
||||
break;
|
||||
}
|
||||
if (!actionData[fieldName]) {
|
||||
throw "empty field value";
|
||||
}
|
||||
name,
|
||||
props: ["protoAPI", "hash", "module", "api", "components", "viewMode"],
|
||||
data: () => ({
|
||||
connection: {},
|
||||
lines: [],
|
||||
actionName: undefined,
|
||||
actionDataModel: {},
|
||||
locale: {
|
||||
ru: {
|
||||
buttonExecAction: "Выполнить действие",
|
||||
connected: "— подключение к серверу установлено",
|
||||
connError: "Не удалось подключиться к серверу",
|
||||
recvError: "Не удалось выполнить операцию",
|
||||
checkError: "Данные введены некорректно",
|
||||
actionError: "Выберите действие из списка",
|
||||
actionSelectPl: "Выбрать действие"
|
||||
},
|
||||
en: {
|
||||
buttonExecAction: "Exec action",
|
||||
connected: "— connection to the server established",
|
||||
connError: "Failed to connect to the server",
|
||||
recvError: "Unable to perform the operation",
|
||||
checkError: "Data entered incorrectly",
|
||||
actionError: "Please choose action from list",
|
||||
actionSelectPl: "Select action"
|
||||
}
|
||||
}
|
||||
}),
|
||||
created() {
|
||||
if (this.viewMode === 'agent') {
|
||||
this.protoAPI.connect().then(
|
||||
connection => {
|
||||
const date = new Date().toLocaleTimeString();
|
||||
this.connection = connection;
|
||||
this.connection.subscribe(this.recvData, "data");
|
||||
this.$root.NotificationsService.success(`${date} ${this.locale[this.$i18n.locale]['connected']}`);
|
||||
},
|
||||
error => {
|
||||
this.$root.NotificationsService.error(this.locale[this.$i18n.locale]['connError']);
|
||||
console.log(error);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
recvData(msg) {
|
||||
const date = new Date();
|
||||
const date_ms = date.toLocaleTimeString() + `.${date.getMilliseconds()}`;
|
||||
this.lines.push(
|
||||
`${date_ms} RECV DATA: ${new TextDecoder(
|
||||
"utf-8"
|
||||
).decode(msg.content.data)}`
|
||||
);
|
||||
},
|
||||
submitReqToExecAction() {
|
||||
const date = new Date();
|
||||
const date_ms = date.toLocaleTimeString() + `.${date.getMilliseconds()}`;
|
||||
if (!this.actionName) {
|
||||
this.$root.NotificationsService.error(this.locale[this.$i18n.locale]["actionError"]);
|
||||
return;
|
||||
}
|
||||
const defActCfg = this.module.default_action_config[this.actionName]
|
||||
if (typeof (defActCfg) !== "object" || !Array.isArray(defActCfg.fields) || defActCfg.fields.length === 0) {
|
||||
this.$root.NotificationsService.error(this.locale[this.$i18n.locale]["checkError"]);
|
||||
return;
|
||||
}
|
||||
let actionData = {};
|
||||
try {
|
||||
for (let fieldID in this.module.default_action_config[this.actionName].fields) {
|
||||
const fieldName = this.module.default_action_config[this.actionName].fields[fieldID];
|
||||
switch (this.module.fields_schema.properties[fieldName]["type"]) {
|
||||
case "number":
|
||||
actionData[fieldName] = parseInt(this.actionDataModel[fieldName], 10);
|
||||
break;
|
||||
case "string":
|
||||
actionData[fieldName] = this.actionDataModel[fieldName].toString();
|
||||
break;
|
||||
case "array":
|
||||
case "object":
|
||||
actionData[fieldName] = JSON.parse(this.actionDataModel[fieldName].toString());
|
||||
break;
|
||||
}
|
||||
if (!actionData[fieldName]) {
|
||||
throw "empty field value";
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
this.$root.NotificationsService.error(this.locale[this.$i18n.locale]["checkError"]);
|
||||
return;
|
||||
}
|
||||
let data = JSON.stringify({
|
||||
data: actionData,
|
||||
actions: [`${this.module.info.name}.${this.actionName}`]
|
||||
});
|
||||
this.lines.push(
|
||||
`${date_ms} SEND ACTION: ${data}`
|
||||
);
|
||||
this.connection.sendAction(data, this.actionName);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
this.$root.NotificationsService.error(this.locale[this.$i18n.locale]["checkError"]);
|
||||
return;
|
||||
}
|
||||
let data = JSON.stringify({
|
||||
data: actionData,
|
||||
actions: [`${this.module.info.name}.${this.actionName}`]
|
||||
});
|
||||
this.lines.push(
|
||||
`${date_ms} SEND ACTION: ${data}`
|
||||
);
|
||||
this.connection.sendAction(data, this.actionName);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#exec_actions .el-select, #inp_actions .el-input {
|
||||
#exec_actions .el-select, #inp_actions .el-input {
|
||||
max-width: 800px;
|
||||
min-width: 400px;
|
||||
width: 100%;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
return {
|
||||
pt_kill_object_process_by_file_path = "pt_kill_object_process_by_file_path",
|
||||
pt_kill_object_process_by_image = "pt_kill_object_process_by_image",
|
||||
pt_kill_object_process_by_name = "pt_kill_object_process_by_name",
|
||||
pt_kill_object_process_by_name_and_id = "pt_kill_object_process_by_name_and_id",
|
||||
pt_kill_object_process_by_image_and_id = "pt_kill_object_process_by_image_and_id",
|
||||
pt_kill_object_process_tree_by_file_path = "pt_kill_object_process_tree_by_file_path",
|
||||
pt_kill_object_process_tree_by_image = "pt_kill_object_process_tree_by_image",
|
||||
pt_kill_object_process_tree_by_name = "pt_kill_object_process_tree_by_name",
|
||||
pt_kill_object_process_tree_by_name_and_id = "pt_kill_object_process_tree_by_name_and_id",
|
||||
pt_kill_object_process_tree_by_image_and_id = "pt_kill_object_process_tree_by_image_and_id",
|
||||
pt_kill_subject_process_by_image = "pt_kill_subject_process_by_image",
|
||||
pt_kill_subject_process_by_name = "pt_kill_subject_process_by_name",
|
||||
pt_kill_subject_process_by_name_and_id = "pt_kill_subject_process_by_name_and_id",
|
||||
pt_kill_subject_process_by_image_and_id = "pt_kill_subject_process_by_image_and_id",
|
||||
pt_kill_subject_process_tree_by_image = "pt_kill_subject_process_tree_by_image",
|
||||
pt_kill_subject_process_tree_by_name = "pt_kill_subject_process_tree_by_name",
|
||||
pt_kill_subject_process_tree_by_name_and_id = "pt_kill_subject_process_tree_by_name_and_id",
|
||||
pt_kill_subject_process_tree_by_image_and_id = "pt_kill_subject_process_tree_by_image_and_id",
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
require("engine")
|
||||
local bit = require("bit")
|
||||
local ffi = require("ffi")
|
||||
local lfs = require("lfs")
|
||||
local glue = require("glue")
|
||||
local cjson = require("cjson.safe")
|
||||
local luapath = require("path")
|
||||
local process_api = require("process_api")
|
||||
local lk32
|
||||
if ffi.os == "Windows" then
|
||||
lk32 = require("waffi.windows.kernel32")
|
||||
lk32.STILL_ALIVE = 259
|
||||
else
|
||||
ffi.cdef[[
|
||||
typedef uint32_t pid_t;
|
||||
@@ -93,7 +93,20 @@ local function push_event(event_name, action_name, action_data)
|
||||
end
|
||||
|
||||
local function update_agent_info()
|
||||
agent_id, agent_path = dyn_handlers.update_agent_info()
|
||||
agent_id, agent_path = process_api.update_agent_info()
|
||||
end
|
||||
|
||||
local function collect_process_info(object_type)
|
||||
local process_list = {}
|
||||
process_api.for_each_process(function(proc_info)
|
||||
table.insert(process_list, {
|
||||
[object_type .. ".process.id"] = proc_info.pid,
|
||||
[object_type .. ".process.name"] = proc_info.name,
|
||||
[object_type .. ".process.fullpath"] = proc_info.path,
|
||||
[object_type .. ".process.parent.id"] = proc_info.parent_pid,
|
||||
})
|
||||
end)
|
||||
return process_list
|
||||
end
|
||||
|
||||
local function get_process_tree(check_ppid, object_type, full_process_info, depth)
|
||||
@@ -104,7 +117,7 @@ local function get_process_tree(check_ppid, object_type, full_process_info, dept
|
||||
return child_list
|
||||
end
|
||||
if full_process_info == nil then
|
||||
full_process_info = dyn_handlers.collect_process_info(object_type)
|
||||
full_process_info = collect_process_info(object_type)
|
||||
end
|
||||
|
||||
for _, proc_info in ipairs(full_process_info) do
|
||||
@@ -182,7 +195,7 @@ local function kill_proc_children(action_name, object_type, proc_id)
|
||||
child_action_data.data = {
|
||||
[object_type .. ".process.name"] = ch_proc_name,
|
||||
[object_type .. ".process.id"] = ch_proc_id,
|
||||
[object_type .. ".process.fullpath"] = dyn_handlers.get_process_path(ch_proc_id)
|
||||
[object_type .. ".process.fullpath"] = process_api.get_process_path(ch_proc_id)
|
||||
}
|
||||
__log.info("Killing -> " .. ch_proc_id)
|
||||
dyn_handlers.kill_process_by_name_and_id(action_name, child_action_data, object_type, false, true)
|
||||
@@ -213,51 +226,35 @@ local function check_action_structure(action_name, action_data)
|
||||
action_data.data["object.process.id"] = tonumber(action_data.data["object.process.id"])
|
||||
action_data.data["subject.process.id"] = tonumber(action_data.data["subject.process.id"])
|
||||
|
||||
local actions = {
|
||||
pt_kill_object_process_by_file_path = {{"object.fullpath", "string"}},
|
||||
pt_kill_object_process_by_image = {{"object.process.fullpath", "string"}},
|
||||
pt_kill_object_process_by_name = {{"object.process.name", "string"}},
|
||||
pt_kill_object_process_by_name_and_id = {{"object.process.name", "string"}, {"object.process.id", "number"}},
|
||||
pt_kill_object_process_by_image_and_id = {{"object.process.fullpath", "string"}, {"object.process.id", "number"}},
|
||||
pt_kill_object_process_tree_by_file_path = {{"object.fullpath", "string"}},
|
||||
pt_kill_object_process_tree_by_image = {{"object.process.fullpath", "string"}},
|
||||
pt_kill_object_process_tree_by_name = {{"object.process.name", "string"}},
|
||||
pt_kill_object_process_tree_by_name_and_id = {{"object.process.name", "string"}, {"object.process.id", "number"}},
|
||||
pt_kill_object_process_tree_by_image_and_id = {{"object.process.fullpath", "string"}, {"object.process.id", "number"}},
|
||||
pt_kill_subject_process_by_image = {{"subject.process.fullpath", "string"}},
|
||||
pt_kill_subject_process_by_name = {{"subject.process.name", "string"}},
|
||||
pt_kill_subject_process_by_name_and_id = {{"subject.process.name", "string"}, {"subject.process.id", "number"}},
|
||||
pt_kill_subject_process_by_image_and_id = {{"subject.process.fullpath", "string"}, {"subject.process.id", "number"}},
|
||||
pt_kill_subject_process_tree_by_image = {{"subject.process.fullpath", "string"}},
|
||||
pt_kill_subject_process_tree_by_name = {{"subject.process.name", "string"}},
|
||||
pt_kill_subject_process_tree_by_name_and_id = {{"subject.process.name", "string"}, {"subject.process.id", "number"}},
|
||||
pt_kill_subject_process_tree_by_image_and_id = {{"subject.process.fullpath", "string"}, {"subject.process.id", "number"}}
|
||||
}
|
||||
|
||||
-- check action data structure
|
||||
return (action_name == "pt_kill_object_process_by_file_path" and
|
||||
type(action_data.data["object.fullpath"]) == "string") or
|
||||
(action_name == "pt_kill_object_process_by_image" and
|
||||
type(action_data.data["object.process.fullpath"]) == "string") or
|
||||
(action_name == "pt_kill_object_process_by_name" and
|
||||
type(action_data.data["object.process.name"]) == "string") or
|
||||
(action_name == "pt_kill_object_process_by_name_and_id" and
|
||||
type(action_data.data["object.process.name"]) == "string" and
|
||||
type(action_data.data["object.process.id"]) == "number") or
|
||||
(action_name == "pt_kill_object_process_by_image_and_id" and
|
||||
type(action_data.data["object.process.fullpath"]) == "string" and
|
||||
type(action_data.data["object.process.id"]) == "number") or
|
||||
(action_name == "pt_kill_object_process_tree_by_file_path" and
|
||||
type(action_data.data["object.fullpath"]) == "string") or
|
||||
(action_name == "pt_kill_object_process_tree_by_image" and
|
||||
type(action_data.data["object.process.fullpath"]) == "string") or
|
||||
(action_name == "pt_kill_object_process_tree_by_name" and
|
||||
type(action_data.data["object.process.name"]) == "string") or
|
||||
(action_name == "pt_kill_object_process_tree_by_name_and_id" and
|
||||
type(action_data.data["object.process.name"]) == "string" and
|
||||
type(action_data.data["object.process.id"]) == "number") or
|
||||
(action_name == "pt_kill_object_process_tree_by_image_and_id" and
|
||||
type(action_data.data["object.process.fullpath"]) == "string" and
|
||||
type(action_data.data["object.process.id"]) == "number") or
|
||||
(action_name == "pt_kill_subject_process_by_image" and
|
||||
type(action_data.data["subject.process.fullpath"]) == "string") or
|
||||
(action_name == "pt_kill_subject_process_by_name" and
|
||||
type(action_data.data["subject.process.name"]) == "string") or
|
||||
(action_name == "pt_kill_subject_process_by_name_and_id" and
|
||||
type(action_data.data["subject.process.name"]) == "string" and
|
||||
type(action_data.data["subject.process.id"]) == "number") or
|
||||
(action_name == "pt_kill_subject_process_by_image_and_id" and
|
||||
type(action_data.data["subject.process.fullpath"]) == "string" and
|
||||
type(action_data.data["subject.process.id"]) == "number") or
|
||||
(action_name == "pt_kill_subject_process_tree_by_image" and
|
||||
type(action_data.data["subject.process.fullpath"]) == "string") or
|
||||
(action_name == "pt_kill_subject_process_tree_by_name" and
|
||||
type(action_data.data["subject.process.name"]) == "string") or
|
||||
(action_name == "pt_kill_subject_process_tree_by_name_and_id" and
|
||||
type(action_data.data["subject.process.name"]) == "string" and
|
||||
type(action_data.data["subject.process.id"]) == "number") or
|
||||
(action_name == "pt_kill_subject_process_tree_by_image_and_id" and
|
||||
type(action_data.data["subject.process.fullpath"]) == "string" and
|
||||
type(action_data.data["subject.process.id"]) == "number")
|
||||
for _, value in ipairs(actions[action_name]) do
|
||||
local data_name, data_type = unpack(value)
|
||||
if type(action_data.data[data_name]) ~= data_type then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function exec_action(action_name, action_data)
|
||||
@@ -328,25 +325,24 @@ end
|
||||
|
||||
if ffi.os == "Windows" then
|
||||
|
||||
--[[ Windows handlers ]]
|
||||
|
||||
function handlers.windows.kill_proc_common(action_name, action_data, object_type, proc_handle)
|
||||
local exitCode = ffi.new("DWORD[1]", 0)
|
||||
if lk32.TerminateProcess(proc_handle, 0) == 1 then
|
||||
if lk32.TerminateProcess(proc_handle, 0) ~= 0 then
|
||||
lk32.WaitForSingleObject(proc_handle, wait_kill_timeout)
|
||||
action_data.data.result = true
|
||||
push_event("pt_" .. object_type .. "_process_killed_successful", action_name, action_data)
|
||||
return action_data.data
|
||||
-- we can fail if the process is already terminating, so check for it
|
||||
else
|
||||
-- https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getexitcodeprocess
|
||||
if lk32.GetExitCodeProcess(proc_handle, exitCode) == 1 then
|
||||
__log.debugf("exit code from requested kill process: %d", tonumber(exitCode[0]))
|
||||
-- 259 - STILL_ALIVE
|
||||
if tonumber(exitCode[0]) ~= 259 then
|
||||
action_data.data.result = true
|
||||
action_data.data.reason = "already terminating"
|
||||
push_event("pt_" .. object_type .. "_process_killed_successful", action_name, action_data)
|
||||
return action_data.data
|
||||
end
|
||||
elseif lk32.GetExitCodeProcess(proc_handle, exitCode) ~= 0 then
|
||||
__log.debugf("exit code from requested kill process: %d", tonumber(exitCode[0]))
|
||||
|
||||
if tonumber(exitCode[0]) ~= lk32.STILL_ALIVE then
|
||||
action_data.data.result = true
|
||||
action_data.data.reason = "already terminating"
|
||||
push_event("pt_" .. object_type .. "_process_killed_successful", action_name, action_data)
|
||||
return action_data.data
|
||||
end
|
||||
end
|
||||
|
||||
@@ -362,64 +358,57 @@ if ffi.os == "Windows" then
|
||||
name = name:lower()
|
||||
__log.debug("kill_process_by_name", name, kill_children)
|
||||
|
||||
local full_process_info = dyn_handlers.collect_process_info(object_type)
|
||||
-- expect that we do not fail this one
|
||||
-- check proc name to ensure we really need to open process
|
||||
local s_proc_name = luapath.file(name)
|
||||
s_proc_name = s_proc_name:lower()
|
||||
|
||||
local proc_found = false
|
||||
local action_data_bak = glue.update({}, action_data.data)
|
||||
action_data_bak.result = true
|
||||
for i = 1, #full_process_info do
|
||||
local proc_id = full_process_info[i][object_type .. ".process.id"]
|
||||
local proc_name = full_process_info[i][object_type .. ".process.name"]
|
||||
proc_name = proc_name:lower()
|
||||
|
||||
-- check proc name to ensure we really need to open process
|
||||
local s_proc_name = luapath.file(name)
|
||||
s_proc_name = s_proc_name:lower()
|
||||
if s_proc_name ~= proc_name then
|
||||
goto continue
|
||||
process_api.for_each_process(function(proc_info)
|
||||
if (proc_info.name ~= s_proc_name) then
|
||||
return false
|
||||
end
|
||||
|
||||
local proc_path, err = handlers.windows.get_process_path(proc_id)
|
||||
local proc_path_l = proc_path:lower()
|
||||
local proc_path, err = process_api.get_process_path(proc_info.pid)
|
||||
local proc_path_lower = proc_path:lower()
|
||||
if err == nil then
|
||||
if proc_path == "" and glue.indexof(proc_name, system_process_excludes_windows) then
|
||||
if proc_path == "" and glue.indexof(proc_info.name, system_process_excludes_windows) then
|
||||
proc_found = true
|
||||
action_data.data = update_action_data(action_data, object_type, proc_id, proc_path)
|
||||
action_data.data = update_action_data(action_data, object_type, proc_info.pid, proc_path)
|
||||
push_event("pt_" .. object_type .. "_process_skipped", action_name, action_data)
|
||||
goto continue
|
||||
elseif proc_path == "" or (proc_path_l ~= name and luapath.file(proc_path_l) ~= name) then
|
||||
goto continue
|
||||
return false
|
||||
elseif proc_path == "" or (proc_path_lower ~= name and luapath.file(proc_path_lower) ~= name) then
|
||||
return false
|
||||
end
|
||||
else
|
||||
goto continue
|
||||
return false
|
||||
end
|
||||
|
||||
proc_found = true
|
||||
action_data.data = update_action_data(action_data, object_type, proc_id, proc_path)
|
||||
action_data.data = update_action_data(action_data, object_type, proc_info.pid, proc_path)
|
||||
|
||||
if is_whitelisted(proc_path_l, proc_id, false) then
|
||||
if is_whitelisted(proc_path_lower, proc_info.pid, false) then
|
||||
push_event("pt_" .. object_type .. "_process_skipped", action_name, action_data)
|
||||
goto continue
|
||||
return false
|
||||
end
|
||||
|
||||
if kill_children then
|
||||
kill_proc_children(action_name, object_type, proc_id)
|
||||
kill_proc_children(action_name, object_type, proc_info.pid)
|
||||
end
|
||||
local proc_handle
|
||||
proc_handle, action_data.data = handlers.windows.get_termination_handle(action_name, action_data, object_type,
|
||||
proc_id)
|
||||
proc_handle, action_data.data = handlers.windows.get_termination_handle(
|
||||
action_name, action_data, object_type, proc_info.pid)
|
||||
if proc_handle == nil then
|
||||
action_data_bak.result = false
|
||||
goto continue
|
||||
return false
|
||||
end
|
||||
|
||||
action_data.data = handlers.windows.kill_proc_common(action_name, action_data, object_type, proc_handle)
|
||||
action_data_bak.result = action_data.data.result
|
||||
|
||||
lk32.CloseHandle(proc_handle)
|
||||
::continue::
|
||||
end
|
||||
end)
|
||||
|
||||
action_data.data = action_data_bak
|
||||
action_data.data.reason = not action_data.data.result and "failed_to_kill_a_part_of_processes" or nil
|
||||
@@ -452,7 +441,7 @@ if ffi.os == "Windows" then
|
||||
__log.debug("kill_process_by_name_and_id", dproc_name, dproc_id, kill_children, ignore_whitelist)
|
||||
|
||||
local proc_handle
|
||||
local proc_path, err = handlers.windows.get_process_path(dproc_id)
|
||||
local proc_path, err = process_api.get_process_path(dproc_id)
|
||||
proc_path = proc_path or ""
|
||||
local proc_path_l = proc_path:lower()
|
||||
local proc_name_l = luapath.file(proc_path_l)
|
||||
@@ -492,51 +481,8 @@ if ffi.os == "Windows" then
|
||||
return action_data.data.result
|
||||
end
|
||||
|
||||
-- take snap, get required fields from it
|
||||
-- name - *.process.name
|
||||
-- proc_id - *.process.id
|
||||
-- ppid - *.process.parent.id
|
||||
function handlers.windows.collect_process_info(object_type)
|
||||
local full_process_info = {}
|
||||
local proc_entry = ffi.new("PROCESSENTRY32[1]")
|
||||
proc_entry[0].dwSize = ffi.sizeof("PROCESSENTRY32")
|
||||
local snap_handle = lk32.CreateToolhelp32Snapshot(0x00000002, 0)
|
||||
|
||||
if (lk32.Process32First(snap_handle, proc_entry[0]) == 1) then
|
||||
while (lk32.Process32Next(snap_handle, proc_entry[0]) == 1) do
|
||||
table.insert(full_process_info, {
|
||||
[object_type .. ".process.id"] = tonumber(proc_entry[0].th32ProcessID),
|
||||
[object_type .. ".process.name"] = ffi.string(proc_entry[0].szExeFile),
|
||||
[object_type .. ".process.parent.id"] = tonumber(proc_entry[0].th32ParentProcessID)
|
||||
})
|
||||
end
|
||||
else
|
||||
__log.error("failed to get info from snapshot")
|
||||
end
|
||||
if snap_handle ~= ffi.NULL then
|
||||
lk32.CloseHandle(snap_handle)
|
||||
end
|
||||
return full_process_info
|
||||
end
|
||||
|
||||
function handlers.windows.get_last_error()
|
||||
local err = lk32.GetLastError()
|
||||
__log.debugf("winapi last err: %d", tonumber(err))
|
||||
return err
|
||||
end
|
||||
|
||||
function handlers.windows.get_process_handle(proc_id)
|
||||
local handle = lk32.OpenProcess(bit.bor(lk32.PROCESS_QUERY_LIMITED_INFORMATION, lk32.PROCESS_TERMINATE,
|
||||
lk32.PROCESS_VM_READ, 0x00100000 -- lk32.SYNCHRONIZE
|
||||
), false, proc_id)
|
||||
if handle == ffi.NULL then
|
||||
return nil, handlers.windows.get_last_error()
|
||||
end
|
||||
return handle, nil
|
||||
end
|
||||
|
||||
function handlers.windows.get_termination_handle(action_name, action_data, object_type, proc_id)
|
||||
local proc_handle, err = handlers.windows.get_process_handle(proc_id)
|
||||
local proc_handle, err = process_api.get_process_handle(proc_id)
|
||||
if proc_handle == nil then
|
||||
-- access denied
|
||||
if err == 5 then
|
||||
@@ -554,34 +500,10 @@ if ffi.os == "Windows" then
|
||||
return proc_handle, action_data.data
|
||||
end
|
||||
|
||||
-- by using less priveleged handle we can get path for any process
|
||||
-- GetModuleFileNameExA didn't work on w7x64
|
||||
function handlers.windows.get_process_path(proc_id)
|
||||
local proc_handle, err = lk32.OpenProcess(lk32.PROCESS_QUERY_LIMITED_INFORMATION, false, proc_id)
|
||||
if proc_handle == nil then
|
||||
return "", err
|
||||
end
|
||||
local max_path = lk32.MAX_PATH
|
||||
local filename = ffi.new("char[?]", max_path)
|
||||
local size = ffi.new("DWORD[1]", 2048)
|
||||
if lk32.QueryFullProcessImageNameA(proc_handle, 0, filename, size) == 1 then
|
||||
lk32.CloseHandle(proc_handle)
|
||||
return ffi.string(filename, size[0]), nil
|
||||
end
|
||||
lk32.CloseHandle(proc_handle)
|
||||
__log.errorf("failed to get process path for proc_id '%d'", proc_id)
|
||||
return "", nil
|
||||
end
|
||||
|
||||
function handlers.windows.update_agent_info()
|
||||
local aid, apath
|
||||
aid = tonumber(lk32.GetCurrentProcessId())
|
||||
apath = handlers.windows.get_process_path(aid):lower()
|
||||
return aid, apath
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
--[[ Linux handlers ]]
|
||||
|
||||
function handlers.linux.kill_proc_common(action_name, action_data, object_type, proc_id)
|
||||
assert(type(proc_id) == "number", "input process id has invalid type")
|
||||
-- If proc_id is positive, then signal sig is sent to the process with
|
||||
@@ -593,35 +515,89 @@ else
|
||||
-- calling process has permission to send signals, except for
|
||||
-- process 1 (init), but see below.
|
||||
|
||||
local err
|
||||
if proc_id <= 0 then
|
||||
action_data.data.result = false
|
||||
action_data.data.reason = "Invalid PID specified"
|
||||
push_event("pt_" .. object_type .. "process_not_found", action_name, action_data)
|
||||
return action_data, nil
|
||||
return action_data
|
||||
end
|
||||
__log.info("call linux.kill_proc_common", action_name, proc_id)
|
||||
if ffi.C.kill(proc_id, 9) == 0 then
|
||||
action_data.data.result = true
|
||||
push_event("pt_" .. object_type .. "_process_killed_successful", action_name, action_data)
|
||||
return action_data.data, nil
|
||||
else
|
||||
-- #define EPERM 1 /* Operation not permitted */
|
||||
-- #define ESRCH 3 /* No such process */
|
||||
err = ffi.errno()
|
||||
if err == 1 then
|
||||
action_data.data.result = false
|
||||
action_data.data.reason = "Access denied"
|
||||
push_event("pt_" .. object_type .. "_process_killed_failed", action_name, action_data)
|
||||
elseif err == 3 then
|
||||
action_data.data.result = false
|
||||
action_data.data.reason = "Process not found"
|
||||
push_event("pt_process_not_found", action_name, action_data)
|
||||
end
|
||||
return action_data.data
|
||||
end
|
||||
|
||||
local EPERM = 1 -- Operation not permitted
|
||||
local ESRCH = 3 -- No such process
|
||||
action_data.data.result = false
|
||||
|
||||
local err = ffi.errno()
|
||||
if err == ESRCH then
|
||||
action_data.data.reason = "Process not found"
|
||||
push_event("pt_process_not_found", action_name, action_data)
|
||||
return action_data.data
|
||||
end
|
||||
|
||||
action_data.data.reason = err == EPERM and "Access denied" or ("errno: %d"):format(err)
|
||||
push_event("pt_" .. object_type .. "_process_killed_failed", action_name, action_data)
|
||||
return action_data.data, err
|
||||
end
|
||||
|
||||
function handlers.linux.kill_process_by_name(action_name, action_data, object_type, name, kill_children, ignore_whitelist)
|
||||
assert(type(name) == "string", "input process name or path has invalid type")
|
||||
assert(type(kill_children) == "boolean", "kill_children flag has invalid type")
|
||||
__log.debug("kill_process_by_name", name, kill_children)
|
||||
|
||||
local proc_found = false
|
||||
local action_data_bak = glue.update({}, action_data.data)
|
||||
action_data_bak.result = true
|
||||
|
||||
process_api.for_each_process(function(proc_info)
|
||||
clear_proc_data(action_data, object_type)
|
||||
|
||||
-- some processes on osx might start with dash
|
||||
-- current way of getting process info does not guarantee getting full process name
|
||||
-- instead it gets argv[0] of running process
|
||||
if ffi.os == "OSX" then
|
||||
if proc_info.path == "" or ( not glue.ends(proc_info.name, name)) then
|
||||
return false
|
||||
end
|
||||
else
|
||||
if proc_info.path == "" or (proc_info.path ~= name and proc_info.name ~= name) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
proc_found = true
|
||||
action_data.data = update_action_data(action_data, object_type, proc_info.pid, proc_info.path)
|
||||
|
||||
if is_whitelisted(proc_info.path, proc_info.pid, ignore_whitelist) then
|
||||
action_data.data.result = true
|
||||
push_event("pt_" .. object_type .. "_process_skipped", action_name, action_data)
|
||||
return false
|
||||
end
|
||||
|
||||
if kill_children then
|
||||
kill_proc_children(action_name, object_type, proc_info.pid)
|
||||
end
|
||||
|
||||
local err
|
||||
action_data.data, err = dyn_handlers.kill_proc_common(action_name, action_data, object_type, proc_info.pid)
|
||||
if err then
|
||||
__log.debugf("process killed -> '%d' with error -> '%s'", proc_info.pid, err)
|
||||
else
|
||||
__log.debugf("process killed -> '%d'", proc_info.pid)
|
||||
end
|
||||
end)
|
||||
|
||||
if not proc_found then
|
||||
action_data.data.result = false
|
||||
action_data.data.reason = "Process not found"
|
||||
push_event("pt_process_not_found", action_name, action_data)
|
||||
end
|
||||
return action_data.data.result
|
||||
end
|
||||
|
||||
function handlers.linux.kill_process_by_name_and_id(action_name, action_data, object_type, kill_children, ignore_whitelist)
|
||||
assert(type(kill_children) == "boolean", "kill_children flag has invalid type")
|
||||
assert(type(ignore_whitelist) == "boolean", "ignore_whitelist flag has invalid type")
|
||||
@@ -640,7 +616,7 @@ else
|
||||
end
|
||||
__log.debug("linux.kill_process_by_name_and_id", dproc_name, dproc_id, kill_children, ignore_whitelist)
|
||||
|
||||
local proc_path, err = dyn_handlers.get_process_path(dproc_id)
|
||||
local proc_path, err = process_api.get_process_path(dproc_id)
|
||||
__log.debugf("proc info -> '%s' error -> '%s'", proc_path, err)
|
||||
if not err and proc_path ~= "" and proc_path ~= nil and (not dproc_path or dproc_path == proc_path) then
|
||||
action_data.data = update_action_data(action_data, object_type, dproc_id, proc_path)
|
||||
@@ -675,192 +651,18 @@ else
|
||||
return action_data.data.result
|
||||
end
|
||||
|
||||
function handlers.linux.kill_process_by_name(action_name, action_data, object_type, name, kill_children, ignore_whitelist)
|
||||
assert(type(name) == "string", "input process name or path has invalid type")
|
||||
assert(type(kill_children) == "boolean", "kill_children flag has invalid type")
|
||||
__log.debug("kill_process_by_name", name, kill_children)
|
||||
--[[ OSX handlers ]]
|
||||
|
||||
local proc_found = false
|
||||
local action_data_bak = glue.update({}, action_data.data)
|
||||
action_data_bak.result = true
|
||||
|
||||
local full_process_info = dyn_handlers.collect_process_info(object_type)
|
||||
|
||||
local proc_name, proc_id, proc_path, err
|
||||
for _, proc_info in ipairs(full_process_info) do
|
||||
clear_proc_data(action_data, object_type)
|
||||
proc_name = proc_info[object_type .. ".process.name"]
|
||||
proc_id = proc_info[object_type .. ".process.id"]
|
||||
proc_path = proc_info[object_type .. ".process.fullpath"]
|
||||
|
||||
-- some processes on osx might start with dash
|
||||
-- current way of getting process info does not guarantee getting full process name
|
||||
-- instead it gets argv[0] of running process
|
||||
if ffi.os == "OSX" then
|
||||
if proc_path == "" or ( not glue.ends(proc_name, name)) then
|
||||
goto continue
|
||||
end
|
||||
else
|
||||
if proc_path == "" or (proc_path ~= name and proc_name ~= name) then
|
||||
goto continue
|
||||
end
|
||||
end
|
||||
proc_found = true
|
||||
action_data.data = update_action_data(action_data, object_type, proc_id, proc_path)
|
||||
|
||||
if is_whitelisted(proc_path, proc_id, ignore_whitelist) then
|
||||
action_data.data.result = true
|
||||
push_event("pt_" .. object_type .. "_process_skipped", action_name, action_data)
|
||||
goto continue
|
||||
end
|
||||
|
||||
if kill_children then
|
||||
kill_proc_children(action_name, object_type, proc_id)
|
||||
end
|
||||
|
||||
action_data.data, err = dyn_handlers.kill_proc_common(action_name, action_data, object_type, proc_id)
|
||||
__log.debugf("proc killed -> '%d' error -> '%s'", proc_id, err)
|
||||
|
||||
::continue::
|
||||
end
|
||||
|
||||
if not proc_found then
|
||||
action_data.data.result = false
|
||||
action_data.data.reason = "Process not found"
|
||||
push_event("pt_process_not_found", action_name, action_data)
|
||||
end
|
||||
return action_data.data.result
|
||||
end
|
||||
|
||||
function handlers.linux.get_process_path(proc_id)
|
||||
local attrs = lfs.symlinkattributes(string.format("/proc/%s/exe", proc_id))
|
||||
if type(attrs) ~= "table" then
|
||||
return "", "not found"
|
||||
elseif attrs["mode"] ~= "link" then
|
||||
return "", "invalid process id"
|
||||
elseif type(attrs["target"]) ~= "string" then
|
||||
return "", "permission deny"
|
||||
end
|
||||
return attrs["target"]
|
||||
end
|
||||
|
||||
-- might be a number or "self"
|
||||
function handlers.linux.get_process_info(proc_id_str)
|
||||
assert(type(proc_id_str) == "string")
|
||||
local file = io.open("/proc/" .. proc_id_str .. "/stat", "r")
|
||||
if file ~= nil then
|
||||
local info = file:read()
|
||||
local _pid, _ppid = info:match("(%S+) %S+ %S+ (%S+)")
|
||||
local proc_id = tonumber(_pid)
|
||||
local ppid = tonumber(_ppid)
|
||||
file:close()
|
||||
if proc_id ~= nil and ppid ~= nil then
|
||||
return proc_id, ppid, false
|
||||
else
|
||||
return nil, nil, true
|
||||
end
|
||||
end
|
||||
|
||||
return nil, nil, true
|
||||
end
|
||||
|
||||
function handlers.linux.collect_process_info(object_type)
|
||||
local process_list = {}
|
||||
local imagepath, err
|
||||
for file in lfs.dir("/proc") do
|
||||
if file == "." or file == ".." or tonumber(file) == nil then
|
||||
goto continue
|
||||
end
|
||||
local attrs = lfs.attributes(string.format("/proc/%s", file))
|
||||
if type(attrs) ~= "table" or attrs["mode"] ~= "directory" then
|
||||
goto continue
|
||||
end
|
||||
|
||||
imagepath, err = handlers.linux.get_process_path(file)
|
||||
if not err then
|
||||
local proc_id, ppid
|
||||
local name = luapath.file(imagepath)
|
||||
proc_id, ppid, err = handlers.linux.get_process_info(file)
|
||||
if not err then
|
||||
if proc_id == nil or ppid == nil then
|
||||
__log.info("Invalid PID: -> " .. proc_id .. " expected ->" .. file)
|
||||
end
|
||||
table.insert(process_list, {
|
||||
[object_type .. ".process.id"] = proc_id,
|
||||
[object_type .. ".process.parent.id"] = ppid,
|
||||
[object_type .. ".process.fullpath"] = imagepath,
|
||||
[object_type .. ".process.name"] = name
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
::continue::
|
||||
end
|
||||
return process_list
|
||||
end
|
||||
|
||||
function handlers.linux.update_agent_info()
|
||||
local aid, apath
|
||||
aid = handlers.linux.get_process_info("self")
|
||||
apath = handlers.linux.get_process_path("self")
|
||||
return aid, apath
|
||||
end
|
||||
|
||||
function handlers.osx.update_agent_info()
|
||||
local aid, apath
|
||||
aid = ffi.C.getpid()
|
||||
apath = handlers.osx.get_process_path(aid)
|
||||
return aid, apath
|
||||
end
|
||||
|
||||
function handlers.osx.get_process_path(proc_id)
|
||||
assert(type(proc_id) == "number", "PID should a number")
|
||||
local cmd = "/bin/ps o comm=\"\" " .. tostring(proc_id) -- comm for osx, command for linux
|
||||
local cmd_handle = assert(io.popen(cmd, "r"), "failed to call io.popen")
|
||||
local imagepath = assert(cmd_handle:read("*all"), "failed to read from pipe")
|
||||
imagepath = string.gsub(imagepath, '^%s*(.-)%s*$', '%1')
|
||||
__log.debugf("handlers.osx.get_process_path for '%d' -> '%s'", proc_id, imagepath)
|
||||
cmd_handle:close()
|
||||
if imagepath ~= nil and imagepath ~= "" then
|
||||
return imagepath, nil
|
||||
else
|
||||
return nil, "Not found"
|
||||
end
|
||||
end
|
||||
|
||||
function handlers.osx.collect_process_info(object_type)
|
||||
local process_list = {}
|
||||
-- TODO move this to sysctl syscall to retrieve the process table.
|
||||
local cmd = "/bin/ps axo pid=\"\",ppid=\"\",comm=\"\"" -- comm for osx, command for linux
|
||||
local cmd_handle = assert(io.popen(cmd, "r"), "failed to call io.popen")
|
||||
local cmd_res = assert(cmd_handle:read("*all"), "failed to read from pipe")
|
||||
cmd_handle:close()
|
||||
for str in string.gmatch(cmd_res, "([^"..'\n'.."]+)") do
|
||||
local _pid, _ppid, imagepath = str:match("%s+(%S+)%s+(%S+) ([^.]+)")
|
||||
imagepath = string.gsub(imagepath, '^%s*(.-)%s*$', '%1')
|
||||
__log.debugf("handlers.osx.collect_process_info PID -> '%s' PPID -> '%s' IMAGE -> '%s", _pid, _ppid , imagepath)
|
||||
if _pid ~= nil and _ppid ~= nil and imagepath ~= nil then
|
||||
table.insert(process_list, {
|
||||
[object_type .. ".process.id"] = tonumber(_pid),
|
||||
[object_type .. ".process.parent.id"] = tonumber(_ppid),
|
||||
[object_type .. ".process.fullpath"] = imagepath,
|
||||
[object_type .. ".process.name"] = luapath.file(imagepath),
|
||||
})
|
||||
end
|
||||
end
|
||||
return process_list
|
||||
end
|
||||
|
||||
function handlers.osx.kill_process_by_name_and_id(action_name, action_data, object_type, kill_children, ignore_whitelist)
|
||||
return handlers.linux.kill_process_by_name_and_id(action_name, action_data, object_type, kill_children, ignore_whitelist)
|
||||
function handlers.osx.kill_proc_common(action_name, action_data, object_type, proc_id)
|
||||
return handlers.linux.kill_proc_common(action_name, action_data, object_type, proc_id)
|
||||
end
|
||||
|
||||
function handlers.osx.kill_process_by_name(action_name, action_data, object_type, name, kill_children, ignore_whitelist)
|
||||
return handlers.linux.kill_process_by_name(action_name, action_data, object_type, name, kill_children, ignore_whitelist)
|
||||
end
|
||||
|
||||
function handlers.osx.kill_proc_common(action_name, action_data, object_type, proc_id)
|
||||
return handlers.linux.kill_proc_common(action_name, action_data, object_type, proc_id)
|
||||
function handlers.osx.kill_process_by_name_and_id(action_name, action_data, object_type, kill_children, ignore_whitelist)
|
||||
return handlers.linux.kill_process_by_name_and_id(action_name, action_data, object_type, kill_children, ignore_whitelist)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,296 @@
|
||||
require("engine")
|
||||
local bit = require("bit")
|
||||
local ffi = require("ffi")
|
||||
local lfs = require("lfs")
|
||||
local luapath = require("path")
|
||||
local lk32
|
||||
if ffi.os == "Windows" then
|
||||
lk32 = require("waffi.windows.kernel32")
|
||||
lk32.TH32CS_SNAPPROCESS = 0x00000002
|
||||
lk32.SYNCHRONIZE = 0x00100000
|
||||
else
|
||||
ffi.cdef[[
|
||||
typedef uint32_t pid_t;
|
||||
|
||||
int kill( pid_t proc_id, int sig );
|
||||
|
||||
pid_t getpid();
|
||||
]]
|
||||
end
|
||||
|
||||
-- API for different OS types
|
||||
local api = {windows = {}, linux = {}, osx = {}}
|
||||
-- API for current OS type
|
||||
local process_api
|
||||
|
||||
local function run_callback_safe(callback, args)
|
||||
local result, need_stop = pcall(callback, args)
|
||||
if not result then
|
||||
__log.error("callback failure")
|
||||
return false
|
||||
end
|
||||
return need_stop
|
||||
end
|
||||
|
||||
if ffi.os == "Windows" then
|
||||
|
||||
--[[
|
||||
Call given callback for each process
|
||||
Callback arg table: {
|
||||
pid - process id
|
||||
name - process name
|
||||
parent_pid - process parent id
|
||||
path - process image path
|
||||
}
|
||||
Callback return value:
|
||||
bool - whether to stop iteration
|
||||
--]]
|
||||
function api.windows.for_each_process(callback)
|
||||
if not callback then
|
||||
__log.error("no callback provided")
|
||||
return
|
||||
end
|
||||
|
||||
local proc_entry = ffi.new("PROCESSENTRY32[1]")
|
||||
proc_entry[0].dwSize = ffi.sizeof("PROCESSENTRY32")
|
||||
local snap_handle = lk32.CreateToolhelp32Snapshot(lk32.TH32CS_SNAPPROCESS, 0)
|
||||
|
||||
if (lk32.Process32First(snap_handle, proc_entry[0]) == 1) then
|
||||
while (lk32.Process32Next(snap_handle, proc_entry[0]) == 1) do
|
||||
local pid = tonumber(proc_entry[0].th32ProcessID)
|
||||
local args = {
|
||||
pid = pid,
|
||||
name = ffi.string(proc_entry[0].szExeFile),
|
||||
parent_pid = tonumber(proc_entry[0].th32ParentProcessID),
|
||||
path = api.windows.get_process_path(pid),
|
||||
}
|
||||
|
||||
if (run_callback_safe(callback, args)) then
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
__log.error("failed to get info from snapshot")
|
||||
end
|
||||
if snap_handle ~= ffi.NULL then
|
||||
lk32.CloseHandle(snap_handle)
|
||||
end
|
||||
end
|
||||
|
||||
function api.windows.get_last_error()
|
||||
local err = lk32.GetLastError()
|
||||
__log.debugf("winapi last err: %d", tonumber(err))
|
||||
return err
|
||||
end
|
||||
|
||||
function api.windows.get_process_handle(pid)
|
||||
local handle = lk32.OpenProcess(bit.bor(lk32.PROCESS_QUERY_LIMITED_INFORMATION, lk32.PROCESS_TERMINATE,
|
||||
lk32.PROCESS_VM_READ, lk32.SYNCHRONIZE
|
||||
), false, pid)
|
||||
if handle == ffi.NULL then
|
||||
return nil, api.windows.get_last_error()
|
||||
end
|
||||
return handle, nil
|
||||
end
|
||||
|
||||
function api.windows.kill_process(pid)
|
||||
local handle, error = api.windows.get_process_handle(pid)
|
||||
if error then
|
||||
return false
|
||||
end
|
||||
if lk32.TerminateProcess(handle, 0) == 0 then
|
||||
return false
|
||||
end
|
||||
lk32.WaitForSingleObject(handle, 0)
|
||||
return true
|
||||
end
|
||||
|
||||
-- by using less priveleged handle we can get path for any process
|
||||
-- GetModuleFileNameExA didn't work on w7x64
|
||||
function api.windows.get_process_path(pid)
|
||||
local proc_handle, err = lk32.OpenProcess(lk32.PROCESS_QUERY_LIMITED_INFORMATION, false, pid)
|
||||
if proc_handle == nil then
|
||||
return "", err
|
||||
end
|
||||
local max_path = lk32.MAX_PATH
|
||||
local filename = ffi.new("char[?]", max_path)
|
||||
local size = ffi.new("DWORD[1]", 2048)
|
||||
if lk32.QueryFullProcessImageNameA(proc_handle, 0, filename, size) ~= 1 then
|
||||
lk32.CloseHandle(proc_handle)
|
||||
__log.errorf("failed to get process path for pid '%d'", pid)
|
||||
return "", "failed to get process path"
|
||||
end
|
||||
lk32.CloseHandle(proc_handle)
|
||||
local path = ffi.string(filename, size[0])
|
||||
return path, nil
|
||||
end
|
||||
|
||||
function api.windows.update_agent_info()
|
||||
local aid, apath
|
||||
aid = tonumber(lk32.GetCurrentProcessId())
|
||||
apath = api.windows.get_process_path(aid):lower()
|
||||
return aid, apath
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
function api.linux.get_process_path(pid)
|
||||
local attrs = lfs.symlinkattributes(string.format("/proc/%s/exe", pid))
|
||||
if type(attrs) ~= "table" then
|
||||
return "", "not found"
|
||||
elseif attrs["mode"] ~= "link" then
|
||||
return "", "invalid process id"
|
||||
elseif type(attrs["target"]) ~= "string" then
|
||||
return "", "permission deny"
|
||||
end
|
||||
return attrs["target"]
|
||||
end
|
||||
|
||||
function api.linux.kill_process(pid)
|
||||
return ffi.C.kill(pid, 9) == 0
|
||||
end
|
||||
|
||||
-- might be a number or "self"
|
||||
local function get_process_info_linux(proc_id_str)
|
||||
assert(type(proc_id_str) == "string")
|
||||
local file = io.open("/proc/" .. proc_id_str .. "/stat", "r")
|
||||
if file ~= nil then
|
||||
local info = file:read()
|
||||
local _pid, _ppid = info:match("(%S+) %S+ %S+ (%S+)")
|
||||
local pid = tonumber(_pid)
|
||||
local parent_pid = tonumber(_ppid)
|
||||
file:close()
|
||||
if pid ~= nil and parent_pid ~= nil then
|
||||
return pid, parent_pid, false
|
||||
else
|
||||
return nil, nil, true
|
||||
end
|
||||
end
|
||||
|
||||
return nil, nil, true
|
||||
end
|
||||
|
||||
function api.linux.for_each_process(callback)
|
||||
if not callback then
|
||||
error("no callback provided")
|
||||
end
|
||||
|
||||
local imagepath, err
|
||||
for file in lfs.dir("/proc") do
|
||||
if file == "." or file == ".." or tonumber(file) == nil then
|
||||
goto continue
|
||||
end
|
||||
|
||||
local attrs = lfs.attributes(string.format("/proc/%s", file))
|
||||
if type(attrs) ~= "table" or attrs["mode"] ~= "directory" then
|
||||
-- __log.debugf("Wrong attributes for '%s'", file)
|
||||
goto continue
|
||||
end
|
||||
|
||||
imagepath, err = api.linux.get_process_path(file)
|
||||
if err then
|
||||
-- __log.debugf("Failed to get process path for '%s': %s", file, err)
|
||||
goto continue
|
||||
end
|
||||
|
||||
local pid, parent_pid
|
||||
local name = luapath.file(imagepath)
|
||||
pid, parent_pid, err = get_process_info_linux(file)
|
||||
if err then
|
||||
-- __log.debugf("Failed to get process info for '%s': %s", file, err)
|
||||
goto continue
|
||||
end
|
||||
|
||||
if pid == nil or parent_pid == nil then
|
||||
__log.info("Invalid PID: -> " .. pid .. " expected ->" .. file)
|
||||
end
|
||||
|
||||
local args = {
|
||||
pid = tonumber(pid),
|
||||
name = name,
|
||||
parent_pid = tonumber(parent_pid),
|
||||
path = imagepath,
|
||||
}
|
||||
|
||||
if (run_callback_safe(callback, args)) then
|
||||
return
|
||||
end
|
||||
|
||||
::continue::
|
||||
end
|
||||
end
|
||||
|
||||
function api.linux.update_agent_info()
|
||||
local aid, apath
|
||||
aid = get_process_info_linux("self")
|
||||
apath = api.linux.get_process_path("self")
|
||||
return aid, apath
|
||||
end
|
||||
|
||||
function api.osx.get_process_path(pid)
|
||||
assert(type(pid) == "number", "PID should a number")
|
||||
local cmd = "/bin/ps o comm=\"\" " .. tostring(pid) -- comm for osx, command for linux
|
||||
local cmd_handle = assert(io.popen(cmd, "r"), "failed to call io.popen")
|
||||
local imagepath = assert(cmd_handle:read("*all"), "failed to read from pipe")
|
||||
imagepath = string.gsub(imagepath, '^%s*(.-)%s*$', '%1')
|
||||
__log.debugf("handlers.osx.get_process_path for '%d' -> '%s'", pid, imagepath)
|
||||
cmd_handle:close()
|
||||
if imagepath ~= nil and imagepath ~= "" then
|
||||
return imagepath, nil
|
||||
else
|
||||
return nil, "Not found"
|
||||
end
|
||||
end
|
||||
|
||||
function api.osx.kill_process(pid)
|
||||
return api.linux.kill_process(pid)
|
||||
end
|
||||
|
||||
function api.osx.for_each_process(callback)
|
||||
-- TODO move this to sysctl syscall to retrieve the process table.
|
||||
local cmd = "/bin/ps axo pid=\"\",ppid=\"\",comm=\"\"" -- comm for osx, command for linux
|
||||
local cmd_handle = assert(io.popen(cmd, "r"), "failed to call io.popen")
|
||||
local cmd_res = assert(cmd_handle:read("*all"), "failed to read from pipe")
|
||||
cmd_handle:close()
|
||||
for str in string.gmatch(cmd_res, "([^"..'\n'.."]+)") do
|
||||
local pid, parent_pid, imagepath = str:match("%s*(%S+)%s+(%S+) ([^.]+)")
|
||||
if (imagepath ~= nil) then
|
||||
imagepath = imagepath:gsub('^%s*(.-)%s*$', '%1')
|
||||
end
|
||||
__log.debugf("api.osx.for_each_process PID -> '%s' PPID -> '%s' IMAGE -> '%s", pid, parent_pid , imagepath)
|
||||
if pid ~= nil and parent_pid ~= nil and imagepath ~= nil then
|
||||
local args = {
|
||||
pid = tonumber(pid),
|
||||
name = luapath.file(imagepath),
|
||||
parent_pid = tonumber(parent_pid),
|
||||
path = imagepath,
|
||||
}
|
||||
|
||||
if (run_callback_safe(callback, args)) then
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function api.osx.update_agent_info()
|
||||
local aid, apath
|
||||
aid = ffi.C.getpid()
|
||||
apath = api.osx.get_process_path(aid)
|
||||
return aid, apath
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ffi.os == "Windows" then
|
||||
process_api = api.windows
|
||||
elseif ffi.os == "Linux" then
|
||||
process_api = api.linux
|
||||
elseif ffi.os == "OSX" then
|
||||
process_api = api.osx
|
||||
else
|
||||
__log.error("unsupported OS")
|
||||
return
|
||||
end
|
||||
|
||||
return process_api
|
||||
+93
-108
@@ -1,122 +1,107 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-tabs tab-position="left" v-model="leftTab">
|
||||
<el-tab-pane
|
||||
name="api"
|
||||
:label="locale[$i18n.locale]['api']"
|
||||
class="layout-fill overflow-hidden"
|
||||
v-if="viewMode === 'agent'"
|
||||
>
|
||||
<div class="layout-margin-xl limit-length">
|
||||
<el-input :placeholder="locale[$i18n.locale]['inputPlaceholder']" v-model="eventString">
|
||||
<el-button
|
||||
slot="append"
|
||||
icon="el-icon-s-promotion"
|
||||
class="layout-row-none"
|
||||
@click="submitReqToSend"
|
||||
>{{ locale[$i18n.locale]['buttonSendEventReq'] }}
|
||||
</el-button>
|
||||
</el-input>
|
||||
<div>
|
||||
<div class="layout-margin-bottom-xl">
|
||||
<el-input :placeholder="locale[$i18n.locale]['inputPlaceholder']" v-model="eventString">
|
||||
<el-button
|
||||
slot="append"
|
||||
icon="el-icon-s-promotion"
|
||||
class="flex-none"
|
||||
@click="submitReqToSend"
|
||||
>{{ locale[$i18n.locale]['buttonSendEventReq'] }}
|
||||
</el-button>
|
||||
</el-input>
|
||||
</div>
|
||||
<div class="layout-fill layout-row layout-row-column layout-row-between scrollable">
|
||||
<ul>
|
||||
<li :key="line" v-for="line in lines">{{ line }}</li>
|
||||
</ul>
|
||||
<div class="layout-column layout-align-space-between scrollable">
|
||||
<ul>
|
||||
<li :key="line" v-for="line in lines">{{ line }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const name = "responder";
|
||||
|
||||
module.exports = {
|
||||
name,
|
||||
props: ["protoAPI", "hash", "module", "eventsAPI", "modulesAPI", "components", "viewMode"],
|
||||
data: () => ({
|
||||
leftTab: undefined,
|
||||
connection: {},
|
||||
lines: [],
|
||||
eventString: "",
|
||||
locale: {
|
||||
ru: {
|
||||
api: "Отправка событий",
|
||||
inputPlaceholder: "Событие в формате {'name': 'event_name', 'data': {'event_key': 'value'}}",
|
||||
buttonSendEventReq: "Отправить",
|
||||
connected: "— подключение к серверу установлено",
|
||||
connError: "Не удалось подключиться к серверу",
|
||||
recvError: "Не удалось выполнить операцию",
|
||||
parseError: "Данные о событии введены некорректно"
|
||||
},
|
||||
en: {
|
||||
api: "Event sender",
|
||||
inputPlaceholder: "Event in format {'name': 'event_name', 'data': {'event_key': 'value'}}",
|
||||
buttonSendEventReq: "Send",
|
||||
connected: "— connection to the server established",
|
||||
connError: "Failed to connect to the server",
|
||||
recvError: "Unable to perform the operation",
|
||||
parseError: "Event data entered incorrectly"
|
||||
}
|
||||
}
|
||||
}),
|
||||
created() {
|
||||
if (this.viewMode === 'agent') {
|
||||
this.protoAPI.connect().then(
|
||||
connection => {
|
||||
const date = new Date().toLocaleTimeString();
|
||||
this.connection = connection;
|
||||
this.connection.subscribe(this.recvData, "data");
|
||||
this.$root.NotificationsService.success(`${date} ${this.locale[this.$i18n.locale]['connected']}`);
|
||||
},
|
||||
error => {
|
||||
this.$root.NotificationsService.error(this.locale[this.$i18n.locale]['connError']);
|
||||
console.log(error);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.leftTab = this.viewMode === 'agent' ? 'api' : undefined;
|
||||
},
|
||||
methods: {
|
||||
recvData(msg) {
|
||||
const date = new Date();
|
||||
const date_ms = date.toLocaleTimeString() + `.${date.getMilliseconds()}`;
|
||||
this.lines.push(
|
||||
`${date_ms} RECV DATA: ${new TextDecoder(
|
||||
"utf-8"
|
||||
).decode(msg.content.data)}`
|
||||
);
|
||||
},
|
||||
parseJsonString(str) {
|
||||
if (!(str && typeof(str) === "string")){
|
||||
return [false];
|
||||
}
|
||||
try {
|
||||
const event = JSON.parse(str);
|
||||
if (typeof(event) !== "object" || typeof(event.name) !== "string" || typeof(event.data) !== "object") {
|
||||
return [false];
|
||||
name,
|
||||
props: ["protoAPI", "hash", "module", "api", "components", "viewMode"],
|
||||
data: () => ({
|
||||
connection: {},
|
||||
lines: [],
|
||||
eventString: "",
|
||||
locale: {
|
||||
ru: {
|
||||
inputPlaceholder: "Событие в формате {'name': 'event_name', 'data': {'event_key': 'value'}}",
|
||||
buttonSendEventReq: "Отправить",
|
||||
connected: "— подключение к серверу установлено",
|
||||
connError: "Не удалось подключиться к серверу",
|
||||
recvError: "Не удалось выполнить операцию",
|
||||
parseError: "Данные о событии введены некорректно"
|
||||
},
|
||||
en: {
|
||||
inputPlaceholder: "Event in format {'name': 'event_name', 'data': {'event_key': 'value'}}",
|
||||
buttonSendEventReq: "Send",
|
||||
connected: "— connection to the server established",
|
||||
connError: "Failed to connect to the server",
|
||||
recvError: "Unable to perform the operation",
|
||||
parseError: "Event data entered incorrectly"
|
||||
}
|
||||
}
|
||||
}),
|
||||
created() {
|
||||
if (this.viewMode === 'agent') {
|
||||
this.protoAPI.connect().then(
|
||||
connection => {
|
||||
const date = new Date().toLocaleTimeString();
|
||||
this.connection = connection;
|
||||
this.connection.subscribe(this.recvData, "data");
|
||||
this.$root.NotificationsService.success(`${date} ${this.locale[this.$i18n.locale]['connected']}`);
|
||||
},
|
||||
error => {
|
||||
this.$root.NotificationsService.error(this.locale[this.$i18n.locale]['connError']);
|
||||
console.log(error);
|
||||
},
|
||||
);
|
||||
}
|
||||
return [true, event];
|
||||
} catch (e) {
|
||||
return [false];
|
||||
}
|
||||
},
|
||||
submitReqToSend() {
|
||||
const date = new Date();
|
||||
const date_ms = date.toLocaleTimeString() + `.${date.getMilliseconds()}`;
|
||||
const event = this.parseJsonString(this.eventString);
|
||||
if (!event[0]) {
|
||||
this.$root.NotificationsService.error(this.locale[this.$i18n.locale]['parseError']);
|
||||
return;
|
||||
}
|
||||
let data = JSON.stringify({ type: "events", message: [event[1]] });
|
||||
this.lines.push(
|
||||
`${date_ms} SEND DATA: ${data}`
|
||||
);
|
||||
this.connection.sendData(data);
|
||||
methods: {
|
||||
recvData(msg) {
|
||||
const date = new Date();
|
||||
const date_ms = date.toLocaleTimeString() + `.${date.getMilliseconds()}`;
|
||||
this.lines.push(
|
||||
`${date_ms} RECV DATA: ${new TextDecoder(
|
||||
"utf-8"
|
||||
).decode(msg.content.data)}`
|
||||
);
|
||||
},
|
||||
parseJsonString(str) {
|
||||
if (!(str && typeof (str) === "string")) {
|
||||
return [false];
|
||||
}
|
||||
try {
|
||||
const event = JSON.parse(str);
|
||||
if (typeof (event) !== "object" || typeof (event.name) !== "string" || typeof (event.data) !== "object") {
|
||||
return [false];
|
||||
}
|
||||
return [true, event];
|
||||
} catch (e) {
|
||||
return [false];
|
||||
}
|
||||
},
|
||||
submitReqToSend() {
|
||||
const date = new Date();
|
||||
const date_ms = date.toLocaleTimeString() + `.${date.getMilliseconds()}`;
|
||||
const event = this.parseJsonString(this.eventString);
|
||||
if (!event[0]) {
|
||||
this.$root.NotificationsService.error(this.locale[this.$i18n.locale]['parseError']);
|
||||
return;
|
||||
}
|
||||
let data = JSON.stringify({type: "events", message: [event[1]]});
|
||||
this.lines.push(
|
||||
`${date_ms} SEND DATA: ${data}`
|
||||
);
|
||||
this.connection.sendData(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -8,7 +8,7 @@ const name = "empty";
|
||||
|
||||
module.exports = {
|
||||
name,
|
||||
props: ["protoAPI", "hash", "module", "eventsAPI", "modulesAPI", "components", "viewMode"],
|
||||
props: ["protoAPI", "hash", "module", "api", "components", "viewMode"],
|
||||
data: () => ({
|
||||
})
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ const name = "empty";
|
||||
|
||||
module.exports = {
|
||||
name,
|
||||
props: ["protoAPI", "hash", "module", "eventsAPI", "modulesAPI", "components", "viewMode"],
|
||||
props: ["protoAPI", "hash", "module", "api", "components", "viewMode"],
|
||||
data: () => ({
|
||||
})
|
||||
};
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<el-button
|
||||
icon="el-icon-plus"
|
||||
type="primary"
|
||||
class="layout-margin-left-s"
|
||||
class="layout-margin-left-m"
|
||||
@click="goToNewCheckView()">
|
||||
{{ $t('BrowserModule.YaraManagement.ButtonText.NewCheck') }}
|
||||
</el-button>
|
||||
@@ -190,11 +190,11 @@
|
||||
</el-tab-pane>
|
||||
<el-tab-pane v-if="viewMode === 'agent'" name="rules" :label="$t('BrowserModule.YaraManagement.TabTitle.Rules')">
|
||||
<!-- RULES LIST -->
|
||||
<div class="layout-fill layout-row layout-row-row layout-row-stretch">
|
||||
<div class="layout-fill layout-row layout-align-start-stretch">
|
||||
<component
|
||||
v-if="connection"
|
||||
ref="rulesGrid"
|
||||
class="layout-row-auto layout-fill"
|
||||
class="flex-auto layout-fill"
|
||||
storage-key="yara-rules-grid"
|
||||
:is="components['grid']"
|
||||
:data="rules"
|
||||
@@ -272,7 +272,7 @@
|
||||
<div class="rules-view__title">
|
||||
{{ selectedRule.rule_name }}
|
||||
</div>
|
||||
<div class="rules-view__hash layout-margin-bottom-s">
|
||||
<div class="rules-view__hash layout-margin-bottom-m">
|
||||
<div v-for="hash of (selectedRule.hash || '').split('|')">
|
||||
{{ hash }}
|
||||
</div>
|
||||
@@ -499,7 +499,7 @@ const EN_LOCALE = {
|
||||
|
||||
module.exports = {
|
||||
name,
|
||||
props: [ "protoAPI", "hash", "module", "eventsAPI", "modulesAPI", "components", "viewMode", "helpers", "entity" ],
|
||||
props: [ "protoAPI", "hash", "module", "api", "components", "viewMode", "helpers", "entity" ],
|
||||
data: () => ({
|
||||
leftTab: undefined,
|
||||
connection: undefined,
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div class="layout-row layout-row-column">
|
||||
<div class="layout-row layout-row-none layout-row-row layout-row-middle">
|
||||
<div class="layout-column">
|
||||
<div class="flex-none layout-row layout-align-start-center">
|
||||
<el-button type="text" icon="el-icon-back" @click="onBack()"></el-button>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<header class="layout-row layout-row-auto quick-check-scope__header">
|
||||
<header class="flex-auto quick-check-scope__header">
|
||||
{{ $t('BrowserModule.YaraManagement.Label.QuickCheckParams') }}
|
||||
</header>
|
||||
</div>
|
||||
<div class="layout-row layout-row-auto layout-row-column quick-check-scope__content">
|
||||
<div class="flex-auto layout-column quick-check-scope__content">
|
||||
<header class="quick-check-scope__subheader">
|
||||
{{ $t('BrowserModule.YaraManagement.Label.CheckScope') }}
|
||||
</header>
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
<!-- VIEW -->
|
||||
<div
|
||||
v-if="task && !canShowParams"
|
||||
class="layout-fill layout-row layout-row-column overflow-hidden">
|
||||
<div class="layout-row layout-row-none layout-row-row layout-row-middle view-check__header">
|
||||
<div class="layout-row layout-row-auto layout-row-column">
|
||||
<div class="layout-row layout-row-none layout-row-row layout-row-middle">
|
||||
class="layout-fill layout-column overflow-hidden">
|
||||
<div class="flex-none layout-row layout-align-start-center view-check__header">
|
||||
<div class="flex-auto layout-column">
|
||||
<div class="flex-none layout-row layout-align-start-center">
|
||||
<el-button type="text" icon="el-icon-back" @click="onBack()"></el-button>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<div class="layout-row layout-row-auto layout-row-column">
|
||||
<div class="flex-auto layout-column">
|
||||
<header class="view-check__title">
|
||||
{{
|
||||
$t('BrowserModule.YaraManagement.Label.CheckFiles', { dt: toLocalizedDateTime(task.time_start) })
|
||||
@@ -28,7 +28,7 @@
|
||||
@stop-check="stopCheck">
|
||||
</component>
|
||||
</div>
|
||||
<div class="layout-row flew-none">
|
||||
<div class="flex-none">
|
||||
<el-tooltip :content="$t('BrowserModule.YaraManagement.ButtonTooltip.ShowParams')">
|
||||
<el-button class="el-icon-info" @click="showCheckParams()"></el-button>
|
||||
</el-tooltip>
|
||||
@@ -43,7 +43,7 @@
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-row layout-row-auto layout-row-column view-check__content">
|
||||
<div class="flex-auto layout-column view-check__content">
|
||||
<component
|
||||
class="layout-fill"
|
||||
:is="components['grid']"
|
||||
@@ -129,13 +129,13 @@
|
||||
</div>
|
||||
|
||||
<!-- CHECK PARAMS -->
|
||||
<div v-if="task && canShowParams" class="layout-fill layout-row layout-row-column overflow-hidden">
|
||||
<div class="layout-row layout-row-none layout-row-row layout-row-middle view-check__header">
|
||||
<div class="layout-row layout-row-auto layout-row-column">
|
||||
<div class="layout-row layout-row-none layout-row-row layout-row-middle">
|
||||
<div v-if="task && canShowParams" class="layout-fill layout-column overflow-hidden">
|
||||
<div class="flex-none layout-row layout-align-start-center view-check__header">
|
||||
<div class="flex-auto layout-column">
|
||||
<div class="flex-none layout-row layout-align-start-center">
|
||||
<el-button type="text" icon="el-icon-back" @click="showView()"></el-button>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<div class="layout-row layout-row-auto layout-row-column">
|
||||
<div class="flex-auto layout-column">
|
||||
<header class="view-check__title">
|
||||
{{
|
||||
$t('BrowserModule.YaraManagement.Label.CheckFiles', { dt: toLocalizedDateTime(task.time_start) })
|
||||
@@ -154,18 +154,18 @@
|
||||
@stop-check="stopCheck">
|
||||
</component>
|
||||
</div>
|
||||
<div class="layout-row flew-none">
|
||||
<div class="flex-none">
|
||||
<el-tooltip :content="$t('BrowserModule.YaraManagement.ButtonTooltip.Copy')">
|
||||
<el-button class="el-icon-copy-document" @click="doCopy()"></el-button>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-row-none layout-row layout-row-auto layout-row-column view-check__content">
|
||||
<div class="layout-row layout-row-row layout-row-top view-check__params">
|
||||
<div class="flex-auto layout-column view-check__content">
|
||||
<div class="layout-row layout-align-start-start view-check__params">
|
||||
<div class="view-check__params-label">
|
||||
{{ $t('BrowserModule.YaraManagement.ColumnTitle.Type') }}
|
||||
</div>
|
||||
<div class="layout-row-auto">
|
||||
<div class="flex-auto">
|
||||
<span v-if="[TaskType.CustomFs, TaskType.FastFs, TaskType.FullFs].includes(task.task_type)">
|
||||
{{ $t('BrowserModule.YaraManagement.Text.File') }}
|
||||
</span>
|
||||
@@ -176,13 +176,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layout-row-none layout-row layout-row-row layout-row-top view-check__params">
|
||||
<div class="flex-none layout-row layout-align-start-start view-check__params">
|
||||
<div
|
||||
class="view-check__params-label"
|
||||
:class="{'view-check__params-label_with-button': [TaskType.FastFs, TaskType.FastProc].includes(task.task_type)}">
|
||||
{{ $t('BrowserModule.YaraManagement.ColumnTitle.Path') }}
|
||||
</div>
|
||||
<div class="layout-row-auto">
|
||||
<div class="flex-auto">
|
||||
<div v-if="[TaskType.CustomProc, TaskType.CustomFs].includes(task.task_type)">
|
||||
{{ task.task_params.filepath || task.task_params.proc_image }}
|
||||
</div>
|
||||
@@ -201,32 +201,32 @@
|
||||
</div>
|
||||
|
||||
<div v-if="task.task_type === TaskType.FastFs">
|
||||
<header class="view-check__params-label layout-margin-bottom-s">
|
||||
<header class="view-check__params-label layout-margin-bottom-m">
|
||||
{{ $t('BrowserModule.YaraManagement.Label.CheckScopeFs') }}
|
||||
</header>
|
||||
<div v-for="item of fastScanFsItems"
|
||||
class="layout-margin-bottom-s">
|
||||
class="layout-margin-bottom-m">
|
||||
{{ item.filepath }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="task.task_type === TaskType.FastProc">
|
||||
<header class="view-check__params-label layout-margin-bottom-s">
|
||||
<header class="view-check__params-label layout-margin-bottom-m">
|
||||
{{ $t('BrowserModule.YaraManagement.Label.CheckScopeProc') }}
|
||||
</header>
|
||||
<div v-for="item of fastScanProcItems"
|
||||
class="layout-margin-bottom-s">
|
||||
class="layout-margin-bottom-m">
|
||||
{{ item.proc_image }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="task.task_type === TaskType.FastFs && excludeFsItems.length > 0">
|
||||
<header class="view-check__params-label layout-margin-bottom-s">
|
||||
<header class="view-check__params-label layout-margin-bottom-m">
|
||||
{{ $t('BrowserModule.YaraManagement.Label.CheckExcludedScope') }}
|
||||
</header>
|
||||
<div v-for="item of excludeFsItems"
|
||||
class="layout-margin-bottom-s">
|
||||
class="layout-margin-bottom-m">
|
||||
{{ item.filepath }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -238,7 +238,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layout-row-auto layout-row layout-row-row layout-row-stretch view-check__params">
|
||||
<div class="flex-auto layout-row layout-align-start-stretch view-check__params">
|
||||
<div
|
||||
class="view-check__params-label"
|
||||
:class="{'view-check__params-label_with-button': !task.custom_rules}">
|
||||
@@ -246,12 +246,12 @@
|
||||
</div>
|
||||
<div
|
||||
v-if="task.custom_rules"
|
||||
class="layout-row-auto">
|
||||
class="flex-auto">
|
||||
<div
|
||||
class="layout-row layout-row-row layout-row-right layout-margin-bottom-s">
|
||||
class="layout-row layout-align-end layout-margin-bottom-m">
|
||||
<el-link
|
||||
type="primary"
|
||||
class="layout-margin-left-s"
|
||||
class="layout-margin-left-m"
|
||||
icon="el-icon-download"
|
||||
:underline="false"
|
||||
@click="doExport">
|
||||
@@ -264,7 +264,7 @@
|
||||
</div>
|
||||
<div
|
||||
v-if="!task.custom_rules"
|
||||
class="layout-row-auto layout-row layout-row-column layout-row-stretch">
|
||||
class="flex-auto layout-column layout-align-start-stretch">
|
||||
<div v-if="!canShowPolicyRules">
|
||||
{{ $t('BrowserModule.YaraManagement.Text.FromPolicyConfig') }}
|
||||
<el-button type="text" @click="showPolicyRules()">
|
||||
@@ -277,14 +277,14 @@
|
||||
{{ $t('BrowserModule.YaraManagement.ButtonText.Hide') }}
|
||||
</el-button>
|
||||
<div>
|
||||
<div class="view-check__params-label layout-margin-bottom-s">
|
||||
<div class="view-check__params-label layout-margin-bottom-m">
|
||||
{{ $t('BrowserModule.YaraManagement.Label.Classes') }}
|
||||
</div>
|
||||
|
||||
<div class="layout-row layout-row-row layout-row-wrap layout-row-left">
|
||||
<div class="layout-row layout-wrap layout-align-start">
|
||||
<div
|
||||
v-for="item of module.current_config.malware_class_items"
|
||||
class="view-check__class-item layout-margin-bottom-s">
|
||||
class="view-check__class-item layout-margin-bottom-m">
|
||||
<el-checkbox
|
||||
:value="item.enabled"
|
||||
:disabled="true">
|
||||
@@ -294,14 +294,14 @@
|
||||
</div>
|
||||
|
||||
<div v-if="module.current_config.exclude_rules.length > 0">
|
||||
<div class="view-check__params-label layout-margin-bottom-s">
|
||||
<div class="view-check__params-label layout-margin-bottom-m">
|
||||
{{ $t('BrowserModule.YaraManagement.Label.ExcludedRules') }}
|
||||
</div>
|
||||
|
||||
<div class="layout-row layout-row-column">
|
||||
<div class="layout-column">
|
||||
<div
|
||||
v-for="item of module.current_config.exclude_rules"
|
||||
class="layout-margin-bottom-s">
|
||||
class="layout-margin-bottom-m">
|
||||
<div>{{ item.rule_name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -310,23 +310,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="layout-row-auto layout-row layout-row-row layout-row-stretch view-check__params">-->
|
||||
<!-- <div class="view-check__params-label">-->
|
||||
<!-- {{ $t('BrowserModule.YaraManagement.Label.CheckOptions') }}-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="layout-row-auto layout-row layout-row-column layout-row-stretch">-->
|
||||
<!-- <div-->
|
||||
<!-- v-for="key of Object.keys(check.options)"-->
|
||||
<!-- class="view-check__check-option layout-margin-bottom-s">-->
|
||||
<!-- <el-checkbox-->
|
||||
<!-- :value="check.options[key]"-->
|
||||
<!-- :disabled="true">-->
|
||||
<!-- {{ key }}-->
|
||||
<!-- </el-checkbox>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user