From 10e8c08ce3657103cd273ae213be32aef248a19a Mon Sep 17 00:00:00 2001 From: jokob-sk Date: Thu, 5 Jun 2025 13:38:43 +1000 Subject: [PATCH] initCheck #1065 --- back/app.conf | 2 +- docker-compose.yml | 1 + docs/INITIAL_SETUP.md | 107 +++++++++++++++----- docs/NAME_RESOLUTION.md | 6 ++ docs/REVERSE_DNS.md | 5 + front/css/app.css | 38 +++++++ front/devices.php | 4 +- front/initCheck.php | 52 ++++++++++ front/js/common.js | 71 ++++++++----- front/js/tests.js | 128 ++++++++++++++++++++++++ front/maintenance.php | 70 +++++++++---- front/multiEditCore.php | 4 - front/php/templates/header.php | 3 + front/php/templates/language/ar_ar.json | 5 + front/php/templates/language/ca_ca.json | 5 + front/php/templates/language/cs_cz.json | 5 + front/php/templates/language/de_de.json | 5 + front/php/templates/language/en_us.json | 5 + front/php/templates/language/es_es.json | 5 + front/php/templates/language/fr_fr.json | 5 + front/php/templates/language/it_it.json | 5 + front/php/templates/language/nb_no.json | 5 + front/php/templates/language/pl_pl.json | 5 + front/php/templates/language/pt_br.json | 5 + front/php/templates/language/ru_ru.json | 5 + front/php/templates/language/tr_tr.json | 5 + front/php/templates/language/uk_ua.json | 5 + front/php/templates/language/zh_cn.json | 5 + front/plugins/csv_backup/config.json | 4 +- 29 files changed, 491 insertions(+), 79 deletions(-) create mode 100755 front/initCheck.php diff --git a/back/app.conf b/back/app.conf index b00fa6f2..b966ea84 100755 --- a/back/app.conf +++ b/back/app.conf @@ -18,7 +18,7 @@ # 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', 'DIGSCAN', 'INTRNT','MAINT','NEWDEV', 'NBTSCAN', 'NSLOOKUP','NTFPRCS', 'AVAHISCAN', 'SETPWD','SMTP', 'SYNC', 'VNDRPDT', 'WORKFLOWS', 'UI'] diff --git a/docker-compose.yml b/docker-compose.yml index 296f79cd..06e06851 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -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 diff --git a/docs/INITIAL_SETUP.md b/docs/INITIAL_SETUP.md index 8ede12eb..d5fa8afd 100755 --- a/docs/INITIAL_SETUP.md +++ b/docs/INITIAL_SETUP.md @@ -1,42 +1,99 @@ -# ⚙ Initial Setup +# ⚡ Quick Start Guide -## 📁 Configuration Files +Get **NetAlertX** up and running in a few simple steps. -- 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/`. +> [!TIP] +> Enable additional plugins under **Settings → `LOADED_PLUGINS`**. +> Make sure to **save** your changes and **reload the page** to activate them. +> ![Loaded plugins settings](./img/PLUGINS/loaded_plugins_setting.png) --- -## 🖥️ 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). +**Initial configuration**: `ARPSCAN`, `INTRNT` -### 🔄 PiHole Sync -- If using **PiHole**, devices can be synced automatically. -- 📖 [PiHole configuration guide](./PIHOLE_GUIDE.md). - -### 📦 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: +**Initial configuration**: The app auto-selects a root node (MAC `internet`) and attempts to identify other network devices by vendor or name. -- 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) +> [!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 + +**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! diff --git a/docs/NAME_RESOLUTION.md b/docs/NAME_RESOLUTION.md index 0f788703..a726c68e 100755 --- a/docs/NAME_RESOLUTION.md +++ b/docs/NAME_RESOLUTION.md @@ -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: diff --git a/docs/REVERSE_DNS.md b/docs/REVERSE_DNS.md index 4f0f1fc5..1f4b3db3 100755 --- a/docs/REVERSE_DNS.md +++ b/docs/REVERSE_DNS.md @@ -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` > diff --git a/front/css/app.css b/front/css/app.css index 202bab03..3b90b3ee 100755 --- a/front/css/app.css +++ b/front/css/app.css @@ -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; @@ -1418,6 +1451,11 @@ input[readonly] { cursor: default; } +.small-box:hover +{ + color: inherit; +} + /* ----------------------------------------------------------------- */ /* Device details */ /* ----------------------------------------------------------------- */ diff --git a/front/devices.php b/front/devices.php index e4c917c6..16c01952 100755 --- a/front/devices.php +++ b/front/devices.php @@ -768,8 +768,8 @@ function initializeDatatable (status) { {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) diff --git a/front/initCheck.php b/front/initCheck.php new file mode 100755 index 00000000..5d1c9dd9 --- /dev/null +++ b/front/initCheck.php @@ -0,0 +1,52 @@ + + +
+
+
+
+ +
+
+ + +
+
+
+
+
+
+
+

+
+
+
+
+ +
+
+
+
+ + \ No newline at end of file diff --git a/front/js/common.js b/front/js/common.js index 2fe35796..7bbaaa11 100755 --- a/front/js/common.js +++ b/front/js/common.js @@ -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') }; // ----------------------------------------------------------------------------- diff --git a/front/js/tests.js b/front/js/tests.js index 375031fe..67261ea8 100755 --- a/front/js/tests.js +++ b/front/js/tests.js @@ -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(''); + } else if (status === 'fail') { + icon.html(''); + } else { + icon.html(''); + } + } + + + 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(` +
+
+
+ ${file} + +
+
+
+ `); + + fileStatus[file] = 'checking'; + }); + + checkAppInitializedJson(); +} + + + + diff --git a/front/maintenance.php b/front/maintenance.php index 34df64d5..810078e1 100755 --- a/front/maintenance.php +++ b/front/maintenance.php @@ -51,7 +51,7 @@ $db->close();

- +

@@ -59,7 +59,7 @@ $db->close();
- +
"> @@ -111,7 +111,7 @@ $db->close();
-
+ + +
+
+
+ + + +
+
+
+ +
+
-
+
- + - + -
-
+ +
+
+ + + + + + + + + - - - - - - - + diff --git a/front/multiEditCore.php b/front/multiEditCore.php index f5eb327f..111fc1fd 100755 --- a/front/multiEditCore.php +++ b/front/multiEditCore.php @@ -64,10 +64,6 @@ - - - -