diff --git a/README.md b/README.md index ba0777a24..388db71d5 100755 --- a/README.md +++ b/README.md @@ -157,7 +157,7 @@ Check the [GitHub Issues](https://github.com/netalertx/NetAlertX/issues) for the ## Everything else -jokob-sk%2FNetAlertX | Trendshift +jokob-sk%2FNetAlertX | Trendshift ### 📧 Get notified what's new @@ -170,6 +170,7 @@ Get notified about a new release, what new functionality you can use and about b - [Fing](https://www.fing.com/) - Network scanner app for your Internet security (Commercial, Phone App, Proprietary hardware) - [NetBox](https://netboxlabs.com/) - The gold standard for Network Source of Truth (NSoT) and IPAM. - [Zabbix](https://www.zabbix.com/) or [Nagios](https://www.nagios.org/) - Strong focus on infrastructure monitoring. +- [Domotz](https://www.domotz.com/) - Commercial network monitoring and remote management platform aimed at MSPs, IT teams, and multi-site environments. - [NetAlertX](https://netalertx.com) - The streamlined, discovery-focused choice for real-time asset intelligence and noise-free alerting. ### 💙 Donations diff --git a/back/app.conf b/back/app.conf index 95fcf24f9..4add3c212 100755 --- a/back/app.conf +++ b/back/app.conf @@ -30,6 +30,7 @@ REPORT_DASHBOARD_URL='update_REPORT_DASHBOARD_URL_setting' INTRNT_RUN='schedule' ARPSCAN_RUN='schedule' NSLOOKUP_RUN='before_name_updates' +DIGSCAN_RUN='before_name_updates' AVAHISCAN_RUN='before_name_updates' NBTSCAN_RUN='before_name_updates' diff --git a/docs/ADVISORY_EYES_ON_GLASS.md b/docs/ADVISORY_EYES_ON_GLASS.md index ace8f0dcc..41803b762 100644 --- a/docs/ADVISORY_EYES_ON_GLASS.md +++ b/docs/ADVISORY_EYES_ON_GLASS.md @@ -4,6 +4,9 @@ For Managed Service Providers (MSPs) and Network Operations Centers (NOC), "Eyes ![filters](./img/ADVISORIES/filters.png) +> [!TIP] +> If you are using Grafana check the `/metrics` endpoint that exposes **Prometheus-compatible metrics** for NetAlertX, including aggregate device counts and per-device status. See the [Metrics API endpoint](./API_METRICS.md) documentation for details. + --- ### 1. Configure Auto-Refresh for Live Monitoring diff --git a/docs/ADVISORY_MULTI_NETWORK.md b/docs/ADVISORY_MULTI_NETWORK.md index 7a0dd0948..b56f58aef 100644 --- a/docs/ADVISORY_MULTI_NETWORK.md +++ b/docs/ADVISORY_MULTI_NETWORK.md @@ -12,20 +12,25 @@ Effective multi-network monitoring starts with understanding how NetAlertX "sees * **Manual Entry:** For static assets where only ICMP (ping) status is needed. > [!TIP] -> Explore the [remote networks](./REMOTE_NETWORKS.md) documentation for more details on how to set up the approaches menationed above. +> Explore the [remote networks](./REMOTE_NETWORKS.md) documentation for more details on how to set up the approaches mentioned above. --- ### 2. Automating IT Asset Inventory with Workflows -[Workflows](./WORKFLOWS.md) are the "engine" of NetAlertX, reducing manual overhead as your device list grows. +[Workflows](./WORKFLOWS.md) are the "engine" of NetAlertX, reducing manual overhead as your device list grows. See some examples below: + +#### A. Logical Ownership & VLAN Tagging + +Create a workflow triggered on **Device Creation** to: -* **A. Logical Ownership & VLAN Tagging:** Create a workflow triggered on **Device Creation** to: 1. Inspect the IP/Subnet. 2. Set `devVlan` or `devOwner` custom fields automatically. +#### B. Auto-Grouping: + +Use conditional logic to categorize devices. -* **B. Auto-Grouping:** Use conditional logic to categorize devices. * *Example:* If `devLastIP == 10.10.20.*`, then `Set devLocation = "BranchOffice"`. ```json @@ -56,9 +61,9 @@ Effective multi-network monitoring starts with understanding how NetAlertX "sees ] } ``` +#### C. Sync Node Tracking - -* **C. Sync Node Tracking:** When using multiple instances, ensure all synchub nodes have a descriptive `SYNC_node_name` name to distinguish between sites. +When using multiple instances, ensure all sync hub nodes have a descriptive `SYNC_node_name` name to distinguish between sites. > [!TIP] > Always test new workflows in a "Staging" instance. A misconfigured workflow can trigger thousands of unintended updates across your database. @@ -107,6 +112,7 @@ As your environment grows, tuning the underlying engine is vital to maintain a s * **Plugin Scheduling:** Avoid "Scan Storms" by staggering plugin execution. Running intensive tasks like `NMAP` or `MASS_DNS` simultaneously can spike CPU and cause database locks. * **Database Health:** Large-scale monitoring generates massive event logs. Use the **[DBCLNP (Database Cleanup)](https://www.google.com/search?q=https://docs.netalertx.com/PLUGINS/%23dbclnp)** plugin to prune old records and keep the SQLite database performant. * **Resource Management:** For high-device counts, consider increasing the memory limit for the container and utilizing `tmpfs` for temporary files to reduce SD card/disk I/O bottlenecks. +* Enable the `DEEP_SLEEP` setting. > [!IMPORTANT] > For a deep dive into hardware requirements, database vacuuming, and specific environment variables for high-load instances, refer to the full **[Performance Optimization Guide](https://docs.netalertx.com/PERFORMANCE/)**. diff --git a/docs/PLUGINS_DEV_UI_COMPONENTS.md b/docs/PLUGINS_DEV_UI_COMPONENTS.md index 663f52e0f..ef2d75fdf 100644 --- a/docs/PLUGINS_DEV_UI_COMPONENTS.md +++ b/docs/PLUGINS_DEV_UI_COMPONENTS.md @@ -7,6 +7,7 @@ Configure how your plugin's data is displayed in the NetAlertX web interface. Plugin results are displayed in the UI via the **Plugins page** and **Device details tabs**. You control the appearance and functionality of these displays by defining `database_column_definitions` in your plugin's `config.json`. Each column definition specifies: + - Which data field to display - How to render it (label, link, color-coded badge, etc.) - What CSS classes to apply @@ -275,6 +276,7 @@ Replaces specific values with display strings or HTML. ``` **Output Examples:** + - `"online"` → 🟢 Online - `"offline"` → 🔴 Offline - `"idle"` → 🟡 Idle diff --git a/docs/WORKFLOW_EXAMPLES.md b/docs/WORKFLOW_EXAMPLES.md index a6c1b3f06..5f5da444b 100755 --- a/docs/WORKFLOW_EXAMPLES.md +++ b/docs/WORKFLOW_EXAMPLES.md @@ -45,22 +45,22 @@ Sometimes devices are manually archived (e.g., no longer expected on the network ], "enabled": "Yes" } -``` +```` ### 🔍 Explanation - - Trigger: Listens for updates to device records. - - Conditions: - - `devIsArchived` is `1` (archived). - - `devPresentLastScan` is `1` (device was detected in the latest scan). - - Action: Updates the device to set `devIsArchived` to `0` (unarchived). +* **Trigger**: Listens for updates to device records. +* **Conditions**: -### ✅ Result + * `devIsArchived` is `1` (archived). + * `devPresentLastScan` is `1` (device was detected in the latest scan). +* **Action**: -Whenever a previously archived device shows up during a network scan, it will be automatically unarchived — allowing it to reappear in your device lists and dashboards. + * Updates the device to set `devIsArchived` to `0` (unarchived). +### ✅ Result -Here is your updated version of **Example 2** and **Example 3**, fully aligned with the format and structure of **Example 1** for consistency and professionalism: +Whenever a previously archived device shows up during a network scan, it will be automatically unarchived — allowing it to reappear in your device lists and dashboards. --- @@ -107,7 +107,7 @@ When new devices join your network, assigning them to the correct network node i ### 🔍 Explanation * **Trigger**: Activates when a new device is added. -* **Condition**: +* **Conditions**: * `devLastIP` contains `192.168.1.` (matches subnet). * **Action**: @@ -173,12 +173,12 @@ You may want to automatically clear out newly detected Google devices (such as C * **Trigger**: Runs on device updates. * **Conditions**: - * Vendor contains `Google`. - * Device is marked as new (`devIsNew` is `1`). + * `devVendor` contains `Google`. + * `devIsNew` is `1` (device marked as new). * **Actions**: - 1. Set `devIsNew` to `0` (mark as not new). - 2. Delete the device. + 1. Sets `devIsNew` to `0` (mark as not new). + 2. Deletes the device. ### ✅ Result diff --git a/front/css/app.css b/front/css/app.css index df77fc02e..24bbdf6b6 100755 --- a/front/css/app.css +++ b/front/css/app.css @@ -1417,6 +1417,7 @@ textarea[readonly], grid-template-columns: repeat(auto-fit, minmax(125px, 1fr)); gap: 0.75em; padding: 0.5em 0; + padding-top: 0; } #columnFilters::before, diff --git a/front/deviceDetails.php b/front/deviceDetails.php index 6c0a1180b..050672641 100755 --- a/front/deviceDetails.php +++ b/front/deviceDetails.php @@ -307,7 +307,10 @@ function updateChevrons(currentMac) { pos = refreshedList.findIndex(item => item.devMac === currentMac); if (pos === -1) { - console.error('Still not found after re-cache:', currentMac); + console.warn('Device not found in device list after re-cache — hiding navigation controls:', currentMac); + $('#txtRecord').hide(); + $('#btnPrevious').hide(); + $('#btnNext').hide(); return; } @@ -499,26 +502,9 @@ function initializeTabs () { } } -function updateDevicePageName(mac) { - let name = getDevDataByMac(mac, "devName"); - let owner = getDevDataByMac(mac, "devOwner"); - - // If data is missing, re-cache and retry once - if (mac != 'new' && (name === null|| owner === null)) { - console.warn("Device not found in cache, retrying after re-cache:", mac); - showSpinner(); - cacheDevices(true).then(() => { - hideSpinner(); - // Retry after successful cache - updateDevicePageName(mac); - }).catch((err) => { - hideSpinner(); - console.error("Failed to refresh devices:", err); - }); - return; // Exit early to avoid showing bad data - } - - // Page title - Name +// ---------------------------------------- +// Write device name/owner into page title DOM. Pure DOM side-effect, no data fetching. +function applyDevicePageTitle(mac, name, owner) { let pageTitleText; if (mac === "new") { @@ -530,12 +516,12 @@ function updateDevicePageName(mac) { ` ` + getString("Gen_create_new_device_info") ); $('#devicePageInfoPlc').show(); - } else if (!owner || name.toString().includes(owner)) { - pageTitleText = name; + } else if (!owner || (name && name.toString().includes(owner))) { + pageTitleText = encodeSpecialChars(name ?? getString("DevDetail_EveandAl_NewDevice")); $('#pageTitle').html(pageTitleText); $('#devicePageInfoPlc').hide(); } else { - pageTitleText = `${name} (${owner})`; + pageTitleText = `${encodeSpecialChars(name ?? getString("DevDetail_EveandAl_NewDevice"))} (${encodeSpecialChars(owner)})`; $('#pageTitle').html(pageTitleText); $('#devicePageInfoPlc').hide(); } @@ -544,6 +530,53 @@ function updateDevicePageName(mac) { $('title').html(pageTitleText + ' - ' + $('title').html()); } +// ---------------------------------------- +// Resolve device name/owner for the page title. +// Stage 1: localStorage cache (synchronous, fast path). +// Stage 2: one forced re-cache from table_devices.json. +// Stage 3: REST API fallback so a direct-link visit never loops. +async function updateDevicePageName(mac) { + let name = getDevDataByMac(mac, "devName"); + let owner = getDevDataByMac(mac, "devOwner"); + + // Stage 2: one re-cache attempt + if (mac !== 'new' && name === null) { + console.warn("Device not in cache, attempting re-cache:", mac); + showSpinner(); + try { + await cacheDevices(true); + } catch (err) { + console.error("Re-cache failed:", err); + } finally { + hideSpinner(); + } + name = getDevDataByMac(mac, "devName"); + owner = getDevDataByMac(mac, "devOwner"); + } + + // Stage 3: REST fallback — same endpoint renderSmallBoxes uses, always DB-direct + if (mac !== 'new' && name === null) { + console.warn("Device not found in cache after re-cache, falling back to REST API:", mac); + try { + const { apiBase, authHeader } = getAuthContext(); + const res = await fetch(`${apiBase}/device/${encodeURIComponent(mac)}`, { + headers: authHeader + }); + if (res.ok) { + const data = await res.json(); + name = data.devName ?? null; + owner = data.devOwner ?? null; + } else { + console.error("REST fallback for device name returned:", res.status); + } + } catch (err) { + console.error("REST fallback error:", err); + } + } + + applyDevicePageTitle(mac, name, owner); +} + //----------------------------------------------------------------------------------- diff --git a/front/deviceDetailsEdit.php b/front/deviceDetailsEdit.php index 542f2a595..6c70ac4b3 100755 --- a/front/deviceDetailsEdit.php +++ b/front/deviceDetailsEdit.php @@ -236,6 +236,7 @@ function getDeviceData() { // console.log(setting.setKey); // console.log(fieldData); + // Additional form elements like the random MAC address button for devMac let inlineControl = ""; // handle random mac @@ -329,6 +330,11 @@ function getDeviceData() { fieldOptionsOverride = fieldDataNew; } + // XSS prevention - encode special characters for string fields, but not for arrays (like children dynamic) + // Don't move above the handle devChildrenDynamic block because it relies on the original fieldData to generate options + fieldData = encodeSpecialChars(fieldData); + // console.log(fieldData); + // Generate the input field HTML const inputFormHtml = `