Compare commits
74 Commits
v25.5.24
...
69d79dbd7c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69d79dbd7c | ||
|
|
31806c707f | ||
|
|
2a4198c2c8 | ||
|
|
cecfe60bac | ||
|
|
ef42eb1fef | ||
|
|
1e2be52371 | ||
|
|
0034e49c1a | ||
|
|
350412be33 | ||
|
|
c9312719ea | ||
|
|
3010bbf1df | ||
|
|
59d5f1053f | ||
|
|
ae81b86e78 | ||
|
|
1f80a7d8ca | ||
|
|
047797daf2 | ||
|
|
f62e0513f9 | ||
|
|
b7471fd91c | ||
|
|
0e8f8a09cb | ||
|
|
8cc85a3203 | ||
|
|
8f41d71ac4 | ||
|
|
470d362ab4 | ||
|
|
a342f73f68 | ||
|
|
05842ab4a0 | ||
|
|
b54d95e5af | ||
|
|
202dcf16b9 | ||
|
|
153383343b | ||
|
|
6f138d95ca | ||
|
|
e3bbb0afff | ||
|
|
8e05e5739b | ||
|
|
7a2c4942bf | ||
|
|
95189a9d4b | ||
|
|
ded15aa628 | ||
|
|
b1d74dcfea | ||
|
|
f4db748eae | ||
|
|
b797713b2d | ||
|
|
69cf4057ac | ||
|
|
a1d5341840 | ||
|
|
8b1e705a96 | ||
|
|
dff63b74f5 | ||
|
|
f709c97602 | ||
|
|
0b2a722218 | ||
|
|
168275343c | ||
|
|
05335df9bf | ||
|
|
de2e924aa2 | ||
|
|
6fd8c2fbd9 | ||
|
|
a3dba96908 | ||
|
|
ae6be2f525 | ||
|
|
16a45c7826 | ||
|
|
5676b50d5d | ||
|
|
7940038728 | ||
|
|
1e13bf6629 | ||
|
|
7dcec16152 | ||
|
|
01f1893431 | ||
|
|
d51f79a154 | ||
|
|
4bc5c9c8ab | ||
|
|
d6260e6fb2 | ||
|
|
ce05ce240c | ||
|
|
10e8c08ce3 | ||
|
|
71a36f2fe6 | ||
|
|
a282d2ff08 | ||
|
|
f3aeaa6344 | ||
|
|
503027c06e | ||
|
|
8d58224a95 | ||
|
|
415394fce2 | ||
|
|
7826139a7c | ||
|
|
75fc11f008 | ||
|
|
7fa76346b4 | ||
|
|
b4addd9630 | ||
|
|
d6af3363ed | ||
|
|
f4a3717859 | ||
|
|
692070de21 | ||
|
|
5dcfb37c4b | ||
|
|
941e838c74 | ||
|
|
481e236faf | ||
|
|
06ec6884a4 |
1
FUNDING.yml → .github/FUNDING.yml
vendored
@@ -1,2 +1,3 @@
|
||||
github: jokob-sk
|
||||
patreon: 84385063
|
||||
buy_me_a_coffee: jokobsk
|
||||
4
.github/tweet.md
vendored
@@ -1,2 +1,2 @@
|
||||
🎉 New release: ** v25.4.14 - Styling, Workflows and other fixes ** is live! 🚀
|
||||
Check it out here: https://github.com/jokob-sk/NetAlertX/releases/tag/v25.4.14
|
||||
🎉 New release: **v25.6.7 - Legacy upgrade removal and Fully Qualified Domain Names 🆎** is live! 🚀
|
||||
Check it out here: https://github.com/jokob-sk/NetAlertX/releases/tag/v25.6.7
|
||||
|
||||
16
.github/workflows/code_checks.yml
vendored
@@ -17,14 +17,22 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Check for absolute path URLs
|
||||
- name: Check for incorrect absolute '/php/' URLs in frontend code
|
||||
run: |
|
||||
if grep -r -E "\burl:\s*['\"]\/php" --include=\*.{js,php} .; then
|
||||
echo "❌ Found absolute path URLs starting with '/php/'. Please use relative paths."
|
||||
echo "🔍 Checking for incorrect absolute '/php/' URLs (should be 'php/' or './php/')..."
|
||||
|
||||
MATCHES=$(grep -rE "['\"]\/php\/" --include=\*.{js,php,html} ./front | grep -E "\.get|\.post|\.ajax|fetch|url\s*:") || true
|
||||
|
||||
if [ -n "$MATCHES" ]; then
|
||||
echo "$MATCHES"
|
||||
echo "❌ Found incorrectly absolute '/php/' URLs. Use 'php/' or './php/' for relative paths."
|
||||
exit 1
|
||||
else
|
||||
echo "✅ No absolute path URLs found."
|
||||
echo "✅ No bad '/php/' URLs found."
|
||||
fi
|
||||
|
||||
|
||||
|
||||
- name: Check Python syntax
|
||||
run: |
|
||||
set -e
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM alpine:3.21 AS builder
|
||||
FROM alpine:3.22 AS builder
|
||||
|
||||
ARG INSTALL_DIR=/app
|
||||
|
||||
@@ -22,7 +22,7 @@ RUN pip install openwrt-luci-rpc asusrouter asyncio aiohttp graphene flask tplin
|
||||
RUN cat ${INSTALL_DIR}/install/freebox_certificate.pem >> /opt/venv/lib/python3.12/site-packages/aiofreepybox/freebox_certificates.pem
|
||||
|
||||
# second stage
|
||||
FROM alpine:3.21 AS runner
|
||||
FROM alpine:3.22 AS runner
|
||||
|
||||
ARG INSTALL_DIR=/app
|
||||
|
||||
|
||||
@@ -18,18 +18,20 @@
|
||||
# SCAN_SUBNETS = [ '192.168.1.0/24 --interface=eth1', '192.168.1.0/24 --interface=eth0' ]
|
||||
|
||||
DISCOVER_PLUGINS=True
|
||||
SCAN_SUBNETS=['192.168.1.0/24 --interface=eth0']
|
||||
SCAN_SUBNETS=['--localnet']
|
||||
TIMEZONE='Europe/Berlin'
|
||||
LOADED_PLUGINS=['ARPSCAN','CSVBCKP','DBCLNP', 'INTRNT','MAINT','NEWDEV','NSLOOKUP','NTFPRCS', 'AVAHISCAN', 'SETPWD','SMTP', 'SYNC', 'VNDRPDT', 'WORKFLOWS', 'UI']
|
||||
LOADED_PLUGINS=['ARPSCAN', 'AVAHISCAN', 'CSVBCKP','DBCLNP', 'DIGSCAN', 'INTRNT', 'MAINT', 'NEWDEV', 'NBTSCAN', 'NSLOOKUP','NTFPRCS', 'SETPWD', 'SMTP', 'SYNC', 'VNDRPDT', 'WORKFLOWS', 'UI']
|
||||
|
||||
DAYS_TO_KEEP_EVENTS=90
|
||||
# Used for generating links in emails. Make sure not to add a trailing slash!
|
||||
REPORT_DASHBOARD_URL='http://netalertx'
|
||||
REPORT_DASHBOARD_URL='http://127.0.0.1'
|
||||
|
||||
# Make sure at least these scanners are enabled for new installs, other defaults are taken from the config.json
|
||||
INTRNT_RUN='schedule'
|
||||
ARPSCAN_RUN='schedule'
|
||||
NSLOOKUP_RUN='before_name_updates'
|
||||
AVAHISCAN_RUN='before_name_updates'
|
||||
NBTSCAN_RUN='before_name_updates'
|
||||
|
||||
# Email
|
||||
#-------------------------------------
|
||||
|
||||
BIN
back/app.db
BIN
back/app_clean.db
Executable file
BIN
back/app_old.db
Executable file
@@ -53,6 +53,7 @@ services:
|
||||
- ${DEV_LOCATION}/front/plugins.php:/app/front/plugins.php
|
||||
- ${DEV_LOCATION}/front/pluginsCore.php:/app/front/pluginsCore.php
|
||||
- ${DEV_LOCATION}/front/index.php:/app/front/index.php
|
||||
- ${DEV_LOCATION}/front/initCheck.php:/app/front/initCheck.php
|
||||
- ${DEV_LOCATION}/front/maintenance.php:/app/front/maintenance.php
|
||||
- ${DEV_LOCATION}/front/network.php:/app/front/network.php
|
||||
- ${DEV_LOCATION}/front/presence.php:/app/front/presence.php
|
||||
@@ -65,7 +66,7 @@ services:
|
||||
- ${DEV_LOCATION}/front/appEvents.php:/app/front/appEvents.php
|
||||
- ${DEV_LOCATION}/front/appEventsCore.php:/app/front/appEventsCore.php
|
||||
- ${DEV_LOCATION}/front/multiEditCore.php:/app/front/multiEditCore.php
|
||||
- ${DEV_LOCATION}/front/plugins:/app/front/plugins
|
||||
- ${DEV_LOCATION}/front/plugins:/app/front/plugins
|
||||
# DELETE END anyone trying to use this file: comment out / delete ABOVE lines, they are only for development purposes
|
||||
# ---------------------------------------------------------------------------
|
||||
environment:
|
||||
|
||||
@@ -49,6 +49,8 @@ query GetDevices($options: PageQueryOptionsInput) {
|
||||
}
|
||||
```
|
||||
|
||||
See also: [Debugging GraphQL issues](./DEBUG_GRAPHQL.md)
|
||||
|
||||
### `curl` Command
|
||||
|
||||
You can use the following `curl` command to execute the query.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
Use the official installation guides at first and use community content as supplementary material. Open an issue or PR if you'd like to add your link to the list 🙏 (Ordered by last update time)
|
||||
|
||||
- ▶ [Discover & Monitor Your Network with This Self-Hosted Open Source Tool - Lawrence Systems](https://www.youtube.com/watch?v=R3b5cxLZMpo) (June 2025)
|
||||
- ▶ [Home Lab Network Monitoring - Scotti-BYTE Enterprise Consulting Services](https://www.youtube.com/watch?v=0DryhzrQSJA) (July 2024)
|
||||
- 📄 [How to Install NetAlertX on Your Synology NAS - Marius hosting](https://mariushosting.com/how-to-install-pi-alert-on-your-synology-nas/) (Updated frequently)
|
||||
- 📄 [Using the PiAlert Network Security Scanner on a Raspberry Pi - PiMyLifeUp](https://pimylifeup.com/raspberry-pi-pialert/)
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
| `devSyncHubNode` | The NetAlertX node ID used for synchronization between NetAlertX instances. | `node_1` |
|
||||
| `devSourcePlugin` | Source plugin that discovered the device. | `ARPSCAN` |
|
||||
| `devCustomProps` | [Custom properties](./CUSTOM_PROPERTIES.md) related to the device. The value is a base64-encoded JSON object. | `PHN2ZyB...` |
|
||||
| `devFQDN` | Fully qualified domain name. | `raspberrypi.local` |
|
||||
|
||||
|
||||
To understand how values of these fields influuence application behavior, such as Notifications or Network topology, see also:
|
||||
|
||||
64
docs/DEBUG_GRAPHQL.md
Executable file
@@ -0,0 +1,64 @@
|
||||
# Debugging GraphQL server issues
|
||||
|
||||
The GraphQL server is an API middle layer, running on it's own port specified by `GRAPHQL_PORT`, to retrieve and show the data in the UI. It can also be used to retrieve data for custom third party integarions. Check the [API documentation](./API.md) for details.
|
||||
|
||||
The most common issue is that the GraphQL server doesn't start properly, usually due to a **port conflict**. If you are running multiple NetAlertX instances, make sure to use **unique ports** by changing the `GRAPHQL_PORT` setting. The default is `20212`.
|
||||
|
||||
## How to update the `GRAPHQL_PORT` in case of issues
|
||||
|
||||
As a first troubleshooting step try changing the default `GRAPHQL_PORT` setting. Please remember NetAlertX is running on the host so any application uising the same port will cause issues.
|
||||
|
||||
### Updating the setting via the Settings UI
|
||||
|
||||
Ideally use the Settings UI to update the setting under General -> Core -> GraphQL port:
|
||||
|
||||

|
||||
|
||||
You might need to temporarily stop other applications or NetAlertX instances causing conflicts to update the setting. The `API_TOKEN` is used to authenticate any API calls, including GraphQL requests.
|
||||
|
||||
### Updating the `app.conf` file
|
||||
|
||||
If the UI is not accessible, you can directly edit the `app.conf` file in your `/config` folder:
|
||||
|
||||

|
||||
|
||||
### Using a docker variable
|
||||
|
||||
All application settings can also be initialized via the `APP_CONF_OVERRIDE` docker env variable.
|
||||
|
||||
```yaml
|
||||
...
|
||||
environment:
|
||||
- TZ=Europe/Berlin
|
||||
- PORT=20213
|
||||
- APP_CONF_OVERRIDE={"GRAPHQL_PORT":"20214"}
|
||||
...
|
||||
```
|
||||
|
||||
## How to check the GraphQL server is running?
|
||||
|
||||
There are several ways to check if the GraphQL server is running.
|
||||
|
||||
### Init Check
|
||||
|
||||
You can navigate to Maintenance -> Init Check to see if `isGraphQLServerRunning` is ticked:
|
||||
|
||||

|
||||
|
||||
### Checking the Logs
|
||||
|
||||
You can navigate to Maintenance -> Logs and search for `graphql` to see if it started correctly and serving requests:
|
||||
|
||||

|
||||
|
||||
### Inspecting the Browser console
|
||||
|
||||
In your browser open the dev console (usually F12) and navigate to the Network tab where you can filter GraphQL requests (e.g., reload the Devices page).
|
||||
|
||||

|
||||
|
||||
You can then inspect any of the POST requests by opening them in a new tab.
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -1,42 +1,109 @@
|
||||
# ⚙ Initial Setup
|
||||
# ⚡ Quick Start Guide
|
||||
|
||||
## 📁 Configuration Files
|
||||
|
||||
- On first run, the app generates a default `app.conf` and `app.db` if unavailable.
|
||||
- Preferred method: Use the **Settings UI**.
|
||||
- If the UI is inaccessible, manually edit [`app.conf`](https://github.com/jokob-sk/NetAlertX/tree/main/back) in `/app/config/`.
|
||||
Get **NetAlertX** up and running in a few simple steps.
|
||||
|
||||
---
|
||||
|
||||
## 🖥️ Setting Up Scanners
|
||||
### 1. Configure Scanner Plugin(s)
|
||||
|
||||
- Define networks to scan by entering accessible subnets.
|
||||
- Default plugin: **ARPSCAN** → Requires at least one valid subnet + interface in `SCAN_SUBNETS`.
|
||||
- 📖 [Subnet & VLAN setup guide](./SUBNETS.md) (for troubleshooting and advanced scenarios).
|
||||
> [!TIP]
|
||||
> Enable additional plugins under **Settings → `LOADED_PLUGINS`**.
|
||||
> Make sure to **save** your changes and **reload the page** to activate them.
|
||||
> 
|
||||
|
||||
### 🔄 PiHole Sync
|
||||
- If using **PiHole**, devices can be synced automatically.
|
||||
- 📖 [PiHole configuration guide](./PIHOLE_GUIDE.md).
|
||||
**Initial configuration**: `ARPSCAN`, `INTRNT`
|
||||
|
||||
### 📦 Bulk Import
|
||||
> [!NOTE]
|
||||
> You can bulk-import devices via the [CSV import method](./DEVICES_BULK_EDITING.md).
|
||||
> [!NOTE]
|
||||
> `ARPSCAN` and `INTRNT` scan the current network. You can complement them with other `🔍 dev scanner` plugins like `NMAPDEV`, or import devices using `📥 importer` plugins.
|
||||
> See the [Subnet & VLAN Setup Guide](./SUBNETS.md) and [Remote Networks](./REMOTE_NETWORKS.md) for advanced configurations.
|
||||
|
||||
---
|
||||
|
||||
## 🌍 Community Guides
|
||||
### 2. Choose a Publisher Plugin
|
||||
|
||||
- Various community-written configuration guides in **Chinese, Korean, German, French**.
|
||||
- 📖 [Community Guides](./COMMUNITY_GUIDES.md)
|
||||
**Initial configuration**: `SMTP`
|
||||
|
||||
> ⚠️ **Note:** These guides may be outdated. Always refer to the official documentation first.
|
||||
> [!NOTE]
|
||||
> Configure your SMTP settings or enable additional `▶️ publisher` plugins to send alerts.
|
||||
> For more flexibility, try [📚 `_publisher_apprise`](/front/plugins/_publisher_apprise/), which supports over 80 notification services.
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Common Issues
|
||||
### 3. Set Up a Network Topology Diagram
|
||||
|
||||
Before creating a new issue:
|
||||

|
||||
|
||||
- Check if a similar issue was [already resolved](https://github.com/jokob-sk/NetAlertX/issues?q=is%3Aissue+is%3Aclosed).
|
||||
- Review [common debugging tips](./DEBUG_TIPS.md).
|
||||
- Check [Common Issues](./COMMON_ISSUES.md)
|
||||
**Initial configuration**: The app auto-selects a root node (MAC `internet`) and attempts to identify other network devices by vendor or name.
|
||||
|
||||
> [!NOTE]
|
||||
> Visualize and manage your network using the [Network Guide](./NETWORK_TREE.md).
|
||||
> Some plugins (e.g., `UNFIMP`) build the topology automatically, or you can use [Custom Workflows](./WORKFLOWS.md) to generate it based on your own rules.
|
||||
|
||||
---
|
||||
|
||||
### 4. Configure Notifications
|
||||
|
||||

|
||||
|
||||
**Initial configuration**: Notifies on `new_devices`, `down_devices`, and `events` as defined in `NTFPRCS_INCLUDED_SECTIONS`.
|
||||
|
||||
> [!NOTE]
|
||||
> Notification settings support global, plugin-specific, and per-device rules.
|
||||
> For fine-tuning, refer to the [Notification Guide](./NOTIFICATIONS.md).
|
||||
|
||||
---
|
||||
|
||||
### 5. Set Up Workflows
|
||||
|
||||

|
||||
|
||||
**Initial configuration**: N/A
|
||||
|
||||
> [!NOTE]
|
||||
> Automate responses to device status changes, group management, topology updates, and more.
|
||||
> See the [Workflows Guide](./WORKFLOWS.md) to simplify your network operations.
|
||||
|
||||
---
|
||||
|
||||
### 6. Backup Your Configuration
|
||||
|
||||

|
||||
|
||||
**Initial configuration**: The `CSVBCKP` plugin creates a daily backup to `/config/devices.csv`.
|
||||
|
||||
> [!NOTE]
|
||||
> For a complete backup strategy, follow the [Backup Guide](./BACKUPS.md).
|
||||
|
||||
---
|
||||
|
||||
### 7. (Optional) Create Custom Plugins
|
||||
|
||||
[](https://youtu.be/cdbxlwiWhv8)
|
||||
|
||||
**Initial configuration**: N/A
|
||||
|
||||
> [!NOTE]
|
||||
> Build your own scanner, importer, or publisher plugin.
|
||||
> See the [Plugin Development Guide](./PLUGINS_DEV.md) and included video tutorials.
|
||||
|
||||
---
|
||||
|
||||
## 📁 Recommended Guides
|
||||
|
||||
* 📘 [PiHole Setup Guide](./PIHOLE_GUIDE.md)
|
||||
* 📘 [CSV Import Method](./DEVICES_BULK_EDITING.md)
|
||||
* 📘 [Community Guides (Chinese, Korean, German, French)](./COMMUNITY_GUIDES.md)
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Troubleshooting & Help
|
||||
|
||||
Before opening a new issue:
|
||||
|
||||
* 📘 [Common Issues](./COMMON_ISSUES.md)
|
||||
* 🧰 [Debugging Tips](./DEBUG_TIPS.md)
|
||||
* ✅ [Browse resolved GitHub issues](https://github.com/jokob-sk/NetAlertX/issues?q=is%3Aissue+is%3Aclosed)
|
||||
|
||||
---
|
||||
|
||||
Let me know if you want a condensed README version, separate pages for each section, or UI copy based on this!
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Migration form PiAlert to NetAlertX
|
||||
|
||||
> [!WARNING]
|
||||
> Follow this guide only after you you downloaded and started NetAlert X at least once after previously using the PiAlert image.
|
||||
> Follow this guide only after you you downloaded and started a version of NetAlertX prior to v25.6.7 (e.g. `docker pull ghcr.io/jokob-sk/netalertx:25.5.24`) at least once after previously using the PiAlert image. Later versions don't support migration and devices and settings will have to migrated manually, e.g. via [CSV import](./DEVICES_BULK_EDITING.md).
|
||||
|
||||
## STEPS:
|
||||
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
Name resolution in NetAlertX relies on multiple plugins to resolve device names from IP addresses. If you are seeing `(name not found)` as device names, follow these steps to diagnose and fix the issue.
|
||||
|
||||
> [!TIP]
|
||||
> Before proceeding, make sure [Reverse DNS](./REVERSE_DNS.md) is enabled on your network.
|
||||
> You can control how names are handled and cleaned using the `NEWDEV_NAME_CLEANUP_REGEX` setting.
|
||||
> To auto-update Fully Qualified Domain Names (FQDN), enable the `REFRESH_FQDN` setting.
|
||||
|
||||
|
||||
## Required Plugins
|
||||
|
||||
For best results, ensure the following name resolution plugins are enabled:
|
||||
@@ -9,6 +15,7 @@ For best results, ensure the following name resolution plugins are enabled:
|
||||
- **AVAHISCAN** – Uses mDNS/Avahi to resolve local network names.
|
||||
- **NBTSCAN** – Queries NetBIOS to find device names.
|
||||
- **NSLOOKUP** – Performs standard DNS lookups.
|
||||
- **DIGSCAN** – Performs Name Resolution with the Dig utility (DNS).
|
||||
|
||||
You can check which plugins are active in your _Settings_ section and enable any that are missing.
|
||||
|
||||
|
||||
@@ -85,8 +85,8 @@ services:
|
||||
# (Optional) Useful for debugging setup issues
|
||||
- local/path/logs:/app/log
|
||||
# (API: OPTION 1) Store temporary files in memory (recommended for performance)
|
||||
- type: tmpfs # ◀
|
||||
target: /app/api # ◀
|
||||
- type: tmpfs # ◀ 🔺
|
||||
target: /app/api # ◀ 🔺
|
||||
# (API: OPTION 2) Store API data on disk (useful for debugging)
|
||||
# - local/path/api:/app/api
|
||||
environment:
|
||||
|
||||
@@ -9,7 +9,7 @@ NetAlertX supports additional plugins to extend its functionality, each with its
|
||||
|
||||
> [!TIP]
|
||||
> You can load additional Plugins via the General -> `LOADED_PLUGINS` setting. You need to save the settings for the new plugins to load (cache/page reload may be necessary).
|
||||
> 
|
||||
> 
|
||||
|
||||
1. Pick your `🔍 dev scanner` plugin (e.g. `ARPSCAN` or `NMAPDEV`), or import devices into the application with an `📥 importer` plugin. (See **Enabling plugins** below)
|
||||
2. Pick a `▶️ publisher` plugin, if you want to send notifications. If you don't see a publisher you'd like to use, look at the [📚_publisher_apprise](/front/plugins/_publisher_apprise/) plugin which is a proxy for over 80 notification services.
|
||||
@@ -56,6 +56,7 @@ Device-detecting plugins insert values into the `CurrentScan` database table. T
|
||||
| `DDNS` | ⚙ | DDNS update | | | Script | [ddns_update](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/ddns_update/) |
|
||||
| `DHCPLSS` | 🔍/📥/🆎| Import devices from DHCP leases | | | Script | [dhcp_leases](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/dhcp_leases/) |
|
||||
| `DHCPSRVS` | ♻ | DHCP servers | | | Script | [dhcp_servers](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/dhcp_servers/) |
|
||||
| `DIGSCAN` | 🆎 | Dig (DNS) Name resolution | | | Script | [dig_scan](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/dig_scan/) |
|
||||
| `FREEBOX` | 🔍/♻/🆎| Pull data and names from Freebox/Iliadbox | | | Script | [freebox](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/freebox/) |
|
||||
| `ICMP` | ♻ | ICMP (ping) status checker | | | Script | [icmp_scan](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/icmp_scan/) |
|
||||
| `INTRNT` | 🔍 | Internet IP scanner | | | Script | [internet_ip](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/internet_ip/) |
|
||||
@@ -71,8 +72,8 @@ Device-detecting plugins insert values into the `CurrentScan` database table. T
|
||||
| `NSLOOKUP` | 🆎 | NSLookup (DNS-based) name resolution | | | Script | [nslookup_scan](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/nslookup_scan/) |
|
||||
| `NTFPRCS` | ⚙ | Notification processing | | Yes | Template | [notification_processing](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/notification_processing/)|
|
||||
| `NTFY` | ▶️ | NTFY notifications | | | Script | [_publisher_ntfy](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/_publisher_ntfy/) |
|
||||
| `OMDSDN` | 📥/🆎 | OMADA TP-Link import | 🖧 🔄 | | Script | [omada_sdn_imp](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/omada_sdn_imp/) |
|
||||
| `OMDSDNOPENAPI`| 📥/🆎 | OMADA TP-Link import via OpenAPI | 🖧 | | Script | [omada_sdn_openapi](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/omada_sdn_openapi/) |
|
||||
| `OMDSDN` | 📥/🆎 ❌ | UNMAINTAINED use `OMDSDNOPENAPI` | 🖧 🔄 | | Script | [omada_sdn_imp](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/omada_sdn_imp/) |
|
||||
| `OMDSDNOPENAPI`| 📥/🆎 | OMADA TP-Link import via OpenAPI | 🖧 | | Script | [omada_sdn_openapi](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/omada_sdn_openapi/) |
|
||||
| `PIHOLE` | 🔍/🆎/📥| Pi-hole device import & sync | | | SQLite DB | [pihole_scan](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/pihole_scan/) |
|
||||
| `PUSHSAFER` | ▶️ | Pushsafer notifications | | | Script | [_publisher_pushsafer](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/_publisher_pushsafer/) |
|
||||
| `PUSHOVER` | ▶️ | Pushover notifications | | | Script | [_publisher_pushover](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/_publisher_pushover/) |
|
||||
@@ -90,7 +91,7 @@ Device-detecting plugins insert values into the `CurrentScan` database table. T
|
||||
|
||||
|
||||
> \* The database cleanup plugin (`DBCLNP`) is not _required_ but the app will become unusable after a while if not executed.
|
||||
> ❌ marked for removal
|
||||
> ❌ marked for removal/unmaintained - looking for help
|
||||
> ⌚It's recommended to use the same schedule interval for all plugins responsible for discovering new devices.
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
If you are running a DNS server, such as **AdGuard**, set up **Private reverse DNS servers** for a better name resolution on your network. Enabling this setting will enable NetAlertX to execute dig and nslookup commands to automatically resolve device names based on their IP addresses.
|
||||
|
||||
> [!TIP]
|
||||
> Before proceeding, ensure that [name resolution plugins](./NAME_RESOLUTION.md) are enabled.
|
||||
> You can customize how names are cleaned using the `NEWDEV_NAME_CLEANUP_REGEX` setting.
|
||||
> To auto-update Fully Qualified Domain Names (FQDN), enable the `REFRESH_FQDN` setting.
|
||||
|
||||
|
||||
> Example 1: Reverse DNS `disabled`
|
||||
>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
# Docker Update Strategies to upgrade NetAlertX
|
||||
|
||||
> [!WARNING]
|
||||
> For versions prior to `v25.6.7` upgrade to version `v25.5.24` first (`docker pull ghcr.io/jokob-sk/netalertx:25.5.24`) as later versions don't support a full upgrade. Alternatovelly, devices and settings can be migrated manually, e.g. via [CSV import](./DEVICES_BULK_EDITING.md).
|
||||
|
||||
This guide outlines approaches for updating Docker containers, usually when upgrading to a newer version of NetAlertX. Each method offers different benefits depending on the situation. Here are the methods:
|
||||
|
||||
- Manual: Direct commands to stop, remove, and rebuild containers.
|
||||
|
||||
BIN
docs/img/DEBUG_GRAPHQL/Init_check.png
Executable file
|
After Width: | Height: | Size: 135 KiB |
BIN
docs/img/DEBUG_GRAPHQL/app_conf_graphql_port.png
Executable file
|
After Width: | Height: | Size: 11 KiB |
BIN
docs/img/DEBUG_GRAPHQL/dev_console_graphql_json.png
Executable file
|
After Width: | Height: | Size: 32 KiB |
BIN
docs/img/DEBUG_GRAPHQL/graphql_running_logs.png
Executable file
|
After Width: | Height: | Size: 36 KiB |
BIN
docs/img/DEBUG_GRAPHQL/graphql_settings_port_token.png
Executable file
|
After Width: | Height: | Size: 34 KiB |
BIN
docs/img/DEBUG_GRAPHQL/network_graphql.png
Executable file
|
After Width: | Height: | Size: 35 KiB |
BIN
docs/img/NETWORK_TREE/Network_tree_details.png
Executable file
|
After Width: | Height: | Size: 93 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 71 KiB |
BIN
docs/img/PLUGINS/enable_plugin.gif
Executable file
|
After Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 8.0 KiB |
BIN
docs/img/netalertx_docs_old.png
Executable file
|
After Width: | Height: | Size: 7.5 KiB |
@@ -19,7 +19,7 @@ showSpinner()
|
||||
$(document).ready(function() {
|
||||
|
||||
// Load JSON data from the provided URL
|
||||
$.getJSON('/php/server/query_json.php?file=table_appevents.json', function(data) {
|
||||
$.getJSON('php/server/query_json.php?file=table_appevents.json', function(data) {
|
||||
// Process the JSON data and generate UI dynamically
|
||||
processData(data)
|
||||
|
||||
|
||||
@@ -695,6 +695,39 @@ body
|
||||
|
||||
/* maintenance buttons */
|
||||
|
||||
#file-check-list{
|
||||
display: block;
|
||||
}
|
||||
|
||||
.file-checking .icon-wrap{
|
||||
width: 200px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.file-checking .icon-wrap i{
|
||||
position: absolute;
|
||||
font-size: xx-large;
|
||||
right: 0;
|
||||
top: 0;
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.file-checking .file-name-wrap{
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: flex;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.file-checking{
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
|
||||
.dbtools-button {
|
||||
display: inline-block;
|
||||
width: 160px;
|
||||
@@ -842,6 +875,11 @@ height: 50px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#notifications .notification-buttons{
|
||||
margin: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
#notificationData textarea{
|
||||
width: 100%;
|
||||
}
|
||||
@@ -1098,7 +1136,7 @@ height: 50px;
|
||||
input[readonly] {
|
||||
/* Apply styles to the readonly input */
|
||||
background-color: #646566 !important;
|
||||
color: #000;
|
||||
color: #e6e6e6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
@@ -1418,6 +1456,11 @@ input[readonly] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.small-box:hover
|
||||
{
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
/* Device details */
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
@@ -63,14 +63,14 @@
|
||||
|
||||
// some race condition, need to implement delay
|
||||
setTimeout(() => {
|
||||
$.get('/php/server/query_json.php', { file: 'table_settings.json', nocache: Date.now() }, function(res) {
|
||||
$.get('php/server/query_json.php', { file: 'table_settings.json', nocache: Date.now() }, function(res) {
|
||||
|
||||
settingsData = res["data"];
|
||||
|
||||
// columns to hide
|
||||
hiddenFields = ["NEWDEV_devScan", "NEWDEV_devPresentLastScan" ]
|
||||
// columns to disable - conditional depending if a new dummy device is created
|
||||
disabledFields = mac == "new" ? ["NEWDEV_devLastNotification", "NEWDEV_devFirstConnection", "NEWDEV_devLastConnection"] : ["NEWDEV_devLastNotification", "NEWDEV_devFirstConnection", "NEWDEV_devLastConnection", "NEWDEV_devMac", "NEWDEV_devLastIP", "NEWDEV_devSyncHubNode" ];
|
||||
// columns to disable/readonly - conditional depending if a new dummy device is created
|
||||
disabledFields = mac == "new" ? ["NEWDEV_devLastNotification", "NEWDEV_devFirstConnection", "NEWDEV_devLastConnection"] : ["NEWDEV_devLastNotification", "NEWDEV_devFirstConnection", "NEWDEV_devLastConnection", "NEWDEV_devMac", "NEWDEV_devLastIP", "NEWDEV_devSyncHubNode", "NEWDEV_devFQDN" ];
|
||||
|
||||
// Grouping of fields into categories with associated documentation links
|
||||
const fieldGroups = {
|
||||
@@ -82,16 +82,7 @@
|
||||
inputGroupClasses: "field-group main-group col-lg-4 col-sm-6 col-xs-12",
|
||||
labelClasses: "col-sm-4 col-xs-12 control-label",
|
||||
inputClasses: "col-sm-8 col-xs-12 input-group"
|
||||
},
|
||||
// Group for session information
|
||||
DevDetail_SessionInfo_Title: {
|
||||
data: ["devStatus", "devLastConnection", "devFirstConnection"],
|
||||
docs: "https://github.com/jokob-sk/NetAlertX/blob/main/docs/SESSION_INFO.md",
|
||||
iconClass: "fa fa-calendar",
|
||||
inputGroupClasses: "field-group session-group col-lg-4 col-sm-6 col-xs-12",
|
||||
labelClasses: "col-sm-4 col-xs-12 control-label",
|
||||
inputClasses: "col-sm-8 col-xs-12 input-group"
|
||||
},
|
||||
},
|
||||
// Group for event and alert settings
|
||||
DevDetail_EveandAl_Title: {
|
||||
data: ["devAlertEvents", "devAlertDown", "devSkipRepeated"],
|
||||
@@ -119,6 +110,15 @@
|
||||
labelClasses: "col-sm-4 col-xs-12 control-label",
|
||||
inputClasses: "col-sm-8 col-xs-12 input-group"
|
||||
},
|
||||
// Group for session information
|
||||
DevDetail_SessionInfo_Title: {
|
||||
data: ["devStatus", "devLastConnection", "devFirstConnection", "devFQDN"],
|
||||
docs: "https://github.com/jokob-sk/NetAlertX/blob/main/docs/SESSION_INFO.md",
|
||||
iconClass: "fa fa-calendar",
|
||||
inputGroupClasses: "field-group session-group col-lg-4 col-sm-6 col-xs-12",
|
||||
labelClasses: "col-sm-4 col-xs-12 control-label",
|
||||
inputClasses: "col-sm-8 col-xs-12 input-group"
|
||||
},
|
||||
// Group for Custom properties.
|
||||
DevDetail_CustomProperties_Title: {
|
||||
data: ["devCustomProps"],
|
||||
|
||||
@@ -538,7 +538,8 @@ function mapColumnIndexToFieldName(index, tableColumnVisible) {
|
||||
"devSourcePlugin",
|
||||
"devPresentLastScan",
|
||||
"devAlertDown",
|
||||
"devCustomProps"
|
||||
"devCustomProps",
|
||||
"devFQDN"
|
||||
];
|
||||
|
||||
// console.log("OrderBy: " + columnNames[tableColumnOrder[index]]);
|
||||
@@ -648,6 +649,7 @@ function initializeDatatable (status) {
|
||||
devParentChildrenCount
|
||||
devIpLong
|
||||
devCustomProps
|
||||
devFQDN
|
||||
}
|
||||
count
|
||||
}
|
||||
@@ -722,7 +724,8 @@ function initializeDatatable (status) {
|
||||
device.devSourcePlugin || "",
|
||||
device.devPresentLastScan || "",
|
||||
device.devAlertDown || "",
|
||||
device.devCustomProps || ""
|
||||
device.devCustomProps || "",
|
||||
device.devFQDN || ""
|
||||
];
|
||||
|
||||
const newRow = [];
|
||||
@@ -760,13 +763,13 @@ function initializeDatatable (status) {
|
||||
{visible: false, targets: tableColumnHide },
|
||||
{className: 'text-center', targets: [mapIndx(4), mapIndx(9), mapIndx(10), mapIndx(15), mapIndx(18)] },
|
||||
{className: 'iconColumn text-center', targets: [mapIndx(3)]},
|
||||
{width: '80px', targets: [mapIndx(6), mapIndx(7), mapIndx(15)] },
|
||||
{width: '80px', targets: [mapIndx(6), mapIndx(7), mapIndx(15), mapIndx(27)] },
|
||||
{width: '85px', targets: [mapIndx(9)] },
|
||||
{width: '30px', targets: [mapIndx(3), mapIndx(10), mapIndx(13), mapIndx(18)] },
|
||||
{orderData: [mapIndx(12)], targets: mapIndx(8) },
|
||||
|
||||
// Device Name
|
||||
{targets: [mapIndx(0)],
|
||||
// Device Name and FQDN
|
||||
{targets: [mapIndx(0), mapIndx(27)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
|
||||
// console.log(cellData)
|
||||
@@ -845,7 +848,7 @@ function initializeDatatable (status) {
|
||||
{targets: [mapIndx(26)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
if (!emptyArr.includes(cellData)){
|
||||
$(td).html (`<span>${renderCustomProps(cellData, rowData[mapIndx(11)])}<span>`);
|
||||
$(td).html (`<span>${renderCustomProps(cellData, rowData[mapIndx(11)])}</span>`);
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ if (isset ($_GET["action"]) && $_GET["action"] == 'logout')
|
||||
}
|
||||
|
||||
// Password without Cookie check -> pass and set initial cookie
|
||||
if (isset ($_POST["loginpassword"]) && $nax_Password == hash('sha256',$_POST["loginpassword"]))
|
||||
if (isset ($_POST["loginpassword"]) && $nax_Password === hash('sha256',$_POST["loginpassword"]))
|
||||
{
|
||||
header('Location: devices.php');
|
||||
$_SESSION["login"] = 1;
|
||||
@@ -37,7 +37,7 @@ if (isset ($_POST["loginpassword"]) && $nax_Password == hash('sha256',$_POST["lo
|
||||
}
|
||||
|
||||
// active Session or valid cookie (cookie not extends)
|
||||
if (( isset ($_SESSION["login"]) && ($_SESSION["login"] == 1)) || (isset ($_COOKIE[$CookieSaveLoginName]) && $nax_Password == $_COOKIE[$CookieSaveLoginName]))
|
||||
if (( isset ($_SESSION["login"]) && ($_SESSION["login"] == 1)) || (isset ($_COOKIE[$CookieSaveLoginName]) && $nax_Password === $_COOKIE[$CookieSaveLoginName]))
|
||||
{
|
||||
header('Location: devices.php');
|
||||
$_SESSION["login"] = 1;
|
||||
@@ -53,7 +53,7 @@ $login_icon = 'fa-info';
|
||||
// no active session, cookie not checked
|
||||
if (isset ($_SESSION["login"]) == FALSE || $_SESSION["login"] != 1)
|
||||
{
|
||||
if ($nax_Password == '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92')
|
||||
if ($nax_Password === '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92')
|
||||
{
|
||||
$login_info = lang('Login_Default_PWD');
|
||||
$login_mode = 'danger';
|
||||
|
||||
52
front/initCheck.php
Executable file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
//------------------------------------------------------------------------------
|
||||
// check if authenticated
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
||||
?>
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="py-5">
|
||||
<div class="mt-4 text-center" id="check-status-plc" >
|
||||
<div class="alert alert-warning">
|
||||
<i class="fa-solid fa-spinner fa-spin text-secondary"></i> <?= lang('Maintenance_InitCheck_Checking');?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 text-center" id="check-status" style="display: none;">
|
||||
<div class="alert alert-success">
|
||||
<i class="fa-solid fa-check text-success"></i> <?= lang('Maintenance_InitCheck_Success');?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="d-flex flex-wrap gap-2 w-100" id="file-check-list"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="text-center box box-secondary col-md-6">
|
||||
<p class="text-muted"><?= lang('Maintenance_InitCheck_QuickSetupGuide');?></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12 center text-center" >
|
||||
<button type="button" class=" col-md-12 btn btn-default bg-green " onclick="retryCheck()"><?= lang('Maintenance_ReCheck');?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
function retryCheck() {
|
||||
// re-set page
|
||||
$('#file-check-list').empty();
|
||||
$('#check-status').hide();
|
||||
$('#check-status-plc').show();
|
||||
// re-run check
|
||||
checkAppInitializedJsonInit();
|
||||
}
|
||||
|
||||
$(document).ready(() => {
|
||||
checkAppInitializedJsonInit();
|
||||
});
|
||||
</script>
|
||||
@@ -113,7 +113,7 @@ function deleteAllCookies() {
|
||||
function cacheSettings()
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
if(!getCache('completedCalls').includes('cacheSettings'))
|
||||
if(!getCache('cacheSettings_completed') === true)
|
||||
{
|
||||
$.get('php/server/query_json.php', { file: 'table_settings.json', nocache: Date.now() }, function(resSet) {
|
||||
|
||||
@@ -211,8 +211,18 @@ function getSetting (key) {
|
||||
function cacheStrings() {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
// Create a promise for each language
|
||||
languagesToLoad = ['en_us', getLangCode()]
|
||||
// Create a promise for each language (include en_us by default as fallback)
|
||||
languagesToLoad = ['en_us']
|
||||
|
||||
additionalLanguage = getLangCode()
|
||||
|
||||
if(additionalLanguage != 'en_us')
|
||||
{
|
||||
languagesToLoad.push(additionalLanguage)
|
||||
}
|
||||
|
||||
console.log(languagesToLoad);
|
||||
|
||||
const languagePromises = languagesToLoad.map((language_code) => {
|
||||
return new Promise((resolveLang, rejectLang) => {
|
||||
// Fetch core strings and translations
|
||||
@@ -235,7 +245,7 @@ function cacheStrings() {
|
||||
});
|
||||
|
||||
// Handle successful completion of language processing
|
||||
handleSuccess(`cacheStrings[${language_code}]`, resolveLang);
|
||||
handleSuccess(`cacheStrings`, resolveLang);
|
||||
})
|
||||
.fail((pluginError) => {
|
||||
// Handle failure in plugin strings fetching
|
||||
@@ -356,9 +366,11 @@ function getLangCode() {
|
||||
|
||||
function localizeTimestamp(result)
|
||||
{
|
||||
|
||||
// contains TZ in format Europe/Berlin
|
||||
tz = getSetting("TIMEZONE")
|
||||
|
||||
// set default if not available or app still loading
|
||||
tz == "" ? tz = 'Europe/Berlin' : tz = tz;
|
||||
|
||||
const date = new Date(result); // Assumes result is a timestamp or ISO string
|
||||
const formatter = new Intl.DateTimeFormat('default', {
|
||||
@@ -1366,8 +1378,8 @@ function restartBackend() {
|
||||
const sessionStorageKey = "myScriptExecuted_common_js";
|
||||
var completedCalls = []
|
||||
var completedCalls_final = ['cacheSettings', 'cacheStrings', 'cacheDevices'];
|
||||
var completedCallsCount = 0;
|
||||
var completedCallsCount_final;
|
||||
var lang_completedCalls = 0;
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Clearing all the caches
|
||||
@@ -1453,12 +1465,27 @@ async function isGraphQLServerRunning() {
|
||||
// Check if the code has been executed before by checking sessionStorage
|
||||
function isAppInitialized() {
|
||||
|
||||
completedCalls = parseInt(getCache("completedCallsCount"));
|
||||
shouldBeCompletedCalls = getLangCode() == 'en_us' ? 3 : 4;
|
||||
lang_shouldBeCompletedCalls = getLangCode() == 'en_us' ? 1 : 2;
|
||||
|
||||
return (
|
||||
completedCalls >= shouldBeCompletedCalls
|
||||
);
|
||||
// check if each ajax call completed succesfully
|
||||
$.each(completedCalls_final, function(index, call_name){
|
||||
|
||||
if(getCache(call_name + "_completed") != "true")
|
||||
{
|
||||
console.log(`[isAppInitialized] AJAX call ${call_name} unsuccesful: ${getCache(call_name + "_completed")}`)
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// check if all required languages chached
|
||||
if(parseInt(getCache("cacheStringsCountCompleted")) != lang_shouldBeCompletedCalls)
|
||||
{
|
||||
console.log(`[isAppInitialized] AJAX call cacheStrings unsuccesful: ${getCache("cacheStringsCountCompleted")} out of ${lang_shouldBeCompletedCalls}`)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -1489,27 +1516,25 @@ async function executeOnce() {
|
||||
// Function to handle successful completion of an AJAX call
|
||||
const handleSuccess = (callName) => {
|
||||
console.log(`AJAX call successful: ${callName}`);
|
||||
// completedCalls.push(callName);
|
||||
// setCache('completedCalls', mergeUniqueArrays(getCache('completedCalls').split(','), [callName]));
|
||||
|
||||
val = getCache('completedCallsCount');
|
||||
|
||||
if(val == "")
|
||||
if(callName.includes("cacheStrings"))
|
||||
{
|
||||
val = 0;
|
||||
} else
|
||||
{
|
||||
val = parseInt(val)
|
||||
completed_tmp = getCache("cacheStringsCountCompleted");
|
||||
completed_tmp == "" ? completed_tmp = 0 : completed_tmp = completed_tmp;
|
||||
completed_tmp++;
|
||||
setCache("cacheStringsCountCompleted", completed_tmp);
|
||||
}
|
||||
|
||||
setCache('completedCallsCount', val + 1)
|
||||
setCache(callName + "_completed", true)
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function to handle failure of an AJAX call
|
||||
const handleFailure = (callName, callback) => {
|
||||
console.error(`AJAX call ${callName} failed`);
|
||||
msg = `AJAX call ${callName} failed`
|
||||
console.error(msg);
|
||||
// Implement retry logic here if needed
|
||||
// write_notification(msg, 'interrupt')
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -33,7 +33,7 @@ function versionUpdateUI(){
|
||||
// Checks if a new version is available via the global app_state.json
|
||||
function checkIfNewVersionAvailable()
|
||||
{
|
||||
$.get('/php/server/query_json.php', { file: 'app_state.json', nocache: Date.now() }, function(appState) {
|
||||
$.get('php/server/query_json.php', { file: 'app_state.json', nocache: Date.now() }, function(appState) {
|
||||
|
||||
// console.log(appState["isNewVersionChecked"])
|
||||
// console.log(appState["isNewVersion"])
|
||||
@@ -48,4 +48,4 @@ function checkIfNewVersionAvailable()
|
||||
}
|
||||
|
||||
// handle the dispaly of the NEW icon
|
||||
checkIfNewVersionAvailable()
|
||||
checkIfNewVersionAvailable()
|
||||
|
||||
@@ -433,7 +433,7 @@ function initListInteractionOptions(element) {
|
||||
if (clickCounter === 1) {
|
||||
// Single-click action
|
||||
showModalFieldInput(
|
||||
`<i class="fa-regular fa-pen-to-square"></i> ${getString(
|
||||
`<i class="fa fa-pen-to-square"></i> ${getString(
|
||||
"Gen_Update_Value"
|
||||
)}`,
|
||||
getString("settings_update_item_warning"),
|
||||
|
||||
@@ -26,6 +26,134 @@ function lockDatabase(delay=20) {
|
||||
}
|
||||
|
||||
|
||||
const requiredFiles = [
|
||||
'app_state.json',
|
||||
'plugins.json',
|
||||
'table_devices.json',
|
||||
'table_devices_filters.json',
|
||||
'table_devices_tiles.json',
|
||||
'table_notifications.json',
|
||||
'table_online_history.json',
|
||||
'table_appevents.json',
|
||||
'table_custom_endpoint.json',
|
||||
'table_events_pending_alert.json',
|
||||
'table_plugins_events.json',
|
||||
'table_plugins_history.json',
|
||||
'table_plugins_language_strings.json',
|
||||
'table_plugins_objects.json',
|
||||
'table_settings.json',
|
||||
'user_notifications.json'
|
||||
];
|
||||
|
||||
const internalChecks = ['isAppInitialized', 'isGraphQLServerRunning'];
|
||||
|
||||
const fileStatus = {}; // Track file check results
|
||||
|
||||
function updateFileStatusUI(file, status) {
|
||||
const item = $(`#file-${file.replace(/[^a-z0-9]/gi, '-')}`);
|
||||
const icon = item.find('span.icon-wrap');
|
||||
|
||||
if (status === 'ok') {
|
||||
icon.html('<i class="fa-solid fa-check "></i>');
|
||||
} else if (status === 'fail') {
|
||||
icon.html('<i class="fa-solid fa-xmark "></i>');
|
||||
} else {
|
||||
icon.html('<i class="fa-solid fa-spinner fa-spin text-secondary"></i>');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function checkAppInitializedJson() {
|
||||
requiredFiles.forEach(file => {
|
||||
$.get('php/server/query_json.php', { file, nocache: Date.now() })
|
||||
.done(() => {
|
||||
if (fileStatus[file] !== 'ok') {
|
||||
fileStatus[file] = 'ok';
|
||||
updateFileStatusUI(file, 'ok');
|
||||
}
|
||||
})
|
||||
.fail(() => {
|
||||
fileStatus[file] = 'fail';
|
||||
updateFileStatusUI(file, 'fail');
|
||||
});
|
||||
});
|
||||
|
||||
const allOk = requiredFiles.every(file => fileStatus[file] === 'ok');
|
||||
|
||||
if (allOk) {
|
||||
checkInternalStatusAfterFiles();
|
||||
} else {
|
||||
setTimeout(checkAppInitializedJson, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function checkInternalStatusAfterFiles() {
|
||||
const promises = [
|
||||
waitForAppInitialized().then(() => {
|
||||
fileStatus['isAppInitialized'] = 'ok';
|
||||
updateFileStatusUI('isAppInitialized', 'ok');
|
||||
}).catch(() => {
|
||||
fileStatus['isAppInitialized'] = 'fail';
|
||||
updateFileStatusUI('isAppInitialized', 'fail');
|
||||
}),
|
||||
|
||||
waitForGraphQLServer().then(() => {
|
||||
fileStatus['isGraphQLServerRunning'] = 'ok';
|
||||
updateFileStatusUI('isGraphQLServerRunning', 'ok');
|
||||
}).catch(() => {
|
||||
fileStatus['isGraphQLServerRunning'] = 'fail';
|
||||
updateFileStatusUI('isGraphQLServerRunning', 'fail');
|
||||
})
|
||||
];
|
||||
|
||||
Promise.allSettled(promises).then(() => {
|
||||
const allPassed = internalChecks.every(key => fileStatus[key] === 'ok');
|
||||
if (allPassed) {
|
||||
$('#check-status').show();
|
||||
$('#check-status-plc').hide();
|
||||
} else {
|
||||
setTimeout(checkInternalStatusAfterFiles, 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
function waitForAppInitialized() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (isAppInitialized()) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Initial UI setup for all items
|
||||
function checkAppInitializedJsonInit() {
|
||||
const allItems = [...requiredFiles, ...internalChecks];
|
||||
|
||||
allItems.forEach(file => {
|
||||
|
||||
|
||||
$('#file-check-list').append(`
|
||||
<div class="panel panel-secondary col-xs-6 col-sm-4 col-md-3 col-lg-2 col-xxl-1 padding-5px">
|
||||
<div class="file-checking border rounded p-2 d-flex flex-column justify-content-between h-100" id="file-${file.replace(/[^a-z0-9]/gi, '-')}">
|
||||
<div class="d-flex align-items-center gap-2 mb-2">
|
||||
<span class="file-name-wrap flex-grow-1 text-truncate" title="${file}">${file}</span>
|
||||
<span class="icon-wrap align-items-center text-center"><i class="fa-solid fa-spinner fa-spin text-secondary"></i></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
|
||||
fileStatus[file] = 'checking';
|
||||
});
|
||||
|
||||
checkAppInitializedJson();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -200,9 +200,9 @@ function validateRegex(elem) {
|
||||
|
||||
// Validate against regex
|
||||
if (regex.test(value)) {
|
||||
iconSpan.html("<i class='fa-regular fa-check'></i>");
|
||||
iconSpan.html("<i class='fa fa-check'></i>");
|
||||
} else {
|
||||
iconSpan.html("<i class='fa-regular fa-xmark'></i>");
|
||||
iconSpan.html("<i class='fa fa-xmark'></i>");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ $db->close();
|
||||
<div class="box" id="Maintain-Status">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">
|
||||
<i class="fa fa-display"></i></i>
|
||||
<i class="fa fa-display"></i>
|
||||
<?= lang('Maintenance_Status');?>
|
||||
</h3>
|
||||
</div>
|
||||
@@ -59,7 +59,7 @@ $db->close();
|
||||
<div class="db_info_table">
|
||||
<div class="db_info_table_row">
|
||||
<div class="db_info_table_cell" style="min-width: 140px"><?= lang('Maintenance_version');?>
|
||||
<a href="https://github.com/jokob-sk/NetAlertX/blob/main/docs/VERSIONS.md" target="_blank"> <span><i class="fa fa-circle-question"></i></a><span>
|
||||
<a href="https://github.com/jokob-sk/NetAlertX/blob/main/docs/VERSIONS.md" target="_blank"> <span><i class="fa fa-circle-question"></i></a></span>
|
||||
</div>
|
||||
<div class="db_info_table_cell">
|
||||
<div class="version" id="version" data-build-time="<?php echo file_get_contents( "buildtimestamp.txt");?>">
|
||||
@@ -111,7 +111,7 @@ $db->close();
|
||||
</div>
|
||||
|
||||
<div class="nav-tabs-custom">
|
||||
<ul class="nav nav-tabs">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active">
|
||||
<a id="tab_DBTools_id" href="#tab_DBTools" data-toggle="tab">
|
||||
<i class="fa fa-toolbox"></i>
|
||||
@@ -136,7 +136,13 @@ $db->close();
|
||||
<?= lang('Device_MultiEdit');?>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<li>
|
||||
<a id="tab_initCheck_id" href="#tab_initCheck" data-toggle="tab">
|
||||
<i class="fa-solid fa-check"></i>
|
||||
<?= lang('Maintenance_InitCheck');?>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="tab_DBTools">
|
||||
<div class="db_info_table">
|
||||
@@ -178,6 +184,8 @@ $db->close();
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ---------------------------Backup restore -------------------------------------------- -->
|
||||
<div class="tab-pane" id="tab_BackupRestore">
|
||||
<div class="db_info_table">
|
||||
<div class="db_info_table_row">
|
||||
@@ -245,11 +253,11 @@ $db->close();
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="db_info_table">
|
||||
|
||||
<div class="db_info_table">
|
||||
<div id="logsPlc"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ---------------------------Bulk edit -------------------------------------------- -->
|
||||
<div class="tab-pane" id="tab_multiEdit">
|
||||
<div class="db_info_table">
|
||||
@@ -260,35 +268,53 @@ $db->close();
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ---------------------------Init check -------------------------------------------- -->
|
||||
<div class="tab-pane" id="tab_initCheck">
|
||||
<div class="db_info_table">
|
||||
<div class="box box-solid">
|
||||
|
||||
<?php
|
||||
require 'initCheck.php';
|
||||
?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- ------------------------------------------------------------------------------ -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box-body" style="text-align: center;">
|
||||
<div class="box-body " style="text-align: center;">
|
||||
<h5 class="text-aqua" style="font-size: 16px;">
|
||||
<span id="lastCommit">
|
||||
|
||||
|
||||
</span>
|
||||
<span id="lastDockerUpdate">
|
||||
|
||||
|
||||
</span>
|
||||
</h5>
|
||||
</div>
|
||||
</h5>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
<!-- /.content -->
|
||||
<?php
|
||||
require 'php/templates/footer.php';
|
||||
?>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<!-- /.content -->
|
||||
<?php
|
||||
require 'php/templates/footer.php';
|
||||
?>
|
||||
</div>
|
||||
<!-- /.content-wrapper -->
|
||||
<!-- /.content-wrapper -->
|
||||
|
||||
<!-- ----------------------------------------------------------------------- -->
|
||||
|
||||
|
||||
@@ -64,10 +64,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script defer>
|
||||
|
||||
@@ -77,7 +73,7 @@
|
||||
|
||||
// some race condition, need to implement delay
|
||||
setTimeout(() => {
|
||||
$.get('/php/server/query_json.php', { file: 'table_settings.json', nocache: Date.now() }, function(res) {
|
||||
$.get('php/server/query_json.php', { file: 'table_settings.json', nocache: Date.now() }, function(res) {
|
||||
|
||||
settingsData = res["data"];
|
||||
|
||||
|
||||
@@ -125,8 +125,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
</table>
|
||||
<div id="assignedDevices" class="box-body no-padding">
|
||||
<div class="page-header">
|
||||
<h3>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
|
||||
function initOnlineHistoryGraph() {
|
||||
$.get('/php/server/query_json.php', { file: 'table_online_history.json', nocache: Date.now() }, function(res) {
|
||||
$.get('php/server/query_json.php', { file: 'table_online_history.json', nocache: Date.now() }, function(res) {
|
||||
// Extracting data from the JSON response
|
||||
var timeStamps = [];
|
||||
var onlineCounts = [];
|
||||
@@ -53,4 +53,4 @@ function initOnlineHistoryGraph() {
|
||||
|
||||
</script>
|
||||
<!-- <canvas id="clientsChart" width="800" height="140" class="extratooltipcanvas no-user-select"></canvas> -->
|
||||
<canvas id="OnlineChart" style="width:100%; height: 150px; margin-bottom: 15px;"></canvas>
|
||||
<canvas id="OnlineChart" style="width:100%; height: 150px; margin-bottom: 15px;"></canvas>
|
||||
|
||||
@@ -112,7 +112,8 @@ function getServerDeviceData() {
|
||||
"devSessions" => 0,
|
||||
"devEvents" => 0,
|
||||
"devDownAlerts" => 0,
|
||||
"devPresenceHours" => 0
|
||||
"devPresenceHours" => 0,
|
||||
"devFQDN" => ""
|
||||
];
|
||||
echo json_encode($deviceData);
|
||||
return;
|
||||
|
||||
@@ -586,7 +586,8 @@ function getDevicesColumns(){
|
||||
"devSite",
|
||||
"devSSID",
|
||||
"devSourcePlugin",
|
||||
"devCustomProps"
|
||||
"devCustomProps",
|
||||
"devFQDN"
|
||||
];
|
||||
|
||||
return $columns;
|
||||
|
||||
@@ -21,7 +21,7 @@ $config_file_lines = array_values(preg_grep('/^SETPWD_password.*=/', $config_fil
|
||||
$password_line = explode("'", $config_file_lines[0]);
|
||||
$nax_Password = $password_line[1];
|
||||
|
||||
if (isset($_COOKIE[$CookieSaveLoginName]) && $nax_Password == $_COOKIE[$CookieSaveLoginName]) {
|
||||
if (isset($_COOKIE[$CookieSaveLoginName]) && $nax_Password === $_COOKIE[$CookieSaveLoginName]) {
|
||||
$isAuthenticated = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
<!-- To the right -->
|
||||
<div class="pull-right no-hidden-xs">
|
||||
| <a href="https://gurubase.io/g/netalertx" class="pointer" target="_blank" title="Ask AI"><i class="fa-regular fa-comment-dots fa-flip-horizontal"></i></a>
|
||||
| <a href="https://gurubase.io/g/netalertx" class="pointer" target="_blank" title="Ask AI"><i class="fa fa-comment-dots fa-flip-horizontal"></i></a>
|
||||
| <a href="https://jokob-sk.github.io/NetAlertX/" class="pointer" target="_blank" title="Documentation"><i class="fa fa-book"></i></a>
|
||||
| <a href="https://github.com/jokob-sk/NetAlertX/issues" class="pointer" target="_blank"><i class="fa fa-bug" title="Report a bug"></i></a>
|
||||
| <a href="https://discord.com/invite/NczTUTWyRr" class="pointer" target="_blank"><i class="fa-brands fa-discord" title="Join Discord"></i></a>
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
// -------------------------------------------------------------
|
||||
// Updates the backend application state/status in the header
|
||||
function updateState(){
|
||||
$.get('/php/server/query_json.php', { file: 'app_state.json', nocache: Date.now() }, function(appState) {
|
||||
$.get('php/server/query_json.php', { file: 'app_state.json', nocache: Date.now() }, function(appState) {
|
||||
|
||||
document.getElementById('state').innerHTML = appState["currentState"].replaceAll('"', '');
|
||||
|
||||
@@ -357,6 +357,9 @@
|
||||
<li>
|
||||
<a href="maintenance.php#tab_multiEdit" onclick="initializeTabs()"> <?= lang("Device_MultiEdit");?> </a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="maintenance.php#tab_initCheck" onclick="initializeTabs()"> <?= lang("Maintenance_InitCheck");?> </a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
1496
front/php/templates/language/ar_ar.json
Executable file → Normal file
8
front/php/templates/language/ca_ca.json
Executable file → Normal file
@@ -211,6 +211,7 @@
|
||||
"Device_TableHead_AlertDown": "Cancel·lar alerta",
|
||||
"Device_TableHead_Connected_Devices": "Connexions",
|
||||
"Device_TableHead_CustomProps": "Props / Accions",
|
||||
"Device_TableHead_FQDN": "",
|
||||
"Device_TableHead_Favorite": "Favorit",
|
||||
"Device_TableHead_FirstSession": "Primera Sessió",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -358,6 +359,11 @@
|
||||
"Maint_PurgeLog": "Registre de purga",
|
||||
"Maint_RestartServer": "Reinici del servidor",
|
||||
"Maint_Restart_Server_noti_text": "Estàs segur que vols reiniciar el servidor backend? Això pot causar incongruència a l'aplicació. Abans fes còpia de seguretat de la vostra configuració. <br/> <br/> Nota: Això pot durar uns quants minuts.",
|
||||
"Maintenance_InitCheck": "",
|
||||
"Maintenance_InitCheck_Checking": "",
|
||||
"Maintenance_InitCheck_QuickSetupGuide": "",
|
||||
"Maintenance_InitCheck_Success": "",
|
||||
"Maintenance_ReCheck": "",
|
||||
"Maintenance_Running_Version": "Versió instal·lada",
|
||||
"Maintenance_Status": "Estat",
|
||||
"Maintenance_Title": "Eines de manteniment",
|
||||
@@ -559,6 +565,8 @@
|
||||
"Presence_Shortcut_Favorites": "Favorits",
|
||||
"Presence_Shortcut_NewDevices": "Nous dispositius",
|
||||
"Presence_Title": "Detecció de dispositius",
|
||||
"REFRESH_FQDN_description": "",
|
||||
"REFRESH_FQDN_name": "",
|
||||
"REPORT_DASHBOARD_URL_description": "Aquesta URL s'utilitza com a base per generar enllaços en informes HTML (per exemple: correus electrònics). Introduïu la URL completa començant per <code>http://</code> incloent el número de port (sense barra inicial <code>/</code>).",
|
||||
"REPORT_DASHBOARD_URL_name": "URL NetAlertX",
|
||||
"REPORT_ERROR": "Si us plau, introdueix dins de la caixa de text els caràcters que veu a la imatge de sota. Això és requerit per evitar enviaments automàtics",
|
||||
|
||||
@@ -211,6 +211,7 @@
|
||||
"Device_TableHead_AlertDown": "",
|
||||
"Device_TableHead_Connected_Devices": "",
|
||||
"Device_TableHead_CustomProps": "",
|
||||
"Device_TableHead_FQDN": "",
|
||||
"Device_TableHead_Favorite": "",
|
||||
"Device_TableHead_FirstSession": "",
|
||||
"Device_TableHead_GUID": "",
|
||||
@@ -358,6 +359,11 @@
|
||||
"Maint_PurgeLog": "",
|
||||
"Maint_RestartServer": "",
|
||||
"Maint_Restart_Server_noti_text": "",
|
||||
"Maintenance_InitCheck": "",
|
||||
"Maintenance_InitCheck_Checking": "",
|
||||
"Maintenance_InitCheck_QuickSetupGuide": "",
|
||||
"Maintenance_InitCheck_Success": "",
|
||||
"Maintenance_ReCheck": "",
|
||||
"Maintenance_Running_Version": "",
|
||||
"Maintenance_Status": "",
|
||||
"Maintenance_Title": "",
|
||||
@@ -559,6 +565,8 @@
|
||||
"Presence_Shortcut_Favorites": "",
|
||||
"Presence_Shortcut_NewDevices": "",
|
||||
"Presence_Title": "",
|
||||
"REFRESH_FQDN_description": "",
|
||||
"REFRESH_FQDN_name": "",
|
||||
"REPORT_DASHBOARD_URL_description": "",
|
||||
"REPORT_DASHBOARD_URL_name": "",
|
||||
"REPORT_ERROR": "",
|
||||
@@ -742,4 +750,4 @@
|
||||
"settings_update_item_warning": "",
|
||||
"test_event_icon": "",
|
||||
"test_event_tooltip": ""
|
||||
}
|
||||
}
|
||||
@@ -223,6 +223,7 @@
|
||||
"Device_TableHead_AlertDown": "Alarm aus",
|
||||
"Device_TableHead_Connected_Devices": "Verbindungen",
|
||||
"Device_TableHead_CustomProps": "Eigenschaften / Aktionen",
|
||||
"Device_TableHead_FQDN": "",
|
||||
"Device_TableHead_Favorite": "Favorit",
|
||||
"Device_TableHead_FirstSession": "Erste Sitzung",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -384,24 +385,29 @@
|
||||
"Maint_PurgeLog": "Protokoll bereinigen",
|
||||
"Maint_RestartServer": "Server neu starten",
|
||||
"Maint_Restart_Server_noti_text": "Soll der Backend-Server wirklich neu gestartet werden? Das könnte Instabilitäten verursachen. Vorher ein Backup erstellen. <br/><br/>Hinweis: Das kann einige Minuten dauern.",
|
||||
"Maintenance_InitCheck": "",
|
||||
"Maintenance_InitCheck_Checking": "",
|
||||
"Maintenance_InitCheck_QuickSetupGuide": "",
|
||||
"Maintenance_InitCheck_Success": "",
|
||||
"Maintenance_ReCheck": "Wiederhole Check",
|
||||
"Maintenance_Running_Version": "Installierte Version",
|
||||
"Maintenance_Status": "Status",
|
||||
"Maintenance_Title": "Wartungswerkzeuge",
|
||||
"Maintenance_Tool_DownloadConfig": "Einstellungen exportieren",
|
||||
"Maintenance_Tool_DownloadConfig_text": "",
|
||||
"Maintenance_Tool_DownloadWorkflows": "",
|
||||
"Maintenance_Tool_DownloadWorkflows_text": "",
|
||||
"Maintenance_Tool_ExportCSV": "CSV Export",
|
||||
"Maintenance_Tool_ExportCSV_noti": "CSV Export",
|
||||
"Maintenance_Tool_DownloadConfig_text": "Download eines Voll-Backup deiner Einstellungen. Konfiguration gespeichert in <code>app.conf</code> Datei.",
|
||||
"Maintenance_Tool_DownloadWorkflows": "Workflows Export",
|
||||
"Maintenance_Tool_DownloadWorkflows_text": "Download eines Voll-Backups deiner Worksflows. Gespeichert in <code>workflows.json</code> Datei.",
|
||||
"Maintenance_Tool_ExportCSV": "Export Geräte (csv)",
|
||||
"Maintenance_Tool_ExportCSV_noti": "Geräte Export (csv)",
|
||||
"Maintenance_Tool_ExportCSV_noti_text": "Sind Sie sich sicher, dass Sie die CSV-Datei erstellen wollen?",
|
||||
"Maintenance_Tool_ExportCSV_text": "Generiere eine CSV-Datei (comma separated values) mit einer Liste aller Geräte und deren Beziehungen zwischen Netzwerkknoten und verbundenen Geräten. Dies kann auch durch das Besuchen der URL <code>your NetAlertX url/php/server/devices.php?action=ExportCSV</code> oder durch Aktivieren des <a href=\"settings.php#CSVBCKP_header\">CSV-Backups</a> ausgelöst werden.",
|
||||
"Maintenance_Tool_ImportCSV": "CSV Import",
|
||||
"Maintenance_Tool_ImportCSV_noti": "CSV Import",
|
||||
"Maintenance_Tool_ImportCSV_noti_text": "Sind Sie sich sicher, dass Sie die CSV-Datei importieren wollen? Dies wird <b>alle Geräte in der Datenbank überschreiben</b>.",
|
||||
"Maintenance_Tool_ImportCSV_text": "Machen Sie ein Backup, bevor Sie diese Funktion nutzen. Importiere eine CSV-Datei (comma separated values) mit einer Liste aller Geräte und deren Beziehungen zwischen Netzwerkknoten und verbundenen Geräten. Um dies zu tun platziere die <b>devices.csv</b> benannte CSV-Datei in deinen <b>/config</b> Ordner.",
|
||||
"Maintenance_Tool_ImportConfig_noti": "",
|
||||
"Maintenance_Tool_ImportPastedCSV": "CSV-Import (Einfügen)",
|
||||
"Maintenance_Tool_ImportPastedCSV_noti_text": "",
|
||||
"Maintenance_Tool_ImportCSV": "Geräte Import (csv)",
|
||||
"Maintenance_Tool_ImportCSV_noti": "Geräte Import (csv)",
|
||||
"Maintenance_Tool_ImportCSV_noti_text": "Sind Sie sich sicher, dass Sie die CSV-Datei importieren wollen? Dies wird alle Geräte in der Datenbank <b>überschreiben</b>.",
|
||||
"Maintenance_Tool_ImportCSV_text": "Mache ein Backup, bevor Du diese Funktion nutzt. Importiere eine CSV-Datei (comma separated values) mit einer Liste aller Geräte und deren Beziehungen zwischen Netzwerkknoten und verbundenen Geräten. Um dies zu tun platziere die <b>devices.csv</b> benannte CSV-Datei in deinen <b>/config</b> Ordner.",
|
||||
"Maintenance_Tool_ImportConfig_noti": "Einstellungen importieren (app.conf)",
|
||||
"Maintenance_Tool_ImportPastedCSV": "Geräte importieren (csv) (einfügen)",
|
||||
"Maintenance_Tool_ImportPastedCSV_noti_text": "Bist Du dir sicher, dass Du die eingefügte CSV importieren willst? Es werden alle Geräte in deiner Datenbank <b>überschrieben</b>.",
|
||||
"Maintenance_Tool_ImportPastedCSV_text": "",
|
||||
"Maintenance_Tool_ImportPastedConfig": "",
|
||||
"Maintenance_Tool_ImportPastedConfig_noti_text": "",
|
||||
@@ -600,6 +606,8 @@
|
||||
"Presence_Shortcut_Favorites": "Favoriten",
|
||||
"Presence_Shortcut_NewDevices": "Neue Geräte",
|
||||
"Presence_Title": "Anwesenheit pro Gerät",
|
||||
"REFRESH_FQDN_description": "",
|
||||
"REFRESH_FQDN_name": "",
|
||||
"REPORT_APPRISE_description": "Enable sending notifications via <a target=\"_blank\" href=\"https://hub.docker.com/r/caronc/apprise\">Apprise</a>.",
|
||||
"REPORT_APPRISE_name": "Enable Apprise",
|
||||
"REPORT_DASHBOARD_URL_description": "Diese URL wird als Basis fürs Erstellen von Links in E-Mails genutzt. Geben Sie die gesamte URL startend mit <code>http://</code> inklusive der genutzten Portnummer ein (keinen nachfolgenden Schrägstrich <code>/</code> nutzen).",
|
||||
|
||||
12
front/php/templates/language/en_us.json
Executable file → Normal file
@@ -194,7 +194,7 @@
|
||||
"DevDetail_button_Save": "Save",
|
||||
"DeviceEdit_ValidMacIp": "Enter a valid <b>Mac</b> and <b>IP</b> address.",
|
||||
"Device_MultiEdit": "Multi-edit",
|
||||
"Device_MultiEdit_Backup": "Careful, entering wrong values below will break your setup. Please backup your database or Devices configuration first (<a href=\"php/server/devices.php?action=ExportCSV\">click to download <i class=\"fa-solid fa-download fa-bounce\"></i></a>). Read how to recover Devices from this file in the <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/BACKUPS.md#scenario-2-corrupted-database\" target=\"_blank\">Backups documentation</a>.",
|
||||
"Device_MultiEdit_Backup": "Careful, entering wrong values below will break your setup. Please backup your database or Devices configuration first (<a href=\"php/server/devices.php?action=ExportCSV\">click to download <i class=\"fa-solid fa-download fa-bounce\"></i></a>). Read how to recover Devices from this file in the <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/BACKUPS.md#scenario-2-corrupted-database\" target=\"_blank\">Backups documentation</a>. In order to apply your changes click the <b>Save<i class=\"fa-solid fa-save\"></i></b> icon on each field you want to update.",
|
||||
"Device_MultiEdit_Fields": "Edit fields:",
|
||||
"Device_MultiEdit_MassActions": "Mass actions:",
|
||||
"Device_MultiEdit_Tooltip": "Careful. Clicking this will apply the value on the left to all devices selected above.",
|
||||
@@ -211,6 +211,7 @@
|
||||
"Device_TableHead_AlertDown": "Alert Down",
|
||||
"Device_TableHead_Connected_Devices": "Connections",
|
||||
"Device_TableHead_CustomProps": "Props / Actions",
|
||||
"Device_TableHead_FQDN": "FQDN",
|
||||
"Device_TableHead_Favorite": "Favorite",
|
||||
"Device_TableHead_FirstSession": "First Session",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -358,6 +359,11 @@
|
||||
"Maint_PurgeLog": "Purge log",
|
||||
"Maint_RestartServer": "Restart server",
|
||||
"Maint_Restart_Server_noti_text": "Are you sure you want to restart the backend server? This may casue app inconsistency. Backup your setup first. <br/> <br/> Note: This may take a few minutes.",
|
||||
"Maintenance_InitCheck": "Init Check",
|
||||
"Maintenance_InitCheck_Checking": "Checking...",
|
||||
"Maintenance_InitCheck_QuickSetupGuide": "Make sure you followed the <a href=\"https://jokob-sk.github.io/NetAlertX/INITIAL_SETUP/\" target=\"_blank\">quick setup guide</a>.",
|
||||
"Maintenance_InitCheck_Success": "Application initialized succesfully!",
|
||||
"Maintenance_ReCheck": "Retry Check",
|
||||
"Maintenance_Running_Version": "Installed version",
|
||||
"Maintenance_Status": "Status",
|
||||
"Maintenance_Title": "Maintenance tools",
|
||||
@@ -559,6 +565,8 @@
|
||||
"Presence_Shortcut_Favorites": "Favorites",
|
||||
"Presence_Shortcut_NewDevices": "New Devices",
|
||||
"Presence_Title": "Presence by Device",
|
||||
"REFRESH_FQDN_description": "Rescans all devices and refreshes their Fully Qualified Domain Name (FQDN). If disabled, only devices without a known name are scanned to improve performance. In this case, FQDN is updated only during initial device discovery.",
|
||||
"REFRESH_FQDN_name": "Refresh FQDN",
|
||||
"REPORT_DASHBOARD_URL_description": "This URL is used as the base for generating links in HTML reports (e.g.: emails). Enter full URL starting with <code>http://</code> including the port number (no trailing slash <code>/</code>).",
|
||||
"REPORT_DASHBOARD_URL_name": "NetAlertX URL",
|
||||
"REPORT_ERROR": "The page you are looking for is temporarily unavailable, please try again after a few seconds",
|
||||
@@ -742,4 +750,4 @@
|
||||
"settings_update_item_warning": "Update the value below. Be careful to follow the previous format. <b>Validation is not performed.</b>",
|
||||
"test_event_icon": "fa-vial-circle-check",
|
||||
"test_event_tooltip": "Save your changes at first before you test your settings."
|
||||
}
|
||||
}
|
||||
|
||||
8
front/php/templates/language/es_es.json
Executable file → Normal file
@@ -221,6 +221,7 @@
|
||||
"Device_TableHead_AlertDown": "Alerta desactivada",
|
||||
"Device_TableHead_Connected_Devices": "Conexiones",
|
||||
"Device_TableHead_CustomProps": "Propiedades / Acciones",
|
||||
"Device_TableHead_FQDN": "",
|
||||
"Device_TableHead_Favorite": "Favorito",
|
||||
"Device_TableHead_FirstSession": "1ra. sesión",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -382,6 +383,11 @@
|
||||
"Maint_PurgeLog": "Purgar los registros",
|
||||
"Maint_RestartServer": "Restablecer el servidor",
|
||||
"Maint_Restart_Server_noti_text": "¿Estás seguro de que desea reiniciar el servidor backend? Esto puede causar inconsistencia en la aplicación. Primero haga una copia de seguridad de su configuración.<br/> <br/> Nota: Esto puede tardar unos minutos.",
|
||||
"Maintenance_InitCheck": "",
|
||||
"Maintenance_InitCheck_Checking": "",
|
||||
"Maintenance_InitCheck_QuickSetupGuide": "",
|
||||
"Maintenance_InitCheck_Success": "",
|
||||
"Maintenance_ReCheck": "",
|
||||
"Maintenance_Running_Version": "Versión instalada",
|
||||
"Maintenance_Status": "Situación",
|
||||
"Maintenance_Title": "Herramientas de mantenimiento",
|
||||
@@ -598,6 +604,8 @@
|
||||
"Presence_Shortcut_Favorites": "Favorito(s)",
|
||||
"Presence_Shortcut_NewDevices": "Nuevo(s)",
|
||||
"Presence_Title": "Historial por dispositivo",
|
||||
"REFRESH_FQDN_description": "",
|
||||
"REFRESH_FQDN_name": "",
|
||||
"REPORT_APPRISE_description": "Habilitar el envío de notificaciones a través de <a target=\"_blank\" href=\"https://hub.docker.com/r/caronc/apprise\">Apprise</a>.",
|
||||
"REPORT_APPRISE_name": "Habilitar Apprise",
|
||||
"REPORT_DASHBOARD_URL_description": "Esta URL se utiliza como base para generar enlaces en los correos electrónicos. Ingrese la URL completa que comienza con <code>http://</code>, incluido el número de puerto (sin barra inclinada al final <code>/</code>).",
|
||||
|
||||
10
front/php/templates/language/fr_fr.json
Executable file → Normal file
@@ -194,7 +194,7 @@
|
||||
"DevDetail_button_Save": "Enregistrer",
|
||||
"DeviceEdit_ValidMacIp": "Renseigner une adresse <b>Mac</b> et une adresse <b>IP</b> valides.",
|
||||
"Device_MultiEdit": "Édition multiple",
|
||||
"Device_MultiEdit_Backup": "Attention, renseigner des valeurs non cohérentes ci-dessous peut bloquer votre paramétrage. Veillez à faire une sauvegarde de votre base de données ou de la configuration de vos appareils en premier lieu (<a href=\"php/server/devices.php?action=ExportCSV\">clisuer ici pour la télécharger <i class=\"fa-solid fa-download fa-bounce\"></i></a>). Renseignez-vous sur comment remettre les appareils depuis ce fichier via la <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/BACKUPS.md#scenario-2-corrupted-database\" target=\"_blank\">documentation des sauvegardes</a>.",
|
||||
"Device_MultiEdit_Backup": "Attention, renseigner des valeurs non cohérentes ci-dessous peut bloquer votre paramétrage. Veillez à faire une sauvegarde de votre base de données ou de la configuration de vos appareils en premier lieu (<a href=\"php/server/devices.php?action=ExportCSV\">clisuer ici pour la télécharger <i class=\"fa-solid fa-download fa-bounce\"></i></a>). Renseignez-vous sur comment remettre les appareils depuis ce fichier via la <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/BACKUPS.md#scenario-2-corrupted-database\" target=\"_blank\">documentation des sauvegardes</a>. Afin d'enregistrer les changements, cliquer sur l'icône <b>Sauvegarder<i class=\"fa-solid fa-save\"></i></b> sur chaque champ que vous voulez mettre à jour.",
|
||||
"Device_MultiEdit_Fields": "Champs modifiables :",
|
||||
"Device_MultiEdit_MassActions": "Actions en masse :",
|
||||
"Device_MultiEdit_Tooltip": "Attention. Ceci va appliquer la valeur de gauche à tous les appareils sélectionnés au-dessus.",
|
||||
@@ -211,6 +211,7 @@
|
||||
"Device_TableHead_AlertDown": "Alerter si En panne",
|
||||
"Device_TableHead_Connected_Devices": "Connexions",
|
||||
"Device_TableHead_CustomProps": "Champs / Actions",
|
||||
"Device_TableHead_FQDN": "Nom de domaine FQDN",
|
||||
"Device_TableHead_Favorite": "Favori",
|
||||
"Device_TableHead_FirstSession": "Première session",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -358,6 +359,11 @@
|
||||
"Maint_PurgeLog": "Nettoyer les logs",
|
||||
"Maint_RestartServer": "Relancer le serveur",
|
||||
"Maint_Restart_Server_noti_text": "Êtes-vous sûr de vouloir relancer le serveur back-end ? Cela peut causer des incohérences avec l'application. Sauvegarder vos paramètres en premier lieu. <br/> <br/> Remarque : cela peut prendre quelques minutes.",
|
||||
"Maintenance_InitCheck": "Vérification initiale",
|
||||
"Maintenance_InitCheck_Checking": "Vérification...",
|
||||
"Maintenance_InitCheck_QuickSetupGuide": "Assurez-vous de suivre le <a href=\"https://jokob-sk.github.io/NetAlertX/INITIAL_SETUP/\" target=\"_blank\">guide de démarrage rapide</a>.",
|
||||
"Maintenance_InitCheck_Success": "Application initialisée avec succès !",
|
||||
"Maintenance_ReCheck": "Relancer la vérification",
|
||||
"Maintenance_Running_Version": "Version installée",
|
||||
"Maintenance_Status": "État",
|
||||
"Maintenance_Title": "Outils de maintenance",
|
||||
@@ -559,6 +565,8 @@
|
||||
"Presence_Shortcut_Favorites": "Favoris",
|
||||
"Presence_Shortcut_NewDevices": "Nouveaux appareils",
|
||||
"Presence_Title": "Présence par appareil",
|
||||
"REFRESH_FQDN_description": "Rescanne tous les appareils et met à jour leur nom de domaine complètement qualifié (FQDN). Si désactivé, seul les appareils sans nom connu sont scannés, pour améliorer les performances. Dans ce cas, les noms de domaine FQDN sont mis à jour uniquement durant la découverte initiale des appareils.",
|
||||
"REFRESH_FQDN_name": "Rafraîchir les noms de domaine FQDN",
|
||||
"REPORT_DASHBOARD_URL_description": "Cette URL est utilisée comme base pour générer les liens des rapports HTML (par ex. les courriels). Renseignez l'adresse complète, commençant par <code>http://</code> et incluznt le numero de port (sans slash <code>/</code> à la fin).",
|
||||
"REPORT_DASHBOARD_URL_name": "URL de NetAlertX",
|
||||
"REPORT_ERROR": "La page que vous cherchez est temporairement indisponible. Merci de réessayer dans quelques secondes",
|
||||
|
||||
10
front/php/templates/language/it_it.json
Executable file → Normal file
@@ -194,7 +194,7 @@
|
||||
"DevDetail_button_Save": "Salva",
|
||||
"DeviceEdit_ValidMacIp": "Inserisci un indirizzo <b>Mac</b> e un indirizzo <b>IP</b> validi.",
|
||||
"Device_MultiEdit": "Modifica multipla",
|
||||
"Device_MultiEdit_Backup": "Attento, l'inserimento di valori errati di seguito interromperà la configurazione. Effettua prima il backup del database o della configurazione dei dispositivi (<a href=\"php/server/devices.php?action=ExportCSV\">fai clic per scaricare <i class=\"fa-solid fa-download fa-bounce\"></i> </a>). Leggi come ripristinare i dispositivi da questo file nella <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/BACKUPS.md#scenario-2-corrupted-database\" target=\" _blank\">Documentazione di backup</a>.",
|
||||
"Device_MultiEdit_Backup": "Attento, l'inserimento di valori errati di seguito interromperà la configurazione. Effettua prima il backup del database o della configurazione dei dispositivi (<a href=\"php/server/devices.php?action=ExportCSV\">fai clic per scaricare <i class=\"fa-solid fa-download fa-bounce\"></i> </a>). Leggi come ripristinare i dispositivi da questo file nella <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/BACKUPS.md#scenario-2-corrupted-database\" target=\" _blank\">Documentazione di backup</a>. Per applicare le modifiche, fai clic sull'icona <b>Salva<i class=\"fa-solid fa-save\"></i></b> su ogni campo che desideri aggiornare.",
|
||||
"Device_MultiEdit_Fields": "Modifica campi:",
|
||||
"Device_MultiEdit_MassActions": "Azioni di massa:",
|
||||
"Device_MultiEdit_Tooltip": "Attento. Facendo clic verrà applicato il valore sulla sinistra a tutti i dispositivi selezionati sopra.",
|
||||
@@ -211,6 +211,7 @@
|
||||
"Device_TableHead_AlertDown": "Avviso disconnessione",
|
||||
"Device_TableHead_Connected_Devices": "Connessioni",
|
||||
"Device_TableHead_CustomProps": "Proprietà/Azioni",
|
||||
"Device_TableHead_FQDN": "FQDN",
|
||||
"Device_TableHead_Favorite": "Preferito",
|
||||
"Device_TableHead_FirstSession": "Prima sessione",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -358,6 +359,11 @@
|
||||
"Maint_PurgeLog": "Elimina log",
|
||||
"Maint_RestartServer": "Riavvia server",
|
||||
"Maint_Restart_Server_noti_text": "Sei sicuro di voler riavviare il server backend? Questo potrebbe causare incoerenze dell'app. Prima esegui il backup della tua configurazione. <br/> <br/> Nota: l'operazione potrebbe richiedere alcuni minuti.",
|
||||
"Maintenance_InitCheck": "Controllo iniziale",
|
||||
"Maintenance_InitCheck_Checking": "Controllo in corso...",
|
||||
"Maintenance_InitCheck_QuickSetupGuide": "Assicurati di aver seguito la <a href=\"https://jokob-sk.github.io/NetAlertX/INITIAL_SETUP/\" target=\"_blank\">guida di configurazione rapida</a>.",
|
||||
"Maintenance_InitCheck_Success": "Applicazione inizializzata con successo!",
|
||||
"Maintenance_ReCheck": "Riprova controllo",
|
||||
"Maintenance_Running_Version": "Versione installata",
|
||||
"Maintenance_Status": "Stato",
|
||||
"Maintenance_Title": "Strumenti di manutenzione",
|
||||
@@ -559,6 +565,8 @@
|
||||
"Presence_Shortcut_Favorites": "Preferiti",
|
||||
"Presence_Shortcut_NewDevices": "Nuovi dispositivi",
|
||||
"Presence_Title": "Presenza per dispositivo",
|
||||
"REFRESH_FQDN_description": "Esegue nuovamente la scansione di tutti i dispositivi e aggiorna il loro nome di dominio completo (FQDN). Se disabilitato, vengono scansionati solo i dispositivi senza nome noto per migliorare le prestazioni. In questo caso, l'FQDN viene aggiornato solo durante la rilevazione iniziale del dispositivo.",
|
||||
"REFRESH_FQDN_name": "Aggiorna FQDN",
|
||||
"REPORT_DASHBOARD_URL_description": "Questo URL viene utilizzato come base per generare collegamenti nei report HTML (ad esempio: e-mail). Inserisci l'URL completo che inizia con <code>http://</code> incluso il numero di porta (nessuna barra finale <code>/</code>).",
|
||||
"REPORT_DASHBOARD_URL_name": "URL NetAlertX",
|
||||
"REPORT_ERROR": "La pagina che stai cercando è momentaneamente non disponibile, riprova tra qualche secondo",
|
||||
|
||||
10
front/php/templates/language/nb_no.json
Executable file → Normal file
@@ -211,6 +211,7 @@
|
||||
"Device_TableHead_AlertDown": "",
|
||||
"Device_TableHead_Connected_Devices": "Tilkoblinger",
|
||||
"Device_TableHead_CustomProps": "",
|
||||
"Device_TableHead_FQDN": "",
|
||||
"Device_TableHead_Favorite": "Favoritt",
|
||||
"Device_TableHead_FirstSession": "Første Økt",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -358,6 +359,11 @@
|
||||
"Maint_PurgeLog": "",
|
||||
"Maint_RestartServer": "",
|
||||
"Maint_Restart_Server_noti_text": "",
|
||||
"Maintenance_InitCheck": "",
|
||||
"Maintenance_InitCheck_Checking": "",
|
||||
"Maintenance_InitCheck_QuickSetupGuide": "",
|
||||
"Maintenance_InitCheck_Success": "",
|
||||
"Maintenance_ReCheck": "",
|
||||
"Maintenance_Running_Version": "Installert versjon",
|
||||
"Maintenance_Status": "Status",
|
||||
"Maintenance_Title": "Vedlikeholdsverktøy",
|
||||
@@ -559,6 +565,8 @@
|
||||
"Presence_Shortcut_Favorites": "Favoritter",
|
||||
"Presence_Shortcut_NewDevices": "Nye enheter",
|
||||
"Presence_Title": "Tilstedeværelse etter enhet",
|
||||
"REFRESH_FQDN_description": "",
|
||||
"REFRESH_FQDN_name": "",
|
||||
"REPORT_DASHBOARD_URL_description": "Denne URL-en brukes som base for å generere lenker i HTML-rapporter (f.eks.: E -post). Skriv inn full URL som starter med <code>http://</code> inkludert portnummeret (ingen etterfølgende slash <code>/</code>).",
|
||||
"REPORT_DASHBOARD_URL_name": "NetAlertX URL",
|
||||
"REPORT_ERROR": "Siden du leter etter er midlertidig utilgjengelig, prøv igjen etter noen sekunder",
|
||||
@@ -742,4 +750,4 @@
|
||||
"settings_update_item_warning": "Oppdater verdien nedenfor. Pass på å følge forrige format. <b>Validering etterpå utføres ikke.</b>",
|
||||
"test_event_icon": "fa-vial-circle-check",
|
||||
"test_event_tooltip": "Lagre endringene først, før du tester innstillingene dine."
|
||||
}
|
||||
}
|
||||
|
||||
10
front/php/templates/language/pl_pl.json
Executable file → Normal file
@@ -211,6 +211,7 @@
|
||||
"Device_TableHead_AlertDown": "",
|
||||
"Device_TableHead_Connected_Devices": "Połączenia",
|
||||
"Device_TableHead_CustomProps": "",
|
||||
"Device_TableHead_FQDN": "",
|
||||
"Device_TableHead_Favorite": "Ulubione",
|
||||
"Device_TableHead_FirstSession": "Pierwsza Sesja",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -358,6 +359,11 @@
|
||||
"Maint_PurgeLog": "Wyczyść Logi",
|
||||
"Maint_RestartServer": "Zrestartuj serwer",
|
||||
"Maint_Restart_Server_noti_text": "Jesteś pewien, że chcesz zrestartować serwer backend? Może spowodować to niespujności w aplikacji. Najpierw utwórz backup konfiguracji. <br/> <br/> Uwaga: Może to zająć kilkla minut.",
|
||||
"Maintenance_InitCheck": "",
|
||||
"Maintenance_InitCheck_Checking": "",
|
||||
"Maintenance_InitCheck_QuickSetupGuide": "",
|
||||
"Maintenance_InitCheck_Success": "",
|
||||
"Maintenance_ReCheck": "",
|
||||
"Maintenance_Running_Version": "Zainstalowana wersja",
|
||||
"Maintenance_Status": "Status",
|
||||
"Maintenance_Title": "Narzędzia konserwacyjne",
|
||||
@@ -559,6 +565,8 @@
|
||||
"Presence_Shortcut_Favorites": "Ulubione",
|
||||
"Presence_Shortcut_NewDevices": "Nowe Urządzenia",
|
||||
"Presence_Title": "Obecność Urządzenia",
|
||||
"REFRESH_FQDN_description": "",
|
||||
"REFRESH_FQDN_name": "",
|
||||
"REPORT_DASHBOARD_URL_description": "Link jest używany jako podstawa do generowania linków dla zgłoszeń HTML (np. e-maile). Wprowadź pełen adres zaczynając od <code>http://</code> oraz dodając numer portu (bez zakańczania ukośnikiem <code>/</code>).",
|
||||
"REPORT_DASHBOARD_URL_name": "Link NetAlertX",
|
||||
"REPORT_ERROR": "Strona której szukasz jest tymczasowo niedostępna, spróbuj ponownie za kilka sekund",
|
||||
@@ -742,4 +750,4 @@
|
||||
"settings_update_item_warning": "Zaktualizuj poniższą wartość. Zachowaj ostrożność i postępuj zgodnie z poprzednim formatem. <b>Walidacja nie jest wykonywana.</b>",
|
||||
"test_event_icon": "fa-vial-circle-check",
|
||||
"test_event_tooltip": "Zapisz zmiany zanim będziesz testować swoje ustawienia."
|
||||
}
|
||||
}
|
||||
|
||||
8
front/php/templates/language/pt_br.json
Executable file → Normal file
@@ -211,6 +211,7 @@
|
||||
"Device_TableHead_AlertDown": "Alerta em baixo",
|
||||
"Device_TableHead_Connected_Devices": "Conexões",
|
||||
"Device_TableHead_CustomProps": "",
|
||||
"Device_TableHead_FQDN": "",
|
||||
"Device_TableHead_Favorite": "Favorito",
|
||||
"Device_TableHead_FirstSession": "Primeira sessão",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -358,6 +359,11 @@
|
||||
"Maint_PurgeLog": "Limpar o registo",
|
||||
"Maint_RestartServer": "Reiniciar o servidor",
|
||||
"Maint_Restart_Server_noti_text": "Tem certeza de que deseja reiniciar o servidor backend? Isso pode causar inconsistência no aplicativo. Faça backup da sua configuração primeiro. <br/> <br/> Nota: Isso pode levar alguns minutos.",
|
||||
"Maintenance_InitCheck": "",
|
||||
"Maintenance_InitCheck_Checking": "",
|
||||
"Maintenance_InitCheck_QuickSetupGuide": "",
|
||||
"Maintenance_InitCheck_Success": "",
|
||||
"Maintenance_ReCheck": "",
|
||||
"Maintenance_Running_Version": "Versão instalada",
|
||||
"Maintenance_Status": "Situação",
|
||||
"Maintenance_Title": "Ferramentas de manutenção",
|
||||
@@ -559,6 +565,8 @@
|
||||
"Presence_Shortcut_Favorites": "",
|
||||
"Presence_Shortcut_NewDevices": "",
|
||||
"Presence_Title": "",
|
||||
"REFRESH_FQDN_description": "",
|
||||
"REFRESH_FQDN_name": "",
|
||||
"REPORT_DASHBOARD_URL_description": "",
|
||||
"REPORT_DASHBOARD_URL_name": "",
|
||||
"REPORT_ERROR": "",
|
||||
|
||||
@@ -211,6 +211,7 @@
|
||||
"Device_TableHead_AlertDown": "Оповещение о сост. ВЫКЛ",
|
||||
"Device_TableHead_Connected_Devices": "Соединения",
|
||||
"Device_TableHead_CustomProps": "Свойства / Действия",
|
||||
"Device_TableHead_FQDN": "FQDN",
|
||||
"Device_TableHead_Favorite": "Избранное",
|
||||
"Device_TableHead_FirstSession": "Первый сеанс",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -358,6 +359,11 @@
|
||||
"Maint_PurgeLog": "Очистить журнал",
|
||||
"Maint_RestartServer": "Перезапустить сервер",
|
||||
"Maint_Restart_Server_noti_text": "Вы уверены, что хотите перезапустить внутренний сервер? Это может привести к несогласованности работы приложения. Сначала создайте резервную копию настроек. <br/> <br/> Примечание: Это может занять несколько минут.",
|
||||
"Maintenance_InitCheck": "Инициализация проверки",
|
||||
"Maintenance_InitCheck_Checking": "Проверяется...",
|
||||
"Maintenance_InitCheck_QuickSetupGuide": "Убедитесь, что вы следовали быстрому руководству по настройке <a href=\"https://jokob-sk.github.io/NetAlertX/INITIAL_SETUP/\" target=\"_blank\"></a>.",
|
||||
"Maintenance_InitCheck_Success": "Приложение инициализировано успешно!",
|
||||
"Maintenance_ReCheck": "Повторить проверку",
|
||||
"Maintenance_Running_Version": "Установленная версия",
|
||||
"Maintenance_Status": "Статус",
|
||||
"Maintenance_Title": "Инструменты обслуживания",
|
||||
@@ -559,6 +565,8 @@
|
||||
"Presence_Shortcut_Favorites": "Избранные",
|
||||
"Presence_Shortcut_NewDevices": "Новые устройства",
|
||||
"Presence_Title": "Присутствие по устройству",
|
||||
"REFRESH_FQDN_description": "Повторное сканирование всех устройств и обновление их полного доменного имени (FQDN). Если эта функция отключена, то для повышения производительности сканируются только устройства без известного имени. В этом случае FQDN обновляется только при первоначальном обнаружении устройства.",
|
||||
"REFRESH_FQDN_name": "Обновить FQDN",
|
||||
"REPORT_DASHBOARD_URL_description": "Этот URL-адрес используется в качестве основы для создания ссылок в отчетах HTML (например, в электронных письмах). Введите полный URL-адрес, начинающийся с <code>http://</code>, включая номер порта (без косой черты <code>/</code>).",
|
||||
"REPORT_DASHBOARD_URL_name": "NetAlertX URL",
|
||||
"REPORT_ERROR": "Страница, которую вы ищете, временно недоступна, повторите попытку через несколько секунд",
|
||||
|
||||
8
front/php/templates/language/tr_tr.json
Executable file → Normal file
@@ -211,6 +211,7 @@
|
||||
"Device_TableHead_AlertDown": "Çalışmama Alarmı",
|
||||
"Device_TableHead_Connected_Devices": "Bağlantılar",
|
||||
"Device_TableHead_CustomProps": "Özellikler / Eylemler",
|
||||
"Device_TableHead_FQDN": "",
|
||||
"Device_TableHead_Favorite": "Favori",
|
||||
"Device_TableHead_FirstSession": "İlk Oturum",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -358,6 +359,11 @@
|
||||
"Maint_PurgeLog": "Kayıtları Sil",
|
||||
"Maint_RestartServer": "Sunucuyu Yeniden Başlat",
|
||||
"Maint_Restart_Server_noti_text": "Arka uç sunucusunu yeniden başlatmak istediğinizden emin misiniz? Bu, uygulama tutarsızlıklarına yol açabilir. Önce yapılandırmanızı yedekleyin. <br/> <br/> Not: Bu işlem birkaç dakika sürebilir.",
|
||||
"Maintenance_InitCheck": "",
|
||||
"Maintenance_InitCheck_Checking": "",
|
||||
"Maintenance_InitCheck_QuickSetupGuide": "",
|
||||
"Maintenance_InitCheck_Success": "",
|
||||
"Maintenance_ReCheck": "",
|
||||
"Maintenance_Running_Version": "Yüklenmiş sürüm",
|
||||
"Maintenance_Status": "Durum",
|
||||
"Maintenance_Title": "Bakım Araçları",
|
||||
@@ -559,6 +565,8 @@
|
||||
"Presence_Shortcut_Favorites": "Favoriler",
|
||||
"Presence_Shortcut_NewDevices": "Yeni Cihazlar",
|
||||
"Presence_Title": "",
|
||||
"REFRESH_FQDN_description": "",
|
||||
"REFRESH_FQDN_name": "",
|
||||
"REPORT_DASHBOARD_URL_description": "",
|
||||
"REPORT_DASHBOARD_URL_name": "",
|
||||
"REPORT_ERROR": "",
|
||||
|
||||
10
front/php/templates/language/uk_ua.json
Executable file → Normal file
@@ -194,7 +194,7 @@
|
||||
"DevDetail_button_Save": "зберегти",
|
||||
"DeviceEdit_ValidMacIp": "Введіть дійсну адресу <b>Mac</b> та <b>IP</b>.",
|
||||
"Device_MultiEdit": "Мультиредагування",
|
||||
"Device_MultiEdit_Backup": "Обережно, введення неправильних значень нижче порушить налаштування. Спершу створіть резервну копію вашої бази даних або конфігурації пристроїв (<a href=\"php/server/devices.php?action=ExportCSV\">натисніть, щоб завантажити <i class=\"fa-solid fa-download fa-bounce\"></i> </a>). Прочитайте, як відновити пристрої з цього файлу, у <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/BACKUPS.md#scenario-2-corrupted-database\" target=\" _blank\">Документація резервних копій</a>.",
|
||||
"Device_MultiEdit_Backup": "Обережно, введення неправильних значень нижче призведе до порушення роботи налаштувань. Спочатку створіть резервну копію бази даних або конфігурації пристроїв (<a href=\"php/server/devices.php?action=ExportCSV\">натисніть, щоб завантажити <i class=\"fa-solid fa-download fa-bounce\"></i></a>). Прочитайте, як відновити пристрої з цього файлу, у <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/BACKUPS.md#scenario-2-corrupted-database\" target=\"_blank\">документації щодо резервних копій</a>. Щоб застосувати зміни, натисніть значок <b>Зберегти<i class=\"fa-solid fa-save\"></i></b> у кожному полі, яке потрібно оновити.",
|
||||
"Device_MultiEdit_Fields": "Редагувати поля:",
|
||||
"Device_MultiEdit_MassActions": "Масові акції:",
|
||||
"Device_MultiEdit_Tooltip": "Обережно. Якщо натиснути це, значення зліва буде застосовано до всіх пристроїв, вибраних вище.",
|
||||
@@ -211,6 +211,7 @@
|
||||
"Device_TableHead_AlertDown": "Сповіщення вниз",
|
||||
"Device_TableHead_Connected_Devices": "Зв'язки",
|
||||
"Device_TableHead_CustomProps": "Реквізит / дії",
|
||||
"Device_TableHead_FQDN": "FQDN",
|
||||
"Device_TableHead_Favorite": "улюблений",
|
||||
"Device_TableHead_FirstSession": "Перша сесія",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -358,6 +359,11 @@
|
||||
"Maint_PurgeLog": "Журнал очищення",
|
||||
"Maint_RestartServer": "Перезапустіть сервер",
|
||||
"Maint_Restart_Server_noti_text": "Ви впевнені, що бажаєте перезапустити внутрішній сервер? Це може спричинити неузгодженість програми. Спершу створіть резервну копію налаштувань. <br/> <br/> Примітка. Це може зайняти кілька хвилин.",
|
||||
"Maintenance_InitCheck": "Перевірка ініціалізації",
|
||||
"Maintenance_InitCheck_Checking": "Перевірка...",
|
||||
"Maintenance_InitCheck_QuickSetupGuide": "Переконайтеся, що ви дотримувалися інструкцій у <a href=\"https://jokob-sk.github.io/NetAlertX/INITIAL_SETUP/\" target=\"_blank\">короткому посібнику з налаштування</a>.",
|
||||
"Maintenance_InitCheck_Success": "Застосунок успішно ініціалізовано!",
|
||||
"Maintenance_ReCheck": "Повторна спроба перевірки",
|
||||
"Maintenance_Running_Version": "Встановлена версія",
|
||||
"Maintenance_Status": "Статус",
|
||||
"Maintenance_Title": "Інструменти обслуговування",
|
||||
@@ -559,6 +565,8 @@
|
||||
"Presence_Shortcut_Favorites": "Вибране",
|
||||
"Presence_Shortcut_NewDevices": "Нові пристрої",
|
||||
"Presence_Title": "Присутність за пристроєм",
|
||||
"REFRESH_FQDN_description": "Повторно сканує всі пристрої та оновлює їхнє повністю кваліфіковане доменне ім'я (FQDN). Якщо вимкнено, для покращення продуктивності скануються лише пристрої без відомого імені. У цьому випадку повне доменне ім'я (FQDN) оновлюється лише під час початкового виявлення пристрою.",
|
||||
"REFRESH_FQDN_name": "Оновити FQDN",
|
||||
"REPORT_DASHBOARD_URL_description": "Ця URL-адреса використовується як основа для створення посилань у звітах HTML (наприклад, електронних листах). Введіть повну URL-адресу, починаючи з <code>http://</code>, включаючи номер порту (без скісної риски <code>/</code>).",
|
||||
"REPORT_DASHBOARD_URL_name": "URL-адреса NetAlertX",
|
||||
"REPORT_ERROR": "Сторінка, яку ви шукаєте, тимчасово недоступна, спробуйте ще раз через кілька секунд",
|
||||
|
||||
18
front/php/templates/language/zh_cn.json
Executable file → Normal file
@@ -59,16 +59,16 @@
|
||||
"BackDevices_Restore_okay": "已成功恢复。",
|
||||
"BackDevices_darkmode_disabled": "暗黑模式已禁用",
|
||||
"BackDevices_darkmode_enabled": "已启用暗黑模式",
|
||||
"CLEAR_NEW_FLAG_description": "",
|
||||
"CLEAR_NEW_FLAG_name": "",
|
||||
"CustProps_cant_remove": "",
|
||||
"CLEAR_NEW_FLAG_description": "若启用( <code>0</code> 为禁用),当设备 <b>首次会话</b> 时间超出设定时限(以小时计)时,其 <b>New Device</b> 标记将自动取消。",
|
||||
"CLEAR_NEW_FLAG_name": "清除新标记",
|
||||
"CustProps_cant_remove": "无法移除,至少需要保留一个属性。",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "这是维护设置。它指定将保留的事件条目的天数。所有较旧的事件将被定期删除。也适用于插件事件历史记录。",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "删除早于",
|
||||
"DISCOVER_PLUGINS_description": "",
|
||||
"DISCOVER_PLUGINS_description": "禁用此选项可加快初始化和设置保存的速度。当禁用时,插件不会被发现,并且您无法将新插件添加到 <code>LOADED_PLUGINS</code>设置中。",
|
||||
"DISCOVER_PLUGINS_name": "",
|
||||
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> 从设备复制详细信息",
|
||||
"DevDetail_Copy_Device_Tooltip": "从下拉列表中复制设备的详细信息。此页面上的所有内容都将被覆盖",
|
||||
"DevDetail_CustomProperties_Title": "",
|
||||
"DevDetail_CustomProperties_Title": "自定义属性",
|
||||
"DevDetail_CustomProps_reset_info": "",
|
||||
"DevDetail_DisplayFields_Title": "",
|
||||
"DevDetail_EveandAl_AlertAllEvents": "提醒所有事件",
|
||||
@@ -211,6 +211,7 @@
|
||||
"Device_TableHead_AlertDown": "",
|
||||
"Device_TableHead_Connected_Devices": "链接",
|
||||
"Device_TableHead_CustomProps": "",
|
||||
"Device_TableHead_FQDN": "",
|
||||
"Device_TableHead_Favorite": "收藏",
|
||||
"Device_TableHead_FirstSession": "加入",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -358,6 +359,11 @@
|
||||
"Maint_PurgeLog": "清除日志",
|
||||
"Maint_RestartServer": "重启服务器",
|
||||
"Maint_Restart_Server_noti_text": "您确定要重新启动后端服务器吗?这可能会导致应用程序不一致。请先备份您的设置。<br/> <br/> 注意:这可能需要几分钟。",
|
||||
"Maintenance_InitCheck": "",
|
||||
"Maintenance_InitCheck_Checking": "",
|
||||
"Maintenance_InitCheck_QuickSetupGuide": "",
|
||||
"Maintenance_InitCheck_Success": "",
|
||||
"Maintenance_ReCheck": "",
|
||||
"Maintenance_Running_Version": "安装版本",
|
||||
"Maintenance_Status": "状态",
|
||||
"Maintenance_Title": "维护工具",
|
||||
@@ -559,6 +565,8 @@
|
||||
"Presence_Shortcut_Favorites": "收藏夹",
|
||||
"Presence_Shortcut_NewDevices": "新设备",
|
||||
"Presence_Title": "按设备显示状态",
|
||||
"REFRESH_FQDN_description": "",
|
||||
"REFRESH_FQDN_name": "",
|
||||
"REPORT_DASHBOARD_URL_description": "此 URL 用作生成 HTML 报告(例如电子邮件)中链接的基础。输入以 <code>http://</code> 开头的完整 URL,包括端口号(无尾部斜杠 <code>/</code>)。",
|
||||
"REPORT_DASHBOARD_URL_name": "NetAlertX 网址",
|
||||
"REPORT_ERROR": "您正在浏览的页面暂时不可用,请稍后重试",
|
||||
|
||||
@@ -71,7 +71,7 @@ if ($nax_WebProtection == 'true') {
|
||||
$isLoggedIn = isset($_SESSION['login']) && $_SESSION['login'] == 1;
|
||||
|
||||
// Determine if the user should be redirected
|
||||
if ($isLoggedIn || $isLogonPage || (isset($_COOKIE[COOKIE_SAVE_LOGIN_NAME]) && $nax_Password == $_COOKIE[COOKIE_SAVE_LOGIN_NAME])) {
|
||||
if ($isLoggedIn || $isLogonPage || (isset($_COOKIE[COOKIE_SAVE_LOGIN_NAME]) && $nax_Password === $_COOKIE[COOKIE_SAVE_LOGIN_NAME])) {
|
||||
// Logged in or stay on this page if we are on the index.php already
|
||||
} else {
|
||||
// We need to redirect
|
||||
|
||||
@@ -11,3 +11,31 @@ You need to bring your own separate Apprise instance to use this publisher gatew
|
||||
- Go to settings and fill in relevant details.
|
||||
- Use the Apprise container's URL in the `APPRISE_HOST` setting.
|
||||
|
||||
## Examples
|
||||
|
||||
### Telegram
|
||||
|
||||

|
||||
|
||||
#### Troubleshooting
|
||||
|
||||
1. Replace `<bottoken>` and `<chatid>` with your values.
|
||||
|
||||
2. Test telegram notification in browser
|
||||
|
||||
```
|
||||
https://api.telegram.org/bot<bottoken>/sendMessage?chat_id=<chatid>&text=%40%40TEXT%40%40
|
||||
```
|
||||
3. Test apprise notification in console (replace `192.168.1.2:9999` with your apprise ip and port)
|
||||
|
||||
```
|
||||
curl -X POST -d '{"urls":"tgram://<bottoken>/<chatid>","body":"test body from curl","title":"test title from curl"}' -H "Content-Type: application/json" "http://192.168.1.2:9999/notify/"
|
||||
```
|
||||
|
||||
4. Test from the docker apprise container console
|
||||
```
|
||||
apprise -vv -t "Test Message from apprise console" -b "Test Message from apprise console" \
|
||||
tgram://<bottoken>/<chatid>/
|
||||
```
|
||||
|
||||
|
||||
|
||||
BIN
front/plugins/_publisher_apprise/apprise_telegram.png
Executable file
|
After Width: | Height: | Size: 139 KiB |
@@ -57,22 +57,25 @@ def main():
|
||||
device_handler = DeviceInstance(db)
|
||||
|
||||
# Retrieve devices
|
||||
unknown_devices = device_handler.getUnknown()
|
||||
if get_setting_value("REFRESH_FQDN"):
|
||||
devices = device_handler.getAll()
|
||||
else:
|
||||
devices = device_handler.getUnknown()
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Devices count: {len(devices)}'])
|
||||
|
||||
# Mock list of devices (replace with actual device_handler.getUnknown() in production)
|
||||
# unknown_devices = [
|
||||
# devices = [
|
||||
# {'devMac': '00:11:22:33:44:55', 'devLastIP': '192.168.1.121'},
|
||||
# {'devMac': '00:11:22:33:44:56', 'devLastIP': '192.168.1.9'},
|
||||
# {'devMac': '00:11:22:33:44:57', 'devLastIP': '192.168.1.82'},
|
||||
# ]
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Unknown devices count: {len(unknown_devices)}'])
|
||||
|
||||
if len(unknown_devices) > 0:
|
||||
if len(devices) > 0:
|
||||
# ensure service is running
|
||||
ensure_avahi_running()
|
||||
|
||||
for device in unknown_devices:
|
||||
for device in devices:
|
||||
domain_name = execute_name_lookup(device['devLastIP'], timeout)
|
||||
|
||||
# check if found and not a timeout ('to')
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
{ "elementType": "select", "elementOptions": [], "transformers": [] }
|
||||
]
|
||||
},
|
||||
"default_value": "before_name_updates",
|
||||
"default_value": "disabled",
|
||||
"options": [
|
||||
"disabled",
|
||||
"before_name_updates",
|
||||
|
||||
@@ -195,7 +195,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"default_value": "0 2 * * 3",
|
||||
"default_value": "0 2 * * *",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name",
|
||||
@@ -297,7 +297,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"default_value": false,
|
||||
"default_value": true,
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name",
|
||||
|
||||
7
front/plugins/dig_scan/README.md
Executable file
@@ -0,0 +1,7 @@
|
||||
## Overview
|
||||
|
||||
Plugin for device name discovery via the [nbtscan](https://linuxcommandlibrary.com/man/nbtscan) network utility supporting NetBIOS.
|
||||
|
||||
### Usage
|
||||
|
||||
- Check the Settings page for details.
|
||||
385
front/plugins/dig_scan/config.json
Executable file
@@ -0,0 +1,385 @@
|
||||
{
|
||||
"code_name": "dig_scan",
|
||||
"unique_prefix": "DIGSCAN",
|
||||
"plugin_type": "other",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"execution_order" : "Layer_7",
|
||||
"show_ui": true,
|
||||
"data_filters": [
|
||||
{
|
||||
"compare_column": "Object_PrimaryID",
|
||||
"compare_operator": "==",
|
||||
"compare_field_id": "txtMacFilter",
|
||||
"compare_js_template": "'{value}'.toString()",
|
||||
"compare_use_quotes": true
|
||||
}
|
||||
],
|
||||
"localized": ["display_name", "description", "icon"],
|
||||
"display_name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Dig (Name resolution)"
|
||||
}
|
||||
],
|
||||
"icon": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "<i class=\"fa-solid fa-search\"></i>"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "A plugin to resolve device names via Dig."
|
||||
}
|
||||
],
|
||||
"params": [
|
||||
{
|
||||
"name": "ips",
|
||||
"type": "sql",
|
||||
"value": "SELECT devLastIP from DEVICES order by devMac",
|
||||
"timeoutMultiplier": true
|
||||
}
|
||||
],
|
||||
"settings": [
|
||||
{
|
||||
"function": "RUN",
|
||||
"events": ["run"],
|
||||
"type": {
|
||||
"dataType": "string",
|
||||
"elements": [
|
||||
{ "elementType": "select", "elementOptions": [], "transformers": [] }
|
||||
]
|
||||
},
|
||||
"default_value": "before_name_updates",
|
||||
"options": [
|
||||
"disabled",
|
||||
"before_name_updates",
|
||||
"on_new_device",
|
||||
"once",
|
||||
"schedule",
|
||||
"always_after_scan"
|
||||
],
|
||||
"localized": ["name", "description"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "When to run"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Cuándo ejecutar"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Wann laufen"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "When the plugin should be executed. If enabled this will execute the scan until there are no <code>(unknown)</code> or <code>(name not found)</code> devices. Setting this to <code>before_name_updates</code> is recommended.<br/><br/> Depends on the <a onclick=\"toggleAllSettings()\" href=\"#SCAN_SUBNETS\"><code>SCAN_SUBNETS</code> setting</a>."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "CMD",
|
||||
"type": {
|
||||
"dataType": "string",
|
||||
"elements": [
|
||||
{
|
||||
"elementType": "input",
|
||||
"elementOptions": [{ "readonly": "true" }],
|
||||
"transformers": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"default_value": "python3 /app/front/plugins/dig_scan/digscan.py",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Command"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Comando"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Befehl"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Command to run. This can not be changed"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Comando a ejecutar. Esto no se puede cambiar"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Befehl zum Ausführen. Dies kann nicht geändert werden"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "RUN_SCHD",
|
||||
"type": {
|
||||
"dataType": "string",
|
||||
"elements": [
|
||||
{
|
||||
"elementType": "span",
|
||||
"elementOptions": [
|
||||
{
|
||||
"cssClasses": "input-group-addon validityCheck"
|
||||
},
|
||||
{
|
||||
"getStringKey": "Gen_ValidIcon"
|
||||
}
|
||||
],
|
||||
"transformers": []
|
||||
},
|
||||
{
|
||||
"elementType": "input",
|
||||
"elementOptions": [
|
||||
{
|
||||
"onChange": "validateRegex(this)"
|
||||
},
|
||||
{
|
||||
"base64Regex": "Xig/OlwqfCg/OlswLTldfFsxLTVdWzAtOV18WzAtOV0rLVswLTldK3xcKi9bMC05XSspKVxzKyg/OlwqfCg/OlswLTldfDFbMC05XXwyWzAtM118WzAtOV0rLVswLTldK3xcKi9bMC05XSspKVxzKyg/OlwqfCg/OlsxLTldfFsxMl1bMC05XXwzWzAxXXxbMC05XSstWzAtOV0rfFwqL1swLTldKykpXHMrKD86XCp8KD86WzEtOV18MVswLTJdfFswLTldKy1bMC05XSt8XCovWzAtOV0rKSlccysoPzpcKnwoPzpbMC02XXxbMC02XS1bMC02XXxcKi9bMC05XSspKSQ="
|
||||
}
|
||||
],
|
||||
"transformers": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"default_value": "*/30 * * * *",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Schedule"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Schedule"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Schedule"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Only enabled if you select <code>schedule</code> in the <a href=\"#DIGSCAN_RUN\"><code>DIGSCAN_RUN</code> setting</a>. Make sure you enter the schedule in the correct cron-like format (e.g. validate at <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). For example entering <code>0 4 * * *</code> will run the scan after 4 am in the <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</code> you set above</a>. Will be run NEXT time the time passes."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Solo está habilitado si selecciona <code>schedule</code> en la configuración <a href=\"#DIGSCAN_RUN\"><code>DIGSCAN_RUN</code></a>. Asegúrese de ingresar la programación en el formato similar a cron correcto (por ejemplo, valide en <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). Por ejemplo, ingresar <code>0 4 * * *</code> ejecutará el escaneo después de las 4 a.m. en el <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</ código> que configuró arriba</a>. Se ejecutará la PRÓXIMA vez que pase el tiempo."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Nur aktiviert, wenn Sie <code>schedule</code> in der <a href=\"#DIGSCAN_RUN\"><code>DIGSCAN_RUN</code>-Einstellung</a> auswählen. Stellen Sie sicher, dass Sie den Zeitplan im richtigen Cron-ähnlichen Format eingeben (z. B. validieren unter <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). Wenn Sie beispielsweise <code>0 4 * * *</code> eingeben, wird der Scan nach 4 Uhr morgens in der <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</ ausgeführt. Code> den Sie oben festgelegt haben</a>. Wird das NÄCHSTE Mal ausgeführt, wenn die Zeit vergeht."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "RUN_TIMEOUT",
|
||||
"type": {
|
||||
"dataType": "integer",
|
||||
"elements": [
|
||||
{
|
||||
"elementType": "input",
|
||||
"elementOptions": [{ "type": "number" }],
|
||||
"transformers": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"default_value": 5,
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Run timeout"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Tiempo límite de ejecución"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Zeitüberschreitung"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Maximum time in seconds to wait for the script to finish. If this time is exceeded the script is aborted."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Tiempo máximo en segundos para esperar a que finalice el script. Si se supera este tiempo, el script se cancela."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Maximale Zeit in Sekunden, die auf den Abschluss des Skripts gewartet werden soll. Bei Überschreitung dieser Zeit wird das Skript abgebrochen."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"database_column_definitions": [
|
||||
{
|
||||
"column": "Index",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "none",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Index"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Object_PrimaryID",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "device_name_mac",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "MAC (name)"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "MAC"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Object_SecondaryID",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "IP"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "IP"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value1",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Server"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value2",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Name"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "DateTimeCreated",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Created"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "DateTimeChanged",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Changed"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Status",
|
||||
"css_classes": "col-sm-1",
|
||||
"show": true,
|
||||
"type": "replace",
|
||||
"default_value": "",
|
||||
"options": [
|
||||
{
|
||||
"equals": "watched-not-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-square-check'></i><div></div>"
|
||||
},
|
||||
{
|
||||
"equals": "watched-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-triangle-exclamation'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "new",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-circle-plus'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "missing-in-last-scan",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-question'></i></div>"
|
||||
}
|
||||
],
|
||||
"localized": ["name"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Status"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
133
front/plugins/dig_scan/digscan.py
Executable file
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
import json
|
||||
import sqlite3
|
||||
import subprocess
|
||||
|
||||
# Define the installation path and extend the system path for plugin imports
|
||||
INSTALL_PATH = "/app"
|
||||
sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
|
||||
|
||||
from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64
|
||||
from plugin_utils import get_plugins_configs
|
||||
from logger import mylog, Logger
|
||||
from const import pluginsPath, fullDbPath, logPath
|
||||
from helper import timeNowTZ, get_setting_value
|
||||
from messaging.in_app import write_notification
|
||||
from database import DB
|
||||
from models.device_instance import DeviceInstance
|
||||
import conf
|
||||
from pytz import timezone
|
||||
|
||||
# Make sure the TIMEZONE for logging is correct
|
||||
conf.tz = timezone(get_setting_value('TIMEZONE'))
|
||||
|
||||
# Make sure log level is initialized correctly
|
||||
Logger(get_setting_value('LOG_LEVEL'))
|
||||
|
||||
pluginName = 'DIGSCAN'
|
||||
|
||||
# Define the current path and log file paths
|
||||
LOG_PATH = logPath + '/plugins'
|
||||
LOG_FILE = os.path.join(LOG_PATH, f'script.{pluginName}.log')
|
||||
RESULT_FILE = os.path.join(LOG_PATH, f'last_result.{pluginName}.log')
|
||||
|
||||
# Initialize the Plugin obj output file
|
||||
plugin_objects = Plugin_Objects(RESULT_FILE)
|
||||
|
||||
|
||||
def main():
|
||||
mylog('verbose', [f'[{pluginName}] In script'])
|
||||
|
||||
timeout = get_setting_value('DIGSCAN_RUN_TIMEOUT')
|
||||
|
||||
# Create a database connection
|
||||
db = DB() # instance of class DB
|
||||
db.open()
|
||||
|
||||
# Initialize the Plugin obj output file
|
||||
plugin_objects = Plugin_Objects(RESULT_FILE)
|
||||
|
||||
# Create a DeviceInstance instance
|
||||
device_handler = DeviceInstance(db)
|
||||
|
||||
# Retrieve devices
|
||||
if get_setting_value("REFRESH_FQDN"):
|
||||
devices = device_handler.getAll()
|
||||
else:
|
||||
devices = device_handler.getUnknown()
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Devices count: {len(devices)}'])
|
||||
|
||||
# TEST - below is a WINDOWS host IP
|
||||
# execute_name_lookup('192.168.1.121', timeout)
|
||||
|
||||
for device in devices:
|
||||
domain_name, dns_server = execute_name_lookup(device['devLastIP'], timeout)
|
||||
|
||||
if domain_name != '':
|
||||
plugin_objects.add_object(
|
||||
# "MAC", "IP", "Server", "Name"
|
||||
primaryId = device['devMac'],
|
||||
secondaryId = device['devLastIP'],
|
||||
watched1 = dns_server,
|
||||
watched2 = domain_name,
|
||||
watched3 = '',
|
||||
watched4 = '',
|
||||
extra = '',
|
||||
foreignKey = device['devMac'])
|
||||
|
||||
plugin_objects.write_result_file()
|
||||
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Script finished'])
|
||||
|
||||
return 0
|
||||
|
||||
#===============================================================================
|
||||
# Execute scan
|
||||
#===============================================================================
|
||||
def execute_name_lookup (ip, timeout):
|
||||
"""
|
||||
Execute the DIG command on IP.
|
||||
"""
|
||||
|
||||
args = ['dig', '+short', '-x', ip]
|
||||
|
||||
# Execute command
|
||||
output = ""
|
||||
|
||||
try:
|
||||
mylog('verbose', [f'[{pluginName}] DEBUG CMD :', args])
|
||||
|
||||
# try runnning a subprocess with a forced (timeout) in case the subprocess hangs
|
||||
output = subprocess.check_output (args, universal_newlines=True, stderr=subprocess.STDOUT, timeout=(timeout), text=True).strip()
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] DEBUG OUTPUT : {output}'])
|
||||
|
||||
domain_name = output
|
||||
dns_server = ''
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Domain Name: {domain_name}'])
|
||||
|
||||
return domain_name, dns_server
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
mylog('verbose', [f'[{pluginName}] ⚠ ERROR - {e.output}'])
|
||||
|
||||
except subprocess.TimeoutExpired as timeErr:
|
||||
mylog('verbose', [f'[{pluginName}] TIMEOUT - the process forcefully terminated as timeout reached'])
|
||||
|
||||
if output == "": # check if the subprocess failed
|
||||
mylog('verbose', [f'[{pluginName}] Scan: FAIL - check logs'])
|
||||
else:
|
||||
mylog('verbose', [f'[{pluginName}] Scan: SUCCESS'])
|
||||
|
||||
return '', ''
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
@@ -66,13 +66,23 @@ device_type_map = {
|
||||
"networking_device": "Router",
|
||||
"multimedia_device": "TV Decoder",
|
||||
"car": "House Appliance",
|
||||
"watch": "Clock",
|
||||
"light": "Domotic",
|
||||
"outlet": "Domotic",
|
||||
"appliances": "House Appliance",
|
||||
"thermostat": "Domotic",
|
||||
"shutter": "Domotic",
|
||||
"other": "(Unknown)",
|
||||
}
|
||||
|
||||
|
||||
def map_device_type(type: str):
|
||||
return device_type_map[type]
|
||||
|
||||
try:
|
||||
return device_type_map[type]
|
||||
except KeyError:
|
||||
# This device type has not been mapped yet
|
||||
mylog("minimal", [f"[{pluginName}] Unknown device type: {type}"])
|
||||
return device_type_map["other"]
|
||||
|
||||
async def get_device_data(api_version: int, api_address: str, api_port: int):
|
||||
# ensure existence of db path
|
||||
|
||||
@@ -57,14 +57,17 @@ def main():
|
||||
device_handler = DeviceInstance(db)
|
||||
|
||||
# Retrieve devices
|
||||
unknown_devices = device_handler.getUnknown()
|
||||
if get_setting_value("REFRESH_FQDN"):
|
||||
devices = device_handler.getAll()
|
||||
else:
|
||||
devices = device_handler.getUnknown()
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Unknown devices count: {len(unknown_devices)}'])
|
||||
mylog('verbose', [f'[{pluginName}] Devices count: {len(devices)}'])
|
||||
|
||||
# TEST - below is a WINDOWS host IP
|
||||
# execute_name_lookup('192.168.1.121', timeout)
|
||||
|
||||
for device in unknown_devices:
|
||||
for device in devices:
|
||||
domain_name, dns_server = execute_name_lookup(device['devLastIP'], timeout)
|
||||
|
||||
if domain_name != '':
|
||||
|
||||
@@ -1629,6 +1629,42 @@
|
||||
"string": "Custom device properties to store additional data or to perform an action on the device. Check the <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/CUSTOM_PROPERTIES.md\" target=\"_blank\">documentation on Custom Properties</a> for additional details."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "devFQDN",
|
||||
"type": {
|
||||
"dataType": "string",
|
||||
"elements": [
|
||||
{
|
||||
"elementType": "input",
|
||||
"elementOptions": [
|
||||
{
|
||||
"readonly": "true"
|
||||
}
|
||||
],
|
||||
"transformers": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"maxLength": 50,
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "FQDN"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Fully Qualified Domain Name - Autodetected and Uneditable. Can be auto-refreshed by enabling the <code>REFRESH_FQDN</code> setting."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"required": [],
|
||||
|
||||
@@ -505,7 +505,7 @@
|
||||
"column": "Dummy",
|
||||
"mapped_to_column": "cur_ScanMethod",
|
||||
"mapped_to_column_data": {
|
||||
"value": "nmap-dev-scan"
|
||||
"value": "NMAPDEV"
|
||||
},
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
|
||||
@@ -59,11 +59,17 @@ def main():
|
||||
device_handler = DeviceInstance(db)
|
||||
|
||||
# Retrieve devices
|
||||
unknown_devices = device_handler.getUnknown()
|
||||
if get_setting_value("REFRESH_FQDN"):
|
||||
devices = device_handler.getAll()
|
||||
else:
|
||||
devices = device_handler.getUnknown()
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Unknown devices count: {len(unknown_devices)}'])
|
||||
mylog('verbose', [f'[{pluginName}] Devices count: {len(devices)}'])
|
||||
|
||||
# TEST - below is a WINDOWS host IP
|
||||
# execute_name_lookup('192.168.1.121', timeout)
|
||||
|
||||
for device in unknown_devices:
|
||||
for device in devices:
|
||||
domain_name, dns_server = execute_nslookup(device['devLastIP'], timeout)
|
||||
|
||||
if domain_name != '':
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
## Overview
|
||||
|
||||
> [!WARNING]
|
||||
> UNMAINTAINED - Looking for maintainers. If possible, use the `OMDSDNOPENAPI` instead.
|
||||
|
||||
The OMADA SDN plugin aims at synchronizing data between NetAlertX and a TPLINK OMADA SND controler by leveraging a tplink omada python library.
|
||||
|
||||
#### Features
|
||||
|
||||
@@ -377,7 +377,8 @@
|
||||
"Device_TableHead_SourcePlugin",
|
||||
"Device_TableHead_PresentLastScan",
|
||||
"Device_TableHead_AlertDown",
|
||||
"Device_TableHead_CustomProps"
|
||||
"Device_TableHead_CustomProps",
|
||||
"Device_TableHead_FQDN"
|
||||
],
|
||||
"localized": ["name", "description"],
|
||||
"name": [
|
||||
|
||||
@@ -12,7 +12,7 @@ import sys
|
||||
import requests
|
||||
from requests import Request, Session, packages
|
||||
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
||||
from pyunifi.controller import Controller
|
||||
from nax_pyunifi.controller import Controller
|
||||
|
||||
|
||||
# Register NetAlertX directories
|
||||
@@ -96,7 +96,14 @@ def get_entries(plugin_objects: Plugin_Objects) -> Plugin_Objects:
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] site: {site}'])
|
||||
|
||||
c = Controller(UNIFI_HOST, UNIFI_USERNAME, UNIFI_PASSWORD, port=PORT, version=VERSION, ssl_verify=VERIFYSSL, site_id=site)
|
||||
c = Controller(
|
||||
UNIFI_HOST,
|
||||
UNIFI_USERNAME,
|
||||
UNIFI_PASSWORD,
|
||||
port=PORT,
|
||||
version=VERSION,
|
||||
ssl_verify=VERIFYSSL,
|
||||
site_id=site)
|
||||
|
||||
online_macs = set()
|
||||
processed_macs = []
|
||||
|
||||
@@ -19,7 +19,7 @@ from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64, handleEmp
|
||||
from logger import mylog, Logger, append_line_to_file
|
||||
from helper import timeNowTZ, get_setting_value
|
||||
from const import logPath, applicationPath, fullDbPath
|
||||
from device import query_MAC_vendor
|
||||
from scan.device_handling import query_MAC_vendor
|
||||
import conf
|
||||
from pytz import timezone
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
import argparse
|
||||
import requests
|
||||
from requests.exceptions import SSLError, Timeout, RequestException
|
||||
import pathlib
|
||||
import sys
|
||||
import os
|
||||
|
||||
@@ -206,7 +206,7 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
|
||||
}, 3000);
|
||||
} else
|
||||
{
|
||||
$.get('/php/server/query_json.php', { file: 'plugins.json', nocache: Date.now() }, function(res) {
|
||||
$.get('php/server/query_json.php', { file: 'plugins.json', nocache: Date.now() }, function(res) {
|
||||
|
||||
pluginsData = res["data"];
|
||||
|
||||
@@ -354,7 +354,7 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
|
||||
|
||||
enabledHtml = `
|
||||
<div class="enabled-disabled-icon">
|
||||
<i class="fa-regular fa-${onOff}"></i>
|
||||
<i class="fa fa-${onOff}"></i>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
@@ -365,7 +365,7 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
|
||||
let pluginHtml = `
|
||||
<div class="row table_row docs">
|
||||
<div class="table_cell bold">
|
||||
<i class="fa-regular fa-book fa-sm"></i>
|
||||
<i class="fa fa-book fa-sm"></i>
|
||||
${getString(prefix+'_description')}
|
||||
<a href="https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/${getPluginCodeName(pluginsData, prefix)}" target="_blank">
|
||||
${getString('Gen_ReadDocs')}
|
||||
@@ -550,7 +550,7 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
|
||||
|
||||
// collect values for each of the different input form controls
|
||||
// get settings to determine setting type to store values appropriately
|
||||
$.get('/php/server/query_json.php', { file: 'table_settings.json', nocache: Date.now() }, function(res) {
|
||||
$.get('php/server/query_json.php', { file: 'table_settings.json', nocache: Date.now() }, function(res) {
|
||||
// loop through the settings definitions from the json
|
||||
res["data"].forEach(set => {
|
||||
|
||||
@@ -740,7 +740,7 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
|
||||
} else
|
||||
{
|
||||
// check if config file has been updated
|
||||
$.get('/php/server/query_json.php', { file: 'app_state.json', nocache: Date.now() }, function(appState) {
|
||||
$.get('php/server/query_json.php', { file: 'app_state.json', nocache: Date.now() }, function(appState) {
|
||||
|
||||
console.log("Settings: Got app_state.json");
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ require 'php/templates/header.php';
|
||||
|
||||
<div id="notifications" class="content-wrapper">
|
||||
<section class="content">
|
||||
<div class="box box-gray col-xs-12" >
|
||||
<div class="notification-box box box-gray col-xs-12" >
|
||||
<div class="box-header">
|
||||
<h3 class="box-title text-aqua"><?= lang('Notifications_All');?></h3>
|
||||
</div>
|
||||
@@ -33,9 +33,10 @@ require 'php/templates/header.php';
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<button id="clearNotificationsBtn" class="btn btn-danger"><?= lang("Gen_DeleteAll");?></button>
|
||||
<button id="notificationsMarkAllRead" class="btn btn-default"><?= lang("Notifications_Mark_All_Read");?></button>
|
||||
<div class="notification-buttons">
|
||||
<button id="clearNotificationsBtn" class="btn btn-danger"><?= lang("Gen_DeleteAll");?></button>
|
||||
<button id="notificationsMarkAllRead" class="btn btn-default"><?= lang("Notifications_Mark_All_Read");?></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -39,12 +39,12 @@
|
||||
let workflows = [];
|
||||
|
||||
let fieldOptions = [
|
||||
"devName", "devOwner", "devType", "devVendor", "devFavorite",
|
||||
"devName", "devMac", "devOwner", "devType", "devVendor", "devFavorite",
|
||||
"devGroup", "devComments", "devFirstConnection", "devLastConnection",
|
||||
"devLastIP", "devStaticIP", "devScan", "devLogEvents", "devAlertEvents",
|
||||
"devAlertDown", "devSkipRepeated", "devLastNotification", "devPresentLastScan",
|
||||
"devIsNew", "devLocation", "devIsArchived", "devParentMAC", "devParentPort",
|
||||
"devIcon", "devSite", "devSSID", "devSyncHubNode", "devSourcePlugin"
|
||||
"devIcon", "devSite", "devSSID", "devSyncHubNode", "devSourcePlugin", "devFQDN"
|
||||
];
|
||||
|
||||
let triggerTypes = [
|
||||
@@ -144,7 +144,7 @@ function generateWorkflowUI(wf, wfIndex) {
|
||||
)
|
||||
|
||||
let $wfEnabledIcon = $("<i>", {
|
||||
class: `alignRight fa-regular ${wfEnabled ? "fa-dot-circle" : "fa-circle" }`
|
||||
class: `alignRight fa ${wfEnabled ? "fa-dot-circle" : "fa-circle" }`
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ nav:
|
||||
- Troubleshooting:
|
||||
- Inspecting Logs: LOGGING.md
|
||||
- Debugging Tips: DEBUG_TIPS.md
|
||||
- Debugging GraphQL: DEBUG_GRAPHQL.md
|
||||
- Debugging Invalid JSON: DEBUG_INVALID_JSON.md
|
||||
- Debugging Plugins: DEBUG_PLUGINS.md
|
||||
- Debugging Web UI Port: WEB_UI_PORT_DEBUG.md
|
||||
|
||||
19
scripts/db_empty/README.md
Executable file
@@ -0,0 +1,19 @@
|
||||
# Overview
|
||||
|
||||
A script for deleting all data from the database.
|
||||
|
||||
# Usage
|
||||
|
||||
1. **Run the Script**
|
||||
|
||||
`python ./db_empty.py`
|
||||
|
||||
### Other info
|
||||
|
||||
- Version: 1.0
|
||||
- Release Date: 01-Jun-2025
|
||||
- Author: [jokob-sk](https://github.com/jokob-sk)
|
||||
|
||||
|
||||
> [!NOTE]
|
||||
> This is a community supplied script and not maintained.
|
||||
26
scripts/db_empty/db_empty.py
Executable file
@@ -0,0 +1,26 @@
|
||||
import sqlite3
|
||||
|
||||
# Connect to the database
|
||||
conn = sqlite3.connect("/app/db/app.db")
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Get the names of all tables (excluding SQLite internal tables)
|
||||
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%';")
|
||||
tables = cursor.fetchall()
|
||||
|
||||
# Disable foreign key constraints temporarily
|
||||
cursor.execute("PRAGMA foreign_keys = OFF;")
|
||||
|
||||
# Delete all rows from each table
|
||||
for (table_name,) in tables:
|
||||
cursor.execute(f"DELETE FROM {table_name};")
|
||||
|
||||
# Commit changes and re-enable foreign keys
|
||||
conn.commit()
|
||||
cursor.execute("PRAGMA foreign_keys = ON;")
|
||||
|
||||
# Vacuum to shrink database file
|
||||
cursor.execute("VACUUM;")
|
||||
|
||||
# Close connection
|
||||
conn.close()
|
||||
@@ -33,6 +33,7 @@ from initialise import importConfigs
|
||||
from database import DB
|
||||
from messaging.reporting import get_notifications
|
||||
from models.notification_instance import NotificationInstance
|
||||
from models.user_events_queue_instance import UserEventsQueueInstance
|
||||
from plugin import plugin_manager
|
||||
from scan.device_handling import update_devices_names
|
||||
from workflows.manager import WorkflowManager
|
||||
@@ -153,7 +154,7 @@ def main ():
|
||||
|
||||
# Resolve devices names
|
||||
mylog('debug','[Main] Resolve devices names')
|
||||
update_devices_names(db)
|
||||
update_devices_names(db)
|
||||
|
||||
# Check if new devices found
|
||||
sql.execute (sql_new_devices)
|
||||
@@ -221,6 +222,15 @@ def main ():
|
||||
updateState("Workflows: End")
|
||||
|
||||
|
||||
# check if devices list needs updating
|
||||
userUpdatedDevices = UserEventsQueueInstance().has_update_devices()
|
||||
|
||||
mylog('debug', [f'[Plugins] Should I update API (userUpdatedDevices): {userUpdatedDevices}'])
|
||||
|
||||
if userUpdatedDevices:
|
||||
|
||||
update_api(db, all_plugins, True, ["devices"], userUpdatedDevices)
|
||||
|
||||
#loop
|
||||
time.sleep(5) # wait for N seconds
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ sql_devices_all = """
|
||||
IFNULL(devSyncHubNode, '') AS devSyncHubNode,
|
||||
IFNULL(devSourcePlugin, '') AS devSourcePlugin,
|
||||
IFNULL(devCustomProps, '') AS devCustomProps,
|
||||
IFNULL(devFQDN, '') AS devFQDN,
|
||||
CASE
|
||||
WHEN devIsNew = 1 THEN 'New'
|
||||
WHEN devPresentLastScan = 1 THEN 'On-line'
|
||||
|
||||
@@ -80,370 +80,10 @@ class DB():
|
||||
"""
|
||||
Check the current tables in the DB and upgrade them if neccessary
|
||||
"""
|
||||
|
||||
self.sql.execute("""
|
||||
CREATE TABLE IF NOT EXISTS "Online_History" (
|
||||
"Index" INTEGER,
|
||||
"Scan_Date" TEXT,
|
||||
"Online_Devices" INTEGER,
|
||||
"Down_Devices" INTEGER,
|
||||
"All_Devices" INTEGER,
|
||||
"Archived_Devices" INTEGER,
|
||||
"Offline_Devices" INTEGER,
|
||||
PRIMARY KEY("Index" AUTOINCREMENT)
|
||||
);
|
||||
""")
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# DevicesNew - cleanup after 6/6/2025 - need to update also DB in the source code!
|
||||
|
||||
# check if migration already done based on devMac
|
||||
devMac_missing = self.sql.execute ("""
|
||||
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Devices') WHERE name='devMac'
|
||||
""").fetchone()[0] == 0
|
||||
|
||||
if devMac_missing:
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Alter Devices table
|
||||
# -------------------------------------------------------------------------
|
||||
# dev_Network_Node_MAC_ADDR column
|
||||
dev_Network_Node_MAC_ADDR_missing = self.sql.execute ("""
|
||||
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Devices') WHERE name='dev_Network_Node_MAC_ADDR'
|
||||
""").fetchone()[0] == 0
|
||||
|
||||
if dev_Network_Node_MAC_ADDR_missing :
|
||||
mylog('verbose', ["[upgradeDB] Adding dev_Network_Node_MAC_ADDR to the Devices table"])
|
||||
self.sql.execute("""
|
||||
ALTER TABLE "Devices" ADD "dev_Network_Node_MAC_ADDR" TEXT
|
||||
""")
|
||||
|
||||
# dev_Network_Node_port column
|
||||
dev_Network_Node_port_missing = self.sql.execute ("""
|
||||
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Devices') WHERE name='dev_Network_Node_port'
|
||||
""").fetchone()[0] == 0
|
||||
|
||||
if dev_Network_Node_port_missing :
|
||||
mylog('verbose', ["[upgradeDB] Adding dev_Network_Node_port to the Devices table"])
|
||||
self.sql.execute("""
|
||||
ALTER TABLE "Devices" ADD "dev_Network_Node_port" INTEGER
|
||||
""")
|
||||
|
||||
# dev_Icon column
|
||||
dev_Icon_missing = self.sql.execute ("""
|
||||
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Devices') WHERE name='dev_Icon'
|
||||
""").fetchone()[0] == 0
|
||||
|
||||
if dev_Icon_missing :
|
||||
mylog('verbose', ["[upgradeDB] Adding dev_Icon to the Devices table"])
|
||||
self.sql.execute("""
|
||||
ALTER TABLE "Devices" ADD "dev_Icon" TEXT
|
||||
""")
|
||||
|
||||
# dev_GUID column
|
||||
dev_GUID_missing = self.sql.execute ("""
|
||||
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Devices') WHERE name='dev_GUID'
|
||||
""").fetchone()[0] == 0
|
||||
|
||||
if dev_GUID_missing :
|
||||
mylog('verbose', ["[upgradeDB] Adding dev_GUID to the Devices table"])
|
||||
self.sql.execute("""
|
||||
ALTER TABLE "Devices" ADD "dev_GUID" TEXT
|
||||
""")
|
||||
|
||||
# dev_NetworkSite column
|
||||
dev_NetworkSite_missing = self.sql.execute ("""
|
||||
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Devices') WHERE name='dev_NetworkSite'
|
||||
""").fetchone()[0] == 0
|
||||
|
||||
if dev_NetworkSite_missing :
|
||||
mylog('verbose', ["[upgradeDB] Adding dev_NetworkSite to the Devices table"])
|
||||
self.sql.execute("""
|
||||
ALTER TABLE "Devices" ADD "dev_NetworkSite" TEXT
|
||||
""")
|
||||
|
||||
# dev_SSID column
|
||||
dev_SSID_missing = self.sql.execute ("""
|
||||
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Devices') WHERE name='dev_SSID'
|
||||
""").fetchone()[0] == 0
|
||||
|
||||
if dev_SSID_missing :
|
||||
mylog('verbose', ["[upgradeDB] Adding dev_SSID to the Devices table"])
|
||||
self.sql.execute("""
|
||||
ALTER TABLE "Devices" ADD "dev_SSID" TEXT
|
||||
""")
|
||||
|
||||
# SQL query to update missing dev_GUID
|
||||
self.sql.execute(f'''
|
||||
UPDATE Devices
|
||||
SET dev_GUID = {sql_generateGuid}
|
||||
WHERE dev_GUID IS NULL
|
||||
''')
|
||||
|
||||
# dev_SyncHubNodeName column
|
||||
dev_SyncHubNodeName_missing = self.sql.execute ("""
|
||||
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Devices') WHERE name='dev_SyncHubNodeName'
|
||||
""").fetchone()[0] == 0
|
||||
|
||||
if dev_SyncHubNodeName_missing :
|
||||
mylog('verbose', ["[upgradeDB] Adding dev_SyncHubNodeName to the Devices table"])
|
||||
self.sql.execute("""
|
||||
ALTER TABLE "Devices" ADD "dev_SyncHubNodeName" TEXT
|
||||
""")
|
||||
|
||||
# dev_SourcePlugin column
|
||||
dev_SourcePlugin_missing = self.sql.execute ("""
|
||||
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Devices') WHERE name='dev_SourcePlugin'
|
||||
""").fetchone()[0] == 0
|
||||
|
||||
if dev_SourcePlugin_missing :
|
||||
mylog('verbose', ["[upgradeDB] Adding dev_SourcePlugin to the Devices table"])
|
||||
self.sql.execute("""
|
||||
ALTER TABLE "Devices" ADD "dev_SourcePlugin" TEXT
|
||||
""")
|
||||
|
||||
# SQL to create Devices table with indexes
|
||||
sql_create_devices_new_tmp = """
|
||||
CREATE TABLE IF NOT EXISTS Devices_tmp (
|
||||
devMac STRING (50) PRIMARY KEY NOT NULL COLLATE NOCASE,
|
||||
devName STRING (50) NOT NULL DEFAULT "(unknown)",
|
||||
devOwner STRING (30) DEFAULT "(unknown)" NOT NULL,
|
||||
devType STRING (30),
|
||||
devVendor STRING (250),
|
||||
devFavorite BOOLEAN CHECK (devFavorite IN (0, 1)) DEFAULT (0) NOT NULL,
|
||||
devGroup STRING (10),
|
||||
devComments TEXT,
|
||||
devFirstConnection DATETIME NOT NULL,
|
||||
devLastConnection DATETIME NOT NULL,
|
||||
devLastIP STRING (50) NOT NULL COLLATE NOCASE,
|
||||
devStaticIP BOOLEAN DEFAULT (0) NOT NULL CHECK (devStaticIP IN (0, 1)),
|
||||
devScan INTEGER DEFAULT (1) NOT NULL,
|
||||
devLogEvents BOOLEAN NOT NULL DEFAULT (1) CHECK (devLogEvents IN (0, 1)),
|
||||
devAlertEvents BOOLEAN NOT NULL DEFAULT (1) CHECK (devAlertEvents IN (0, 1)),
|
||||
devAlertDown BOOLEAN NOT NULL DEFAULT (0) CHECK (devAlertDown IN (0, 1)),
|
||||
devSkipRepeated INTEGER DEFAULT 0 NOT NULL,
|
||||
devLastNotification DATETIME,
|
||||
devPresentLastScan BOOLEAN NOT NULL DEFAULT (0) CHECK (devPresentLastScan IN (0, 1)),
|
||||
devIsNew BOOLEAN NOT NULL DEFAULT (1) CHECK (devIsNew IN (0, 1)),
|
||||
devLocation STRING (250) COLLATE NOCASE,
|
||||
devIsArchived BOOLEAN NOT NULL DEFAULT (0) CHECK (devIsArchived IN (0, 1)),
|
||||
devParentMAC TEXT,
|
||||
devParentPort INTEGER,
|
||||
devIcon TEXT,
|
||||
devGUID TEXT,
|
||||
devSite TEXT,
|
||||
devSSID TEXT,
|
||||
devSyncHubNode TEXT,
|
||||
devSourcePlugin TEXT
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS IDX_dev_PresentLastScan ON Devices_tmp (devPresentLastScan);
|
||||
CREATE INDEX IF NOT EXISTS IDX_dev_FirstConnection ON Devices_tmp (devFirstConnection);
|
||||
CREATE INDEX IF NOT EXISTS IDX_dev_AlertDeviceDown ON Devices_tmp (devAlertDown);
|
||||
CREATE INDEX IF NOT EXISTS IDX_dev_StaticIP ON Devices_tmp (devStaticIP);
|
||||
CREATE INDEX IF NOT EXISTS IDX_dev_ScanCycle ON Devices_tmp (devScan);
|
||||
CREATE INDEX IF NOT EXISTS IDX_dev_Favorite ON Devices_tmp (devFavorite);
|
||||
CREATE INDEX IF NOT EXISTS IDX_dev_LastIP ON Devices_tmp (devLastIP);
|
||||
CREATE INDEX IF NOT EXISTS IDX_dev_NewDevice ON Devices_tmp (devIsNew);
|
||||
CREATE INDEX IF NOT EXISTS IDX_dev_Archived ON Devices_tmp (devIsArchived);
|
||||
"""
|
||||
|
||||
# Execute the creation of the Devices table and indexes
|
||||
self.sql.executescript(sql_create_devices_new_tmp)
|
||||
|
||||
|
||||
# copy over data
|
||||
sql_copy_from_devices = """
|
||||
INSERT OR IGNORE INTO Devices_tmp (
|
||||
devMac,
|
||||
devName,
|
||||
devOwner,
|
||||
devType,
|
||||
devVendor,
|
||||
devFavorite,
|
||||
devGroup,
|
||||
devComments,
|
||||
devFirstConnection,
|
||||
devLastConnection,
|
||||
devLastIP,
|
||||
devStaticIP,
|
||||
devScan,
|
||||
devLogEvents,
|
||||
devAlertEvents,
|
||||
devAlertDown,
|
||||
devSkipRepeated,
|
||||
devLastNotification,
|
||||
devPresentLastScan,
|
||||
devIsNew,
|
||||
devLocation,
|
||||
devIsArchived,
|
||||
devParentMAC,
|
||||
devParentPort,
|
||||
devIcon,
|
||||
devGUID,
|
||||
devSite,
|
||||
devSSID,
|
||||
devSyncHubNode,
|
||||
devSourcePlugin
|
||||
)
|
||||
SELECT
|
||||
dev_MAC AS devMac,
|
||||
dev_Name AS devName,
|
||||
dev_Owner AS devOwner,
|
||||
dev_DeviceType AS devType,
|
||||
dev_Vendor AS devVendor,
|
||||
dev_Favorite AS devFavorite,
|
||||
dev_Group AS devGroup,
|
||||
dev_Comments AS devComments,
|
||||
dev_FirstConnection AS devFirstConnection,
|
||||
dev_LastConnection AS devLastConnection,
|
||||
dev_LastIP AS devLastIP,
|
||||
dev_StaticIP AS devStaticIP,
|
||||
dev_ScanCycle AS devScan,
|
||||
dev_LogEvents AS devLogEvents,
|
||||
dev_AlertEvents AS devAlertEvents,
|
||||
dev_AlertDeviceDown AS devAlertDown,
|
||||
dev_SkipRepeated AS devSkipRepeated,
|
||||
dev_LastNotification AS devLastNotification,
|
||||
dev_PresentLastScan AS devPresentLastScan,
|
||||
dev_NewDevice AS devIsNew,
|
||||
dev_Location AS devLocation,
|
||||
dev_Archived AS devIsArchived,
|
||||
dev_Network_Node_MAC_ADDR AS devParentMAC,
|
||||
dev_Network_Node_port AS devParentPort,
|
||||
dev_Icon AS devIcon,
|
||||
dev_GUID AS devGUID,
|
||||
dev_NetworkSite AS devSite,
|
||||
dev_SSID AS devSSID,
|
||||
dev_SyncHubNodeName AS devSyncHubNode,
|
||||
dev_SourcePlugin AS devSourcePlugin
|
||||
FROM Devices;
|
||||
"""
|
||||
|
||||
self.sql.execute(sql_copy_from_devices)
|
||||
|
||||
|
||||
self.sql.execute(""" DROP TABLE Devices;""")
|
||||
# SQL to create Devices table with indexes
|
||||
sql_create_devices_new = """
|
||||
CREATE TABLE IF NOT EXISTS Devices (
|
||||
devMac STRING (50) PRIMARY KEY NOT NULL COLLATE NOCASE,
|
||||
devName STRING (50) NOT NULL DEFAULT "(unknown)",
|
||||
devOwner STRING (30) DEFAULT "(unknown)" NOT NULL,
|
||||
devType STRING (30),
|
||||
devVendor STRING (250),
|
||||
devFavorite BOOLEAN CHECK (devFavorite IN (0, 1)) DEFAULT (0) NOT NULL,
|
||||
devGroup STRING (10),
|
||||
devComments TEXT,
|
||||
devFirstConnection DATETIME NOT NULL,
|
||||
devLastConnection DATETIME NOT NULL,
|
||||
devLastIP STRING (50) NOT NULL COLLATE NOCASE,
|
||||
devStaticIP BOOLEAN DEFAULT (0) NOT NULL CHECK (devStaticIP IN (0, 1)),
|
||||
devScan INTEGER DEFAULT (1) NOT NULL,
|
||||
devLogEvents BOOLEAN NOT NULL DEFAULT (1) CHECK (devLogEvents IN (0, 1)),
|
||||
devAlertEvents BOOLEAN NOT NULL DEFAULT (1) CHECK (devAlertEvents IN (0, 1)),
|
||||
devAlertDown BOOLEAN NOT NULL DEFAULT (0) CHECK (devAlertDown IN (0, 1)),
|
||||
devSkipRepeated INTEGER DEFAULT 0 NOT NULL,
|
||||
devLastNotification DATETIME,
|
||||
devPresentLastScan BOOLEAN NOT NULL DEFAULT (0) CHECK (devPresentLastScan IN (0, 1)),
|
||||
devIsNew BOOLEAN NOT NULL DEFAULT (1) CHECK (devIsNew IN (0, 1)),
|
||||
devLocation STRING (250) COLLATE NOCASE,
|
||||
devIsArchived BOOLEAN NOT NULL DEFAULT (0) CHECK (devIsArchived IN (0, 1)),
|
||||
devParentMAC TEXT,
|
||||
devParentPort INTEGER,
|
||||
devIcon TEXT,
|
||||
devGUID TEXT,
|
||||
devSite TEXT,
|
||||
devSSID TEXT,
|
||||
devSyncHubNode TEXT,
|
||||
devSourcePlugin TEXT
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS IDX_dev_PresentLastScan ON Devices (devPresentLastScan);
|
||||
CREATE INDEX IF NOT EXISTS IDX_dev_FirstConnection ON Devices (devFirstConnection);
|
||||
CREATE INDEX IF NOT EXISTS IDX_dev_AlertDeviceDown ON Devices (devAlertDown);
|
||||
CREATE INDEX IF NOT EXISTS IDX_dev_StaticIP ON Devices (devStaticIP);
|
||||
CREATE INDEX IF NOT EXISTS IDX_dev_ScanCycle ON Devices (devScan);
|
||||
CREATE INDEX IF NOT EXISTS IDX_dev_Favorite ON Devices (devFavorite);
|
||||
CREATE INDEX IF NOT EXISTS IDX_dev_LastIP ON Devices (devLastIP);
|
||||
CREATE INDEX IF NOT EXISTS IDX_dev_NewDevice ON Devices (devIsNew);
|
||||
CREATE INDEX IF NOT EXISTS IDX_dev_Archived ON Devices (devIsArchived);
|
||||
"""
|
||||
|
||||
# Execute the creation of the Devices table and indexes
|
||||
self.sql.executescript(sql_create_devices_new)
|
||||
|
||||
# copy over data
|
||||
sql_copy_from_devices_tmp = """
|
||||
INSERT OR IGNORE INTO Devices (
|
||||
devMac,
|
||||
devName,
|
||||
devOwner,
|
||||
devType,
|
||||
devVendor,
|
||||
devFavorite,
|
||||
devGroup,
|
||||
devComments,
|
||||
devFirstConnection,
|
||||
devLastConnection,
|
||||
devLastIP,
|
||||
devStaticIP,
|
||||
devScan,
|
||||
devLogEvents,
|
||||
devAlertEvents,
|
||||
devAlertDown,
|
||||
devSkipRepeated,
|
||||
devLastNotification,
|
||||
devPresentLastScan,
|
||||
devIsNew,
|
||||
devLocation,
|
||||
devIsArchived,
|
||||
devParentMAC,
|
||||
devParentPort,
|
||||
devIcon,
|
||||
devGUID,
|
||||
devSite,
|
||||
devSSID,
|
||||
devSyncHubNode,
|
||||
devSourcePlugin
|
||||
)
|
||||
SELECT
|
||||
devMac,
|
||||
devName,
|
||||
devOwner,
|
||||
devType,
|
||||
devVendor,
|
||||
devFavorite,
|
||||
devGroup,
|
||||
devComments,
|
||||
devFirstConnection,
|
||||
devLastConnection,
|
||||
devLastIP,
|
||||
devStaticIP,
|
||||
devScan,
|
||||
devLogEvents,
|
||||
devAlertEvents,
|
||||
devAlertDown,
|
||||
devSkipRepeated,
|
||||
devLastNotification,
|
||||
devPresentLastScan,
|
||||
devIsNew,
|
||||
devLocation,
|
||||
devIsArchived,
|
||||
devParentMAC,
|
||||
devParentPort,
|
||||
devIcon,
|
||||
devGUID,
|
||||
devSite,
|
||||
devSSID,
|
||||
devSyncHubNode,
|
||||
devSourcePlugin
|
||||
FROM Devices_tmp;
|
||||
"""
|
||||
|
||||
self.sql.execute(sql_copy_from_devices_tmp)
|
||||
self.sql.execute(""" DROP TABLE Devices_tmp;""")
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Alter Devices table
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
# VIEWS
|
||||
|
||||
@@ -477,17 +117,19 @@ class DB():
|
||||
|
||||
|
||||
# add fields if missing
|
||||
|
||||
# devCustomProps column
|
||||
devCustomProps_missing = self.sql.execute ("""
|
||||
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Devices') WHERE name='devCustomProps'
|
||||
|
||||
# devFQDN missing?
|
||||
devFQDN_missing = self.sql.execute ("""
|
||||
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Devices') WHERE name='devFQDN'
|
||||
""").fetchone()[0] == 0
|
||||
|
||||
if devFQDN_missing:
|
||||
|
||||
if devCustomProps_missing :
|
||||
mylog('verbose', ["[upgradeDB] Adding devCustomProps to the Devices table"])
|
||||
mylog('verbose', ["[upgradeDB] Adding devFQDN to the Devices table"])
|
||||
self.sql.execute("""
|
||||
ALTER TABLE "Devices" ADD "devCustomProps" TEXT
|
||||
ALTER TABLE "Devices" ADD "devFQDN" TEXT
|
||||
""")
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Settings table setup
|
||||
@@ -564,48 +206,6 @@ class DB():
|
||||
); """
|
||||
self.sql.execute(sql_Plugins_Objects)
|
||||
|
||||
# -----------------------------------------
|
||||
# REMOVE after 6/6/2025 - START
|
||||
# -----------------------------------------
|
||||
# syncHubNodeName column
|
||||
plug_SyncHubNodeName_missing = self.sql.execute ("""
|
||||
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Plugins_Objects') WHERE name='SyncHubNodeName'
|
||||
""").fetchone()[0] == 0
|
||||
|
||||
if plug_SyncHubNodeName_missing :
|
||||
mylog('verbose', ["[upgradeDB] Adding SyncHubNodeName to the Plugins_Objects table"])
|
||||
self.sql.execute("""
|
||||
ALTER TABLE "Plugins_Objects" ADD "SyncHubNodeName" TEXT
|
||||
""")
|
||||
|
||||
# helper columns HelpVal1-4
|
||||
plug_HelpValues_missing = self.sql.execute ("""
|
||||
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Plugins_Objects') WHERE name='HelpVal1'
|
||||
""").fetchone()[0] == 0
|
||||
|
||||
if plug_HelpValues_missing :
|
||||
mylog('verbose', ["[upgradeDB] Adding HelpVal1-4 to the Plugins_Objects table"])
|
||||
self.sql.execute('ALTER TABLE "Plugins_Objects" ADD COLUMN "HelpVal1" TEXT')
|
||||
self.sql.execute('ALTER TABLE "Plugins_Objects" ADD COLUMN "HelpVal2" TEXT')
|
||||
self.sql.execute('ALTER TABLE "Plugins_Objects" ADD COLUMN "HelpVal3" TEXT')
|
||||
self.sql.execute('ALTER TABLE "Plugins_Objects" ADD COLUMN "HelpVal4" TEXT')
|
||||
|
||||
# plug_ObjectGUID_missing column
|
||||
plug_ObjectGUID_missing = self.sql.execute ("""
|
||||
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Plugins_Objects') WHERE name='ObjectGUID'
|
||||
""").fetchone()[0] == 0
|
||||
|
||||
if plug_ObjectGUID_missing :
|
||||
mylog('verbose', ["[upgradeDB] Adding ObjectGUID to the Plugins_Objects table"])
|
||||
self.sql.execute("""
|
||||
ALTER TABLE "Plugins_Objects" ADD "ObjectGUID" TEXT
|
||||
""")
|
||||
|
||||
|
||||
# -----------------------------------------
|
||||
# REMOVE after 6/6/2025 - END
|
||||
# -----------------------------------------
|
||||
|
||||
# Plugin execution results
|
||||
sql_Plugins_Events = """ CREATE TABLE IF NOT EXISTS Plugins_Events(
|
||||
"Index" INTEGER,
|
||||
@@ -631,49 +231,6 @@ class DB():
|
||||
); """
|
||||
self.sql.execute(sql_Plugins_Events)
|
||||
|
||||
# -----------------------------------------
|
||||
# REMOVE after 6/6/2025 - START
|
||||
# -----------------------------------------
|
||||
|
||||
# syncHubNodeName column
|
||||
plug_SyncHubNodeName_missing = self.sql.execute ("""
|
||||
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Plugins_Events') WHERE name='SyncHubNodeName'
|
||||
""").fetchone()[0] == 0
|
||||
|
||||
if plug_SyncHubNodeName_missing :
|
||||
mylog('verbose', ["[upgradeDB] Adding SyncHubNodeName to the Plugins_Events table"])
|
||||
self.sql.execute("""
|
||||
ALTER TABLE "Plugins_Events" ADD "SyncHubNodeName" TEXT
|
||||
""")
|
||||
|
||||
# helper columns HelpVal1-4
|
||||
plug_HelpValues_missing = self.sql.execute ("""
|
||||
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Plugins_Events') WHERE name='HelpVal1'
|
||||
""").fetchone()[0] == 0
|
||||
|
||||
if plug_HelpValues_missing :
|
||||
mylog('verbose', ["[upgradeDB] Adding HelpVal1-4 to the Plugins_Events table"])
|
||||
self.sql.execute('ALTER TABLE "Plugins_Events" ADD COLUMN "HelpVal1" TEXT')
|
||||
self.sql.execute('ALTER TABLE "Plugins_Events" ADD COLUMN "HelpVal2" TEXT')
|
||||
self.sql.execute('ALTER TABLE "Plugins_Events" ADD COLUMN "HelpVal3" TEXT')
|
||||
self.sql.execute('ALTER TABLE "Plugins_Events" ADD COLUMN "HelpVal4" TEXT')
|
||||
|
||||
# plug_ObjectGUID_missing column
|
||||
plug_ObjectGUID_missing = self.sql.execute ("""
|
||||
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Plugins_Events') WHERE name='ObjectGUID'
|
||||
""").fetchone()[0] == 0
|
||||
|
||||
if plug_ObjectGUID_missing :
|
||||
mylog('verbose', ["[upgradeDB] Adding ObjectGUID to the Plugins_Events table"])
|
||||
self.sql.execute("""
|
||||
ALTER TABLE "Plugins_Events" ADD "ObjectGUID" TEXT
|
||||
""")
|
||||
|
||||
# -----------------------------------------
|
||||
# REMOVE after 6/6/2025 - END
|
||||
# -----------------------------------------
|
||||
|
||||
|
||||
# Plugin execution history
|
||||
sql_Plugins_History = """ CREATE TABLE IF NOT EXISTS Plugins_History(
|
||||
"Index" INTEGER,
|
||||
@@ -699,48 +256,6 @@ class DB():
|
||||
); """
|
||||
self.sql.execute(sql_Plugins_History)
|
||||
|
||||
# -----------------------------------------
|
||||
# REMOVE after 6/6/2025 - START
|
||||
# -----------------------------------------
|
||||
|
||||
# syncHubNodeName column
|
||||
plug_SyncHubNodeName_missing = self.sql.execute ("""
|
||||
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Plugins_History') WHERE name='SyncHubNodeName'
|
||||
""").fetchone()[0] == 0
|
||||
|
||||
if plug_SyncHubNodeName_missing :
|
||||
mylog('verbose', ["[upgradeDB] Adding SyncHubNodeName to the Plugins_History table"])
|
||||
self.sql.execute("""
|
||||
ALTER TABLE "Plugins_History" ADD "SyncHubNodeName" TEXT
|
||||
""")
|
||||
|
||||
# helper columns HelpVal1-4
|
||||
plug_HelpValues_missing = self.sql.execute ("""
|
||||
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Plugins_History') WHERE name='HelpVal1'
|
||||
""").fetchone()[0] == 0
|
||||
|
||||
if plug_HelpValues_missing :
|
||||
mylog('verbose', ["[upgradeDB] Adding HelpVal1-4 to the Plugins_History table"])
|
||||
self.sql.execute('ALTER TABLE "Plugins_History" ADD COLUMN "HelpVal1" TEXT')
|
||||
self.sql.execute('ALTER TABLE "Plugins_History" ADD COLUMN "HelpVal2" TEXT')
|
||||
self.sql.execute('ALTER TABLE "Plugins_History" ADD COLUMN "HelpVal3" TEXT')
|
||||
self.sql.execute('ALTER TABLE "Plugins_History" ADD COLUMN "HelpVal4" TEXT')
|
||||
|
||||
|
||||
# plug_ObjectGUID_missing column
|
||||
plug_ObjectGUID_missing = self.sql.execute ("""
|
||||
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Plugins_History') WHERE name='ObjectGUID'
|
||||
""").fetchone()[0] == 0
|
||||
|
||||
if plug_ObjectGUID_missing :
|
||||
mylog('verbose', ["[upgradeDB] Adding ObjectGUID to the Plugins_History table"])
|
||||
self.sql.execute("""
|
||||
ALTER TABLE "Plugins_History" ADD "ObjectGUID" TEXT
|
||||
""")
|
||||
|
||||
# -----------------------------------------
|
||||
# REMOVE after 6/6/2025 - END
|
||||
# -----------------------------------------
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Plugins_Language_Strings table setup
|
||||
@@ -845,21 +360,6 @@ class DB():
|
||||
# Init the AppEvent database table
|
||||
AppEvent_obj(self)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# DELETING OBSOLETE TABLES - to remove with updated db file after 9/9/2024
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
# Deletes obsolete ScanCycles
|
||||
self.sql.execute(""" DROP TABLE IF EXISTS ScanCycles;""")
|
||||
self.sql.execute(""" DROP TABLE IF EXISTS DHCP_Leases;""")
|
||||
self.sql.execute(""" DROP TABLE IF EXISTS PiHole_Network;""")
|
||||
|
||||
self.commitDB()
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# DELETING OBSOLETE TABLES - to remove with updated db file after 9/9/2024
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def get_table_as_json(self, sqlQuery):
|
||||
|
||||
@@ -73,6 +73,7 @@ class Device(ObjectType):
|
||||
devParentChildrenCount = Int()
|
||||
devIpLong = Int()
|
||||
devFilterStatus = String()
|
||||
devFQDN = String()
|
||||
|
||||
|
||||
class DeviceResult(ObjectType):
|
||||
@@ -180,7 +181,7 @@ class Query(ObjectType):
|
||||
searchable_fields = [
|
||||
"devName", "devMac", "devOwner", "devType", "devVendor", "devLastIP",
|
||||
"devGroup", "devComments", "devLocation", "devStatus",
|
||||
"devSSID", "devSite", "devSourcePlugin", "devSyncHubNode"
|
||||
"devSSID", "devSite", "devSourcePlugin", "devSyncHubNode", "devFQDN"
|
||||
]
|
||||
|
||||
search_term = options.search.lower()
|
||||
@@ -198,7 +199,9 @@ class Query(ObjectType):
|
||||
for sort_option in options.sort:
|
||||
devices_data = sorted(
|
||||
devices_data,
|
||||
key=lambda x: mixed_type_sort_key(x.get(sort_option.field)),
|
||||
key=lambda x: mixed_type_sort_key(
|
||||
x.get(sort_option.field).lower() if isinstance(x.get(sort_option.field), str) else x.get(sort_option.field)
|
||||
),
|
||||
reverse=(sort_option.order.lower() == "desc")
|
||||
)
|
||||
|
||||
|
||||
227
server/helper.py
@@ -18,6 +18,7 @@ import hashlib
|
||||
import random
|
||||
import string
|
||||
import ipaddress
|
||||
import dns.resolver
|
||||
|
||||
import conf
|
||||
from const import *
|
||||
@@ -427,211 +428,6 @@ def check_IP_format (pIP):
|
||||
# Return IP
|
||||
return IP.group(0)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def get_device_name_mdns(db, pMAC, pIP):
|
||||
|
||||
nameNotFound = "(name not found)"
|
||||
|
||||
sql = db.sql
|
||||
|
||||
name = nameNotFound
|
||||
|
||||
# get names from the AVAHISCAN plugin entries vased on MAC
|
||||
sql.execute(
|
||||
f"""
|
||||
SELECT Watched_Value2 FROM Plugins_Objects
|
||||
WHERE
|
||||
Plugin = 'AVAHISCAN' AND
|
||||
Object_PrimaryID = '{pMAC}'
|
||||
"""
|
||||
)
|
||||
nameEntry = sql.fetchall()
|
||||
db.commitDB()
|
||||
|
||||
if len(nameEntry) != 0:
|
||||
name = cleanDeviceName(nameEntry[0][0], False)
|
||||
|
||||
return name
|
||||
|
||||
# get names from the AVAHISCAN plugin entries based on IP
|
||||
sql.execute(
|
||||
f"""
|
||||
SELECT Watched_Value2 FROM Plugins_Objects
|
||||
WHERE
|
||||
Plugin = 'AVAHISCAN' AND
|
||||
Object_SecondaryID = '{pIP}'
|
||||
"""
|
||||
)
|
||||
nameEntry = sql.fetchall()
|
||||
db.commitDB()
|
||||
|
||||
if len(nameEntry) != 0:
|
||||
name = cleanDeviceName(nameEntry[0][0], True)
|
||||
|
||||
return name
|
||||
|
||||
return name
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def get_device_name_nslookup(db, pMAC, pIP):
|
||||
|
||||
nameNotFound = "(name not found)"
|
||||
|
||||
sql = db.sql
|
||||
|
||||
name = nameNotFound
|
||||
|
||||
# get names from the NSLOOKUP plugin entries vased on MAC
|
||||
sql.execute(
|
||||
f"""
|
||||
SELECT Watched_Value2 FROM Plugins_Objects
|
||||
WHERE
|
||||
Plugin = 'NSLOOKUP' AND
|
||||
Object_PrimaryID = '{pMAC}'
|
||||
"""
|
||||
)
|
||||
nameEntry = sql.fetchall()
|
||||
db.commitDB()
|
||||
|
||||
if len(nameEntry) != 0:
|
||||
name = cleanDeviceName(nameEntry[0][0], False)
|
||||
|
||||
return name
|
||||
|
||||
# get names from the NSLOOKUP plugin entries based on IP
|
||||
sql.execute(
|
||||
f"""
|
||||
SELECT Watched_Value2 FROM Plugins_Objects
|
||||
WHERE
|
||||
Plugin = 'NSLOOKUP' AND
|
||||
Object_SecondaryID = '{pIP}'
|
||||
"""
|
||||
)
|
||||
nameEntry = sql.fetchall()
|
||||
db.commitDB()
|
||||
|
||||
if len(nameEntry) != 0:
|
||||
name = cleanDeviceName(nameEntry[0][0], True)
|
||||
|
||||
return name
|
||||
|
||||
return name
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def get_device_name_nbtlookup(db, pMAC, pIP):
|
||||
|
||||
nameNotFound = "(name not found)"
|
||||
|
||||
sql = db.sql
|
||||
|
||||
name = nameNotFound
|
||||
|
||||
# get names from the NBTSCAN plugin entries vased on MAC
|
||||
sql.execute(
|
||||
f"""
|
||||
SELECT Watched_Value2 FROM Plugins_Objects
|
||||
WHERE
|
||||
Plugin = 'NBTSCAN' AND
|
||||
Object_PrimaryID = '{pMAC}'
|
||||
"""
|
||||
)
|
||||
nameEntry = sql.fetchall()
|
||||
db.commitDB()
|
||||
|
||||
if len(nameEntry) != 0:
|
||||
name = cleanDeviceName(nameEntry[0][0], False)
|
||||
|
||||
return name
|
||||
|
||||
# get names from the NSLOOKUP plugin entries based on IP
|
||||
sql.execute(
|
||||
f"""
|
||||
SELECT Watched_Value2 FROM Plugins_Objects
|
||||
WHERE
|
||||
Plugin = 'NBTSCAN' AND
|
||||
Object_SecondaryID = '{pIP}'
|
||||
"""
|
||||
)
|
||||
nameEntry = sql.fetchall()
|
||||
db.commitDB()
|
||||
|
||||
if len(nameEntry) != 0:
|
||||
name = cleanDeviceName(nameEntry[0][0], True)
|
||||
|
||||
return name
|
||||
|
||||
return name
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def resolve_device_name_dig (pMAC, pIP):
|
||||
|
||||
nameNotFound = "(name not found)"
|
||||
|
||||
dig_args = ['dig', '+short', '-x', pIP]
|
||||
|
||||
# Execute command
|
||||
try:
|
||||
# try runnning a subprocess
|
||||
newName = subprocess.check_output (dig_args, universal_newlines=True)
|
||||
|
||||
# Check returns
|
||||
newName = newName.strip()
|
||||
|
||||
if len(newName) == 0 :
|
||||
return nameNotFound
|
||||
|
||||
# Cleanup
|
||||
newName = cleanDeviceName(newName, True)
|
||||
|
||||
if newName == "" or len(newName) == 0 or newName == '-1' or newName == -1 or "communications error" in newName or 'malformed message packet' in newName :
|
||||
return nameNotFound
|
||||
|
||||
# all checks passed
|
||||
mylog('debug', [f'[resolve_device_name_dig] Found a new name: "{newName}"'])
|
||||
|
||||
return newName
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
# An error occured, handle it
|
||||
mylog('none', ['[resolve_device_name_dig] ⚠ ERROR: ', e.output])
|
||||
# newName = "Error - check logs"
|
||||
return nameNotFound
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# DNS record (Name resolution) cleanup methods
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
import dns.resolver
|
||||
|
||||
def cleanDeviceName(str, match_IP):
|
||||
|
||||
mylog('debug', ["[cleanDeviceName] input: " + str])
|
||||
|
||||
# add matching info
|
||||
if match_IP:
|
||||
str = str + " (IP match)"
|
||||
|
||||
# Applying cleanup REGEXEs
|
||||
mylog('debug', ["[Name cleanup] Using old cleanDeviceName(" + str + ")"])
|
||||
|
||||
regexes = get_setting_value('NEWDEV_NAME_CLEANUP_REGEX')
|
||||
|
||||
for rgx in regexes:
|
||||
mylog('trace', ["[cleanDeviceName] applying regex : " + rgx])
|
||||
mylog('trace', ["[cleanDeviceName] name before regex : " + str])
|
||||
str = re.sub(rgx, "", str)
|
||||
mylog('trace', ["[cleanDeviceName] name after regex : " + str])
|
||||
|
||||
# str = re.sub(r'\.\b', '', str) # trailing dot after words
|
||||
str = re.sub(r'\.$', '', str) # trailing dot at the end of the string
|
||||
str = str.replace(". (IP match)", " (IP match)") # Remove dot if (IP match) is added
|
||||
|
||||
mylog('debug', ["[cleanDeviceName] output: " + str])
|
||||
|
||||
return str
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# String manipulation methods
|
||||
#-------------------------------------------------------------------------------
|
||||
@@ -838,6 +634,27 @@ def collect_lang_strings(json, pref, stringSqlParams):
|
||||
# Misc
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def print_table_schema(db, table):
|
||||
sql = db.sql
|
||||
sql.execute(f"PRAGMA table_info({table})")
|
||||
result = sql.fetchall()
|
||||
|
||||
if not result:
|
||||
mylog('none', f'[Schema] Table "{table}" not found or has no columns.')
|
||||
return
|
||||
|
||||
mylog('debug', f'[Schema] Structure for table: {table}')
|
||||
header = f"{'cid':<4} {'name':<20} {'type':<10} {'notnull':<8} {'default':<10} {'pk':<2}"
|
||||
mylog('debug', header)
|
||||
mylog('debug', '-' * len(header))
|
||||
|
||||
for row in result:
|
||||
# row = (cid, name, type, notnull, dflt_value, pk)
|
||||
line = f"{row[0]:<4} {row[1]:<20} {row[2]:<10} {row[3]:<8} {str(row[4]):<10} {row[5]:<2}"
|
||||
mylog('debug', line)
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def checkNewVersion():
|
||||
mylog('debug', [f"[Version check] Checking if new version available"])
|
||||
|
||||
@@ -163,11 +163,12 @@ def importConfigs (db, all_plugins):
|
||||
conf.LOG_LEVEL = ccd('LOG_LEVEL', 'verbose' , c_d, 'Log verboseness', '{"dataType":"string", "elements": [{"elementType" : "select", "elementOptions" : [] ,"transformers": []}]}', "['none', 'minimal', 'verbose', 'debug', 'trace']", 'General')
|
||||
conf.TIMEZONE = ccd('TIMEZONE', default_tz , c_d, 'Time zone', '{"dataType":"string", "elements": [{"elementType" : "input", "elementOptions" : [] ,"transformers": []}]}', '[]', 'General')
|
||||
conf.PLUGINS_KEEP_HIST = ccd('PLUGINS_KEEP_HIST', 250 , c_d, 'Keep history entries', '{"dataType":"integer", "elements": [{"elementType" : "input", "elementOptions" : [{"type": "number"}] ,"transformers": []}]}', '[]', 'General')
|
||||
conf.REPORT_DASHBOARD_URL = ccd('REPORT_DASHBOARD_URL', 'http://netalertx/' , c_d, 'NetAlertX URL', '{"dataType":"string", "elements": [{"elementType" : "input", "elementOptions" : [] ,"transformers": []}]}', '[]', 'General')
|
||||
conf.REPORT_DASHBOARD_URL = ccd('REPORT_DASHBOARD_URL', 'http://127.0.0.1/' , c_d, 'NetAlertX URL', '{"dataType":"string", "elements": [{"elementType" : "input", "elementOptions" : [] ,"transformers": []}]}', '[]', 'General')
|
||||
conf.DAYS_TO_KEEP_EVENTS = ccd('DAYS_TO_KEEP_EVENTS', 90 , c_d, 'Delete events days', '{"dataType":"integer", "elements": [{"elementType" : "input", "elementOptions" : [{"type": "number"}] ,"transformers": []}]}', '[]', 'General')
|
||||
conf.HRS_TO_KEEP_NEWDEV = ccd('HRS_TO_KEEP_NEWDEV', 0 , c_d, 'Keep new devices for', '{"dataType":"integer", "elements": [{"elementType" : "input", "elementOptions" : [{"type": "number"}] ,"transformers": []}]}', "[]", 'General')
|
||||
conf.HRS_TO_KEEP_OFFDEV = ccd('HRS_TO_KEEP_OFFDEV', 0 , c_d, 'Keep offline devices for', '{"dataType":"integer", "elements": [{"elementType" : "input", "elementOptions" : [{"type": "number"}] ,"transformers": []}]}', "[]", 'General')
|
||||
conf.CLEAR_NEW_FLAG = ccd('CLEAR_NEW_FLAG', 0 , c_d, 'Clear new flag', '{"dataType":"integer", "elements": [{"elementType" : "input", "elementOptions" : [{"type": "number"}] ,"transformers": []}]}', "[]", 'General')
|
||||
conf.REFRESH_FQDN = ccd('REFRESH_FQDN', False , c_d, 'Refresh FQDN', """{"dataType": "boolean","elements": [{"elementType": "input","elementOptions": [{ "type": "checkbox" }],"transformers": []}]}""", '[]', 'General')
|
||||
conf.API_CUSTOM_SQL = ccd('API_CUSTOM_SQL', 'SELECT * FROM Devices WHERE devPresentLastScan = 0' , c_d, 'Custom endpoint', '{"dataType":"string", "elements": [{"elementType" : "input", "elementOptions" : [] ,"transformers": []}]}', '[]', 'General')
|
||||
conf.VERSION = ccd('VERSION', '' , c_d, 'Version', '{"dataType":"string", "elements": [{"elementType" : "input", "elementOptions" : [{ "readonly": "true" }] ,"transformers": []}]}', '', 'General')
|
||||
conf.NETWORK_DEVICE_TYPES = ccd('NETWORK_DEVICE_TYPES', ['AP', 'Gateway', 'Firewall', 'Hypervisor', 'Powerline', 'Switch', 'WLAN', 'PLC', 'Router','USB LAN Adapter', 'USB WIFI Adapter', 'Internet'] , c_d, 'Network device types', '{"dataType":"array","elements":[{"elementType":"input","elementOptions":[{"placeholder":"Enter value"},{"suffix":"_in"},{"cssClasses":"col-sm-10"},{"prefillValue":"null"}],"transformers":[]},{"elementType":"button","elementOptions":[{"sourceSuffixes":["_in"]},{"separator":""},{"cssClasses":"col-xs-12"},{"onClick":"addList(this,false)"},{"getStringKey":"Gen_Add"}],"transformers":[]},{"elementType":"select", "elementHasInputValue":1,"elementOptions":[{"multiple":"true"},{"readonly":"true"},{"editable":"true"}],"transformers":[]},{"elementType":"button","elementOptions":[{"sourceSuffixes":[]},{"separator":""},{"cssClasses":"col-xs-6"},{"onClick":"removeAllOptions(this)"},{"getStringKey":"Gen_Remove_All"}],"transformers":[]},{"elementType":"button","elementOptions":[{"sourceSuffixes":[]},{"separator":""},{"cssClasses":"col-xs-6"},{"onClick":"removeFromList(this)"},{"getStringKey":"Gen_Remove_Last"}],"transformers":[]}]}', '[]', 'General')
|
||||
@@ -445,46 +446,6 @@ replacements = {
|
||||
r'\bREPORT_TO\b': 'SMTP_REPORT_TO',
|
||||
r'\bSYNC_api_token\b': 'API_TOKEN',
|
||||
r'\bAPI_TOKEN=\'\'': f'API_TOKEN=\'t_{generate_random_string(20)}\'',
|
||||
r'\bREPORT_FROM\b': 'SMTP_REPORT_FROM',
|
||||
r'\bPIALERT_WEB_PROTECTION\b': 'SETPWD_enable_password',
|
||||
r'\bPIALERT_WEB_PASSWORD\b': 'SETPWD_password',
|
||||
r'REPORT_MAIL=True': "SMTP_RUN='on_notification'",
|
||||
r'REPORT_APPRISE=True': "APPRISE_RUN='on_notification'",
|
||||
r'REPORT_NTFY=True': "NTFY_RUN='on_notification'",
|
||||
r'REPORT_WEBHOOK=True': "WEBHOOK_RUN='on_notification'",
|
||||
r'REPORT_PUSHSAFER=True': "PUSHSAFER_RUN='on_notification'",
|
||||
r'REPORT_MQTT=True': "MQTT_RUN='on_notification'",
|
||||
# r'PIHOLE_CMD=': 'PIHOLE_CMD_OLD=',
|
||||
r'\bINCLUDED_SECTIONS\b': 'NTFPRCS_INCLUDED_SECTIONS',
|
||||
r'\bDIG_GET_IP_ARG\b': 'INTRNT_DIG_GET_IP_ARG',
|
||||
r'dev_MAC': 'devMac',
|
||||
r'dev_Name': 'devName',
|
||||
r'dev_Favorite': 'devFavorite',
|
||||
r'dev_Group': 'devGroup',
|
||||
r'dev_Comments': 'devComments',
|
||||
r'dev_FirstConnection': 'devFirstConnection',
|
||||
r'dev_LastConnection': 'devLastConnection',
|
||||
r'dev_LastIP': 'devLastIP',
|
||||
r'dev_StaticIP': 'devStaticIP',
|
||||
r'dev_ScanCycle': 'devScan',
|
||||
r'dev_LogEvents': 'devLogEvents',
|
||||
r'dev_AlertEvents': 'devAlertEvents',
|
||||
r'dev_AlertDeviceDown': 'devAlertDown',
|
||||
r'dev_SkipRepeated': 'devSkipRepeated',
|
||||
r'dev_LastNotification': 'devLastNotification',
|
||||
r'dev_PresentLastScan': 'devPresentLastScan',
|
||||
r'dev_NewDevice': 'devIsNew',
|
||||
r'dev_Location': 'devLocation',
|
||||
r'dev_Archived': 'devIsArchived',
|
||||
r'dev_Network_Node_MAC_ADDR': 'devParentMAC',
|
||||
r'dev_Network_Node_port': 'devParentPort',
|
||||
r'dev_Icon': 'devIcon',
|
||||
r'dev_GUID': 'devGUID',
|
||||
r'dev_NetworkSite': 'devSite',
|
||||
r'dev_SSID': 'devSSID',
|
||||
r'dev_SyncHubNodeName': 'devSyncHubNode',
|
||||
r'dev_SourcePlugin': 'devSourcePlugin',
|
||||
r'/home/pi/pialert\b': '/app'
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -562,7 +562,10 @@ def execute_plugin(db, all_plugins, plugin ):
|
||||
endpoints = ["plugins_events","plugins_objects", "plugins_history", "appevents"]
|
||||
|
||||
# check if we need to update devices api endpoint as well to prevent long user waits on Loading...
|
||||
userUpdatedDevices = UserEventsQueueInstance().has_update_devices
|
||||
userUpdatedDevices = UserEventsQueueInstance().has_update_devices()
|
||||
|
||||
mylog('verbose', [f'[Plugins] Should I update API (userUpdatedDevices): {userUpdatedDevices}'])
|
||||
|
||||
if userUpdatedDevices:
|
||||
endpoints += ["devices"]
|
||||
|
||||
|
||||
@@ -8,10 +8,11 @@ import subprocess
|
||||
import conf
|
||||
import os
|
||||
import re
|
||||
from helper import timeNowTZ, get_setting, get_setting_value, list_to_where, resolve_device_name_dig, get_device_name_nbtlookup, get_device_name_nslookup, get_device_name_mdns, check_IP_format, sanitize_SQL_input
|
||||
from helper import timeNowTZ, get_setting, get_setting_value, list_to_where, check_IP_format, sanitize_SQL_input
|
||||
from logger import mylog
|
||||
from const import vendorsPath, vendorsPathNewest, sql_generateGuid
|
||||
from models.device_instance import DeviceInstance
|
||||
from scan.name_resolution import NameResolver
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Removing devices from the CurrentScan DB table which the user chose to ignore by MAC or IP
|
||||
@@ -481,88 +482,109 @@ def update_devices_data_from_scan (db):
|
||||
mylog('debug','[Update Devices] Update devices end')
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def update_devices_names (db):
|
||||
sql = db.sql #TO-DO
|
||||
# Initialize variables
|
||||
recordsToUpdate = []
|
||||
recordsNotFound = []
|
||||
def update_devices_names(db):
|
||||
sql = db.sql
|
||||
resolver = NameResolver(db)
|
||||
device_handler = DeviceInstance(db)
|
||||
|
||||
nameNotFound = "(name not found)"
|
||||
|
||||
ignored = 0
|
||||
notFound = 0
|
||||
# Define resolution strategies in priority order
|
||||
strategies = [
|
||||
(resolver.resolve_dig, 'dig'),
|
||||
(resolver.resolve_mdns, 'mdns'),
|
||||
(resolver.resolve_nslookup, 'nslookup'),
|
||||
(resolver.resolve_nbtlookup, 'nbtlookup')
|
||||
]
|
||||
|
||||
foundDig = 0
|
||||
foundmDNSLookup = 0
|
||||
foundNsLookup = 0
|
||||
foundNbtLookup = 0
|
||||
def resolve_devices(devices, resolve_both_name_and_fqdn=True):
|
||||
"""
|
||||
Attempts to resolve device names and/or FQDNs using available strategies.
|
||||
|
||||
Parameters:
|
||||
devices (list): List of devices to resolve.
|
||||
resolve_both_name_and_fqdn (bool): If True, resolves both name and FQDN.
|
||||
If False, resolves only FQDN.
|
||||
|
||||
Returns:
|
||||
recordsToUpdate (list): List of [newName, newFQDN, devMac] or [newFQDN, devMac] for DB update.
|
||||
recordsNotFound (list): List of [nameNotFound, devMac] for DB update.
|
||||
foundStats (dict): Number of successes per strategy.
|
||||
notFound (int): Number of devices not resolved.
|
||||
"""
|
||||
recordsToUpdate = []
|
||||
recordsNotFound = []
|
||||
foundStats = {label: 0 for _, label in strategies}
|
||||
notFound = 0
|
||||
|
||||
# Gen unknown devices
|
||||
device_handler = DeviceInstance(db)
|
||||
# Retrieve devices
|
||||
for device in devices:
|
||||
newName = nameNotFound
|
||||
newFQDN = ''
|
||||
|
||||
# Attempt each resolution strategy in order
|
||||
for resolve_fn, label in strategies:
|
||||
resolved = resolve_fn(device['devMac'], device['devLastIP'])
|
||||
|
||||
# Only use name if resolving both name and FQDN
|
||||
newName = resolved.cleaned if resolve_both_name_and_fqdn else None
|
||||
newFQDN = resolved.raw
|
||||
|
||||
# If a valid result is found, record it and stop further attempts
|
||||
if newFQDN not in [nameNotFound, '', 'localhost.'] and ' communications error to ' not in newFQDN:
|
||||
foundStats[label] += 1
|
||||
|
||||
if resolve_both_name_and_fqdn:
|
||||
recordsToUpdate.append([newName, newFQDN, device['devMac']])
|
||||
else:
|
||||
recordsToUpdate.append([newFQDN, device['devMac']])
|
||||
break
|
||||
|
||||
# If no name was resolved, queue device for "(name not found)" update
|
||||
if resolve_both_name_and_fqdn and newName == nameNotFound:
|
||||
notFound += 1
|
||||
if device['devName'] != nameNotFound:
|
||||
recordsNotFound.append([nameNotFound, device['devMac']])
|
||||
|
||||
return recordsToUpdate, recordsNotFound, foundStats, notFound
|
||||
|
||||
# --- Step 1: Update device names for unknown devices ---
|
||||
unknownDevices = device_handler.getUnknown()
|
||||
if unknownDevices:
|
||||
mylog('verbose', f'[Update Device Name] Trying to resolve devices without name. Unknown devices count: {len(unknownDevices)}')
|
||||
|
||||
# skip checks if no unknown devices
|
||||
if len(unknownDevices) == 0:
|
||||
return
|
||||
# Try resolving both name and FQDN
|
||||
recordsToUpdate, recordsNotFound, foundStats, notFound = resolve_devices(unknownDevices)
|
||||
|
||||
# Devices without name
|
||||
mylog('verbose', f'[Update Device Name] Trying to resolve devices without name. Unknown devices count: {len(unknownDevices)}')
|
||||
# Log summary
|
||||
mylog('verbose', f"[Update Device Name] Names Found (DiG/mDNS/NSLOOKUP/NBTSCAN): {len(recordsToUpdate)} ({foundStats['dig']}/{foundStats['mdns']}/{foundStats['nslookup']}/{foundStats['nbtlookup']})")
|
||||
mylog('verbose', f'[Update Device Name] Names Not Found : {notFound}')
|
||||
|
||||
for device in unknownDevices:
|
||||
newName = nameNotFound
|
||||
|
||||
# Resolve device name with DiG
|
||||
newName = resolve_device_name_dig (device['devMac'], device['devLastIP'])
|
||||
|
||||
# count
|
||||
if newName != nameNotFound:
|
||||
foundDig += 1
|
||||
|
||||
# Resolve device name with AVAHISCAN plugin data
|
||||
if newName == nameNotFound:
|
||||
newName = get_device_name_mdns(db, device['devMac'], device['devLastIP'])
|
||||
# Apply updates to database
|
||||
sql.executemany("UPDATE Devices SET devName = ? WHERE devMac = ?", recordsNotFound)
|
||||
sql.executemany("UPDATE Devices SET devName = ?, devFQDN = ? WHERE devMac = ?", recordsToUpdate)
|
||||
|
||||
if newName != nameNotFound:
|
||||
foundmDNSLookup += 1
|
||||
# --- Step 2: Optionally refresh FQDN for all devices ---
|
||||
if get_setting_value("REFRESH_FQDN"):
|
||||
allDevices = device_handler.getAll()
|
||||
if allDevices:
|
||||
mylog('verbose', f'[Update FQDN] Trying to resolve FQDN. Devices count: {len(allDevices)}')
|
||||
|
||||
# Resolve device name with NSLOOKUP plugin data
|
||||
if newName == nameNotFound:
|
||||
newName = get_device_name_nslookup(db, device['devMac'], device['devLastIP'])
|
||||
# Try resolving only FQDN
|
||||
recordsToUpdate, _, foundStats, notFound = resolve_devices(allDevices, resolve_both_name_and_fqdn=False)
|
||||
|
||||
if newName != nameNotFound:
|
||||
foundNsLookup += 1
|
||||
|
||||
# Resolve device name with NBTLOOKUP plugin data
|
||||
if newName == nameNotFound:
|
||||
newName = get_device_name_nbtlookup(db, device['devMac'], device['devLastIP'])
|
||||
# Log summary
|
||||
mylog('verbose', f"[Update FQDN] Names Found (DiG/mDNS/NSLOOKUP/NBTSCAN): {len(recordsToUpdate)} ({foundStats['dig']}/{foundStats['mdns']}/{foundStats['nslookup']}/{foundStats['nbtlookup']})")
|
||||
mylog('verbose', f'[Update FQDN] Names Not Found : {notFound}')
|
||||
|
||||
if newName != nameNotFound:
|
||||
foundNbtLookup += 1
|
||||
|
||||
# if still not found update name so we can distinguish the devices where we tried already
|
||||
if newName == nameNotFound :
|
||||
# Apply FQDN-only updates
|
||||
sql.executemany("UPDATE Devices SET devFQDN = ? WHERE devMac = ?", recordsToUpdate)
|
||||
|
||||
notFound += 1
|
||||
|
||||
# if devName is the same as what we will change it to, take no action
|
||||
# this mitigates a race condition which would overwrite a users edits that occured since the select earlier
|
||||
if device['devName'] != nameNotFound:
|
||||
recordsNotFound.append (["(name not found)", device['devMac']])
|
||||
else:
|
||||
# name was found
|
||||
recordsToUpdate.append ([newName, device['devMac']])
|
||||
|
||||
# Print log
|
||||
mylog('verbose', [f'[Update Device Name] Names Found (DiG/mDNS/NSLOOKUP/NBTSCAN): {len(recordsToUpdate)} ({foundDig}/{foundmDNSLookup}/{foundNsLookup}/{foundNbtLookup})'] )
|
||||
mylog('verbose', [f'[Update Device Name] Names Not Found : {notFound}'] )
|
||||
|
||||
# update not found devices with (name not found)
|
||||
sql.executemany ("UPDATE Devices SET devName = ? WHERE devMac = ? ", recordsNotFound )
|
||||
# update names of devices which we were bale to resolve
|
||||
sql.executemany ("UPDATE Devices SET devName = ? WHERE devMac = ? ", recordsToUpdate )
|
||||
# Commit all database changes
|
||||
db.commitDB()
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Check if the variable contains a valid MAC address or "Internet"
|
||||
def check_mac_or_internet(input_str):
|
||||
@@ -652,9 +674,9 @@ def guess_icon(vendor, mac, ip, name, default):
|
||||
mylog('debug', [f"[guess_icon] Guessing icon for (vendor|mac|ip|name): ('{vendor}'|'{mac}'|{ip}|{name})"])
|
||||
|
||||
result = default
|
||||
mac = mac.upper()
|
||||
vendor = vendor.lower() if vendor else "unknown"
|
||||
name = name.lower() if name else "(unknown)"
|
||||
mac = str(mac).upper() if mac else "00:00:00:00:00:00"
|
||||
vendor = str(vendor).lower() if vendor else "unknown"
|
||||
name = str(name).lower() if name else "(unknown)"
|
||||
|
||||
# Guess icon based on vendor
|
||||
if any(brand in vendor for brand in {"samsung", "motorola"}):
|
||||
@@ -710,8 +732,8 @@ def guess_icon(vendor, mac, ip, name, default):
|
||||
# Guess device type
|
||||
def guess_type(vendor, mac, ip, name, default):
|
||||
result = default
|
||||
mac = mac.upper()
|
||||
vendor = vendor.lower() if vendor else "unknown"
|
||||
mac = str(mac).upper() if mac else "00:00:00:00:00:00"
|
||||
vendor = str(vendor).lower() if vendor else "unknown"
|
||||
name = str(name).lower() if name else "(unknown)"
|
||||
|
||||
# Guess icon based on vendor
|
||||
|
||||
83
server/scan/name_resolution.py
Executable file
@@ -0,0 +1,83 @@
|
||||
import sys
|
||||
import re
|
||||
import subprocess
|
||||
import socket
|
||||
import dns.resolver
|
||||
|
||||
# Register NetAlertX directories
|
||||
INSTALL_PATH = "/app"
|
||||
sys.path.extend([f"{INSTALL_PATH}/server"])
|
||||
|
||||
import conf
|
||||
from const import *
|
||||
from logger import mylog
|
||||
from helper import get_setting_value
|
||||
|
||||
class ResolvedName:
|
||||
def __init__(self, raw: str = "(name not found)", cleaned: str = "(name not found)"):
|
||||
self.raw = raw
|
||||
self.cleaned = cleaned
|
||||
|
||||
def __str__(self):
|
||||
return self.cleaned
|
||||
|
||||
class NameResolver:
|
||||
def __init__(self, db):
|
||||
self.db = db
|
||||
|
||||
def resolve_from_plugin(self, plugin: str, pMAC: str, pIP: str) -> ResolvedName:
|
||||
sql = self.db.sql
|
||||
nameNotFound = ResolvedName()
|
||||
|
||||
# Check by MAC
|
||||
sql.execute(f"""
|
||||
SELECT Watched_Value2 FROM Plugins_Objects
|
||||
WHERE Plugin = '{plugin}' AND Object_PrimaryID = '{pMAC}'
|
||||
""")
|
||||
result = sql.fetchall()
|
||||
self.db.commitDB()
|
||||
if result:
|
||||
raw = result[0][0]
|
||||
return ResolvedName(raw, self.clean_device_name(raw, False))
|
||||
|
||||
# Check by IP
|
||||
sql.execute(f"""
|
||||
SELECT Watched_Value2 FROM Plugins_Objects
|
||||
WHERE Plugin = '{plugin}' AND Object_SecondaryID = '{pIP}'
|
||||
""")
|
||||
result = sql.fetchall()
|
||||
self.db.commitDB()
|
||||
if result:
|
||||
raw = result[0][0]
|
||||
return ResolvedName(raw, self.clean_device_name(raw, True))
|
||||
|
||||
return nameNotFound
|
||||
|
||||
def resolve_mdns(self, pMAC, pIP) -> ResolvedName:
|
||||
return self.resolve_from_plugin("AVAHISCAN", pMAC, pIP)
|
||||
|
||||
def resolve_nslookup(self, pMAC, pIP) -> ResolvedName:
|
||||
return self.resolve_from_plugin("NSLOOKUP", pMAC, pIP)
|
||||
|
||||
def resolve_nbtlookup(self, pMAC, pIP) -> ResolvedName:
|
||||
return self.resolve_from_plugin("NBTSCAN", pMAC, pIP)
|
||||
|
||||
def resolve_dig(self, pMAC, pIP) -> ResolvedName:
|
||||
return self.resolve_from_plugin("DIGSCAN", pMAC, pIP)
|
||||
|
||||
def clean_device_name(self, name: str, match_ip: bool) -> str:
|
||||
mylog('debug', [f"[cleanDeviceName] input: {name}"])
|
||||
|
||||
if match_ip:
|
||||
name += " (IP match)"
|
||||
|
||||
regexes = get_setting_value('NEWDEV_NAME_CLEANUP_REGEX') or []
|
||||
for rgx in regexes:
|
||||
mylog('trace', [f"[cleanDeviceName] applying regex: {rgx}"])
|
||||
name = re.sub(rgx, "", name)
|
||||
|
||||
name = re.sub(r'\.$', '', name)
|
||||
name = name.replace(". (IP match)", " (IP match)")
|
||||
|
||||
mylog('debug', [f"[cleanDeviceName] output: {name}"])
|
||||
return name
|
||||