diff --git a/front/img/NetAlertX_logo.png b/front/img/NetAlertX_logo.png index 5a18b9fe..a3bfaec7 100755 Binary files a/front/img/NetAlertX_logo.png and b/front/img/NetAlertX_logo.png differ diff --git a/front/img/NetAlertX_logo_notification.png b/front/img/NetAlertX_logo_notification.png index 1032b889..5a18b9fe 100755 Binary files a/front/img/NetAlertX_logo_notification.png and b/front/img/NetAlertX_logo_notification.png differ diff --git a/front/img/NetAlertX_logo_red.png b/front/img/NetAlertX_logo_red.png new file mode 100755 index 00000000..5a18b9fe Binary files /dev/null and b/front/img/NetAlertX_logo_red.png differ diff --git a/front/img/NetAlertX_logo_notification_white.png b/front/img/NetAlertX_logo_white.png similarity index 100% rename from front/img/NetAlertX_logo_notification_white.png rename to front/img/NetAlertX_logo_white.png diff --git a/front/img/NetAlertX_logo_notification_yellow.png b/front/img/NetAlertX_logo_yellow.png similarity index 100% rename from front/img/NetAlertX_logo_notification_yellow.png rename to front/img/NetAlertX_logo_yellow.png diff --git a/front/php/templates/header.php b/front/php/templates/header.php index 33c446b8..7d15c117 100755 --- a/front/php/templates/header.php +++ b/front/php/templates/header.php @@ -165,7 +165,7 @@ if ($ENABLED_DARKMODE === True) {
  • - 0 + 0
  • diff --git a/front/plugins/sync/README.md b/front/plugins/sync/README.md index 4f03eff6..ebf02d22 100755 --- a/front/plugins/sync/README.md +++ b/front/plugins/sync/README.md @@ -1,6 +1,52 @@ ## Overview -Synchronization plugin to synchronize multiple app instances. The plugin sends encrypted `last_result.log` files for individual plugins. +Synchronization plugin to synchronize multiple app instances. The Plugin can sychronize 2 types of data: + +1. 💻 Devices: The plugin sends an encrypted `table_devices.json` file to synchronize the whole Devices DB table. +1. 🔌 Plugin data: The plugin sends encrypted `last_result.log` files for individual plugins. + +### Synchronizing 💻 Devices data + +This is probably what most of the setups will use. Required settings follow. + +#### Node (Source) Settings + +- When to run `SYNC_RUN` +- Schedule `SYNC_RUN_SCHD` +- API token `SYNC_api_token` +- Encryption Key `SYNC_encryption_key` +- Node name `SYNC_node_name` +- Hub URL `SYNC_hub_url` +- Send Devices `SYNC_devices` 👈 + +#### Hub (Target) Settings + +- When to run `SYNC_RUN` +- Schedule `SYNC_RUN_SCHD` +- API token `SYNC_api_token` +- Encryption Key `SYNC_encryption_key` + +### Synchronizing 🔌 Plugins data + +This mechanism will be probably used in special use cases. Required settings follow. + +#### Node (Source) Settings + +- When to run `SYNC_RUN` +- Schedule `SYNC_RUN_SCHD` +- API token `SYNC_api_token` +- Encryption Key `SYNC_encryption_key` +- Node name `SYNC_node_name` +- Hub URL `SYNC_hub_url` +- Send Plugins `SYNC_plugins` 👈 + +#### Hub (Target) Settings + +- When to run `SYNC_RUN` +- Schedule `SYNC_RUN_SCHD` +- API token `SYNC_api_token` +- Encryption Key `SYNC_encryption_key` + ### Usage diff --git a/front/plugins/sync/config.json b/front/plugins/sync/config.json index 4c92ba24..dda81414 100755 --- a/front/plugins/sync/config.json +++ b/front/plugins/sync/config.json @@ -81,6 +81,82 @@ "string" : "When the node sync should run. Data might be lost if you run the sync less frequently. Good options are always_after_scan, on_new_device, on_notification" }] }, + { + "function": "RUN_SCHD", + "type": "text", + "display_condition": { + "type" : "setting", + "name" : "SYNC_instance_type", + "value": "hub" + }, + "default_value":"*/5 * * * *", + "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 schedule in the SYNC_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." + }, + { + "language_code":"es_es", + "string" : "Solo está habilitado si selecciona schedule en la configuración SYNC_RUN. Asegúrese de ingresar la programación en el formato similar a cron correcto (por ejemplo, valide en crontab.guru). Por ejemplo, ingresar 0 4 * * * ejecutará el escaneo después de las 4 a.m. en el TIMEZONE que configuró arriba. Se ejecutará la PRÓXIMA vez que pase el tiempo." + }, + { + "language_code":"de_de", + "string" : "Nur aktiviert, wenn Sie schedule in der SYNC_RUN-Einstellung auswählen. Stellen Sie sicher, dass Sie den Zeitplan im richtigen Cron-ähnlichen Format eingeben (z. B. validieren unter crontab.guru). Wenn Sie beispielsweise 0 4 * * * eingeben, wird der Scan nach 4 Uhr morgens in der TIMEZONE den Sie oben festgelegt haben. Wird das NÄCHSTE Mal ausgeführt, wenn die Zeit vergeht." + }] + }, + { + "function": "api_token", + "type": "text", + "maxLength": 50, + "default_value": "", + "options": [], + "localized": ["name", "description"], + "name": [ + { + "language_code": "en_us", + "string": "API token" + } + ], + "description": [ + { + "language_code": "en_us", + "string": "API token to secure communication. The API token needs to be the same on the hub and on the nodes." + } + ] + }, + { + "function": "encryption_key", + "type": "text", + "maxLength": 50, + "default_value": "", + "options": [], + "localized": ["name", "description"], + "name": [ + { + "language_code": "en_us", + "string": "Encryption Key" + } + ], + "description": [ + { + "language_code": "en_us", + "string": "Encryption key used to encrypt the sent data. The key needs to be the same on the hub and on the nodes." + } + ] + }, { "function": "hub_url", "type": "text", @@ -183,46 +259,6 @@ } ] }, - { - "function": "api_token", - "type": "text", - "maxLength": 50, - "default_value": "", - "options": [], - "localized": ["name", "description"], - "name": [ - { - "language_code": "en_us", - "string": "API token" - } - ], - "description": [ - { - "language_code": "en_us", - "string": "API token to secure communication. The API token needs to be the same on the hub and on the nodes." - } - ] - }, - { - "function": "encryption_key", - "type": "text", - "maxLength": 50, - "default_value": "", - "options": [], - "localized": ["name", "description"], - "name": [ - { - "language_code": "en_us", - "string": "Encryption Key" - } - ], - "description": [ - { - "language_code": "en_us", - "string": "Encryption key used to encrypt the sent data. The key needs to be the same on the hub and on the nodes." - } - ] - }, { "function": "CMD", "type": "readonly", @@ -258,42 +294,6 @@ } ] }, - { - "function": "RUN_SCHD", - "type": "text", - "display_condition": { - "type" : "setting", - "name" : "SYNC_instance_type", - "value": "hub" - }, - "default_value":"*/5 * * * *", - "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 schedule in the SYNC_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." - }, - { - "language_code":"es_es", - "string" : "Solo está habilitado si selecciona schedule en la configuración SYNC_RUN. Asegúrese de ingresar la programación en el formato similar a cron correcto (por ejemplo, valide en crontab.guru). Por ejemplo, ingresar 0 4 * * * ejecutará el escaneo después de las 4 a.m. en el TIMEZONE que configuró arriba. Se ejecutará la PRÓXIMA vez que pase el tiempo." - }, - { - "language_code":"de_de", - "string" : "Nur aktiviert, wenn Sie schedule in der SYNC_RUN-Einstellung auswählen. Stellen Sie sicher, dass Sie den Zeitplan im richtigen Cron-ähnlichen Format eingeben (z. B. validieren unter crontab.guru). Wenn Sie beispielsweise 0 4 * * * eingeben, wird der Scan nach 4 Uhr morgens in der TIMEZONE den Sie oben festgelegt haben. Wird das NÄCHSTE Mal ausgeführt, wenn die Zeit vergeht." - }] - }, { "function": "RUN_TIMEOUT", "type": "integer", diff --git a/front/plugins/sync/hub.php b/front/plugins/sync/hub.php index 941f6ec7..3fc560ba 100755 --- a/front/plugins/sync/hub.php +++ b/front/plugins/sync/hub.php @@ -35,8 +35,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } // Generate a unique file path to avoid overwriting existing files - $files = glob("{$storage_path}/last_result.{encoded,decoded}.{$node_name}.*.log", GLOB_BRACE); + $encoded_files = glob("{$storage_path}/last_result.encoded.{$node_name}.*.log"); + $decoded_files = glob("{$storage_path}/last_result.decoded.{$node_name}.*.log"); + + $files = array_merge($encoded_files, $decoded_files); $file_count = count($files) + 1; + $file_path = "{$storage_path}/last_result.encoded.{$node_name}.{$file_count}.log"; diff --git a/front/plugins/sync/sync.py b/front/plugins/sync/sync.py index 9abe3498..dae53408 100755 --- a/front/plugins/sync/sync.py +++ b/front/plugins/sync/sync.py @@ -128,24 +128,18 @@ def main(): unique_mac_addresses.add(device['dev_MAC']) device_data.append(device) + + if len(device_data) > 0: # Retrieve existing dev_MAC values from the Devices table placeholders = ', '.join('?' for _ in unique_mac_addresses) cursor.execute(f'SELECT dev_MAC FROM Devices WHERE dev_MAC IN ({placeholders})', tuple(unique_mac_addresses)) existing_mac_addresses = set(row[0] for row in cursor.fetchall()) + - # Filter out existing devices - new_devices = [device for device in device_data if device['dev_MAC'] not in existing_mac_addresses] - - # Remove 'rowid' key if it exists - for device in new_devices: - device.pop('rowid', None) - - - # Prepare the insert statement - if new_devices: - # insert devices into the lats_result.log to manage state - for device in new_devices: + # insert devices into the lats_result.log to manage state + for device in device_data: + if device['dev_PresentLastScan'] == 1: plugin_objects.add_object( primaryId = device['dev_MAC'], secondaryId = device['dev_LastIP'], @@ -156,6 +150,19 @@ def main(): extra = '', foreignKey = device['dev_GUID']) + # Filter out existing devices + new_devices = [device for device in device_data if device['dev_MAC'] not in existing_mac_addresses] + + # Remove 'rowid' key if it exists + for device in new_devices: + device.pop('rowid', None) + + mylog('verbose', [f'[{pluginName}] All devices: "{len(device_data)}"']) + mylog('verbose', [f'[{pluginName}] New devices: "{len(new_devices)}"']) + + # Prepare the insert statement + if new_devices: + columns = ', '.join(k for k in new_devices[0].keys() if k != 'rowid') placeholders = ', '.join('?' for k in new_devices[0] if k != 'rowid') sql = f'INSERT INTO Devices ({columns}) VALUES ({placeholders})' diff --git a/server/plugin.py b/server/plugin.py index af63a469..b6b2bf58 100755 --- a/server/plugin.py +++ b/server/plugin.py @@ -225,13 +225,15 @@ def execute_plugin(db, all_plugins, plugin, pluginsState = plugins_state() ): file_dir = os.path.join(pluginsPath, plugin["code_name"]) file_prefix = 'last_result' - # Decode files, rename them, and get the list of files files_to_process = decode_and_rename_files(file_dir, file_prefix) for filename in files_to_process: + + full_path = os.path.join(file_dir, filename) + # Open the decrypted file and process its contents - with open(os.path.join(file_dir, filename), 'r') as f: + with open(full_path, 'r') as f: newLines = f.read().split('\n') # if the script produced some output, clean it up to ensure it's the correct format @@ -271,9 +273,11 @@ def execute_plugin(db, all_plugins, plugin, pluginsState = plugins_state() ): ) else: mylog('none', ['[Plugins] Skipped invalid line in the output: ', line]) - - # TODO: delete processed files - # os.rename(file_path, os.path.join(file_dir, new_filename)) + + # keep current instance log file, delete all from other nodes + if filename != 'last_result.log' and os.path.exists(full_path): + os.remove(full_path) + mylog('verbose', [f'[Plugins] Processed and deleted file: {full_path} ']) # app-db-query