mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2025-12-07 01:26:11 -08:00
NMAPDEV plugin work v0.5 #645 🆕🔎
This commit is contained in:
@@ -875,24 +875,24 @@ input[readonly] {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.removable-option:hover::before {
|
||||
.interactable-option:hover::before {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.removable-option::before {
|
||||
content: 'Double-click to ❌';
|
||||
.interactable-option::before {
|
||||
content: 'Click 📝 | 2x❌';
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
color: white;
|
||||
background-color: rgb(255, 87, 87);
|
||||
background-color: rgb(255, 188, 87);
|
||||
padding: 3px;
|
||||
transition: opacity 0.5s;
|
||||
opacity: 0;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.removable-option:hover {
|
||||
.interactable-option:hover {
|
||||
transition: background-color 2s;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -366,6 +366,28 @@ function showModalInput (title, message, btnCancel=getString('Gen_Cancel'), btnO
|
||||
$('#modal-input').modal('show');
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function showModalFieldInput (title, message, btnCancel=getString('Gen_Cancel'), btnOK=getString('Gen_Okay'), curValue="", callbackFunction=null) {
|
||||
// set captions
|
||||
prefix = 'modal-field-input'
|
||||
|
||||
$(`#${prefix}-title`).html (title);
|
||||
$(`#${prefix}-message`).html (message);
|
||||
$(`#${prefix}-cancel`).html (btnCancel);
|
||||
$(`#${prefix}-OK`).html (btnOK);
|
||||
|
||||
if ( callbackFunction != null)
|
||||
{
|
||||
modalCallbackFunction = callbackFunction;
|
||||
}
|
||||
|
||||
$(`#modal-field-input-field`).val(curValue)
|
||||
|
||||
|
||||
// Show modal
|
||||
$(`#${prefix}`).modal('show');
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function modalDefaultOK () {
|
||||
// Hide modal
|
||||
|
||||
@@ -185,12 +185,43 @@
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Function to initialize remove functionality on select options
|
||||
function initRemoveBtnOptn(selectorId) {
|
||||
|
||||
let isDoubleClick = false;
|
||||
|
||||
function initListInteractionOptions(selectorId) {
|
||||
|
||||
$(`#${selectorId} option`).addClass('interactable-option')
|
||||
|
||||
// Attach double-click event listeners to "Remove"
|
||||
$(`#${selectorId} option`).addClass('removable-option').on('dblclick', function() {
|
||||
$(`#${selectorId} option`).on('dblclick', function() {
|
||||
isDoubleClick = true;
|
||||
const $option = $(this);
|
||||
removeOptionItem($option);
|
||||
});
|
||||
|
||||
$(`#${selectorId} option`).on('click', function() {
|
||||
const $option = $(this);
|
||||
|
||||
// Reset the flag after a short delay
|
||||
setTimeout(() => {
|
||||
console.log(isDoubleClick);
|
||||
if (!isDoubleClick) {
|
||||
// Single-click action
|
||||
showModalFieldInput (
|
||||
`<i class="fa fa-square-plus pointer"></i> ${getString('DevDetail_button_AddIcon')}`,
|
||||
getString('DevDetail_button_AddIcon_Help'),
|
||||
getString('Gen_Cancel'),
|
||||
getString('Gen_Okay'),
|
||||
$option.html(),
|
||||
function() {
|
||||
alert('aaa');
|
||||
});
|
||||
|
||||
isDoubleClick = false;
|
||||
}
|
||||
|
||||
}, 300); // Adjust this delay as needed
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -198,3 +229,9 @@ function initRemoveBtnOptn(selectorId) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal input -->
|
||||
<!-- Modal textarea input -->
|
||||
<div class="modal modal-warning fade" id="modal-input" style="display: none;">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
@@ -118,6 +118,30 @@
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Modal field input -->
|
||||
<div class="modal modal-warning fade" id="modal-field-input" style="display: none;">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 id="modal-field-input-title" class="modal-title"> Modal Title </h4>
|
||||
</div>
|
||||
|
||||
<div id="modal-field-input-message" class="modal-body"> Modal message </div>
|
||||
|
||||
<input id="modal-field-input-field" class="modal-field-input" type="text" ></input>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button id="modal-field-input-cancel" type="button" class="btn btn-outline pull-left" style="min-width: 80px;" data-dismiss="modal"> Cancel </button>
|
||||
<button id="modal-field-input-OK" type="button" class="btn btn-outline" style="min-width: 80px;" onclick="modalDefaultInput()"> OK </button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Alert float -->
|
||||
<div id="notification" class="alert alert-dimissible pa_alert_notification">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
|
||||
@@ -20,7 +20,7 @@ sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
|
||||
|
||||
from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64
|
||||
from logger import mylog, append_line_to_file
|
||||
from helper import timeNowTZ, get_setting_value
|
||||
from helper import timeNowTZ, get_setting_value, extract_between_strings, extract_ip_addresses, extract_mac_addresses
|
||||
from const import logPath, applicationPath, fullDbPath
|
||||
from database import DB
|
||||
from device import Device_obj
|
||||
@@ -52,20 +52,20 @@ def main():
|
||||
|
||||
unique_devices = execute_scan(subnets, timeout)
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Unknown devices count: {len(unique_devices)}'])
|
||||
mylog('verbose', [f'[{pluginName}] Devices found: {len(unique_devices)}'])
|
||||
|
||||
for device in unique_devices:
|
||||
|
||||
plugin_objects.add_object(
|
||||
# "MAC", "IP", "Name", "Vendor", "Interface"
|
||||
primaryId = device[0],
|
||||
secondaryId = device[1],
|
||||
watched1 = device[2],
|
||||
watched2 = device[3],
|
||||
watched3 = device[4],
|
||||
primaryId = device['mac'],
|
||||
secondaryId = device['ip'],
|
||||
watched1 = device['name'],
|
||||
watched2 = device['vendor'],
|
||||
watched3 = device['interface'],
|
||||
watched4 = '',
|
||||
extra = '',
|
||||
foreignKey = device[0])
|
||||
foreignKey = device['mac'])
|
||||
|
||||
plugin_objects.write_result_file()
|
||||
|
||||
@@ -84,34 +84,30 @@ def execute_scan (subnets_list, timeout):
|
||||
|
||||
# scan each interface
|
||||
|
||||
for interface in subnets_list :
|
||||
for interface in subnets_list:
|
||||
nmap_output = execute_scan_on_interface(interface, timeout)
|
||||
mylog('verbose', [f'[{pluginName}] nmap_output: ', nmap_output])
|
||||
|
||||
scan_output = execute_scan_on_interface (interface, timeout)
|
||||
if nmap_output is not None:
|
||||
nmap_output_ent = nmap_output.split('Nmap scan report for')
|
||||
# loop thru entries for individual devices
|
||||
for ent in nmap_output_ent:
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] scan_output: ', scan_output])
|
||||
lines = ent.split('\n')
|
||||
|
||||
if len(lines) >= 3:
|
||||
# lines[0] can be DESKTOP-DIHOG0E.localdomain (192.168.1.121) or 192.168.1.255
|
||||
# lines[1] can be Host is up (0.21s latency).
|
||||
# lines[2] can be MAC Address: 6C:4A:4A:7B:4A:43 (Motorola Mobility, a Lenovo Company)
|
||||
|
||||
# Regular expression patterns
|
||||
entry_pattern = r'Nmap scan report for (.*?) \((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\)'
|
||||
mac_pattern = r'MAC Address: ([0-9A-Fa-f:]+)'
|
||||
vendor_pattern = r'\((.*?)\)'
|
||||
ip_address = extract_ip_addresses(lines[0])[0]
|
||||
host_name = extract_between_strings(lines[0], ' ', ' ')
|
||||
vendor = extract_between_strings(lines[2], '(', ')')
|
||||
mac_addresses = extract_mac_addresses(lines[2])
|
||||
|
||||
# Compile regular expression patterns
|
||||
entry_regex = re.compile(entry_pattern)
|
||||
mac_regex = re.compile(mac_pattern)
|
||||
vendor_regex = re.compile(vendor_pattern)
|
||||
|
||||
# Find all matches
|
||||
entries = entry_regex.findall(scan_output)
|
||||
mac_addresses = mac_regex.findall(scan_output)
|
||||
vendors = vendor_regex.findall(scan_output)
|
||||
|
||||
for i in range(len(entries)):
|
||||
name, ip_address = entries[i]
|
||||
|
||||
|
||||
devices_list.append([mac_addresses[i], ip_address, name, vendors[i], interface])
|
||||
if len(mac_addresses) == 1:
|
||||
|
||||
devices_list.append({'name': host_name, 'ip': ip_address, 'mac': mac_addresses[0], 'vendor': vendor, 'interface': interface})
|
||||
|
||||
return devices_list
|
||||
|
||||
|
||||
@@ -441,11 +441,11 @@ while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
|
||||
<input class="form-control" id="ipInterface" type="text" placeholder="eth0" />
|
||||
</div>
|
||||
<div class="col-xs-3">
|
||||
<button class="btn btn-primary" onclick="addInterface();initRemoveBtnOptn('${codeName}')">Add</button>
|
||||
<button class="btn btn-primary" onclick="addInterface();initListInteractionOptions('${codeName}')">Add</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<select class="form-control" my-data-type="${setType}" name="${codeName}" id="${codeName}" onchange="initRemoveBtnOptn(${codeName})" multiple readonly>`;
|
||||
<select class="form-control" my-data-type="${setType}" name="${codeName}" id="${codeName}" onchange="initListInteractionOptions(${codeName})" multiple readonly>`;
|
||||
|
||||
|
||||
options = createArray(val);
|
||||
@@ -471,7 +471,7 @@ while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
|
||||
<input class="form-control" type="text" id="${codeName}_input" placeholder="Enter value"/>
|
||||
</div>
|
||||
<div class="col-xs-3">
|
||||
<button class="btn btn-primary" my-input-from="${codeName}_input" my-input-to="${codeName}" onclick="addList(this);initRemoveBtnOptn('${codeName}')">Add</button>
|
||||
<button class="btn btn-primary" my-input-from="${codeName}_input" my-input-to="${codeName}" onclick="addList(this);initListInteractionOptions('${codeName}')">Add</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@@ -523,7 +523,7 @@ while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
|
||||
// init remove list item buttons
|
||||
if(['subnets', 'list' ].includes(setType))
|
||||
{
|
||||
initRemoveBtnOptn(codeName)
|
||||
initListInteractionOptions(codeName)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -659,6 +659,27 @@ def generate_mac_links (html, deviceUrl):
|
||||
|
||||
return html
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def extract_between_strings(text, start, end):
|
||||
start_index = text.find(start)
|
||||
end_index = text.find(end, start_index + len(start))
|
||||
if start_index != -1 and end_index != -1:
|
||||
return text[start_index + len(start):end_index]
|
||||
else:
|
||||
return ""
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def extract_mac_addresses(text):
|
||||
mac_pattern = r"([0-9A-Fa-f]{2}(?:[:-][0-9A-Fa-f]{2}){5})"
|
||||
mac_addresses = re.findall(mac_pattern, text)
|
||||
return mac_addresses
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def extract_ip_addresses(text):
|
||||
ip_pattern = r"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b"
|
||||
ip_addresses = re.findall(ip_pattern, text)
|
||||
return ip_addresses
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# JSON methods
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user