diff --git a/.env b/.env index 7ac7cf6a..c75c843a 100644 --- a/.env +++ b/.env @@ -2,5 +2,9 @@ APP_DATA_LOCATION=/path/to/docker_appdata APP_CONFIG_LOCATION=/path/to/docker_config LOGS_LOCATION=/path/to/docker_logs +TZ=Europe/Paris +HOST_USER_ID=1000 +HOST_USER_GID=1000 +PORT=20211 diff --git a/Dockerfile b/Dockerfile index 02d225a6..cd17f6c6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,7 @@ ENV USER=pi USER_ID=1000 USER_GID=1000 TZ=Europe/London PORT=20211 # Todo, do we still need all these packages? I can already see sudo which isn't needed RUN apt-get update \ - && apt-get install --no-install-recommends ca-certificates curl libwww-perl arp-scan perl apt-utils cron sudo lighttpd php php-cgi php-fpm php-sqlite3 sqlite3 dnsutils net-tools python iproute2 nmap python-pip -y \ + && apt-get install --no-install-recommends ca-certificates curl libwww-perl arp-scan perl apt-utils cron sudo lighttpd php php-cgi php-fpm php-sqlite3 sqlite3 dnsutils net-tools python iproute2 nmap python-pip zip -y \ && pip install requests \ && apt-get clean autoclean \ && apt-get autoremove \ @@ -29,8 +29,7 @@ RUN groupadd --gid "${USER_GID}" "${USER}" && \ COPY . /home/pi/pialert # Pi.Alert -RUN sed -ie "s|TIMEZONE|${TZ}|g" /home/pi/pialert/install/pialert.cron \ - && python /home/pi/pialert/back/pialert.py update_vendors \ +RUN python /home/pi/pialert/back/pialert.py update_vendors \ && sed -ie 's/= 80/= '${PORT}'/g' /etc/lighttpd/lighttpd.conf \ && (crontab -l 2>/dev/null; cat /home/pi/pialert/install/pialert.cron) | crontab - diff --git a/README.md b/README.md index 42901f45..58ff9da2 100644 --- a/README.md +++ b/README.md @@ -4,25 +4,26 @@ WIFI / LAN intruder detector. Scan the devices connected to your WIFI / LAN and alert you the connection of -unknown devices. It also warns the disconnection of "always connected" devices. +unknown devices. It also warns if a "always connected" devices disconnects. ![Main screen][main] *(Apologies for my English and my limited knowledge of Python, php and JavaScript)* -# Docker image :whale: +# Docker image 🐳 [![Docker](https://github.com/jokob-sk/Pi.Alert/actions/workflows/docker.yml/badge.svg)](https://github.com/jokob-sk/Pi.Alert/actions/workflows/docker.yml) [![Docker Image Size](https://img.shields.io/docker/image-size/jokobsk/pi.alert?logo=Docker)](https://hub.docker.com/r/jokobsk/pi.alert) Docker Pulls -All credit for Pi.Alert goes to: [pucherot/Pi.Alert](https://github.com/pucherot/Pi.Alert). -A pre-built image is available on :whale: Docker Hub: [jokobsk/Pi.Alert](https://registry.hub.docker.com/r/jokobsk/pi.alert). -The source :page_facing_up: Dockerfile is available [here](https://github.com/jokob-sk/Pi.Alert/blob/main/Dockerfile) with a detailed :books: [readme](https://github.com/jokob-sk/Pi.Alert/blob/main//dockerfiles/README.md) included. +🥇 Pi.Alert credit goes to [pucherot/Pi.Alert](https://github.com/pucherot/Pi.Alert).
+🐳 Docker Image: [jokobsk/Pi.Alert](https://registry.hub.docker.com/r/jokobsk/pi.alert).
+📄 [Dockerfile](https://github.com/jokob-sk/Pi.Alert/blob/main/Dockerfile)
+📚 [Dockerfile instructions](https://github.com/jokob-sk/Pi.Alert/blob/main//dockerfiles/README.md). ![Main screen dark][main_dark] -Optional Darkmode (and 12H activity chart) within this fork courtesy of [leiweibau](https://github.com/leiweibau/Pi.Alert) +Dark mode (and Device presence over time) within this fork courtesy of [leiweibau](https://github.com/leiweibau/Pi.Alert) ## How it works The system continuously scans the network for: @@ -54,14 +55,18 @@ In charge of: - Scan the network searching connected devices using the scanning methods described - Store the information in the DB - - Report the changes detected by e-mail + - Report the changes detected by e-mail and/or other services (Pushsafer, NTFY, Gotify) - Optional speedtest for Device "Internet" | ![Report 1][report1] | ![Report 2][report2] | | -------------------- | -------------------- | ### Front -A web frontal that allows: +There is a configurable login to prevent unauthorized use. + +> * Set `PIALERT_WEB_PROTECTION = True` in `pialert.conf` to enable + +A web frontend that allows: - Manage the devices inventory and the characteristics - Display in a visual way all the information collected by the back - Sessions @@ -72,7 +77,7 @@ A web frontal that allows: - Concurrent devices - Down alerts - IP's - - manuel nmap scans + - Manual Nmap scans - Optional speedtest for Device "Internet" - ... @@ -98,9 +103,9 @@ Initially designed to run on a Raspberry Pi, probably it can run on many other Linux distributions. - One-step Automated Install: - #### `curl -sSL https://github.com/pucherot/Pi.Alert/raw/main/install/pialert_install.sh | bash` + #### `curl -sSL https://github.com/leiweibau/Pi.Alert/raw/main/install/pialert_install.sh | bash` -- One-step Automated Install (forked) without Webserver: +- One-step Automated Install without Webserver if another Webserver is already installed. (not recommended): #### `curl -sSL https://github.com/leiweibau/Pi.Alert/raw/main/install/pialert_install_no_webserver.sh | bash` - [Installation Guide (step by step)](docs/INSTALL.md) @@ -109,7 +114,7 @@ Linux distributions. # Update - One-step Automated Update: - #### `curl -sSL https://github.com/pucherot/Pi.Alert/raw/main/install/pialert_update.sh | bash` + #### `curl -sSL https://github.com/leiweibau/Pi.Alert/raw/main/install/pialert_update.sh | bash` # Uninstall process @@ -159,6 +164,16 @@ Linux distributions. ***Suggestions and comments are welcome*** +### Special thanks 🥇 + + This code is a collaborative body of work, with special thanks to: + + - [leiweibau](https://github.com/leiweibau/Pi.Alert): Dark mode (and Last X scans activity chart) + - [Macleykun](https://github.com/Macleykun): Help with Dockerfile clean-up + - [Final-Hawk](https://github.com/Final-Hawk): Help with NTFY, styling and other fixes + - [terorero](https://github.com/terorero): Spanish translation + - [jokob-sk](https://github.com/jokob-sk/Pi.Alert): DB Maintenance tools + - Please see the [Git commit history](https://github.com/jokob-sk/Pi.Alert/commits/main) for a full list of people and their contributions to the project [main]: ./docs/img/1_devices.jpg "Main screen" diff --git a/back/pialert.py b/back/pialert.py index 3cc7c5bb..76dc2db2 100644 --- a/back/pialert.py +++ b/back/pialert.py @@ -1230,21 +1230,21 @@ def email_reporting (): mail_text = mail_text.replace ('', socket.gethostname() ) mail_html = mail_html.replace ('', socket.gethostname() ) - mail_text = mail_text.replace ('', VERSION ) - mail_html = mail_html.replace ('', VERSION ) + # mail_text = mail_text.replace ('', VERSION ) + # mail_html = mail_html.replace ('', VERSION ) - mail_text = mail_text.replace ('', VERSION_DATE ) - mail_html = mail_html.replace ('', VERSION_DATE ) + # mail_text = mail_text.replace ('', VERSION_DATE ) + # mail_html = mail_html.replace ('', VERSION_DATE ) - mail_text = mail_text.replace ('', VERSION_YEAR ) - mail_html = mail_html.replace ('', VERSION_YEAR ) + # mail_text = mail_text.replace ('', VERSION_YEAR ) + # mail_html = mail_html.replace ('', VERSION_YEAR ) # Compose Internet Section print (' Formating report...') mail_section_Internet = False mail_text_Internet = '' mail_html_Internet = '' - text_line_template = '{}\t{}\n{}\t{}\n{}\t{}\n{}\t{}\n\n' + text_line_template = '{} \t{}\t{}\t{}\n' html_line_template = '\n'+ \ ' {} \n {} \n'+ \ ' {} \n'+ \ @@ -1273,7 +1273,7 @@ def email_reporting (): mail_section_new_devices = False mail_text_new_devices = '' mail_html_new_devices = '' - text_line_template = '{}\t{}\n\t{}\t{}\n\t{}\t{}\n\t{}\t{}\n\t{}\t{}\n\n' + text_line_template = '{}\t{}\n\t{}\t{}\n\t{}\t{}\n\t{}\t{}\n\t{}\t{}\n\n' html_line_template = '\n'+ \ ' {} \n {} \n'+\ ' {} \n {} \n {} \n\n' @@ -1286,8 +1286,8 @@ def email_reporting (): for eventAlert in sql : mail_section_new_devices = True mail_text_new_devices += text_line_template.format ( - 'Name:', eventAlert['dev_Name'], 'MAC:', eventAlert['eve_MAC'], 'IP:', eventAlert['eve_IP'], - 'Time:', eventAlert['eve_DateTime'], 'More Info:', eventAlert['eve_AdditionalInfo']) + 'Name: ', eventAlert['dev_Name'], 'MAC: ', eventAlert['eve_MAC'], 'IP: ', eventAlert['eve_IP'], + 'Time: ', eventAlert['eve_DateTime'], 'More Info: ', eventAlert['eve_AdditionalInfo']) mail_html_new_devices += html_line_template.format ( REPORT_DEVICE_URL, eventAlert['eve_MAC'], eventAlert['eve_MAC'], eventAlert['eve_DateTime'], eventAlert['eve_IP'], @@ -1300,7 +1300,7 @@ def email_reporting (): mail_section_devices_down = False mail_text_devices_down = '' mail_html_devices_down = '' - text_line_template = '{}\t{}\n\t{}\t{}\n\t{}\t{}\n\t{}\t{}\n\n' + text_line_template = '{}\t{}\n\t{}\t{}\n\t{}\t{}\n\t{}\t{}\n\n' html_line_template = '\n'+ \ ' {} \n {} \n'+ \ ' {} \n {} \n\n' @@ -1313,8 +1313,8 @@ def email_reporting (): for eventAlert in sql : mail_section_devices_down = True mail_text_devices_down += text_line_template.format ( - 'Name:', eventAlert['dev_Name'], 'MAC:', eventAlert['eve_MAC'], - 'Time:', eventAlert['eve_DateTime'],'IP:', eventAlert['eve_IP']) + 'Name: ', eventAlert['dev_Name'], 'MAC: ', eventAlert['eve_MAC'], + 'Time: ', eventAlert['eve_DateTime'],'IP: ', eventAlert['eve_IP']) mail_html_devices_down += html_line_template.format ( REPORT_DEVICE_URL, eventAlert['eve_MAC'], eventAlert['eve_MAC'], eventAlert['eve_DateTime'], eventAlert['eve_IP'], @@ -1342,9 +1342,9 @@ def email_reporting (): for eventAlert in sql : mail_section_events = True mail_text_events += text_line_template.format ( - 'Name:', eventAlert['dev_Name'],'Event:', eventAlert['eve_EventType'], - 'MAC:', eventAlert['eve_MAC'], 'IP:', eventAlert['eve_IP'], - 'Time:', eventAlert['eve_DateTime'],'More Info:', eventAlert['eve_AdditionalInfo']) + 'Name: ', eventAlert['dev_Name'], 'MAC: ', eventAlert['eve_MAC'], + 'IP: ', eventAlert['eve_IP'],'Time: ', eventAlert['eve_DateTime'], + 'Event: ', eventAlert['eve_EventType'],'More Info: ', eventAlert['eve_AdditionalInfo']) mail_html_events += html_line_template.format ( REPORT_DEVICE_URL, eventAlert['eve_MAC'], eventAlert['eve_MAC'], eventAlert['eve_DateTime'], eventAlert['eve_IP'], @@ -1372,8 +1372,14 @@ def email_reporting (): send_ntfy (mail_text) else : print (' Skip NTFY...') + if REPORT_PUSHSAFER : + print (' Sending report by PUSHSAFER...') + send_pushsafer (mail_text) + else : + print (' Skip PUSHSAFER...') else : print (' No changes to report...') + # Clean Pending Alert Events @@ -1400,6 +1406,36 @@ def send_ntfy (_Text): "Priority": "urgent", "Tags": "warning" }) + +def send_pushsafer (_Text): + url = 'https://www.pushsafer.com/api' + post_fields = { + "t" : 'Pi.Alert Message', + "m" : _Text, + "s" : 11, + "v" : 3, + "i" : 148, + "c" : '#ef7f7f', + "d" : 'a', + "u" : REPORT_DASHBOARD_URL, + "ut" : 'Open Pi.Alert', + "k" : PUSHSAFER_TOKEN, + } + requests.post(url, data=post_fields) + + +#------------------------------------------------------------------------------- + +def send_ntfy (_Text): + requests.post("https://ntfy.sh/{}".format(NTFY_TOPIC), + data=_Text, + headers={ + "Title": "Pi.Alert Notification", + "Click": REPORT_DASHBOARD_URL, + "Priority": "urgent", + "Tags": "warning" + }) + #------------------------------------------------------------------------------- def format_report_section (pActive, pSection, pTable, pText, pHTML): global mail_text @@ -1470,27 +1506,51 @@ def send_email (pText, pHTML): # Send mail smtp_connection = smtplib.SMTP (SMTP_SERVER, SMTP_PORT) smtp_connection.ehlo() - smtp_connection.starttls() - smtp_connection.ehlo() - smtp_connection.login (SMTP_USER, SMTP_PASS) +# smtp_connection.starttls() +# smtp_connection.ehlo() +# smtp_connection.login (SMTP_USER, SMTP_PASS) + if not SafeParseGlobalBool("SMTP_SKIP_TLS"): + smtp_connection.starttls() + smtp_connection.ehlo() + if not SafeParseGlobalBool("SMTP_SKIP_LOGIN"): + smtp_connection.login (SMTP_USER, SMTP_PASS) smtp_connection.sendmail (REPORT_FROM, REPORT_TO, msg.as_string()) smtp_connection.quit() +#------------------------------------------------------------------------------- +def SafeParseGlobalBool(boolVariable): + if boolVariable in globals(): + return eval(boolVariable) + return False #=============================================================================== # DB #=============================================================================== -def upgradeDB (): +def upgradeDB (): openDB() - # check if table exists - listOfTables = sql.execute( - """SELECT name FROM sqlite_master WHERE type='table' - AND name='Online_History'; """).fetchall() + # indicates, if Online_History table is available + onlineHistoryAvailable = sql.execute(""" + SELECT name FROM sqlite_master WHERE type='table' + AND name='Online_History'; + """).fetchall() != [] + + # Check if it is incompatible (Check if table has all required columns) + isIncompatible = False - if listOfTables == []: - print_log ('Upgrading DB (creating Online_History table)') + if onlineHistoryAvailable : + isIncompatible = sql.execute (""" + SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Online_History') WHERE name='Archived_Devices' + """).fetchone()[0] == 0 + + # Drop table if available, but incompatible + if onlineHistoryAvailable and isIncompatible: + print_log ('Table is incompatible, Dropping the Online_History table)') + sql.execute("DROP TABLE Online_History;") + onlineHistoryAvailable = False + + if onlineHistoryAvailable == False : sql.execute(""" CREATE TABLE "Online_History" ( "Index" INTEGER, @@ -1503,6 +1563,7 @@ def upgradeDB (): ); """) + #------------------------------------------------------------------------------- def openDB (): diff --git a/back/report_template.txt b/back/report_template.txt index a2943c63..9a2d72e3 100644 --- a/back/report_template.txt +++ b/back/report_template.txt @@ -4,18 +4,18 @@ Server: Internet ---------------------- +---------------------- New Devices ---------------------- +---------------------- Devices Down ---------------------- +---------------------- Events ---------------------- +---------------------- diff --git a/config/pialert.conf b/config/pialert.conf index d5897392..cbb6420a 100644 --- a/config/pialert.conf +++ b/config/pialert.conf @@ -7,38 +7,51 @@ # Puche 2021 pi.alert.application@gmail.com GNU GPLv3 #------------------------------------------------------------------------------- -PIALERT_PATH = '/home/pi/pialert' -DB_PATH = PIALERT_PATH + '/db/pialert.db' -LOG_PATH = PIALERT_PATH + '/log' -VENDORS_DB = '/usr/share/arp-scan/ieee-oui.txt' -PRINT_LOG = False +PIALERT_PATH = '/home/pi/pialert' +DB_PATH = PIALERT_PATH + '/db/pialert.db' +LOG_PATH = PIALERT_PATH + '/log' +VENDORS_DB = '/usr/share/arp-scan/ieee-oui.txt' +PRINT_LOG = False +TIMEZONE = 'Europe/Berlin' +PIALERT_WEB_PROTECTION = False +PIALERT_WEB_PASSWORD = '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92' -SMTP_SERVER = 'smtp.gmail.com' -SMTP_PORT = 587 -SMTP_USER = 'user@gmail.com' -SMTP_PASS = 'password' +# EMAIL settings +SMTP_SERVER = 'smtp.gmail.com' +SMTP_PORT = 587 +SMTP_USER = 'user@gmail.com' +SMTP_PASS = 'password' +SMTP_SKIP_TLS = False +SMTP_SKIP_LOGIN = False -REPORT_MAIL = False -REPORT_FROM = 'Pi.Alert <' + SMTP_USER +'>' -REPORT_TO = 'user@gmail.com' -REPORT_DEVICE_URL = 'http://pi.alert/deviceDetails.php?mac=' +REPORT_MAIL = False +REPORT_FROM = 'Pi.Alert <' + SMTP_USER +'>' +REPORT_TO = 'user@gmail.com' +REPORT_DEVICE_URL = 'http://pi.alert/deviceDetails.php?mac=' +REPORT_DASHBOARD_URL = 'http://pi.alert/' -REPORT_NTFY = False -REPORT_DASHBOARD_URL = 'http://pi.alert/' -NTFY_TOPIC = 'replace-my-secure-topicname-91h889f28' +# NTFY (https://ntfy.sh/) settings +REPORT_NTFY = False +NTFY_TOPIC = 'replace_my_secure_topicname_91h889f28' +REPORT_DASHBOARD_URL = 'http://pi.alert/' -# QUERY_MYIP_SERVER = 'https://diagnostic.opendns.com/myip' -QUERY_MYIP_SERVER = 'http://ipv4.icanhazip.com' -DDNS_ACTIVE = False -DDNS_DOMAIN = 'your_domain.freeddns.org' -DDNS_USER = 'dynu_user' -DDNS_PASSWORD = 'A0000000B0000000C0000000D0000000' -DDNS_UPDATE_URL = 'https://api.dynu.com/nic/update?' +# PUSHSAFER (https://www.pushsafer.com/) settings +REPORT_PUSHSAFER = False +PUSHSAFER_TOKEN = 'ApiKey' -PIHOLE_ACTIVE = False -PIHOLE_DB = '/etc/pihole/pihole-FTL.db' -DHCP_ACTIVE = False -DHCP_LEASES = '/etc/pihole/dhcp.leases' +# QUERY_MYIP_SERVER = 'https://diagnostic.opendns.com/myip' +QUERY_MYIP_SERVER = 'http://ipv4.icanhazip.com' +DDNS_ACTIVE = False +DDNS_DOMAIN = 'your_domain.freeddns.org' +DDNS_USER = 'dynu_user' +DDNS_PASSWORD = 'A0000000B0000000C0000000D0000000' +DDNS_UPDATE_URL = 'https://api.dynu.com/nic/update?' + +# PIHOLE settings +PIHOLE_ACTIVE = False +PIHOLE_DB = '/etc/pihole/pihole-FTL.db' +DHCP_ACTIVE = False +DHCP_LEASES = '/etc/pihole/dhcp.leases' # arp-scan options & samples # @@ -51,4 +64,4 @@ DHCP_LEASES = '/etc/pihole/dhcp.leases' # Scan using interface eth0 # SCAN_SUBNETS = '--localnet --interface=eth0' -SCAN_SUBNETS = '--localnet' +SCAN_SUBNETS = '--localnet' diff --git a/config/reset_password.sh b/config/reset_password.sh new file mode 100644 index 00000000..a7f933ee --- /dev/null +++ b/config/reset_password.sh @@ -0,0 +1,7 @@ +cp pialert.conf pialert.conf.bak +PIA_PASS=$1 +echo "The password '$1' is hashed" +PIA_PASS_HASH=$(echo -n $PIA_PASS | sha256sum | awk '{print $1}') +echo "The hashed password is: $PIA_PASS_HASH" +sed -i "/PIALERT_WEB_PASSWORD/c\PIALERT_WEB_PASSWORD = '$PIA_PASS_HASH'" pialert.conf +echo "The hash was saved in the configuration file" \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index f629723b..b1ec288d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,7 +10,7 @@ services: - ${APP_DATA_LOCATION}/pialert/db/pialert.db:/home/pi/pialert/db/pialert.db - ${LOGS_LOCATION}/tmp:/home/pi/pialert/log environment: - - TZ=Europe/London - - PORT=20211 - - HOST_USER_ID=1000 - - HOST_USER_GID=1000 + - TZ=${TZ} + - PORT=${PORT} + - HOST_USER_ID=${HOST_USER_ID} + - HOST_USER_GID=${HOST_USER_GID} diff --git a/dockerfiles/README.md b/dockerfiles/README.md index 44b125e7..03e8d97e 100644 --- a/dockerfiles/README.md +++ b/dockerfiles/README.md @@ -4,11 +4,12 @@ Docker Pulls -# :whale: A docker image for Pi.Alert +# 🐳 A docker image for Pi.Alert -All credit for Pi.Alert goes to: [pucherot/Pi.Alert](https://github.com/pucherot/Pi.Alert). -A pre-built image is available on :whale: Docker Hub: [jokobsk/Pi.Alert](https://registry.hub.docker.com/r/jokobsk/pi.alert). -The source :page_facing_up: Dockerfile is available [here](https://github.com/jokob-sk/Pi.Alert/blob/main/Dockerfile) with a detailed :books: [readme](https://github.com/jokob-sk/Pi.Alert/blob/main//dockerfiles/README.md) included. +🥇 Pi.Alert credit goes to [pucherot/Pi.Alert](https://github.com/pucherot/Pi.Alert).
+🐳 Docker Image: [jokobsk/Pi.Alert](https://registry.hub.docker.com/r/jokobsk/pi.alert).
+📄 [Dockerfile](https://github.com/jokob-sk/Pi.Alert/blob/main/Dockerfile)
+📚 [Dockerfile instructions](https://github.com/jokob-sk/Pi.Alert/blob/main//dockerfiles/README.md). Big thanks to @Macleykun for help and tips&tricks for Dockerfile(s): @@ -16,20 +17,20 @@ Big thanks to @Macleykun for help and -## :information_source: Usage +## ℹ Usage Network - - You will have to probably run the container on the host network, e.g: `sudo docker run --rm --net=host jokobsk/pi.alert` + - You will have to run the container on the host network, e.g: `sudo docker run --rm --net=host jokobsk/pi.alert` Default Port - The app is accessible on the port `:20211`. -> Please note - the cronjob is executed every 1, 5 and 15 minutes so wait that long for all of the scans to run. +> Please note - the cronjob is executed every 3 and 5 minutes so wait that long for all of the scans to run. -## :floppy_disk: Setup and Backups +## 💾 Setup and Backups 1. (**required**) Download `pialert.conf` and `version.conf` from [here](https://github.com/jokob-sk/Pi.Alert/tree/main/config). -2. (**required**) In `pialert.config` specify your network adapter (will probably be `eth0` or `eth1`) and the network filter (which **significantly** speeds up the scan process), e.g. if your DHCP server assigns IPs in the 192.168.1.0 to 192.168.1.255 range specify it the following way: +2. (**required**) In `pialert.conf` specify your network adapter (will probably be `eth0` or `eth1`) and the network filter (which **significantly** speeds up the scan process), e.g. if your DHCP server assigns IPs in the 192.168.1.0 to 192.168.1.255 range specify it the following way: * `SCAN_SUBNETS = '192.168.1.0/24 --interface=eth0'` 3. (**required**) Use your configuration by: * Mapping the container folder `/home/pi/pialert/config` to a persistent folder containing `pialert.conf` and `version.conf`, @@ -37,14 +38,12 @@ Default Port 4. Set the `TZ` environment variable to your current time zone (e.g.`Europe/Paris`). Find your time zone [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). 5. Database backup * The DB is stored under `/home/pi/pialert/db/pialert.db`. Map this file to a persistent location (see [Examples](https://github.com/jokob-sk/Pi.Alert/tree/main/dockerfiles#page_facing_up-examples) for details). If facing issues (AJAX errors, can't write to DB, etc, make sure permissions are set correctly, alternatively check the logs under `/home/pi/pialert/log`) - * Automated copy - The docker image copies the DB once every 30 min to `/home/pi/pialert/config/pialert.db_bak`. If you have a backup already available, make sure you rename this file if you want to keep older backups before starting a new container. To restore the DB run: `cp /home/pi/pialert/config/pialert.db_bak /home/pi/pialert/db/pialert.db` 6. The container supports mapping to local User nad Group IDs. Specify the enviroment variables `HOST_USER_ID` and `HOST_USER_GID` if needed. 7. You can override the port by specifying the `PORT` env variable. Config examples can be found below. -## :page_facing_up: Examples +## 📄 Examples ### Example 1 @@ -61,22 +60,25 @@ services: volumes: - ${APP_DATA_LOCATION}/pialert/config:/home/pi/pialert/config - ${APP_DATA_LOCATION}/pialert/db/pialert.db:/home/pi/pialert/db/pialert.db - - ${LOGS_LOCATION}/:/home/pi/pialert/log + - ${LOGS_LOCATION}/tmp:/home/pi/pialert/log environment: - - TZ=Europe/London - - PORT=20211 - - HOST_USER_ID=1000 - - HOST_USER_GID=1000 + - TZ=${TZ} + - PORT=${PORT} + - HOST_USER_ID=${HOST_USER_ID} + - HOST_USER_GID=${HOST_USER_GID} ``` `.env` file ```yaml - +#GLOBAL APP_DATA_LOCATION=/path/to/docker_appdata APP_CONFIG_LOCATION=/path/to/docker_config LOGS_LOCATION=/path/to/docker_logs - +TZ=Europe/Paris +HOST_USER_ID=1000 +HOST_USER_GID=1000 +PORT=20211 ``` To run the container execute: `sudo docker-compose --env-file /path/to/.env up` @@ -102,7 +104,7 @@ Courtesy of [pbek](https://github.com/pbek). The volume `pialert_db` is used by - ./pialert/version.conf:/home/pi/pialert/config/version.conf ``` -## :coffee: Support +## ☕ Support > Disclaimer: This is my second container and I might have used unconventional hacks so if anyone is more experienced, feel free to fork/create pull requests. Also, please only donate if you don't have any debt yourself. Support yourself first, then others. diff --git a/dockerfiles/start.sh b/dockerfiles/start.sh index 3ab58572..247ba2d4 100755 --- a/dockerfiles/start.sh +++ b/dockerfiles/start.sh @@ -3,7 +3,8 @@ # if custom variables not set we do not need to do anything if [ -n "${TZ}" ]; then - sed -ie "s|Europe/London|${TZ}|g" /home/pi/pialert/install/pialert.cron + sed -ie "s|Europe/Berlin|${TZ}|g" /home/pi/pialert/install/pialert.cron + sed -ie "s|Europe/Berlin|${TZ}|g" /home/pi/pialert/config/pialert.conf crontab < /home/pi/pialert/install/pialert.cron fi if [ -n "${PORT}" ]; then diff --git a/front/css/dark-patch.css b/front/css/dark-patch.css index 7b0ec0cf..97738f34 100644 --- a/front/css/dark-patch.css +++ b/front/css/dark-patch.css @@ -672,6 +672,19 @@ input[type="password"]::-webkit-caps-lock-indicator { .table-responsive { border: 0px; } + +.login-page { + background-color: transparent; +} + +.login-logo a { + color: white; +} + +.login-box-body { + color: #bec5cb; + background-color: #272c30; +} /* Add border radius to bottom of the status boxes*/ .pa-small-box-footer { border-bottom-left-radius: 10px; diff --git a/front/deviceDetails.php b/front/deviceDetails.php index b5b11762..aefd7542 100644 --- a/front/deviceDetails.php +++ b/front/deviceDetails.php @@ -8,6 +8,14 @@ #--------------------------------------------------------------------------- --> diff --git a/front/devices.php b/front/devices.php index 3e8563d4..071f0c02 100644 --- a/front/devices.php +++ b/front/devices.php @@ -8,6 +8,14 @@ #--------------------------------------------------------------------------- --> @@ -106,7 +114,7 @@
-

12

+

diff --git a/front/events.php b/front/events.php index 0655c08a..597cca30 100644 --- a/front/events.php +++ b/front/events.php @@ -8,6 +8,14 @@ #--------------------------------------------------------------------------- --> diff --git a/front/index.php b/front/index.php index a1338922..55005e41 100644 --- a/front/index.php +++ b/front/index.php @@ -1,5 +1,159 @@ + + + + + + + + + + Pi-Alert | Log in + + + + + + + + + + + + + + +'; + $BACKGROUND_IMAGE_PATCH='style="background-image: url(\'img/boxed-bg-dark.png\');"'; +} else { $BACKGROUND_IMAGE_PATCH='style="background-image: url(\'img/background.png\');"';} +?> + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/front/maintenance.php b/front/maintenance.php index 95761ad1..0057584f 100644 --- a/front/maintenance.php +++ b/front/maintenance.php @@ -1,4 +1,12 @@
@@ -321,13 +329,13 @@ if (submit && isset($_POST['langselector_set'])) {
- +
-
+
-
-
-
+
+
+ @@ -433,8 +441,22 @@ function PiaRestoreDBfromArchive() }); } -// Restore DB from Archive -function askPiaEnableDarkmode () { +// Purge Backups +function askPiaPurgeDBBackups() { + // Ask + showModalWarning('', '', + 'Cancel', 'Purge', 'PiaPurgeDBBackups'); +} +function PiaPurgeDBBackups() +{ + // Execute + $.get('php/server/devices.php?action=PiaPurgeDBBackups', function(msg) { + showMessage (msg); + }); +} + +// Switch Darkmode +function askPiaEnableDarkmode() { // Ask showModalWarning('', '', 'Cancel', 'Switch', 'PiaEnableDarkmode'); @@ -461,20 +483,6 @@ function PiaToggleArpScan() }); } -// upgrade DB -function askUpgradeDatabase () { - // Ask - showModalWarning('', '', - 'Cancel', 'Upgrade', 'upgradeDatabase'); -} -function upgradeDatabase() -{ - // Upgrade DB - $.get('php/server/devices.php?action=upgradeDatabase', function(msg) { - showMessage (msg); - }); -} - diff --git a/front/php/server/devices.php b/front/php/server/devices.php index 4d7484d9..38fd7c7d 100644 --- a/front/php/server/devices.php +++ b/front/php/server/devices.php @@ -35,8 +35,7 @@ if (strlen($pia_lang_selected) == 0) {$pia_lang_selected = 'en_us';} case 'getDeviceData': getDeviceData(); break; case 'setDeviceData': setDeviceData(); break; case 'deleteDevice': deleteDevice(); break; - case 'deleteAllWithEmptyMACs': deleteAllWithEmptyMACs(); break; - case 'upgradeDatabase': upgradeDB(); break; + case 'deleteAllWithEmptyMACs': deleteAllWithEmptyMACs(); break; case 'createBackupDB': createBackupDB(); break; case 'restoreBackupDB': restoreBackupDB(); break; case 'deleteAllDevices': deleteAllDevices(); break; @@ -46,6 +45,7 @@ if (strlen($pia_lang_selected) == 0) {$pia_lang_selected = 'en_us';} case 'deleteEvents': deleteEvents(); break; case 'PiaBackupDBtoArchive': PiaBackupDBtoArchive(); break; case 'PiaRestoreDBfromArchive': PiaRestoreDBfromArchive(); break; + case 'PiaPurgeDBBackups': PiaPurgeDBBackups(); break; case 'PiaEnableDarkmode': PiaEnableDarkmode(); break; case 'PiaToggleArpScan': PiaToggleArpScan(); break; @@ -212,36 +212,6 @@ function deleteAllWithEmptyMACs() { } } -//------------------------------------------------------------------------------ -// Upgrade the database to enable new functionality -//------------------------------------------------------------------------------ -function upgradeDB() { - global $db; - global $pia_lang; - - // sql - $sql = ' - -- Online_History definition - - CREATE TABLE "Online_History" ( - "Index" INTEGER, - "Scan_Date" TEXT, - "Online_Devices" INTEGER, - "Down_Devices" INTEGER, - "All_Devices" INTEGER, - PRIMARY KEY("Index" AUTOINCREMENT) - );'; - // execute sql - $result = $db->query($sql); - - // check result - if ($result == TRUE) { - echo $pia_lang['BackDevices_DBTools_Upgrade']; - } else { - echo $pia_lang['BackDevices_DBTools_UpgradeError']."\n\n$sql \n\n". $db->lastErrorMsg(); - } -} - //------------------------------------------------------------------------------ // Delete all devices with empty MAC addresses //------------------------------------------------------------------------------ @@ -262,8 +232,6 @@ function deleteUnknownDevices() { } } - - //------------------------------------------------------------------------------ // Delete all devices //------------------------------------------------------------------------------ @@ -361,6 +329,37 @@ function PiaRestoreDBfromArchive() { } +//------------------------------------------------------------------------------ +// Purge Backups +//------------------------------------------------------------------------------ +function PiaPurgeDBBackups() { + global $pia_lang; + + $Pia_Archive_Path = '../../../db'; + $Pia_Backupfiles = array(); + $files = array_diff(scandir($Pia_Archive_Path, SCANDIR_SORT_DESCENDING), array('.', '..', 'pialert.db', 'pialertdb-reset.zip')); + + foreach ($files as &$item) + { + $item = $Pia_Archive_Path.'/'.$item; + if (stristr($item, 'setting_') == '') {array_push($Pia_Backupfiles, $item);} + } + + if (sizeof($Pia_Backupfiles) > 3) + { + rsort($Pia_Backupfiles); + unset($Pia_Backupfiles[0], $Pia_Backupfiles[1], $Pia_Backupfiles[2]); + $Pia_Backupfiles_Purge = array_values($Pia_Backupfiles); + for ($i = 0; $i < sizeof($Pia_Backupfiles_Purge); $i++) + { + unlink($Pia_Backupfiles_Purge[$i]); + } + } + echo $pia_lang['BackDevices_DBTools_Purge']; + echo(""); + + } + //------------------------------------------------------------------------------ // Toggle Dark/Light Themes //------------------------------------------------------------------------------ diff --git a/front/php/server/events.php b/front/php/server/events.php index 1d0fa228..b083f0ab 100644 --- a/front/php/server/events.php +++ b/front/php/server/events.php @@ -217,9 +217,9 @@ function getDeviceSessions() { // Disconnection DateTime if ($row['ses_StillConnected'] == true) { - $end = '...'; + $end = '...'; } elseif ($row['ses_EventTypeDisconnection'] == '') { - $end = $row['ses_EventTypeDisconnection']; + $end = $row['ses_EventTypeDisconnection']; } else { $end = formatDate ($row['ses_DateTimeDisconnection']); } @@ -267,7 +267,7 @@ function getDevicePresence() { // SQL $SQL = 'SELECT ses_EventTypeConnection, ses_DateTimeConnection, - ses_EventTypeDisconnection, ses_DateTimeDisconnection, ses_IP, ses_AdditionalInfo, + ses_EventTypeDisconnection, ses_DateTimeDisconnection, ses_IP, ses_AdditionalInfo, ses_StillConnected, CASE WHEN ses_EventTypeConnection = "" THEN @@ -292,10 +292,13 @@ function getDevicePresence() { // Event color if ($row['ses_EventTypeConnection'] == '' || $row['ses_EventTypeDisconnection'] == '') { $color = '#f39c12'; + } elseif ($row['ses_StillConnected'] == 1 ) { + $color = '#00a659'; } else { $color = '#0073b7'; } + // tooltip $tooltip = 'Connection: ' . formatEventDate ($row['ses_DateTimeConnection'], $row['ses_EventTypeConnection']) . chr(13) . 'Disconnection: ' . formatEventDate ($row['ses_DateTimeDisconnection'], $row['ses_EventTypeDisconnection']) . chr(13) . @@ -331,9 +334,9 @@ function getEventsCalendar() { $startDate = '"'. $_REQUEST ['start'] .'"'; $endDate = '"'. $_REQUEST ['end'] .'"'; - // SQL + // SQL $SQL = 'SELECT ses_MAC, ses_EventTypeConnection, ses_DateTimeConnection, - ses_EventTypeDisconnection, ses_DateTimeDisconnection, ses_IP, ses_AdditionalInfo, + ses_EventTypeDisconnection, ses_DateTimeDisconnection, ses_IP, ses_AdditionalInfo, ses_StillConnected, CASE WHEN ses_EventTypeConnection = "" THEN @@ -357,6 +360,8 @@ function getEventsCalendar() { // Event color if ($row['ses_EventTypeConnection'] == '' || $row['ses_EventTypeDisconnection'] == '') { $color = '#f39c12'; + } elseif ($row['ses_StillConnected'] == 1 ) { + $color = '#00a659'; } else { $color = '#0073b7'; } diff --git a/front/php/templates/header.php b/front/php/templates/header.php index 146e66cf..5f3aba36 100644 --- a/front/php/templates/header.php +++ b/front/php/templates/header.php @@ -8,7 +8,23 @@ #--------------------------------------------------------------------------- --> @@ -84,12 +102,7 @@ if ($ENABLED_DARKMODE === True) {