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;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.removable-option:hover::before {
|
.interactable-option:hover::before {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.removable-option::before {
|
.interactable-option::before {
|
||||||
content: 'Double-click to ❌';
|
content: 'Click 📝 | 2x❌';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
color: white;
|
color: white;
|
||||||
background-color: rgb(255, 87, 87);
|
background-color: rgb(255, 188, 87);
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
transition: opacity 0.5s;
|
transition: opacity 0.5s;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.removable-option:hover {
|
.interactable-option:hover {
|
||||||
transition: background-color 2s;
|
transition: background-color 2s;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -366,6 +366,28 @@ function showModalInput (title, message, btnCancel=getString('Gen_Cancel'), btnO
|
|||||||
$('#modal-input').modal('show');
|
$('#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 () {
|
function modalDefaultOK () {
|
||||||
// Hide modal
|
// Hide modal
|
||||||
|
|||||||
@@ -185,11 +185,42 @@
|
|||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// Function to initialize remove functionality on select options
|
// 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"
|
// Attach double-click event listeners to "Remove"
|
||||||
$(`#${selectorId} option`).addClass('removable-option').on('dblclick', function() {
|
$(`#${selectorId} option`).on('dblclick', function() {
|
||||||
const $option = $(this);
|
isDoubleClick = true;
|
||||||
removeOptionItem($option);
|
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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Modal input -->
|
<!-- Modal textarea input -->
|
||||||
<div class="modal modal-warning fade" id="modal-input" style="display: none;">
|
<div class="modal modal-warning fade" id="modal-input" style="display: none;">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@@ -118,6 +118,30 @@
|
|||||||
</div>
|
</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 -->
|
<!-- Alert float -->
|
||||||
<div id="notification" class="alert alert-dimissible pa_alert_notification">
|
<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>
|
<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 plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64
|
||||||
from logger import mylog, append_line_to_file
|
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 const import logPath, applicationPath, fullDbPath
|
||||||
from database import DB
|
from database import DB
|
||||||
from device import Device_obj
|
from device import Device_obj
|
||||||
@@ -52,20 +52,20 @@ def main():
|
|||||||
|
|
||||||
unique_devices = execute_scan(subnets, timeout)
|
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:
|
for device in unique_devices:
|
||||||
|
|
||||||
plugin_objects.add_object(
|
plugin_objects.add_object(
|
||||||
# "MAC", "IP", "Name", "Vendor", "Interface"
|
# "MAC", "IP", "Name", "Vendor", "Interface"
|
||||||
primaryId = device[0],
|
primaryId = device['mac'],
|
||||||
secondaryId = device[1],
|
secondaryId = device['ip'],
|
||||||
watched1 = device[2],
|
watched1 = device['name'],
|
||||||
watched2 = device[3],
|
watched2 = device['vendor'],
|
||||||
watched3 = device[4],
|
watched3 = device['interface'],
|
||||||
watched4 = '',
|
watched4 = '',
|
||||||
extra = '',
|
extra = '',
|
||||||
foreignKey = device[0])
|
foreignKey = device['mac'])
|
||||||
|
|
||||||
plugin_objects.write_result_file()
|
plugin_objects.write_result_file()
|
||||||
|
|
||||||
@@ -83,36 +83,32 @@ def execute_scan (subnets_list, timeout):
|
|||||||
devices_list = []
|
devices_list = []
|
||||||
|
|
||||||
# scan each interface
|
# scan each interface
|
||||||
|
|
||||||
|
for interface in subnets_list:
|
||||||
|
nmap_output = execute_scan_on_interface(interface, timeout)
|
||||||
|
mylog('verbose', [f'[{pluginName}] nmap_output: ', nmap_output])
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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])
|
||||||
|
|
||||||
|
if len(mac_addresses) == 1:
|
||||||
|
|
||||||
|
devices_list.append({'name': host_name, 'ip': ip_address, 'mac': mac_addresses[0], 'vendor': vendor, 'interface': interface})
|
||||||
|
|
||||||
for interface in subnets_list :
|
|
||||||
|
|
||||||
scan_output = execute_scan_on_interface (interface, timeout)
|
|
||||||
|
|
||||||
mylog('verbose', [f'[{pluginName}] scan_output: ', scan_output])
|
|
||||||
|
|
||||||
|
|
||||||
# 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'\((.*?)\)'
|
|
||||||
|
|
||||||
# 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])
|
|
||||||
|
|
||||||
|
|
||||||
return devices_list
|
return devices_list
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -441,11 +441,11 @@ while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
|
|||||||
<input class="form-control" id="ipInterface" type="text" placeholder="eth0" />
|
<input class="form-control" id="ipInterface" type="text" placeholder="eth0" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-3">
|
<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>
|
</div>
|
||||||
<div class="form-group">
|
<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);
|
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"/>
|
<input class="form-control" type="text" id="${codeName}_input" placeholder="Enter value"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-3">
|
<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>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -523,7 +523,7 @@ while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
|
|||||||
// init remove list item buttons
|
// init remove list item buttons
|
||||||
if(['subnets', 'list' ].includes(setType))
|
if(['subnets', 'list' ].includes(setType))
|
||||||
{
|
{
|
||||||
initRemoveBtnOptn(codeName)
|
initListInteractionOptions(codeName)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -659,6 +659,27 @@ def generate_mac_links (html, deviceUrl):
|
|||||||
|
|
||||||
return html
|
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
|
# JSON methods
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user