From b7ebc8206fdc3fdbafaa0f8725ed277052c47654 Mon Sep 17 00:00:00 2001 From: Tanner Snow <53470063+Neutronlul@users.noreply.github.com> Date: Sat, 9 May 2026 16:47:32 -0700 Subject: [PATCH 01/16] Fix typo in docker installation documentation --- docs/DOCKER_INSTALLATION.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/DOCKER_INSTALLATION.md b/docs/DOCKER_INSTALLATION.md index 1c03e998..70183b10 100644 --- a/docs/DOCKER_INSTALLATION.md +++ b/docs/DOCKER_INSTALLATION.md @@ -36,7 +36,7 @@ docker run -d --rm --network=host \ > Runtime UID/GID: The image defaults to a service user `netalertx` (UID/GID 20211). A separate readonly lock owner also uses UID/GID 20211 for 004/005 immutability. You can override the runtime UID/GID at build (ARG) or run (`--user` / compose `user:`) but must align writable mounts (`/data`, `/tmp*`) and tmpfs `uid/gid` to that choice. -See alternative [docked-compose examples](https://docs.netalertx.com/DOCKER_COMPOSE). +See alternative [docker-compose examples](https://docs.netalertx.com/DOCKER_COMPOSE). ### Default ports From b290d3c3d2902f54839dca5bf2d1c8622976c7ec Mon Sep 17 00:00:00 2001 From: void-spark <81029971+void-spark@users.noreply.github.com> Date: Sun, 10 May 2026 18:15:05 +0200 Subject: [PATCH 02/16] First attempt at kea dhcp support --- front/plugins/kea_api/README.md | 70 +++++ front/plugins/kea_api/config.json | 455 ++++++++++++++++++++++++++++++ front/plugins/kea_api/script.py | 70 +++++ 3 files changed, 595 insertions(+) create mode 100755 front/plugins/kea_api/README.md create mode 100644 front/plugins/kea_api/config.json create mode 100644 front/plugins/kea_api/script.py diff --git a/front/plugins/kea_api/README.md b/front/plugins/kea_api/README.md new file mode 100755 index 00000000..8a35edf2 --- /dev/null +++ b/front/plugins/kea_api/README.md @@ -0,0 +1,70 @@ +## Overview + +A plugin allowing for importing devices from the Kea DHCP API. +https://www.isc.org/kea/ + +And specifically: +https://kea.readthedocs.io/en/kea-2.6.3/api.html#lease4-get-all + + +### Usage + +To enable the API, first you want to add something like this to your main kea configuration (this is for debian 13): + +```json + "control-socket": { + "socket-type": "unix", + "socket-name": "/run/kea/kea4-ctrl-socket" + }, + + "hooks-libraries": [ + { + "library": "/usr/lib/x86_64-linux-gnu/kea/hooks/libdhcp_lease_cmds.so" + } + ], +``` + + +And you need to install kea-ctrl-agent, with a config that looks something like this: + +```json +{ +"Control-agent": { + "http-host": "127.0.0.1", + "http-port": 8000, + + "authentication": { + "type": "basic", + "realm": "Kea Control Agent", + "directory": "/etc/kea", + "clients": [ + { + "user": "kea-api", + "password-file": "kea-api-password" + } + ] + }, + "control-sockets": { + "dhcp4": { + "socket-type": "unix", + "socket-name": "/run/kea/kea4-ctrl-socket" + } + }, + "loggers": [ + { + "name": "kea-ctrl-agent", + "output-options": [ + { + "output": "stdout", + "pattern": "%-5p %m\n" + } + ], + "severity": "INFO", + "debuglevel": 0 + } + ] +} +} +``` + +You will need to configure the plugin with the URL to the API, and the username and password configured above (from kea-api-password file in the example) diff --git a/front/plugins/kea_api/config.json b/front/plugins/kea_api/config.json new file mode 100644 index 00000000..ffa434bd --- /dev/null +++ b/front/plugins/kea_api/config.json @@ -0,0 +1,455 @@ +{ + "code_name": "kea_api", + "unique_prefix": "KEALSS", + "plugin_type": "device_scanner", + "execution_order" : "Layer_3", + "enabled": true, + "data_source": "script", + "data_filters": [ + { + "compare_column": "objectPrimaryId", + "compare_operator": "==", + "compare_field_id": "txtMacFilter", + "compare_js_template": "'{value}'.toString()", + "compare_use_quotes": true + } + ], + "show_ui": true, + "localized": ["display_name", "description", "icon"], + "mapped_to_table": "CurrentScan", + "display_name": [{"language_code": "en_us", "string": "Kea DHCP API"}], + "icon": [{"language_code": "en_us", "string": ""}], + "description": [{"language_code": "en_us", "string": "Imports leases via Kea Control Agent REST API"}], + "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": "objectPrimaryId", + "mapped_to_column": "scanMac", + "css_classes": "col-sm-2", + "show": true, + "type": "device_mac", + "default_value": "", + "options": [], + "localized": ["name"], + "name": [{"language_code": "en_us", "string": "MAC address"}] + }, + { + "column": "objectSecondaryId", + "mapped_to_column": "scanLastIP", + "css_classes": "col-sm-2", + "show": true, + "type": "device_ip", + "default_value": "", + "options": [], + "localized": ["name"], + "name": [{"language_code": "en_us", "string": "IP" }] + }, + { + "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", + "mapped_to_column": "scanLastConnection", + "css_classes": "col-sm-2", + "show": true, + "type": "label", + "default_value": "", + "options": [], + "localized": ["name"], + "name": [{"language_code": "en_us", "string": "Changed"}] + }, + { + "column": "watchedValue1", + "css_classes": "col-sm-2", + "show": true, + "type": "label", + "default_value": "", + "options": [], + "localized": ["name"], + "name": [{"language_code": "en_us", "string": "Is active"}] + }, + { + "column": "watchedValue2", + "mapped_to_column": "scanName", + "css_classes": "col-sm-2", + "show": true, + "type": "label", + "default_value": "", + "options": [], + "localized": ["name"], + "name": [{"language_code": "en_us", "string": "Hostname"}] + }, + { + "column": "watchedValue4", + "css_classes": "col-sm-2", + "show": true, + "type": "label", + "default_value": "", + "options": [], + "localized": ["name"], + "name": [{"language_code": "en_us", "string": "State"}] + }, + { + "column": "userData", + "css_classes": "col-sm-2", + "show": false, + "type": "textbox_save", + "default_value": "", + "options": [], + "localized": ["name"], + "name": [{"language_code": "en_us", "string": "Comments"}] + }, + { + "column": "Dummy", + "mapped_to_column": "scanSourcePlugin", + "mapped_to_column_data": { + "value": "KEALSS" + }, + "css_classes": "col-sm-2", + "show": false, + "type": "label", + "default_value": "", + "options": [], + "localized": ["name"], + "name": [{"language_code": "en_us", "string": "Scan method"}] + }, + { + "column": "status", + "css_classes": "col-sm-1", + "show": true, + "type": "replace", + "default_value": "", + "options": [ + { + "equals": "watched-not-changed", + "replacement": "
" + }, + { + "equals": "watched-changed", + "replacement": "
" + }, + { + "equals": "new", + "replacement": "
" + }, + { + "equals": "missing-in-last-scan", + "replacement": "
" + } + ], + "localized": ["name"], + "name": [{"language_code": "en_us", "string": "Status"}] + } + ], + "settings": [ + { + "function": "RUN", + "events": ["run"], + "type": { + "dataType": "string", + "elements": [{"elementType": "select", "elementOptions": [], "transformers": []}] + }, + "default_value": "disabled", + "options": [ + "disabled", + "once", + "schedule", + "always_after_scan", + "on_new_device" + ], + "localized": ["name", "description"], + "name": [{"language_code": "en_us", "string": "When to run"}], + "description": [ + { + "language_code": "en_us", + "string": "Enable import of devices from Kea API. If you select schedule the scheduling settings from below are applied. If you select once the scan is run only once on start of the application (container) or after you update your settings. ⚠ Use the same schedule if you have multiple Device scanners enabled." + } + ] + }, + { + "function": "CMD", + "type": { + "dataType": "string", + "elements": [ + { "elementType": "input", "elementOptions": [], "transformers": [] } + ] + }, + "default_value": "python3 /app/front/plugins/kea_api/script.py", + "options": [], + "localized": ["name", "description"], + "name": [{"language_code": "en_us", "string": "Command"}], + "description": [{"language_code": "en_us", "string": "Command to run"}] + }, + { + "function": "URL", + "localized": ["name", "description"], + "name": [{"language_code": "en_us", "string": "API URL"}], + "description": [{"language_code": "en_us", "string": "Kea Control Agent URL"}], + "type": { + "dataType": "string", + "elements": [ + { + "elementType": "input", + "elementOptions": [], + "transformers": [] + } + ] + }, + "default_value": "http://127.0.0.1:8000" + }, + { + "function": "USER", + "localized": ["name", "description"], + "name": [{"language_code": "en_us", "string": "API User"}], + "description": [{"language_code": "en_us", "string": "Basic Auth Username"}], + "type": { + "dataType": "string", + "elements": [ + { + "elementType": "input", + "elementOptions": [], + "transformers": [] + } + ] + }, + "default_value": "kea-api" + }, + { + "function": "PASS", + "localized": ["name", "description"], + "name": [{"language_code": "en_us", "string": "API Password"}], + "description": [{"language_code": "en_us", "string": "Basic Auth Password"}], + "type": { + "dataType": "string", + "elements": [ + { + "elementType": "input", + "elementOptions": [{"type": "password"}], + "transformers": [] + } + ] + }, + "default_value": "" + }, + { + "function": "RUN_SCHD", + "type": { + "dataType": "string", + "elements": [ + { + "elementType": "span", + "elementOptions": [ + { + "cssClasses": "input-group-addon validityCheck" + }, + { + "getStringKey": "Gen_ValidIcon" + } + ], + "transformers": [] + }, + { + "elementType": "input", + "elementOptions": [ + { + "focusout": "validateRegex(this)" + }, + { + "base64Regex": "Xig/OlwqfCg/OlswLTldfFsxLTVdWzAtOV18WzAtOV0rLVswLTldK3xcKi9bMC05XSspKVxzKyg/OlwqfCg/OlswLTldfDFbMC05XXwyWzAtM118WzAtOV0rLVswLTldK3xcKi9bMC05XSspKVxzKyg/OlwqfCg/OlsxLTldfFsxMl1bMC05XXwzWzAxXXxbMC05XSstWzAtOV0rfFwqL1swLTldKykpXHMrKD86XCp8KD86WzEtOV18MVswLTJdfFswLTldKy1bMC05XSt8XCovWzAtOV0rKSlccysoPzpcKnwoPzpbMC02XXxbMC02XS1bMC02XXxcKi9bMC05XSspKSQ=" + } + ], + "transformers": [] + } + ] + }, + "default_value": "0 2 * * *", + "options": [], + "localized": ["name", "description"], + "name": [ + { + "language_code": "en_us", + "string": "Schedule" + } + ], + "description": [ + { + "language_code": "en_us", + "string": "Only enabled if you select schedule in the KEALSS_RUN setting. Make sure you enter the schedule in the correct cron-like format (e.g. validate at crontab.guru). For example entering 0 4 * * * will run the scan after 4 am in the TIMEZONE you set above. Will be run NEXT time the time passes.
It's recommended to use the same schedule interval for all plugins responsible for discovering new devices." + } + ] + }, + { + "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" + } + ], + "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." + } + ] + }, + { + "function": "SET_ALWAYS", + "type": { + "dataType": "array", + "elements": [ + { + "elementType": "select", + "elementOptions": [{ "multiple": "true", "orderable": "true"}], + "transformers": [] + } + ] + }, + "default_value": ["devMac", "devLastIP"], + "options": [ + "devMac", + "devLastIP" + ], + "localized": ["name", "description"], + "name": [ + { + "language_code": "en_us", + "string": "Set always columns" + } + ], + "description": [ + { + "language_code": "en_us", + "string": "These columns are treated as authoritative and will overwrite existing values, including those set by other plugins, unless the current value was explicitly set by the user (Source = USER or Source = LOCKED)." + } + ] + }, + { + "function": "SET_EMPTY", + "type": { + "dataType": "array", + "elements": [ + { + "elementType": "select", + "elementOptions": [{ "multiple": "true", "orderable": "true" }], + "transformers": [] + } + ] + }, + "default_value": [], + "options": [ + "devMac", + "devLastIP", + "devName", + "devSourcePlugin" + ], + "localized": ["name", "description"], + "name": [ + { + "language_code": "en_us", + "string": "Set empty columns" + } + ], + "description": [ + { + "language_code": "en_us", + "string": "These columns are only overwritten if they are empty (NULL / empty string) or if their Source is set to NEWDEV" + } + ] + }, + { + "function": "WATCH", + "type": { + "dataType": "array", + "elements": [ + { + "elementType": "select", + "elementOptions": [{ "multiple": "true", "orderable": "true"}], + "transformers": [] + } + ] + }, + "default_value": ["watchedValue1", "watchedValue4"], + "options": [ + "watchedValue1", + "watchedValue2", + "watchedValue4" + ], + "localized": ["name", "description"], + "name": [ + { + "language_code": "en_us", + "string": "Watched" + } + ], + "description": [ + { + "language_code": "en_us", + "string": "Send a notification if selected values change. Use CTRL + Click to select/deselect. " + } + ] + }, + { + "function": "REPORT_ON", + "type": { + "dataType": "array", + "elements": [ + { + "elementType": "select", + "elementOptions": [{ "multiple": "true", "orderable": "true"}], + "transformers": [] + } + ] + }, + "default_value": ["new", "watched-changed"], + "options": [ + "new", + "watched-changed", + "watched-not-changed", + "missing-in-last-scan" + ], + "localized": ["name", "description"], + "name": [ + { + "language_code": "en_us", + "string": "Report on" + } + ], + "description": [ + { + "language_code": "en_us", + "string": "Send a notification only on these statuses. new means a new unique (unique combination of PrimaryId and SecondaryId) object was discovered. watched-changed means that selected watchedValueN columns changed." + } + ] + } + ] +} \ No newline at end of file diff --git a/front/plugins/kea_api/script.py b/front/plugins/kea_api/script.py new file mode 100644 index 00000000..1f65253a --- /dev/null +++ b/front/plugins/kea_api/script.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +import os +import sys +import requests + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../server')) +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../plugins')) + +from plugin_helper import Plugin_Objects, mylog, handleEmpty, is_mac +from helper import get_setting_value +from const import logPath + +pluginName = "KEALSS" +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') + +plugin_objects = Plugin_Objects(RESULT_FILE) + + +def main(): + try: + url = get_setting_value(f'{pluginName}_URL') + user = get_setting_value(f'{pluginName}_USER') + password = get_setting_value(f'{pluginName}_PASS') + + mylog('verbose', [f'[{pluginName}] Querying Kea API at {url}']) + + payload = {'command': 'lease4-get-all', 'service': ['dhcp4']} + + response = requests.post(url, json=payload, auth=(user, password), timeout=10) + response.raise_for_status() + data = response.json() + + count = 0 + for entry in data: + # Result: 0 (success), 1 (error), or 3 (empty). + if entry.get("result") == 0: + leases = entry["arguments"].get("leases", []) + for l in leases: + mac = l['hw-address'] + state = l['state'] + if is_mac(mac): + plugin_objects.add_object( + primaryId = mac, + secondaryId = l['ip-address'], + # Active or not, similar to watched 1 of DHCPLSS plugin + watched1 = state == 0, + watched2 = l['hostname'], + watched3 = None, + # Default (or assigned) (0), declined (1), expired-reclaimed (2), released (3), and registered (4)). + watched4 = state, + extra = None, + foreignKey = mac + ) + count += 1 + elif entry.get("result") == 1: + mylog('none', [f'[{pluginName}] ⚠ ERROR: Kea API indicated error']) + + plugin_objects.write_result_file() + + mylog('verbose', [f'[{pluginName}] Successfully imported {count} devices reported by Kea API']) + + except Exception as e: + mylog('none', [f'[{pluginName}] ⚠ ERROR: {str(e)}']) + + + +if __name__ == '__main__': + main() From 608686e4bd3a88c7b492225e432a27d77adf2c69 Mon Sep 17 00:00:00 2001 From: void-spark <81029971+void-spark@users.noreply.github.com> Date: Mon, 11 May 2026 21:51:32 +0200 Subject: [PATCH 03/16] Add list with settings to readme --- front/plugins/kea_api/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/front/plugins/kea_api/README.md b/front/plugins/kea_api/README.md index 8a35edf2..6bbd2aa9 100755 --- a/front/plugins/kea_api/README.md +++ b/front/plugins/kea_api/README.md @@ -68,3 +68,20 @@ And you need to install kea-ctrl-agent, with a config that looks something like ``` You will need to configure the plugin with the URL to the API, and the username and password configured above (from kea-api-password file in the example) + + +#### Required Settings + +These settings are required, besides the common device scanner settings: + +- **Kea Control Agent URL** (`KEALSS_URL`): The full URL, including port number, to the Kea API. + - Default: `http://127.0.0.1:8000` + - This mirrors what you set up in the kea-ctrl-agent configuration. + +- **Basic Auth Username** (`KEALSS_USER`): The user to use for authenticating with the Kea API. + - Default: `kea-api` + - This mirrors what you set up in the kea-ctrl-agent configuration. + +- **Basic Auth Password** (`KEALSS_PASS`): The password to use for authenticating with the Kea API. + - This mirrors what you set up in the kea-ctrl-agent configuration. + - When using a password file, it should be the content of the password file. From 7273899e3ec51e01f4648efe5cd6e44e27e15ba6 Mon Sep 17 00:00:00 2001 From: void-spark <81029971+void-spark@users.noreply.github.com> Date: Mon, 11 May 2026 22:03:29 +0200 Subject: [PATCH 04/16] Use single quote consistently Use 'l' instead of 'lease' (I see you little rabbit) Use [] over get in most places, if expected fields are missing an error is an acceptable outcome. Include 'text' field in logging. Add logging for result '3' --- front/plugins/kea_api/script.py | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/front/plugins/kea_api/script.py b/front/plugins/kea_api/script.py index 1f65253a..74d543f8 100644 --- a/front/plugins/kea_api/script.py +++ b/front/plugins/kea_api/script.py @@ -10,8 +10,8 @@ from plugin_helper import Plugin_Objects, mylog, handleEmpty, is_mac from helper import get_setting_value from const import logPath -pluginName = "KEALSS" -LOG_PATH = logPath + "/plugins" +pluginName = 'KEALSS' +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') @@ -34,19 +34,20 @@ def main(): count = 0 for entry in data: + text = entry.get('text', '[API provided no text]'); # Result: 0 (success), 1 (error), or 3 (empty). - if entry.get("result") == 0: - leases = entry["arguments"].get("leases", []) - for l in leases: - mac = l['hw-address'] - state = l['state'] + if entry['result'] == 0: + leases = entry['arguments']['leases'] + for lease in leases: + mac = lease['hw-address'] + state = lease['state'] if is_mac(mac): plugin_objects.add_object( primaryId = mac, - secondaryId = l['ip-address'], - # Active or not, similar to watched 1 of DHCPLSS plugin + secondaryId = lease['ip-address'], + # Active or not, similar to watched1 of DHCPLSS plugin watched1 = state == 0, - watched2 = l['hostname'], + watched2 = lease['hostname'], watched3 = None, # Default (or assigned) (0), declined (1), expired-reclaimed (2), released (3), and registered (4)). watched4 = state, @@ -54,12 +55,15 @@ def main(): foreignKey = mac ) count += 1 - elif entry.get("result") == 1: - mylog('none', [f'[{pluginName}] ⚠ ERROR: Kea API indicated error']) + plugin_objects.write_result_file() - plugin_objects.write_result_file() + mylog('verbose', [f'[{pluginName}] Kea API response: {text}']) + mylog('verbose', [f'[{pluginName}] Successfully imported {count} devices reported by Kea API']) + elif entry['result'] == 1: + mylog('none', [f'[{pluginName}] ⚠ ERROR: Kea API indicated error: {text}']) + elif entry['result'] == 3: + mylog('verbose', [f'[{pluginName}] Kea API indicates no entries found: {text}']) - mylog('verbose', [f'[{pluginName}] Successfully imported {count} devices reported by Kea API']) except Exception as e: mylog('none', [f'[{pluginName}] ⚠ ERROR: {str(e)}']) From 76612e5d0ea5796172c8e5ededef4a750d1f23ba Mon Sep 17 00:00:00 2001 From: void-spark <81029971+void-spark@users.noreply.github.com> Date: Mon, 11 May 2026 22:09:07 +0200 Subject: [PATCH 05/16] Change default timeout to 10 seconds, match request timeout to script timeout -1 second. Always use at least 1 sec. timeout for request. --- front/plugins/kea_api/config.json | 2 +- front/plugins/kea_api/script.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/front/plugins/kea_api/config.json b/front/plugins/kea_api/config.json index ffa434bd..6bc00f3d 100644 --- a/front/plugins/kea_api/config.json +++ b/front/plugins/kea_api/config.json @@ -306,7 +306,7 @@ } ] }, - "default_value": 5, + "default_value": 10, "options": [], "localized": ["name", "description"], "name": [ diff --git a/front/plugins/kea_api/script.py b/front/plugins/kea_api/script.py index 74d543f8..a772929d 100644 --- a/front/plugins/kea_api/script.py +++ b/front/plugins/kea_api/script.py @@ -23,12 +23,13 @@ def main(): url = get_setting_value(f'{pluginName}_URL') user = get_setting_value(f'{pluginName}_USER') password = get_setting_value(f'{pluginName}_PASS') + timeout = get_setting_value(f'{pluginName}_RUN_TIMEOUT') mylog('verbose', [f'[{pluginName}] Querying Kea API at {url}']) payload = {'command': 'lease4-get-all', 'service': ['dhcp4']} - response = requests.post(url, json=payload, auth=(user, password), timeout=10) + response = requests.post(url, json=payload, auth=(user, password), timeout=max(1, timeout - 1)) response.raise_for_status() data = response.json() From 957c779cb5b326b5abfb754fb2772f7344f29d30 Mon Sep 17 00:00:00 2001 From: void-spark <81029971+void-spark@users.noreply.github.com> Date: Mon, 11 May 2026 22:16:51 +0200 Subject: [PATCH 06/16] Add KEALSS to plugin list --- docs/PLUGINS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/PLUGINS.md b/docs/PLUGINS.md index d108aeea..e8224fd2 100755 --- a/docs/PLUGINS.md +++ b/docs/PLUGINS.md @@ -62,6 +62,7 @@ Device-detecting plugins insert values into the `CurrentScan` database table. T | `INTRNT` | [internet_ip](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/internet_ip/) | 🔍 | Internet IP scanner | | | | `INTRSPD` | [internet_speedtest](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/internet_speedtest/) | ♻ | Internet speed test | | | | `IPNEIGH` | [ipneigh](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/ipneigh/) | 🔍 | Scan ARP (IPv4) and NDP (IPv6) tables | | | +| `KEALSS` | [kea_api](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/kea_api/) | 🔍/🆎 | Pull lease data from the Kea DHCP API | | | | `LUCIRPC` | [luci_import](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/luci_import/) | 🔍 | Import connected devices from OpenWRT | | | | `MAINT` | [maintenance](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/maintenance/) | ⚙ | Maintenance of logs, etc. | | | | `MQTT` | [_publisher_mqtt](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/_publisher_mqtt/) | ▶️ | MQTT for synching to Home Assistant | | | From 39068e982442f715436bd879d5b8d51494e57966 Mon Sep 17 00:00:00 2001 From: void-spark <81029971+void-spark@users.noreply.github.com> Date: Mon, 11 May 2026 22:21:10 +0200 Subject: [PATCH 07/16] And 'notes' to README.md --- front/plugins/kea_api/README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/front/plugins/kea_api/README.md b/front/plugins/kea_api/README.md index 6bbd2aa9..9ddc174c 100755 --- a/front/plugins/kea_api/README.md +++ b/front/plugins/kea_api/README.md @@ -85,3 +85,15 @@ These settings are required, besides the common device scanner settings: - **Basic Auth Password** (`KEALSS_PASS`): The password to use for authenticating with the Kea API. - This mirrors what you set up in the kea-ctrl-agent configuration. - When using a password file, it should be the content of the password file. + + +### Notes + +- This was tested on a basic Debian 13 install. +- When you install kea-ctrl-agent, it should ask you about creating a password. +- It's possible to run kea-ctrl-agent without password, but it's not recommended and at the moment we don't support that. +- I may provide some minimal support, if you ask nicely :) + +- Version: 1.0.0 +- Author: `void-spark` +- Release Date: `11/05/2026` From 6d661dd12c09476ee9e784ebc3fba3a1f42f7651 Mon Sep 17 00:00:00 2001 From: void-spark <81029971+void-spark@users.noreply.github.com> Date: Mon, 11 May 2026 22:29:37 +0200 Subject: [PATCH 08/16] I did add a ';' from habit, removed again, must please the bunny :) --- front/plugins/kea_api/script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/plugins/kea_api/script.py b/front/plugins/kea_api/script.py index a772929d..9dc72d8c 100644 --- a/front/plugins/kea_api/script.py +++ b/front/plugins/kea_api/script.py @@ -35,7 +35,7 @@ def main(): count = 0 for entry in data: - text = entry.get('text', '[API provided no text]'); + text = entry.get('text', '[API provided no text]') # Result: 0 (success), 1 (error), or 3 (empty). if entry['result'] == 0: leases = entry['arguments']['leases'] From 2fac87579200b34e23001415c316404a57a5ba80 Mon Sep 17 00:00:00 2001 From: anton garcias Date: Mon, 11 May 2026 17:55:32 +0200 Subject: [PATCH 09/16] Translated using Weblate (Catalan) Currently translated at 99.7% (807 of 809 strings) Translation: NetAlertX/core Translate-URL: https://hosted.weblate.org/projects/pialert/core/ca/ --- front/php/templates/language/ca_ca.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/front/php/templates/language/ca_ca.json b/front/php/templates/language/ca_ca.json index 807ab146..4e28136c 100644 --- a/front/php/templates/language/ca_ca.json +++ b/front/php/templates/language/ca_ca.json @@ -66,8 +66,8 @@ "CustProps_cant_remove": "No es pot eliminar, es necessita una propietat mínim.", "DAYS_TO_KEEP_EVENTS_description": "Això és una configuració de manteniment. Especifica el nombre de dies que es conservaran els esdeveniments. Els esdeveniments antics s'esborraran periòdicament. També aplica als esdeveniments dels Connectors (Plugins).", "DAYS_TO_KEEP_EVENTS_name": "Esborrar esdeveniments més vells de", - "DEEP_SLEEP_description": "", - "DEEP_SLEEP_name": "", + "DEEP_SLEEP_description": "Redueix l'ús de la CPU ampliant els temps d'espera inactiu entre els cicles de processament. Quan està activat, les exploracions es poden retardar fins a 1 minut i la interfície d'usuari pot ser menys sensible.", + "DEEP_SLEEP_name": "Son profund", "DISCOVER_PLUGINS_description": "Desactiva aquesta opció per accelerar la inicialització i l'estalvi de configuració. Quan està desactivat, els connectors no es descobreixen, i no podeu afegir nous connectors a la configuració LOADED_PLUGINS.", "DISCOVER_PLUGINS_name": "Descobreix els plugins", "DevDetail_Children_Title": "Relacions filles", @@ -141,7 +141,7 @@ "DevDetail_SessionTable_Duration": "Durada", "DevDetail_SessionTable_IP": "IP", "DevDetail_SessionTable_Order": "Ordre", - "DevDetail_Shortcut_CurrentStatus": "Estat actual", + "DevDetail_Shortcut_CurrentStatus": "Estat", "DevDetail_Shortcut_DownAlerts": "Aturar alertes", "DevDetail_Shortcut_Presence": "Presència", "DevDetail_Shortcut_Sessions": "Sessions", @@ -250,7 +250,7 @@ "Device_TableHead_NetworkSite": "Network Site", "Device_TableHead_Owner": "Propietari", "Device_TableHead_ParentRelType": "Tipus de relació", - "Device_TableHead_Parent_MAC": "Node pare de xarxa", + "Device_TableHead_Parent_MAC": "Node pare", "Device_TableHead_Port": "Port", "Device_TableHead_PresentLastScan": "Presència", "Device_TableHead_ReqNicsOnline": "Requereix NICs En línia", @@ -346,7 +346,7 @@ "Gen_LockedDB": "ERROR - DB podria estar bloquejada - Fes servir F12 Eines desenvolupament -> Consola o provar-ho més tard.", "Gen_NetworkMask": "Màscara de xarxa", "Gen_New": "Nou", - "Gen_No_Data": "", + "Gen_No_Data": "Sense dades", "Gen_Offline": "Fora de línia", "Gen_Okay": "Ok", "Gen_Online": "En línia", @@ -808,4 +808,4 @@ "settings_system_label": "Sistema", "settings_update_item_warning": "Actualitza el valor sota. Sigues curós de seguir el format anterior. No hi ha validació.", "test_event_tooltip": "Deseu els canvis primer abans de comprovar la configuració." -} \ No newline at end of file +} From f11a63bb7f48b38080cc6f34bd440e622805b22f Mon Sep 17 00:00:00 2001 From: jokob-sk Date: Wed, 13 May 2026 08:43:04 +1000 Subject: [PATCH 10/16] BE: DIGSCAN could not be disbaled due to default RUN set in config.json #1631 --- back/app.conf | 1 + front/plugins/dig_scan/config.json | 2 +- server/initialise.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/back/app.conf b/back/app.conf index 95fcf24f..4add3c21 100755 --- a/back/app.conf +++ b/back/app.conf @@ -30,6 +30,7 @@ REPORT_DASHBOARD_URL='update_REPORT_DASHBOARD_URL_setting' INTRNT_RUN='schedule' ARPSCAN_RUN='schedule' NSLOOKUP_RUN='before_name_updates' +DIGSCAN_RUN='before_name_updates' AVAHISCAN_RUN='before_name_updates' NBTSCAN_RUN='before_name_updates' diff --git a/front/plugins/dig_scan/config.json b/front/plugins/dig_scan/config.json index fb39b55d..9c176e7f 100755 --- a/front/plugins/dig_scan/config.json +++ b/front/plugins/dig_scan/config.json @@ -52,7 +52,7 @@ { "elementType": "select", "elementOptions": [], "transformers": [] } ] }, - "default_value": "before_name_updates", + "default_value": "disabled", "options": [ "disabled", "before_name_updates", diff --git a/server/initialise.py b/server/initialise.py index 9509b06b..bf53c494 100755 --- a/server/initialise.py +++ b/server/initialise.py @@ -488,7 +488,7 @@ def importConfigs(pm, db, all_plugins): # Plugins START # ----------------- - # necessary_plugins = ['UI', 'CUSTPROP', 'CLOUD' ,'DBCLNP', 'INTRNT','MAINT','NEWDEV', 'SETPWD', 'SYNC', 'VNDRPDT', 'WORKFLOWS'] + # necessary_plugins = ['UI', 'CUSTPROP', 'HEARTBEAT' ,'DBCLNP', 'INTRNT','MAINT','NEWDEV', 'SETPWD', 'SYNC', 'VNDRPDT', 'WORKFLOWS'] necessary_plugins = [ "UI", "CUSTPROP", From 13f88583194a173437a89d05f8d222984804d96d Mon Sep 17 00:00:00 2001 From: jokob-sk Date: Wed, 13 May 2026 08:43:04 +1000 Subject: [PATCH 11/16] BE: Less verbose SYNC plugin #1164 --- back/app.conf | 1 + front/plugins/dig_scan/config.json | 2 +- server/api_server/sync_endpoint.py | 10 ++++++++-- server/initialise.py | 2 +- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/back/app.conf b/back/app.conf index 95fcf24f..4add3c21 100755 --- a/back/app.conf +++ b/back/app.conf @@ -30,6 +30,7 @@ REPORT_DASHBOARD_URL='update_REPORT_DASHBOARD_URL_setting' INTRNT_RUN='schedule' ARPSCAN_RUN='schedule' NSLOOKUP_RUN='before_name_updates' +DIGSCAN_RUN='before_name_updates' AVAHISCAN_RUN='before_name_updates' NBTSCAN_RUN='before_name_updates' diff --git a/front/plugins/dig_scan/config.json b/front/plugins/dig_scan/config.json index fb39b55d..9c176e7f 100755 --- a/front/plugins/dig_scan/config.json +++ b/front/plugins/dig_scan/config.json @@ -52,7 +52,7 @@ { "elementType": "select", "elementOptions": [], "transformers": [] } ] }, - "default_value": "before_name_updates", + "default_value": "disabled", "options": [ "disabled", "before_name_updates", diff --git a/server/api_server/sync_endpoint.py b/server/api_server/sync_endpoint.py index 23529161..51d1704b 100755 --- a/server/api_server/sync_endpoint.py +++ b/server/api_server/sync_endpoint.py @@ -1,13 +1,15 @@ import os import base64 from flask import jsonify, request -from logger import mylog +from logger import mylog, Logger from helper import get_setting_value from utils.datetime_utils import timeNowUTC from messaging.in_app import write_notification INSTALL_PATH = os.getenv("NETALERTX_APP", "/app") +# Make sure log level is initialized correctly +lggr = Logger(get_setting_value('LOG_LEVEL')) def handle_sync_get(): """Handle GET requests for SYNC (NODE → HUB).""" @@ -28,7 +30,11 @@ def handle_sync_get(): response_data = base64.b64encode(raw_data).decode("utf-8") - write_notification("[Plugin: SYNC] Data sent", "info", timeNowUTC()) + message = "[Plugin: SYNC] Data sent" + mylog('verbose', [message]) + if lggr.isAbove('verbose'): + write_notification(message, 'info', timeNowUTC()) + return jsonify({ "node_name": get_setting_value("SYNC_node_name"), "status": 200, diff --git a/server/initialise.py b/server/initialise.py index 9509b06b..bf53c494 100755 --- a/server/initialise.py +++ b/server/initialise.py @@ -488,7 +488,7 @@ def importConfigs(pm, db, all_plugins): # Plugins START # ----------------- - # necessary_plugins = ['UI', 'CUSTPROP', 'CLOUD' ,'DBCLNP', 'INTRNT','MAINT','NEWDEV', 'SETPWD', 'SYNC', 'VNDRPDT', 'WORKFLOWS'] + # necessary_plugins = ['UI', 'CUSTPROP', 'HEARTBEAT' ,'DBCLNP', 'INTRNT','MAINT','NEWDEV', 'SETPWD', 'SYNC', 'VNDRPDT', 'WORKFLOWS'] necessary_plugins = [ "UI", "CUSTPROP", From 03938d8c28aef34f53d143bd330e149192531258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B3nio=20Oliveira?= Date: Wed, 13 May 2026 18:42:59 +0200 Subject: [PATCH 12/16] Translated using Weblate (Portuguese (Portugal)) Currently translated at 100.0% (809 of 809 strings) Translation: NetAlertX/core Translate-URL: https://hosted.weblate.org/projects/pialert/core/pt_PT/ --- front/php/templates/language/pt_pt.json | 82 ++++++++++++------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/front/php/templates/language/pt_pt.json b/front/php/templates/language/pt_pt.json index 15aca397..a5629325 100644 --- a/front/php/templates/language/pt_pt.json +++ b/front/php/templates/language/pt_pt.json @@ -37,7 +37,7 @@ "BackDevDetail_Tools_WOL_error": "O comando NÃO foi executado.", "BackDevDetail_Tools_WOL_okay": "O comando foi executado.", "BackDevices_Arpscan_disabled": "Análise Arp Desativada", - "BackDevices_Arpscan_enabled": "Análise ARP Ativada", + "BackDevices_Arpscan_enabled": "Análise Arp Ativada", "BackDevices_Backup_CopError": "A base da dados original não pode ser gravada.", "BackDevices_Backup_Failed": "A copia de segurança foi parcialmente executada. O arquivo não pode ser criado ou está vazio.", "BackDevices_Backup_okay": "A copia de segurança foi feita executado corretamente com o novo arquivo", @@ -61,14 +61,14 @@ "BackDevices_Restore_okay": "Restauração executada com sucesso.", "BackDevices_darkmode_disabled": "Modo Noturno Desativado", "BackDevices_darkmode_enabled": "Modo Noturno Ativado", - "CLEAR_NEW_FLAG_description": "Se ativado (0 está desativado), dispositivos marcados comoNovo Dispositivo serão desmarcados se o limite (especificado em horas) exceder o tempo da Primeira Sessão .", + "CLEAR_NEW_FLAG_description": "Se ativado (0 está desativado), dispositivos marcados como Novo Dispositivo serão desmarcados se o limite (especificado em horas) exceder o tempo da Primeira Sessão.", "CLEAR_NEW_FLAG_name": "Limpar a flag nova", "CustProps_cant_remove": "Não é possível remover, é necessária pelo menos uma propriedade.", "DAYS_TO_KEEP_EVENTS_description": "Esta é uma definição de manutenção. Especifica o número de dias de entradas de eventos que serão mantidas. Todos os eventos mais antigos serão apagados periodicamente. Também se aplica ao Histórico de eventos do plug-in.", "DAYS_TO_KEEP_EVENTS_name": "Apagar eventos mais antigos que", "DEEP_SLEEP_description": "Diminui a utilização do CPU ao prolongar tempos de espera ociosos entre ciclos de processamento. Quando ativo, análises podem ser atrasadas por até 1 minuto e o UI pode ficar menos responsivo.", "DEEP_SLEEP_name": "Sleep profundo", - "DISCOVER_PLUGINS_description": "Desative esta opção para acelerar a inicialização e a gravação de definições. Quando desativada, os plug-ins não são descobertos e não é possível adicionar novos plug-ins à definiçãoLOADED_PLUGINS.", + "DISCOVER_PLUGINS_description": "Desative esta opção para acelerar a inicialização e a gravação de definições. Quando desativada, os plug-ins não são descobertos e não é possível adicionar novos plug-ins à definição LOADED_PLUGINS.", "DISCOVER_PLUGINS_name": "Descobrir plugins", "DevDetail_Children_Title": "Relacionamentos de crianças", "DevDetail_Copy_Device_Title": "Copiar pormenores do dispositivo", @@ -98,7 +98,7 @@ "DevDetail_MainInfo_Location": "Localização", "DevDetail_MainInfo_Name": "Nome", "DevDetail_MainInfo_Network": " Node (MAC)", - "DevDetail_MainInfo_Network_Port": "Porta", + "DevDetail_MainInfo_Network_Port": " Porta", "DevDetail_MainInfo_Network_Site": "Site", "DevDetail_MainInfo_Network_Title": "Detalhes de Rede", "DevDetail_MainInfo_Owner": "Proprietário", @@ -341,7 +341,7 @@ "Gen_Filter": "Filtro", "Gen_Flapping": "Flapping", "Gen_Generate": "Gerar", - "Gen_InvalidMac": "Endereço MAC Inválido.", + "Gen_InvalidMac": "Endereço Mac inválido.", "Gen_Invalid_Value": "Um valor inválido foi inserido", "Gen_LockedDB": "ERRO - A base de dados pode estar bloqueada - Verifique F12 Ferramentas de desenvolvimento -> Console ou tente mais tarde.", "Gen_NetworkMask": "Máscara de Rede", @@ -350,7 +350,7 @@ "Gen_Offline": "Offline", "Gen_Okay": "Ok", "Gen_Online": "Online", - "Gen_Purge": "Purge", + "Gen_Purge": "Purgar", "Gen_ReadDocs": "Leia mais em documentos.", "Gen_Remove_All": "Remover tudo", "Gen_Remove_Last": "Remover o último", @@ -495,7 +495,7 @@ "Maintenance_Tool_upgrade_database_noti_text": "Tem certeza de que deseja atualizar a base de dados?
(talvez prefira arquivá-la)", "Maintenance_Tool_upgrade_database_text": "Este botão atualizará a base de dados para ativar o gráfico Atividade de rede nas últimas 12 horas. Faça uma cópia de segurança da sua base de dados em caso de problemas.", "Maintenance_Tools_Tab_BackupRestore": "Backup / Restauração", - "Maintenance_Tools_Tab_Logging": "Logs", + "Maintenance_Tools_Tab_Logging": "Registos", "Maintenance_Tools_Tab_Settings": "Configurações", "Maintenance_Tools_Tab_Tools": "Ferramentas", "Maintenance_Tools_Tab_UISettings": "Configurações de interface", @@ -503,7 +503,7 @@ "Maintenance_arp_status_off": "está atualmente desativado", "Maintenance_arp_status_on": "Scan em curso", "Maintenance_built_on": "Construído em", - "Maintenance_current_version": "Você está atualizado. Confira o que estou a trabalhar em.", + "Maintenance_current_version": "Você está atualizado. Confira no que é que estou a trabalhar em.", "Maintenance_database_backup": "Backups DB", "Maintenance_database_backup_found": "foram encontrados backups", "Maintenance_database_backup_total": "uso total do disco", @@ -538,7 +538,7 @@ "Navigation_Report": "Reports enviados", "Navigation_Settings": "Definições", "Navigation_SystemInfo": "Informação de sistema", - "Navigation_Workflows": "Workflows", + "Navigation_Workflows": "Fluxos de Trabalho", "Network_Assign": "Conectar ao nodo de network em cima", "Network_Cant_Assign": "Não é possível atribuir o node raiz da Internet como um node folha filho.", "Network_Cant_Assign_No_Node_Selected": "Não é possível atribuir, nenhum node pai selecionado.", @@ -565,13 +565,13 @@ "Network_ManageEdit_Name": "Novo nome de dispositivo", "Network_ManageEdit_Name_text": "Nome sem caracteres especiais", "Network_ManageEdit_Port": " Nova contagem de portas", - "Network_ManageEdit_Port_text": "Deixe em branco para Wi-Fi e Powerline.", + "Network_ManageEdit_Port_text": "Deixe em branco para Wi-Fi e Powerline", "Network_ManageEdit_Submit": "Guardar Alterações", "Network_ManageEdit_Type": "Novo tipo de dispositivo", "Network_ManageEdit_Type_text": "-- Selecionar tipo --", "Network_ManageLeaf": "Gerir atribuição", "Network_ManageUnassign": "Cancelar Atribuição", - "Network_NoAssignedDevices": "Este nó de rede não tem quaisquer dispositivos atribuídos (nós folha). Atribua um abaixo ou vá ao separador Detalhes em qualquer dispositivo em Dispositivos, e atribua-o a um Nó de rede (MAC) e Porta lá.", + "Network_NoAssignedDevices": "Este nó de rede não tem quaisquer dispositivos atribuídos (nós folha). Atribua um abaixo ou vá à aba Detalhes de qualquer dispositivo em Dispositivos, e atribua os mesmos a uma rede Nó (MAC) e Porta lá.", "Network_NoDevices": "Sem dispositivos para configurar", "Network_Node": "Nó de rede", "Network_Node_Name": "Nome do nó", @@ -777,35 +777,35 @@ "new_version_available": "Uma versão nova está disponível.", "report_guid": "Guid de Notificação:", "report_guid_missing": "Notificação associada não foi encontrada. Há um pequeno atraso entre notificações recentemente enviadas e as mesmas estarem disponíveis. Atualize a sua página e cache após alguns segundos. Também é possível que a notificação selecionada tenha sido eliminada durante a manutenção como especificado na definição DBCLNP_NOTIFI_HIST.

Em vez disso, a última notificação é mostrada. A notificação em falta tem o seguinte GUID:", - "report_select_format": "", - "report_time": "", - "run_event_tooltip": "", - "select_icon_event_tooltip": "", - "settings_core_icon": "", - "settings_core_label": "", - "settings_device_scanners": "", - "settings_device_scanners_icon": "", - "settings_device_scanners_info": "", - "settings_device_scanners_label": "", - "settings_enabled": "", - "settings_enabled_icon": "", - "settings_expand_all": "", - "settings_imported": "", - "settings_imported_label": "", - "settings_missing": "", - "settings_missing_block": "", - "settings_old": "", - "settings_other_scanners": "", - "settings_other_scanners_icon": "", - "settings_other_scanners_label": "", - "settings_publishers": "", - "settings_publishers_icon": "", - "settings_publishers_info": "", - "settings_publishers_label": "", - "settings_readonly": "", - "settings_saved": "", - "settings_system_icon": "", - "settings_system_label": "", - "settings_update_item_warning": "", + "report_select_format": "Selecionar Formato:", + "report_time": "Tempo de notificação:", + "run_event_tooltip": "Ative a definição e guarde as suas mudanças primeiro antes de corrê-lo.", + "select_icon_event_tooltip": "Selecionar ícone", + "settings_core_icon": "fa-solid fa-gem", + "settings_core_label": "Core", + "settings_device_scanners": "Scaneadores de dispositivos usados para descobrir dispositivos que escrevem para a tabela da base de dados CurrentScan.", + "settings_device_scanners_icon": "fa-solid fa-magnifying-glass-plus", + "settings_device_scanners_info": "Carregar mais scaneadores de dispositivos com a definição LOADED_PLUGINS", + "settings_device_scanners_label": "Scaneadores de dispositivos", + "settings_enabled": "Definições ativas", + "settings_enabled_icon": "fa-solid fa-toggle-on", + "settings_expand_all": "Expandir todos", + "settings_imported": "Na última vez, as definições foram importadas a partir do ficheiro app.conf", + "settings_imported_label": "Definições importadas", + "settings_missing": "Nem todas as configurações foram carregadas! Carga elevada na base de dados ou na sequência de começo da aplicação. Clique no botão 🔄 de atualizar no topo.", + "settings_missing_block": "Erro: Definições não carregadas corretamente. Clique no botão 🔄 de atualizar no topo ou, alternativamente, verifique o registo do navegador para detalhes (F12).", + "settings_old": "A importar definições e a reinicializar…", + "settings_other_scanners": "Outros plugins de scaneadores que não são do dispositivo estão atualmente ativos.", + "settings_other_scanners_icon": "fa-solid fa-recycle", + "settings_other_scanners_label": "Outros scaneadores", + "settings_publishers": "Gateways de notificação ativados - editores que enviarão uma notificação de acordo com as suas definições.", + "settings_publishers_icon": "fa-solid fa-paper-plane", + "settings_publishers_info": "Carregar mais Editores com a definição LOADED_PLUGINS", + "settings_publishers_label": "Editores", + "settings_readonly": "Não foi possível LÊR ou ESCREVER na app.conf. Tente reiniciar o contentoer e ler a documentação de permissões de ficheiro", + "settings_saved": "
Definições guardadas.
A recarregar...

", + "settings_system_icon": "fa-solid fa-gear", + "settings_system_label": "Sistema", + "settings_update_item_warning": "Atualize o valor abaixo. Tenha cuidado em seguir o formato anterior. Validação não é efetuada.", "test_event_tooltip": "Guarde as alterações antes de testar as definições." } From 198ca5d4106a4086a0f3d8a0f828de02e8d028ae Mon Sep 17 00:00:00 2001 From: Safeguard Date: Thu, 14 May 2026 19:46:41 +0200 Subject: [PATCH 13/16] Translated using Weblate (Russian) Currently translated at 100.0% (809 of 809 strings) Translation: NetAlertX/core Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/ --- front/php/templates/language/ru_ru.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/php/templates/language/ru_ru.json b/front/php/templates/language/ru_ru.json index eb2acbe3..4d6b1732 100644 --- a/front/php/templates/language/ru_ru.json +++ b/front/php/templates/language/ru_ru.json @@ -27,7 +27,7 @@ "AppEvents_ObjectType": "Тип объекта", "AppEvents_Plugin": "Плагин", "AppEvents_Type": "Тип", - "BACKEND_API_URL_description": "Используется для обеспечения связи между фронтендом и бэкендом. По умолчанию это значение установлено на /server и, как правило, не должно изменяться.", + "BACKEND_API_URL_description": "Используется для обеспечения связи между фронтендом и бэкендом. По умолчанию это значение установлено на /server и, как правило, не должно изменяться.", "BACKEND_API_URL_name": "URL-адрес серверного API", "BackDevDetail_Actions_Ask_Run": "Вы хотите выполнить действие?", "BackDevDetail_Actions_Not_Registered": "Действие не зарегистрировано:· ", From 35dc9f9fa0f6ade39f2c12e24c176b6462417387 Mon Sep 17 00:00:00 2001 From: npt-1707 Date: Mon, 18 May 2026 06:15:43 +0800 Subject: [PATCH 14/16] front/lib/moment/moment.js: Avoid loading path-looking locales from fs --- front/lib/moment/moment.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/front/lib/moment/moment.js b/front/lib/moment/moment.js index 1b129716..5a21cf45 100755 --- a/front/lib/moment/moment.js +++ b/front/lib/moment/moment.js @@ -1842,11 +1842,16 @@ return globalLocale; } + function isLocaleNameSane(name) { + // Prevent names that look like filesystem paths, i.e contain '/' or '\' + return name.match('^[^/\\\\]*$') != null; + } + function loadLocale(name) { var oldLocale = null; // TODO: Find a better way to register and load all the locales in Node if (!locales[name] && (typeof module !== 'undefined') && - module && module.exports) { + module && module.exports && isLocaleNameSane(name)) { try { oldLocale = globalLocale._abbr; var aliasedRequire = require; From 0517da24056d081a10cac363ccb4354035ce2513 Mon Sep 17 00:00:00 2001 From: npt-1707 Date: Mon, 18 May 2026 06:17:10 +0800 Subject: [PATCH 15/16] front/lib/moment/moment.js: fix redos using local backtracking regex --- front/lib/moment/moment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/lib/moment/moment.js b/front/lib/moment/moment.js index 1b129716..b5c59233 100755 --- a/front/lib/moment/moment.js +++ b/front/lib/moment/moment.js @@ -2294,7 +2294,7 @@ function preprocessRFC2822(s) { // Remove comments and folding whitespace and replace multiple-spaces with a single space - return s.replace(/\([^)]*\)|[\n\t]/g, ' ').replace(/(\s\s+)/g, ' ').replace(/^\s\s*/, '').replace(/\s\s*$/, ''); + return s.replace(/\((?:(?!\().)*\)|[\n\t]/gs, ' ').replace(/(\s\s+)/g, ' ').replace(/^\s\s*/, '').replace(/\s\s*$/, ''); } function checkWeekday(weekdayStr, parsedInput, config) { From 80c8a66396149edb452e3943bd47b808e422d4dc Mon Sep 17 00:00:00 2001 From: npt-1707 Date: Mon, 18 May 2026 06:19:59 +0800 Subject: [PATCH 16/16] front/lib/datatables/datatables.js: Fix XSS in Alert, Carousel, Collapse, Dropdown and Modal --- front/lib/datatables/datatables.js | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/front/lib/datatables/datatables.js b/front/lib/datatables/datatables.js index 2027407d..168f9fe8 100755 --- a/front/lib/datatables/datatables.js +++ b/front/lib/datatables/datatables.js @@ -10832,7 +10832,8 @@ if (typeof jQuery === 'undefined') { selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 } - var $parent = $(selector === '#' ? [] : selector) + selector = selector === '#' ? [] : selector + var $parent = $(document).find(selector) if (e) e.preventDefault() @@ -11228,9 +11229,15 @@ if (typeof jQuery === 'undefined') { // ================= var clickHandler = function (e) { - var href var $this = $(this) - var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7 + var href = $this.attr('href') + if (href) { + href = href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7 + } + + var target = $this.attr('data-target') || href + var $target = $(document).find(target) + if (!$target.hasClass('carousel')) return var options = $.extend({}, $target.data(), $this.data()) var slideIndex = $this.attr('data-slide-to') @@ -11420,7 +11427,7 @@ if (typeof jQuery === 'undefined') { var target = $trigger.attr('data-target') || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7 - return $(target) + return $(document).find(target) } @@ -11502,7 +11509,7 @@ if (typeof jQuery === 'undefined') { selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 } - var $parent = selector && $(selector) + var $parent = selector && $(document).find(selector) return $parent && $parent.length ? $parent : $this.parent() } @@ -11961,7 +11968,10 @@ if (typeof jQuery === 'undefined') { $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) { var $this = $(this) var href = $this.attr('href') - var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7 + var target = $this.attr('data-target') || + (href && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7 + + var $target = $(document).find(target) var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data()) if ($this.is('a')) e.preventDefault()