From 6dcf09a2f6ff1329863745d03cc261939be6c373 Mon Sep 17 00:00:00 2001 From: Jokob-sk Date: Thu, 31 Aug 2023 08:10:29 +1000 Subject: [PATCH] NMAP, PHOLUS, PIHOLE, DB upgrade + cleanup, docs fixes --- docs/DATABASE.md | 7 +- front/deviceDetails.php | 82 +---------- front/php/server/devices.php | 80 +--------- front/plugins/README.md | 99 ++++++++----- front/plugins/nmap_scan/config.json | 37 +++-- front/plugins/pholus_scan/config.json | 3 +- front/plugins/pholus_scan/script.py | 3 +- front/plugins/pihole_scan/config.json | 3 +- pialert/database.py | 202 ++++++++++++++------------ pialert/device.py | 12 +- pialert/publishers/email.py | 7 + 11 files changed, 219 insertions(+), 316 deletions(-) diff --git a/docs/DATABASE.md b/docs/DATABASE.md index 6184cdb7..8c130917 100755 --- a/docs/DATABASE.md +++ b/docs/DATABASE.md @@ -19,7 +19,6 @@ | Plugins_History | History of all entries from the `Plugins_Events` table | ![Screen11][screen11] | | Plugins_Language_Strings | Language strings colelcted from the plugin `config.json` files used for string resolution in the frontend. | ![Screen12][screen12] | | Plugins_Objects | Unique objects detected by individual plugins. | ![Screen13][screen13] | - | ScanCycles | (obsolete) Used to determine and identify different scan cycles. | ![Screen14][screen14] | | Sessions | Used to display sessions in the charts | ![Screen15][screen15] | | Settings | Database representation of the sum of all settings from `pialert.conf` and plugins coming from `config.json` files. | ![Screen16][screen16] | @@ -27,16 +26,14 @@ [screen1]: /docs/img/DATABASE/CurrentScan.png [screen2]: /docs/img/DATABASE/Devices.png - [screen4]: /docs/img/DATABASE/Events.png - [screen5]: /docs/img/DATABASE/Nmap_Scan.png + [screen4]: /docs/img/DATABASE/Events.png [screen6]: /docs/img/DATABASE/Online_History.png [screen7]: /docs/img/DATABASE/Parameters.png [screen8]: /docs/img/DATABASE/Pholus_Scan.png [screen10]: /docs/img/DATABASE/Plugins_Events.png [screen11]: /docs/img/DATABASE/Plugins_History.png [screen12]: /docs/img/DATABASE/Plugins_Language_Strings.png - [screen13]: /docs/img/DATABASE/Plugins_Objects.png - [screen14]: /docs/img/DATABASE/ScanCycles.png + [screen13]: /docs/img/DATABASE/Plugins_Objects.png [screen15]: /docs/img/DATABASE/Sessions.png [screen16]: /docs/img/DATABASE/Settings.png diff --git a/front/deviceDetails.php b/front/deviceDetails.php index 994e41af..9b602117 100755 --- a/front/deviceDetails.php +++ b/front/deviceDetails.php @@ -582,28 +582,7 @@ } }) } - - -

- -
- - - - - - - - - - - - - - - - -
+ @@ -1874,60 +1853,11 @@ function initializeTabsNew () { if(target == "#panNmap") { - loadNmap(); + // loadNmap(); } }); } -// ----------------------------------------------------------------------------- - -function loadNmap() -{ - $(".deviceSpecific").remove(); // remove any previous data listed in the table - - $.get('php/server/devices.php?action=getNmap&mac='+ mac, function(data) { - - data = sanitize(data); - - if(data != "false" && $.trim(data) != []) - { - var listData = JSON.parse(data); - var order = 1; - - tableRows = ""; - - // for each item - listData.forEach(function (item, index) { - tableRows += '\ - '+item.Index+'\ - '+item.Time+'\ - \ - '+item.Port+'\ - \ - \ - \ - '+item.State+'\ - '+item.Service+'\ - \ -
\ - \ - \ -
\ - \ - '; - }); - - $("#tableNmapBody").html($("#tableNmapBody").html()+tableRows); - $("#tableNmapPlc").hide(); - } - else - { - // console.log("else") - $("#tableNmapPlc").show(); - $(".deviceSpecific").remove(); - } - }); -} //----------------------------------------------------------------------------------- @@ -2006,12 +1936,4 @@ function reloadTab() } } -//----------------------------------------------------------------------------------- - -function saveNmapPort(index) -{ - saveData('saveNmapPort', index, $('#port_'+index).val()) -} - - diff --git a/front/php/server/devices.php b/front/php/server/devices.php index 62b40fd2..51e2729f 100755 --- a/front/php/server/devices.php +++ b/front/php/server/devices.php @@ -50,9 +50,7 @@ case 'getOwners': getOwners(); break; case 'getDeviceTypes': getDeviceTypes(); break; case 'getGroups': getGroups(); break; - case 'getLocations': getLocations(); break; - case 'getNmap': getNmap(); break; - case 'saveNmapPort': saveNmapPort(); break; + case 'getLocations': getLocations(); break; case 'updateNetworkLeaf': updateNetworkLeaf(); break; case 'overwriteIconType': overwriteIconType(); break; case 'getIcons': getIcons(); break; @@ -1009,82 +1007,6 @@ function getLocations() { echo (json_encode ($tableData)); } - -//------------------------------------------------------------------------------ -// Query the List of Nmap entries -//------------------------------------------------------------------------------ -function getNmap() { - global $db; - - // SQL - $mac = $_REQUEST['mac']; - - if ($mac == "Internet") // Not performing data lookup for router (improvement idea for later maybe) - { - echo "false"; - return; - } - - if (false === filter_var($mac , FILTER_VALIDATE_MAC)) { - throw new Exception('Invalid mac address'); - } - else{ - // $sql = 'SELECT * from Nmap_Scan where MAC ="'.$mac.'" '; - $sql = 'select * from (select * from Nmap_Scan INNER JOIN Devices on Nmap_Scan.MAC = Devices.dev_MAC) where MAC = "'.$mac.'" '; - - // array - $tableData = array(); - - // execute query - $result = $db->query($sql); - while ($row = $result -> fetchArray (SQLITE3_ASSOC)){ - // Push row data - $tableData[] = array( 'Index' => $row['Index'], - 'MAC' => $row['MAC'], - 'Port' => $row['Port'], - 'Time' => $row['Time'], - 'State' => $row['State'], - 'Service' => $row['Service'], - 'IP' => $row['dev_LastIP'], - 'Extra' => $row['Extra']); - } - - if(count($tableData) == 0) - { - echo "false"; - } else{ - // Return json - echo (json_encode ($tableData)); - } - } -} - -// ------------------------------------------------------------------------------------------- - -function saveNmapPort() -{ - - $portIndex = $_REQUEST['id']; - $value = $_REQUEST['value']; - - if(is_integer((int)$portIndex)) - { - global $db; - // sql - $sql = 'UPDATE Nmap_Scan SET "Extra" = "'. $value .'" WHERE "Index"=' . $portIndex ; - // update Data - $result = $db->query($sql); - - // check result - if ($result == TRUE) { - echo 'OK'; - } else { - echo 'KO'; - } - } - -} - // ---------------------------------------------------------------------------------------- function updateNetworkLeaf() { diff --git a/front/plugins/README.md b/front/plugins/README.md index 048d591c..3a6c4375 100755 --- a/front/plugins/README.md +++ b/front/plugins/README.md @@ -500,36 +500,56 @@ Below are some general additional notes, when defining `params`: Required attributes are: -- `"function": ""` - What function the setting drives or a simple unique code name -- `"type": ""` - The form control used for the setting displayed in the Settings page and what values are accepted. -- `"localized"` - a list of properties on the current JSON level which need to be localized -- `"name"` and `"description"` - Displayed on the Settings page. An array of localized strings. (see Localized strings below). -- (optional) `"events"` - `` - to generate an execution button next to the input field of the setting (not fully tested) -- (optional) `"override_value"` - used to determine a user-defined override for the setting. Useful for template-based plugins, where you can choose to leave the current value or override it with the value defined in the setting. (work in progress) -- (optional) `"events": ["run", "test"]` - used to trigger the plugin. Usually used on the `RUN` setting. Not fully tested in all scenarios. Will show a play button next to the setting and then after clicking an event is generated for the backend in the `Parameters` database table to process the front-end event on the next run. +| Property | Description | +| -------- | ----------- | +| `"function"` | Specifies the function the setting drives or a simple unique code name. See Supported settings function values for options. | +| `"type"` | Specifies the form control used for the setting displayed in the Settings page and what values are accepted. Supported options include: | +| | - `text` | +| | - `integer` | +| | - `boolean` | +| | - `password` | +| | - `readonly` | +| | - `integer.select` | +| | - `text.select` | +| | - `text.multiselect` | +| | - `list` | +| | - `integer.checkbox` | +| | - `text.template` | +| `"localized"` | A list of properties on the current JSON level that need to be localized. | +| `"name"` | Displayed on the Settings page. An array of localized strings. See Localized strings below. | +| `"description"` | Displayed on the Settings page. An array of localized strings. See Localized strings below. | +| (optional) `"events"` | Specifies whether to generate an execution button next to the input field of the setting. Supported values: | +| | - `test` | +| | - `run` | +| (optional) `"override_value"` | Used to determine a user-defined override for the setting. Useful for template-based plugins, where you can choose to leave the current value or override it with the value defined in the setting. (Work in progress) | +| (optional) `"events"` | Used to trigger the plugin. Usually used on the `RUN` setting. Not fully tested in all scenarios. Will show a play button next to the setting. After clicking, an event is generated for the backend in the `Parameters` database table to process the front-end event on the next run. | + ##### Supported settings `function` values You can have any `"function": "my_custom_name"` custom name, however, the ones listed below have a specific functionality attached to them. If you use a custom name, then the setting is mostly used as an input parameter for the `params` section. -- `RUN` - (required) Specifies when the service is executed - - Supported Options: - - "disabled" - not run - - "once" - run on app start or on settings saved - - "schedule" - if included then a `RUN_SCHD` setting needs to be specified to determine what's the schedule, - - "always_after_scan" - run always after a scan is finished - - "on_new_device" - run when a new device is detected - - "before_config_save" - run before the config is marked as saved. Useful if your plugin needs to modify the `pialert.conf` file. -- `RUN_SCHD` - (required if you include the above `RUN` function) Cron-like scheduling is used if the `RUN` setting set to `schedule` -- `CMD` - (required) What command should be executed. -- `API_SQL` - (optional) Generates a `table_` + code_name + `.json` file as per [API docs](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/API.md). -- `RUN_TIMEOUT` - (optional) Max execution time of the script. If not specified a default value of 10 seconds is used to prevent hanging. -- `WATCH` - (optional) Which database columns are watched for changes for this particular plugin. If not specified no notifications are sent. -- `REPORT_ON` - (optional) Send a notification only on these statuses. Supported options are: - - `new` means a new unique (unique combination of PrimaryId and SecondaryId) object was discovered. - - `watched-changed` - means that selected `Watched_ValueN` columns changed - - `watched-not-changed` - reports even on events where selected `Watched_ValueN` did not change - - `missing-in-last-scan` - if object is missing compared to previous scans +| Setting | Description | +| ------- | ----------- | +| `RUN` | (required) Specifies when the service is executed. | +| | Supported Options: | +| | - "disabled" - not run | +| | - "once" - run on app start or on settings saved | +| | - "schedule" - if included, then a `RUN_SCHD` setting needs to be specified to determine the schedule | +| | - "always_after_scan" - run always after a scan is finished | +| | - "on_new_device" - run when a new device is detected | +| | - "before_config_save" - run before the config is marked as saved. Useful if your plugin needs to modify the `pialert.conf` file. | +| `RUN_SCHD` | (required if you include the above `RUN` function) Cron-like scheduling is used if the `RUN` setting is set to `schedule`. | +| `CMD` | (required) Specifies the command that should be executed. | +| `API_SQL` | (optional) Generates a `table_` + `code_name` + `.json` file as per [API docs](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/API.md). | +| `RUN_TIMEOUT` | (optional) Specifies the maximum execution time of the script. If not specified, a default value of 10 seconds is used to prevent hanging. | +| `WATCH` | (optional) Specifies which database columns are watched for changes for this particular plugin. If not specified, no notifications are sent. | +| `REPORT_ON` | (optional) Specifies when to send a notification. Supported options are: | +| | - `new` means a new unique (unique combination of PrimaryId and SecondaryId) object was discovered. | +| | - `watched-changed` - means that selected `Watched_ValueN` columns changed | +| | - `watched-not-changed` - reports even on events where selected `Watched_ValueN` did not change | +| | - `missing-in-last-scan` - if the object is missing compared to previous scans | + > 🔎 Example: @@ -573,18 +593,23 @@ You can have any `"function": "my_custom_name"` custom name, however, the ones l The UI will adjust how columns are displayed in the UI based on the definition of the `database_column_definitions` object. These are the supported form controls and related functionality: - Only columns with `"show": true` and also with at least an English translation will be shown in the UI. -- Supported types: `label`, `text`, `threshold`, `replace`, `device_ip`, `device_mac`, `url`. Check for details below, how columns behave based on the type. - - `label` makes a column display only - - `text` makes a column editable and a save icon is displayed next to it. - - See below for information on `threshold`, `replace` -- The `options` property is used in conjunction with these types: - - `threshold` - The `options` array contains objects from lowest `maximum` to highest with the corresponding `hexColor` used for the value background color if it's less than the specified `maximum`, but more than the previous one in the `options` array - - `replace` - The `options` array contains objects with an `equals` property, that is compared to the "value" and if the values are the same, the string in `replacement` is displayed in the UI instead of the actual "value" -- `device_mac` - The value is considered to be a Mac address and a link pointing to the device with the given Mac address is generated. -- `device_ip` - The value is considered to be an IP address and a link pointing to the device with the given IP is generated. The IP is checked against the last detected IP address and translated into a Mac address that is then used for the link itself. -- `device_name_mac` - The value is considered to be a MAC address and a link pointing to the device with the given IP is generated. The link label is resolved as the target device name. -- `url` - The value is considered to be a URL so a link is generated. -- `textbox_save` - An editable and saveable text box is generated that saves values in the database. Primarily intended for the `UserData` database column in the `Plugins_Objects` table. + +| Supported Types | Description | +| -------------- | ----------- | +| `label` | Displays a column only. | +| `text` | Makes a column editable, and a save icon is displayed next to it. See below for information on `threshold`, `replace`. | +| | | +| `options` Property | Used in conjunction with types like `threshold`, `replace`. | +| `threshold` | The `options` array contains objects ordered from the lowest `maximum` to the highest. The corresponding `hexColor` is used for the value background color if it's less than the specified `maximum` but more than the previous one in the `options` array. | +| `replace` | The `options` array contains objects with an `equals` property, which is compared to the "value." If the values are the same, the string in `replacement` is displayed in the UI instead of the actual "value". | +| | | +| Type Definitions | | +| `device_mac` | The value is considered to be a MAC address, and a link pointing to the device with the given MAC address is generated. | +| `device_ip` | The value is considered to be an IP address. A link pointing to the device with the given IP is generated. The IP is checked against the last detected IP address and translated into a MAC address, which is then used for the link itself. | +| `device_name_mac` | The value is considered to be a MAC address, and a link pointing to the device with the given IP is generated. The link label is resolved as the target device name. | +| `url` | The value is considered to be a URL, so a link is generated. | +| `textbox_save` | Generates an editable and saveable text box that saves values in the database. Primarily intended for the `UserData` database column in the `Plugins_Objects` table. | + ```json diff --git a/front/plugins/nmap_scan/config.json b/front/plugins/nmap_scan/config.json index 7d7f4a66..6f075f4c 100755 --- a/front/plugins/nmap_scan/config.json +++ b/front/plugins/nmap_scan/config.json @@ -102,7 +102,7 @@ "language_code":"en_us", "string" : "Device name" }, - { + { "language_code":"es_es", "string" : "Nombre del dispositivo" }] @@ -119,7 +119,7 @@ "language_code":"en_us", "string" : "Port" }, - { + { "language_code":"es_es", "string" : "Puerto" }] @@ -136,7 +136,7 @@ "language_code":"en_us", "string" : "Created" }, - { + { "language_code":"es_es", "string" : "Creado" }] @@ -153,7 +153,7 @@ "language_code":"en_us", "string" : "Changed" }, - { + { "language_code":"es_es", "string" : "Cambiado" }] @@ -170,7 +170,7 @@ "language_code":"en_us", "string" : "State" }, - { + { "language_code":"es_es", "string" : "Estado" }] @@ -186,8 +186,8 @@ "language_code":"en_us", "string" : "Service" }, - { - "language_code":"es_es", + { + "language_code":"es_es", "string" : "Servicio" }] }, @@ -203,7 +203,7 @@ "language_code":"en_us", "string" : "N/A" }, - { + { "language_code":"es_es", "string" : "N/A" }] @@ -220,7 +220,7 @@ "language_code":"en_us", "string" : "N/A" }, - { + { "language_code":"es_es", "string" : "N/A" }] @@ -237,11 +237,28 @@ "language_code":"en_us", "string" : "Extra" }, - { + { "language_code":"es_es", "string" : "Extra" }] }, + { + "column": "UserData", + "css_classes": "col-sm-3", + "show": true, + "type": "textbox_save", + "default_value":"", + "options": [], + "localized": ["name"], + "name":[{ + "language_code":"en_us", + "string" : "User data" + }, + { + "language_code":"es_es", + "string" : "N/A" + }] + }, { "column": "ForeignKey", "css_classes": "col-sm-2", diff --git a/front/plugins/pholus_scan/config.json b/front/plugins/pholus_scan/config.json index 3fb45301..19fdc520 100755 --- a/front/plugins/pholus_scan/config.json +++ b/front/plugins/pholus_scan/config.json @@ -50,7 +50,8 @@ { "name" : "subnets", "type" : "setting", - "value" : "SCAN_SUBNETS" + "value" : "SCAN_SUBNETS", + "base64": true }, { "name" : "timeout", diff --git a/front/plugins/pholus_scan/script.py b/front/plugins/pholus_scan/script.py index a6f06483..6566ed97 100755 --- a/front/plugins/pholus_scan/script.py +++ b/front/plugins/pholus_scan/script.py @@ -27,7 +27,7 @@ fullPholusPath = os.path.join(CUR_PATH, 'pholus/pholus3.py') def main(): # sample # /home/pi/pialert/front/plugins/pholus_scan/script.py userSubnets=b'MTkyLjE2OC4xLjAvMjQgLS1pbnRlcmZhY2U9ZXRoMQ==' timeoutSec=10 - # sudo docker exec pialert /home/pi/pialert/front/plugins/pholus_scan__ignore/script.py userSubnets=b'MTkyLjE2OC4xLjAvMjQgLS1pbnRlcmZhY2U9ZXRoMQ==' timeoutSec=10 + # sudo docker exec pialert /home/pi/pialert/front/plugins/pholus_scan/script.py userSubnets=b'MTkyLjE2OC4xLjAvMjQgLS1pbnRlcmZhY2U9ZXRoMQ==' timeoutSec=10 # the script expects a parameter in the format of userSubnets=subnet1,subnet2,... parser = argparse.ArgumentParser(description='Import devices from settings') @@ -46,6 +46,7 @@ def main(): # which holds a list of user-submitted subnets. # Printing the userSubnets list to check its content. mylog('verbose',['[Pholus] Subnets: ', values.userSubnets]) + mylog('verbose',['[Pholus] len Subnets: ', len(values.userSubnets)]) # Extract the base64-encoded subnet information from the first element of the userSubnets list. # The format of the element is assumed to be like 'userSubnets=b'. diff --git a/front/plugins/pihole_scan/config.json b/front/plugins/pihole_scan/config.json index d0166624..91ad3058 100755 --- a/front/plugins/pihole_scan/config.json +++ b/front/plugins/pihole_scan/config.json @@ -50,7 +50,8 @@ { "name" : "subnets", "type" : "setting", - "value" : "SCAN_SUBNETS" + "value" : "SCAN_SUBNETS", + "base64": true }], "settings": [ diff --git a/pialert/database.py b/pialert/database.py index 04992a05..349f1878 100755 --- a/pialert/database.py +++ b/pialert/database.py @@ -96,11 +96,6 @@ class DB(): self.sql.execute (f"""DELETE FROM Events WHERE eve_DateTime <= date('now', '-{str(DAYS_TO_KEEP_EVENTS)} day')""") - # # Cleanup Plugin Events History - # mylog('verbose', ['[DB Cleanup] Plugins_History: Delete all older than '+str(DAYS_TO_KEEP_EVENTS)+' days (DAYS_TO_KEEP_EVENTS setting)']) - # self.sql.execute (f"""DELETE FROM Plugins_History - # WHERE DateTimeChanged <= date('now', '{str(DAYS_TO_KEEP_EVENTS)} day')""") - # Trim Plugins_History entries to less than PLUGINS_KEEP_HIST setting per unique "Plugin" column entry mylog('verbose', [f'[DB Cleanup] Plugins_History: Trim Plugins_History entries to less than {str(PLUGINS_KEEP_HIST)} per Plugin (PLUGINS_KEEP_HIST setting)']) @@ -154,17 +149,6 @@ class DB(): AND Pholus_Scan.Value = p2.Value AND Pholus_Scan.Record_Type = p2.Record_Type );""") - # De-Dupe (de-duplicate - remove duplicate entries) from the Nmap_Scan table - mylog('verbose', ['[DB Cleanup] Nmap_Scan: Delete all duplicates']) - self.sql.execute ("""DELETE FROM Nmap_Scan - WHERE rowid > ( - SELECT MIN(rowid) FROM Nmap_Scan p2 - WHERE Nmap_Scan.MAC = p2.MAC - AND Nmap_Scan.Port = p2.Port - AND Nmap_Scan.State = p2.State - AND Nmap_Scan.Service = p2.Service - );""") - # Shrink DB mylog('verbose', ['[DB Cleanup] Shrink Database']) @@ -210,7 +194,9 @@ class DB(): ); """) - # Alter Devices table + # ------------------------------------------------------------------------- + # 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' @@ -244,18 +230,16 @@ class DB(): ALTER TABLE "Devices" ADD "dev_Icon" TEXT """) - # indicates, if Settings table is available - settingsMissing = self.sql.execute(""" - SELECT name FROM sqlite_master WHERE type='table' - AND name='Settings'; - """).fetchone() == None + # ------------------------------------------------------------------------- + # Settings table setup + # ------------------------------------------------------------------------- + + # Re-creating Settings table mylog('verbose', ["[upgradeDB] Re-creating Settings table"]) - if settingsMissing == False: - self.sql.execute("DROP TABLE Settings;") - + self.sql.execute(""" DROP TABLE IF EXISTS Settings;""") self.sql.execute(""" CREATE TABLE "Settings" ( "Code_Name" TEXT, @@ -270,21 +254,14 @@ class DB(): ); """) - # indicates, if Pholus_Scan table is available - pholusScanMissing = self.sql.execute(""" - SELECT name FROM sqlite_master WHERE type='table' - AND name='Pholus_Scan'; - """).fetchone() == None - # if pholusScanMissing == False: - # # Re-creating Pholus_Scan table - # self.sql.execute("DROP TABLE Pholus_Scan;") - # pholusScanMissing = True + # ------------------------------------------------------------------------- + # Pholus_Scan table setup + # ------------------------------------------------------------------------- - if pholusScanMissing: - mylog('verbose', ["[upgradeDB] Re-creating Pholus_Scan table"]) - self.sql.execute(""" - CREATE TABLE "Pholus_Scan" ( + # Create Pholus_Scan table if missing + mylog('verbose', ["[upgradeDB] Re-creating Pholus_Scan table"]) + self.sql.execute("""CREATE TABLE IF NOT EXISTS "Pholus_Scan" ( "Index" INTEGER, "Info" TEXT, "Time" TEXT, @@ -294,14 +271,13 @@ class DB(): "Value" TEXT, "Extra" TEXT, PRIMARY KEY("Index" AUTOINCREMENT) - ); - """) + ); + """) - # indicates, if Nmap_Scan table is available - nmapScanMissing = self.sql.execute(""" - SELECT name FROM sqlite_master WHERE type='table' - AND name='Nmap_Scan'; - """).fetchone() == None + + # ------------------------------------------------------------------------- + # Parameters table setup + # ------------------------------------------------------------------------- # Re-creating Parameters table mylog('verbose', ["[upgradeDB] Re-creating Parameters table"]) @@ -317,25 +293,71 @@ class DB(): # Initialize Parameters if unavailable initOrSetParam(self, 'Back_App_State','Initializing') - # if nmapScanMissing == False: - # # Re-creating Nmap_Scan table - # self.sql.execute("DROP TABLE Nmap_Scan;") - # nmapScanMissing = True + # ------------------------------------------------------------------------- + # Parameters table setup DEPRECATED after 1/1/2024 + # ------------------------------------------------------------------------- - if nmapScanMissing: - mylog('verbose', ["[upgradeDB] Re-creating Nmap_Scan table"]) - self.sql.execute(""" - CREATE TABLE "Nmap_Scan" ( - "Index" INTEGER, - "MAC" TEXT, - "Port" TEXT, - "Time" TEXT, - "State" TEXT, - "Service" TEXT, - "Extra" TEXT, - PRIMARY KEY("Index" AUTOINCREMENT) - ); - """) + # indicates, if Nmap_Scan table is available + nmapScanMissing = self.sql.execute(""" + SELECT name FROM sqlite_master WHERE type='table' + AND name='Nmap_Scan'; + """).fetchone() == None + + if nmapScanMissing == False: + # move data into the PLugins_Objects table + self.sql.execute("""INSERT INTO Plugins_Objects ( + Plugin, + Object_PrimaryID, + Object_SecondaryID, + DateTimeCreated, + DateTimeChanged, + Watched_Value1, + Watched_Value2, + Watched_Value3, + Watched_Value4, + Status, + Extra, + UserData, + ForeignKey + ) + SELECT + 'NMAP' AS Plugin, + MAC AS Object_PrimaryID, + Port AS Object_SecondaryID, + Time AS DateTimeCreated, + DATETIME('now') AS DateTimeChanged, + State AS Watched_Value1, + Service AS Watched_Value2, + '' AS Watched_Value3, + '' AS Watched_Value4, + 'watched-not-changed' AS Status, + Extra AS Extra, + Extra AS UserData, + MAC AS ForeignKey + FROM Nmap_Scan;""") + + # Delete the Nmap_Scan table + self.sql.execute("DROP TABLE Nmap_Scan;") + nmapScanMissing = True + + # if nmapScanMissing: + # mylog('verbose', ["[upgradeDB] Re-creating Nmap_Scan table"]) + # self.sql.execute(""" + # CREATE TABLE "Nmap_Scan" ( + # "Index" INTEGER, + # "MAC" TEXT, + # "Port" TEXT, + # "Time" TEXT, + # "State" TEXT, + # "Service" TEXT, + # "Extra" TEXT, + # PRIMARY KEY("Index" AUTOINCREMENT) + # ); + # """) + + # ------------------------------------------------------------------------- + # Plugins tables setup + # ------------------------------------------------------------------------- # Plugin state sql_Plugins_Objects = """ CREATE TABLE IF NOT EXISTS Plugins_Objects( @@ -397,16 +419,12 @@ class DB(): ); """ self.sql.execute(sql_Plugins_History) + # ------------------------------------------------------------------------- + # Plugins_Language_Strings table setup + # ------------------------------------------------------------------------- + # Dynamically generated language strings - # indicates, if Language_Strings table is available - languageStringsMissing = self.sql.execute(""" - SELECT name FROM sqlite_master WHERE type='table' - AND name='Plugins_Language_Strings'; - """).fetchone() == None - - if languageStringsMissing == False: - self.sql.execute("DROP TABLE Plugins_Language_Strings;") - + self.sql.execute("DROP TABLE IF EXISTS Plugins_Language_Strings;") self.sql.execute(""" CREATE TABLE IF NOT EXISTS Plugins_Language_Strings( "Index" INTEGER, Language_Code TEXT NOT NULL, @@ -417,16 +435,13 @@ class DB(): ); """) self.commitDB() + + # ------------------------------------------------------------------------- + # CurrentScan table setup + # ------------------------------------------------------------------------- # indicates, if CurrentScan table is available - currentScanMissing = self.sql.execute(""" - SELECT name FROM sqlite_master WHERE type='table' - AND name='CurrentScan'; - """).fetchone() == None - - if currentScanMissing == False: - self.sql.execute("DROP TABLE CurrentScan;") - + self.sql.execute("DROP TABLE IF EXISTS CurrentScan;") self.sql.execute(""" CREATE TABLE CurrentScan ( cur_ScanCycle INTEGER, cur_MAC STRING(50) NOT NULL COLLATE NOCASE, @@ -439,26 +454,21 @@ class DB(): ); """) - # indicates, if DHCP_Leases table is available - DHCP_LeasesMissing = self.sql.execute(""" - SELECT name FROM sqlite_master WHERE type='table' - AND name='DHCP_Leases'; - """).fetchone() == None + # ------------------------------------------------------------------------- + # DELETING OBSOLETE TABLES - to remove with updated db file after 1/1/2024 + # ------------------------------------------------------------------------- - if DHCP_LeasesMissing == False: - self.sql.execute("DROP TABLE DHCP_Leases;") - - # indicates, if PiHole_Network table is available - PiHole_NetworkMissing = self.sql.execute(""" - SELECT name FROM sqlite_master WHERE type='table' - AND name='PiHole_Network'; - """).fetchone() == None - - if PiHole_NetworkMissing == False: - self.sql.execute("DROP TABLE PiHole_Network;") + # 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 1/1/2024 + # ------------------------------------------------------------------------- + #------------------------------------------------------------------------------- def get_table_as_json(self, sqlQuery): diff --git a/pialert/device.py b/pialert/device.py index fed157bd..c2d3c0c0 100755 --- a/pialert/device.py +++ b/pialert/device.py @@ -93,12 +93,12 @@ def print_scan_stats(db): stats = sql.fetchall() mylog('verbose', f'[Scan Stats] Devices Detected.......: {stats[0]["devices_detected"]}') - mylog('verbose', f'[Scan Stats] New Devices..........: {stats[0]["new_devices"]}') - mylog('verbose', f'[Scan Stats] Down Alerts..........: {stats[0]["down_alerts"]}') - mylog('verbose', f'[Scan Stats] New Down Alerts......: {stats[0]["new_down_alerts"]}') - mylog('verbose', f'[Scan Stats] New Connections......: {stats[0]["new_connections"]}') - mylog('verbose', f'[Scan Stats] Disconnections.......: {stats[0]["disconnections"]}') - mylog('verbose', f'[Scan Stats] IP Changes...........: {stats[0]["ip_changes"]}') + mylog('verbose', f'[Scan Stats] New Devices............: {stats[0]["new_devices"]}') + mylog('verbose', f'[Scan Stats] Down Alerts............: {stats[0]["down_alerts"]}') + mylog('verbose', f'[Scan Stats] New Down Alerts........: {stats[0]["new_down_alerts"]}') + mylog('verbose', f'[Scan Stats] New Connections........: {stats[0]["new_connections"]}') + mylog('verbose', f'[Scan Stats] Disconnections.........: {stats[0]["disconnections"]}') + mylog('verbose', f'[Scan Stats] IP Changes.............: {stats[0]["ip_changes"]}') mylog('verbose', '[Scan Stats] Scan Method Statistics:') for row in stats: diff --git a/pialert/publishers/email.py b/pialert/publishers/email.py index 3d7bc3e7..be045463 100755 --- a/pialert/publishers/email.py +++ b/pialert/publishers/email.py @@ -6,6 +6,7 @@ import smtplib import conf +import socket from helper import hide_email, noti_struc from logger import mylog, print_log @@ -83,8 +84,14 @@ def send (msg: noti_struc): except smtplib.SMTPAuthenticationError as e: mylog('none', [' ERROR: Failed at - ', failedAt]) mylog('none', [' ERROR: Couldn\'t connect to the SMTP server (SMTPAuthenticationError), skipping Email (enable LOG_LEVEL=debug for more logging)']) + mylog('none', [' ERROR: ', str(e)]) except smtplib.SMTPServerDisconnected as e: mylog('none', [' ERROR: Failed at - ', failedAt]) mylog('none', [' ERROR: Couldn\'t connect to the SMTP server (SMTPServerDisconnected), skipping Email (enable LOG_LEVEL=debug for more logging)']) + mylog('none', [' ERROR: ', str(e)]) + except socket.gaierror as e: + mylog('none', [' ERROR: Failed at - ', failedAt]) + mylog('none', [' ERROR: Could not resolve hostname (socket.gaierror), skipping Email (enable LOG_LEVEL=debug for more logging)']) + mylog('none', [' ERROR: ', str(e)]) mylog('debug', '[Send Email] Last executed - ' + str(failedAt)) \ No newline at end of file