diff --git a/README.md b/README.md index 18e27b1e..f1d5ca8b 100755 --- a/README.md +++ b/README.md @@ -7,7 +7,6 @@ Scans for devices connected to your WIFI / LAN and alerts you if new and unknown ![Main screen][main] - # 🐳 Docker image [![Docker](https://img.shields.io/github/actions/workflow/status/jokob-sk/Pi.Alert/docker_prod.yml?label=Build&logo=GitHub)](https://github.com/jokob-sk/Pi.Alert/actions/workflows/docker_prod.yml) [![GitHub Committed](https://img.shields.io/github/last-commit/jokob-sk/Pi.Alert?color=40ba12&label=Committed&logo=GitHub&logoColor=fff)](https://github.com/jokob-sk/Pi.Alert) @@ -30,7 +29,6 @@ The system continuously scans the network for, **New devices**, **New connection examines the DHCP leases (addresses assigned) to find active devices that were not discovered by the other methods. - ## 🧩 Integrations - [Apprise](https://hub.docker.com/r/caronc/apprise), [Pushsafer](https://www.pushsafer.com/), [NTFY](https://ntfy.sh/) - [Webhooks](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/WEBHOOK_N8N.md) ([sample JSON](docs/webhook_json_sample.json)) @@ -49,18 +47,16 @@ The system continuously scans the network for, **New devices**, **New connection - Sessions, Connected devices, Favorites, Events, Presence, Concurrent devices, Down alerts, IP's - Manual Nmap scans, Optional speedtest for Device "Internet" - Simple Network relationship display - - Maintenance tasks and Settings like: - - Status Infos (active scans, database size, backup counter) - - Theme Selection (blue, red, green, yellow, black, purple) and Light/Dark-Mode Switch - - Language Selection (English, German, Spanish) - - Pause arp-scan + - Maintenance tasks and Settings like: + - Theme Selection (blue, red, green, yellow, black, purple) and Light/Dark-Mode Switch - DB maintenance, Backup, Restore tools and CSV Export / Import - - Configurable login to prevent unauthorized use. + - Simple login Support - 🌟(Experimental) [Plugin system](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins) - Create custom plugins with automatically generated settings and UI. - Monitor anything for changes - - Check the instructions carefully if you are up for a challenge! - - Help/FAQ Section + - Check the instructions carefully if you are up for a challenge! Current plugins include: + - Detecting Rogue DHCP servers + - Monitoring HTTP status changes of domains/URLs | ![Screen 1][screen1] | ![Screen 2][screen2] | ![Screen 5][screen5] | |----------------------|----------------------| ----------------------| @@ -93,8 +89,6 @@ Device Management [instructions](docs/DEVICE_MANAGEMENT.md) | Old Versions [Hist ## ☕ Support me -Disclaimer: Please only donate if you don't have any debt yourself. Support yourself first, then others. - Sponsor Me on GitHub Buy Me A Coffee Support me on patreon diff --git a/back/pialert.py b/back/pialert.py index 63cb57a2..71a080a4 100755 --- a/back/pialert.py +++ b/back/pialert.py @@ -1197,8 +1197,6 @@ def copy_pihole_network (): #------------------------------------------------------------------------------- def read_DHCP_leases (): - reporting = False - # Read DHCP Leases # Bugfix #1 - dhcp.leases: lines with different number of columns (5 col) data = [] @@ -1209,14 +1207,13 @@ def read_DHCP_leases (): if len(row) == 5 : data.append (row) - # Insert into PiAlert table - sql.execute ("DELETE FROM DHCP_Leases") + # Insert into PiAlert table sql.executemany ("""INSERT INTO DHCP_Leases (DHCP_DateTime, DHCP_MAC, DHCP_IP, DHCP_Name, DHCP_MAC2) VALUES (?, ?, ?, ?, ?) """, data) - return reporting + #------------------------------------------------------------------------------- def save_scanned_devices (p_arpscan_devices, p_cycle_interval): @@ -1591,8 +1588,7 @@ def update_devices_data_from_scan (): sql.execute ("""UPDATE Devices SET dev_NAME = (SELECT PH_Name FROM PiHole_Network WHERE PH_MAC = dev_MAC) - WHERE (dev_Name = "(unknown)" - OR dev_Name = "" + WHERE (dev_Name in ("(unknown)", "(name not found)", "" ) OR dev_Name IS NULL) AND EXISTS (SELECT 1 FROM PiHole_Network WHERE PH_MAC = dev_MAC @@ -1603,8 +1599,7 @@ def update_devices_data_from_scan (): sql.execute ("""UPDATE Devices SET dev_NAME = (SELECT DHCP_Name FROM DHCP_Leases WHERE DHCP_MAC = dev_MAC) - WHERE (dev_Name = "(unknown)" - OR dev_Name = "" + WHERE (dev_Name in ("(unknown)", "(name not found)", "" ) OR dev_Name IS NULL) AND EXISTS (SELECT 1 FROM DHCP_Leases WHERE DHCP_MAC = dev_MAC)""") @@ -1625,6 +1620,8 @@ def update_devices_data_from_scan (): sql.executemany ("UPDATE Devices SET dev_Vendor = ? WHERE dev_MAC = ? ", recordsToUpdate ) + # clean-up device leases table + sql.execute ("DELETE FROM DHCP_Leases") print_log ('Update devices end') #------------------------------------------------------------------------------- @@ -2353,15 +2350,7 @@ def send_notifications (): mail_text = mail_text.replace ('', portsTxt ) if 'plugins' in INCLUDED_SECTIONS and ENABLE_PLUGINS: - # Compose Plugins Section - # sqlQuery = get_plugin_events_to_report_on_SQL() - - # # handle plugins - # for plugin in plugins: - # print_plugin_info(plugin, ['display_name','description']) - - # pref = plugin["unique_prefix"] - + # Compose Plugins Section sqlQuery = """SELECT Plugin, Object_PrimaryId, Object_SecondaryId, DateTimeChanged, Watched_Value1, Watched_Value2, Watched_Value3, Watched_Value4, Status from Plugins_Events""" notiStruc = construct_notifications(sqlQuery, "Plugins") @@ -3994,7 +3983,7 @@ def process_plugin_events(plugin): pluginEvents[index].status = "watched-not-changed" index += 1 - # Merge existing plugin objects with newly discovered ones and update existin ones with new values + # Merge existing plugin objects with newly discovered ones and update existing ones with new values for eveObj in pluginEvents: if eveObj.status == 'new': pluginObjects.append(eveObj) @@ -4037,7 +4026,74 @@ def process_plugin_events(plugin): # insert only events if they are to be reported on if plugObj.status in get_plugin_setting_value(plugin, "REPORT_ON"): - sql.execute ("INSERT INTO Plugins_Events (Plugin, Object_PrimaryID, Object_SecondaryID, DateTimeCreated, DateTimeChanged, Watched_Value1, Watched_Value2, Watched_Value3, Watched_Value4, Status, Extra, UserData, ForeignKey) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", (plugObj.pluginPref, plugObj.primaryId , plugObj.secondaryId , createdTime, plugObj.changed , plugObj.watched1 , plugObj.watched2 , plugObj.watched3 , plugObj.watched4 , plugObj.status , plugObj.extra, plugObj.userData, plugObj.foreignKey )) + sql.execute ("INSERT INTO Plugins_Events (Plugin, Object_PrimaryID, Object_SecondaryID, DateTimeCreated, DateTimeChanged, Watched_Value1, Watched_Value2, Watched_Value3, Watched_Value4, Status, Extra, UserData, ForeignKey) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", (plugObj.pluginPref, plugObj.primaryId , plugObj.secondaryId , createdTime, plugObj.changed , plugObj.watched1 , plugObj.watched2 , plugObj.watched3 , plugObj.watched4 , plugObj.status , plugObj.extra, plugObj.userData, plugObj.foreignKey )) + + # Perform databse table mapping if enabled for the plugin + # "mapped_to_table": "DHCP_Leases", + + if len(pluginEvents) > 0 and "mapped_to_table" in plugin: + + sqlParams = [] + + dbTable = plugin['mapped_to_table'] + + mylog('debug', [' [Plugins] Mapping objects to database table: ', dbTable]) + + # collect all columns to be mapped + mappedCols = [] + columnsStr = '' + valuesStr = '' + + for clmn in plugin['database_column_definitions']: + if 'mapped_to_column' in clmn: + mappedCols.append(clmn) + columnsStr = f'{columnsStr}, "{clmn["mapped_to_column"]}"' + valuesStr = f'{valuesStr}, ?' + + if len(columnsStr) > 0: + columnsStr = columnsStr[1:] # remove first ',' + valuesStr = valuesStr[1:] # remove first ',' + + # map the column names to plugin object event values + for plgEv in pluginEvents: + + tmpList = [] + + for col in mappedCols: + if col['column'] == 'Index': + tmpList.append(plgEv.index) + elif col['column'] == 'Plugin': + tmpList.append(plgEv.pluginPref) + elif col['column'] == 'Object_PrimaryID': + tmpList.append(plgEv.primaryId) + elif col['column'] == 'Object_SecondaryID': + tmpList.append(plgEv.secondaryId) + elif col['column'] == 'DateTimeCreated': + tmpList.append(plgEv.created) + elif col['column'] == 'DateTimeChanged': + tmpList.append(plgEv.changed) + elif col['column'] == 'Watched_Value1': + tmpList.append(plgEv.watched1) + elif col['column'] == 'Watched_Value2': + tmpList.append(plgEv.watched2) + elif col['column'] == 'Watched_Value3': + tmpList.append(plgEv.watched3) + elif col['column'] == 'Watched_Value4': + tmpList.append(plgEv.watched4) + elif col['column'] == 'UserData': + tmpList.append(plgEv.userData) + elif col['column'] == 'Extra': + tmpList.append(plgEv.extra) + elif col['column'] == 'Status': + tmpList.append(plgEv.status) + + sqlParams.append(tuple(tmpList)) + + q = f'INSERT into {dbTable} ({columnsStr}) VALUES ({valuesStr})' + + mylog('debug', [' [Plugins] SQL query for mapping: ', q ]) + + sql.executemany (q, sqlParams) commitDB() @@ -4084,7 +4140,7 @@ class plugin_object_class: self.watchedHash = str(hash(tmp)) - + #------------------------------------------------------------------------------- # Combine plugin objects, keep user-defined values, created time, changed time if nothing changed and the index def combine_plugin_objects(old, new): diff --git a/docker-compose.yml b/docker-compose.yml index 83359199..fd148df4 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,9 +7,9 @@ services: network_mode: "host" restart: unless-stopped volumes: - - ${APP_DATA_LOCATION}/pialert/config:/home/pi/pialert/config + - ${APP_DATA_LOCATION}/pialert2/config:/home/pi/pialert/config # - ${APP_DATA_LOCATION}/pialert/db/pialert.db:/home/pi/pialert/db/pialert.db - - ${APP_DATA_LOCATION}/pialert/db:/home/pi/pialert/db + - ${APP_DATA_LOCATION}/pialert2/db:/home/pi/pialert/db # (optional) useful for debugging if you have issues setting up the container - ${LOGS_LOCATION}:/home/pi/pialert/front/log # DELETE START anyone trying to use this file: comment out / delete BELOW lines, they are only for development purposes diff --git a/front/plugins/dhcp_leases/config.json b/front/plugins/dhcp_leases/config.json index 4616911f..f24960d4 100755 --- a/front/plugins/dhcp_leases/config.json +++ b/front/plugins/dhcp_leases/config.json @@ -4,6 +4,7 @@ "enabled": true, "data_source": "python-script", "localized": ["display_name", "description", "icon"], + "mapped_to_table": "DHCP_Leases", "display_name" : [{ "language_code":"en_us", "string" : "DHCP Leases" @@ -25,7 +26,7 @@ "database_column_definitions": [ { - "column": "Index", + "column": "Index", "css_classes": "col-sm-2", "show": false, "type": "label", @@ -52,6 +53,7 @@ }, { "column": "Object_PrimaryID", + "mapped_to_column": "DHCP_MAC", "css_classes": "col-sm-2", "show": true, "type": "devicemac", @@ -60,11 +62,12 @@ "localized": ["name"], "name":[{ "language_code":"en_us", - "string" : "IP" + "string" : "MAC address" }] }, { "column": "Object_SecondaryID", + "mapped_to_column": "DHCP_IP", "css_classes": "col-sm-2", "show": true, "type": "deviceip", @@ -73,7 +76,7 @@ "localized": ["name"], "name":[{ "language_code":"en_us", - "string" : "MAC address" + "string" : "IP" }] } , { @@ -91,6 +94,7 @@ }, { "column": "DateTimeChanged", + "mapped_to_column": "DHCP_DateTime", "css_classes": "col-sm-2", "show": true, "type": "label", @@ -117,6 +121,7 @@ }, { "column": "Watched_Value2", + "mapped_to_column": "DHCP_Name", "css_classes": "col-sm-2", "show": true, "type": "label",