Compare commits

...

409 Commits

Author SHA1 Message Date
jokob-sk
38b525f0b8 Mobile CSS fixes 2024-06-09 00:00:20 +10:00
jokob-sk
931155ea25 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-06-08 23:45:08 +10:00
jokob-sk
35cae3a7d4 🔃 Sync Hub v1.0 + Mobile CSS fixes 2024-06-08 23:44:51 +10:00
github-actions[bot]
72bccd0098 [🤖Automation] Update README with sponsors information 2024-06-08 11:54:00 +00:00
jokob-sk
b743e68155 🔃 Sync Hub v0.8.2 - 📚docs 2024-06-08 18:52:07 +10:00
jokob-sk
1d525cb84c 🔃 Sync Hub v0.8.1 + CSS fixes + Empty settings sanity check + JSON linting + docs 2024-06-08 18:01:58 +10:00
jokob-sk
bbd69c60bf 🔃 Sync Hub v0.8 2024-06-08 12:42:11 +10:00
jokob-sk
c591ab9ce3 🔃 Sync Hub v0.8 2024-06-08 12:29:03 +10:00
jokob-sk
b613775031 🔽HW install fixes 2024-06-08 10:56:24 +10:00
jokob-sk
bd3b15dedc 🔃 Sync Hub v0.7.3 2024-06-08 10:39:53 +10:00
jokob-sk
0d83ed3179 🔃 Sync Hub v0.7.2 2024-06-08 09:34:07 +10:00
jokob-sk
f077c85c2d Weblate 2024-06-08 08:54:58 +10:00
jokob-sk
2eb3f9347a Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-06-08 08:48:58 +10:00
jokob-sk
9daa4491a1 🔃 Sync Hub v0.7.1 2024-06-08 08:48:39 +10:00
Massimo Pissarello
02f882b105 Translated using Weblate (Italian)
Currently translated at 100.0% (676 of 676 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-06-07 16:09:23 +02:00
gallegonovato
5203d4959b Translated using Weblate (Spanish)
Currently translated at 100.0% (676 of 676 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-06-07 16:09:22 +02:00
github-actions[bot]
9e264f7a9f [🤖Automation] Update README with sponsors information 2024-06-07 11:53:49 +00:00
jokob-sk
26e4249f5c 🔃 Sync Hub v0.7 - Devices working 2024-06-07 21:23:49 +10:00
jokob-sk
d63e0d9fd2 🔃 Sync Hub v0.6.51 - Devices table + Permissions fixes 2024-06-07 20:48:44 +10:00
jokob-sk
ebe41ab384 ▶ First/Last session sent in MQTT #697 2024-06-07 20:22:47 +10:00
jokob-sk
1e3cea0f7f 🔃 Sync Hub v0.6.5 - Devices table + Permissions fixes 2024-06-07 20:10:05 +10:00
jokob-sk
b2d38c1c55 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-06-06 23:00:30 +10:00
jokob-sk
23703e4e22 🔃 Sync Hub v0.6.4 - Guid, SyncHubNodeName added 2024-06-06 23:00:05 +10:00
github-actions[bot]
ff6d728dee [🤖Automation] Update README with sponsors information 2024-06-06 11:53:47 +00:00
jokob-sk
73db99fe2f 🔃 Sync Hub v0.6.31 2024-06-06 20:38:12 +10:00
jokob-sk
302a687d41 📅 Remove +timezone offset from First/:ast session columns #695 2024-06-06 18:58:09 +10:00
jokob-sk
6133c2c937 🔃 Sync Hub v0.6.3 2024-06-06 18:52:22 +10:00
jokob-sk
ac8bbca37f 🔃 Sync Hub v0.6.2 2024-06-06 18:50:15 +10:00
Anonymous
be4ca42803 Translated using Weblate (Italian)
Currently translated at 99.1% (670 of 676 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-06-05 23:54:05 +02:00
Anonymous
0355d9214d Translated using Weblate (Russian)
Currently translated at 98.9% (669 of 676 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-06-05 23:54:05 +02:00
Anonymous
d2badf4b51 Translated using Weblate (Spanish)
Currently translated at 99.1% (670 of 676 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-06-05 23:54:05 +02:00
Anonymous
c3e9e84cde Translated using Weblate (German)
Currently translated at 92.3% (624 of 676 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/de/
2024-06-05 23:54:05 +02:00
jokob-sk
09b3f44e23 Weblate 2024-06-06 07:52:49 +10:00
jokob-sk
205cbcf9eb Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-06-06 07:34:30 +10:00
jokob-sk
b7b1a9eb48 🔃 Sync Hub v0.6.1 2024-06-06 07:34:13 +10:00
github-actions[bot]
19eb375da1 [🤖Automation] Update README with sponsors information 2024-06-05 11:53:50 +00:00
jokob-sk
5f59097b0d 🔃 Sync Hub v0.6 2024-06-05 12:57:29 +10:00
jokob-sk
96f18b40d1 🔃 Sync Hub v0.57 2024-06-05 08:16:28 +10:00
jokob-sk
da169c1173 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-06-05 08:05:37 +10:00
jokob-sk
bd11c2ecdf 🔃 Sync Hub v0.56 2024-06-05 08:05:20 +10:00
github-actions[bot]
c636bf1914 [🤖Automation] Update README with sponsors information 2024-06-04 11:53:39 +00:00
jokob-sk
0f724e6a1d 🔃 Sync Hub v0.55 2024-06-04 20:16:30 +10:00
jokob-sk
2599e47121 🔃 Sync Hub v0.54 2024-06-04 20:08:04 +10:00
jokob-sk
bac8ac30aa 🔃 Sync Hub v0.53 2024-06-04 19:58:48 +10:00
jokob-sk
2c8c998a97 🔃 Sync Hub v0.52 2024-06-04 18:39:39 +10:00
jokob-sk
4b577109c8 🔃 Sync Hub v0.51 2024-06-04 18:32:19 +10:00
jokob-sk
a07e5b59c3 🔃 Sync Hub v0.5 2024-06-04 18:22:47 +10:00
jokob-sk
44bf47edc2 🔃 Sync Hub v0.41 2024-06-04 17:47:00 +10:00
jokob-sk
02eafadf15 🔃 Sync Hub v0.4 2024-06-04 17:36:10 +10:00
jokob-sk
46e7e7bc01 🔃 Sync Hub v0.3 2024-06-03 23:06:25 +10:00
jokob-sk
8c96f61b54 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-06-03 22:24:28 +10:00
jokob-sk
8a8df3c7b8 🔃 Node sync v0.2 2024-06-03 22:24:06 +10:00
github-actions[bot]
4cd8aa209b [🤖Automation] Update README with sponsors information 2024-06-03 11:53:53 +00:00
jokob-sk
e3557ad7d2 🔃 Node sync v0.1 2024-06-03 07:56:05 +10:00
jokob-sk
3a7ff90ce1 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-06-03 07:39:52 +10:00
jokob-sk
8a0b8b8a10 🔔 User Notifications v0.6 2024-06-03 07:39:27 +10:00
github-actions[bot]
93e6cc339e [🤖Automation] Update README with sponsors information 2024-06-02 11:53:56 +00:00
jokob-sk
91ff13df27 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-06-01 22:09:38 +10:00
jokob-sk
e49432aee7 🔔 User Notifications v0.6 2024-06-01 22:09:19 +10:00
github-actions[bot]
7ae4465522 [🤖Automation] Update README with sponsors information 2024-06-01 11:53:44 +00:00
jokob-sk
d14fc6586a 🔔 User Notifications v0.5 2024-06-01 20:59:54 +10:00
jokob-sk
cb3c0ecee7 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-06-01 20:05:39 +10:00
jokob-sk
de561e1ad0 🔒DB lock v0.4 #685 + 🔔userNotifications 2024-06-01 20:05:15 +10:00
github-actions[bot]
09f7b1e394 [🤖Automation] Update README with sponsors information 2024-05-31 11:53:35 +00:00
jokob-sk
2e9aa37cd2 🔒DB lock v0.3 #685 + cleanup 2024-05-31 19:30:11 +10:00
jokob-sk
29c3a46170 Merge pull request #692 from vladaurosh/main
upgrading base image to Alpine 3.20, upgrading php to 8.3
2024-05-31 18:53:22 +10:00
Hosted Weblate
9f2e3ae397 Merge branch 'origin/main' into Weblate. 2024-05-31 04:09:17 +02:00
Massimo Pissarello
32a43881dd Translated using Weblate (Italian)
Currently translated at 100.0% (672 of 672 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-05-31 04:09:15 +02:00
Safeguard
c5ed0e92e8 Translated using Weblate (Russian)
Currently translated at 99.8% (671 of 672 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-05-31 04:09:14 +02:00
gallegonovato
a5d120b0d3 Translated using Weblate (Spanish)
Currently translated at 100.0% (672 of 672 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-05-31 04:09:13 +02:00
root
d80bd48294 upgrading base image to Alpine 3.20, upgrading php to 8.3 2024-05-31 00:30:46 +01:00
github-actions[bot]
45c5ee24c7 [🤖Automation] Update README with sponsors information 2024-05-30 11:53:55 +00:00
jokob-sk
ff4b1a16a2 Alpine 3.19 rollback 2024-05-30 17:32:17 +10:00
jokob-sk
74f1177ec6 DB lock v0.2 #685 2024-05-30 16:43:15 +10:00
Anonymous
79b81b8bc2 Translated using Weblate (Italian)
Currently translated at 98.9% (665 of 672 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-05-30 02:38:13 +02:00
Anonymous
c06c4e2ae7 Translated using Weblate (Russian)
Currently translated at 98.8% (664 of 672 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-05-30 02:38:13 +02:00
Anonymous
a2b9ce9c25 Translated using Weblate (Spanish)
Currently translated at 99.1% (666 of 672 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-05-30 02:38:13 +02:00
Anonymous
0a6c11bdaa Translated using Weblate (German)
Currently translated at 92.8% (624 of 672 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/de/
2024-05-30 02:38:12 +02:00
jokob-sk
b682b7cc2f Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-05-30 10:35:16 +10:00
jokob-sk
2dadae1762 Weblate 2024-05-30 10:34:34 +10:00
Massimo Pissarello
ce09ded979 Translated using Weblate (Italian)
Currently translated at 100.0% (670 of 670 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-05-30 02:09:18 +02:00
jokob-sk
9589cfb2cb Merge pull request #688 from vladaurosh/main
Update base docker image to alpine 3.20
2024-05-29 22:29:47 +10:00
github-actions[bot]
d604591162 [🤖Automation] Update README with sponsors information 2024-05-29 11:53:58 +00:00
jokob-sk
bb2beda12a ⚙ settings saving improvements + refactor - DB lock v0.1 #685 2024-05-29 19:24:43 +10:00
jokob-sk
3853b8a4ec ⚙ settings saving improvements - Inline editing bug 🐛 2024-05-29 17:34:51 +10:00
jokob-sk
b0c47e824d 🔍SNMP bugfix #690 + ⚙ settings saving improvemnts 2024-05-29 17:06:35 +10:00
jokob-sk
e138840ecf Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-05-29 13:47:03 +10:00
jokob-sk
43e2e7c11f 📚 docs + ⚙settings saving improvemnts 2024-05-29 13:46:37 +10:00
github-actions[bot]
3118f4324a [🤖Automation] Update README with sponsors information 2024-05-28 11:53:44 +00:00
vladaurosh
667b3b6262 Update base docker image to alpine 3.20
Updating base docker image to alpine 3.20
2024-05-28 01:42:50 +01:00
github-actions[bot]
5cd75b96be [🤖Automation] Update README with sponsors information 2024-05-27 11:53:46 +00:00
jokob-sk
6be2ba967e Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-05-27 19:25:49 +10:00
jokob-sk
bef7f87706 📚 file permissions guide #652 2024-05-27 19:25:24 +10:00
github-actions[bot]
57c0d590be [🤖Automation] Update README with sponsors information 2024-05-26 11:53:47 +00:00
jokob-sk
0cf525bd30 💠down_reconnected support v0.75 #611 2024-05-26 16:52:07 +10:00
jokob-sk
b3f81967c6 💠down_reconnected support v0.7 #611 2024-05-26 15:50:26 +10:00
jokob-sk
df071c0835 🆕 db locked icon #685 2024-05-26 15:28:37 +10:00
jokob-sk
2c7d71d13c 💠down_reconnected support v0.6 #611 2024-05-26 13:54:49 +10:00
jokob-sk
f9b16081d6 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-05-25 23:29:22 +10:00
jokob-sk
3102b8a76e 💠down_reconnected support v0.5 #611 2024-05-25 23:28:48 +10:00
github-actions[bot]
b42cf07b21 [🤖Automation] Update README with sponsors information 2024-05-25 11:53:55 +00:00
jokob-sk
2f4423481d Retry support for INTRNT #667 2024-05-25 12:18:59 +10:00
jokob-sk
fb88f5f722 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-05-25 09:54:33 +10:00
jokob-sk
23ef5759f6 Removed Pholus Dependency in DBCLNP #681 2024-05-25 09:54:23 +10:00
github-actions[bot]
0781c77ce2 [🤖Automation] Update README with sponsors information 2024-05-24 11:53:40 +00:00
jokob-sk
10b3e91b8a Loading plugins v 0.6 🔌 + Show only Down #676 + Docs📚 + Settings page work ⚙ 2024-05-24 08:01:48 +10:00
github-actions[bot]
5e45bf6d4a [🤖Automation] Update README with sponsors information 2024-05-23 11:53:51 +00:00
Hosted Weblate
21ae76e77e Merge branch 'origin/main' into Weblate. 2024-05-22 23:02:30 +02:00
SirAfino
a6b6617fcd Translated using Weblate (Italian)
Currently translated at 97.7% (655 of 670 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-05-22 23:02:06 +02:00
github-actions[bot]
edd81527d5 [🤖Automation] Update README with sponsors information 2024-05-22 11:53:55 +00:00
github-actions[bot]
395d0a7723 [🤖Automation] Update README with sponsors information 2024-05-21 11:53:41 +00:00
github-actions[bot]
e4f2e1ac4c [🤖Automation] Update README with sponsors information 2024-05-20 11:53:42 +00:00
jokob-sk
a04bef9b31 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-05-20 08:14:58 +10:00
jokob-sk
03f82d9510 Loading plugins v 0.5 🔌 2024-05-20 08:14:36 +10:00
Hosted Weblate
8c1a7fb828 Merge branch 'origin/main' into Weblate. 2024-05-19 21:01:57 +02:00
gallegonovato
67651acfc3 Translated using Weblate (Spanish)
Currently translated at 100.0% (670 of 670 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-05-19 21:01:54 +02:00
github-actions[bot]
da1090dd7a [🤖Automation] Update README with sponsors information 2024-05-19 11:53:35 +00:00
github-actions[bot]
f4960f5793 [🤖Automation] Update README with sponsors information 2024-05-18 11:53:47 +00:00
jokob-sk
924ac72401 Loading plugins v 0.36 🔌 2024-05-18 11:27:35 +10:00
jokob-sk
862b1e7a08 Weblate 2024-05-18 11:21:54 +10:00
jokob-sk
6f4ae1d29f Loading plugins v 0.35 🔌 2024-05-18 11:16:28 +10:00
jokob-sk
315921873d Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-05-18 10:14:15 +10:00
jokob-sk
c5211eb8ed Loading plugins v 0.31 🔌 2024-05-18 10:14:07 +10:00
SirAfino
572aaacf20 Translated using Weblate (Italian)
Currently translated at 91.0% (608 of 668 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-05-18 00:01:54 +02:00
github-actions[bot]
960d74640d [🤖Automation] Update README with sponsors information 2024-05-17 11:54:00 +00:00
jokob-sk
e01125c5cb Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-05-16 22:51:46 +10:00
jokob-sk
01d96cb60b Loading plugins v 0.3 🔌 2024-05-16 22:51:28 +10:00
github-actions[bot]
3519e4b680 [🤖Automation] Update README with sponsors information 2024-05-16 11:53:38 +00:00
jokob-sk
ecc6eb5c5d Loading plugins v 0.2 🔌 2024-05-16 21:46:02 +10:00
jokob-sk
f97339020c template 2024-05-16 20:59:38 +10:00
jokob-sk
d38691e131 template 2024-05-16 20:57:22 +10:00
Hosted Weblate
4cf02c451b Merge branch 'origin/main' into Weblate. 2024-05-16 08:02:12 +00:00
SirAfino
03713aae11 Translated using Weblate (Italian)
Currently translated at 83.9% (561 of 668 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-05-16 08:02:06 +00:00
Safeguard
f5770f4cce Translated using Weblate (Russian)
Currently translated at 99.8% (667 of 668 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-05-16 08:02:05 +00:00
github-actions[bot]
155cf61e2b [🤖Automation] Update README with sponsors information 2024-05-15 11:54:03 +00:00
github-actions[bot]
1bca1095a8 [🤖Automation] Update README with sponsors information 2024-05-14 11:53:56 +00:00
github-actions[bot]
0064955533 [🤖Automation] Update README with sponsors information 2024-05-13 11:54:00 +00:00
Hosted Weblate
9ac82c9269 Merge branch 'origin/main' into Weblate. 2024-05-13 02:08:41 +02:00
Cesar Osvaldo Müller
aeb90e8143 Translated using Weblate (Portuguese (Brazil))
Currently translated at 10.6% (71 of 668 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/pt_BR/
2024-05-13 02:02:28 +02:00
SirAfino
8d57c53d0b Translated using Weblate (Italian)
Currently translated at 82.0% (548 of 668 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-05-13 02:02:27 +02:00
jokob-sk
7ab503efd2 Update feature_request.yml 2024-05-13 08:26:14 +10:00
github-actions[bot]
fdf9626498 [🤖Automation] Update README with sponsors information 2024-05-12 11:53:49 +00:00
github-actions[bot]
1ddbeb751e [🤖Automation] Update README with sponsors information 2024-05-11 11:53:35 +00:00
jokob-sk
0ad3d33402 Update feature_request.yml 2024-05-11 12:39:42 +10:00
jokob-sk
035ec80f3d Loading plugins v 0.1 🔌 2024-05-11 12:37:32 +10:00
jokob-sk
36af285c0a Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-05-11 09:00:28 +10:00
jokob-sk
c4fc968d2a MQTT device_tracker sensor fix #664 🚑 2024-05-11 09:00:22 +10:00
github-actions[bot]
563343b94d [🤖Automation] Update README with sponsors information 2024-05-10 11:53:42 +00:00
Hosted Weblate
2d8a5d283f Merge branch 'origin/main' into Weblate. 2024-05-10 09:33:27 +02:00
Szymon Niewczas
13efc0a29c Translated using Weblate (Polish)
Currently translated at 56.7% (379 of 668 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/pl/
2024-05-10 09:31:20 +02:00
Mehdi
8eef4b6390 Translated using Weblate (French)
Currently translated at 45.2% (302 of 668 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-05-10 09:31:19 +02:00
github-actions[bot]
3c633b4b71 [🤖Automation] Update README with sponsors information 2024-05-09 11:53:51 +00:00
jokob-sk
645a4e68f0 Multi-edit urlencode #660 2024-05-09 07:53:43 +10:00
github-actions[bot]
9007658e40 [🤖Automation] Update README with sponsors information 2024-05-08 11:53:51 +00:00
jokob-sk
316cb9ca57 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-05-08 07:49:33 +10:00
jokob-sk
bfddccddec Work on settings #655 🔃 2024-05-08 07:49:28 +10:00
github-actions[bot]
77f46417a9 [🤖Automation] Update README with sponsors information 2024-05-07 11:53:46 +00:00
jokob-sk
d5c0f898df Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-05-07 08:03:46 +10:00
jokob-sk
28e403356b Work on settings styles & #618 2024-05-07 08:03:41 +10:00
github-actions[bot]
07546bc7df [🤖Automation] Update README with sponsors information 2024-05-06 11:53:38 +00:00
github-actions[bot]
bf054dfc3f [🤖Automation] Update README with sponsors information 2024-05-05 11:53:43 +00:00
jokob-sk
78b3228159 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-05-05 09:06:42 +10:00
jokob-sk
6fc73aa2eb MQTT config update 2024-05-05 09:06:36 +10:00
github-actions[bot]
9537de7361 [🤖Automation] Update README with sponsors information 2024-05-04 11:53:33 +00:00
Hosted Weblate
059cc4a162 Merge branch 'origin/main' into Weblate. 2024-05-04 04:07:15 +02:00
onebest1
72d7996315 Translated using Weblate (Chinese (Simplified))
Currently translated at 8.3% (56 of 668 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/zh_Hans/
2024-05-04 04:07:13 +02:00
Massimo Pissarello
ecbbcba6aa Translated using Weblate (Italian)
Currently translated at 78.4% (524 of 668 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-05-04 04:07:12 +02:00
jokob-sk
427c0f9d80 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-05-04 11:17:59 +10:00
jokob-sk
1524bbd23c MQTT docs and presence sensor type #664 2024-05-04 11:17:55 +10:00
github-actions[bot]
ea080dde8c [🤖Automation] Update README with sponsors information 2024-05-03 11:54:06 +00:00
jokob-sk
45be8a0dbb Chinese 🌏 2024-05-03 08:18:56 +10:00
Hosted Weblate
a0166f58e9 Merge branch 'origin/main' into Weblate. 2024-05-03 00:14:43 +02:00
SirAfino
296525f390 Translated using Weblate (Italian)
Currently translated at 77.2% (516 of 668 strings)

Co-authored-by: SirAfino <serafino.9966@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
Translation: NetAlertX/core
2024-05-03 00:14:40 +02:00
jokob-sk
9040591ae7 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-05-03 08:10:59 +10:00
jokob-sk
95fd7435d2 Refreshing the settings page cache #663 2024-05-03 08:10:39 +10:00
Hosted Weblate
0a58cca5c3 Merge branch 'origin/main' into Weblate. 2024-05-02 20:07:36 +02:00
Massimo Pissarello
71686aeab5 Translated using Weblate (Italian)
Currently translated at 70.6% (472 of 668 strings)

Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
Translation: NetAlertX/core
2024-05-02 20:07:28 +02:00
Safeguard
152729724c Translated using Weblate (Russian)
Currently translated at 99.7% (666 of 668 strings)

Co-authored-by: Safeguard <yo-safeguard@yandex.ru>
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
Translation: NetAlertX/core
2024-05-02 20:07:26 +02:00
github-actions[bot]
e347454802 [🤖Automation] Update README with sponsors information 2024-05-02 11:53:37 +00:00
jokob-sk
0b6071a272 dnsmasq dhcp.leases v0.1 #661 2024-05-02 20:57:55 +10:00
jokob-sk
5d761e8687 Vendors update work v0.1 #618 2024-05-02 20:33:19 +10:00
jokob-sk
9435cd3081 Vendors update work #618 2024-05-02 20:18:24 +10:00
jokob-sk
ef725103aa Loading cleanup in Maintenance + case insensitive vendor MAC matching #618 🔄 2024-05-02 08:39:16 +10:00
jokob-sk
7568071ce8 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-05-02 07:24:50 +10:00
jokob-sk
96f90fa5c9 Startup helper fix 2024-05-02 07:24:10 +10:00
Massimo Pissarello
323ca5a8a9 Translated using Weblate (Italian)
Currently translated at 68.5% (458 of 668 strings)

Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
Translation: NetAlertX/core
2024-05-01 19:21:14 +02:00
SirAfino
09549b1922 Translated using Weblate (Italian)
Currently translated at 68.5% (458 of 668 strings)

Co-authored-by: SirAfino <serafino.9966@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
Translation: NetAlertX/core
2024-05-01 19:21:13 +02:00
Massimo Pissarello
09339b9b6d Translated using Weblate (Italian)
Currently translated at 68.5% (458 of 668 strings)

Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
Translation: NetAlertX/core
2024-05-01 19:21:13 +02:00
github-actions[bot]
1fb46add24 [🤖Automation] Update README with sponsors information 2024-05-01 11:53:55 +00:00
jokob-sk
1dcca191d9 Loading cleanup #660 🔄 2024-05-01 20:47:54 +10:00
jokob-sk
584fdb7734 Add version to JS files to flush cache #659 2024-05-01 18:25:48 +10:00
jokob-sk
525b05db5a Merge pull request #650 from ulrichwisser/main
cleanDeviceName rewritten to remove all _ labels and remove search list and local domain
2024-05-01 08:25:25 +10:00
jokob-sk
5d8561818f Merge branch 'main' into main 2024-05-01 08:24:43 +10:00
jokob-sk
d3d019b487 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-05-01 08:12:14 +10:00
jokob-sk
2fbbf220fb Sanity check before settings are saved #655 2024-05-01 08:11:58 +10:00
Hosted Weblate
dbfb49d03d Merge branch 'origin/main' into Weblate. 2024-04-30 22:07:29 +02:00
Szymon Niewczas
c52a615720 Translated using Weblate (Polish)
Currently translated at 53.2% (356 of 668 strings)

Co-authored-by: Szymon Niewczas <szymon.other@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/pialert/core/pl/
Translation: NetAlertX/core
2024-04-30 22:07:23 +02:00
SirAfino
51365f82b8 Translated using Weblate (Italian)
Currently translated at 60.3% (403 of 668 strings)

Co-authored-by: SirAfino <serafino.9966@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
Translation: NetAlertX/core
2024-04-30 22:07:21 +02:00
jokob-sk
0e02b1beec Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-04-30 23:37:25 +10:00
jokob-sk
cc9b08ad04 NMAPDEV plugin work v0.7 #645 🆕🔎 2024-04-30 23:37:05 +10:00
Ulrich Wisser
aad1bcede3 Merge branch 'jokob-sk:main' into main 2024-04-30 14:47:01 +02:00
Ulrich Wisser
aa28fe2b0e - update dependencies for docker and debian install
- follow project naming guidelines
2024-04-30 14:44:53 +02:00
github-actions[bot]
c9a297b72a [🤖Automation] Update README with sponsors information 2024-04-30 11:53:53 +00:00
Hosted Weblate
e0cff6b81a Merge branch 'origin/main' into Weblate. 2024-04-29 16:07:13 +02:00
gallegonovato
6262f874a3 Translated using Weblate (Spanish)
Currently translated at 100.0% (668 of 668 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-04-29 16:07:08 +02:00
github-actions[bot]
eb81d0a1e3 [🤖Automation] Update README with sponsors information 2024-04-29 11:53:50 +00:00
github-actions[bot]
f4d13f3fb6 [🤖Automation] Update README with sponsors information 2024-04-28 11:53:47 +00:00
Hosted Weblate
1dbfa7dc0a Merge branch 'origin/main' into Weblate. 2024-04-28 06:29:18 +02:00
Massimo Pissarello
c6fbf0dd0e Translated using Weblate (Italian)
Currently translated at 48.8% (326 of 668 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-04-28 06:29:15 +02:00
jokob-sk
ab0d4fe259 NMAPDEV plugin work v0.6 #645 🆕🔎 2024-04-28 10:47:31 +10:00
jokob-sk
ecf6c1848d NMAPDEV plugin work v0.6 #645 🆕🔎 2024-04-28 10:17:02 +10:00
github-actions[bot]
8647bf2699 [🤖Automation] Update README with sponsors information 2024-04-27 11:53:42 +00:00
jokob-sk
87b114604c NMAPDEV plugin work v0.6 #645 🆕🔎 2024-04-27 10:30:40 +10:00
jokob-sk
fbbe4dc64b Notification docs 📚 2024-04-27 09:09:32 +10:00
jokob-sk
1a78810691 Notification docs 📚 2024-04-27 09:04:14 +10:00
jokob-sk
f45717cee4 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-04-27 08:21:41 +10:00
jokob-sk
31e358280c Weblate 2024-04-27 08:21:36 +10:00
gallegonovato
444333d44f Translated using Weblate (Spanish)
Currently translated at 100.0% (664 of 664 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-04-26 22:07:13 +02:00
github-actions[bot]
4d85c77738 [🤖Automation] Update README with sponsors information 2024-04-26 11:53:52 +00:00
jokob-sk
d26d6c8b0b Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-04-26 07:37:33 +10:00
jokob-sk
944619af81 Settings filter v0.4 + docs for #653 🔍 2024-04-26 07:37:19 +10:00
github-actions[bot]
1332b73a92 [🤖Automation] Update README with sponsors information 2024-04-25 11:53:58 +00:00
jokob-sk
c11deeb57f Settings filter v0.3 🔍 2024-04-25 18:05:16 +10:00
jokob-sk
294518b146 Settings filter v0.2 🔍 2024-04-25 14:14:19 +10:00
jokob-sk
b5be221aec Settings filter 🔍 2024-04-25 13:09:53 +10:00
jokob-sk
8ab3945871 Modals refactor, autofocus support, ESC/ENTER support⌨ 2024-04-25 12:30:05 +10:00
jokob-sk
73732a7d0c Remove all/last on Settings 2024-04-25 10:22:54 +10:00
jokob-sk
5599bbdf31 1x📝|2x🚮 click list edit options in Settings 2024-04-25 10:00:14 +10:00
jokob-sk
2a085f5703 Inline edit list item data in Settings 🚑 2024-04-25 09:04:32 +10:00
Hosted Weblate
2943da7c07 Merge branch 'origin/main' into Weblate. 2024-04-25 00:51:24 +02:00
SirAfino
e1e4a1da07 Translated using Weblate (Italian)
Currently translated at 48.5% (321 of 661 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-04-25 00:51:21 +02:00
Ulrich Wisser
8bb9328201 make new cleanDeviceName configurable, fix debug logging 2024-04-24 18:02:33 +02:00
jokob-sk
9d54273947 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-04-24 23:19:32 +10:00
jokob-sk
141ba5d6c1 NMAPDEV plugin work v0.5 #645 🆕🔎 2024-04-24 23:19:23 +10:00
github-actions[bot]
ebd514e278 [🤖Automation] Update README with sponsors information 2024-04-24 11:53:50 +00:00
Anonymous
aa1468af34 Translated using Weblate (Russian)
Currently translated at 99.3% (657 of 661 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-04-23 23:39:57 +02:00
Anonymous
003732c20d Translated using Weblate (Spanish)
Currently translated at 99.5% (658 of 661 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-04-23 23:39:57 +02:00
Anonymous
d762e2b6ae Translated using Weblate (German)
Currently translated at 94.8% (627 of 661 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/de/
2024-04-23 23:39:56 +02:00
jokob-sk
c7cb69c914 Weblate 2024-04-24 07:38:08 +10:00
Szymon Niewczas
663e5539c8 Translated using Weblate (Polish)
Currently translated at 48.8% (322 of 659 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/pl/
2024-04-23 17:07:28 +02:00
SirAfino
52b130d812 Translated using Weblate (Italian)
Currently translated at 42.6% (281 of 659 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-04-23 17:07:24 +02:00
Ulrich Wisser
788f23b955 cleanDeviceName rewritten to remove all _ labels and remove search list and local domain 2024-04-23 15:28:53 +02:00
jokob-sk
047f6a1ed2 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-04-23 22:57:43 +10:00
jokob-sk
a8fad6ac74 Double-click to remove in Settings lists 2024-04-23 22:57:24 +10:00
github-actions[bot]
3ed406021c [🤖Automation] Update README with sponsors information 2024-04-23 11:53:45 +00:00
jokob-sk
f600398353 Seelct all / Remove all in multi-edit 2024-04-23 20:15:20 +10:00
jokob-sk
3af04246d0 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-04-22 23:48:09 +10:00
jokob-sk
95d7856978 NMAPDEV plugin work #645 🆕🔎 2024-04-22 23:47:50 +10:00
github-actions[bot]
fd10379c7f [🤖Automation] Update README with sponsors information 2024-04-22 11:53:50 +00:00
Hosted Weblate
fe776a1443 Merge branch 'origin/main' into Weblate. 2024-04-22 13:07:30 +02:00
Massimo Pissarello
81842b8521 Translated using Weblate (Italian)
Currently translated at 26.4% (174 of 659 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-04-22 13:07:22 +02:00
SirAfino
dc7ff4c94d Translated using Weblate (Italian)
Currently translated at 26.4% (174 of 659 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-04-22 13:07:21 +02:00
gallegonovato
c13df2e0c8 Translated using Weblate (Spanish)
Currently translated at 100.0% (659 of 659 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-04-22 13:07:19 +02:00
jokob-sk
0846c3914a UI Settings refresh improvements + remove last button on subnets 2024-04-22 20:43:05 +10:00
jokob-sk
5a2616800f Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-04-22 07:37:36 +10:00
jokob-sk
9cef7848c5 encode special characters when saving device details #644🚑 2024-04-22 07:37:31 +10:00
github-actions[bot]
b14345f390 [🤖Automation] Update README with sponsors information 2024-04-21 11:53:46 +00:00
jokob-sk
b0f1f581dc 🌍 Init empty Polish language 2024-04-21 08:59:15 +10:00
Hosted Weblate
e97a63b814 Merge branch 'origin/main' into Weblate. 2024-04-21 00:53:14 +02:00
SirAfino
45afc4ee1f Translated using Weblate (Italian)
Currently translated at 17.6% (116 of 659 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-04-21 00:53:11 +02:00
Massimo Pissarello
ec0b1d18ca Translated using Weblate (Italian)
Currently translated at 17.6% (116 of 659 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-04-21 00:53:11 +02:00
jokob-sk
07b0cfdd7b Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-04-21 08:26:22 +10:00
jokob-sk
44408c8cfc MQTT new settings 2024-04-21 08:26:13 +10:00
github-actions[bot]
01d3d0523e [🤖Automation] Update README with sponsors information 2024-04-20 11:53:36 +00:00
jokob-sk
436669173b 🌎 Portuguese (Brazil) empty file init 2024-04-20 11:41:35 +10:00
jokob-sk
003fc557cd 🔐PWD work #634 2024-04-20 10:14:22 +10:00
jokob-sk
c1b5a2684b Missed rename 2024-04-19 22:11:56 +10:00
github-actions[bot]
2b6cc1f8c7 [🤖Automation] Update README with sponsors information 2024-04-19 11:53:41 +00:00
Hosted Weblate
820dc023e8 Merge branch 'origin/main' into Weblate. 2024-04-18 18:03:31 +02:00
SirAfino
a0544368fb Translated using Weblate (Italian)
Currently translated at 10.3% (68 of 659 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-04-18 18:03:22 +02:00
Safeguard
f2c6778574 Translated using Weblate (Russian)
Currently translated at 99.8% (658 of 659 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-04-18 18:03:21 +02:00
Antonio Sanchez Castellón
62dffc4ac3 Translated using Weblate (Spanish)
Currently translated at 99.8% (658 of 659 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-04-18 18:03:21 +02:00
gallegonovato
847fefcc46 Translated using Weblate (Spanish)
Currently translated at 99.8% (658 of 659 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-04-18 18:03:21 +02:00
Techsider
47680fc64e Translated using Weblate (German)
Currently translated at 95.2% (628 of 659 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/de/
2024-04-18 18:03:21 +02:00
github-actions[bot]
277cfd3a03 [🤖Automation] Update README with sponsors information 2024-04-18 11:53:59 +00:00
jokob-sk
6ffceee3ca Docs 📚 2024-04-18 08:11:16 +10:00
jokob-sk
fd00db7886 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-04-18 07:32:34 +10:00
jokob-sk
c86aa276b9 Docs 📚 2024-04-18 07:32:26 +10:00
github-actions[bot]
dc36709297 [🤖Automation] Update README with sponsors information 2024-04-17 11:53:58 +00:00
jokob-sk
b63fb6c966 Translated using Weblate (English (United States))
Currently translated at 100.0% (659 of 659 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/en_US/
2024-04-17 13:20:20 +02:00
Anonymous
c570ff1d1c Translated using Weblate (Russian)
Currently translated at 99.2% (654 of 659 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-04-17 11:32:58 +02:00
Anonymous
c462a83c3d Translated using Weblate (Spanish)
Currently translated at 99.2% (654 of 659 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-04-17 11:32:57 +02:00
jokob-sk
81a2f34731 Weblate 2024-04-17 19:32:12 +10:00
jokob-sk
af9ce3bb55 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-04-17 19:20:38 +10:00
jokob-sk
f2593a113b Footer tweaks 2024-04-17 19:20:31 +10:00
Safeguard
4e376aad73 Translated using Weblate (Russian)
Currently translated at 99.6% (655 of 657 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-04-17 06:50:13 +02:00
github-actions[bot]
dbf0e3f777 [🤖Automation] Update README with sponsors information 2024-04-16 11:53:49 +00:00
jokob-sk
a21ac1fab3 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-04-15 22:10:23 +10:00
jokob-sk
796413429b Logo tweaks 2024-04-15 22:10:05 +10:00
github-actions[bot]
27b4349ec8 [🤖Automation] Update README with sponsors information 2024-04-15 11:53:39 +00:00
jokob-sk
a1b025d461 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-04-15 20:51:26 +10:00
jokob-sk
9f1247141e More icons work - default icon fix🔨 2024-04-15 20:51:17 +10:00
github-actions[bot]
72cec47e11 [🤖Automation] Update README with sponsors information 2024-04-14 14:33:42 +00:00
jokob-sk
b55bab964e More icons work - lang fix🔨 2024-04-14 12:39:41 +10:00
jokob-sk
da171f6d3c More icons work - lang🔨 2024-04-14 12:36:28 +10:00
jokob-sk
8e7e437b4c More icons work 🔨 2024-04-14 12:34:14 +10:00
jokob-sk
d75f27c6db Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-04-14 09:52:14 +10:00
jokob-sk
1779da3be0 CSS icon button fix #629 & DB fucntion test 2024-04-14 09:52:00 +10:00
github-actions[bot]
17ab77e78f [🤖Automation] Update README with sponsors information 2024-04-13 11:53:59 +00:00
jokob-sk
ed983279d5 Filter applied on <> arrows #627 2024-04-13 12:58:10 +10:00
jokob-sk
e7ce7513ae IP address not updated when <> used #626 2024-04-13 12:02:10 +10:00
jokob-sk
ae0ba6ed8f Merge pull request #625 from vladaurosh/main
Update Dockerfile with nmap-scripts
2024-04-13 10:12:40 +10:00
vladaurosh
6700565c8b Update Dockerfile
Adding nmap-scripts package to fix https://github.com/jokob-sk/NetAlertX/issues/623
2024-04-13 01:07:02 +01:00
jokob-sk
efeb15de76 CLI small refactor 2024-04-13 09:10:29 +10:00
jokob-sk
30c7035f30 ALWAYS_FRESH_INSTALL account for old dir location 2024-04-13 08:50:41 +10:00
jokob-sk
7fb4db01e7 Weblate 2024-04-13 08:42:01 +10:00
Anonymous
98080fba9f Translated using Weblate (Italian)
Currently translated at 0.1% (1 of 656 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-04-13 00:39:34 +02:00
Safeguard
db3539615f Translated using Weblate (Russian)
Currently translated at 98.7% (648 of 656 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-04-13 00:39:30 +02:00
Anonymous
77bff384b8 Translated using Weblate (Norwegian Bokmål)
Currently translated at 1.6% (11 of 656 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/nb_NO/
2024-04-13 00:39:29 +02:00
Gooseman
a7abd31f77 Translated using Weblate (French)
Currently translated at 45.2% (297 of 656 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-04-13 00:39:13 +02:00
gallegonovato
bc7e3519e1 Translated using Weblate (Spanish)
Currently translated at 99.8% (655 of 656 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-04-13 00:39:12 +02:00
Anonymous
d10c60f569 Translated using Weblate (German)
Currently translated at 87.8% (576 of 656 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/de/
2024-04-13 00:39:12 +02:00
jokob-sk
7b714064bb Moving of report templates 2024-04-13 08:37:00 +10:00
jokob-sk
b977781937 Fresh install fixes 2024-04-13 07:13:09 +10:00
jokob-sk
ee90897208 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-04-13 06:48:49 +10:00
jokob-sk
121178452f Missing app.log init 2024-04-13 06:48:29 +10:00
github-actions[bot]
421d5129ff [🤖Automation] Update README with sponsors information 2024-04-12 11:53:43 +00:00
jokob-sk
8579b010c6 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-04-12 21:32:02 +10:00
jokob-sk
0d20562930 New logo 2024-04-12 21:31:38 +10:00
Hosted Weblate
63b3c4eadb Merge branch 'origin/main' into Weblate. 2024-04-12 11:47:37 +02:00
Anonymous
b2185f48a7 Translated using Weblate (Italian)
Currently translated at 0.1% (1 of 655 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-04-12 11:47:34 +02:00
Anonymous
5b1eecfd7d Translated using Weblate (Norwegian Bokmål)
Currently translated at 1.6% (11 of 655 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/nb_NO/
2024-04-12 11:47:32 +02:00
Gooseman
ccce4f9edf Translated using Weblate (French)
Currently translated at 45.3% (297 of 655 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-04-12 11:47:30 +02:00
jokob-sk
5cb7553ed5 Rename work 🏗 2024-04-12 19:44:29 +10:00
github-actions[bot]
b003df323d [🤖Automation] Update README with sponsors information 2024-04-11 11:53:36 +00:00
Hosted Weblate
eb473cac21 Merge branch 'origin/main' into Weblate. 2024-04-11 12:01:48 +02:00
gallegonovato
6213fe84de Translated using Weblate (Spanish)
Currently translated at 100.0% (655 of 655 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-04-11 12:01:46 +02:00
github-actions[bot]
3e26cf67bb [🤖Automation] Update README with sponsors information 2024-04-10 11:53:49 +00:00
Anonymous
81fef80432 Translated using Weblate (Russian)
Currently translated at 98.7% (647 of 655 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-04-10 11:44:03 +02:00
Anonymous
67c18c16d0 Translated using Weblate (Spanish)
Currently translated at 99.8% (654 of 655 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-04-10 11:44:03 +02:00
Anonymous
5ca85137ac Translated using Weblate (German)
Currently translated at 87.7% (575 of 655 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/de/
2024-04-10 11:44:03 +02:00
github-actions[bot]
f32ebb2557 [🤖Automation] Update README with sponsors information 2024-04-09 11:53:36 +00:00
github-actions[bot]
052ce7362a [🤖Automation] Update README with sponsors information 2024-04-08 11:53:43 +00:00
jokob-sk
6c0de70c76 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-04-08 07:58:32 +10:00
jokob-sk
cacc52cd27 More rename work 2024-04-08 07:57:36 +10:00
github-actions[bot]
db765fe78d [🤖Automation] Update README with sponsors information 2024-04-07 11:53:50 +00:00
jokob-sk
8c023e4cb5 More rename work 2024-04-07 13:43:57 +10:00
jokob-sk
e9cc57a2fc Icons work 2024-04-07 13:32:44 +10:00
jokob-sk
4f04562b67 More rename work 2024-04-07 12:56:32 +10:00
jokob-sk
775a119f32 More rename work 2024-04-07 12:38:17 +10:00
jokob-sk
f06e084336 Intit NetAlertX dockerhub image 2024-04-07 10:27:40 +10:00
Anonymous
4329ff98ac Translated using Weblate (German)
Currently translated at 87.7% (575 of 655 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/de/
2024-04-07 02:00:49 +02:00
jokob-sk
4eae7e1023 Weblate 2024-04-07 09:55:37 +10:00
Anonymous
1bc2fe6cd2 Translated using Weblate (Italian)
Currently translated at 0.1% (1 of 655 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-04-07 01:48:51 +02:00
Safeguard
e0313f5970 Translated using Weblate (Russian)
Currently translated at 98.9% (648 of 655 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-04-07 01:48:50 +02:00
Anonymous
cdca7488fb Translated using Weblate (Norwegian Bokmål)
Currently translated at 1.6% (11 of 655 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/nb_NO/
2024-04-07 01:48:48 +02:00
Anonymous
f4068165d0 Translated using Weblate (German)
Currently translated at 88.5% (580 of 655 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/de/
2024-04-07 01:48:25 +02:00
jokob-sk
7653ddce63 PiAlert -> NetAlertX ✍ 2024-04-07 09:44:37 +10:00
Hosted Weblate
77eb472416 Merge branch 'origin/main' into Weblate. 2024-04-07 00:14:54 +02:00
Gooseman
1369017216 Translated using Weblate (French)
Currently translated at 45.3% (297 of 655 strings)

Translation: PiAlert/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-04-07 00:14:52 +02:00
gallegonovato
ad294cd612 Translated using Weblate (Spanish)
Currently translated at 100.0% (655 of 655 strings)

Translation: PiAlert/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-04-07 00:14:52 +02:00
Jokob-sk
3e0b980548 Settings tuning 2024-04-07 07:38:48 +10:00
Jokob-sk
116806b68b Merge branch 'main' of https://github.com/jokob-sk/Pi.Alert 2024-04-07 07:04:31 +10:00
Jokob-sk
8155af8813 Docs 2024-04-07 07:04:27 +10:00
jokob-sk
1720df4036 Merge pull request #619 from wintergew/design-improvements
Design improvements - thanks a lot @wintergew 🙏
2024-04-07 07:00:20 +10:00
Emre Varci
13f5e68eba Replace fa-toggle's with solid and regular circles in the settings menu to improve design language 2024-04-06 21:03:08 +03:00
Emre Varci
7147f0691d Change card titles in the settings menu to white to increase accessibility 2024-04-06 21:02:18 +03:00
github-actions[bot]
70fcd90f8b [🤖Automation] Update README with sponsors information 2024-04-06 11:53:42 +00:00
github-actions[bot]
aec0002837 [🤖Automation] Update README with sponsors information 2024-04-05 11:54:23 +00:00
Jokob-sk
980e83e039 Icons work - docs 📚 #550 2024-04-05 20:09:05 +11:00
Jokob-sk
1f735e9ed5 Icons work #550 + Italian language 2024-04-05 19:20:43 +11:00
github-actions[bot]
f56d7c686d [🤖Automation] Update README with sponsors information 2024-04-04 11:54:03 +00:00
Jokob-sk
e51f2d06d0 UI auto-refresh #614 2024-04-04 07:41:25 +11:00
Jokob-sk
cbc9351961 Merge branch 'main' of https://github.com/jokob-sk/Pi.Alert 2024-04-03 23:02:04 +11:00
Jokob-sk
1367649554 UI auto-refresh #614 Schedule for undiscoverable devices to mark ONLINE work #617 2024-04-03 23:01:36 +11:00
github-actions[bot]
b4143607a1 [🤖Automation] Update README with sponsors information 2024-04-03 11:53:40 +00:00
github-actions[bot]
69450c5885 [🤖Automation] Update README with sponsors information 2024-04-02 11:53:39 +00:00
github-actions[bot]
cc19a6e3c0 [🤖Automation] Update README with sponsors information 2024-04-01 11:53:44 +00:00
Jokob-sk
af8c053ded UI hide Devices sections work #612 2024-04-01 12:26:28 +11:00
Jokob-sk
a672070ff0 UI show sections work + icons work 2024-04-01 11:48:17 +11:00
github-actions[bot]
f85466e1d6 [🤖Automation] Update README with sponsors information 2024-03-31 11:54:01 +00:00
github-actions[bot]
bb14627bbe [🤖Automation] Update README with sponsors information 2024-03-30 11:53:38 +00:00
github-actions[bot]
8ebe696a8d [🤖Automation] Update README with sponsors information 2024-03-29 11:53:44 +00:00
github-actions[bot]
2c5d95ba6d [🤖Automation] Update README with sponsors information 2024-03-28 11:53:53 +00:00
github-actions[bot]
ee6430e34e [🤖Automation] Update README with sponsors information 2024-03-27 11:53:55 +00:00
Hosted Weblate
f44ec2ce51 Merge branch 'origin/main' into Weblate. 2024-03-26 15:02:01 +01:00
Safeguard
962f355d1c Translated using Weblate (Russian)
Currently translated at 100.0% (648 of 648 strings)

Translation: PiAlert/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-03-26 15:01:57 +01:00
github-actions[bot]
f5b62a20dd [🤖Automation] Update README with sponsors information 2024-03-26 11:54:04 +00:00
github-actions[bot]
f09ac5bc86 [🤖Automation] Update README with sponsors information 2024-03-25 11:53:34 +00:00
jokob-sk
2beef711a4 Merge pull request #605 from ameer1234567890/patch-1
Removed duplicate manifest tag - thank you 🙏 @ameer1234567890
2024-03-24 20:21:24 +00:00
github-actions[bot]
990ace45d1 [🤖Automation] Update README with sponsors information 2024-03-24 11:54:00 +00:00
Ameer Dawood
28e0bc8403 Removed duplicate manifest tag 2024-03-24 16:52:14 +05:00
Jokob-sk
d7af5d6611 First load optimization 🔄 2024-03-24 18:43:06 +11:00
Jokob-sk
634e6a7499 Merge branch 'main' of https://github.com/jokob-sk/Pi.Alert 2024-03-24 10:38:18 +11:00
Jokob-sk
046022e2ea ngx prep ⏭ 2024-03-24 10:38:02 +11:00
github-actions[bot]
8d63c6b1ad [🤖Automation] Update README with sponsors information 2024-03-23 11:53:50 +00:00
Hosted Weblate
1d3eb50c01 Merge branch 'origin/main' into Weblate. 2024-03-23 11:02:04 +01:00
Safeguard
6588fc52cb Translated using Weblate (Russian)
Currently translated at 86.4% (560 of 648 strings)

Translation: PiAlert/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-03-23 11:02:01 +01:00
Jokob-sk
7f3938715c First-time load optimization 🔄 2024-03-23 13:04:08 +11:00
Jokob-sk
fc554dcbcb Cleanup 🧹 2024-03-23 12:31:53 +11:00
Jokob-sk
cb324890c8 DevDetails refactor 2024-03-23 09:56:53 +11:00
Jokob-sk
2336befcc1 Merge branch 'main' of https://github.com/jokob-sk/Pi.Alert 2024-03-22 23:06:08 +11:00
Jokob-sk
bb2accc194 DevDetails refactor 2024-03-22 23:05:52 +11:00
github-actions[bot]
67f3c6dea7 [🤖Automation] Update README with sponsors information 2024-03-22 11:53:51 +00:00
Jokob-sk
f9a999c4d0 tz work on #599 2024-03-22 12:38:11 +11:00
Jokob-sk
8d4d985fba path debug output #593, docs #598, Unassign network node #601 2024-03-22 11:37:17 +11:00
jokob-sk
63fc716359 Merge pull request #600 from vladaurosh/main
Improve chmod in setup.sh - thanks to @vladaurosh 🙏
2024-03-21 22:18:24 +00:00
vladaurosh
ff73b3e2c7 Update setup.sh
Reverting back one chmod command
2024-03-21 20:21:29 +00:00
github-actions[bot]
e7b70cc104 [🤖Automation] Update README with sponsors information 2024-03-21 11:53:40 +00:00
vladaurosh
7c084f31d1 Improve chmod in setup.sh 2024-03-21 02:03:57 +00:00
Jokob-sk
9b1cf13924 path debug 2024-03-21 10:03:46 +11:00
Jokob-sk
bb83b4b8bd removal of unnecessary env variables 2024-03-21 08:54:08 +11:00
github-actions[bot]
7d18dd546e [🤖Automation] Update README with sponsors information 2024-03-20 11:53:49 +00:00
Jokob-sk
5584512bcc pytz debug #596 2024-03-20 08:16:12 +11:00
Jokob-sk
de5e120042 roll-back of #593 2024-03-20 07:24:08 +11:00
Jokob-sk
d72812d280 Merge branch 'main' of https://github.com/jokob-sk/Pi.Alert 2024-03-19 23:06:27 +11:00
Jokob-sk
ea3871c69b font-awesome work 🩹 2024-03-19 23:06:08 +11:00
github-actions[bot]
220b14e261 [🤖Automation] Update README with sponsors information 2024-03-19 11:53:39 +00:00
Jokob-sk
27a3b9f6c9 WTZ bug #593 2024-03-19 17:09:54 +11:00
277 changed files with 21042 additions and 14964 deletions

View File

@@ -16,5 +16,4 @@ CONTRIBUTING
FUNDING.yml
config/.gitignore
db/.gitignore
pialert/README.md
pialert/README_ES.md

2
.env
View File

@@ -7,8 +7,6 @@ LOGS_LOCATION=/path/to/docker_logs
#ENVIRONMENT VARIABLES
TZ=Europe/Paris
HOST_USER_ID=1000
HOST_USER_GID=1000
PORT=20211
#DEVELOPMENT VARIABLES

View File

@@ -1,5 +1,5 @@
name: Feature Request
description: 'Suggest an idea for PiAlert'
description: 'Suggest an idea for NetAlertX'
labels: ['Feature request']
body:
- type: checkboxes
@@ -9,6 +9,20 @@ body:
options:
- label: I have searched the existing open and closed issues
required: true
- type: checkboxes
attributes:
label: Am I willing to test this? 🧪
description: I rely on the community to test unreleased features. If you are requesting a feature, please be willing to test it within 48h of test request. Otherwise, the feature might be pulled from the code base.
options:
- label: I will do my best to test this feature on the `netlertx-dev` image when requested within 48h and report bugs to help deliver a great user experience for everyone and not to break existing installations.
required: true
- type: checkboxes
attributes:
label: Can I help implement this? 👩‍💻👨‍💻
description: The maintainer will provide guidance and help. The implementer will read the PR guidelines https://github.com/jokob-sk/NetAlertX/tree/main/docs#-pull-requests-prs
options:
- label: "Yes"
- label: "No"
- type: textarea
attributes:
label: Is your feature request related to a problem? Please describe
@@ -35,4 +49,4 @@ body:
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations:
required: true
required: true

View File

@@ -7,7 +7,7 @@ body:
label: Is there an existing issue for this?
description: Please search to see if an open or closed issue already exists for the bug you encountered.
options:
- label: I have searched the existing open and closed issues and I checked the docs https://github.com/jokob-sk/Pi.Alert/tree/main/docs
- label: I have searched the existing open and closed issues and I checked the docs https://github.com/jokob-sk/NetAlertX/tree/main/docs
required: true
- type: textarea
attributes:
@@ -34,9 +34,9 @@ body:
required: false
- type: textarea
attributes:
label: pialert.conf
label: app.conf
description: |
Paste your `pialert.conf` (remove personal info)
Paste your `app.conf` (remove personal info)
render: python
validations:
required: false
@@ -58,13 +58,13 @@ body:
required: true
- type: textarea
attributes:
label: pialert.log
label: app.log
description: |
Logs with debug enabled (https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEBUG_TIPS.md) ⚠
Logs with debug enabled (https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEBUG_TIPS.md) ⚠
***Generally speaking, all bug reports should have logs provided.***
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
Additionally, any additional info? Screenshots? References? Anything that will give us more context about the issue you are encountering!
You can use `tail -100 /home/pi/pialert/front/log/pialert.log` in teh container if you have troubles getting to the log files.
You can use `tail -100 /app/front/log/app.log` in the container if you have troubles getting to the log files.
validations:
required: false
- type: checkboxes

View File

@@ -4,8 +4,8 @@ on:
workflow_dispatch: # manual option
schedule:
- cron: '15 22 * * 1' # every Monday 10.15pm UTC (~11.15am Tuesday NZT)
# schedule:
# - cron: '15 22 * * 1' # every Monday 10.15pm UTC (~11.15am Tuesday NZT)
jobs:
@@ -19,7 +19,7 @@ jobs:
- uses: actions/delete-package-versions@v4
with:
package-name: pi.alert
package-name: netalertx
package-type: container
min-versions-to-keep: 0
delete-only-untagged-versions: true

View File

@@ -20,7 +20,7 @@ jobs:
packages: write
if: >
contains(github.event.head_commit.message, 'PUSHPROD') != 'True' &&
github.repository == 'jokob-sk/Pi.Alert'
github.repository == 'jokob-sk/NetAlertX'
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -49,6 +49,7 @@ jobs:
# list of Docker images to use as base name for tags
images: |
jokobsk/pi.alert_dev
jokobsk/netalertx-dev
# generate Docker tags based on the following events/attributes
tags: |
type=raw,value=latest
@@ -87,5 +88,5 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
# # ⚠ disable cache if build is failing to download debian packages
# cache-from: type=registry,ref=ghcr.io/jokob-sk/pi.alert:buildcache
# cache-to: type=registry,ref=ghcr.io/jokob-sk/pi.alert:buildcache,mode=max
# cache-from: type=registry,ref=ghcr.io/jokob-sk/netalertx:buildcache
# cache-to: type=registry,ref=ghcr.io/jokob-sk/netalertx:buildcache,mode=max

View File

@@ -49,6 +49,7 @@ jobs:
# list of Docker images to use as base name for tags
images: |
jokobsk/pi.alert
jokobsk/netalertx
# generate Docker tags based on the following events/attributes
tags: |
type=semver,pattern={{version}},value=${{ inputs.version }}
@@ -81,5 +82,5 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
# # ⚠ disable cache if build is failing to download debian packages
# cache-from: type=registry,ref=ghcr.io/jokob-sk/pi.alert:buildcache
# cache-to: type=registry,ref=ghcr.io/jokob-sk/pi.alert:buildcache,mode=max
# cache-from: type=registry,ref=ghcr.io/jokob-sk/netalertx:buildcache
# cache-to: type=registry,ref=ghcr.io/jokob-sk/netalertx:buildcache,mode=max

2
.gitignore vendored
View File

@@ -2,8 +2,10 @@
.DS_Store
config/*
config/pialert.conf
config/app.conf
db/*
db/pialert.db
db/app.db
front/log/*
front/api/*
**/plugins/**/*.log

View File

@@ -6,8 +6,8 @@ The issue tracker is the preferred channel for bug reports, features requests an
Before submitting a new issue please spend a couple of minutes on research:
* Check [🛑 Common issues](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEBUG_TIPS.md#common-issues)
* Check [💡 Closed issues](https://github.com/jokob-sk/Pi.Alert/issues?q=is%3Aissue+is%3Aclosed) if a similar issue was solved in the past.
* Check [🛑 Common issues](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEBUG_TIPS.md#common-issues)
* Check [💡 Closed issues](https://github.com/jokob-sk/NetAlertX/issues?q=is%3Aissue+is%3Aclosed) if a similar issue was solved in the past.
## Pull-requests (PRs)

View File

@@ -1,25 +1,29 @@
FROM alpine:3.19 as builder
FROM alpine:3.20 as builder
ARG INSTALL_DIR=/app
ARG INSTALL_DIR=/home/pi
ENV PYTHONUNBUFFERED 1
RUN apk add --no-cache bash python3 \
# Install build dependencies
RUN apk add --no-cache bash python3 python3-dev gcc musl-dev libffi-dev openssl-dev \
&& python -m venv /opt/venv
# Enable venv
ENV PATH="/opt/venv/bin:$PATH"
COPY . ${INSTALL_DIR}/pialert/
COPY . ${INSTALL_DIR}/
RUN pip install requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet \
RUN pip install pycryptodome requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap dnspython \
&& bash -c "find ${INSTALL_DIR} -type d -exec chmod 750 {} \;" \
&& bash -c "find ${INSTALL_DIR} -type f -exec chmod 640 {} \;" \
&& bash -c "find ${INSTALL_DIR} -type f \( -name '*.sh' -o -name '*.py' -o -name 'pialert-cli' -o -name 'speedtest-cli' \) -exec chmod 750 {} \;"
&& bash -c "find ${INSTALL_DIR} -type f \( -name '*.sh' -o -name '*.py' -o -name 'speedtest-cli' \) -exec chmod 750 {} \;"
# second stage
FROM alpine:3.19 as runner
FROM alpine:3.20 as runner
ARG INSTALL_DIR=/home/pi
ARG INSTALL_DIR=/app
COPY --from=builder /opt/venv /opt/venv
@@ -35,17 +39,17 @@ ENV S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0
# ❗ IMPORTANT - if you modify this file modify the /install/install_dependecies.sh file as well ❗
RUN apk update --no-cache \
&& apk add --no-cache bash zip lsblk gettext-envsubst sudo mtr s6-overlay \
&& apk add --no-cache curl arp-scan iproute2 iproute2-ss nmap traceroute net-tools net-snmp-tools bind-tools awake ca-certificates \
&& apk add --no-cache sqlite php82 php82-fpm php82-cgi php82-curl php82-sqlite3 php82-session \
&& apk add --no-cache bash zip lsblk gettext-envsubst sudo mtr tzdata s6-overlay \
&& apk add --no-cache curl arp-scan iproute2 iproute2-ss nmap nmap-scripts traceroute net-tools net-snmp-tools bind-tools awake ca-certificates \
&& apk add --no-cache sqlite php83 php83-fpm php83-cgi php83-curl php83-sqlite3 php83-session \
&& apk add --no-cache python3 nginx \
&& ln -s /usr/bin/awake /usr/bin/wakeonlan \
&& bash -c "install -d -m 750 -o nginx -g www-data ${INSTALL_DIR} ${INSTALL_DIR}/pialert" \
&& bash -c "install -d -m 750 -o nginx -g www-data ${INSTALL_DIR} ${INSTALL_DIR}" \
&& rm -f /etc/nginx/http.d/default.conf
COPY --from=builder --chown=nginx:www-data ${INSTALL_DIR}/pialert/ ${INSTALL_DIR}/pialert/
COPY --from=builder --chown=nginx:www-data ${INSTALL_DIR}/ ${INSTALL_DIR}/
RUN ${INSTALL_DIR}/pialert/dockerfiles/pre-setup.sh
RUN ${INSTALL_DIR}/dockerfiles/pre-setup.sh
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=2 \
CMD curl -sf -o /dev/null ${LISTEN_ADDR}:${PORT}/api/app_state.json

View File

@@ -10,6 +10,7 @@ ENV USER=pi USER_ID=1000 USER_GID=1000 PORT=20211
RUN apt-get update
RUN apt-get install sudo -y
ARG INSTALL_DIR=/app
# create pi user and group
# add root and www-data to pi group so they can r/w files and db
@@ -23,15 +24,16 @@ RUN groupadd --gid "${USER_GID}" "${USER}" && \
usermod -a -G ${USER_GID} root && \
usermod -a -G ${USER_GID} www-data
COPY --chmod=775 --chown=${USER_ID}:${USER_GID} . /home/pi/pialert/
COPY --chmod=775 --chown=${USER_ID}:${USER_GID} . ${INSTALL_DIR}/
# ❗ IMPORTANT - if you modify this file modify the /install/install_dependecies.debian.sh file as well ❗
RUN apt-get install -y \
tini snmp ca-certificates curl libwww-perl arp-scan perl apt-utils cron sudo \
nginx-light php php-cgi php-fpm php-sqlite3 php-curl sqlite3 dnsutils net-tools \
python3 iproute2 nmap python3-pip zip systemctl usbutils traceroute
nginx-light php php-cgi php-fpm php-sqlite3 php-curl sqlite3 dnsutils net-tools php-openssl \
python3 python3-dev iproute2 nmap python3-pip zip systemctl usbutils traceroute
# Alternate dependencies
RUN apt-get install nginx nginx-core mtr php-fpm php8.2-fpm php-cli php8.2 php8.2-sqlite3 -y
@@ -40,11 +42,12 @@ RUN phpenmod -v 8.2 sqlite3
# Setup virtual python environment and use pip3 to install packages
RUN apt-get install -y python3-venv
RUN python3 -m venv myenv
RUN /bin/bash -c "source myenv/bin/activate && update-alternatives --install /usr/bin/python python /usr/bin/python3 10 && pip3 install requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet"
RUN /bin/bash -c "source myenv/bin/activate && update-alternatives --install /usr/bin/python python /usr/bin/python3 10 && pip3 install pycryptodome requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap dnspython cryptography "
# Create a buildtimestamp.txt to later check if a new version was released
RUN date +%s > /home/pi/pialert/front/buildtimestamp.txt
RUN date +%s > ${INSTALL_DIR}/front/buildtimestamp.txt
CMD ["/home/pi/pialert/install/start.debian.sh"]
CMD ["${INSTALL_DIR}/install/start.debian.sh"]

110
README.md
View File

@@ -1,14 +1,14 @@
# 💻🔍 Network security scanner & notification framework
Get visibility of what's going on on your WIFI/LAN network. Schedule scans for devices, port changes and get alerts if unknown devices or changes are found. Write your own [Plugins](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins#readme) with auto-generated UI and in-build notification system.
Get visibility of what's going on on your WIFI/LAN network. Schedule scans for devices, port changes and get alerts if unknown devices or changes are found. Write your own [Plugins](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins#readme) with auto-generated UI and in-build notification system. Build out and easily maintain your network source of truth (NSoT).
[![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)
[![Docker Size](https://img.shields.io/docker/image-size/jokobsk/pi.alert?label=Size&logo=Docker&color=0aa8d2&logoColor=fff)](https://hub.docker.com/r/jokobsk/pi.alert)
[![Docker Pulls](https://img.shields.io/docker/pulls/jokobsk/pi.alert?label=Pulls&logo=docker&color=0aa8d2&logoColor=fff)](https://hub.docker.com/r/jokobsk/pi.alert)
[![GitHub Release](https://img.shields.io/github/v/release/jokob-sk/Pi.Alert?color=0aa8d2&logoColor=fff&logo=GitHub)](https://github.com/jokob-sk/Pi.Alert/releases)
[![GitHub Committed](https://img.shields.io/github/last-commit/jokob-sk/NetAlertX?color=40ba12&label=Committed&logo=GitHub&logoColor=fff)](https://github.com/jokob-sk/NetAlertX)
[![Docker Size](https://img.shields.io/docker/image-size/jokobsk/netalertx?label=Size&logo=Docker&color=0aa8d2&logoColor=fff)](https://hub.docker.com/r/jokobsk/netalertx)
[![Docker Pulls](https://img.shields.io/docker/pulls/jokobsk/netalertx?label=Pulls&logo=docker&color=0aa8d2&logoColor=fff)](https://hub.docker.com/r/jokobsk/netalertx)
[![GitHub Release](https://img.shields.io/github/v/release/jokob-sk/NetAlertX?color=0aa8d2&logoColor=fff&logo=GitHub)](https://github.com/jokob-sk/NetAlertX/releases)
[![GitHub Sponsors](https://img.shields.io/github/sponsors/jokob-sk?style=social)](https://github.com/sponsors/jokob-sk)
| 🐳 [Docker hub](https://registry.hub.docker.com/r/jokobsk/pi.alert) | 📑 [Docker guide](https://github.com/jokob-sk/Pi.Alert/blob/main/dockerfiles/README.md) |🆕 [Release notes](https://github.com/jokob-sk/Pi.Alert/releases) | 📚 [All Docs](https://github.com/jokob-sk/Pi.Alert/tree/main/docs) |
| 🐳 [Docker hub](https://registry.hub.docker.com/r/jokobsk/netalertx) | 📑 [Docker guide](https://github.com/jokob-sk/NetAlertX/blob/main/dockerfiles/README.md) |🆕 [Release notes](https://github.com/jokob-sk/NetAlertX/releases) | 📚 [All Docs](https://github.com/jokob-sk/NetAlertX/tree/main/docs) |
|----------------------|----------------------| ----------------------| ----------------------|
@@ -25,19 +25,19 @@ Get visibility of what's going on on your WIFI/LAN network. Schedule scans for d
</details>
<details>
<summary>❓ Why use PiAlert?</summary>
<summary>❓ Why use Net <b>Alert</b><sup>x</sup>?</summary>
<hr>
Most of us don't know what's going on on our home network, but we want our family and data to be safe. _Command-line tools_ are great, but the output can be _hard to understand_ and action if you are not a network specialist.
PiAlert gives you peace of mind. _Visualize and immediately report 📬_ what is going on in your network - this is the first step to enhance your _network security 🔐_.
Net <b>Alert</b><sup>x</sup> gives you peace of mind. _Visualize and immediately report 📬_ what is going on in your network - this is the first step to enhance your _network security 🔐_.
PiAlert combines several network and other scanning tools 🔍 with notifications 📧 into one user-friendly package 📦.
Net <b>Alert</b><sup>x</sup> combines several network and other scanning tools 🔍 with notifications 📧 into one user-friendly package 📦.
Set up a _kill switch ☠_ for your network via a smart plug with the available [Home Assistant](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/HOME_ASSISTANT.md) integration. Implement custom automations with the [CSV device Exports 📤](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins/csv_backup), [Webhooks](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/WEBHOOK_N8N.md), or [API endpoints](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/API.md) features.
Set up a _kill switch ☠_ for your network via a smart plug with the available [Home Assistant](https://github.com/jokob-sk/NetAlertX/blob/main/docs/HOME_ASSISTANT.md) integration. Implement custom automations with the [CSV device Exports 📤](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/csv_backup), [Webhooks](https://github.com/jokob-sk/NetAlertX/blob/main/docs/WEBHOOK_N8N.md), or [API endpoints](https://github.com/jokob-sk/NetAlertX/blob/main/docs/API.md) features.
Extend the app if you want to create your own scanner [Plugin](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins#readme) and handle the results and notifications in PiAlert.
Extend the app if you want to create your own scanner [Plugin](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins#readme) and handle the results and notifications in Net <b>Alert</b><sup>x</sup>.
Looking forward to your contributions if you decide to share your work with the community ❤.
@@ -47,10 +47,10 @@ Get visibility of what's going on on your WIFI/LAN network. Schedule scans for d
| Features | Details |
|-------------|-------------|
| 🔍 | The app scans your network for, **New devices**, **New connections** (re-connections), **Disconnections**, **"Always Connected" devices down**, Devices **IP changes** and **Internet IP address changes**. Discovery & scan methods include: **arp-scan**. **Pi-hole - DB import**, **Pi-hole - DHCP leases import**, **Generic DHCP leases import**. **UNIFI controller import**, **SNMP-enabled router import**. Check the [Plugins](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins#readme) docs for more info on individual scans. |
| 🔍 | The app scans your network for, **New devices**, **New connections** (re-connections), **Disconnections**, **"Always Connected" devices down**, Devices **IP changes** and **Internet IP address changes**. Discovery & scan methods include: **arp-scan**, **Pi-hole - DB import**, **Pi-hole - DHCP leases import**, **Generic DHCP leases import**. **UNIFI controller import**, **SNMP-enabled router import**. Check the [Plugins](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins#readme) docs for more info on individual scans. |
|📧 | Send notifications to more than 80+ services, including Telegram via [Apprise](https://hub.docker.com/r/caronc/apprise), or use [Pushsafer](https://www.pushsafer.com/), [Pushover](https://www.pushover.net/), or [NTFY](https://ntfy.sh/). |
|🧩 | Feed your data and device changes into [Home Assistant](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/HOME_ASSISTANT.md), read [API endpoints](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/API.md), or use [Webhooks](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/WEBHOOK_N8N.md) to setup custom automation flows. |
| | Build your own scanners with the [Plugin system](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins#readme) |
|🧩 | Feed your data and device changes into [Home Assistant](https://github.com/jokob-sk/NetAlertX/blob/main/docs/HOME_ASSISTANT.md), read [API endpoints](https://github.com/jokob-sk/NetAlertX/blob/main/docs/API.md), or use [Webhooks](https://github.com/jokob-sk/NetAlertX/blob/main/docs/WEBHOOK_N8N.md) to setup custom automation flows. |
| | Build your own scanners with the [Plugin system](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins#readme) |
## Installation & Documentation
@@ -58,23 +58,37 @@ Get visibility of what's going on on your WIFI/LAN network. Schedule scans for d
| Docs | Link |
|-------------|-------------|
| 📥🐳 | [Docker instructions](https://github.com/jokob-sk/Pi.Alert/blob/main/dockerfiles/README.md)
| 📥💻 | [HW install (experimental 🧪)](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/HW_INSTALL.md) |
| 📚 | [All Documentation](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/README.md) (App Usage and Configuration) |
| 📥🐳 | [Docker instructions](https://github.com/jokob-sk/NetAlertX/blob/main/dockerfiles/README.md)
| 📥💻 | [HW install (experimental 🧪)](https://github.com/jokob-sk/NetAlertX/blob/main/docs/HW_INSTALL.md) |
| 📥🟧 | [Unraid App](https://unraid.net/community/apps) |
| 📚 | [All Documentation](https://github.com/jokob-sk/NetAlertX/blob/main/docs/README.md) (App Usage and Configuration) |
> Other Alternatives
>
> - Check out [leiweibau's on HW installed fork](https://github.com/leiweibau/Pi.Alert/) (maintained)
> - Check instructions for [pucherot's original code](https://github.com/pucherot/Pi.Alert/) (unmaintained)
> - [WatchYourLAN](https://github.com/aceberg/WatchYourLAN) - Lightweight network IP scanner with web GUI (Open source)
> - [Fing](https://www.fing.com/) - Network scanner app for your Internet security (Commercial, Phone App, Proprietary hardware)
> - [NetBox](https://netboxlabs.com/) - Network management software (Commercial)
## ❤ Support me for...
## 🔔 Get notified what's new
- I don't get burned out and the app survives longer🔥🤯
- Regular updates to keep your data and family safe 🔄
- Better and more functionality
- Quicker and better support with issues 🆘
Get notified about a new release, what new functionality you can use and about breaking changes.
![Follow and star][follow_star]
### ⭐ Sponsors
[![GitHub Sponsors](https://img.shields.io/github/sponsors/jokob-sk?style=social)](https://github.com/sponsors/jokob-sk)
Thank you to all the wonderful people who are sponsoring this project.
> preventing my burnout😅 are:
<!-- SPONSORS-LIST DO NOT MODIFY BELOW -->
| All Sponsors |
|---|
<!-- SPONSORS-LIST DO NOT MODIFY ABOVE -->
| [![GitHub](https://i.imgur.com/emsRCPh.png)](https://github.com/sponsors/jokob-sk) | [![Buy Me A Coffee](https://i.imgur.com/pIM6YXL.png)](https://www.buymeacoffee.com/jokobsk) | [![Patreon](https://i.imgur.com/MuYsrq1.png)](https://www.patreon.com/user?u=84385063) |
| --- | --- | --- |
@@ -87,35 +101,16 @@ Get visibility of what's going on on your WIFI/LAN network. Schedule scans for d
- Bitcoin: `1N8tupjeCK12qRVU2XrV17WvKK7LCawyZM`
- Ethereum: `0x6e2749Cb42F4411bc98501406BdcD82244e3f9C7`
📧 Email me at [jokob@duck.com](mailto:jokob@duck.com?subject=PiAlert) if you want to get in touch or if I should add other sponsorship platforms.
📧 Email me at [jokob@duck.com](mailto:jokob@duck.com?subject=NetAlertX) if you want to get in touch or if I should add other sponsorship platforms.
</details>
### ⭐ Sponsors
[![GitHub Sponsors](https://img.shields.io/github/sponsors/jokob-sk?style=social)](https://github.com/sponsors/jokob-sk)
Thank you to all the wonderful people who are sponsoring this project (=preventing my burnout🔥🤯):
<!-- SPONSORS-LIST DO NOT MODIFY BELOW -->
| All Sponsors |
|---|
<!-- SPONSORS-LIST DO NOT MODIFY ABOVE -->
### 🙏Contributors
This project would be nothing without the amazing work of the community, with special thanks to:
> [pucherot/Pi.Alert](https://github.com/pucherot/Pi.Alert) (the original creator of PiAlert), [leiweibau](https://github.com/leiweibau/Pi.Alert): Dark mode (and much more), [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 translations), [Data-Monkey](https://github.com/Data-Monkey), (Split-up of the python.py file and more), [cvc90](https://github.com/cvc90) (Spanish translation and various UI work) to name a few...
Here is everyone that helped and contributed to this project:
<a href="https://github.com/jokob-sk/pi.alert/graphs/contributors">
<img src="https://contri-graphy.yourselfhosted.com/graph?repo=jokob-sk/pi.alert&format=svg" />
</a>
## Everything else
<!--- --------------------------------------------------------------------- --->
@@ -136,18 +131,19 @@ Help out and suggest languages in the [online portal of Weblate](https://hosted.
<!--- --------------------------------------------------------------------- --->
[main]: ./docs/img/devices_split.png "Main screen"
[screen1]: ./docs/img/device_details.png "Screen 1"
[screen2]: ./docs/img/events.png "Screen 2"
[screen3]: ./docs/img/presence.png "Screen 3"
[screen4]: ./docs/img/maintenance.png "Screen 4"
[screen5]: ./docs/img/network.png "Screen 5"
[screen6]: ./docs/img/settings.png "Screen 6"
[screen7]: ./docs/img/help_faq.png "Screen 7"
[screen8]: ./docs/img/plugins_rogue_dhcp.png "Screen 8"
[screen9]: ./docs/img/device_nmap.png "Screen 9"
[report1]: ./docs/img/4_report_1.jpg "Report sample 1"
[report2]: ./docs/img/4_report_2.jpg "Report sample 2"
[main_dark]: /docs/img/1_devices_dark.jpg "Main screen dark"
[maintain_dark]: /docs/img/5_maintain.jpg "Maintain screen dark"
[main]: ./docs/img/devices_split.png "Main screen"
[screen1]: ./docs/img/device_details.png "Screen 1"
[screen2]: ./docs/img/events.png "Screen 2"
[screen3]: ./docs/img/presence.png "Screen 3"
[screen4]: ./docs/img/maintenance.png "Screen 4"
[screen5]: ./docs/img/network.png "Screen 5"
[screen6]: ./docs/img/settings.png "Screen 6"
[screen7]: ./docs/img/help_faq.png "Screen 7"
[screen8]: ./docs/img/plugins_rogue_dhcp.png "Screen 8"
[screen9]: ./docs/img/device_nmap.png "Screen 9"
[report1]: ./docs/img/4_report_1.jpg "Report sample 1"
[report2]: ./docs/img/4_report_2.jpg "Report sample 2"
[main_dark]: /docs/img/1_devices_dark.jpg "Main screen dark"
[maintain_dark]: /docs/img/5_maintain.jpg "Maintain screen dark"
[follow_star]: /docs/img/Follow_Releases_and_Star.gif "Follow and Star"

View File

@@ -3,10 +3,12 @@
# Generated: 2022-12-30_22-19-40 #
# #
# Config file for the LAN intruder detection app: #
# https://github.com/jokob-sk/Pi.Alert #
# https://github.com/jokob-sk/NetAlertX #
# #
#-----------------AUTOGENERATED FILE-----------------#
# 🔺 Use the Settings UI - only edit when necessary 🔺
# General
#---------------------------
@@ -19,20 +21,18 @@
SCAN_SUBNETS=['192.168.1.0/24 --interface=eth1']
TIMEZONE='Europe/Berlin'
PIALERT_WEB_PROTECTION=False
PIALERT_WEB_PASSWORD='8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'
DAYS_TO_KEEP_EVENTS=90
# Used for generating links in emails. Make sure not to add a trailing slash!
REPORT_DASHBOARD_URL='http://pi.alert'
REPORT_DASHBOARD_URL='http://netalertx'
# Email
#---------------------------
REPORT_MAIL=False
SMTP_RUN='disabled' # use 'on_notification' to enable
SMTP_SERVER='smtp.gmail.com'
SMTP_PORT=587
REPORT_TO='user@gmail.com'
REPORT_FROM='Pi.Alert <user@gmail.com>'
SMTP_REPORT_TO='user@gmail.com'
SMTP_REPORT_FROM='NetAlertX <user@gmail.com>'
SMTP_SKIP_LOGIN=False
SMTP_USER='user@gmail.com'
SMTP_PASS='password'
@@ -41,10 +41,10 @@ SMTP_SKIP_TLS=False
# Webhooks
#---------------------------
REPORT_WEBHOOK=False
WEBHOOK_RUN='disabled' # use 'on_notification' to enable
WEBHOOK_URL='http://n8n.local:5555/webhook-test/aaaaaaaa-aaaa-aaaa-aaaaa-aaaaaaaaaaaa'
WEBHOOK_PAYLOAD='json' # webhook payload data format for the "body > attachements > text" attribute
# in https://github.com/jokob-sk/Pi.Alert/blob/main/docs/webhook_json_sample.json
# in https://github.com/jokob-sk/NetAlertX/blob/main/docs/webhook_json_sample.json
# supported values: 'json', 'html' or 'text'
# e.g.: for discord use 'html'
WEBHOOK_REQUEST_METHOD='GET'
@@ -52,14 +52,14 @@ WEBHOOK_REQUEST_METHOD='GET'
# Apprise
#---------------------------
REPORT_APPRISE=False
APPRISE_RUN='disabled' # use 'on_notification' to enable
APPRISE_HOST='http://localhost:8000/notify'
APPRISE_URL='mailto://smtp-relay.sendinblue.com:587?from=user@gmail.com&name=apprise&user=user@gmail.com&pass=password&to=user@gmail.com'
# NTFY
#---------------------------
REPORT_NTFY=False
NTFY_RUN='disabled' # use 'on_notification' to enable
NTFY_HOST='https://ntfy.sh'
NTFY_TOPIC='replace_my_secure_topicname_91h889f28'
NTFY_USER='user'
@@ -68,13 +68,13 @@ NTFY_PASSWORD='passw0rd'
# PUSHSAFER
#---------------------------
REPORT_PUSHSAFER=False
PUSHSAFER_RUN='disabled' # use 'on_notification' to enable
PUSHSAFER_TOKEN='ApiKey'
# MQTT
#---------------------------
REPORT_MQTT=False
MQTT_RUN='disabled' # use 'on_notification' to enable
MQTT_BROKER='192.168.1.2'
MQTT_PORT=1883
MQTT_USER='mqtt'
@@ -83,15 +83,6 @@ MQTT_QOS=0
MQTT_DELAY_SEC=2
# DynDNS
#---------------------------
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?'
#-------------------IMPORTANT INFO-------------------#
# This file is ingested by a python script, so if #
# modified it needs to use python syntax #

View File

@@ -1,141 +0,0 @@
#!/bin/bash
SCRIPT=$(readlink -f $0)
SCRIPTPATH=`dirname $SCRIPT`
PIA_CONF_FILE=${SCRIPTPATH}'/../config/pialert.conf'
case $1 in
help)
echo "pialert-cli v0.1 (https://github.com/leiweibau/Pi.Alert)"
echo "Usage: pialert-cli <command>"
echo ""
echo "The is a list of supported commands:"
echo ""
echo " set_login - Sets the parameter PIALERT_WEB_PROTECTION in the config file to TRUE"
echo " - If the parameter is not present, it will be created. Additionally the"
echo " default password '123456' is set."
echo ""
echo " unset_login - Sets the parameter PIALERT_WEB_PROTECTION in the config file to FALSE"
echo " - If the parameter is not present, it will be created. Additionally the"
echo " default password '123456' is set."
echo ""
echo " set_password <password> - Sets the new password as a hashed value."
echo " - If the PIALERT_WEB_PROTECTION parameter does not exist yet, it will be"
echo " created and set to 'True' (login enabled)"
echo ""
echo " set_autopassword - Sets a new random password as a hashed value and show it plaintext in"
echo " the console."
echo " - If the PIALERT_WEB_PROTECTION parameter does not exist yet, it will be"
echo " created and set to 'True' (login enabled)"
echo ""
echo " disable_scan - Stops all active scans"
echo " - Prevents new scans from starting"
echo ""
echo " enable_scan - Stops all active scans"
echo " - Prevents new scans from starting"
echo ""
echo ""
;;
set_login)
## Check if PIALERT_WEB_PROTECTION exists
CHECK_PROT=$(grep "PIALERT_WEB_PROTECTION" $PIA_CONF_FILE | wc -l)
if [ $CHECK_PROT -eq 0 ]
then
## Create PIALERT_WEB_PROTECTION and enable it
sed -i "/^VENDORS_DB.*/a PIALERT_WEB_PROTECTION = True" $PIA_CONF_FILE
sed -i "/^PIALERT_WEB_PROTECTION.*/a PIALERT_WEB_PASSWORD = '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'" $PIA_CONF_FILE
else
## Switch PIALERT_WEB_PROTECTION to enable
sed -i "/PIALERT_WEB_PROTECTION/c\PIALERT_WEB_PROTECTION = True" $PIA_CONF_FILE
fi
echo "Login is now enabled"
;;
unset_login)
## Check if PIALERT_WEB_PROTECTION exists
CHECK_PROT=$(grep "PIALERT_WEB_PROTECTION" $PIA_CONF_FILE | wc -l)
if [ $CHECK_PROT -eq 0 ]
then
## Create PIALERT_WEB_PROTECTION and disable it
sed -i "/^VENDORS_DB.*/a PIALERT_WEB_PROTECTION = False" $PIA_CONF_FILE
sed -i "/^PIALERT_WEB_PROTECTION.*/a PIALERT_WEB_PASSWORD = '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'" $PIA_CONF_FILE
else
## Switch PIALERT_WEB_PROTECTION to disable
sed -i "/PIALERT_WEB_PROTECTION/c\PIALERT_WEB_PROTECTION = False" $PIA_CONF_FILE
fi
echo "Login is now disabled"
;;
set_password)
PIA_PASS=$2
## Check if PIALERT_WEB_PROTECTION exists
CHECK_PROT=$(grep "PIALERT_WEB_PROTECTION" $PIA_CONF_FILE | wc -l)
if [ $CHECK_PROT -eq 0 ]
then
## Create PIALERT_WEB_PROTECTION and enable it
sed -i "/^VENDORS_DB.*/a PIALERT_WEB_PROTECTION = True" $PIA_CONF_FILE
fi
## Prepare Hash
PIA_PASS_HASH=$(echo -n $PIA_PASS | sha256sum | awk '{print $1}')
echo " The hashed password is:"
echo " $PIA_PASS_HASH"
## Check if the password parameter is set
CHECK_PWD=$(grep "PIALERT_WEB_PASSWORD" $PIA_CONF_FILE | wc -l)
if [ $CHECK_PWD -eq 0 ]
then
sed -i "/^PIALERT_WEB_PROTECTION.*/a PIALERT_WEB_PASSWORD = '$PIA_PASS_HASH'" $PIA_CONF_FILE
else
sed -i "/PIALERT_WEB_PASSWORD/c\PIALERT_WEB_PASSWORD = '$PIA_PASS_HASH'" $PIA_CONF_FILE
fi
echo ""
echo "The new password is set"
;;
set_autopassword)
## Check if PIALERT_WEB_PROTECTION exists
CHECK_PROT=$(grep "PIALERT_WEB_PROTECTION" $PIA_CONF_FILE | wc -l)
if [ $CHECK_PROT -eq 0 ]
then
## Create PIALERT_WEB_PROTECTION and enable it
sed -i "/^VENDORS_DB.*/a PIALERT_WEB_PROTECTION = True" $PIA_CONF_FILE
fi
## Create autopassword
PIA_AUTOPASS=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1)
echo " The password is: $PIA_AUTOPASS"
## Prepare Hash
PIA_AUTOPASS_HASH=$(echo -n $PIA_AUTOPASS | sha256sum | awk '{print $1}')
echo " The hashed password is:"
echo " $PIA_AUTOPASS_HASH"
## Check if the password parameter is set
CHECK_PWD=$(grep "PIALERT_WEB_PASSWORD" $PIA_CONF_FILE | wc -l)
if [ $CHECK_PWD -eq 0 ]
then
## Create password parameter
sed -i "/^PIALERT_WEB_PROTECTION.*/a PIALERT_WEB_PASSWORD = '$PIA_AUTOPASS_HASH'" $PIA_CONF_FILE
else
## Overwrite password parameter
sed -i "/PIALERT_WEB_PASSWORD/c\PIALERT_WEB_PASSWORD = '$PIA_AUTOPASS_HASH'" $PIA_CONF_FILE
fi
echo ""
echo "The new password is set"
;;
disable_scan)
## stop active scans
sudo killall arp-scan
touch ${SCRIPTPATH}/../db/setting_stoparpscan
echo "The arp-scan is disabled"
;;
enable_scan)
## stop active scans
rm ${SCRIPTPATH}/../db/setting_stoparpscan
echo "The arp-scan is enabled"
;;
*)
echo "pialert-cli v0.1 (https://github.com/leiweibau/Pi.Alert)"
echo "Use \"pialert-cli help\" for a list of supported commands."
esac

View File

@@ -1,70 +0,0 @@
<!--
#---------------------------------------------------------------------------------#
# Pi.Alert #
# Open Source Network Guard / WIFI & LAN intrusion detector #
# #
# report_template.html - Back module. Template to email reporting in HTML format #
#---------------------------------------------------------------------------------#
# Puche 2021 pi.alert.application@gmail.com GNU GPLv3 #
# jokob-sk 2022 jokob.sk@gmail.com GNU GPLv3 #
# leiweibau 2022 https://github.com/leiweibau GNU GPLv3 #
# cvc90 2023 https://github.com/cvc90 GNU GPLv3 #
#---------------------------------------------------------------------------------#
-->
<html>
<head>
</head>
<body>
<font face=sans-serif>
<table align=center width=100% cellpadding=0 cellspacing=0 style="border-radius: 5px;">
<tr>
<td bgcolor=#3c8dbc align=center style="padding: 20px 10px 10px 10px; font-size: 30px; font-weight: bold; color:#ffffff; border-top-right-radius: 5px; border-top-left-radius: 5px; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2)">
Pi.Alert Report
</td>
</tr>
<tr>
<td>
<table width=100% border=0 bgcolor=#4b99d3 cellpadding=5px cellspacing=0 style="border-collapse: collapse; font-size: 15px; text-align:center; color:#ffffff"> <tr>
<td width=100% bgcolor="#3c8dbc"> Report Date: <b><REPORT_DATE></b> </td>
</tr>
</table>
</td>
</tr>
<tr>
<td height=200 valign=top style="padding: 10px">
<NEW_DEVICES_TABLE>
<DOWN_DEVICES_TABLE>
<EVENTS_TABLE>
<PLUGINS_TABLE>
</td>
</tr>
<tr>
<td>
<table width=100% bgcolor=#3c8dbc cellpadding=5px cellspacing=0 style="font-size: 13px; font-weight: bold; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px;">
<tr>
<td width=50% style="text-align:center;color: white;" bgcolor="#3c8dbc">
<a href="https://github.com/jokob-sk/Pi.Alert" target="_blank" style="color: white">Pi.Alert</a>
<a href=".." target="_blank" style="color: white"> (<SERVER_NAME>)</a>
<br><span style="display:inline-block;color: white; transform: rotate(180deg)">&copy;</span>2020 Puche (2022+
<a style="color: white" href="mailto:jokob@duck.com?subject=PiAlert">jokob-sk</a>) | <b>Built on: <BUILD_PIALERT> </b> | <b> Version: <VERSION_PIALERT> </b> |
<a href="https://github.com/jokob-sk/Pi.Alert/tree/main/docs" target="_blank" style="color: white">
<span>Docs <i class="fa fa-circle-question"></i>
</a><span>
</td>
</tr>
</table>
</td>
</tr>
</table>
</font>
</body>
</html>

View File

@@ -1,74 +0,0 @@
<!--
#---------------------------------------------------------------------------------#
# Pi.Alert #
# Open Source Network Guard / WIFI & LAN intrusion detector #
# #
# report_template_new_version - Back module. Template to email reporting in text #
#---------------------------------------------------------------------------------#
# Puche 2021 pi.alert.application@gmail.com GNU GPLv3 #
# jokob-sk 2022 jokob.sk@gmail.com GNU GPLv3 #
# leiweibau 2022 https://github.com/leiweibau GNU GPLv3 #
# cvc90 2023 https://github.com/cvc90 GNU GPLv3 #
#---------------------------------------------------------------------------------#
-->
<html>
<head>
</head>
<body>
<font face=sans-serif>
<table align=center width=100% cellpadding=0 cellspacing=0 style="border-radius: 5px;">
<tr>
<td bgcolor=#3c8dbc align=center style="padding: 20px 10px 10px 10px; font-size: 30px; font-weight: bold; color:#ffffff; border-top-right-radius: 5px; border-top-left-radius: 5px; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2)">
Pi.Alert Report
</td>
</tr>
<tr>
<td bgcolor=#2656f1 width=100% align=center style="padding: 20px 10px 10px 10px; font-size: 20px; font-weight: bold; color:#ffffff; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2)">
<a style="color:#ffffff;cursor:pointer;" href="https://github.com/jokob-sk/Pi.Alert/releases">🆕 New version available 🆕</a>
</td>
</tr>
<tr>
<td>
<table width=100% border=0 bgcolor=#4b99d3 cellpadding=5px cellspacing=0 style="border-collapse: collapse; font-size: 15px; text-align:center; color:#ffffff"> <tr>
<td width=100% bgcolor="#3c8dbc"> Report Date: <b><REPORT_DATE></b> </td>
</tr>
</table>
</td>
</tr>
<tr>
<td height=200 valign=top style="padding: 10px">
<NEW_DEVICES_TABLE>
<DOWN_DEVICES_TABLE>
<EVENTS_TABLE>
<PLUGINS_TABLE>
</td>
</tr>
<tr>
<td>
<table width=100% bgcolor=#3c8dbc cellpadding=5px cellspacing=0 style="font-size: 13px; font-weight: bold; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px;">
<tr>
<td width=50% style="text-align:center;color: white;" bgcolor="#3c8dbc">
<a href="https://github.com/jokob-sk/Pi.Alert" target="_blank" style="color: white">Pi.Alert</a>
<a href=".." target="_blank" style="color: white"> (<SERVER_NAME>)</a>
<br><span style="display:inline-block;color: white; transform: rotate(180deg)">&copy;</span>2020 Puche (2022+
<a style="color: white" href="mailto:jokob@duck.com?subject=PiAlert">jokob-sk</a>) | <b>Built on: <BUILD_PIALERT> </b> | <b> Version: <VERSION_PIALERT> </b> |
<a href="https://github.com/jokob-sk/Pi.Alert/tree/main/docs" target="_blank" style="color: white">
<span>Docs <i class="fa fa-circle-question"></i>
</a><span>
</td>
</tr>
</table>
</td>
</tr>
</table>
</font>
</body>
</html>

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash
# ------------------------------------------------------------------------------
# Pi.Alert
# NetAlertX
# Open Source Network Guard / WIFI & LAN intrusion detector
#
# update_vendors.sh - Back module. IEEE Vendors db update
@@ -12,56 +12,31 @@
# ----------------------------------------------------------------------
# Main directories to update:
# /usr/share/arp-scan
# /usr/share/ieee-data
# /var/lib/ieee-data
# ----------------------------------------------------------------------
echo "---------------------------------------------------------"
echo "[INSTALL] Run update_vendors.sh"
echo "---------------------------------------------------------"
# ----------------------------------------------------------------------
echo Updating... /usr/share/ieee-data/
cd /usr/share/ieee-data/ || { echo "could not enter /usr/share/ieee-data directory"; exit 1; }
sudo mkdir -p 2_backup
sudo cp -- *.txt 2_backup
sudo cp -- *.csv 2_backup
echo ""
echo Download Start
echo ""
sudo curl "$1" -LO https://standards-oui.ieee.org/oui28/mam.csv \
-LO https://standards-oui.ieee.org/oui28/mam.csv \
-LO https://standards-oui.ieee.org/oui28/mam.txt \
-LO https://standards-oui.ieee.org/oui36/oui36.csv \
-LO https://standards-oui.ieee.org/oui36/oui36.txt \
-LO https://standards-oui.ieee.org/oui/oui.csv \
-LO https://standards-oui.ieee.org/oui/oui.txt
echo ""
echo Download Finished
DL_DIR=/usr/share/arp-scan
# ----------------------------------------------------------------------
echo ""
echo Updating... /usr/share/arp-scan/
cd /usr/share/arp-scan || { echo "could not enter /usr/share/arp-scan directory"; exit 1; }
echo Updating... $DL_DIR
cd $DL_DIR || { echo "could not enter $DL_DIR directory"; exit 1; }
sudo mkdir -p 2_backup
sudo cp -- *.txt 2_backup
# Define the URL of the IEEE OUI file
IEEE_OUI_URL="http://standards-oui.ieee.org/oui/oui.txt"
# Update from /usb/lib/ieee-data
sudo get-iab -v
sudo get-oui -v
# Download the file using wget
wget "$IEEE_OUI_URL" -O ieee-oui_dl.txt
# make files readable
sudo chmod +r /usr/share/arp-scan/ieee-oui.txt
# Filter lines containing "(base 16)" and remove the "(base 16)" string
grep "(base 16)" ieee-oui_dl.txt | sed 's/ *(base 16)//' > ieee-oui_new.txt
# Update from ieee website
# sudo get-iab -v -u http://standards-oui.ieee.org/iab/iab.txt
# sudo get-oui -v -u http://standards-oui.ieee.org/oui/oui.txt
# Combine ieee-oui_new.txt and ieee-oui.txt, and extract unique MAC start values along with vendor names
# Update from ieee website develop
# sudo get-iab -v -u http://standards.ieee.org/develop/regauth/iab/iab.txt
# sudo get-oui -v -u http://standards.ieee.org/develop/regauth/oui/oui.txt
cat ieee-oui.txt ieee-oui_new.txt >> ieee-oui_all.txt
sort ieee-oui_all.txt > ieee-oui_all_sort.txt
awk '{$1=$1; print}' ieee-oui_all_sort.txt | sort -u > ieee-oui_all_filtered.txt
# Update from Sanitized oui (linuxnet.ca)
# sudo get-oui -v -u https://linuxnet.ca/ieee/oui.txt

View File

@@ -1,68 +1,69 @@
version: "3"
services:
pialert:
netalertx:
privileged: true
build:
dockerfile: Dockerfile
context: .
cache_from:
- type=registry,ref=docker.io/jokob-sk/pi.alert:buildcache
container_name: pialert
- type=registry,ref=docker.io/jokob-sk/netalertx:buildcache
container_name: netalertx
network_mode: host
# restart: unless-stopped
volumes:
# - ${APP_DATA_LOCATION}/pialert_dev/config:/home/pi/pialert/config
- ${APP_DATA_LOCATION}/pialert/config:/home/pi/pialert/config
# - ${APP_DATA_LOCATION}/pialert_dev/db:/home/pi/pialert/db
- ${APP_DATA_LOCATION}/pialert/db:/home/pi/pialert/db
# - ${APP_DATA_LOCATION}/netalertx_dev/config:/app/config
- ${APP_DATA_LOCATION}/netalertx/config:/app/config
# - ${APP_DATA_LOCATION}/netalertx_dev/db:/app/db
- ${APP_DATA_LOCATION}/netalertx/db:/app/db
# (optional) useful for debugging if you have issues setting up the container
# - ${LOGS_LOCATION}:/home/pi/pialert/front/log
# - ${LOGS_LOCATION}:/app/front/log
# ---------------------------------------------------------------------------
# DELETE START anyone trying to use this file: comment out / delete BELOW lines, they are only for development purposes
- ${APP_DATA_LOCATION}/pialert/dhcp_samples/dhcp1.leases:/mnt/dhcp1.leases
- ${APP_DATA_LOCATION}/pialert/dhcp_samples/dhcp2.leases:/mnt/dhcp2.leases
- ${APP_DATA_LOCATION}/pialert/dhcp_samples/pihole_dhcp_full.leases:/etc/pihole/dhcp.leases
- ${APP_DATA_LOCATION}/pialert/dhcp_samples/pihole_dhcp_2.leases:/etc/pihole/dhcp2.leases
- ${APP_DATA_LOCATION}/netalertx/dhcp_samples/dhcp1.leases:/mnt/dhcp1.leases
- ${APP_DATA_LOCATION}/netalertx/dhcp_samples/dhcp2.leases:/mnt/dhcp2.leases
- ${APP_DATA_LOCATION}/netalertx/dhcp_samples/pihole_dhcp_full.leases:/etc/pihole/dhcp.leases
- ${APP_DATA_LOCATION}/netalertx/dhcp_samples/pihole_dhcp_2.leases:/etc/pihole/dhcp2.leases
- ${APP_DATA_LOCATION}/pihole/etc-pihole/pihole-FTL.db:/etc/pihole/pihole-FTL.db
- ${DEV_LOCATION}/pialert:/home/pi/pialert/pialert
- ${DEV_LOCATION}/dockerfiles:/home/pi/pialert/dockerfiles
- ${APP_DATA_LOCATION}/pialert/php.ini:/etc/php/8.2/fpm/php.ini
- ${DEV_LOCATION}/install:/home/pi/pialert/install
- ${DEV_LOCATION}/front/css:/home/pi/pialert/front/css
- ${DEV_LOCATION}/back/update_vendors.sh:/home/pi/pialert/back/update_vendors.sh
- ${DEV_LOCATION}/front/lib/AdminLTE:/home/pi/pialert/front/lib/AdminLTE
- ${DEV_LOCATION}/front/js:/home/pi/pialert/front/js
- ${DEV_LOCATION}/install/start.debian.sh:/home/pi/pialert/install/start.debian.sh
- ${DEV_LOCATION}/install/user-mapping.debian.sh:/home/pi/pialert/install/user-mapping.debian.sh
- ${DEV_LOCATION}/install/install.debian.sh:/home/pi/pialert/install/install.debian.sh
- ${DEV_LOCATION}/install/install_dependencies.debian.sh:/home/pi/pialert/install/install_dependencies.debian.sh
- ${DEV_LOCATION}/front/api:/home/pi/pialert/front/api
- ${DEV_LOCATION}/front/php:/home/pi/pialert/front/php
- ${DEV_LOCATION}/front/deviceDetails.php:/home/pi/pialert/front/deviceDetails.php
- ${DEV_LOCATION}/front/deviceDetailsTools.php:/home/pi/pialert/front/deviceDetailsTools.php
- ${DEV_LOCATION}/front/devices.php:/home/pi/pialert/front/devices.php
- ${DEV_LOCATION}/front/events.php:/home/pi/pialert/front/events.php
- ${DEV_LOCATION}/front/plugins.php:/home/pi/pialert/front/plugins.php
- ${DEV_LOCATION}/front/pluginsCore.php:/home/pi/pialert/front/pluginsCore.php
- ${DEV_LOCATION}/front/help_faq.php:/home/pi/pialert/front/help_faq.php
- ${DEV_LOCATION}/front/index.php:/home/pi/pialert/front/index.php
- ${DEV_LOCATION}/front/maintenance.php:/home/pi/pialert/front/maintenance.php
- ${DEV_LOCATION}/front/network.php:/home/pi/pialert/front/network.php
- ${DEV_LOCATION}/front/presence.php:/home/pi/pialert/front/presence.php
- ${DEV_LOCATION}/front/settings.php:/home/pi/pialert/front/settings.php
- ${DEV_LOCATION}/front/systeminfo.php:/home/pi/pialert/front/systeminfo.php
- ${DEV_LOCATION}/front/report.php:/home/pi/pialert/front/report.php
- ${DEV_LOCATION}/front/workflows.php:/home/pi/pialert/front/workflows.php
- ${DEV_LOCATION}/front/appEventsCore.php:/home/pi/pialert/front/appEventsCore.php
- ${DEV_LOCATION}/front/multiEditCore.php:/home/pi/pialert/front/multiEditCore.php
- ${DEV_LOCATION}/front/donations.php:/home/pi/pialert/front/donations.php
- ${DEV_LOCATION}/front/plugins:/home/pi/pialert/front/plugins
- ${DEV_LOCATION}/server:/app/server
- ${DEV_LOCATION}/dockerfiles:/app/dockerfiles
# - ${APP_DATA_LOCATION}/netalertx/php.ini:/etc/php/8.2/fpm/php.ini
- ${DEV_LOCATION}/install:/app/install
- ${DEV_LOCATION}/front/css:/app/front/css
- ${DEV_LOCATION}/front/img:/app/front/img
- ${DEV_LOCATION}/back/update_vendors.sh:/app/back/update_vendors.sh
- ${DEV_LOCATION}/front/lib:/app/front/lib
- ${DEV_LOCATION}/front/js:/app/front/js
- ${DEV_LOCATION}/front/report_templates:/front/report_templates
- ${DEV_LOCATION}/install/start.debian.sh:/app/install/start.debian.sh
- ${DEV_LOCATION}/install/user-mapping.debian.sh:/app/install/user-mapping.debian.sh
- ${DEV_LOCATION}/install/install.debian.sh:/app/install/install.debian.sh
- ${DEV_LOCATION}/install/install_dependencies.debian.sh:/app/install/install_dependencies.debian.sh
- ${DEV_LOCATION}/front/api:/app/front/api
- ${DEV_LOCATION}/front/php:/app/front/php
- ${DEV_LOCATION}/front/deviceDetails.php:/app/front/deviceDetails.php
- ${DEV_LOCATION}/front/userNotifications.php:/app/front/userNotifications.php
- ${DEV_LOCATION}/front/deviceDetailsTools.php:/app/front/deviceDetailsTools.php
- ${DEV_LOCATION}/front/devices.php:/app/front/devices.php
- ${DEV_LOCATION}/front/events.php:/app/front/events.php
- ${DEV_LOCATION}/front/plugins.php:/app/front/plugins.php
- ${DEV_LOCATION}/front/pluginsCore.php:/app/front/pluginsCore.php
- ${DEV_LOCATION}/front/help_faq.php:/app/front/help_faq.php
- ${DEV_LOCATION}/front/index.php:/app/front/index.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
- ${DEV_LOCATION}/front/settings.php:/app/front/settings.php
- ${DEV_LOCATION}/front/systeminfo.php:/app/front/systeminfo.php
- ${DEV_LOCATION}/front/report.php:/app/front/report.php
- ${DEV_LOCATION}/front/workflows.php:/app/front/workflows.php
- ${DEV_LOCATION}/front/appEventsCore.php:/app/front/appEventsCore.php
- ${DEV_LOCATION}/front/multiEditCore.php:/app/front/multiEditCore.php
- ${DEV_LOCATION}/front/donations.php:/app/front/donations.php
- ${DEV_LOCATION}/front/plugins:/app/front/plugins
# DELETE END anyone trying to use this file: comment out / delete ABOVE lines, they are only for development purposes
# ---------------------------------------------------------------------------
environment:
- TZ=${TZ}
- PORT=${PORT}
- HOST_USER_ID=${HOST_USER_ID}
- HOST_USER_GID=${HOST_USER_GID}
# ❗ DANGER ZONE BELOW - Setting ALWAYS_FRESH_INSTALL=true will delete the content of the /db & /config folders
- ALWAYS_FRESH_INSTALL=${ALWAYS_FRESH_INSTALL}

View File

@@ -1,35 +1,33 @@
[![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)
[![Docker Size](https://img.shields.io/docker/image-size/jokobsk/pi.alert?label=Size&logo=Docker&color=0aa8d2&logoColor=fff)](https://hub.docker.com/r/jokobsk/pi.alert)
[![Docker Pulls](https://img.shields.io/docker/pulls/jokobsk/pi.alert?label=Pulls&logo=docker&color=0aa8d2&logoColor=fff)](https://hub.docker.com/r/jokobsk/pi.alert)
![GitHub Release](https://img.shields.io/github/v/release/jokob-sk/Pi.Alert?color=0aa8d2&logoColor=fff&logo=GitHub)
[![GitHub Committed](https://img.shields.io/github/last-commit/jokob-sk/NetAlertX?color=40ba12&label=Committed&logo=GitHub&logoColor=fff)](https://github.com/jokob-sk/NetAlertX)
[![Docker Size](https://img.shields.io/docker/image-size/jokobsk/netalertx?label=Size&logo=Docker&color=0aa8d2&logoColor=fff)](https://hub.docker.com/r/jokobsk/netalertx)
[![Docker Pulls](https://img.shields.io/docker/pulls/jokobsk/netalertx?label=Pulls&logo=docker&color=0aa8d2&logoColor=fff)](https://hub.docker.com/r/jokobsk/netalertx)
![GitHub Release](https://img.shields.io/github/v/release/jokob-sk/NetAlertX?color=0aa8d2&logoColor=fff&logo=GitHub)
[![GitHub Sponsors](https://img.shields.io/github/sponsors/jokob-sk?style=social)](https://github.com/sponsors/jokob-sk)
# PiAlert 💻🔍 Network security scanner & notification framework
# NetAlertX 💻🔍 Network security scanner & notification framework
| 🐳 [Docker hub](https://registry.hub.docker.com/r/jokobsk/pi.alert) | 📑 [Docker guide](https://github.com/jokob-sk/Pi.Alert/blob/main/dockerfiles/README.md) |🆕 [Release notes](https://github.com/jokob-sk/Pi.Alert/releases) | 📚 [All Docs](https://github.com/jokob-sk/Pi.Alert/tree/main/docs) |
| 🐳 [Docker hub](https://registry.hub.docker.com/r/jokobsk/netalertx) | 📑 [Docker guide](https://github.com/jokob-sk/NetAlertX/blob/main/dockerfiles/README.md) |🆕 [Release notes](https://github.com/jokob-sk/NetAlertX/releases) | 📚 [All Docs](https://github.com/jokob-sk/NetAlertX/tree/main/docs) |
|----------------------|----------------------| ----------------------| ----------------------|
<a href="https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/docs/img/devices_split.png" target="_blank">
<img src="https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/docs/img/devices_split.png" width="300px" />
</a>
<a href="https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/docs/img/network.png" target="_blank">
<img src="https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/docs/img/network.png" width="300px" />
<a href="https://raw.githubusercontent.com/jokob-sk/NetAlertX/main/docs/img/GENERAL/github_social_image.jpg" target="_blank">
<img src="https://raw.githubusercontent.com/jokob-sk/NetAlertX/main/docs/img/GENERAL/github_social_image.jpg" width="1000px" />
</a>
> [!NOTE]
> There is also an experimental 🧪 [bare-metal install](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/HW_INSTALL.md) method available.
> There is also an experimental 🧪 [bare-metal install](https://github.com/jokob-sk/NetAlertX/blob/main/docs/HW_INSTALL.md) method available.
## 📕 Basic Usage
- You will have to run the container on the `host` network, e.g:
> [!WARNING]
> You will have to run the container on the `host` network.
```yaml
docker run -d --rm --network=host \
-v local/path/pialert/config:/home/pi/pialert/config \
-v local/path/pialert/db:/home/pi/pialert/db \
-v local/path/config:/app/config \
-v local/path/db:/app/db \
-e TZ=Europe/Berlin \
-e PORT=20211 \
jokobsk/pi.alert:latest
jokobsk/netalertx:latest
```
- The initial scan can take up to 15min (with 50 devices and MQTT). Subsequent ones 3 and 5 minutes so wait that long for all of the scans to run.
@@ -40,53 +38,42 @@ docker run -d --rm --network=host \
| `PORT` |Port of the web interface | `20211` |
| `LISTEN_ADDR` |Set the specific IP Address for the listener address for the nginx webserver (web interface). This could be useful when using multiple subnets to hide the web interface from all untrusted networks. | `0.0.0.0` |
|`TZ` |Time zone to display stats correctly. Find your time zone [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) | `Europe/Berlin` |
|`HOST_USER_GID` |User ID (UID) to map the user in the container to a server user with sufficient read&write permissions on the mapped files | `1000` |
|`HOST_USER_ID` |User Group ID (GID) to map the user group in the container to a server user group with sufficient read&write permissions on the mapped files | `1000` |
|`ALWAYS_FRESH_INSTALL` | Setting `ALWAYS_FRESH_INSTALL=true` will delete the content of the `/db` & `/config` folders. For testing purposes. Can be coupled with [watchtower](https://github.com/containrrr/watchtower) to have an always freshly installed `pi.alert`/`_dev` image. | `N/A` |
|`ALWAYS_FRESH_INSTALL` | Setting `ALWAYS_FRESH_INSTALL=true` will delete the content of the `/db` & `/config` folders. For testing purposes. Can be coupled with [watchtower](https://github.com/containrrr/watchtower) to have an always freshly installed `netalertx`/`-dev` image. | `N/A` |
### Docker paths
> [!NOTE]
> See also [Backup strategies](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/BACKUPS.md).
> See also [Backup strategies](https://github.com/jokob-sk/NetAlertX/blob/main/docs/BACKUPS.md).
| Required | Path | Description |
| :------------- | :------------- | :-------------|
| ✅ | `:/home/pi/pialert/config` | Folder which will contain the `pialert.conf` & `devices.csv` ([read about devices.csv](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEVICES_BULK_EDITING.md)) files (see below for details) |
| ✅ | `:/home/pi/pialert/db` | Folder which will contain the `pialert.db` file |
| | `:/home/pi/pialert/front/log` | Logs folder useful for debugging if you have issues setting up the container |
| ✅ | `:/app/config` | Folder which will contain the `app.conf` & `devices.csv` ([read about devices.csv](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEVICES_BULK_EDITING.md)) files (see below for details). |
| ✅ | `:/app/db` | Folder which will contain the `app.db` file |
| | `:/app/front/log` | Logs folder useful for debugging if you have issues setting up the container |
| | `:/etc/pihole/pihole-FTL.db` | PiHole's `pihole-FTL.db` database file. Required if you want to use PiHole DB mapping. |
| | `:/etc/pihole/dhcp.leases` | PiHole's `dhcp.leases` file. Required if you want to use PiHole `dhcp.leases` file. This has to be matched with a corresponding `DHCPLSS_paths_to_check` setting entry (the path in the container must contain `pihole`)|
| | `:/home/pi/pialert/front/api` | A simple [API endpoint](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/API.md) containing static (but regularly updated) json and other files. |
| | `:/home/pi/pialert/front/plugins/<plugin>/ignore_plugin` | Map a file `ignore_plugin` to ignore a plugin. Plugins can be soft-disabled via settings. More in the [Plugin docs](https://github.com/jokob-sk/Pi.Alert/blob/main/front/plugins/README.md). |
| | `:/etc/resolv.conf` | Use a custom `resolv.conf` file for [better name resolution](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/REVERSE_DNS.md). |
| | `:/app/front/api` | A simple [API endpoint](https://github.com/jokob-sk/NetAlertX/blob/main/docs/API.md) containing static (but regularly updated) json and other files. |
| | `:/app/front/plugins/<plugin>/ignore_plugin` | Map a file `ignore_plugin` to ignore a plugin. Plugins can be soft-disabled via settings. More in the [Plugin docs](https://github.com/jokob-sk/NetAlertX/blob/main/front/plugins/README.md). |
| | `:/etc/resolv.conf` | Use a custom `resolv.conf` file for [better name resolution](https://github.com/jokob-sk/NetAlertX/blob/main/docs/REVERSE_DNS.md). |
> Use separate `db` and `config` directories, don't nest them.
### Modify the config (`pialert.conf`) only if UI is not available
### (If UI is not available) Modify the config (`app.conf`)
- The preferred way is to manage the configuration via the Settings section in the UI.
- You can modify [pialert.conf](https://github.com/jokob-sk/Pi.Alert/tree/main/config) directly, if needed.
- If unavailable, the app generates a default `pialert.conf` and `pialert.db` file on the first run.
- You can modify [app.conf](https://github.com/jokob-sk/NetAlertX/tree/main/config) directly, if needed.
- If unavailable, the app generates a default `app.conf` and `app.db` file on the first run.
#### Important settings
### Important settings
These are the most important settings to get at least some output in your Devices screen. Usually, only one approach is used, but you should be able to combine these approaches.
These are the most important settings to get at least some output in your Devices screen. Usually, only one approach is used, but you can combine these approaches.
##### For arp-scan: ARPSCAN_RUN, SCAN_SUBNETS
| Scan method | Setting | Description |
| :------------- | :------------- | :-------------|
| arp-scan, nmap-scan | `SCAN_SUBNETS` | See the documentation on how [to setup SUBNETS, VLANs & limitations](https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md) |
| PiHole | `PIHOLE_RUN` | There are 2 approaches how to get PiHole devices imported. Via the PiHole import (`PIHOLE`) plugin or DHCP leases (`DHCPLSS`) plugin. The `PIHOLE` plugin requires you to map the PiHole database, as mentioned above. |
| dhcp.leases | `DHCPLSS_RUN` | You need to map `:/etc/myfiles/dhcp.leases` in the `docker-compose.yml` file if you enable this setting. This path has to be matched with a corresponding `DHCPLSS_paths_to_check` setting entry (check the [DHCPLSS plugin readme](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/dhcp_leases#overview) for details). |
- ❗ To use the arp-scan method, you need to set the `SCAN_SUBNETS` variable. See the documentation on how [to setup SUBNETS, VLANs & limitations](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/SUBNETS.md)
##### For pihole: PIHOLE_RUN, DHCPLSS_RUN
There are 2 approaches how to get PiHole devices imported. Via the PiHole import (PIHOLE) plugin or DHCP leases (DHCPLSS) plugin.
**PiHole (Device sync)**
* `PIHOLE_RUN`: You need to map `:/etc/pihole/pihole-FTL.db` in the `docker-compose.yml` file if you enable this setting.
**DHCP Leases (Device import)**
* `DHCPLSS_RUN`: You need to map `:/etc/pihole/dhcp.leases` in the `docker-compose.yml` file if you enable this setting.
* The above setting has to be matched with a corresponding `DHCPLSS_paths_to_check` setting entry (the path in the container must contain `pihole` as PiHole uses a different format of the `dhcp.leases` file).
> [!NOTE]
> It's recommended to use the same schedule interval for all plugins responsible for discovering new devices.
@@ -109,12 +96,12 @@ Use the official installation guides at first and use community content as suple
### **Common issues**
💡 Before creating a new issue, please check if a similar issue was [already resolved](https://github.com/jokob-sk/Pi.Alert/issues?q=is%3Aissue+is%3Aclosed).
💡 Before creating a new issue, please check if a similar issue was [already resolved](https://github.com/jokob-sk/NetAlertX/issues?q=is%3Aissue+is%3Aclosed).
⚠ Check also common issues and [debugging tips](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEBUG_TIPS.md).
⚠ Check also common issues and [debugging tips](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEBUG_TIPS.md).
> [!NOTE]
> You can bulk-update devices via the [CSV import method](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEVICES_BULK_EDITING.md).
> You can bulk-update devices via the [CSV import method](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEVICES_BULK_EDITING.md).
## 📄 docker-compose.yml Examples
@@ -123,22 +110,20 @@ Use the official installation guides at first and use community content as suple
```yaml
version: "3"
services:
pialert:
container_name: pialert
netalertx:
container_name: netalertx
# use the below line if you want to test the latest dev image
# image: "jokobsk/pi.alert_dev:latest"
image: "jokobsk/pi.alert:latest"
# image: "jokobsk/netalertx-dev:latest"
image: "jokobsk/netalertx:latest"
network_mode: "host"
restart: unless-stopped
volumes:
- local/path/pialert/config:/home/pi/pialert/config
- local/path/pialert/db:/home/pi/pialert/db
- local/path/config:/app/config
- local/path/db:/app/db
# (optional) useful for debugging if you have issues setting up the container
- local/path/logs:/home/pi/pialert/front/log
- local/path/logs:/app/front/log
environment:
- TZ=Europe/Berlin
- HOST_USER_ID=1000
- HOST_USER_GID=1000
- PORT=20211
```
@@ -149,19 +134,19 @@ To run the container execute: `sudo docker-compose up -d`
Example by [SeimuS](https://github.com/SeimusS).
```yaml
pialert:
container_name: PiAlert
hostname: PiAlert
netalertx:
container_name: NetAlertX
hostname: NetAlertX
privileged: true
# use the below line if you want to test the latest dev image
# image: "jokobsk/pi.alert_dev:latest"
image: jokobsk/pi.alert:latest
# image: "jokobsk/netalertx-dev:latest"
image: jokobsk/netalertx:latest
environment:
- TZ=Europe/Bratislava
restart: always
volumes:
- ./pialert/pialert_db:/home/pi/pialert/db
- ./pialert/pialert_config:/home/pi/pialert/config
- ./netalertx/db:/app/db
- ./netalertx/config:/app/config
network_mode: host
```
@@ -174,22 +159,20 @@ To run the container execute: `sudo docker-compose up -d`
```yaml
version: "3"
services:
pialert:
container_name: pialert
netalertx:
container_name: netalertx
# use the below line if you want to test the latest dev image
# image: "jokobsk/pi.alert_dev:latest"
image: "jokobsk/pi.alert:latest"
# image: "jokobsk/netalertx-dev:latest"
image: "jokobsk/netalertx:latest"
network_mode: "host"
restart: unless-stopped
volumes:
- ${APP_DATA_LOCATION}/pialert/config:/home/pi/pialert/config
- ${APP_DATA_LOCATION}/pialert/db/pialert.db:/home/pi/pialert/db/pialert.db
- ${APP_DATA_LOCATION}/netalertx/config:/app/config
- ${APP_DATA_LOCATION}/netalertx/db/:/app/db/
# (optional) useful for debugging if you have issues setting up the container
- ${LOGS_LOCATION}:/home/pi/pialert/front/log
- ${LOGS_LOCATION}:/app/front/log
environment:
- TZ=${TZ}
- HOST_USER_ID=${HOST_USER_ID}
- HOST_USER_GID=${HOST_USER_GID}
- PORT=${PORT}
```
@@ -205,8 +188,6 @@ LOGS_LOCATION=/path/to/docker_logs
#ENVIRONMENT VARIABLES
TZ=Europe/Paris
HOST_USER_ID=1000
HOST_USER_GID=1000
PORT=20211
#DEVELOPMENT VARIABLES
@@ -218,13 +199,13 @@ To run the container execute: `sudo docker-compose --env-file /path/to/.env up`
### Example 4
Courtesy of [pbek](https://github.com/pbek). The volume `pialert_db` is used by the db directory. The two config files are mounted directly from a local folder to their places in the config folder. You can backup the `docker-compose.yaml` folder and the docker volumes folder.
Courtesy of [pbek](https://github.com/pbek). The volume `netalertx_db` is used by the db directory. The two config files are mounted directly from a local folder to their places in the config folder. You can backup the `docker-compose.yaml` folder and the docker volumes folder.
```yaml
pialert:
netalertx:
# use the below line if you want to test the latest dev image
# image: "jokobsk/pi.alert_dev:latest"
image: jokobsk/pi.alert
# image: "jokobsk/netalertx-dev:latest"
image: jokobsk/netalertx
ports:
- "80:20211/tcp"
environment:
@@ -234,22 +215,15 @@ Courtesy of [pbek](https://github.com/pbek). The volume `pialert_db` is used by
ipv4_address: 192.168.1.2
restart: unless-stopped
volumes:
- pialert_db:/home/pi/pialert/db
- ./pialert/pialert.conf:/home/pi/pialert/config/pialert.conf
- netalertx_db:/app/db
- ./netalertx/:/app/config/
```
## 🏅 Recognitions
Big thanks to <a href="https://github.com/Macleykun">@Macleykun</a> & for help and tips&tricks for Dockerfile(s) and <a href="https://github.com/vladaurosh">@vladaurosh</a> for Alpine re-base help.
Big thanks to <a href="https://github.com/Macleykun">@Macleykun</a> & for help and tips & tricks for Dockerfile(s) and <a href="https://github.com/vladaurosh">@vladaurosh</a> for Alpine re-base help.
## ❤ Support me
Get:
- Regular updates to keep your data and family safe 🔄
- Better and more functionality
- I don't get burned out and the app survives longer🔥🤯
- Quicker and better support with issues 🆘
- Less grumpy me 😄
## ❤ Support me
| [![GitHub](https://i.imgur.com/emsRCPh.png)](https://github.com/sponsors/jokob-sk) | [![Buy Me A Coffee](https://i.imgur.com/pIM6YXL.png)](https://www.buymeacoffee.com/jokobsk) | [![Patreon](https://i.imgur.com/MuYsrq1.png)](https://www.patreon.com/user?u=84385063) |
| --- | --- | --- |
@@ -257,4 +231,4 @@ Get:
- Bitcoin: `1N8tupjeCK12qRVU2XrV17WvKK7LCawyZM`
- Ethereum: `0x6e2749Cb42F4411bc98501406BdcD82244e3f9C7`
> 📧 Email me at [jokob@duck.com](mailto:jokob@duck.com?subject=PiAlert) if you want to get in touch or if I should add other sponsorship platforms.
> 📧 Email me at [jokob@duck.com](mailto:jokob@duck.com?subject=NetAlertX) if you want to get in touch or if I should add other sponsorship platforms.

View File

@@ -1,232 +0,0 @@
[![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)
[![Docker Size](https://img.shields.io/docker/image-size/jokobsk/pi.alert?label=Tamaño&logo=Docker&color=0aa8d2&logoColor=fff)](https://hub.docker.com/r/jokobsk/pi.alert)
[![Docker Pulls](https://img.shields.io/docker/pulls/jokobsk/pi.alert?label=Pulls&logo=docker&color=0aa8d2&logoColor=fff)](https://hub.docker.com/r/jokobsk/pi.alert)
[![Docker Pushed](https://img.shields.io/badge/dynamic/json?color=0aa8d2&logoColor=fff&label=Pushed&query=last_updated&url=https%3A%2F%2Fhub.docker.com%2Fv2%2Frepositories%2Fjokobsk%2Fpi.alert%2F&logo=docker&link=http://left&link=https://hub.docker.com/repository/docker/jokobsk/pi.alert)](https://hub.docker.com/r/jokobsk/pi.alert)
# 🐳 Una imagen docker para Pi.Alert
🐳 [Docker hub](https://registry.hub.docker.com/r/jokobsk/pi.alert) | 📑 [Instrucciones para Docker](https://github.com/jokob-sk/Pi.Alert/blob/main/dockerfiles/README.md) | 🆕 [Release notes](https://github.com/jokob-sk/Pi.Alert/releases) | 📚 [Todos los Docs](https://github.com/jokob-sk/Pi.Alert/tree/main/docs)
<a href="https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/docs/img/devices_split.png" target="_blank">
<img src="https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/docs/img/devices_split.png" width="300px" />
</a>
<a href="https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/docs/img/network.png" target="_blank">
<img src="https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/docs/img/network.png" width="300px" />
</a>
## 📕 Uso básico
- Tendrás que ejecutar el contenedor en la red del host, por ejemplo:
```yaml
docker run -d --rm --network=host \
-v local/path/pialert/config:/home/pi/pialert/config \
-v local/path/pialert/db:/home/pi/pialert/db \
-e TZ=Europe/Berlin \
-e PORT=20211 \
jokobsk/pi.alert:latest
```
- El escaneo inicial puede tardar hasta 15 minutos (con 50 dispositivos y MQTT). Los siguientes pueden durar entre 3 y 5 minutos, así que espere a que se ejecuten todos los escaneos.
### Variables de entorno Docker
| Variable | Descripción | Predeterminado |
| :------------- |:-------------| -----:|
| `PORT` |Puerto de la interfaz web | `20211` |
|`TZ` |Zona horaria para mostrar correctamente las estadísticas. Encuentre su zona horaria [aquí](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) | `Europe/Berlin` |
|`HOST_USER_GID` |ID de usuario (UID) para asignar el usuario del contenedor a un usuario del servidor con suficientes permisos de lectura y escritura en los archivos asignados | `1000` |
|`HOST_USER_ID` |ID de grupo de usuarios (GID) para asignar el grupo de usuarios del contenedor a un grupo de usuarios del servidor con suficientes permisos de lectura y escritura en los archivos asignados | `1000` |
### Rutas Docker
| | Ruta | Descripción |
| :------------- | :------------- |:-------------|
| **Obligatorio** | `:/home/pi/pialert/config` | Carpeta que contendrá el archivo `pialert.conf` (para más detalles, véase más abajo) |
| **Obligatorio** | `:/home/pi/pialert/db` | Carpeta que contendrá el archivo `pialert.db` |
|Opcional| `:/home/pi/pialert/front/log` | Carpeta de registros útil para depurar si tiene problemas al configurar el contenedor |
|Opcional| `:/etc/pihole/pihole-FTL.db` | Archivo de base de datos `pihole-FTL.db` de PiHole. Necesario si desea utilizar PiHole |
|Opcional| `:/etc/pihole/dhcp.leases` | Archivo `dhcp.leases` de PiHole. Obligatorio si desea utilizar el archivo `dhcp.leases` de PiHole. Tiene que coincidir con la correspondiente entrada de configuración `DHCPLSS_paths_to_check`. (La ruta en el contenedor debe contener `pihole`)|
|Opcional| `:/home/pi/pialert/front/api` | Una simple [API endpoint](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/API.md) que contiene archivos json estáticos (pero actualizados regularmente) y otros archivos. |
### Configurar (`pialert.conf`)
- Si no está disponible, la aplicación genera un archivo `pialert.conf` y `pialert.db` por defecto en la primera ejecución.
- La forma preferida es gestionar la configuración a través de la sección "Configuración" de la interfaz de usuario.
- Puede modificar [pialert.conf](https://github.com/jokob-sk/Pi.Alert/tree/main/config) directamente, si es necesario.
#### Ajustes importantes
Estos son los ajustes más importantes para obtener al menos alguna salida en la pantalla de tus Dispositivos. Por lo general, sólo se utiliza un enfoque, pero usted debe ser capaz de combinar estos enfoques.
##### Para arp-scan: ARPSCAN_RUN, SCAN_SUBNETS
- ❗ Para usar el método arp-scan, necesitas configurar la variable `SCAN_SUBNETS`. Consulte la documentación sobre cómo [configurar SUBNETS, VLANs y limitaciones](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/SUBNETS.md)
##### Para pihole: PIHOLE_RUN, DHCPLSS_RUN
Hay dos maneras de importar dispositivos PiHole. A través del plugin de importación PiHole (PIHOLE) o del plugin DHCP leases (DHCPLSS).
**PiHole (Sincronización de dispositivos)**
* `PIHOLE_RUN`: Necesitas mapear `:/etc/pihole/pihole-FTL.db` en el fichero `docker-compose.yml` si activas esta opción.
**DHCP Leases (Importación de dispositivos)**
* `DHCPLSS_RUN`: Es necesario mapear `:/etc/pihole/dhcp.leases` en el fichero `docker-compose.yml` si se activa esta opción.
* La configuración anterior tiene que coincidir con una entrada de configuración correspondiente `DHCPLSS_paths_to_check` (la ruta en el contenedor debe contener `pihole` ya que PiHole utiliza un formato diferente del archivo `dhcp.leases`).
> Se recomienda utilizar el mismo intervalo de programación para todos los plugins responsables de descubrir nuevos dispositivos.
### **Problemas comunes**
💡 Antes de crear una nueva incidencia, comprueba si ya se ha resuelto una [incidencia similar](https://github.com/jokob-sk/Pi.Alert/issues?q=is%3Aissue+is%3Aclosed).
⚠ Compruebe también los problemas comunes y los [consejos de depuración](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEBUG_TIPS.md).
## 📄 Ejemplos
### Ejemplo 1
```yaml
version: "3"
services:
pialert:
container_name: pialert
# Utilice la siguiente línea si desea probar la última imagen de desarrollo
# image: "jokobsk/pi.alert_dev:latest"
image: "jokobsk/pi.alert:latest"
network_mode: "host"
restart: unless-stopped
volumes:
- local/path/pialert/config:/home/pi/pialert/config
- local/path/pialert/db:/home/pi/pialert/db
# (optional) useful for debugging if you have issues setting up the container
- local/path/logs:/home/pi/pialert/front/log
environment:
- TZ=Europe/Berlin
- HOST_USER_ID=1000
- HOST_USER_GID=1000
- PORT=20211
```
Para ejecutar el contenedor ejecute: `sudo docker-compose up -d`
### Ejemplo 2
Ejemplo de [SeimuS](https://github.com/SeimusS).
```yaml
pialert:
container_name: PiAlert
hostname: PiAlert
privileged: true
# Utilice la siguiente línea si desea probar la última imagen de desarrollo
# image: "jokobsk/pi.alert_dev:latest"
image: jokobsk/pi.alert:latest
environment:
- TZ=Europe/Bratislava
restart: always
volumes:
- ./pialert/pialert_db:/home/pi/pialert/db
- ./pialert/pialert_config:/home/pi/pialert/config
network_mode: host
```
Para ejecutar el contenedor ejecute: `sudo docker-compose up -d`
### Ejemplo 3
`docker-compose.yml`
```yaml
version: "3"
services:
pialert:
container_name: pialert
# Utilice la siguiente línea si desea probar la última imagen de desarrollo
# image: "jokobsk/pi.alert_dev:latest"
image: "jokobsk/pi.alert:latest"
network_mode: "host"
restart: unless-stopped
volumes:
- ${APP_DATA_LOCATION}/pialert/config:/home/pi/pialert/config
- ${APP_DATA_LOCATION}/pialert/db/pialert.db:/home/pi/pialert/db/pialert.db
# (optional) useful for debugging if you have issues setting up the container
- ${LOGS_LOCATION}:/home/pi/pialert/front/log
environment:
- TZ=${TZ}
- HOST_USER_ID=${HOST_USER_ID}
- HOST_USER_GID=${HOST_USER_GID}
- PORT=${PORT}
```
`.env` file
```yaml
#VARIABLES DE RUTA GLOBAL
APP_DATA_LOCATION=/path/to/docker_appdata
APP_CONFIG_LOCATION=/path/to/docker_config
LOGS_LOCATION=/path/to/docker_logs
#VARIABLES DE ENTORNO
TZ=Europe/Paris
HOST_USER_ID=1000
HOST_USER_GID=1000
PORT=20211
#VARIABLES DE DESARROLLO
DEV_LOCATION=/path/to/local/source/code
```
Para ejecutar el contenedor ejecute: `sudo docker-compose --env-file /path/to/.env up`
### Example 4
Por cortesía de [pbek](https://github.com/pbek). El volumen `pialert_db` es utilizado por el directorio db. Los dos archivos de configuración se montan directamente desde una carpeta local a sus lugares en la carpeta config. Puedes hacer una copia de seguridad de la carpeta `docker-compose.yaml` y de la carpeta docker volumes.
```yaml
pialert:
# Utilice la siguiente línea si desea probar la última imagen de desarrollo
# image: "jokobsk/pi.alert_dev:latest"
image: jokobsk/pi.alert
ports:
- "80:20211/tcp"
environment:
- TZ=Europe/Vienna
networks:
local:
ipv4_address: 192.168.1.2
restart: unless-stopped
volumes:
- pialert_db:/home/pi/pialert/db
- ./pialert/pialert.conf:/home/pi/pialert/config/pialert.conf
```
## 🏅 Reconocimientos
Muchas gracias a <a href="https://github.com/Macleykun">@Macleykun</a> por ayudarme en consejos y trucos para Dockerfile(s):
<a href="https://github.com/Macleykun">
<img src="https://avatars.githubusercontent.com/u/26381427?size=50">
</a>
Muchas gracias a <a href="https://github.com/cvc90">@cvc90</a> por ayudarme y realizar esta traduccion:
<a href="https://github.com/cvc90">
<img src="https://avatars.githubusercontent.com/u/76731844?size=50">
</a>
## ☕ Apóyame
<a href="https://github.com/sponsors/jokob-sk" target="_blank"><img src="https://i.imgur.com/X6p5ACK.png" alt="Sponsor Me on GitHub" style="height: 30px !important;width: 117px !important;" width="150px" ></a>
<a href="https://www.buymeacoffee.com/jokobsk" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 30px !important;width: 117px !important;" width="117px" height="30px" ></a>
<a href="https://www.patreon.com/user?u=84385063" target="_blank"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/8/82/Patreon_logo_with_wordmark.svg/512px-Patreon_logo_with_wordmark.svg.png" alt="Support me on patreon" style="height: 30px !important;width: 117px !important;" width="117px" ></a>
BTC: 1N8tupjeCK12qRVU2XrV17WvKK7LCawyZM

View File

@@ -1,31 +1,41 @@
#!/bin/bash
export INSTALL_DIR=/home/pi
export INSTALL_DIR=/app
export APP_NAME=netalertx
# php-fpm setup
install -d -o nginx -g www-data /run/php/
sed -i "/^;pid/c\pid = /run/php/php8.2-fpm.pid" /etc/php82/php-fpm.conf
sed -i "/^listen/c\listen = /run/php/php8.2-fpm.sock" /etc/php82/php-fpm.d/www.conf
sed -i "/^;listen.owner/c\listen.owner = nginx" /etc/php82/php-fpm.d/www.conf
sed -i "/^;listen.group/c\listen.group = www-data" /etc/php82/php-fpm.d/www.conf
sed -i "/^user/c\user = nginx" /etc/php82/php-fpm.d/www.conf
sed -i "/^group/c\group = www-data" /etc/php82/php-fpm.d/www.conf
sed -i "/^;pid/c\pid = /run/php/php8.3-fpm.pid" /etc/php83/php-fpm.conf
sed -i "/^listen/c\listen = /run/php/php8.3-fpm.sock" /etc/php83/php-fpm.d/www.conf
sed -i "/^;listen.owner/c\listen.owner = nginx" /etc/php83/php-fpm.d/www.conf
sed -i "/^;listen.group/c\listen.group = www-data" /etc/php83/php-fpm.d/www.conf
sed -i "/^user/c\user = nginx" /etc/php83/php-fpm.d/www.conf
sed -i "/^group/c\group = www-data" /etc/php83/php-fpm.d/www.conf
# s6 overlay setup
mkdir -p /etc/s6-overlay/s6-rc.d/{SetupOneshot,php-fpm/dependencies.d,nginx/dependencies.d}
mkdir -p /etc/s6-overlay/s6-rc.d/{SetupOneshot,php-fpm/dependencies.d,nginx/dependencies.d,pialert/dependencies.d}
mkdir -p /etc/s6-overlay/s6-rc.d/{SetupOneshot,php-fpm/dependencies.d,nginx/dependencies.d,$APP_NAME/dependencies.d}
echo "oneshot" > /etc/s6-overlay/s6-rc.d/SetupOneshot/type
echo "longrun" > /etc/s6-overlay/s6-rc.d/php-fpm/type
echo "longrun" > /etc/s6-overlay/s6-rc.d/nginx/type
echo "longrun" > /etc/s6-overlay/s6-rc.d/pialert/type
echo -e "${INSTALL_DIR}/pialert/dockerfiles/setup.sh" > /etc/s6-overlay/s6-rc.d/SetupOneshot/up
echo -e "#!/bin/execlineb -P\n/usr/sbin/php-fpm82 -F" > /etc/s6-overlay/s6-rc.d/php-fpm/run
echo "longrun" > /etc/s6-overlay/s6-rc.d/$APP_NAME/type
echo -e "${INSTALL_DIR}/dockerfiles/setup.sh" > /etc/s6-overlay/s6-rc.d/SetupOneshot/up
echo -e "#!/bin/execlineb -P\n/usr/sbin/php-fpm83 -F" > /etc/s6-overlay/s6-rc.d/php-fpm/run
echo -e '#!/bin/execlineb -P\nnginx -g "daemon off;"' > /etc/s6-overlay/s6-rc.d/nginx/run
echo -e '#!/bin/execlineb -P\n\nwith-contenv\nimportas -i PORT PORT\nif { echo "[INSTALL] 🚀 Starting app - navigate to your <server IP>:${PORT}" }' > /etc/s6-overlay/s6-rc.d/pialert/run
echo -e "python ${INSTALL_DIR}/pialert/pialert" >> /etc/s6-overlay/s6-rc.d/pialert/run
echo -e '#!/bin/execlineb -P
with-contenv
importas -u PORT PORT
if { echo
"
[INSTALL] 🚀 Starting app (:${PORT})
" }' > /etc/s6-overlay/s6-rc.d/$APP_NAME/run
echo -e "python ${INSTALL_DIR}/server" >> /etc/s6-overlay/s6-rc.d/$APP_NAME/run
touch /etc/s6-overlay/s6-rc.d/user/contents.d/{SetupOneshot,php-fpm,nginx} /etc/s6-overlay/s6-rc.d/{php-fpm,nginx}/dependencies.d/SetupOneshot
touch /etc/s6-overlay/s6-rc.d/user/contents.d/{SetupOneshot,php-fpm,nginx,pialert} /etc/s6-overlay/s6-rc.d/{php-fpm,nginx,pialert}/dependencies.d/SetupOneshot
touch /etc/s6-overlay/s6-rc.d/user/contents.d/{SetupOneshot,php-fpm,nginx,$APP_NAME} /etc/s6-overlay/s6-rc.d/{php-fpm,nginx,$APP_NAME}/dependencies.d/SetupOneshot
touch /etc/s6-overlay/s6-rc.d/nginx/dependencies.d/php-fpm
touch /etc/s6-overlay/s6-rc.d/pialert/dependencies.d/nginx
touch /etc/s6-overlay/s6-rc.d/$APP_NAME/dependencies.d/nginx
rm -f $0

View File

@@ -4,12 +4,20 @@ echo "---------------------------------------------------------"
echo "[INSTALL] Run setup.sh"
echo "---------------------------------------------------------"
export INSTALL_DIR=/home/pi # Specify the installation directory here
export INSTALL_DIR=/app # Specify the installation directory here
# DO NOT CHANGE ANYTHING BELOW THIS LINE!
NGINX_CONFIG_FILE=/etc/nginx/http.d/pialert.conf
CONF_FILE="app.conf"
NGINX_CONF_FILE=netalertx.conf
DB_FILE="app.db"
FULL_FILEDB_PATH="${INSTALL_DIR}/db/${DB_FILE}"
NGINX_CONFIG_FILE="/etc/nginx/http.d/${NGINX_CONF_FILE}"
OUI_FILE="/usr/share/arp-scan/ieee-oui.txt" # Define the path to ieee-oui.txt and ieee-iab.txt
FILEDB="${INSTALL_DIR}/pialert/db/pialert.db"
INSTALL_DIR_OLD=/home/pi/pialert
OLD_APP_NAME=pialert
# DO NOT CHANGE ANYTHING ABOVE THIS LINE!
# Check if script is run as root
@@ -18,32 +26,52 @@ if [[ $EUID -ne 0 ]]; then
exit 1
fi
echo "[INSTALL] Copy starter pialert.db and pialert.conf if they don't exist"
echo "[INSTALL] Copy starter ${DB_FILE} and ${CONF_FILE} if they don't exist"
# DANGER ZONE: ALWAYS_FRESH_INSTALL
# DANGER ZONE: ALWAYS_FRESH_INSTALL
if [ "$ALWAYS_FRESH_INSTALL" = true ]; then
echo "[INSTALL] ❗ ALERT /db and /config folders are cleared because the ALWAYS_FRESH_INSTALL is set to: $ALWAYS_FRESH_INSTALL"
# Delete content of "$INSTALL_DIR/pialert/config/"
rm -rf "$INSTALL_DIR/pialert/config/"*
# Delete content of "$INSTALL_DIR/pialert/db/"
rm -rf "$INSTALL_DIR/pialert/db/"*
# Delete content of "$INSTALL_DIR/config/"
rm -rf "$INSTALL_DIR/config/"*
rm -rf "$INSTALL_DIR_OLD/config/"*
# Delete content of "$INSTALL_DIR/db/"
rm -rf "$INSTALL_DIR/db/"*
rm -rf "$INSTALL_DIR_OLD/db/"*
fi
# Copy starter pialert.db and pialert.conf if they don't exist
cp -na "${INSTALL_DIR}/pialert/back/pialert.conf" "${INSTALL_DIR}/pialert/config/pialert.conf"
cp -na "${INSTALL_DIR}/pialert/back/pialert.db" "${FILEDB}"
# 🔻 FOR BACKWARD COMPATIBILITY - REMOVE AFTER 12/12/2024
# Check if pialert.db exists, then create a symbolic link to app.db
if [ -f "${INSTALL_DIR_OLD}/db/${OLD_APP_NAME}.db" ]; then
ln -s "${INSTALL_DIR_OLD}/db/${OLD_APP_NAME}.db" "${FULL_FILEDB_PATH}"
fi
# Check if ${OLD_APP_NAME}.conf exists, then create a symbolic link to app.conf
if [ -f "${INSTALL_DIR_OLD}/config/${OLD_APP_NAME}.conf" ]; then
ln -s "${INSTALL_DIR_OLD}/config/${OLD_APP_NAME}.conf" "${INSTALL_DIR}/config/${CONF_FILE}"
fi
# 🔺 FOR BACKWARD COMPATIBILITY - REMOVE AFTER 12/12/2024
# Copy starter .db and .conf if they don't exist
cp -na "${INSTALL_DIR}/back/${CONF_FILE}" "${INSTALL_DIR}/config/${CONF_FILE}"
cp -na "${INSTALL_DIR}/back/${DB_FILE}" "${FULL_FILEDB_PATH}"
# if custom variables not set we do not need to do anything
if [ -n "${TZ}" ]; then
FILECONF="${INSTALL_DIR}/pialert/config/pialert.conf"
FILECONF="${INSTALL_DIR}/config/${CONF_FILE}"
echo "[INSTALL] Setup timezone"
sed -i "\#^TIMEZONE=#c\TIMEZONE='${TZ}'" "${FILECONF}"
# set TimeZone in container
cp /usr/share/zoneinfo/$TZ /etc/localtime
echo $TZ > /etc/timezone
fi
echo "[INSTALL] Setup NGINX"
echo "Setting webserver to address ($LISTEN_ADDR) and port ($PORT)"
envsubst '$INSTALL_DIR $LISTEN_ADDR $PORT' < "${INSTALL_DIR}/pialert/install/pialert.template.conf" > "${NGINX_CONFIG_FILE}"
envsubst '$INSTALL_DIR $LISTEN_ADDR $PORT' < "${INSTALL_DIR}/install/netalertx.template.conf" > "${NGINX_CONFIG_FILE}"
# Run the hardware vendors update at least once
echo "[INSTALL] Run the hardware vendors update"
@@ -55,25 +83,36 @@ else
echo "The file ieee-oui.txt does not exist. Running update_vendors..."
# Run the update_vendors.sh script
if [ -f "${INSTALL_DIR}/pialert/back/update_vendors.sh" ]; then
"${INSTALL_DIR}/pialert/back/update_vendors.sh"
if [ -f "${INSTALL_DIR}/back/update_vendors.sh" ]; then
"${INSTALL_DIR}/back/update_vendors.sh"
else
echo "update_vendors.sh script not found in ${INSTALL_DIR}."
fi
fi
# Create an empty log files
# Create the execution_queue.log and pialert_front.log files if they don't exist
touch "${INSTALL_DIR}"/pialert/front/log/{execution_queue.log,pialert_front.log,pialert.php_errors.log,stderr.log,stdout.log}
# Create the execution_queue.log and app_front.log files if they don't exist
touch "${INSTALL_DIR}"/front/log/{app.log,execution_queue.log,app_front.log,app.php_errors.log,stderr.log,stdout.log,db_is_locked.log}
touch "${INSTALL_DIR}"/front/api/user_notifications.json
echo "[INSTALL] Fixing permissions after copied starter config & DB"
chown -R nginx:www-data "${INSTALL_DIR}"/pialert/{config,front/log,db}
chmod 750 "${INSTALL_DIR}"/pialert/{config,front/log,db}
chmod 640 "${INSTALL_DIR}"/pialert/{config,front/log,db}/*
chown -R nginx:www-data "${INSTALL_DIR}"/{config,front/log,db,front/api}
chown -R nginx:www-data "${INSTALL_DIR}"/front/api/user_notifications.json
chmod 750 "${INSTALL_DIR}"/{config,front/log,db}
find "${INSTALL_DIR}"/{config,front/log,db} -type f -exec chmod 640 {} \;
# Check if buildtimestamp.txt doesn't exist
if [ ! -f "${INSTALL_DIR}/pialert/front/buildtimestamp.txt" ]; then
if [ ! -f "${INSTALL_DIR}/front/buildtimestamp.txt" ]; then
# Create buildtimestamp.txt
date +%s > "${INSTALL_DIR}/pialert/front/buildtimestamp.txt"
chown nginx:www-data "${INSTALL_DIR}/pialert/front/buildtimestamp.txt"
date +%s > "${INSTALL_DIR}/front/buildtimestamp.txt"
chown nginx:www-data "${INSTALL_DIR}/front/buildtimestamp.txt"
fi
echo -e "
[ENV] PATH is ${PATH}
[ENV] PORT is ${PORT}
[ENV] TZ is ${TZ}
[ENV] LISTEN_ADDR is ${LISTEN_ADDR}
[ENV] ALWAYS_FRESH_INSTALL is ${ALWAYS_FRESH_INSTALL}
"

View File

@@ -1,6 +1,6 @@
## API endpoints
PiAlert comes with a simple API. These API endpoints are static files, that are periodically updated based on your settings.
NetAlertX comes with a simple API. These API endpoints are static files, that are periodically updated based on your settings.
### When are the endpoints updated
@@ -9,7 +9,7 @@ The endpoints are updated when objects in the API endpoints are changed.
### Location of the endpoints
In the container, these files are located under the `/home/pi/pialert/front/api/` folder and thus on the `<pialert_url>/api/<File name>` url.
In the container, these files are located under the `/app/front/api/` folder and thus on the `<netalertx_url>/api/<File name>` url.
### Available endpoints
@@ -19,12 +19,12 @@ You can access the following files:
|----------------------|----------------------|
| `notification_text.txt` | The plain text version of the last notification. |
| `notification_text.html` | The full HTML of the last email notification. |
| `notification_json_final.json` | The json version of the last notification (e.g. used for webhooks - [sample JSON](https://github.com/jokob-sk/Pi.Alert/blob/main/back/webhook_json_sample.json)). |
| `notification_json_final.json` | The json version of the last notification (e.g. used for webhooks - [sample JSON](https://github.com/jokob-sk/NetAlertX/blob/main/front/report_templates/webhook_json_sample.json)). |
| `table_devices.json` | The current (at the time of the last update as mentioned above on this page) state of all of the available Devices detected by the app. |
| `table_pholus_scan.json` | The latest state of the [pholus](https://github.com/jokob-sk/Pi.Alert/tree/main/pholus) (A multicast DNS and DNS Service Discovery Security Assessment Tool) scan results. |
| `table_pholus_scan.json` | The latest state of the [pholus](https://github.com/jokob-sk/NetAlertX/tree/main/pholus) (A multicast DNS and DNS Service Discovery Security Assessment Tool) scan results. |
| `table_plugins_events.json` | The list of the unprocessed (pending) notification events (plugins_events DB table). |
| `table_plugins_history.json` | The list of notification events history. |
| `table_plugins_objects.json` | The content of the plugins_objects table. Find more info on the [Plugin system here](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins)|
| `table_plugins_objects.json` | The content of the plugins_objects table. Find more info on the [Plugin system here](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins)|
| `language_strings.json` | The content of the language_strings table, which in turn is loaded from the plugins `config.json` definitions. |
| `table_custom_endpoint.json` | A custom endpoint generated by the SQL query specified by the `API_CUSTOM_SQL` setting. |
| `table_settings.json` | The content of the settings table. |

View File

@@ -7,8 +7,8 @@ There are 3 artifacts that can be used to backup the application:
| File | Description | Limitations |
|-----------------------|-------------------------------|-------------------------------|
| `/db/pialert.db` | Database file(s) | The database file might be in an uncommitted state or corrupted |
| `/config/pialert.conf` | Configuration file | Doesn't contain settings from the Maintenance section |
| `/db/app.db` | Database file(s) | The database file might be in an uncommitted state or corrupted |
| `/config/app.conf` | Configuration file | Doesn't contain settings from the Maintenance section |
| `/config/devices.csv` | CSV file containing device information | Doesn't contain historical data |
## Data and cackup storage
@@ -17,7 +17,7 @@ To decide on a backup strategy, check where the data is stored:
### Core Configuration
The core application configuration is in the `pialert.conf` file (See [Settings System](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/SETTINGS_SYSTEM.md) for details), such as:
The core application configuration is in the `app.conf` file (See [Settings System](https://github.com/jokob-sk/NetAlertX/blob/main/docs/SETTINGS_SYSTEM.md) for details), such as:
- Notification settings
- Scanner settings
@@ -26,7 +26,7 @@ The core application configuration is in the `pialert.conf` file (See [Settings
### Core Device Data
The core device data is backed up to the `devices_<timestamp>.csv` file via the [CSV Backup `CSVBCKP` Plugin](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins/csv_backup). This file contains data, such as:
The core device data is backed up to the `devices_<timestamp>.csv` file via the [CSV Backup `CSVBCKP` Plugin](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/csv_backup). This file contains data, such as:
- Device names
- Device Icons
@@ -35,7 +35,7 @@ The core device data is backed up to the `devices_<timestamp>.csv` file via the
### Historical data
Historical data is stored in the `pialert.db` database (See [Database overview](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DATABASE.md) for details). This data includes:
Historical data is stored in the `app.db` database (See [Database overview](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DATABASE.md) for details). This data includes:
- Plugin objects
- Plugin historical entries
@@ -46,7 +46,7 @@ Historical data is stored in the `pialert.db` database (See [Database overview](
The safest approach to backups is to backup all of the above, by taking regular file system backups (I use [Kopia](https://github.com/kopia/kopia)).
Arguably, the most time is spent setting up the device list, so if only one file is kept I'd recommend to have a latest backup of the `devices_<timestamp>.csv` file, followed by the `pialert.conf` file.
Arguably, the most time is spent setting up the device list, so if only one file is kept I'd recommend to have a latest backup of the `devices_<timestamp>.csv` file, followed by the `app.conf` file.
### Scenario 1: Full backup
@@ -54,12 +54,12 @@ End-result: Full restore
#### Source artifacts:
- `/db/pialert.db` (uncorrupted)
- `/config/pialert.conf`
- `/db/app.db` (uncorrupted)
- `/config/app.conf`
#### Recovery:
To restore the application map the above files as described in the [Setup documentation](https://github.com/jokob-sk/Pi.Alert/blob/main/dockerfiles/README.md#docker-paths).
To restore the application map the above files as described in the [Setup documentation](https://github.com/jokob-sk/NetAlertX/blob/main/dockerfiles/README.md#docker-paths).
### Scenario 2: Corrupted database
@@ -68,15 +68,15 @@ End-result: Partial restore (historical data & configurations from the Maintenan
#### Source artifacts:
- `/config/pialert.conf`
- `/config/app.conf`
- `/config/devices_<timestamp>.csv` or `/config/devices.csv`
#### Recovery:
Even with a corrupted database you can recover what I would argue is 99% of the configuration (except of a couple of settings under Maintenance).
- map the `/config/pialert.conf` file as described in the [Setup documentation](https://github.com/jokob-sk/Pi.Alert/blob/main/dockerfiles/README.md#docker-paths).
- map the `/config/app.conf` file as described in the [Setup documentation](https://github.com/jokob-sk/NetAlertX/blob/main/dockerfiles/README.md#docker-paths).
- rename the `devices_<timestamp>.csv` to `devices.csv` and place it in the `/config` folder
- Restore the `devices.csv` backup via the [Maintenance section](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEVICES_BULK_EDITING.md)
- Restore the `devices.csv` backup via the [Maintenance section](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEVICES_BULK_EDITING.md)

View File

@@ -1,5 +1,5 @@
# A high-level description of the datbase structure
# A high-level description of the database structure
⚠ Disclaimer: As I'm not the original author, some of the information might be inaccurate. Feel free to submit a PR to correct anything within this page or documentation in general.
@@ -20,7 +20,7 @@
| 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] |
| 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] |
| Settings | Database representation of the sum of all settings from `app.conf` and plugins coming from `config.json` files. | ![Screen16][screen16] |

View File

@@ -8,9 +8,9 @@ Check the the HTTP response of the failing backend call by following these steps
![F12DeveloperConsole][F12DeveloperConsole]
- Copy the URL causing the error and enter it in the address bar of your browser directly and hit enter. The copied URLs could look something like this (notice the query strings at the end):
- `http://<pialert URL>:20211/api/table_devices.json?nocache=1704141103121`
- `http://<pialert URL>:20211/php/server/devices.php?action=getDevicesTotals`
- `http://<pialert URL>:20211/php/server/devices.php?action=getDevicesList&status=all`
- `http://<NetAlertX URL>:20211/api/table_devices.json?nocache=1704141103121`
- `http://<NetAlertX URL>:20211/php/server/devices.php?action=getDevicesTotals`
- `http://<NetAlertX URL>:20211/php/server/devices.php?action=getDevicesList&status=all`
- Post the error response in the existing issue thread on GitHub or create a new issue and include the redacted response of the failing query.

View File

@@ -4,12 +4,12 @@
If a Plugin supplies data to the main app it's doine either vie a SQL query or via a script that updates the `last_result.log` file in the plugin folder (`front/plugins/<plugin>`).
For a more in-depth overview on how plugins work check the [Plugins development docs](https://github.com/jokob-sk/Pi.Alert/blob/main/front/plugins/README.md).
For a more in-depth overview on how plugins work check the [Plugins development docs](https://github.com/jokob-sk/NetAlertX/blob/main/front/plugins/README.md).
### Prerequisites
- Make sure you read and followed the specific plugin setup instructions.
- Ensure you have [debug enabled (see More Logging)](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEBUG_TIPS.md#1-more-logging-)
- Ensure you have [debug enabled (see More Logging)](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEBUG_TIPS.md#1-more-logging-)
### Potential issues
@@ -19,7 +19,7 @@ For a more in-depth overview on how plugins work check the [Plugins development
#### Incorrect input data
Input data from the plugin might cause mapping issues in specific edge cases. Look for a corresponding section in the `pialert.log` file, for example notice the first line of the execution run of the `PIHOLE` plugin below:
Input data from the plugin might cause mapping issues in specific edge cases. Look for a corresponding section in the `app.log` file, for example notice the first line of the execution run of the `PIHOLE` plugin below:
```
17:31:05 [Scheduler] - Scheduler run for PIHOLE: YES
@@ -35,6 +35,7 @@ Input data from the plugin might cause mapping issues in specific edge cases. Lo
17:31:05 [Plugins] base64 value: b'MTkyLjE2OC4xLjAvMjQgLS1pbnRlcmZhY2U9ZXRoMQ=='
17:31:05 [Plugins] Timeout: 10
17:31:05 [Plugins] Executing: SELECT n.hwaddr AS Object_PrimaryID, 'null' AS Object_SecondaryID, datetime() AS DateTime, na.ip AS Watched_Value1, n.lastQuery AS Watched_Value2, na.name AS Watched_Value3, n.macVendor AS Watched_Value4, 'null' AS Extra, n.hwaddr AS ForeignKey FROM EXTERNAL_PIHOLE.Network AS n LEFT JOIN EXTERNAL_PIHOLE.Network_Addresses AS na ON na.network_id = n.id WHERE n.hwaddr NOT LIKE 'ip-%' AND n.hwaddr is not '00:00:00:00:00:00' AND na.ip is not null
🔻
17:31:05 [Plugins] SUCCESS, received 2 entries
17:31:05 [Plugins] sqlParam entries: [(0, 'PIHOLE', '01:01:01:01:01:01', 'null', 'null', '2023-12-25 06:31:05', '172.30.0.1', 0, 'aaaa', 'vvvvvvvvv', 'not-processed', 'null', 'null', '01:01:01:01:01:01'), (0, 'PIHOLE', '02:42:ac:1e:00:02', 'null', 'null', '2023-12-25 06:31:05', '172.30.0.2', 0, 'dddd', 'vvvvv2222', 'not-processed', 'null', 'null', '02:42:ac:1e:00:02')]
17:31:05 [Plugins] Processing : PIHOLE
@@ -52,10 +53,13 @@ Input data from the plugin might cause mapping issues in specific edge cases. Lo
17:31:05 [Plugins] Mapping objects to database table: CurrentScan
17:31:05 [Plugins] SQL query for mapping: INSERT into CurrentScan ( "cur_MAC", "cur_IP", "cur_LastQuery", "cur_Name", "cur_Vendor", "cur_ScanMethod") VALUES ( ?, ?, ?, ?, ?, ?)
17:31:05 [Plugins] SQL sqlParams for mapping: [('01:01:01:01:01:01', '172.30.0.1', 0, 'aaaa', 'vvvvvvvvv', 'PIHOLE'), ('02:42:ac:1e:00:02', '172.30.0.2', 0, 'dddd', 'vvvvv2222', 'PIHOLE')]
🔺
17:31:05 [API] Update API starting
17:31:06 [API] Updating table_plugins_history.json file in /front/api
```
> The debug output between the 🔻red arrows🔺 is important for debugging (arrows added only to highlight the section on this page, they are not available in the actual debug log)
In the above output notice the section logging how many events are produced by the plugin:
```

View File

@@ -15,11 +15,11 @@ Start the container via the **terminal** with a command similar to this one:
```bash
docker run --rm --network=host \
-v local/path/pialert/config:/home/pi/pialert/config \
-v local/path/pialert/db:/home/pi/pialert/db \
-v local/path/netalertx/config:/app/config \
-v local/path/netalertx/db:/app/db \
-e TZ=Europe/Berlin \
-e PORT=20211 \
jokobsk/pi.alert:latest
jokobsk/netalertx:latest
```
@@ -29,11 +29,11 @@ docker run --rm --network=host \
If possible, check if your issue got fixed in the `_dev` image before opening a new issue. The container is:
`jokobsk/pi.alert_dev:latest`
`jokobsk/netalertx-dev:latest`
> ⚠ Please backup your DB and config beforehand!
Please also search [open issues](https://github.com/jokob-sk/Pi.Alert/issues).
Please also search [open issues](https://github.com/jokob-sk/NetAlertX/issues).
## 4. Disable restart behavior 🛑
@@ -53,10 +53,9 @@ services:
### Permissions
* If facing issues (AJAX errors, can't write to DB, empty screen, etc,) make sure permissions are set correctly, and check the logs under `/home/pi/pialert/front/log`.
* To solve permission issues you can try setting the owner and group of the `pialert.db` by executing the following on the host system: `docker exec pialert chown -R www-data:www-data /home/pi/pialert/db/pialert.db`.
* Map to local User and Group IDs. Specify the enviroment variables `HOST_USER_ID` and `HOST_USER_GID` if needed.
* If still facing issues, try to map the pialert.db file (⚠ not folder) to `:/home/pi/pialert/db/pialert.db` (see [docker-compose Examples](https://github.com/jokob-sk/Pi.Alert/blob/main/dockerfiles/README.md#-docker-composeyml-examples) for details)
* If facing issues (AJAX errors, can't write to DB, empty screen, etc,) make sure permissions are set correctly, and check the logs under `/app/front/log`.
* To solve permission issues you can try setting the owner and group of the `app.db` by executing the following on the host system: `docker exec netalertx chown -R www-data:www-data /app/db/app.db`.
* If still facing issues, try to map the app.db file (⚠ not folder) to `:/app/db/app.db` (see [docker-compose Examples](https://github.com/jokob-sk/NetAlertX/blob/main/dockerfiles/README.md#-docker-composeyml-examples) for details)
### Container restarts / crashes

View File

@@ -20,7 +20,7 @@ You can select devices in the _Devices_ view by selecting devices to edit and th
![Maintenance > CSV Export](/docs/img/DEVICES_BULK_EDITING/MAINTENANCE_CSV_EXPORT.png)
> [!NOTE]
> The file containing a list of Devices including the Network relationships between Network Nodes and connected devices. You can also trigger this by acessing this URL: `<your pialert url>/php/server/devices.php?action=ExportCSV` or via the `CSV Backup` plugin. (💡 You can schedule this)
> The file containing a list of Devices including the Network relationships between Network Nodes and connected devices. You can also trigger this by acessing this URL: `<your netalertx url>/php/server/devices.php?action=ExportCSV` or via the `CSV Backup` plugin. (💡 You can schedule this)
![Settings > CSV Backup](/docs/img/DEVICES_BULK_EDITING/CSV_BACKUP_SETTINGS.png)

View File

@@ -1,4 +1,4 @@
# Pi.Alert - Device Management
# NetAlertX - Device Management
<!--- --------------------------------------------------------------------- --->
To edit device information:
- Select "Devices" in the menu on the left of the screen
@@ -11,7 +11,7 @@ To edit device information:
> [!NOTE]
>
> [Bulk-edit devices](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEVICES_BULK_EDITING.md) by using the _CSV Export_ functionality in the _Maintenance_ section.
> [Bulk-edit devices](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEVICES_BULK_EDITING.md) by using the _CSV Export_ functionality in the _Maintenance_ section.
![Device Details][screen1]
@@ -23,7 +23,7 @@ To edit device information:
- **Owner**: Device owner (The list is self-populated with existing owners)
- **Type**: Select a device type from the dropdown list (Smartphone, Table,
Laptop, TV, router, ....) or type a new device type
- **Vendor**: Automatically updated by Pi.Alert when empty or unknown
- **Vendor**: Automatically updated by NetAlertX when empty or unknown
- **Favorite**: Mark the device as favorite and then it will appears at the
begining of the device list
- **Group**: Select a grouper ('Always on', 'Personal', Friends') or type
@@ -66,7 +66,7 @@ know, but it **is totally useless when connecting to our own WIFI's** or known
networks.
**I recommend disabling this operation when connecting our devices to our own
WIFI's**, in this way, Pi.Alert will be able to identify the device, and it
WIFI's**, in this way, NetAlertX will be able to identify the device, and it
will not identify it as a new device every so often (every time IOS or Android
decides to change the MAC).
@@ -89,11 +89,11 @@ decides to change the MAC).
Always use the Issue tracker for the correct fork, for example:
[jokob-sk/Pi.Alert](https://github.com/jokob-sk/Pi.Alert/issues). Please also follow the guidelines on:
[jokob-sk/NetAlertX](https://github.com/jokob-sk/NetAlertX/issues). Please also follow the guidelines on:
- [Pull Request guidelines](https://github.com/jokob-sk/Pi.Alert/tree/main/docs#-pull-requests-prs)
- 🙏 [Feature request guidelines](https://github.com/jokob-sk/Pi.Alert/tree/main/docs#-feature-requests)
- 🐛 [Issue guidelines](https://github.com/jokob-sk/Pi.Alert/tree/main/docs#-submitting-an-issue-or-bug)
- [Pull Request guidelines](https://github.com/jokob-sk/NetAlertX/tree/main/docs#-pull-requests-prs)
- 🙏 [Feature request guidelines](https://github.com/jokob-sk/NetAlertX/tree/main/docs#-feature-requests)
- 🐛 [Issue guidelines](https://github.com/jokob-sk/NetAlertX/tree/main/docs#-submitting-an-issue-or-bug)
***Suggestions and comments are welcome***

33
docs/FILE_PERMISSIONS.md Executable file
View File

@@ -0,0 +1,33 @@
# Managing File Permissions for NetAlertX on Nginx with Docker
NetAlertX runs on an Nginx web server. On Alpine Linux, Nginx operates as the `nginx` user (user ID 101, group ID 82 - `www-data`). Consequently, files accessed or written by the NetAlertX application are owned by `nginx:www-data`.
Upon starting, NetAlertX changes the ownership of files on the host system mapped to `/app/config` and `/app/db` in the container to `nginx:www-data`. This ensures that Nginx can access and write to these files. Since the user in the Docker container is mapped to a user on the host system by ID:GID, the files in `/app/config` and `/app/db` on the host system are owned by a user with the same ID and GID (ID 101 and GID 82). On different systems, this ID:GID may belong to different users (on Debian, the user with ID 82 is `uuidd`), or there may not be a user with ID 82 at all.
While this generally isn't problematic, it can cause issues for host system users needing to access these files (e.g., backup scripts). If users other than root need access to these files, it is recommended to add those users to the group with GID 82. If that group doesn't exist, it should be created.
### Permissions Table for Individual Folders
| Folder | User | User ID | Group | Group ID | Permissions | Notes |
|----------------|--------|---------|-----------|----------|-------------|---------------------------------------------------------------------|
| `/app/config` | nginx | 101 | www-data | 82 | rwxr-xr-x | Ensure `nginx` can read/write; other users can read if in `www-data` |
| `/app/db` | nginx | 101 | www-data | 82 | rwxr-xr-x | Same as above |
### Steps to Add Users to Group
1. **Check if group exists:**
```sh
getent group www-data
```
2. **Create group if it does not exist:**
```sh
sudo groupadd -g 82 www-data
```
3. **Add user to group:**
```sh
sudo usermod -aG www-data <username>
```
Replace `<username>` with the actual username that requires access.

View File

@@ -1,6 +1,6 @@
# 🖼 Frontend development
This page contains tips for frontend development when extending PiAlert. Guiding principles are:
This page contains tips for frontend development when extending NetAlertX. Guiding principles are:
1. Maintainability
2. Extendability
@@ -43,4 +43,4 @@ Some useful frontend JavaScript functions:
- `getSetting(string stringKey)` - method to retrieve settings in the frontend
Check the [pialert_common.js](https://github.com/jokob-sk/Pi.Alert/blob/main-2023-06-10/front/js/pialert_common.js) file for more frontend functions.
Check the [common.js](https://github.com/jokob-sk/NetAlertX/blob/main-2023-06-10/front/js/common.js) file for more frontend functions.

View File

@@ -1,6 +1,6 @@
# Overview
PiAlert comes with MQTT support, allowing you to show all detected devices as devices in Home Assistant. It also supplies a collection of stats, such as number of online devices.
NetAlertX comes with MQTT support, allowing you to show all detected devices as devices in Home Assistant. It also supplies a collection of stats, such as number of online devices.
## ⚠ Note
@@ -16,13 +16,13 @@ PiAlert comes with MQTT support, allowing you to show all detected devices as de
2. Configure a user name and password on your broker.
3. Note down the following details that you will need to configure PiAlert:
3. Note down the following details that you will need to configure NetAlertX:
- MQTT host url (usually your Home Assistant IP)
- MQTT broker port
- User
- Password
4. Open the _PiAlert_ > _Settings_ > _MQTT_ settings group
4. Open the _NetAlertX_ > _Settings_ > _MQTT_ settings group
- Enable MQTT
- Fill in the details from above
- Fill in remaining settings as per description
@@ -36,9 +36,9 @@ PiAlert comes with MQTT support, allowing you to show all detected devices as de
| ![Screen 3][list] | ![Screen 4][overview] |
[configuration]: /docs/img/HOME_ASISSTANT/PiAlert-HomeAssistant-Configuration.png "configuration"
[sensors]: /docs/img/HOME_ASISSTANT/PiAlert-HomeAssistant-Device-as-Sensors.png "sensors"
[history]: /docs/img/HOME_ASISSTANT/PiAlert-HomeAssistant-Device-Presence-History.png "history"
[list]: /docs/img/HOME_ASISSTANT/PiAlert-HomeAssistant-Devices-List.png "list"
[overview]: /docs/img/HOME_ASISSTANT/PiAlert-HomeAssistant-Overview-Card.png "overview"
[configuration]: /docs/img/HOME_ASISSTANT/HomeAssistant-Configuration.png "configuration"
[sensors]: /docs/img/HOME_ASISSTANT/HomeAssistant-Device-as-Sensors.png "sensors"
[history]: /docs/img/HOME_ASISSTANT/HomeAssistant-Device-Presence-History.png "history"
[list]: /docs/img/HOME_ASISSTANT/HomeAssistant-Devices-List.png "list"
[overview]: /docs/img/HOME_ASISSTANT/HomeAssistant-Overview-Card.png "overview"

View File

@@ -1,12 +1,12 @@
# How to install PiAlert on the server hardware
# How to install NetAlertX on the server hardware
To download and install PiAlert on the hardware/server directly use the `curl` or `wget` commands at the bottom of this page.
To download and install NetAlertX on the hardware/server directly use the `curl` or `wget` commands at the bottom of this page.
> [!NOTE]
> This is an Experimental feature 🧪 and it relies on community support.
>
> There is no guarantee that the install script or any other script will gracefully handle other installed software.
> Data loss is a possibility, **it is recommended to install PiAlert using the supplied Docker image**.
> Data loss is a possibility, **it is recommended to install NetAlertX using the supplied Docker image**.
A warning to the installation method below: Piping to bash is [controversial](https://pi-hole.net/2016/07/25/curling-and-piping-to-bash) and may
be dangerous, as you cannot see the code that's about to be executed on your system.
@@ -14,34 +14,34 @@ be dangerous, as you cannot see the code that's about to be executed on your sys
Alternatively you can download the installation script `install/install.debian.sh` from the repository and check the code yourself (beware other scripts are
downloaded too - only from this repo).
PiAlert will be installed in `home/pi/pialert/` and run on port number `20211`.
NetAlertX will be installed in `/app` and run on port number `20211`.
Some facts about what and where something will be changed/installed by the HW install setup (may not contain everything!):
- `/home/pi/pialert` directory will be deleted and newly created
- `/home/pi/pialert` will contain the whole repository (downloaded by `install/install.debian.sh`)
- `/app` directory will be deleted and newly created
- `/app` will contain the whole repository (downloaded by `install/install.debian.sh`)
- The default NGINX site `/etc/nginx/sites-enabled/default` will be disabled (sym-link deleted or backed up to `sites-available`)
- `/var/www/html/pialert` directory will be deleted and newly created
- `/etc/nginx/conf.d/pialert.conf` will be sym-linked to `/home/pi/pialert/install/pialert.debian.conf`
- `/var/www/html/netalertx` directory will be deleted and newly created
- `/etc/nginx/conf.d/netalertx.conf` will be sym-linked to `/app/install/netalertx.debian.conf`
- Some files (IEEE device vendors info, ...) will be created in the directory where the installation script is executed
## Limitations
- No system service is provided. PiAlert must be started using `/home/pi/pialert/install/start.debian.sh`.
- No system service is provided. NetAlertX must be started using `/app/install/start.debian.sh`.
- No checks for other running software is done.
- Only tested to work on Debian Bookworm (Debian 12).
- **EXPERIMENTAL** and not recommended way to install PiAlert.
- **EXPERIMENTAL** and not recommended way to install NetAlertX.
## 📥 Installation via CURL
```bash
curl -o install.debian.sh https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/install/install.debian.sh && sudo chmod +x install.debian.sh && sudo ./install.debian.sh
curl -o install.debian.sh https://raw.githubusercontent.com/jokob-sk/NetAlertX/main/install/install.debian.sh && sudo chmod +x install.debian.sh && sudo ./install.debian.sh
```
## 📥 Installation via WGET
```bash
wget https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/install/install.debian.sh -O install.debian.sh && sudo chmod +x install.debian.sh && sudo ./install.debian.sh
wget https://raw.githubusercontent.com/jokob-sk/NetAlertX/main/install/install.debian.sh -O install.debian.sh && sudo chmod +x install.debian.sh && sudo ./install.debian.sh
```
These commands will download the `install.debian.sh` script from the GitHub repository, make it executable with `chmod`, and then run it using `./install.debian.sh`.

View File

@@ -1,32 +1,51 @@
## Icons overview
Icons are used to visually distinguish devices in the app in most of the device listing tables and the [network tree](/docs/NETWORK_TREE.md). Currently only free [Font Awesome](https://fontawesome.com/search?o=r&m=free) icons (up-to v 6.4.0) are supported.
Icons are used to visually distinguish devices in the app in most of the device listing tables and the [network tree](/docs/NETWORK_TREE.md).
![Raspberry Pi with a brand icon](/docs/img/ICONS/devices-icons.png)
## ⚙ How to use custom device Icons
### Icons Support
Two types of icons are suported:
- Free [Font Awesome](https://fontawesome.com/search?o=r&m=free) icons (up-to v 6.4.0)
- SVG icons (for example from [iconify.design](https://icon-sets.iconify.design/))
You can assign icons individually on each device in the Details tab.
![preview](/docs/img/ICONS/device_icons_preview.gif)
## Adding new icons
![Raspberry Pi device details](/docs/img/ICONS/device-icon.png)
1. You can get an SVG or a Font awesome HTML code
- You can click into the `Icon` field or click the Pencil (2) icon in the above screenshot to enter any text. Only [free Font Awesome](https://fontawesome.com/search?o=r&m=free) icons in the following format will work:
Copying the SVG (for example from [iconify.design](https://icon-sets.iconify.design/)):
1. For any value that is only prefixed with `fa-`, you can enter the value directly, such as `server`, `tv`, `ethernet`.
2. If you want to add another classname, e.g. `fa-brands`, you can enter `brands fa-[fontawesome-icon-name]`, so for `apple` that is using the syntax`fa-brands fa-apple`, you would enter `brands fa-apple`.
![iconify svg](/docs/img/ICONS/iconify_design_copy_svg.png)
- If you want to mass-apply an icon to all devices of the same device type (Field marked (4) in the above screenshot), you can click the copy button (Marked (1) in the above screenshot). A confirmation prompt is displayed. If you proceed, icons of all devices set to the same device type as the current device, will be overwritten with the current device's icon.
Copying the HTML code from [Font Awesome](https://fontawesome.com/search?o=r&m=free).
- The dropdown (3) contains all icons already used in the app for device icons. You need to navigate away or refresh the page once you add a new icon.
![Font awesome](/docs/img/ICONS/font_awesome_copy_html.png)
2. Navigate to the device you want to use the icon on and click the "+" icon:
![preview](/docs/img/ICONS/device_add_icon.png)
3. Paste in the copied HTML or SVG code and click "OK":
![Paste SVG](/docs/img/ICONS/paste-svg.png)
6. "Save" the device
> [!NOTE]
> If you want to mass-apply an icon to all devices of the same device type (Field: Type), you can click the mass-copy button (next to the "+" button). A confirmation prompt is displayed. If you proceed, icons of all devices set to the same device type as the current device, will be overwritten with the current device's icon.
- The blue dropdown contains all icons already used in the app for device icons. You need to navigate away or refresh the page once you add a new icon.
## 🌟 Pro Font Awesome icons
If you own the premium package of Font Awesome icons you can mount it in your Docker container the following way:
```yaml
/font-awesome:/home/pi/pialert/front/lib/AdminLTE/bower_components/font-awesome:ro
/font-awesome:/app/front/lib/AdminLTE/bower_components/font-awesome:ro
```
You can use the full range of Font Awesome icons afterwards.

142
docs/MIGRATION.md Executable file
View File

@@ -0,0 +1,142 @@
# Migration form PiAlert to NetAlertX
> [!WARNING]
> Follow this guide only after you you downloaded and started NetAlert X at least once after previously using the PiAlert image.
## STEPS:
> [!TIP]
> In short: The application will auto-migrate the database, config, and all device information. A ticker message on top will be displayed until you update your docker mount points. It's always good to have a [backup strategy](https://github.com/jokob-sk/NetAlertX/blob/main/docs/BACKUPS.md) in place.
1. Backup your current config and database (optional `devices.csv` to have a backup) (See bellow tip if facing issues)
2. Stop the container
2. Update the Docker file mount locations in your `docker-compose.yml` or docker run command (See bellow **New Docker mount locations**).
3. Rename the DB and conf files to `app.db` and `app.conf` and place them in the appropriate location.
4. Start the Container
> [!TIP]
> If you have troubles accessing past backups, config or database files you can copy them into the newly mapped directories, for example by running this command in the container: `cp -r /app/config /home/pi/pialert/config/old_backup_files`. This should create a folder in the `config` directory called `old_backup_files` conatining all the files in that location. Another approach is to map the old location and the new one at the same time to copy things over.
### New Docker mount locations
The application installation folder in the docker container has changed from `/home/pi/pialert` to `/app`. That means the new mount points are:
| Old mount point | New mount point |
|----------------------|---------------|
| `/home/pi/pialert/config` | `/app/config` |
| `/home/pi/pialert/db` | `/app/db` |
If you were mounting files directly, please note the file names have changed:
| Old file name | New file name |
|----------------------|---------------|
| `pialert.conf` | `app.conf` |
| `pialert.db` | `app.db` |
> [!NOTE]
> The application uses symlinks linking the old db and config locations to the new ones, so data loss should not occur. [Backup strategies](https://github.com/jokob-sk/NetAlertX/blob/main/docs/BACKUPS.md) are still recommended to backup your setup.
# Examples
Exmaples of docker files with the new mount points.
## Example 1: Mapping folders
### Old docker-compose.yml
```yaml
version: "3"
services:
pialert:
container_name: pialert
# use the below line if you want to test the latest dev image
# image: "jokobsk/netalertx-dev:latest"
image: "jokobsk/pialert:latest"
network_mode: "host"
restart: unless-stopped
volumes:
- local/path/config:/home/pi/pialert/config
- local/path/db:/home/pi/pialert/db
# (optional) useful for debugging if you have issues setting up the container
- local/path/logs:/home/pi/pialert/front/log
environment:
- TZ=Europe/Berlin
- PORT=20211
```
### New docker-compose.yml
```yaml
version: "3"
services:
netalertx: # ⚠ This has changed (🟡optional)
container_name: netalertx # ⚠ This has changed (🟡optional)
# use the below line if you want to test the latest dev image
# image: "jokobsk/netalertx-dev:latest"
image: "jokobsk/netalertx:latest" # ⚠ This has changed (🟡optional/🔺required in future)
network_mode: "host"
restart: unless-stopped
volumes:
- local/path/config:/app/config # ⚠ This has changed (🔺required)
- local/path/db:/app/db # ⚠ This has changed (🔺required)
# (optional) useful for debugging if you have issues setting up the container
- local/path/logs:/app/front/log # ⚠ This has changed (🟡optional)
environment:
- TZ=Europe/Berlin
- PORT=20211
```
## Example 2: Mapping files
> [!NOTE]
> The recommendation is to map folders as in Example 1, map files directly only when needed.
### Old docker-compose.yml
```yaml
version: "3"
services:
pialert:
container_name: pialert
# use the below line if you want to test the latest dev image
# image: "jokobsk/netalertx-dev:latest"
image: "jokobsk/pialert:latest"
network_mode: "host"
restart: unless-stopped
volumes:
- local/path/config/pialert.conf:/home/pi/pialert/config/pialert.conf
- local/path/db/pialert.db:/home/pi/pialert/db/pialert.db
# (optional) useful for debugging if you have issues setting up the container
- local/path/logs:/home/pi/pialert/front/log
environment:
- TZ=Europe/Berlin
- PORT=20211
```
### New docker-compose.yml
```yaml
version: "3"
services:
netalertx: # ⚠ This has changed (🟡optional)
container_name: netalertx # ⚠ This has changed (🟡optional)
# use the below line if you want to test the latest dev image
# image: "jokobsk/netalertx-dev:latest"
image: "jokobsk/netalertx:latest" # ⚠ This has changed (🟡optional/🔺required in future)
network_mode: "host"
restart: unless-stopped
volumes:
- local/path/config/app.conf:/app/config/app.conf # ⚠ This has changed (🔺required)
- local/path/db/app.db:/app/db/app.db # ⚠ This has changed (🔺required)
# (optional) useful for debugging if you have issues setting up the container
- local/path/logs:/app/front/log # ⚠ This has changed (🟡optional)
environment:
- TZ=Europe/Berlin
- PORT=20211
```

View File

@@ -2,7 +2,7 @@
Make sure you have a root device with the MAC `Internet` (No other MAC addresses are currently supported as the root node) set to a network device type (e.g.: **Type**:`Router`).
> 💡 Tip: You can add dummy devices via the [Undiscoverables plugin](https://github.com/jokob-sk/Pi.Alert/blob/main/front/plugins/undiscoverables/README.md)
> 💡 Tip: You can add dummy devices via the [Undiscoverables plugin](https://github.com/jokob-sk/NetAlertX/blob/main/front/plugins/undiscoverables/README.md)
> 💡 Tip: Export your configuration of the Network and Devices once in a while via the Export CSV feature under **Maintenance** -> **Backup/Restore** -> **CSV Export**.

53
docs/NOTIFICATIONS.md Executable file
View File

@@ -0,0 +1,53 @@
# Notifications 📧
There are 4 ways how to influence notifications:
1. On the device itself
2. On the settings of the plugin
3. Globally
4. Ignoring devices
> [!NOTE]
> It's recommended to use the same schedule interval for all plugins responsible for scanning devices, otherwise false positives might be reported if different devices are discovered by different plugins. Check the **Settings** > **Enabled settings** section for a warning:
> ![Schedules out-of-sync](/docs/img/NOTIFICATIONS/Schedules_out-of-sync.png)
## Device settings 💻
![Device notification settings](/docs/img/NOTIFICATIONS/Device-notification-settings.png)
There are 4 settings on the device for influencing notifications. You can:
1. Completely disable the scanning of the device
2. **Alert all events**, connections, disconnections, IP changes (noisy, usually not recommended)
3. **Alert down** - alerts when a device goes down. This setting overrides disabled Alert All Events, so you will get a notification of a device going down even if you don't have Alert All Events ticked.
4. **Skip repeated notifications**, if for example you know there is a temporary issue and want to pause the same notification for this device for a given time.
## Plugin settings 🔌
![Plugin notification settings](/docs/img/NOTIFICATIONS/Plugin-notification-settings.png)
On almost all plugins there are 2 core settings, `<plugin>_WATCH` and `<plugin>_REPORT_ON`.
1. `<plugin>_WATCH` specifies the columns which the app should watch. If watched columns change the device state is considered changed. This changed status is then used to decide to send out notifications based on the `<plugin>_REPORT_ON` setting.
2. `<plugin>_REPORT_ON` let's you specify on which events the app should notify you. This is related to the `<plugin>_WATCH` setting. So if you select `watched-changed` and in `<plugin>_WATCH` you only select `Watched_Value1`, then a notification is triggered if `Watched_Value1` is changed from the previous value, but no notification is send if `Watched_Value2` changes.
## Global settings ⚙
![Global notification settings](/docs/img/NOTIFICATIONS/Global-notification-settings.png)
In the Notification Processing section, you can specify blanket rules. These allow you to specify exceptions to the Plugin and Device settings and will override those.
1. Notify on (`NTFPRCS_INCLUDED_SECTIONS`) allows you to specify which events trigger notifications. Usual setups will have `new_devices`, `down_devices`, and possibly `events` set. Setting `plugin` might be too noisy for most setups.
2. Alert down after (`NTFPRCS_alert_down_time`) is useful if you want to wait for some time before the system sends out a down notification for a device. This is related to the on-device **Alert down** setting and only devices with this checked will trigger a down notification.
3. A filter to allow you to set device-specific exceptions to New devices being added to the app.
4. A filter to allow you to set device-specific exceptions to generated Events.
## Ignoring devices 🔕
![Ignoring new devices](/docs/img/NOTIFICATIONS/NEWDEV_ignores.png)
You can completely ignore detected devices globally. This could be because your instance detects docker containers, you want to ignore devices from a specific manufacturer via MAC rules or you want to ignore devices on a specific IP range.
1. Ignored MACs (`NEWDEV_ignored_MACs`) - List of MACs to ignore.
2. Ignored IPs (`NEWDEV_ignored_MACs`) - List of IPs to ignore.

View File

@@ -1,113 +1,79 @@
## 📚 Dokumente für einzelne Plugins
### 🏴 Community-Übersetzungen dieser Datei
* <a href="https://github.com/jokob-sk/Pi.Alert/blob/main/front/plugins/README.md">
<img src="https://github.com/lipis/flag-icons/blob/main/flags/4x3/us.svg" alt="README.md" style="height: 20px !important;width: 20px !important;"> English (American)
</a>
* <a href="https://github.com/jokob-sk/Pi.Alert/blob/main/front/plugins/README_ES.md">
<img src="https://github.com/lipis/flag-icons/blob/main/flags/4x3/es.svg" alt="README_ES.md" style="height: 20px !important;width: 20px !important;"> Spanish (Spain)
</a>
### 🔌 Plugins und 📚 Dokumente
| Required | CurrentScan | Unique Prefix | Plugin Type | Link + Docs |
|-------------|-------------|-----------------------|------------------------|----------------------------------------------------------|
| | Yes | ARPSCAN | Script | [arp_scan](/front/plugins/arp_scan/) |
| | | CSVBCKP | Script | [csv_backup](/front/plugins/csv_backup/) |
| | Yes | DHCPLSS | Script | [dhcp_leases](/front/plugins/dhcp_leases/) |
| | | DHCPSRVS | Script | [dhcp_servers](/front/plugins/dhcp_servers/) |
| Yes | | NEWDEV | Template | [newdev_template](/front/plugins/newdev_template/) |
| | | NMAP | Script | [nmap_scan](/front/plugins/nmap_scan/) |
| | Yes | PIHOLE | External SQLite DB | [pihole_scan](/front/plugins/pihole_scan/) |
| | | SETPWD | Script | [set_password](/front/plugins/set_password/) |
| | | SNMPDSC | Script | [snmp_discovery](/front/plugins/snmp_discovery/) |
| | Yes* | UNDIS | Script | [undiscoverables](/front/plugins/undiscoverables/) |
| | Yes | UNFIMP | Script | [unifi_import](/front/plugins/unifi_import/) |
| | | WEBMON | Script | [website_monitor](/front/plugins/website_monitor/) |
| N/A | | N/A | SQL query | No beispiel available, but the External SQLite based plugins work very similar |
>* Das Undiscoverables-Plugin (`UNDIS`) fügt nur vom Benutzer angegebene Dummy-Geräte ein.
> [!NOTE]
> Sie können Plugins über die Einstellungen sanft deaktivieren oder Plugins vollständig ignorieren, indem Sie eine „ignore_plugin“-Datei im Plugin-Verzeichnis ablegen. Der Unterschied besteht darin, dass ignorierte Plugins nirgendwo in der Benutzeroberfläche angezeigt werden (Einstellungen, Gerätedetails, Plugins-Seiten). Die App überspringt ignorierte Plugins vollständig. Geräteerkennungs-Plugins fügen Werte in die Datenbanktabelle „CurrentScan“ ein. Die Plugins, die nicht erforderlich sind, können getrost ignoriert werden, es ist jedoch sinnvoll, zumindest einige Plugins zur Geräteerkennung (die Einträge in die Tabelle „CurrentScan“ einfügen) zu aktivieren, wie z. B. ARPSCAN oder PIHOLE.
> Es wird empfohlen, für alle Plugins, die für die Erkennung neuer Geräte zuständig sind, das gleiche Zeitplanintervall zu verwenden.
## 🌟 Erstellen Sie ein benutzerdefiniertes Plugin: Übersicht
## 🌟 Create a custom plugin: Overview
| ![Screen 1][screen1] | ![Screen 2][screen2] | ![Screen 3][screen3] |
|----------------------|----------------------| ----------------------|
| ![Screen 4][screen4] | ![Screen 5][screen5] |
PiAlert verfügt über ein Plugin-System, um Ereignisse aus Skripten von Drittanbietern in die Benutzeroberfläche einzuspeisen und dann bei Bedarf Benachrichtigungen zu senden. Die hervorgehobene Kernfunktionalität, die dieses Plugin-System unterstützt, ist:
NetAlertX comes with a plugin system to feed events from third-party scripts into the UI and then send notifications, if desired. The highlighted core functionality this plugin system supports, is:
* dynamische Erstellung einer einfachen Benutzeroberfläche zur Interaktion mit den entdeckten Objekten,
* Filterung der angezeigten Werte in der Geräte-Benutzeroberfläche
* Oberflächeneinstellungen von Plugins in der Benutzeroberfläche,
* verschiedene Spaltentypen für gemeldete Werte, z.B. Link zurück zu einem Gerät
* Objekte in vorhandene PiAlert-Datenbanktabellen importieren
* dynamic creation of a simple UI to interact with the discovered objects,
* filtering of displayed values in the Devices UI
* surface settings of plugins in the UI,
* different column types for reported values to e.g. link back to a device
* import objects into existing NetAlertX database tables
> (Derzeit wird das Aktualisieren/Überschreiben vorhandener Objekte nicht unterstützt.)
> (Currently, update/overwriting of existing objects is not supported.)
Beispielanwendungsfälle für Plugins könnten sein:
Example use cases for plugins could be:
* Überwachen Sie einen Webdienst und benachrichtigen Sie mich, wenn er nicht verfügbar ist
* Importieren Sie Geräte aus dhcp.leases-Dateien anstelle/ergänzend zur Verwendung von PiHole oder arp-scans
* Erstellen von Ad-hoc-UI-Tabellen aus vorhandenen Daten in der PiAlert-Datenbank, z.B. um alle offenen Ports auf Geräten anzuzeigen, um Geräte aufzulisten, die in der letzten Stunde getrennt wurden usw.
* Verwendung anderer Geräteerkennungsmethoden im Netzwerk und Importieren der Daten als neue Geräte
* Erstellen eines Skripts zum Erstellen gefälschter Geräte basierend auf Benutzereingaben über benutzerdefinierte Einstellungen
* ...an diesem Punkt liegt die Einschränkung hauptsächlich in der Kreativität und nicht in der Leistungsfähigkeit (es kann Randfälle geben und die Notwendigkeit, mehr Formularsteuerelemente für Benutzereingaben aus benutzerdefinierten Einstellungen zu unterstützen, aber Sie haben wahrscheinlich schon verstanden, worauf es ankommt)
* Monitor a web service and alert me if it's down
* Import devices from dhcp.leases files instead/complementary to using PiHole or arp-scans
* Creating ad-hoc UI tables from existing data in the NetAlertX database, e.g. to show all open ports on devices, to list devices that disconnected in the last hour, etc.
* Using other device discovery methods on the network and importing the data as new devices
* Creating a script to create FAKE devices based on user input via custom settings
* ...at this point the limitation is mostly the creativity rather than the capability (there might be edge cases and a need to support more form controls for user input off custom settings, but you probably get the idea)
Wenn Sie ein Plugin entwickeln möchten, prüfen Sie bitte die bestehende Plugin-Struktur. Sobald die Einstellungen vom Benutzer gespeichert wurden, müssen sie manuell aus der Datei `pialert.conf` entfernt werden, wenn Sie sie aus der `config.json` des Plugins neu initialisieren möchten.
If you wish to develop a plugin, please check the existing plugin structure. Once the settings are saved by the user they need to be removed from the `app.conf` file manually if you want to re-initialize them from the `config.json` of the plugin.
Bitte lesen Sie das Folgende noch einmal sorgfältig durch, wenn Sie selbst mit einem Plugin beitragen möchten. Diese Dokumentationsdatei ist möglicherweise veraltet. Überprüfen Sie daher auch die Beispiel-Plugins noch einmal.
Again, please read the below carefully if you'd like to contribute with a plugin yourself. This documentation file might be outdated, so double-check the sample plugins as well.
## ⚠ Haftungsausschluss
## ⚠ Disclaimer
Befolgen Sie die nachstehenden Anweisungen sorgfältig und prüfen Sie Beispiel-Plugins, wenn Sie selbst eines schreiben möchten. Die Plugin-Benutzeroberfläche ist derzeit nicht meine Priorität. Gerne genehmige ich PRs, wenn Sie daran interessiert sind, die Benutzeroberfläche zu erweitern/verbessern (siehe [Frontend-Richtlinien](/docs/FRONTEND_DEVELOPMENT.md)). Beispielhafte Verbesserungen zum Mitnehmen:
Follow the below very carefully and check example plugin(s) if you'd like to write one yourself. Plugin UI is not my priority right now, happy to approve PRs if you are interested in extending/improving the UI experience (See [Frontend guidelines](/docs/FRONTEND_DEVELOPMENT.md)). Example improvements for the taking:
* Die Tabellen sortierbar/filterbar machen
* Verwenden des gleichen Ansatzes zum Anzeigen von Tabellendaten wie im Abschnitt "Geräte" (wird oben gelöst)
* Hinzufügen unterstützter Formularsteuerelemente zum Anzeigen der Daten (Derzeit unterstützte Steuerelemente sind im Abschnitt "UI-Einstellungen in Datenbankspaltendefinitionen" unten aufgeführt)
* Making the tables sortable/filterable
* Using the same approach to display table data as in the Devices section (solves above)
* Adding form controls supported to display the data (Currently supported ones are listed in the section "UI settings in database_column_definitions" below)
* ...
## ❗ Bekannte Probleme:
## ❗ Known limitations:
These issues will be hopefully fixed with time, so please don't report them. Instead, if you know how, feel free to investigate and submit a PR to fix the below. Keep the PRs small as it's easier to approve them:
* Vorhandene Plugin-Objekte werden manchmal nicht richtig interpretiert und stattdessen wird ein neues Objekt erstellt, was zu doppelten Einträgen führt. (Rennbedingung?)
* Gelegentliches (zweimal aufgetretenes) Hängenbleiben der Verarbeitungs-Plugin-Skriptdatei.
Die Benutzeroberfläche zeigt veraltete Werte an, bis die API-Endpunkte aktualisiert werden.
* Existing plugin objects are sometimes not interpreted correctly and a new object is created instead, resulting in duplicate entries. (race condition?)
* Occasional (experienced twice) hanging of processing plugin script file.
* UI displays outdated values until the API endpoints get refreshed.
## Übersicht über die Plugin-Dateistruktur
## Plugin file structure overview
> ⚠️Der Ordnername muss mit dem Codenamenwert in Folgendem übereinstimmen: `"code_name": "<value>"`
> Das eindeutige Präfix muss im Vergleich zu den anderen Einstellungspräfixen eindeutig sein, z. B.: Das Präfix `APPRISE` wird bereits verwendet.
> ⚠️Folder name must be the same as the code name value in: `"code_name": "<value>"`
> Unique prefix needs to be unique compared to the other settings prefixes, e.g.: the prefix `APPRISE` is already in use.
| File | Required (plugin type) | Description |
|----------------------|----------------------|----------------------|
| `config.json` | yes | Contains the plugin configuration (manifest) including the settings available to the user. |
| `script.py` | no | The Python script itself. You may call any valid linux command. |
| `last_result.log` | no | The file used to interface between PiAlert and the plugin. Required for a script plugin if you want to feed data into the app. |
| `last_result.log` | no | The file used to interface between NetAlertX and the plugin. Required for a script plugin if you want to feed data into the app. |
| `script.log` | no | Logging output (recommended) |
| `README.md` | yes | Any setup considerations or overview |
Weitere Einzelheiten finden Sie weiter unten.
More on specifics below.
### Spaltenreihenfolge und Werte
### Column order and values
| Order | Represented Column | Required | Description |
> [!IMPORTANT]
> Spend some time reading and trying to understand the below table. This is the interface between the Plugins and the core application.
| Order | Represented Column | Value Required | Description |
|----------------------|----------------------|----------------------|----------------------|
| 0 | `Object_PrimaryID` | yes | The primary ID used to group Events under. |
| 1 | `Object_SecondaryID` | no | Optional secondary ID to create a relationship beween other entities, such as a MAC address |
| 2 | `DateTime` | yes | When the event occured in the format `2023-01-02 15:56:30` |
| 3 | `Watched_Value1` | yes | A value that is watched and users can receive notifications if it changed compared to the previously saved entry. For beispiel IP address |
| 3 | `Watched_Value1` | yes | A value that is watched and users can receive notifications if it changed compared to the previously saved entry. For example IP address |
| 4 | `Watched_Value2` | no | As above |
| 5 | `Watched_Value3` | no | As above |
| 6 | `Watched_Value4` | no | As above |
| 7 | `Extra` | no | Any other data you want to pass and display in PiAlert and the notifications |
| 7 | `Extra` | no | Any other data you want to pass and display in NetAlertX and the notifications |
| 8 | `ForeignKey` | no | A foreign key that can be used to link to the parent object (usually a MAC address) |
> [!NOTE]
@@ -115,37 +81,41 @@ Weitere Einzelheiten finden Sie weiter unten.
# config.json structure
## Unterstützte Datenquellen
The `config.json` file is the manifest of the plugin. It contains mainly settings definitions and the mapping of Plugin objects to NetAlertX objects.
## Supported data sources
Currently, these data sources are supported (valid `data_source` value).
| Name | `data_source` value | Needs to return a "table" | Overview (more details on this page below) |
| Name | `data_source` value | Needs to return a "table"* | Overview (more details on this page below) |
|----------------------|----------------------|----------------------|----------------------|
| Script | `script` | no | Executes any linux command in the `CMD` setting. |
| Pialert DB query | `pialert-db-query` | yes | Executes a SQL query on the PiAlert database in the `CMD` setting. |
| NetAlertX DB query | `app-db-query` | yes | Executes a SQL query on the NetAlertX database in the `CMD` setting. |
| Template | `template` | no | Used to generate internal settings, such as default values. |
| External SQLite DB query | `sqlite-db-query` | yes | Executes a SQL query from the `CMD` setting on an external SQLite database mapped in the `DB_PATH` setting. |
| Plugin type | `plugin_type` | no | Specifies the type of the plugin and in which section the Plugin settings are displayed ( one of `general/system/scanner/other/publisher` ). |
> * "Needs to return a "table" means that the application expects a `last_result.log` file with some results. It's not a blocker, however warnings in the `app.log` might be logged.
> 🔎Beispiel
> 🔎Example
>```json
>"data_source": "pialert-db-query"
>"data_source": "app-db-query"
>```
If you want to display plugin objects or import devices into the app, data sources have to return a "table" of the exact structure as outlined above.
You can show or hide the UI on the "Plugins" page and "Plugins" tab for a plugin on devices via the `show_ui` property:
> 🔎Beispiel
> 🔎Example
>```json
> "show_ui": true,
> ```
### "data_source": "script"
If the `data_source` is set to `script` the `CMD` setting (that you specify in the `settings` array section in the `config.json`) contains an executable Linux command, that usually generates a `last_result.log` file (not required if you don't import any data into the app). This file needs to be stored in the same folder as the plugin.
If the `data_source` is set to `script` the `CMD` setting (that you specify in the `settings` array section in the `config.json`) contains an executable Linux command, that usually generates a `last_result.log` file (not required if you don't import any data into the app). The `last_result.log` file needs to be saved in the same folder as the plugin.
> [!IMPORTANT]
> A lot of the work is taken care of by the [`plugin_helper.py` library](/front/plugins/plugin_helper.py). You don't need to manage the `last_result.log` file if using the helper objects. Check other `script.py` of other plugins for details (The [Undicoverables plugins `script.py` file](/front/plugins/undiscoverables/script.py) is a good beispiel).
> A lot of the work is taken care of by the [`plugin_helper.py` library](/front/plugins/plugin_helper.py). You don't need to manage the `last_result.log` file if using the helper objects. Check other `script.py` of other plugins for details (The [Undicoverables plugins `script.py` file](/front/plugins/undiscoverables/script.py) is a good example).
The content of the `last_result.log` file needs to contain the columns as defined in the "Column order and values" section above. The order of columns can't be changed. After every scan it should contain only the results from the latest scan/execution.
@@ -156,7 +126,7 @@ Every scan result/event entry needs to be on a new line.
- You can find which "columns" need to be present, and if the value is required or optional, in the "Column order and values" section.
- The order of these "columns" can't be changed.
#### 🔎 last_result.log beispieles
#### 🔎 last_result.log examples
Valid CSV:
@@ -181,15 +151,15 @@ https://www.google.com|null|2023-01-02 15:56:30|200|0.7898|
```
### "data_source": "pialert-db-query"
### "data_source": "app-db-query"
If the `data_source` is set to `pialert-db-query` the `CMD` setting needs to contain a SQL query rendering the columns as defined in the "Column order and values" section above. The order of columns is important.
If the `data_source` is set to `app-db-query`, the `CMD` setting needs to contain a SQL query rendering the columns as defined in the "Column order and values" section above. The order of columns is important.
This SQL query is executed on the `pialert.db` SQLite database file.
This SQL query is executed on the `app.db` SQLite database file.
> 🔎Beispiel
> 🔎Example
>
> SQL query Beispiel:
> SQL query example:
>
> ```SQL
> SELECT dv.dev_Name as Object_PrimaryID,
@@ -208,7 +178,7 @@ This SQL query is executed on the `pialert.db` SQLite database file.
> ON ns.MAC = dv.dev_MAC
> ```
>
> Required `CMD` setting beispiel with above query (you can set `"type": "label"` if you want it to make uneditable in the UI):
> Required `CMD` setting example with above query (you can set `"type": "label"` if you want it to make uneditable in the UI):
>
> ```json
> {
@@ -230,13 +200,15 @@ This SQL query is executed on the `pialert.db` SQLite database file.
### "data_source": "template"
Used to initialize internal settings. Check the `newdev_template` plugin for details.
In most cases, it is used to initialize settings. Check the `newdev_template` plugin for details.
### "data_source": "sqlite-db-query"
You can execute a SQL query on an external database connected to the current PiALert database via a temporary `EXTERNAL_<unique prefix>.` prefix. For beispiel for `PIHOLE` (`"unique_prefix": "PIHOLE"`) it is `EXTERNAL_PIHOLE.`. The external SQLite database file has to be mapped in the container to the path specified in the `DB_PATH` setting:
You can execute a SQL query on an external database connected to the current NetAlertX database via a temporary `EXTERNAL_<unique prefix>.` prefix.
> 🔎Beispiel
For example for `PIHOLE` (`"unique_prefix": "PIHOLE"`) it is `EXTERNAL_PIHOLE.`. The external SQLite database file has to be mapped in the container to the path specified in the `DB_PATH` setting:
> 🔎Example
>
>```json
> ...
@@ -258,9 +230,9 @@ You can execute a SQL query on an external database connected to the current PiA
> ...
>```
The actual SQL query you want to execute is then stored as a `CMD` setting, similar to the `pialert-db-query` plugin type The format has to adhere to the format outlined in the "Column order and values" section above.
The actual SQL query you want to execute is then stored as a `CMD` setting, similar to a Plugin of the `app-db-query` plugin type. The format has to adhere to the format outlined in the "Column order and values" section above.
> 🔎Beispiel
> 🔎Example
>
> Notice the `EXTERNAL_PIHOLE.` prefix.
>
@@ -282,9 +254,9 @@ The actual SQL query you want to execute is then stored as a `CMD` setting, simi
> }
> ```
## 🕳 Filter
## 🕳 Filters
Plugin-Einträge können in der Benutzeroberfläche basierend auf in Filterfeldern eingegebenen Werten gefiltert werden. Das Textfeld/Feld `txtMacFilter` enthält die Mac-Adresse des aktuell angezeigten Geräts oder einfach eine Mac-Adresse, die in der Abfragezeichenfolge `mac` verfügbar ist.
Plugin entries can be filtered in the UI based on values entered into filter fields. The `txtMacFilter` textbox/field contains the Mac address of the currently viewed device, or simply a Mac address that's available in the `mac` query string (`<url>?mac=aa:22:aa:22:aa:22:aa`).
| Property | Required | Description |
|----------------------|----------------------|----------------------|
@@ -294,9 +266,9 @@ Plugin-Einträge können in der Benutzeroberfläche basierend auf in Filterfelde
| `compare_js_template` | yes | JavaScript code used to convert left and right side of the equation. `{value}` is replaced with input values. |
| `compare_use_quotes` | yes | If `true` then the end result of the `compare_js_template` i swrapped in `"` quotes. Use to compare strings. |
Filters are only applied if a filter is specified and the `txtMacFilter` is not `undefined` or empty (`--`).
Filters are only applied if a filter is specified, and the `txtMacFilter` is not `undefined`, or empty (`--`).
> 🔎Beispiel:
> 🔎Example:
>
> ```json
> "data_filters": [
@@ -310,7 +282,7 @@ Plugin-Einträge können in der Benutzeroberfläche basierend auf in Filterfelde
> ],
> ```
>
>1. On the `pluginsCore.php` page is an input field with the `txtMacFilter` id:
>1. On the `pluginsCore.php` page is an input field with the id `txtMacFilter`:
>
>```html
><input class="form-control" id="txtMacFilter" type="text" value="--">
@@ -324,27 +296,27 @@ Plugin-Einträge können in der Benutzeroberfläche basierend auf in Filterfelde
>
>5. `compare_use_quotes` is set to `true` so `'{value}'.toString()` is wrappe dinto `"` quotes.
>
>6. Daraus ergibt sich beispielsweise dieser code:
>6. This results in for example this code:
>
>```javascript
> // left part of teh expression coming from compare_column and right from the input field
> // left part of the expression coming from compare_column and right from the input field
> // notice the added quotes ()") around the left and right part of teh expression
> "eval('ac:82:ac:82:ac:82".toString()')" == "eval('ac:82:ac:82:ac:82".toString()')"
>```
>
### 🗺 Zuordnung der Plugin-Ergebnisse zu einer Datenbanktabelle
### 🗺 Mapping the plugin results into a database table
Plugin results are always inserted into the standard `Plugin_Objects` database table. Optionally, PiAlert can take the results of the plugin execution and insert these results into an additional database table. This is enabled by with the property `"mapped_to_table"` in the `config.json` file. The mapping of the columns is defined in the `database_column_definitions` array.
Plugin results are always inserted into the standard `Plugin_Objects` database table. Optionally, NetAlertX can take the results of the plugin execution, and insert these results into an additional database table. This is enabled by with the property `"mapped_to_table"` in the `config.json` file. The mapping of the columns is defined in the `database_column_definitions` array.
> [!NOTE]
> If results are mapped to the `CurrentScan` table, the data is then included into the regular scan loop, so for beispiel notification for devices are sent out.
> If results are mapped to the `CurrentScan` table, the data is then included into the regular scan loop, so for example notification for devices are sent out.
>🔍 Beispiel:
>🔍 Example:
>
>For beispiel, this approach is used to implement the `DHCPLSS` plugin. The script parses all supplied "dhcp.leases" files, gets the results in the generic table format outlined in the "Column order and values" section above and takes individual values and inserts them into the `CurrentScan` database table in the PiAlert database. All this is achieved by:
>For example, this approach is used to implement the `DHCPLSS` plugin. The script parses all supplied "dhcp.leases" files, gets the results in the generic table format outlined in the "Column order and values" section above, takes individual values, and inserts them into the `CurrentScan` database table in the NetAlertX database. All this is achieved by:
>
>1. Specifying the database table into which the results are inserted by defining `"mapped_to_table": "CurrentScan"` in the root of the `config.json` file as shown below:
>
@@ -359,7 +331,7 @@ Plugin results are always inserted into the standard `Plugin_Objects` database t
> ...
>}
>```
>2. Defining the target column with the `mapped_to_column` property for individual columns in the `database_column_definitions` array of the `config.json` file. For beispiel in the `DHCPLSS` plugin, I needed to map the value of the `Object_PrimaryID` column returned by the plugin, to the `cur_MAC` column in the PiAlert database `CurrentScan` table. Notice the `"mapped_to_column": "cur_MAC"` key-value pair in the sample below.
>2. Defining the target column with the `mapped_to_column` property for individual columns in the `database_column_definitions` array of the `config.json` file. For example in the `DHCPLSS` plugin, I needed to map the value of the `Object_PrimaryID` column returned by the plugin, to the `cur_MAC` column in the NetAlertX database table `CurrentScan`. Notice the `"mapped_to_column": "cur_MAC"` key-value pair in the sample below.
>
>```json
>{
@@ -378,13 +350,13 @@ Plugin results are always inserted into the standard `Plugin_Objects` database t
> }
>```
>
>3. That's it. PiAlert takes care of the rest. It loops thru the objects discovered by the plugin, takes the results line, by line and inserts them into the database table specified in `"mapped_to_table"`. The columns are translated from the generic plugin columns to the target table via the `"mapped_to_column"` property in the column definitions.
>3. That's it. The app takes care of the rest. It loops thru the objects discovered by the plugin, takes the results line-by-line, and inserts them into the database table specified in `"mapped_to_table"`. The columns are translated from the generic plugin columns to the target table columns via the `"mapped_to_column"` property in the column definitions.
> [!NOTE]
> You can create a column mapping with a default value via the `mapped_to_column_data` property. This means that the value of the given column will always be this value. Taht also menas that the `"column": "NameDoesntMatter"` is not important as there is no database source column.
> You can create a column mapping with a default value via the `mapped_to_column_data` property. This means that the value of the given column will always be this value. That also menas that the `"column": "NameDoesntMatter"` is not important as there is no database source column.
>🔍 Beispiel:
>🔍 Example:
>
>```json
>{
@@ -408,13 +380,24 @@ Plugin results are always inserted into the standard `Plugin_Objects` database t
#### params
The `params` array in the `config.json` is used to enable the user to change the parameters of the executed script. For beispiel, the user wants to monitor a specific URL.
> [!IMPORTANT]
> An esier way to access settings in scripts is the `get_setting_value` method.
> ```python
> from helper import get_setting_value
>
> ...
> NTFY_TOPIC = get_setting_value('NTFY_TOPIC')
> ...
>
> ```
> 🔎 Beispiel:
The `params` array in the `config.json` is used to enable the user to change the parameters of the executed script. For example, the user wants to monitor a specific URL.
> 🔎 Example:
> Passing user-defined settings to a command. Let's say, you want to have a script, that is called with a user-defined parameter called `urls`:
>
> ```bash
> root@server# python3 /home/pi/pialert/front/plugins/website_monitor/script.py urls=https://google.com,https://duck.com
> root@server# python3 /app/front/plugins/website_monitor/script.py urls=https://google.com,https://duck.com
> ```
* You can allow the user to add URLs to a setting with the `function` property set to a custom name, such as `urls_to_check` (this is not a reserved name from the section "Supported settings `function` values" below).
@@ -435,7 +418,7 @@ The `params` array in the `config.json` is used to enable the user to change the
{
"function": "CMD",
"type": "text",
"default_value":"python3 /home/pi/pialert/front/plugins/website_monitor/script.py urls={urls}",
"default_value":"python3 /app/front/plugins/website_monitor/script.py urls={urls}",
"options": [],
"localized": ["name", "description"],
"name" : [{
@@ -449,7 +432,7 @@ The `params` array in the `config.json` is used to enable the user to change the
}
```
During script execution, the app will take the command `"python3 /home/pi/pialert/front/plugins/website_monitor/script.py urls={urls}"`, take the `{urls}` wildcard and replace it with the value from the `WEBMON_urls_to_check` setting. This is because:
During script execution, the app will take the command `"python3 /app/front/plugins/website_monitor/script.py urls={urls}"`, take the `{urls}` wildcard and replace it with the value from the `WEBMON_urls_to_check` setting. This is because:
1. The app checks the `params` entries
2. It finds `"name" : "urls"`
@@ -461,9 +444,9 @@ During script execution, the app will take the command `"python3 /home/pi/pialer
- let's say the setting with the code name `WEBMON_urls_to_check` contains 2 values entered by the user:
- `WEBMON_urls_to_check=['https://google.com','https://duck.com']`
6. The app takes the value from `WEBMON_urls_to_check` and replaces the `{urls}` wildcard in the setting where `"function":"CMD"`, so you go from:
- `python3 /home/pi/pialert/front/plugins/website_monitor/script.py urls={urls}`
- `python3 /app/front/plugins/website_monitor/script.py urls={urls}`
- to
- `python3 /home/pi/pialert/front/plugins/website_monitor/script.py urls=https://google.com,https://duck.com`
- `python3 /app/front/plugins/website_monitor/script.py urls=https://google.com,https://duck.com`
Below are some general additional notes, when defining `params`:
@@ -476,7 +459,7 @@ Below are some general additional notes, when defining `params`:
- `"base64": true` - use base64 encoding to pass the value to the script (e.g. if there are spaces)
> 🔎Beispiel:
> 🔎Example:
>
> ```json
> {
@@ -506,10 +489,10 @@ Below are some general additional notes, when defining `params`:
> ```
#### ⚙ Objektstruktur festlegen
#### ⚙ Setting object structure
> [!NOTE]
> Der Einstellungsablauf und wann Plugin-spezifische Einstellungen angewendet werden, wird im [Einstellungssystem](/docs/SETTINGS_SYSTEM.md) beschrieben.
> The settings flow and when Plugin specific settings are applied is described under the [Settings system](/docs/SETTINGS_SYSTEM.md).
Required attributes are:
@@ -526,19 +509,20 @@ Required attributes are:
| | - `text.select` |
| | - `text.multiselect` |
| | - `list` |
| | - `list.select` |
| | - `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` |
| | - `"test"` - For notification plugins testing |
| | - `"run"` - Regular plugins testing |
| (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. |
##### Unterstützte Einstellungen `function` werte
##### 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.
@@ -546,15 +530,16 @@ You can have any `"function": "my_custom_name"` custom name, however, the ones l
| ------- | ----------- |
| `RUN` | (required) Specifies when the service is executed. |
| | Supported Options: |
| | - "disabled" - not run |
| | - "disabled" - do 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 |
| | - "before_name_updates" - run before device names are updated (for name discovery plugins) |
| | - "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`. |
| | - "before_config_save" - run before the config is marked as saved. Useful if your plugin needs to modify the `app.conf` file. |
| `RUN_SCHD` | (required if you include "schedule" in 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` | (not implemented) Generates a `table_` + `code_name` + `.json` file as per [API docs](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/API.md). |
| `API_SQL` | (not implemented) Generates a `table_` + `code_name` + `.json` file as per [API docs](https://github.com/jokob-sk/NetAlertX/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: |
@@ -564,8 +549,7 @@ You can have any `"function": "my_custom_name"` custom name, however, the ones l
| | - `missing-in-last-scan` - if the object is missing compared to previous scans |
> 🔎 Beispiel:
> 🔎 Example:
>
> ```json
> {
@@ -585,12 +569,12 @@ You can have any `"function": "my_custom_name"` custom name, however, the ones l
> }
> ```
##### 🌍Lokalisierte Zeichenfolgen
##### 🌍Localized strings
- `"language_code":"<en_us|es_es|de_de>"` - code name of the language string. Only these three are currently supported. At least the `"language_code":"en_us"` variant has to be defined.
- `"string"` - The string to be displayed in the given language.
> 🔎 Beispiel:
> 🔎 Example:
>
> ```json
>
@@ -601,7 +585,7 @@ You can have any `"function": "my_custom_name"` custom name, however, the ones l
>
> ```
##### UI-Einstellungen in database_column_definitions.
##### UI settings in database_column_definitions
The UI will adjust how columns are displayed in the UI based on the resolvers definition of the `database_column_definitions` object. These are the supported form controls and related functionality:
@@ -610,9 +594,11 @@ The UI will adjust how columns are displayed in the UI based on the resolvers de
| 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`. |
| `textarea_readonly` | Generates a read only text area and cleans up the text to display it somewhat formatted with new lines preserved. |
| See below for information on `threshold`, `replace`. | |
| | |
| `options` Property | Used in conjunction with types like `threshold`, `replace`, `regex`. |
| `options_params` Property | Used in conjunction with a `"options": "[{value}]"` template and `text.select`/`list.select`. Can specify SQL query (needs to return 2 columns `SELECT dev_Name as name, dev_Mac as id`) or Setting (not tested) to populate the dropdown. Check example below or have a look at the `NEWDEV` plugin `config.json` file. |
| `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". |
| `regex` | Applies a regex to the value. The `options` array contains objects with an `type` (must be set to `regex`) and `param` (must contain the regex itself) property. |
@@ -624,12 +610,33 @@ The UI will adjust how columns are displayed in the UI based on the resolvers de
| `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. |
| `url_http_https` | Generates two links with the `https` and `http` prefix as lock icons. |
| `eval` | Evaluates as JavaScript. Use the variable `value` to use the given column value as input (e.g. `'<b>${value}<b>'` (replace ' with ` in your code) ) |
> [!NOTE]
> Unterstützt Verkettung. Sie können mehrere Resolver mit „.“ verketten. Zum Beispiel `regex.url_http_https`. Dadurch wird der Resolver `regex` und dann der Resolver `url_http_https` angewendet.
> Supports chaining. You can chain multiple resolvers with `.`. For example `regex.url_http_https`. This will apply the `regex` resolver and then the `url_http_https` resolver.
```json
"function": "dev_DeviceType",
"type": "text.select",
"maxLength": 30,
"default_value": "",
"options": ["{value}"],
"options_params" : [
{
"name" : "value",
"type" : "sql",
"value" : "SELECT '' as id, '' as name UNION SELECT dev_DeviceType as id, dev_DeviceType as name FROM (SELECT dev_DeviceType FROM Devices UNION SELECT 'Smartphone' UNION SELECT 'Tablet' UNION SELECT 'Laptop' UNION SELECT 'PC' UNION SELECT 'Printer' UNION SELECT 'Server' UNION SELECT 'NAS' UNION SELECT 'Domotic' UNION SELECT 'Game Console' UNION SELECT 'SmartTV' UNION SELECT 'Clock' UNION SELECT 'House Appliance' UNION SELECT 'Phone' UNION SELECT 'AP' UNION SELECT 'Gateway' UNION SELECT 'Firewall' UNION SELECT 'Switch' UNION SELECT 'WLAN' UNION SELECT 'Router' UNION SELECT 'Other') AS all_devices ORDER BY id;"
},
{
"name" : "uilang",
"type" : "setting",
"value" : "UI_LANG"
}
]
```
```json
{
@@ -715,8 +722,8 @@ The UI will adjust how columns are displayed in the UI based on the resolvers de
}
```
[screen1]: https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/docs/img/plugins.png "Screen 1"
[screen2]: https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/docs/img/plugins_settings.png "Screen 2"
[screen3]: https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/docs/img/plugins_json_settings.png "Screen 3"
[screen4]: https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/docs/img/plugins_json_ui.png "Screen 4"
[screen5]: https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/docs/img/plugins_device_details.png "Screen 5"
[screen1]: https://raw.githubusercontent.com/jokob-sk/NetAlertX/main/docs/img/plugins.png "Screen 1"
[screen2]: https://raw.githubusercontent.com/jokob-sk/NetAlertX/main/docs/img/plugins_settings.png "Screen 2"
[screen3]: https://raw.githubusercontent.com/jokob-sk/NetAlertX/main/docs/img/plugins_json_settings.png "Screen 3"
[screen4]: https://raw.githubusercontent.com/jokob-sk/NetAlertX/main/docs/img/plugins_json_ui.png "Screen 4"
[screen5]: https://raw.githubusercontent.com/jokob-sk/NetAlertX/main/docs/img/plugins_device_details.png "Screen 5"

View File

@@ -12,7 +12,7 @@ know, but it **is totally useless when connecting to our own WIFI's** or known
networks.
**I recommend disabling this operation when connecting our devices to our own
WIFI's**, in this way, Pi.Alert will be able to identify the device, and it
WIFI's**, in this way, NetAlertX will be able to identify the device, and it
will not identify it as a new device every so often (every time IOS or Android
decides to change the MAC).
@@ -37,11 +37,11 @@ decides to change the MAC).
### Contact
Always use the Issue tracker for the correct fork, for example:
[jokob-sk/Pi.Alert](https://github.com/jokob-sk/Pi.Alert/issues). Please also follow the guidelines on:
[jokob-sk/NetAlertX](https://github.com/jokob-sk/NetAlertX/issues). Please also follow the guidelines on:
- [Pull Request guidelines](https://github.com/jokob-sk/Pi.Alert/tree/main/docs#-pull-requests-prs)
- 🙏 [Feature request guidelines](https://github.com/jokob-sk/Pi.Alert/tree/main/docs#-feature-requests)
- 🐛 [Issue guidelines](https://github.com/jokob-sk/Pi.Alert/tree/main/docs#-submitting-an-issue-or-bug)
- [Pull Request guidelines](https://github.com/jokob-sk/NetAlertX/tree/main/docs#-pull-requests-prs)
- 🙏 [Feature request guidelines](https://github.com/jokob-sk/NetAlertX/tree/main/docs#-feature-requests)
- 🐛 [Issue guidelines](https://github.com/jokob-sk/NetAlertX/tree/main/docs#-submitting-an-issue-or-bug)
***Suggestions and comments are welcome***

View File

@@ -13,11 +13,11 @@ There is also an in-app Help / FAQ section that should be answering frequently a
#### 🐳 Docker (Fully supported)
- The main installation method is as a [docker container - follow these instructions here](https://github.com/jokob-sk/Pi.Alert/blob/main/dockerfiles/README.md).
- The main installation method is as a [docker container - follow these instructions here](https://github.com/jokob-sk/NetAlertX/blob/main/dockerfiles/README.md).
#### 💻 Bare-metal / On-server (Experimental/community supported 🧪)
- [(Experimental 🧪) On-hardware instructions](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/HW_INSTALL.md)
- [(Experimental 🧪) On-hardware instructions](https://github.com/jokob-sk/NetAlertX/blob/main/docs/HW_INSTALL.md)
- Alternative bare-metal install forks:
- [leiweibau's fork](https://github.com/leiweibau/Pi.Alert/) (maintained)
@@ -30,9 +30,11 @@ There is also an in-app Help / FAQ section that should be answering frequently a
- [Subnets and VLANs configuration for arp-scan](/docs/SUBNETS.md)
- [SMTP server config](/docs/SMTP.md)
- [Custom Icon configuration and support](/docs/ICONS.md)
- [Notifications](/docs/NOTIFICATIONS.md)
- [Better name resolution with Reverse DNS](/docs/REVERSE_DNS.md)
- [Network treemap configuration](/docs/NETWORK_TREE.md)
- [Backups](/docs/BACKUPS.md)
- [Plugins overview](/front/plugins/README.md)
#### 🐛 Debugging help & tips
@@ -40,6 +42,7 @@ There is also an in-app Help / FAQ section that should be answering frequently a
- [Debugging UI not showing](/docs/WEB_UI_PORT_DEBUG.md)
- [Invalid JSON errors debug help](/docs/DEBUG_INVALID_JSON.md)
- [Troubleshooting Plugins](/docs/DEBUG_PLUGINS.md)
- [File Permissions](/docs/FILE_PERMISSIONS.md)
#### 🔝 Popular/Suggested
@@ -63,10 +66,10 @@ There is also an in-app Help / FAQ section that should be answering frequently a
#### 👩💻For Developers👨💻
- [APP code structure](/pialert/README.md)
- [Server APP code structure](/server/README.md)
- [Database structure](/docs/DATABASE.md)
- [API endpoints details](/docs/API.md)
- [Plugin system details and how to develop your own](/front/plugins/README.md)
- [Plugin development guide](/docs/PLUGINS_DEV.md)
- [Settings system](/docs/SETTINGS_SYSTEM.md)
- [New Version notifications](/docs/VERSIONS.md)
- [Frontend development tips](/docs/FRONTEND_DEVELOPMENT.md)
@@ -83,7 +86,7 @@ Priorities from highest to lowest:
* 🔵 Refactoring enabling faster implementation of future functionality
* 🔽 (low) UI functionality & improvements (PRs welcome 😉)
Design philosophy: Focus on core functionality and leverage existing apps and tools to make PiAlert integrate into other workflows.
Design philosophy: Focus on core functionality and leverage existing apps and tools to make NetAlertX integrate into other workflows.
Examples:
@@ -122,15 +125,15 @@ Suggested test cases:
Some additional context:
* Permanent settings/config is stored in the `pialert.conf` file
* Permanent settings/config is stored in the `app.conf` file
* Currently temporary (session?) settings are stored in the `Parameters` DB table as key-value pairs. This table is wiped during a container rebuild/restart and its values are re-initialized from cookies/session data from the browser.
## 🐛 Submitting an issue or bug
Before submitting a new issue please spend a couple of minutes on research:
* Check [🛑 Common issues](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEBUG_TIPS.md#common-issues)
* Check [💡 Closed issues](https://github.com/jokob-sk/Pi.Alert/issues?q=is%3Aissue+is%3Aclosed) if a similar issue was solved in the past.
* When submitting an issue ❗[enable debug](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEBUG_TIPS.md)❗
* Check [🛑 Common issues](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEBUG_TIPS.md#common-issues)
* Check [💡 Closed issues](https://github.com/jokob-sk/NetAlertX/issues?q=is%3Aissue+is%3Aclosed) if a similar issue was solved in the past.
* When submitting an issue ❗[enable debug](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEBUG_TIPS.md)❗
⚠ Please follow the pre-defined issue template to resolve your issue faster.

View File

@@ -1,6 +1,6 @@
## Setting up better name discovery with Reverse DNS
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 PiAlert to execute dig and nslookup commands to automatically resolve device names based on their IP addresses.
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.
> Example 1: Reverse DNS `disabled`
@@ -36,20 +36,18 @@ You can configure a custom **/etc/resolv.conf** file in **docker-compose.yml** a
```yaml
version: "3"
services:
pialert:
container_name: pialert
image: "jokobsk/pi.alert:latest"
netalertx:
container_name: netalertx
image: "jokobsk/netalertx:latest"
restart: unless-stopped
volumes:
- ./config/pialert.conf:/home/pi/pialert/config/pialert.conf
- ./pialert_db:/home/pi/pialert/db
- ./log:/home/pi/pialert/front/log
- ./config/app.conf:/app/config/app.conf
- ./db:/app/db
- ./log:/app/front/log
- ./config/resolv.conf:/etc/resolv.conf # Mapping the /resolv.conf file for better name resolution
environment:
- TZ=Europe/Berlin
- PORT=20211
- HOST_USER_ID=1000
- HOST_USER_GID=1000
ports:
- "20211:20211"
network_mode: host

View File

@@ -4,18 +4,18 @@
> [!NOTE]
> There are 2 NGINX files for PiAlert, one for the bare-metal Debian install (`pialert.debian.conf`), and one for the docker container (`pialert.template.conf`). Both can be found in the [install](https://github.com/jokob-sk/Pi.Alert/tree/main/install) folder. Map, or use, the one appropriate for your setup.
> There are 2 NGINX files for NetAlertX, one for the bare-metal Debian install (`netalertx.debian.conf`), and one for the docker container (`netalertx.template.conf`). Both can be found in the [install](https://github.com/jokob-sk/NetAlertX/tree/main/install) folder. Map, or use, the one appropriate for your setup.
## NGINX HTTP Configuration (Direct Path)
1. On your NGINX server, create a new file called /etc/nginx/sites-available/pialert
1. On your NGINX server, create a new file called /etc/nginx/sites-available/netalertx
2. In this file, paste the following code:
```
server {
listen 80;
server_name pi.alert;
server_name netalertx;
proxy_preserve_host on;
proxy_pass http://localhost:20211/;
proxy_pass_reverse http://localhost:20211/;
@@ -26,26 +26,26 @@
`nginx -s reload` or `systemctl restart nginx`
4. Once NGINX restarts, you should be able to access the proxy website at http://pi.alert/
4. Once NGINX restarts, you should be able to access the proxy website at http://netalertx/
<br>
## NGINX HTTP Configuration (Sub Path)
1. On your NGINX server, create a new file called /etc/nginx/sites-available/pialert
1. On your NGINX server, create a new file called /etc/nginx/sites-available/netalertx
2. In this file, paste the following code:
```
server {
listen 80;
server_name pi.alert;
server_name netalertx;
proxy_preserve_host on;
location ^~ /pi.alert/ {
location ^~ /netalertx/ {
proxy_pass http://localhost:20211/;
proxy_pass_reverse http://localhost:20211/;
proxy_redirect ~^/(.*)$ /pi.alert/$1;
rewrite ^/pi.alert/?(.*)$ /$1 break;
proxy_redirect ~^/(.*)$ /netalertx/$1;
rewrite ^/netalertx/?(.*)$ /$1 break;
}
}
```
@@ -54,34 +54,34 @@
`nginx -s reload` or `systemctl restart nginx`
4. Once NGINX restarts, you should be able to access the proxy website at http://pi.alert/pi.alert/
4. Once NGINX restarts, you should be able to access the proxy website at http://netalertx/netalertx/
<br>
## NGINX HTTP Configuration (Sub Path) with module ngx_http_sub_module
1. On your NGINX server, create a new file called /etc/nginx/sites-available/pialert
1. On your NGINX server, create a new file called /etc/nginx/sites-available/netalertx
2. In this file, paste the following code:
```
server {
listen 80;
server_name pi.alert;
server_name netalertx;
proxy_preserve_host on;
location ^~ /pi.alert/ {
location ^~ /netalertx/ {
proxy_pass http://localhost:20211/;
proxy_pass_reverse http://localhost:20211/;
proxy_redirect ~^/(.*)$ /pi.alert/$1;
rewrite ^/pi.alert/?(.*)$ /$1 break;
proxy_redirect ~^/(.*)$ /netalertx/$1;
rewrite ^/netalertx/?(.*)$ /$1 break;
sub_filter_once off;
sub_filter_types *;
sub_filter 'href="/' 'href="/pi.alert/';
sub_filter '(?>$host)/css' '/pi.alert/css';
sub_filter '(?>$host)/js' '/pi.alert/js';
sub_filter '/img' '/pi.alert/img';
sub_filter '/lib' '/pi.alert/lib';
sub_filter '/php' '/pi.alert/php';
sub_filter 'href="/' 'href="/netalertx/';
sub_filter '(?>$host)/css' '/netalertx/css';
sub_filter '(?>$host)/js' '/netalertx/js';
sub_filter '/img' '/netalertx/img';
sub_filter '/lib' '/netalertx/lib';
sub_filter '/php' '/netalertx/php';
}
}
```
@@ -90,23 +90,23 @@
`nginx -s reload` or `systemctl restart nginx`
4. Once NGINX restarts, you should be able to access the proxy website at http://pi.alert/pi.alert/
4. Once NGINX restarts, you should be able to access the proxy website at http://netalertx/netalertx/
<br>
**NGINX HTTPS Configuration (Direct Path)**
1. On your NGINX server, create a new file called /etc/nginx/sites-available/pialert
1. On your NGINX server, create a new file called /etc/nginx/sites-available/netalertx
2. In this file, paste the following code:
```
server {
listen 443;
server_name pi.alert;
server_name netalertx;
SSLEngine On;
SSLCertificateFile /etc/ssl/certs/pi.alert.pem;
SSLCertificateKeyFile /etc/ssl/private/pi.alert.key;
SSLCertificateFile /etc/ssl/certs/netalertx.pem;
SSLCertificateKeyFile /etc/ssl/private/netalertx.key;
proxy_preserve_host on;
proxy_pass http://localhost:20211/;
proxy_pass_reverse http://localhost:20211/;
@@ -117,28 +117,28 @@
`nginx -s reload` or `systemctl restart nginx`
4. Once NGINX restarts, you should be able to access the proxy website at https://pi.alert/
4. Once NGINX restarts, you should be able to access the proxy website at https://netalertx/
<br>
**NGINX HTTPS Configuration (Sub Path)**
1. On your NGINX server, create a new file called /etc/nginx/sites-available/pialert
1. On your NGINX server, create a new file called /etc/nginx/sites-available/netalertx
2. In this file, paste the following code:
```
server {
listen 443;
server_name pi.alert;
server_name netalertx;
SSLEngine On;
SSLCertificateFile /etc/ssl/certs/pi.alert.pem;
SSLCertificateKeyFile /etc/ssl/private/pi.alert.key;
location ^~ /pi.alert/ {
SSLCertificateFile /etc/ssl/certs/netalertx.pem;
SSLCertificateKeyFile /etc/ssl/private/netalertx.key;
location ^~ /netalertx/ {
proxy_pass http://localhost:20211/;
proxy_pass_reverse http://localhost:20211/;
proxy_redirect ~^/(.*)$ /pi.alert/$1;
rewrite ^/pi.alert/?(.*)$ /$1 break;
proxy_redirect ~^/(.*)$ /netalertx/$1;
rewrite ^/netalertx/?(.*)$ /$1 break;
}
}
```
@@ -147,36 +147,36 @@
`nginx -s reload` or `systemctl restart nginx`
4. Once NGINX restarts, you should be able to access the proxy website at https://pi.alert/pi.alert/
4. Once NGINX restarts, you should be able to access the proxy website at https://netalertx/netalertx/
<br>
## NGINX HTTPS Configuration (Sub Path) with module ngx_http_sub_module
1. On your NGINX server, create a new file called /etc/nginx/sites-available/pialert
1. On your NGINX server, create a new file called /etc/nginx/sites-available/netalertx
2. In this file, paste the following code:
```
server {
listen 443;
server_name pi.alert;
server_name netalertx;
SSLEngine On;
SSLCertificateFile /etc/ssl/certs/pi.alert.pem;
SSLCertificateKeyFile /etc/ssl/private/pi.alert.key;
location ^~ /pi.alert/ {
SSLCertificateFile /etc/ssl/certs/netalertx.pem;
SSLCertificateKeyFile /etc/ssl/private/netalertx.key;
location ^~ /netalertx/ {
proxy_pass http://localhost:20211/;
proxy_pass_reverse http://localhost:20211/;
proxy_redirect ~^/(.*)$ /pi.alert/$1;
rewrite ^/pi.alert/?(.*)$ /$1 break;
proxy_redirect ~^/(.*)$ /netalertx/$1;
rewrite ^/netalertx/?(.*)$ /$1 break;
sub_filter_once off;
sub_filter_types *;
sub_filter 'href="/' 'href="/pi.alert/';
sub_filter '(?>$host)/css' '/pi.alert/css';
sub_filter '(?>$host)/js' '/pi.alert/js';
sub_filter '/img' '/pi.alert/img';
sub_filter '/lib' '/pi.alert/lib';
sub_filter '/php' '/pi.alert/php';
sub_filter 'href="/' 'href="/netalertx/';
sub_filter '(?>$host)/css' '/netalertx/css';
sub_filter '(?>$host)/js' '/netalertx/js';
sub_filter '/img' '/netalertx/img';
sub_filter '/lib' '/netalertx/lib';
sub_filter '/php' '/netalertx/php';
}
}
```
@@ -185,19 +185,19 @@
`nginx -s reload` or `systemctl restart nginx`
4. Once NGINX restarts, you should be able to access the proxy website at https://pi.alert/pi.alert/
4. Once NGINX restarts, you should be able to access the proxy website at https://netalertx/netalertx/
<br>
## Apache HTTP Configuration (Direct Path)
1. On your Apache server, create a new file called /etc/apache2/sites-available/pialert.conf.
1. On your Apache server, create a new file called /etc/apache2/sites-available/netalertx.conf.
2. In this file, paste the following code:
```
<VirtualHost *:80>
ServerName pi.alert
ServerName netalertx
ProxyPreserveHost On
ProxyPass / http://localhost:20211/
ProxyPassReverse / http://localhost:20211/
@@ -206,22 +206,22 @@
3. Activate the new website by running the following command:
`a2ensite pialert` or `service apache2 reload`
`a2ensite netalertx` or `service apache2 reload`
4. Once Apache restarts, you should be able to access the proxy website at http://pi.alert/
4. Once Apache restarts, you should be able to access the proxy website at http://netalertx/
<br>
## Apache HTTP Configuration (Sub Path)
1. On your Apache server, create a new file called /etc/apache2/sites-available/pialert.conf.
1. On your Apache server, create a new file called /etc/apache2/sites-available/netalertx.conf.
2. In this file, paste the following code:
```
<VirtualHost *:80>
ServerName pi.alert
location ^~ /pi.alert/ {
ServerName netalertx
location ^~ /netalertx/ {
ProxyPreserveHost On
ProxyPass / http://localhost:20211/
ProxyPassReverse / http://localhost:20211/
@@ -231,24 +231,24 @@
3. Activate the new website by running the following command:
`a2ensite pialert` or `service apache2 reload`
`a2ensite netalertx` or `service apache2 reload`
4. Once Apache restarts, you should be able to access the proxy website at http://pi.alert/
4. Once Apache restarts, you should be able to access the proxy website at http://netalertx/
<br>
## Apache HTTPS Configuration (Direct Path)
1. On your Apache server, create a new file called /etc/apache2/sites-available/pialert.conf.
1. On your Apache server, create a new file called /etc/apache2/sites-available/netalertx.conf.
2. In this file, paste the following code:
```
<VirtualHost *:443>
ServerName pi.alert
ServerName netalertx
SSLEngine On
SSLCertificateFile /etc/ssl/certs/pi.alert.pem
SSLCertificateKeyFile /etc/ssl/private/pi.alert.key
SSLCertificateFile /etc/ssl/certs/netalertx.pem
SSLCertificateKeyFile /etc/ssl/private/netalertx.key
ProxyPreserveHost On
ProxyPass / http://localhost:20211/
ProxyPassReverse / http://localhost:20211/
@@ -257,25 +257,25 @@
3. Activate the new website by running the following command:
`a2ensite pialert` or `service apache2 reload`
`a2ensite netalertx` or `service apache2 reload`
4. Once Apache restarts, you should be able to access the proxy website at https://pi.alert/
4. Once Apache restarts, you should be able to access the proxy website at https://netalertx/
<br>
## Apache HTTPS Configuration (Sub Path)
1. On your Apache server, create a new file called /etc/apache2/sites-available/pialert.conf.
1. On your Apache server, create a new file called /etc/apache2/sites-available/netalertx.conf.
2. In this file, paste the following code:
```
<VirtualHost *:443>
ServerName pi.alert
ServerName netalertx
SSLEngine On
SSLCertificateFile /etc/ssl/certs/pi.alert.pem
SSLCertificateKeyFile /etc/ssl/private/pi.alert.key
location ^~ /pi.alert/ {
SSLCertificateFile /etc/ssl/certs/netalertx.pem
SSLCertificateKeyFile /etc/ssl/private/netalertx.key
location ^~ /netalertx/ {
ProxyPreserveHost On
ProxyPass / http://localhost:20211/
ProxyPassReverse / http://localhost:20211/
@@ -285,9 +285,9 @@
3. Activate the new website by running the following command:
`a2ensite pialert` or `service apache2 reload`
`a2ensite netalertx` or `service apache2 reload`
4. Once Apache restarts, you should be able to access the proxy website at https://pi.alert/pi.alert/
4. Once Apache restarts, you should be able to access the proxy website at https://netalertx/netalertx/
## Reverse proxy example by using LinuxServer's SWAG container.
@@ -295,20 +295,20 @@
## [linuxserver/swag](https://github.com/linuxserver/docker-swag)
In the SWAG container create `/config/nginx/proxy-confs/pialert.subfolder.conf` with the following contents:
In the SWAG container create `/config/nginx/proxy-confs/netalertx.subfolder.conf` with the following contents:
``` nginx
## Version 2023/02/05
# make sure that your pialert container is named pialert
# pialert does not require a base url setting
# make sure that your netalertx container is named netalertx
# netalertx does not require a base url setting
# Since Pi.Alert uses a Host network, you may need to use the IP address of the system running Pi.Alert for $upstream_app.
# Since NetAlertX uses a Host network, you may need to use the IP address of the system running NetAlertX for $upstream_app.
location /pialert {
return 301 $scheme://$host/pialert/;
location /netalertx {
return 301 $scheme://$host/netalertx/;
}
location ^~ /pialert/ {
location ^~ /netalertx/ {
# enable the next two lines for http auth
#auth_basic "Restricted";
#auth_basic_user_file /config/nginx/.htpasswd;
@@ -325,44 +325,44 @@ location ^~ /pialert/ {
include /config/nginx/proxy.conf;
include /config/nginx/resolver.conf;
set $upstream_app pialert;
set $upstream_app netalertx;
set $upstream_port 20211;
set $upstream_proto http;
proxy_pass $upstream_proto://$upstream_app:$upstream_port;
proxy_set_header Accept-Encoding "";
proxy_redirect ~^/(.*)$ /pialert/$1;
rewrite ^/pialert/?(.*)$ /$1 break;
proxy_redirect ~^/(.*)$ /netalertx/$1;
rewrite ^/netalertx/?(.*)$ /$1 break;
sub_filter_once off;
sub_filter_types *;
sub_filter 'href="/' 'href="/pialert/';
sub_filter 'href="/' 'href="/netalertx/';
sub_filter '(?>$host)/css' '/pialert/css';
sub_filter '(?>$host)/js' '/pialert/js';
sub_filter '(?>$host)/css' '/netalertx/css';
sub_filter '(?>$host)/js' '/netalertx/js';
sub_filter '/img' '/pialert/img';
sub_filter '/lib' '/pialert/lib';
sub_filter '/php' '/pialert/php';
sub_filter '/img' '/netalertx/img';
sub_filter '/lib' '/netalertx/lib';
sub_filter '/php' '/netalertx/php';
}
```
## Traefik
> Submitted by [Isegrimm](https://github.com/Isegrimm) 🙏 (based on this [discussion](https://github.com/jokob-sk/Pi.Alert/discussions/449#discussioncomment-7281442))
> Submitted by [Isegrimm](https://github.com/Isegrimm) 🙏 (based on this [discussion](https://github.com/jokob-sk/NetAlertX/discussions/449#discussioncomment-7281442))
Asuming the user already has a working Traefik setup, this is what's needed to make Pi.Alert work at a URL like www.domain.com/pialert/.
Asuming the user already has a working Traefik setup, this is what's needed to make NetAlertX work at a URL like www.domain.com/netalertx/.
Note: Everything in these configs assumes '**www.domain.com**' as your domainname and '**section31**' as an arbitrary name for your certificate setup. You will have to substitute these with your own.
Also, I use the prefix '**pialert**'. If you want to use another prefix, change it in these files: dynamic.toml and default.
Also, I use the prefix '**netalertx**'. If you want to use another prefix, change it in these files: dynamic.toml and default.
Content of my yaml-file (this is the generic Traefik config, which defines which ports to listen on, redirect http to https and sets up the certificate process).
It also contains Authelia, which I use for authentication.
This part contains nothing specific to Pi.Alert.
This part contains nothing specific to NetAlertX.
```yaml
version: '3.8'
@@ -406,29 +406,29 @@ services:
restart: u
nless-stopped
```
Snippet of the dynamic.toml file (referenced in the yml-file above) that defines the config for Pi.Alert:
Snippet of the dynamic.toml file (referenced in the yml-file above) that defines the config for NetAlertX:
The following are self-defined keywords, everything else is traefik keywords:
- pialert-router
- pialert-service
- netalertx-router
- netalertx-service
- auth
- pialert-stripprefix
- netalertx-stripprefix
```toml
[http.routers]
[http.routers.pialert-router]
[http.routers.netalertx-router]
entryPoints = ["websecure"]
rule = "Host(`www.domain.com`) && PathPrefix(`/pialert`)"
service = "pialert-service"
middlewares = "auth,pialert-stripprefix"
[http.routers.pialert-router.tls]
rule = "Host(`www.domain.com`) && PathPrefix(`/netalertx`)"
service = "netalertx-service"
middlewares = "auth,netalertx-stripprefix"
[http.routers.netalertx-router.tls]
certResolver = "section31"
[[http.routers.pialert-router.tls.domains]]
[[http.routers.netalertx-router.tls.domains]]
main = "www.domain.com"
[http.services]
[http.services.pialert-service]
[[http.services.pialert-service.loadBalancer.servers]]
[http.services.netalertx-service]
[[http.services.netalertx-service.loadBalancer.servers]]
url = "http://internal-ip-address:20211/"
[http.middlewares]
@@ -436,12 +436,12 @@ The following are self-defined keywords, everything else is traefik keywords:
address = "http://authelia:9091/api/verify?rd=https://www.domain.com/authelia/"
trustForwardHeader = true
authResponseHeaders = ["Remote-User", "Remote-Groups", "Remote-Name", "Remote-Email"]
[http.middlewares.pialert-stripprefix.stripprefix]
prefixes = "/pialert"
[http.middlewares.netalertx-stripprefix.stripprefix]
prefixes = "/netalertx"
forceSlash = false
```
To make Pi.Alert work with this setup I modified the default file at `/etc/nginx/sites-available/default` in the docker container by copying it to my local filesystem, adding the changes as specified by [cvc90](https://github.com/cvc90) and mounting the new file into the docker container, overwriting the original one. By mapping the file instead of changing the file in-place, the changes persist if an updated dockerimage is pulled. This is also a downside when the default file is updated, so I only use this as a temporary solution, until the dockerimage is updated with this change.
To make NetAlertX work with this setup I modified the default file at `/etc/nginx/sites-available/default` in the docker container by copying it to my local filesystem, adding the changes as specified by [cvc90](https://github.com/cvc90) and mounting the new file into the docker container, overwriting the original one. By mapping the file instead of changing the file in-place, the changes persist if an updated dockerimage is pulled. This is also a downside when the default file is updated, so I only use this as a temporary solution, until the dockerimage is updated with this change.
Default-file:
@@ -450,9 +450,9 @@ server {
listen 80 default_server;
root /var/www/html;
index index.php;
#rewrite /pialert/(.*) / permanent;
add_header X-Forwarded-Prefix "/pialert" always;
proxy_set_header X-Forwarded-Prefix "/pialert";
#rewrite /netalertx/(.*) / permanent;
add_header X-Forwarded-Prefix "/netalertx" always;
proxy_set_header X-Forwarded-Prefix "/netalertx";
location ~* \.php$ {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
@@ -466,18 +466,18 @@ server {
}
```
Mapping the updated file (on the local filesystem at `/appl/docker/pialert/default`) into the docker container:
Mapping the updated file (on the local filesystem at `/appl/docker/netalertx/default`) into the docker container:
```bash
docker run -d --rm --network=host \
--name=pi.alert \
-v /appl/docker/pialert/config:/home/pi/pialert/config \
-v /appl/docker/pialert/db:/home/pi/pialert/db \
-v /appl/docker/pialert/default:/etc/nginx/sites-available/default \
--name=netalertx \
-v /appl/docker/netalertx/config:/app/config \
-v /appl/docker/netalertx/db:/app/db \
-v /appl/docker/netalertx/default:/etc/nginx/sites-available/default \
-e TZ=Europe/Amsterdam \
-e PORT=20211 \
jokobsk/pi.alert:latest
jokobsk/netalertx:latest
```

View File

@@ -6,11 +6,11 @@ If you are a user of the app, settings have a detailed description in the _Setti
### 🛢 Data storage
The source of truth for user-defined values is the `pialert.conf` file. Editing the file makes the App overwrite values in the `Settings` database table and in the `table_settings.json` file.
The source of truth for user-defined values is the `app.conf` file. Editing the file makes the App overwrite values in the `Settings` database table and in the `table_settings.json` file.
#### Settings database table
The `Settings` database table contains settings for App run purposes. The table is recreated every time the App restarts. The settings are loaded from the source-of-truth, that is the `pialert.conf` file. A high-level overview on the database structure can be found in the [database documentation](/docs/DATABASE.md).
The `Settings` database table contains settings for App run purposes. The table is recreated every time the App restarts. The settings are loaded from the source-of-truth, that is the `app.conf` file. A high-level overview on the database structure can be found in the [database documentation](/docs/DATABASE.md).
#### table_settings.json
@@ -20,27 +20,27 @@ This is the [API endpoint](/docs/API.md) that reflects the state of the `Setting
The json file is also cached on the client-side local storage of the browser.
#### pialert.conf
#### app.conf
> [!NOTE]
> This is the source of truth for settings. User-defined values in this files always override default values specified in the Plugin definition.
The App generates two `pialert.conf` entries for every setting (Since version 23.8+). One entry is the setting value, the second is the `__metadata` associated with the setting. This `__metadata` entry contains the full setting definition in JSON format. Currently unused, but intended to be used in future to extend the Settings system.
The App generates two `app.conf` entries for every setting (Since version 23.8+). One entry is the setting value, the second is the `__metadata` associated with the setting. This `__metadata` entry contains the full setting definition in JSON format. Currently unused, but intended to be used in future to extend the Settings system.
#### Plugin settings
> [!NOTE]
> This is the preferred way adding settings going forward. I'll be likely migrating all app settings into plugin-based settings.
Plugin settings are loaded dynamically from the `config.json` of individual plugins. If a setting isn't defined in the `pialert.conf` file, it is initialized via the `default_value` property of a setting from the `config.json` file. Check the [Plugins documentation](https://github.com/jokob-sk/Pi.Alert/blob/main/front/plugins/README.md#-setting-object-structure), section `⚙ Setting object structure` for details on the structure of the setting.
Plugin settings are loaded dynamically from the `config.json` of individual plugins. If a setting isn't defined in the `app.conf` file, it is initialized via the `default_value` property of a setting from the `config.json` file. Check the [Plugins documentation](https://github.com/jokob-sk/NetAlertX/blob/main/front/plugins/README.md#-setting-object-structure), section `⚙ Setting object structure` for details on the structure of the setting.
![Screen 1][screen1]
### Settings Process flow
The process flow is mostly managed by the [initialise.py](/pialert/initialise.py) file.
The process flow is mostly managed by the [initialise.py](/server/initialise.py) file.
The script is responsible for reading user-defined values from a configuration file (`pialert.conf`), initializing settings, and importing them into a database. It also handles plugins and their configurations.
The script is responsible for reading user-defined values from a configuration file (`app.conf`), initializing settings, and importing them into a database. It also handles plugins and their configurations.
Here's a high-level description of the code:
@@ -49,7 +49,7 @@ Here's a high-level description of the code:
- `importConfigs`: This function is the main entry point of the script. It imports user settings from a configuration file, processes them, and saves them to the database.
- `read_config_file`: This function reads the configuration file (`pialert.conf`) and returns a dictionary containing the key-value pairs from the file.
- `read_config_file`: This function reads the configuration file (`app.conf`) and returns a dictionary containing the key-value pairs from the file.
2. Importing Configuration and Initializing Settings:
- The `importConfigs` function starts by checking the modification time of the configuration file to determine if it needs to be re-imported. If the file has not been modified since the last import, the function skips the import process.
@@ -74,4 +74,4 @@ Here's a high-level description of the code:
_____________________
[screen1]: https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/docs/img/plugins_json_settings.png "Screen 1"
[screen1]: https://raw.githubusercontent.com/jokob-sk/NetAlertX/main/docs/img/plugins_json_settings.png "Screen 1"

View File

@@ -6,10 +6,10 @@
2. Under Security Options enable 2FA (Two-factor authentication)
3. Under Security Options generate an Application-specific password
4. Home -> Email Settings -> POP3 & IMAP -> Enable access to this account via POP3 and IMAP
5. In PiAlert specify these settings:
5. In NetAlertX specify these settings:
```python
REPORT_MAIL=True
SMTP_RUN='on_notification'
SMTP_SERVER='mail.gmx.com'
SMTP_PORT=465
SMTP_USER='gmx_email@gmx.com'
@@ -17,8 +17,8 @@
SMTP_SKIP_TLS=True
SMTP_FORCE_SSL=True
SMTP_SKIP_LOGIN=False
REPORT_FROM='gmx_email@gmx.com' # this has to be the same email as in SMTP_USER
REPORT_TO='some_target_email@gmail.com'
SMTP_REPORT_FROM='gmx_email@gmx.com' # this has to be the same email as in SMTP_USER
SMTP_REPORT_TO='some_target_email@gmail.com'
```
@@ -30,12 +30,12 @@
2. Specify the following settings:
```python
REPORT_MAIL=True
SMTP_RUN='on_notification'
SMTP_SKIP_TLS=True
SMTP_FORCE_SSL=True
SMTP_PORT=465
SMTP_SERVER='smtp.gmail.com'
SMTP_PASS='16-digit passcode from google'
REPORT_TO='some_target_email@gmail.com'
SMTP_REPORT_TO='some_target_email@gmail.com'
```

View File

@@ -1,19 +1,19 @@
# Subnets configuration for arp-scan
# Subnets configuration
You need to specify the network interface and the network mask. You can also configure multiple subnets and specify VLANS (see exceptions below).
> [!TIP]
> You may need to increase the time between scans `ARPSCAN_RUN_SCHD` and the timeout `ARPSCAN_RUN_TIMEOUT` settings when adding more subnets. If the timeout setting is exceeded, the scan is cancelled to prevent application hanging from rogue plugins. Check [debugging plugins](/docs/DEBUG_PLUGINS.md) for more tips.
> You may need to increase the time between scans `ARPSCAN_RUN_SCHD` and the timeout `ARPSCAN_RUN_TIMEOUT` (and similar setting on related plugins) when adding more subnets. If the timeout setting is exceeded, the scan is cancelled to prevent application hanging from rogue plugins. Check [debugging plugins](/docs/DEBUG_PLUGINS.md) for more tips.
## Examples
> [!NOTE]
> Please use the UI to configure settings as that ensures that the config file is in the correct format. Edit `pialert.conf` directly only when really necessary.
> ![settings](/front/plugins/arp_scan/arp-scan-settings.png)
> Please use the UI to configure settings as that ensures that the config file is in the correct format. Edit `app.conf` directly only when really necessary.
> ![settings](/docs/img/SUBNETS/subnets-setting-location.png)
* Examples for one and two subnets (❗ Note the `['...', '...']` format):
* One subnet: `SCAN_SUBNETS = ['192.168.1.0/24 --interface=eth0']`
* Two subnets: `SCAN_SUBNETS = ['192.168.1.0/24 --interface=eth0', '192.168.1.0/24 --interface=eth1 -vlan=107']`
* Examples for one and two subnets (❗ Note the `['...','...']` format):
* One subnet: `SCAN_SUBNETS = ['192.168.1.0/24 --interface=eth0']`
* Two subnets: `SCAN_SUBNETS = ['192.168.1.0/24 --interface=eth0','192.168.1.0/24 --interface=eth1 -vlan=107']`
## Explanation
@@ -27,7 +27,7 @@ The arp-scan time itself depends on the number of IP addresses to check.
> The number of IPs to check depends on the [network mask](https://www.calculator.net/ip-subnet-calculator.html) you set on the `SCAN_SUBNETS` setting.
> For example, a `/24` mask results in 256 IPs to check, whereas a `/16` mask checks around 65,536. Every IP takes a couple of seconds. This means that with an incorrect configuration, the arp-scan will take hours to complete instead of seconds.
Specify the network filter (which **significantly** speeds up the scan process). For example, the filter `192.168.1.0/24` covers IP ranges 192.168.1.0 to 192.168.1.255.
Specify the network filter (which **significantly** speeds up the scan process). For example, the filter `192.168.1.0/24` covers IP ranges `192.168.1.0` to `192.168.1.255`.
### Network interface (adapter)
@@ -44,15 +44,15 @@ The adapter will probably be `eth0` or `eth1`. (Check `System info` > `Network H
**Example value: `-vlan=107`**
- Append e.g.: ` -vlan=107` to the interface field (e.g.: `eth0 -vlan=107`) for multiple vlans. More details in this [comment in this issue](https://github.com/jokob-sk/Pi.Alert/issues/170#issuecomment-1419902988)
- Append e.g.: ` -vlan=107` to the interface field (e.g.: `eth0 -vlan=107`) for multiple vlans. More details in this [comment in this issue](https://github.com/jokob-sk/NetAlertX/issues/170#issuecomment-1419902988)
#### VLANs on a Hyper-V setup
> Community sourced content by [mscreations](https://github.com/mscreations) from this [discussion](https://github.com/jokob-sk/Pi.Alert/discussions/404).
> Community sourced content by [mscreations](https://github.com/mscreations) from this [discussion](https://github.com/jokob-sk/NetAlertX/discussions/404).
> [!NOTE]
> The setup this was tested on: Bare Metal -> Hyper-V on Win Server 2019 -> Ubuntu 22.04 VM -> Docker -> PiAlert.
> The setup this was tested on: Bare Metal -> Hyper-V on Win Server 2019 -> Ubuntu 22.04 VM -> Docker -> NetAlertX.
**Approach 1 (may cause issues):**
@@ -91,8 +91,8 @@ network:
via: 192.168.1.1
```
3) Run `sudo netplan apply` and the interfaces are then available to scan in PiAlert.
4) In this case, use `192.168.2.0/24 --interface=eth0.2` in PiAlert
3) Run `sudo netplan apply` and the interfaces are then available to scan in NetAlertX.
4) In this case, use `192.168.2.0/24 --interface=eth0.2` in NetAlertX
#### VLAN 🔍Example:
@@ -102,6 +102,6 @@ network:
Please note the accessibility of the macvlans when they are configured on the same computer. My understanding this is a general networking behavior, but feel free to clarify via a PR/issue.
- Pi.Alert does not detect the macvlan container when it is running on the same computer.
- Pi.Alert recognizes the macvlan container when it is running on a different computer.
- NetAlertX does not detect the macvlan container when it is running on the same computer.
- NetAlertX recognizes the macvlan container when it is running on a different computer.

View File

@@ -1,6 +1,6 @@
## Am I running the latest released version?
Since version 23.01.14 PiAlert uses a simple timestamp-based version check to verify if a new version is available. You can check the [current and past releases here](https://github.com/jokob-sk/Pi.Alert/releases), or have a look at what I'm [currently working on](https://github.com/jokob-sk/Pi.Alert/issues/138).
Since version 23.01.14 NetAlertX uses a simple timestamp-based version check to verify if a new version is available. You can check the [current and past releases here](https://github.com/jokob-sk/NetAlertX/releases), or have a look at what I'm [currently working on](https://github.com/jokob-sk/NetAlertX/issues/138).
If you are not on the latest version, the app will notify you, that a new released version is avialable the following way:
@@ -22,4 +22,4 @@ For a comparison, this is how the UI looks like if you are on the latest stable
## Implementation details
During build a [/home/pi/pialert/front/buildtimestamp.txt](https://github.com/jokob-sk/Pi.Alert/blob/092797e75ccfa8359444ad149e727358ac4da05f/Dockerfile#L44) file is created. The app then periodically checks if a new release is available with a newer timestamp in GitHub's rest-based JSON endpoint (check the `def isNewVersion():` method in `pialert.py` for details).
During build a [/app/front/buildtimestamp.txt](https://github.com/jokob-sk/NetAlertX/blob/092797e75ccfa8359444ad149e727358ac4da05f/Dockerfile#L44) file is created. The app then periodically checks if a new release is available with a newer timestamp in GitHub's rest-based JSON endpoint (check the `def isNewVersion():` method for details).

View File

@@ -14,7 +14,7 @@
| v2.50 | First public release |
# 🆕 2022+ [Newest Release notes](https://github.com/jokob-sk/Pi.Alert/issues/138)
# 🆕 2022+ [Newest Release notes](https://github.com/jokob-sk/NetAlertX/issues/138)
## Pi.Alert v3.02
<!--- --------------------------------------------------------------------- --->
@@ -79,9 +79,9 @@
### Contact
Always use the Issue tracker for the correct fork, for example:
[jokob-sk/Pi.Alert](https://github.com/jokob-sk/Pi.Alert/issues). Please also follow the guidelines on:
[jokob-sk/NetAlertX](https://github.com/jokob-sk/NetAlertX/issues). Please also follow the guidelines on:
- [Pull Request guidelines](https://github.com/jokob-sk/Pi.Alert/tree/main/docs#-pull-requests-prs)
- 🙏 [Feature request guidelines](https://github.com/jokob-sk/Pi.Alert/tree/main/docs#-feature-requests)
- 🐛 [Issue guidelines](https://github.com/jokob-sk/Pi.Alert/tree/main/docs#-submitting-an-issue-or-bug)
- [Pull Request guidelines](https://github.com/jokob-sk/NetAlertX/tree/main/docs#-pull-requests-prs)
- 🙏 [Feature request guidelines](https://github.com/jokob-sk/NetAlertX/tree/main/docs#-feature-requests)
- 🐛 [Issue guidelines](https://github.com/jokob-sk/NetAlertX/tree/main/docs#-submitting-an-issue-or-bug)

View File

@@ -5,7 +5,7 @@ N8N can be used for more advanced conditional notification use cases. For exampl
![n8n workflow](/docs/img/WEBHOOK_N8N/n8n_workflow.png)
### Specify your email template
See [sample JSON](https://github.com/jokob-sk/Pi.Alert/blob/main/back/webhook_json_sample.json) if you want to see the JSON paths used in the email template below
See [sample JSON](https://github.com/jokob-sk/NetAlertX/blob/main/front/report_templates/webhook_json_sample.json) if you want to see the JSON paths used in the email template below
![Email template](/docs/img/WEBHOOK_N8N/n8n_send_email_settings.png)
```
@@ -16,5 +16,5 @@ New devices count: {{ $json["body"]["attachments"][0]["text"]["new_devices"].len
### Get your webhook in n8n
![n8n webhook URL](/docs/img/WEBHOOK_N8N/n8n_webhook_settings.png)
### Configure PiAlert to point to the above URL
![PiAlert config](/docs/img/WEBHOOK_N8N/Webhook_settings.png)
### Configure NetAlertX to point to the above URL
![NetAlertX config](/docs/img/WEBHOOK_N8N/Webhook_settings.png)

View File

@@ -2,7 +2,7 @@
## How does the signing work?
Pi.Alert will use the configured secret to create a hash signature of the request body. This SHA256-HMAC signature will appear in the `X-Webhook-Signature` header of each request to the webhook target URL. You can use the value of this header to validate the request was sent by Pi.Alert.
NetAlertX will use the configured secret to create a hash signature of the request body. This SHA256-HMAC signature will appear in the `X-Webhook-Signature` header of each request to the webhook target URL. You can use the value of this header to validate the request was sent by NetAlertX.
## Activating webhook signatures
@@ -12,7 +12,7 @@ All you need to do in order to add a signature to the request headers is to set
There are a few things to keep in mind when validating the webhook delivery:
- Pi.Alert uses an HMAC hex digest to compute the hash
- NetAlertX uses an HMAC hex digest to compute the hash
- The signature in the `X-Webhook-Signature` header always starts with `sha256=`
- The hash signature is generated using the configured `WEBHOOK_SECRET` and the request body.
- Never use a plain `==` operator. Instead, consider using a method like [`secure_compare`](https://www.rubydoc.info/gems/rack/Rack%2FUtils:secure_compare) or [`crypto.timingSafeEqual`](https://nodejs.org/api/crypto.html#cryptotimingsafeequala-b), which performs a "constant time" string comparison to help mitigate certain timing attacks against regular equality operators, or regular loops in JIT-optimized languages.

View File

@@ -3,7 +3,7 @@
When opening an issue please :
1. Include a screenshot of what you see when accessing `HTTP://<your rpi IP>/20211` (or your custom port)
1. [Follow steps 1, 2, 3, 4 on this page](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEBUG_TIPS.md)
1. [Follow steps 1, 2, 3, 4 on this page](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEBUG_TIPS.md)
1. Execute the following in the container to see the processes and their ports and submit a screenshot of the result:
1. `sudo apt-get install lsof`
1. `sudo lsof -i`

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 KiB

View File

Before

Width:  |  Height:  |  Size: 291 KiB

After

Width:  |  Height:  |  Size: 291 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

BIN
docs/img/ICONS/paste-svg.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View File

@@ -1,8 +1,8 @@
/* -----------------------------------------------------------------------------
# Pi.Alert
# NetAlertX
# Open Source Network Guard / WIFI & LAN intrusion detector
#
# pialert.css - Front module. CSS styles
# app.css - Front module. CSS styles
#-------------------------------------------------------------------------------
# Puche 2021 / 2022+ jokob jokob@duck.com GNU GPLv3
----------------------------------------------------------------------------- */
@@ -144,6 +144,32 @@
{
background-color: rgba(0, 0, 0, 0);
}
.unread-notifications-bell
{
position: absolute;
top: 3px;
margin-left: 15px;
display: none;
}
.navbar-custom-menu .bg-yellow
{
color: white !important;
}
.header-status-locked-db
{
width: 25px;
height: 25px;
color: red;
position: absolute;
top: 12px;
right: -17px;
display: none;
}
.navbar-nav > li > a
{
line-height: 30px;
@@ -151,10 +177,26 @@
/* -----------------------------------------------------------------------------
Customized Main Menu
----------------------------------------------------------------------------- */
.NetAlertX-logo
{
border-color:transparent !important;
height: 50px !important;
width: 50px !important;
margin-top:15px !important;
border-radius: 1px !important;
}
.main-header .logo {
width: 150px;
}
.navbar-nav > .user-menu .user-image
{
margin-top: 3px;
}
.main-header>.navbar {
margin-left: 150px;
}
@@ -465,29 +507,109 @@
/* -----------------------------------------------------------------------------
Notification float banner
----------------------------------------------------------------------------- */
.pa_alert_notification {
.notification_modal {
text-align: center;
font-size: large;
font-weight: bold;
color: #258744;
background-color: #d4edda;
border-color: #c3e6cb;
border-radius: 5px;
max-width: 1000px;
/* 80% wrapper 1250px */
left: 0;
right: 0;
width: 80%;
z-index: 9999;
position: fixed;
top: 30px;
margin: auto;
transform: translate(0, 0);
top: 100px;
display: none;
margin-left: auto;
margin-right: auto;
}
.modal_green
{
color: #258744;
background-color: #d4edda;
border-color: #c3e6cb;
}
.modal_red
{
color: rgb(245, 245, 245);
background-color: #e2acaa;
border-color: #d41001;
}
.modal_grey
{
color: white;
background-color: darkgrey;
border-color: #000000;
}
/* ticker setup */
.ticker-li
{
width: 40%;
}
#ticker_announcement_plc
{
/* height: 50px; */
overflow: hidden;
width: 65%;
position: absolute;
left: 40px;
top: 15px;
}
@media (max-width: 1500px) and (min-width: 1101px) {
#ticker_announcement_plc {
width: 45%; /* Width for screen sizes between 1100px and 730px */
}
}
@media (max-width: 1100px) and (min-width: 801px) {
#ticker_announcement_plc {
width: 30%; /* Width for screen sizes between 1100px and 730px */
}
}
@media (max-width: 800px) {
#ticker_announcement_plc {
width: 25%; /* Width for screen sizes less than 730px */
}
}
#ticker-message a
{
color:#3200bb;
text-decoration: underline;
}
#ticker-message
{
color:#FFFFFF;
}
#ticker_announcement_plc:hover .ticker_announcement {
animation-play-state: paused;
}
@keyframes marquee {
0% {
transform: translateX(100%);
}
100% {
transform: translateX(-150%);
}
}
.ticker_announcement {
text-align: center;
white-space: nowrap;
animation: marquee 20s linear infinite;
cursor: default;
}
/* maintenance buttons */
.dbtools-button {
display: inline-block;
width: 160px;
@@ -589,6 +711,11 @@ height: 50px;
/* report */
/* --------------------------------------------------------- */
#notificationData
{
margin-bottom: 10px;
}
#notificationData textarea{
width: 100%;
}
@@ -635,6 +762,11 @@ height: 50px;
}
}
.settingswrap
{
margin-bottom: 100px;
}
.settingswrap .metadata
{
display: none;
@@ -645,11 +777,16 @@ height: 50px;
float: right;
}
.padding-bottom
{
padding-bottom: 100px;
}
.settings-group
{
font-size: 20px;
padding-top: 7px;
padding-bottom: 9px;
padding-bottom: 9px;
}
.overview-section .small-box .icon
@@ -660,12 +797,12 @@ height: 50px;
.overview-section
{
border: solid;
/* border-top: solid;
border-width: medium;
border-width: medium;
border-width: 1px;
border-radius: 15px;
margin-bottom: 3px;
border-radius: 15px;
margin-bottom: 3px; */
}
@@ -678,6 +815,7 @@ height: 50px;
font-size: 20px;
padding-top: 7px;
padding-bottom: 9px;
margin-left: -20px;
}
@@ -737,7 +875,28 @@ height: 50px;
#settingsPage .overview-setting-value{
display:unset;
}
.overview-setting-value-wrap
{
padding-left: 1px;
text-overflow: clip ;
overflow: hidden;
}
#settingsPage .small-box
{
padding-left: 10px;
padding-right: 10px;
}
#settingsPage .small-box .inner
{
padding-left: 0px;
padding-right: 0px;
}
#settingsPage .panel-title{
/* display: inline-block; */
/* width: 120px; */
@@ -746,6 +905,17 @@ height: 50px;
text-overflow: ellipsis;
}
.padding-5px
{
padding: 5px;
}
.text-overflow-hidden
{
overflow: hidden;
text-overflow: clip;
}
.settings_content {
padding: 10px;
@@ -792,9 +962,91 @@ input[readonly] {
cursor: not-allowed;
}
/* Devices */
.interactable-option:hover::before {
opacity: 1;
}
.interactable-option::before {
content: '1x 📝 | 2x 🚮';
position: sticky;
right: 0px;
top: 0;
color: white;
float: right;
background-color: rgb(0, 0, 0);
transition: opacity 0.5s;
opacity: 0.1;
border-radius: 3px;
}
.interactable-option:hover {
transition: background-color 2s;
cursor: pointer;
}
.settingsImportedTimestamp
{
padding: 25px;
}
.settingsSearchWrap
{
padding:10px;
}
.settings-sticky-bottom-section {
position: fixed;
z-index: 999;
background-color: #5B5B66;
/* opacity: 0.8; */
bottom: 30px;
border-radius: 5px;
margin:1px;
border-width: 1px;
border-style: solid;
border-color: inherit;
/* width: 87%; */
}
.settings-sticky-bottom-section:hover {
border-color: #258744;
}
.settings-sticky-bottom-section .form-group
{
margin-bottom: 0px;
}
.clear-filter
{
opacity: 0.5;
cursor: pointer;
width: 14px;
position: absolute;
right: -6px;
top: 6px;
}
.clear-filter:hover
{
opacity: 1;
}
.saveSettingsWrapper button
{
width:70%;
margin-top:20px;
margin-left:15%;
margin-bottom:20px;
}
/* ----------------------------------------------------------------- */
/* Devices page */
/* ----------------------------------------------------------------- */
#txtIconFA {
min-width: 18px;
min-width: 40px;
}
@@ -846,7 +1098,36 @@ input[readonly] {
margin-bottom: 6px;
}
#tableDevicesBox td svg, #tableDevicesBox td i{
height: 1.5em !important;
}
#dropdownIcon li svg, #dropdownIcon li i{
height: 1.5em !important;
}
/* ----------------------------------------------------------------- */
/* MODAL popups */
/* ----------------------------------------------------------------- */
#modal-input-textarea
{
width: 100%;
}
.modal-field-input
{
margin: 4%;
width: 92%;
}
/* ----------------------------------------------------------------- */
/* NETWORK page */
/* ----------------------------------------------------------------- */
/* AdminLTE overrides */
#networkTree .box
@@ -890,11 +1171,18 @@ input[readonly] {
}
#networkTree .netIcon
{
width: 25px;;
width: 25px;
float:left;
display:inline;
text-align: center;
}
#networkTree .netIcon svg
{
height: 1.2em;
width: auto;
}
#networkTree .netCollapse
{
display: block;
@@ -921,6 +1209,31 @@ input[readonly] {
text-overflow: ellipsis;
}
.networkTable .nav-tabs li i, .networkTable .nav-tabs li svg {
padding: 3px;
height: 2em !important;
/* width: 2em !important; */
position: absolute;
/* z-index: 10; */
top: 0.3em;
/* margin-left: 0.2em; */
}
.networkTable .icon {
/* padding-left:2em; */
width:2em;
height:2em;
float: left;
/* background-color:red; */
}
/* ----------------------------------------------------------------- */
/* PLUGINS page */
/* ----------------------------------------------------------------- */
.plugin-filters
{
margin: 7px;
@@ -993,6 +1306,7 @@ input[readonly] {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: white;
}

View File

@@ -17,9 +17,10 @@ html {
background-color: #353c42;
}
body {
background-color: #353c42;
color: #bec5cb;
body, .bg-yellow, .callout.callout-warning, .alert-warning, .label-warning, .modal-warning .modal-body {
background-color: #353c42 !important;
color: #bec5cb !important;
}
h4 {
color: #44def1;

View File

@@ -1,6 +1,6 @@
<!--
#---------------------------------------------------------------------------------#
# Pi.Alert #
# NetAlertX #
# Open Source Network Guard / WIFI & LAN intrusion detector #
# #
# deviceDetails.php - Front module. Device management page #
@@ -164,6 +164,7 @@
<button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<span class="fa fa-caret-down "></span></button>
<ul id="dropdownOwner" class="dropdown-menu dropdown-menu-right">
<li id="dropdownOwner_tmp"></li>
</ul>
</div>
</div>
@@ -181,7 +182,7 @@
<button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-expanded="false" >
<span class="fa fa-caret-down"></span></button>
<ul id="dropdownDeviceType" class="dropdown-menu dropdown-menu-right">
<li id="dropdownDeviceType_tmp"></li>
</ul>
</div>
</div>
@@ -189,21 +190,23 @@
</div>
<!-- Icon -->
<div class="form-group" title="<?= lang('DevDetail_Icon_Descr');?>">
<div class="form-group" >
<label class="col-sm-3 control-label">
<?= lang('DevDetail_Icon');?>
<a href="https://github.com/jokob-sk/Pi.Alert/blob/main/docs/ICONS.md" target="_blank"> <span><i class="fa fa-circle-question"></i></a><span>
<a href="https://github.com/jokob-sk/NetAlertX/blob/main/docs/ICONS.md" target="_blank"> <span><i class="fa fa-circle-question"></i></a><span>
</label>
<div class="col-sm-9">
<div class="input-group">
<span class="input-group-addon"><i class="fa" id="txtIconFA" onclick="editDrp('txtIcon');"></i></span>
<input class="form-control" id="txtIcon" type="text" value="--">
<span class="input-group-addon" id="txtIconFA"></span>
<input class="form-control" id="txtIcon" type="text" value="--" readonly>
<span class="input-group-addon" title='<?= lang('DevDetail_button_AddIcon_Tooltip');?>'><i class="fa fa-square-plus pointer" onclick="askAddIcon();"></i></span>
<span class="input-group-addon" title='<?= lang('DevDetail_button_OverwriteIcons_Tooltip');?>'><i class="fa fa-copy pointer" onclick="askOverwriteIconType();"></i></span>
<div class="input-group-btn">
<button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-expanded="false" >
<span class="fa fa-caret-down"></span>
</button>
<ul id="dropdownIcon" class="dropdown-menu dropdown-menu-right">
<ul id="dropdownIcon" class="dropdown-menu dropdown-menu-right" >
<li id="dropdownIcon_tmp"></li>
</ul>
</div>
</div>
@@ -238,6 +241,7 @@
<span class="fa fa-caret-down"></span>
</button>
<ul id="dropdownGroup" class="dropdown-menu dropdown-menu-right">
<li id="dropdownGroup_tmp"></li>
</ul>
</div>
</div>
@@ -255,7 +259,7 @@
<button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<span class="fa fa-caret-down"></span></button>
<ul id="dropdownLocation" class="dropdown-menu dropdown-menu-right">
<li id="dropdownLocation_tmp"></li>
</ul>
</div>
</div>
@@ -321,7 +325,7 @@
</div>
<!-- Network -->
<h4 class="bottom-border-aqua"><?= lang('DevDetail_MainInfo_Network_Title');?><span class="networkPageHelp"> <a target="_blank" href="https://github.com/jokob-sk/Pi.Alert/blob/main/docs/NETWORK_TREE.md"><i class="fa fa-circle-question"></i></a><span></h4>
<h4 class="bottom-border-aqua"><?= lang('DevDetail_MainInfo_Network_Title');?><span class="networkPageHelp"> <a target="_blank" href="https://github.com/jokob-sk/NetAlertX/blob/main/docs/NETWORK_TREE.md"><i class="fa fa-circle-question"></i></a><span></h4>
<div class="form-group" title="<?= lang('DevDetail_Network_Node_hover');?>">
<label class="col-sm-3 control-label"><?= lang('DevDetail_MainInfo_Network');?></label>
<div class="col-sm-9">
@@ -333,6 +337,7 @@
<button type="button" class="btn btn-info dropdown-toggle" data-mynodemac="" data-toggle="dropdown" aria-expanded="false" id="buttonNetworkNodeMac">
<span class="fa fa-caret-down"></span></button>
<ul id="dropdownNetworkNodeMac" class="dropdown-menu dropdown-menu-right">
<li id="dropdownNetworkNodeMac_tmp"></li>
</ul>
</div>
@@ -437,7 +442,7 @@
<span id="iconRandomMACactive" data-toggle="tooltip" data-placement="right" title="Random MAC is Active" class="hidden">
<i style="font-size: 24px;" class="text-yellow glyphicon glyphicon-random"></i> &nbsp &nbsp </span>
<a href="https://github.com/jokob-sk/Pi.Alert/blob/main/docs/RANDOM_MAC.md" target="_blank" style="color: #777;">
<a href="https://github.com/jokob-sk/NetAlertX/blob/main/docs/RANDOM_MAC.md" target="_blank" style="color: #777;">
<i class="fa fa-info-circle"></i> </a>
</div>
</div>
@@ -495,14 +500,10 @@
<!-- Buttons -->
<div class="col-xs-12">
<div class="pull-right">
<button type="button" class="btn btn-default pa-btn pa-btn-delete" style="margin-left:0px;"
id="btnDeleteEvents" onclick="askDeleteDeviceEvents()"> <?= lang('DevDetail_button_DeleteEvents');?> </button>
<button type="button" class="btn btn-default pa-btn pa-btn-delete" style="margin-left:0px;"
id="btnDelete" onclick="askDeleteDevice()"> <?= lang('DevDetail_button_Delete');?> </button>
<button type="button" class="btn btn-default pa-btn" style="margin-left:6px;"
id="btnRestore" onclick="getDeviceData(true)"> <?= lang('DevDetail_button_Reset');?> </button>
<button type="button" disabled class="btn btn-primary pa-btn" style="margin-left:6px; "
id="btnSave" onclick="setDeviceData()" > <?= lang('DevDetail_button_Save');?> </button>
<button type="button" class="btn btn-default pa-btn pa-btn-delete" style="margin-left:0px;" id="btnDeleteEvents" onclick="askDeleteDeviceEvents()"> <?= lang('DevDetail_button_DeleteEvents');?> </button>
<button type="button" class="btn btn-default pa-btn pa-btn-delete" style="margin-left:0px;" id="btnDelete" onclick="askDeleteDevice()"> <?= lang('DevDetail_button_Delete');?> </button>
<!-- <button type="button" class="btn btn-default pa-btn" style="margin-left:6px;" id="btnRestore" onclick="getDeviceData(true)"> <?= lang('DevDetail_button_Reset');?> </button> -->
<button type="button" disabled class="btn btn-primary pa-btn" style="margin-left:6px; " id="btnSave" onclick="setDeviceData()" > <?= lang('DevDetail_button_Save');?> </button>
</div>
</div>
@@ -621,6 +622,10 @@
<script src="lib/AdminLTE/bower_components/moment/moment.js"></script>
<script src="lib/AdminLTE/bower_components/fullcalendar/dist/fullcalendar.min.js"></script>
<script src="lib/AdminLTE/bower_components/fullcalendar/dist/locale-all.js"></script>
<!-- ----------------------------------------------------------------------- -->
<!-- ----------------------------------------------------------------------- -->
<!-- Dark-Mode Patch -->
<?php
@@ -632,14 +637,6 @@ if ($ENABLED_DARKMODE === True) {
<!-- page script ----------------------------------------------------------- -->
<script defer>
// ------------------------------------------------------------
function getMac(){
params = new Proxy(new URLSearchParams(window.location.search), {
get: (searchParams, prop) => searchParams.get(prop),
});
return params.mac
}
// ------------------------------------------------------------
function getDevicesList()
@@ -653,6 +650,26 @@ if ($ENABLED_DARKMODE === True) {
devicesList = [];
}
// only loop thru the filtered down list
visibleDevices = getCache("ntx_visible_macs")
if(visibleDevices != "") {
visibleDevicesMACs = visibleDevices.split(',');
devicesList_tmp = [];
// Iterate through the data and filter only visible devices
$.each(devicesList, function(index, item) {
// Check if the current item's MAC exists in visibleDevicesMACs
if (visibleDevicesMACs.includes(item.dev_MAC)) {
devicesList_tmp.push(item);
}
});
// Update devicesList with the filtered items
devicesList = devicesList_tmp;
}
return devicesList;
}
@@ -661,7 +678,6 @@ if ($ENABLED_DARKMODE === True) {
mac = getMac() // can also be rowID!! not only mac
var devicesList = []; // this will contain a list the database row IDs of the devices ordered by the position displayed in the UI
main();
var pos = -1;
var parPeriod = 'Front_Details_Period';
@@ -678,6 +694,7 @@ if ($ENABLED_DARKMODE === True) {
var selectedTab = 'tabDetails';
var emptyArr = ['undefined', "", undefined, null];
main();
// -----------------------------------------------------------------------------
@@ -701,67 +718,37 @@ function main () {
tab = selectedTab;
// get parameter value
$.get('php/server/parameters.php?action=get&defaultValue=1 day&parameter='+ parPeriod, function(data) {
var result = JSON.parse(data);
if (result) {
period = result;
$('#period').val(period);
period = '1 day';
sessionsRows = 50;
eventsRows = 50;
$('#chkHideConnectionEvents')[0].checked = eval(eventsHide == 'true');
// Initialize components with parameters
initializeTabs();
initializeiCheck();
initializeCombos();
initializeDatatables();
initializeCalendar();
// query data
getDeviceData(true);
getSessionsPresenceEvents();
// Force re-render calendar on tab change
// (bugfix for render error at left panel)
$(document).on('shown.bs.tab', 'a[data-toggle="tab"]', function (nav) {
if ($(nav.target).attr('href') == '#panPresence') {
$('#calendar').fullCalendar('rerenderEvents');
}
// get parameter value
$.get('php/server/parameters.php?action=get&defaultValue=50&parameter='+ parSessionsRows, function(data) {
var result = JSON.parse(data);
if (Number.isInteger (result) ) {
sessionsRows = result;
}
// get parameter value
$.get('php/server/parameters.php?action=get&defaultValue=50&parameter='+ parEventsRows, function(data) {
var result = JSON.parse(data);
if (Number.isInteger (result) ) {
eventsRows = result;
}
// get parameter value
$.get('php/server/parameters.php?action=get&defaultValue=true&parameter='+ parEventsHide, function(data) {
var result = JSON.parse(data);
if (result) {
eventsHide = result;
$('#chkHideConnectionEvents')[0].checked = eval(eventsHide == 'true');
}
// Initialize components with parameters
initializeTabs();
initializeiCheck();
initializeCombos();
initializeDatatables();
initializeCalendar();
// query data
getDeviceData(true);
getSessionsPresenceEvents();
// Force re-render calendar on tab change
// (bugfix for render error at left panel)
$(document).on('shown.bs.tab', 'a[data-toggle="tab"]', function (nav) {
if ($(nav.target).attr('href') == '#panPresence') {
$('#calendar').fullCalendar('rerenderEvents');
}
});
// Show device icon as it changes
$('#txtIcon').on('change input', function() {
$('#txtIconFA').removeClass().addClass(`fa fa-${$(this).val()} pointer`)
});
});
});
});
});
}
// Show device icon as it changes
$('#txtIcon').on('change input', function() {
updateIconPreview('#txtIcon')
});
}
// -----------------------------------------------------------------------------
@@ -820,15 +807,26 @@ function initializeiCheck () {
// -----------------------------------------------------------------------------
function initializeCombos () {
// Initialize combos with queries
initializeCombo ( '#dropdownOwner', 'getOwners', 'txtOwner', true);
initializeCombo ( '#dropdownDeviceType', 'getDeviceTypes', 'txtDeviceType', true);
initializeCombo ( '#dropdownGroup', 'getGroups', 'txtGroup', true);
initializeCombo ( '#dropdownLocation', 'getLocations', 'txtLocation', true);
initializeCombo ( '#dropdownNetworkNodeMac', 'getNetworkNodes', 'txtNetworkNodeMac', false);
initializeCombo ( '#dropdownIcon', 'getIcons', 'txtIcon', false);
initializeCombo ( '#dropdownAction', 'getActions', 'txtAction', false);
initializeCombo ( '#dropdownDevices', 'getDevices', 'txtFromDevice', false);
// Initiate dropdown
// function initSettingDropdown(settingKey, // Identifier for the setting
// valuesArray, // Array of values to be pre-selected in the dropdown
// targetLocation, // ID of the HTML element where dropdown should be rendered (will be replaced)
// callbackToGenerateEntries, // Callback function to generate entries based on options
// targetField, // Target field or element where selected value should be applied or updated
// nameTransformer) // callback to transform name
initSettingDropdown("NEWDEV_dev_Icon", [], "dropdownIcon_tmp", genListWithInputSet, 'txtIcon', atob )
initSettingDropdown("NEWDEV_dev_DeviceType", [], "dropdownDeviceType_tmp", genListWithInputSet, 'txtDeviceType' )
initSettingDropdown("NEWDEV_dev_Owner", [], "dropdownOwner_tmp", genListWithInputSet, 'txtOwner' )
initSettingDropdown("NEWDEV_dev_Group", [], "dropdownGroup_tmp", genListWithInputSet, 'txtGroup' )
initSettingDropdown("NEWDEV_dev_Location", [], "dropdownLocation_tmp", genListWithInputSet, 'txtLocation' )
initSettingDropdown("NEWDEV_dev_Network_Node_MAC_ADDR", [], "dropdownNetworkNodeMac_tmp", genListWithInputSet, 'txtNetworkNodeMac' )
// Initialize static combos
initializeComboSkipRepeated ();
}
@@ -904,9 +902,8 @@ function writeDropdownHtml(dropdownId, dropdownHtmlContent)
HTMLelement.innerHTML = ''
HTMLelement.innerHTML += dropdownHtmlContent;
}
// -----------------------------------------------------------------------------
function initializeComboSkipRepeated () {
// find dropdown menu element
HTMLelement = $('#dropdownSkipRepeated')[0];
@@ -1138,6 +1135,10 @@ function initializeCalendar () {
if (isLoading) {
showSpinner()
} else {
setTimeout(() => {
updateIconPreview('#txtIcon')
}, 100);
hideSpinner()
}
}
@@ -1303,7 +1304,7 @@ function getDeviceData (readAllData=false) {
$('#txtOwner').val (deviceData['dev_Owner']);
$('#txtDeviceType').val (deviceData['dev_DeviceType']);
$('#txtVendor').val (deviceData['dev_Vendor']);
$('#txtIcon').val (initDefault(deviceData['dev_Icon'], 'laptop'));
$('#txtIcon').val (initDefault(deviceData['dev_Icon'], 'PGkgY2xhc3M9ImZhIGZhLWxhcHRvcCI+PC9pPg==')); // base64 laptop icon
$('#txtIcon').trigger('change')
if (deviceData['dev_Favorite'] == 1) {$('#chkFavorite').iCheck('check');} else {$('#chkFavorite').iCheck('uncheck');}
@@ -1436,17 +1437,19 @@ function setDeviceData (direction='', refreshCallback='') {
return;
}
showSpinner()
// update data to server
$.get('php/server/devices.php?action=setDeviceData&mac='+ mac
+ '&name=' + $('#txtName').val()
+ '&owner=' + $('#txtOwner').val()
+ '&name=' + encodeURIComponent($('#txtName').val())
+ '&owner=' + encodeURIComponent($('#txtOwner').val())
+ '&type=' + $('#txtDeviceType').val()
+ '&vendor=' + $('#txtVendor').val()
+ '&icon=' + $('#txtIcon').val()
+ '&vendor=' + encodeURIComponent($('#txtVendor').val())
+ '&icon=' + encodeURIComponent($('#txtIcon').val())
+ '&favorite=' + ($('#chkFavorite')[0].checked * 1)
+ '&group=' + $('#txtGroup').val()
+ '&location=' + $('#txtLocation').val()
+ '&comments=' + $('#txtComments').val()
+ '&group=' + encodeURIComponent($('#txtGroup').val())
+ '&location=' + encodeURIComponent($('#txtLocation').val())
+ '&comments=' + encodeURIComponent($('#txtComments').val())
+ '&networknode=' + $('#txtNetworkNodeMac').attr('data-mynodemac')
+ '&networknodeport=' + $('#txtNetworkPort').val()
+ '&staticIP=' + ($('#chkStaticIP')[0].checked * 1)
@@ -1458,32 +1461,37 @@ function setDeviceData (direction='', refreshCallback='') {
+ '&archived=' + ($('#chkArchived')[0].checked * 1)
, function(msg) {
showMessage (msg);
showMessage (msg);
// clear session storage
setCache("#dropdownOwner","");
setCache("#dropdownDeviceType","");
setCache("#dropdownGroup","");
setCache("#dropdownLocation","");
setCache("#dropdownNetworkNodeMac","");
// clear session storage
setCache("#dropdownOwner","");
setCache("#dropdownDeviceType","");
setCache("#dropdownGroup","");
setCache("#dropdownLocation","");
setCache("#dropdownNetworkNodeMac","");
// Remove navigation prompt "Are you sure you want to leave..."
window.onbeforeunload = null;
somethingChanged = false;
// Remove navigation prompt "Are you sure you want to leave..."
window.onbeforeunload = null;
somethingChanged = false;
// refresh API
updateApi()
// refresh API
updateApi()
// Callback fuction
if (typeof refreshCallback == 'function') {
refreshCallback(direction);
}
hideSpinner()
// Callback fuction
if (typeof refreshCallback == 'function') {
refreshCallback(direction);
}
});
}
// -----------------------------------------------------------------------------
function askSkipNotifications () {
// Check MAC
@@ -1612,7 +1620,7 @@ function overwriteIconType () {
return;
}
var icon = $('#txtIcon').val();
var icon = encodeURIComponent($('#txtIcon').val());
// Mass update icons
$.get('php/server/devices.php?action=overwriteIconType&mac='+ mac + '&icon=' + icon, function(msg) {
@@ -1623,6 +1631,42 @@ function overwriteIconType () {
$('#panDetails :input').attr('disabled', true);
}
// -----------------------------------------------------------------------------
// Add a new Icon
function askAddIcon () {
// Check MAC
if (mac == '') {
return;
}
// Add new icon as base64 string
showModalInput ('<i class="fa fa-square-plus pointer"></i> <?= lang('DevDetail_button_AddIcon');?>', '<?= lang('DevDetail_button_AddIcon_Help');?>',
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Okay');?>', 'addAsBase64');
}
// -----------------------------------------------------------------------------
function addAsBase64 () {
// Check MAC
if (mac == '') {
return;
}
var iconHtml = $('#modal-input-textarea').val();
console.log(iconHtml);
iconHtmlBase64 = btoa(iconHtml.replace(/"/g, "'"));
console.log(iconHtmlBase64);
$('#txtIcon').val(iconHtmlBase64);
updateIconPreview('#txtIcon')
}
// -----------------------------------------------------------------------------
function askDeleteDevice () {
// Check MAC

View File

@@ -1,6 +1,4 @@
<script>
deviceIP = getDeviceDataByMacAddress("<?php echo $_REQUEST["mac"]?>", "dev_LastIP")
</script>
<?php if ($_REQUEST["mac"] == "Internet") { ?>
@@ -79,16 +77,16 @@
<?= lang("DevDetail_Nmap_Scans_desc") ?>
</div>
<button type="button" id="piamanualnmap_fast" class="btn btn-primary pa-btn" style="margin-bottom: 20px; margin-left: 10px; margin-right: 10px;" onclick="manualnmapscan(deviceIP, 'fast')">
<button type="button" id="piamanualnmap_fast" class="btn btn-primary pa-btn" style="margin-bottom: 20px; margin-left: 10px; margin-right: 10px;" onclick="manualnmapscan(getDeviceDataByMacAddress(getMac(), 'dev_LastIP'), 'fast')">
<?= lang("DevDetail_Loading") ?>
</button>
<button type="button" id="piamanualnmap_normal" class="btn btn-primary pa-btn" style="margin-bottom: 20px; margin-left: 10px; margin-right: 10px;" onclick="manualnmapscan(deviceIP, 'normal')">
<button type="button" id="piamanualnmap_normal" class="btn btn-primary pa-btn" style="margin-bottom: 20px; margin-left: 10px; margin-right: 10px;" onclick="manualnmapscan(getDeviceDataByMacAddress(getMac(), 'dev_LastIP'), 'normal')">
<?= lang("DevDetail_Loading") ?>
</button>
<button type="button" id="piamanualnmap_detail" class="btn btn-primary pa-btn" style="margin-bottom: 20px; margin-left: 10px; margin-right: 10px;" onclick="manualnmapscan(deviceIP, 'detail')">
<button type="button" id="piamanualnmap_detail" class="btn btn-primary pa-btn" style="margin-bottom: 20px; margin-left: 10px; margin-right: 10px;" onclick="manualnmapscan(getDeviceDataByMacAddress(getMac(), 'dev_LastIP'), 'detail')">
<?= lang("DevDetail_Loading") ?>
</button>
<button type="button" id="piamanualnmap_skipdiscovery" class="btn btn-primary pa-btn" style="margin-bottom: 20px; margin-left: 10px; margin-right: 10px;" onclick="manualnmapscan(deviceIP, 'skipdiscovery')">
<button type="button" id="piamanualnmap_skipdiscovery" class="btn btn-primary pa-btn" style="margin-bottom: 20px; margin-left: 10px; margin-right: 10px;" onclick="manualnmapscan(getDeviceDataByMacAddress(getMac(), 'dev_LastIP'), 'skipdiscovery')">
<?= lang("DevDetail_Loading") ?>
</button>
@@ -157,7 +155,7 @@
$( "#tracerouteoutput" ).empty();
$.ajax({
method: "GET",
url: "./php/server/traceroute.php?action=get&ip=" + deviceIP + "",
url: "./php/server/traceroute.php?action=get&ip=" + getDeviceDataByMacAddress(getMac(), 'dev_LastIP') + "",
beforeSend: function() { $('#tracerouteoutput').addClass("ajax_scripts_loading"); },
complete: function() { $('#tracerouteoutput').removeClass("ajax_scripts_loading"); },
success: function(data, textStatus) {
@@ -172,7 +170,7 @@
$( "#nslookupoutput" ).empty();
$.ajax({
method: "GET",
url: "./php/server/nslookup.php?action=get&ip=" + deviceIP + "",
url: "./php/server/nslookup.php?action=get&ip=" + getDeviceDataByMacAddress(getMac(), 'dev_LastIP') + "",
beforeSend: function() { $('#nslookupoutput').addClass("ajax_scripts_loading"); },
complete: function() { $('#nslookupoutput').removeClass("ajax_scripts_loading"); },
success: function(data, textStatus) {
@@ -182,20 +180,22 @@
}
// ----------------------------------------------------------------
setTimeout(function(){
document.getElementById('piamanualnmap_fast').innerHTML='<?= lang(
"DevDetail_Nmap_buttonFast"
) ?> (' + deviceIP +')';
document.getElementById('piamanualnmap_normal').innerHTML='<?= lang(
"DevDetail_Nmap_buttonDefault"
) ?> (' + deviceIP +')';
document.getElementById('piamanualnmap_detail').innerHTML='<?= lang(
"DevDetail_Nmap_buttonDetail"
) ?> (' + deviceIP +')';
document.getElementById('piamanualnmap_skipdiscovery').innerHTML='<?= lang(
"DevDetail_Nmap_buttonSkipDiscovery"
) ?> (' + deviceIP +')';
}, 2000);
function initNmapButtons() {
setTimeout(function(){
document.getElementById('piamanualnmap_fast').innerHTML=getString(
"DevDetail_Nmap_buttonFast"
) ;
document.getElementById('piamanualnmap_normal').innerHTML=getString(
"DevDetail_Nmap_buttonDefault"
) ;
document.getElementById('piamanualnmap_detail').innerHTML=getString(
"DevDetail_Nmap_buttonDetail"
) ;
document.getElementById('piamanualnmap_skipdiscovery').innerHTML=getString(
"DevDetail_Nmap_buttonSkipDiscovery"
) ;
}, 500);
}
// ----------------------------------------------------------------
@@ -211,4 +211,7 @@
}
})
}
// init first time
initNmapButtons();
</script>

View File

@@ -1,6 +1,6 @@
<!--
#---------------------------------------------------------------------------------#
# Pi.Alert #
# NetAlertX #
# Open Source Network Guard / WIFI & LAN intrusion detector #
# #
# devices.php - Front module. Devices list page #
@@ -19,12 +19,13 @@
// check permissions
$dbPath = "../db/pialert.db";
$confPath = "../config/pialert.conf";
$dbPath = "../db/app.db";
$confPath = "../config/app.conf";
checkPermissions([$dbPath, $confPath]);
?>
<!-- Page ------------------------------------------------------------------ -->
<div class="content-wrapper">
@@ -39,8 +40,9 @@
<!-- Main content ---------------------------------------------------------- -->
<section class="content">
<!-- top small box 1 ------------------------------------------------------- -->
<div class="row">
<!-- Tile toggle cards ------------------------------------------------------- -->
<div class="row" id="TileCards">
<!-- top small box 1 ------------------------------------------------------- -->
<div class="col-lg-2 col-sm-4 col-xs-6">
<a href="#" onclick="javascript: initializeDatatable('my');">
<div class="small-box bg-aqua">
@@ -52,7 +54,7 @@
</a>
</div>
<!-- top small box 2 ------------------------------------------------------- -->
<!-- top small box 2 ------------------------------------------------------- -->
<div class="col-lg-2 col-sm-4 col-xs-6">
<a href="#" onclick="javascript: initializeDatatable('connected');">
<div class="small-box bg-green">
@@ -64,7 +66,7 @@
</a>
</div>
<!-- top small box 3 ------------------------------------------------------- -->
<!-- top small box 3 ------------------------------------------------------- -->
<div class="col-lg-2 col-sm-4 col-xs-6">
<a href="#" onclick="javascript: initializeDatatable('favorites');">
<div class="small-box bg-yellow">
@@ -76,7 +78,7 @@
</a>
</div>
<!-- top small box 4 ------------------------------------------------------- -->
<!-- top small box 4 ------------------------------------------------------- -->
<div class="col-lg-2 col-sm-4 col-xs-6">
<a href="#" onclick="javascript: initializeDatatable('new');">
<div class="small-box bg-yellow">
@@ -88,19 +90,19 @@
</a>
</div>
<!-- top small box 5 ------------------------------------------------------- -->
<!-- top small box 5 ------------------------------------------------------- -->
<div class="col-lg-2 col-sm-4 col-xs-6">
<a href="#" onclick="javascript: initializeDatatable('down');">
<div class="small-box bg-red">
<div class="inner"><h3 id="devicesDown"> -- </h3>
<p class="infobox_label"><?= lang('Device_Shortcut_DownAlerts');?></p>
<p class="infobox_label"><?= lang('Device_Shortcut_DownOnly');?></p>
</div>
<div class="icon"><i class="fa fa-warning text-red-40"></i></div>
</div>
</a>
</div>
<!-- top small box 6 ------------------------------------------------------- -->
<!-- top small box 6 ------------------------------------------------------- -->
<div class="col-lg-2 col-sm-4 col-xs-6">
<a href="#" onclick="javascript: initializeDatatable('archived');">
<div class="small-box bg-gray top_small_box_gray_text">
@@ -114,9 +116,9 @@
</div>
<!-- Activity Chart ------------------------------------------------------- -->
<!-- Device presence / Activity Chart ------------------------------------------------------- -->
<div class="row">
<div class="row" id="DevicePresence">
<div class="col-md-12">
<div class="box" id="clients">
<div class="box-header with-border">
@@ -124,7 +126,7 @@
</div>
<div class="box-body">
<div class="chart">
<script src="lib/AdminLTE/bower_components/chart.js/Chart.js"></script>
<script src="lib/AdminLTE/bower_components/chart.js/Chart.js?v=<?php include 'php/templates/version.php'; ?>"></script>
<canvas id="OnlineChart" style="width:100%; height: 150px; margin-bottom: 15px;"></canvas>
</div>
</div>
@@ -138,7 +140,15 @@
var pia_js_online_history_ondev = [<?php pia_graph_devices_data($Pia_Graph_Device_Online); ?>];
var pia_js_online_history_dodev = [<?php pia_graph_devices_data($Pia_Graph_Device_Down); ?>];
var pia_js_online_history_ardev = [<?php pia_graph_devices_data($Pia_Graph_Device_Arch); ?>];
pia_draw_graph_online_history(pia_js_online_history_time, pia_js_online_history_ondev, pia_js_online_history_dodev, pia_js_online_history_ardev);
setTimeout(() => {
pia_draw_graph_online_history(
pia_js_online_history_time,
pia_js_online_history_ondev,
pia_js_online_history_dodev,
pia_js_online_history_ardev);
}, 500);
</script>
<!-- datatable ------------------------------------------------------------- -->
@@ -203,8 +213,8 @@
var tableOrder = [[3,'desc'], [0,'asc']];
var tableColumnHide = [];
var columnsStr = '[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]';
var tableColumnOrder = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18];
var columnsStr = '[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]';
var tableColumnOrder = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
var tableColumnVisible = tableColumnOrder;
//initialize the table headers in the correct order
var headersDefaultOrder = [
@@ -226,10 +236,13 @@
getString('Device_TableHead_Connected_Devices'),
getString('Device_TableHead_Location'),
getString('Device_TableHead_Vendor'),
getString('Device_TableHead_Port')
getString('Device_TableHead_Port'),
getString('Device_TableHead_GUID'),
getString('Device_TableHead_SyncHubNodeName')
];
// Read parameters & Initialize components
showSpinner();
main();
@@ -238,6 +251,13 @@ function main () {
handleLoadingDialog()
// Hide UI elements as per settings
// setTimeout(() => {
hideUIelements("UI_DEV_SECTIONS")
// }, 10);
// get from cookie if available (need to use decodeURI as saved as part of URI in PHP)
cookieColumnsVisibleStr = decodeURI(getCookie("Front_Devices_Columns_Visible")).replaceAll('%2C',',')
@@ -300,7 +320,7 @@ function main () {
// check if dat outdated and show spinner if so
// check if data outdated and show spinner if so
handleLoadingDialog()
@@ -353,7 +373,7 @@ function getDevicesTotals(devicesData) {
setCache("getDevicesTotals", resultJSON);
}
console.log(resultJSON);
// console.log(resultJSON);
}
// -----------------------------------------------------------------------------
@@ -385,8 +405,10 @@ function filterDataByStatus(data, status) {
return item.dev_Favorite === 1;
case 'new':
return item.dev_NewDevice === 1;
case 'offline':
return item.dev_PresentLastScan === 0;
case 'down':
return (item.dev_PresentLastScan === 0 && item.dev_AlertDeviceDown !== 0) || item.dev_PresentLastScan === 0;
return (item.dev_PresentLastScan === 0 && item.dev_AlertDeviceDown !== 0);
case 'archived':
return item.dev_Archived === 1;
default:
@@ -440,7 +462,7 @@ function initializeDatatable (status) {
case 'connected': tableTitle = getString('Device_Shortcut_Connected'); color = 'green'; break;
case 'favorites': tableTitle = getString('Device_Shortcut_Favorites'); color = 'yellow'; break;
case 'new': tableTitle = getString('Device_Shortcut_NewDevices'); color = 'yellow'; break;
case 'down': tableTitle = getString('Device_Shortcut_DownAlerts'); color = 'red'; break;
case 'down': tableTitle = getString('Device_Shortcut_DownOnly'); color = 'red'; break;
case 'archived': tableTitle = getString('Device_Shortcut_Archived'); color = 'gray'; break;
default: tableTitle = getString('Device_Shortcut_Devices'); color = 'gray'; break;
}
@@ -491,7 +513,9 @@ function initializeDatatable (status) {
getNumberOfChildren(item.dev_MAC, result.data) || 0,
item.dev_Location || "",
item.dev_Vendor || "",
item.dev_Network_Node_port || 0
item.dev_Network_Node_port || 0,
item.dev_GUID || "",
item.dev_SyncHubNodeName || ""
];
var newRow = [];
@@ -567,7 +591,7 @@ function initializeDatatable (status) {
{targets: [mapIndx(3)],
'createdCell': function (td, cellData, rowData, row, col) {
if (!emptyArr.includes(cellData)){
$(td).html ('<i class="fa fa-'+cellData+' " style="font-size:16px"></i>');
$(td).html (atob(cellData));
} else {
$(td).html ('');
}
@@ -606,7 +630,11 @@ function initializeDatatable (status) {
// Dates
{targets: [mapIndx(6), mapIndx(7)],
'createdCell': function (td, cellData, rowData, row, col) {
$(td).html (translateHTMLcodes (cellData));
var result = cellData.toString(); // Convert to string
if (result.includes("+")) { // Check if timezone offset is present
result = result.split('+')[0]; // Remove timezone offset
}
$(td).html (translateHTMLcodes (result));
} },
// Random MAC
@@ -689,6 +717,7 @@ function initializeDatatable (status) {
});
hideSpinner();
});
};
@@ -741,25 +770,30 @@ function getNumberOfChildren(mac, devices)
}
// -----------------------------------------------------------------------------
function handleLoadingDialog()
function handleLoadingDialog(needsReload = false)
{
$.get('log/execution_queue.log?nocache=' + Date.now(), function(data) {
// console.log('needsReload:');
// console.log(needsReload);
$.get('log/execution_queue.log?nocache=' + Date.now(), function(data) {
if(data.includes("update_api|devices"))
{
showSpinner("devices_old")
setTimeout("handleLoadingDialog()", 1000);
setTimeout(handleLoadingDialog(true), 1000);
} else if ($("#loadingSpinner").is(":visible"))
} else if (needsReload)
{
location.reload();
}else
{
hideSpinner();
location.reload();
// hideSpinner();
}
})
}
// -----------------------------------------------------------------------------
@@ -772,7 +806,7 @@ function multiEditDevices()
// Initialize an empty array to store selected rows
var selectedRows = [];
console.log($('#tableDevices')[0].rows);
// console.log($('#tableDevices')[0].rows);
// Loop through each row in the HTML collection
for (var i = 0; i < rows.length; i++) {
@@ -796,7 +830,7 @@ function multiEditDevices()
}
// Now, selectedDevices contains all selected devices
console.log(selectedDevices);
// console.log(selectedDevices);
macs = ""
@@ -808,5 +842,39 @@ function multiEditDevices()
window.location.href = window.location.origin + '/maintenance.php#tab_multiEdit?macs=' + macs.slice(0, -1);
}
// -----------------------------------------------------------------------------
// Function collects shown devices from the DataTable
function getMacsOfShownDevices() {
rows = $('#tableDevices')[0].rows
macs = []
var devicesDataTableData = $('#tableDevices').dataTable().fnGetData();
var selectedDevices = [];
for (var i = 0; i < rows.length; i++) {
selectedDevices.push(devicesDataTableData[rows[i]._DT_RowIndex]);
}
for (var i = 1; i < selectedDevices.length; i++) {
macs.push(selectedDevices[i][mapIndx(11)]); // mapIndx(11) == MAC
}
return macs;
}
// -----------------------------------------------------------------------------
// Update cahce with shown devices before navigating away
window.addEventListener('beforeunload', function(event) {
// Call your function here
macs = getMacsOfShownDevices();
setCache("ntx_visible_macs", macs)
});
</script>

View File

@@ -1,6 +1,6 @@
<!--
#---------------------------------------------------------------------------------#
# Pi.Alert #
# NetAlertX #
# Open Source Network Guard / WIFI & LAN intrusion detector #
# #
# events.php - Front module. Events page #
@@ -145,6 +145,9 @@
<th><?= lang('Events_TableHead_IP');?></th>
<th><?= lang('Events_TableHead_IPOrder');?></th>
<th><?= lang('Events_TableHead_AdditionalInfo');?></th>
<th>N/A</th>
<th>MAC</th>
<th><?= lang('Events_TableHead_PendingAlert');?></th>
</tr>
</thead>
</table>
@@ -236,7 +239,7 @@ function initializeDatatable () {
'pageLength' : tableRows,
'columnDefs' : [
{visible: false, targets: [0,5,6,7,8,10] },
{visible: false, targets: [0,5,6,7,8,10,11,12,13] },
{className: 'text-center', targets: [] },
{orderData: [8], targets: 7 },
{orderData: [10], targets: 9 },
@@ -251,6 +254,13 @@ function initializeDatatable () {
{targets: [3,4,5,6,7],
"createdCell": function (td, cellData, rowData, row, col) {
$(td).html (translateHTMLcodes (cellData));
} },
// PendingAlert
{targets: [14],
"createdCell": function (td, cellData, rowData, row, col) {
// console.log(cellData);
$(td).html (cellData);
} }
],
@@ -331,7 +341,7 @@ function getEvents (p_eventsType) {
$('#tableEventsBox')[0].className = 'box box-' + color;
$('#tableEventsTitle').html (tableTitle);
// Coluumns Visibility
// Columns Visibility
$('#tableEvents').DataTable().column(3).visible (!sesionCols);
$('#tableEvents').DataTable().column(4).visible (!sesionCols);
$('#tableEvents').DataTable().column(5).visible (sesionCols);

BIN
front/img/NetAlertX_logo.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

BIN
front/img/NetAlertX_logo_red.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@@ -1,6 +1,6 @@
{
"name": "Pi-Alert Console",
"short_name": "Pi-Alert",
"name": "NetAlertX Console",
"short_name": "NetAlertX",
"display": "standalone",
"icons": [
{

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -1,11 +1,11 @@
<!-- Pi.Alert CSS -->
<link rel="stylesheet" href="css/pialert.css">
<!-- NetAlertX CSS -->
<link rel="stylesheet" href="css/app.css">
<?php
require dirname(__FILE__).'/php/server/init.php';
require 'php/templates/security.php';
$CookieSaveLoginName = 'NetAlertX_SaveLogin';
if ($Pia_WebProtection != 'true')
{
@@ -17,7 +17,7 @@ if ($Pia_WebProtection != 'true')
// Logout
if (isset ($_GET["action"]) && $_GET["action"] == 'logout')
{
setcookie("PiAlert_SaveLogin", '', time()+1); // reset cookie
setcookie($CookieSaveLoginName, '', time()+1); // reset cookie
$_SESSION["login"] = 0;
header('Location: index.php');
exit;
@@ -28,15 +28,15 @@ if (isset ($_POST["loginpassword"]) && $Pia_Password == hash('sha256',$_POST["lo
{
header('Location: devices.php');
$_SESSION["login"] = 1;
if (isset($_POST['PWRemember'])) {setcookie("PiAlert_SaveLogin", hash('sha256',$_POST["loginpassword"]), time()+604800);}
if (isset($_POST['PWRemember'])) {setcookie($CookieSaveLoginName, hash('sha256',$_POST["loginpassword"]), time()+604800);}
}
// active Session or valid cookie (cookie not extends)
if (( isset ($_SESSION["login"]) && ($_SESSION["login"] == 1)) || (isset ($_COOKIE["PiAlert_SaveLogin"]) && $Pia_Password == $_COOKIE["PiAlert_SaveLogin"]))
if (( isset ($_SESSION["login"]) && ($_SESSION["login"] == 1)) || (isset ($_COOKIE[$CookieSaveLoginName]) && $Pia_Password == $_COOKIE[$CookieSaveLoginName]))
{
header('Location: devices.php');
$_SESSION["login"] = 1;
if (isset($_POST['PWRemember'])) {setcookie("PiAlert_SaveLogin", hash('sha256',$_POST["loginpassword"]), time()+604800);}
if (isset($_POST['PWRemember'])) {setcookie($CookieSaveLoginName, hash('sha256',$_POST["loginpassword"]), time()+604800);}
}
$login_headline = lang('Login_Toggle_Info_headline');
@@ -78,13 +78,13 @@ if (isset ($_SESSION["login"]) == FALSE || $_SESSION["login"] != 1)
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Pi-Alert | Log in</title>
<title>Net Alert X | Log in</title>
<!-- Tell the browser to be responsive to screen width -->
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<!-- Bootstrap 3.3.7 -->
<link rel="stylesheet" href="lib/AdminLTE/bower_components/bootstrap/dist/css/bootstrap.min.css">
<!-- Font Awesome -->
<link rel="stylesheet" href="lib/AdminLTE/bower_components/font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="lib/AdminLTE/bower_components/font-awesome/css/fontawesome.min.css">
<!-- Ionicons -->
<link rel="stylesheet" href="lib/AdminLTE/bower_components/Ionicons/css/ionicons.min.css">
<!-- Theme style -->
@@ -99,13 +99,12 @@ if ($ENABLED_DARKMODE === True) {
$BACKGROUND_IMAGE_PATCH='style="background-image: url(\'img/boxed-bg-dark.png\');"';
} else { $BACKGROUND_IMAGE_PATCH='style="background-image: url(\'img/background.png\');"';}
?>
<!-- /var/www/html/pialert/css/offline-font.css -->
<link rel="stylesheet" href="/css/offline-font.css">
</head>
<body class="hold-transition login-page">
<div class="login-box login-custom">
<div class="login-logo">
<a href="/index2.php">Pi.<b>Alert</b></a>
<a href="/index2.php">Net <b>Alert</b><sup>x</sup></a>
</div>
<!-- /.login-logo -->
<div class="login-box-body">
@@ -148,7 +147,6 @@ if ($ENABLED_DARKMODE === True) {
<button type="button" class="close" data-dismiss="alert" aria-hidden="true"><3E></button>
<h4><i class="icon fa <?php echo $login_icon;?>"></i><?php echo $login_headline;?></h4>
<p><?php echo $login_info;?></p>
<p><?= lang('Login_Psw_run');?><br><span style="border: solid 1px yellow; padding: 2px;"> /home/pi/pialert/back/pialert-cli set_password <?= lang('Login_Psw_new');?></span><br><?= lang('Login_Psw_folder');?></p>
</div>
</div>

View File

@@ -1,25 +1,20 @@
/* -----------------------------------------------------------------------------
* Pi.Alert
* NetAlertX
* Open Source Network Guard / WIFI & LAN intrusion detector
*
* pialert_common.js - Front module. Common Javascript functions
* common.js - Front module. Common Javascript functions
*-------------------------------------------------------------------------------
# Puche 2021 / 2022+ jokob jokob@duck.com GNU GPLv3
----------------------------------------------------------------------------- */
// -----------------------------------------------------------------------------
var timerRefreshData = ''
var modalCallbackFunction = '';
var emptyArr = ['undefined', "", undefined, null, 'null'];
var UI_LANG = "English";
var settingsJSON = {}
// urlParams = new Proxy(new URLSearchParams(window.location.search), {
// get: (searchParams, prop) => searchParams.get(prop.toString()),
// });
// -----------------------------------------------------------------------------
// Simple session cache withe expiration managed via cookies
// -----------------------------------------------------------------------------
@@ -116,47 +111,60 @@ function deleteAllCookies() {
// -----------------------------------------------------------------------------
function cacheSettings()
{
$.get('api/table_settings.json?nocache=' + Date.now(), function(resSet) {
return new Promise((resolve, reject) => {
if(!getCache('completedCalls').includes('cacheSettings'))
{
$.get('api/table_settings.json?nocache=' + Date.now(), function(resSet) {
$.get('api/plugins.json?nocache=' + Date.now(), function(resPlug) {
$.get('api/plugins.json?nocache=' + Date.now(), function(resPlug) {
pluginsData = resPlug["data"];
settingsData = resSet["data"];
pluginsData = resPlug["data"];
settingsData = resSet["data"];
settingsData.forEach((set) => {
settingsData.forEach((set) => {
resolvedOptions = createArray(set.Options)
setPlugObj = {};
options_params = [];
// proceed only if first option item contains something to resolve
if( !set.Code_Name.includes("__metadata") &&
resolvedOptions.length != 0 &&
resolvedOptions[0].includes("{value}"))
{
// get setting definition from the plugin config if available
setPlugObj = getPluginSettingObject(pluginsData, set.Code_Name)
// check if options contains parameters and resolve
if(setPlugObj != {} && setPlugObj["options_params"])
{
// get option_params for {value} resolution
options_params = setPlugObj["options_params"]
if(options_params != [])
resolvedOptions = createArray(set.Options)
setPlugObj = {};
options_params = [];
// proceed only if first option item contains something to resolve
if( !set.Code_Name.includes("__metadata") &&
resolvedOptions.length != 0 &&
resolvedOptions[0].includes("{value}"))
{
// handles only strings of length == 1
resolvedOptions = `["${resolveParams(options_params, resolvedOptions[0])}"]`
}
}
}
// get setting definition from the plugin config if available
setPlugObj = getPluginSettingObject(pluginsData, set.Code_Name)
setCache(`pia_set_${set.Code_Name}`, set.Value)
setCache(`pia_set_opt_${set.Code_Name}`, resolvedOptions)
});
}).then(() => handleSuccess('cacheSettings')).catch(() => handleFailure('cacheSettings', cacheSettings)); // handle AJAX synchronization
})
// check if options contains parameters and resolve
if(setPlugObj != {} && setPlugObj["options_params"])
{
// get option_params for {value} resolution
options_params = setPlugObj["options_params"]
if(options_params != [])
{
// handles only strings of length == 1
resolved = resolveParams(options_params, resolvedOptions[0])
if(resolved.includes('"')) // check if list of strings
{
resolvedOptions = `[${resolved}]`
} else // one value only
{
resolvedOptions = `["${resolved}"]`
}
}
}
}
setCache(`pia_set_${set.Code_Name}`, set.Value)
setCache(`pia_set_opt_${set.Code_Name}`, resolvedOptions)
});
}).then(() => handleSuccess('cacheSettings', resolve())).catch(() => handleFailure('cacheSettings', reject("cacheSettings already completed"))); // handle AJAX synchronization
})
}
});
}
// -----------------------------------------------------------------------------
@@ -197,48 +205,45 @@ function getSetting (key) {
// Get language string
// -----------------------------------------------------------------------------
function cacheStrings()
{
{
return new Promise((resolve, reject) => {
if(!getCache('completedCalls').includes('cacheStrings'))
{
// handle core strings and translations
var allLanguages = ["en_us", "es_es", "de_de", "fr_fr", "it_it", "ru_ru", "nb_no", "pl_pl", "zh_cn"]; // needs to be same as in lang.php
// handle core strings and translations
var allLanguages = ["en_us", "es_es", "de_de", "fr_fr", "ru_ru", "nb_no"]; // needs to be same as in lang.php
allLanguages.forEach(function (language_code) {
$.get(`php/templates/language/${language_code}.json?nocache=${Date.now()}`, function (res) {
// Iterate over each language
Object.entries(res).forEach(([key, value]) => {
// Store translations for each key-value pair
setCache(`pia_lang_${key}_${language_code}`, value)
});
allLanguages.forEach(function (language_code) {
$.get(`php/templates/language/${language_code}.json?nocache=${Date.now()}`, function (res) {
// Iterate over each language
Object.entries(res).forEach(([key, value]) => {
// Store translations for each key-value pair
setCache(`pia_lang_${key}_${language_code}`, value)
// handle strings and translations from plugins
$.get(`api/table_plugins_language_strings.json?nocache=${Date.now()}`, function(res) {
data = res["data"];
data.forEach((langString) => {
setCache(`pia_lang_${langString.String_Key}_${langString.Language_Code}`, langString.String_Value)
});
}).then(() => handleSuccess('cacheStrings', resolve())).catch(() => handleFailure('cacheStrings', reject("cacheStrings already completed"))); // handle AJAX synchronization
});
});
});
}
});
// handle strings and translations from plugins
$.get(`api/table_plugins_language_strings.json?nocache=${Date.now()}`, function(res) {
data = res["data"];
data.forEach((langString) => {
setCache(`pia_lang_${langString.String_Key}_${langString.Language_Code}`, langString.String_Value)
});
}).then(() => handleSuccess('cacheStrings')).catch(() => handleFailure('cacheStrings', cacheStrings)); // handle AJAX synchronization
}
// Get translated language string
function getString (key) {
// handle initial laod to make sure everything is set-up and cached
handleFirstLoad()
// handle initial load to make sure everything is set-up and cached
handleFirstLoad(getString)
UI_LANG = getSetting("UI_LANG");
// //
// if(UI_LANG == "")
// {
// }
lang_code = 'en_us';
switch(UI_LANG)
@@ -258,9 +263,24 @@ function getString (key) {
case 'Norwegian':
lang_code = 'nb_no';
break;
case 'Polish (pl_pl)':
lang_code = 'pl_pl';
break;
case 'Portuguese (pt_br)':
lang_code = 'pt_br';
break;
case 'Turkish (tr_tr)':
lang_code = 'tr_tr';
break;
case 'Italian (it_it)':
lang_code = 'it_it';
break;
case 'Russian':
lang_code = 'ru_ru';
break;
case 'Chinese (zh_cn)':
lang_code = 'zh_cn';
break;
}
result = getCache(`pia_lang_${key}_${lang_code}`, true);
@@ -273,114 +293,7 @@ function getString (key) {
return result;
}
// -----------------------------------------------------------------------------
// Modal dialog handling
// -----------------------------------------------------------------------------
function showModalOK (title, message, callbackFunction) {
showModalOk (title, message, callbackFunction)
}
function showModalOk (title, message, callbackFunction) {
// set captions
$('#modal-ok-title').html (title);
$('#modal-ok-message').html (message);
if(callbackFunction!= null)
{
$("#modal-ok-OK").click(function()
{
callbackFunction()
});
}
// Show modal
$('#modal-ok').modal('show');
}
// -----------------------------------------------------------------------------
function showModalDefault (title, message, btnCancel, btnOK, callbackFunction) {
// set captions
$('#modal-default-title').html (title);
$('#modal-default-message').html (message);
$('#modal-default-cancel').html (btnCancel);
$('#modal-default-OK').html (btnOK);
modalCallbackFunction = callbackFunction;
// Show modal
$('#modal-default').modal('show');
}
// -----------------------------------------------------------------------------
function showModalDefaultStrParam (title, message, btnCancel, btnOK, callbackFunction, param='') {
// set captions
$('#modal-str-title').html (title);
$('#modal-str-message').html (message);
$('#modal-str-cancel').html (btnCancel);
$('#modal-str-OK').html (btnOK);
$("#modal-str-OK").off("click"); //remove existing handlers
$('#modal-str-OK').on('click', function (){
$('#modal-str').modal('hide');
callbackFunction(param)
})
// Show modal
$('#modal-str').modal('show');
}
// -----------------------------------------------------------------------------
function showModalWarning (title, message, btnCancel=getString('Gen_Cancel'), btnOK=getString('Gen_Okay'), callbackFunction=null) {
// set captions
$('#modal-warning-title').html (title);
$('#modal-warning-message').html (message);
$('#modal-warning-cancel').html (btnCancel);
$('#modal-warning-OK').html (btnOK);
if ( callbackFunction != null)
{
modalCallbackFunction = callbackFunction;
}
// Show modal
$('#modal-warning').modal('show');
}
// -----------------------------------------------------------------------------
function modalDefaultOK () {
// Hide modal
$('#modal-default').modal('hide');
// timer to execute function
window.setTimeout( function() {
window[modalCallbackFunction]();
}, 100);
}
// -----------------------------------------------------------------------------
function modalWarningOK () {
// Hide modal
$('#modal-warning').modal('hide');
// timer to execute function
window.setTimeout( function() {
window[modalCallbackFunction]();
}, 100);
}
// -----------------------------------------------------------------------------
function showMessage (textMessage="") {
if (textMessage.toLowerCase().includes("error") ) {
// show error
alert (textMessage);
} else {
// show temporal notification
$("#alert-message").html (textMessage);
$("#notification").fadeIn(1, function () {
window.setTimeout( function() {
$("#notification").fadeOut(500)
}, 3000);
} );
}
}
// -----------------------------------------------------------------------------
@@ -408,6 +321,15 @@ function jsonSyntaxHighlight(json) {
});
}
function isValidBase64(str) {
// Base64 characters set
var base64CharacterSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
// Remove all valid characters from the string
var invalidCharacters = str.replace(new RegExp('[' + base64CharacterSet + ']', 'g'), '');
// If there are any characters left, the string is invalid
return invalidCharacters === '';
}
// -----------------------------------------------------------------------------
// General utilities
@@ -632,10 +554,19 @@ function stopTimerRefreshData () {
// -----------------------------------------------------------------------------
function newTimerRefreshData (refeshFunction) {
function newTimerRefreshData (refeshFunction, timeToRefresh) {
if(timeToRefresh && (timeToRefresh != 0 || timeToRefresh != ""))
{
time = parseInt(timeToRefresh)
} else
{
time = 60000
}
timerRefreshData = setTimeout (function() {
refeshFunction();
}, 60000);
}, time);
}
@@ -644,6 +575,22 @@ function debugTimer () {
$('#pageTitle').html (new Date().getSeconds());
}
// -----------------------------------------------------------------------------
function secondsSincePageLoad() {
// Get the current time
var currentTime = Date.now();
// Get the time when the page was loaded
var pageLoadTime = performance.timeOrigin;
// Calculate the difference in milliseconds
var timeDifference = currentTime - pageLoadTime;
// Convert milliseconds to seconds
var secondsAgo = Math.floor(timeDifference / 1000);
return secondsAgo;
}
// -----------------------------------------------------------------------------
// Open url in new tab
@@ -720,6 +667,15 @@ function checkMacOrInternet(inputStr) {
}
}
// -----------------------------------------------------------------------------
// Gte MAC from query string
function getMac(){
params = new Proxy(new URLSearchParams(window.location.search), {
get: (searchParams, prop) => searchParams.get(prop),
});
return params.mac
}
// -----------------------------------------------------------------------------
// A function used to make the IP address orderable
@@ -865,34 +821,38 @@ function getDeviceDataByMacAddress(macAddress, dbColumn) {
}
// -----------------------------------------------------------------------------
function initDeviceListAll_JSON()
// Cache teh devices as one JSON
function cacheDevices()
{
$.get('api/table_devices.json', function(data) {
// console.log(data)
return new Promise((resolve, reject) => {
devicesListAll_JSON = data["data"]
devicesListAll_JSON_str = JSON.stringify(devicesListAll_JSON)
if(devicesListAll_JSON_str == "")
if(!getCache('completedCalls').includes('cacheDevices'))
{
setTimeout(() => {
initDeviceListAll_JSON()
}, 1000);
}
$.get('api/table_devices.json', function(data) {
// console.log(data)
devicesListAll_JSON = data["data"]
// console.log("devicesListAll_JSON_str");
// console.log(devicesListAll_JSON_str);
devicesListAll_JSON_str = JSON.stringify(devicesListAll_JSON)
setCache('devicesListAll_JSON', devicesListAll_JSON_str)
if(devicesListAll_JSON_str == "")
{
showSpinner()
// console.log(getCache('devicesListAll_JSON'))
}).then(() => handleSuccess('initDeviceListAll_JSON')).catch(() => handleFailure('initDeviceListAll_JSON', initDeviceListAll_JSON)); // handle AJAX synchronization
setTimeout(() => {
cacheDevices()
}, 1000);
}
// console.log(devicesListAll_JSON_str);
setCache('devicesListAll_JSON', devicesListAll_JSON_str)
// console.log(getCache('devicesListAll_JSON'))
}).then(() => handleSuccess('cacheDevices', resolve())).catch(() => handleFailure('cacheDevices', reject("cacheDevices already completed"))); // handle AJAX synchronization
}
});
}
var devicesListAll_JSON = []; // this will contain a list off all devices
@@ -903,6 +863,18 @@ function isEmpty(value)
return emptyArr.includes(value)
}
// -----------------------------------------------------------------------------
function mergeUniqueArrays(arr1, arr2) {
let mergedArray = [...arr1]; // Make a copy of arr1
arr2.forEach(element => {
if (!mergedArray.includes(element)) {
mergedArray.push(element);
}
});
return mergedArray;
}
// -----------------------------------------------------------------------------
// Generate a GUID
@@ -923,6 +895,15 @@ function getGuid() {
// -----------------------------------------------------------------------------
function showSpinner(stringKey='Loading')
{
if(stringKey == "")
{
text = ''
} else
{
text = getString(stringKey)
}
if($("#loadingSpinner").length)
{
$("#loadingSpinner").show();
@@ -934,7 +915,7 @@ function showSpinner(stringKey='Loading')
<div class="pa_semitransparent-panel"></div>
<div class="panel panel-default pa_spinner">
<table>
<td width="130px" align="middle">${getString(stringKey)}</td>
<td width="130px" align="middle">${text}</td>
<td><i class="ion ion-ios-loop-strong fa-spin fa-2x fa-fw"></td>
</table>
</div>
@@ -996,7 +977,7 @@ function setupSmoothScrolling() {
var url = window.location.href;
if (url.includes("#")) {
var idFromURL = url.substring(url.indexOf("#") + 1);
if ($("#" + idFromURL).length > 0) {
if (idFromURL != "" && $("#" + idFromURL).length > 0) {
scrollToElement(idFromURL);
}
}
@@ -1058,8 +1039,18 @@ function resolveParams(params, template) {
// If the parameter type is 'setting', retrieve setting value
if (param.type == "setting") {
var value = getSetting(param.value);
// Remove brackets and single quotes, replace them with double quotes
value = value.replace('[','').replace(']','').replace(/'/g, '"');
// Split the string into an array, remove empty elements
const arr = value.split(',').filter(Boolean);
// Join the array elements with commas
const result = arr.join(', ');
// Replace placeholder with setting value
template = template.replace("{" + param.name + "}", value);
template = template.replace("{" + param.name + "}", result);
} else {
// If the parameter type is not 'setting', use the provided value
template = template.replace("{" + param.name + "}", param.value);
@@ -1077,132 +1068,153 @@ function resolveParams(params, template) {
// -----------------------------------------------------------------------------
// check if two arrays contain same values even if out of order
function arraysContainSameValues(arr1, arr2) {
// Sort and stringify arrays, then compare
return JSON.stringify(arr1.slice().sort()) === JSON.stringify(arr2.slice().sort());
// Check if both parameters are arrays
if (!Array.isArray(arr1) || !Array.isArray(arr2)) {
return false;
} else
{
// Sort and stringify arrays, then compare
return JSON.stringify(arr1.slice().sort()) === JSON.stringify(arr2.slice().sort());
}
}
// -----------------------------------------------------------------------------
// initialize
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// Define a unique key for storing the flag in sessionStorage
var sessionStorageKey = "myScriptExecuted_pialert_common";
const sessionStorageKey = "myScriptExecuted_common_js";
var completedCalls = []
var completedCalls_final = ['cacheSettings', 'cacheStrings', 'cacheDevices'];
// -----------------------------------------------------------------------------
// Clearing all the caches
function clearCache()
{
resetInitializedFlag()
window.location.reload()
}
// -----------------------------------------------------------------------------
function resetInitializedFlag()
{
// Clear local storage
function clearCache() {
showSpinner();
sessionStorage.clear();
localStorage.clear();
// Set the flag in sessionStorage to indicate that the code and cahce needs to be reloaded
sessionStorage.setItem(sessionStorageKey, "false");
setTimeout(() => {
window.location.reload();
}, 500);
}
// -----------------------------------------------------------------------------
// check if cache needs to be refreshed because of setting changes
$.get('api/app_state.json?nocache=' + Date.now(), function(appState) {
// Function to check if cache needs to be refreshed because of setting changes
function checkSettingChanges() {
$.get('api/app_state.json?nocache=' + Date.now(), function(appState) {
const importedMilliseconds = parseInt(appState["settingsImported"] * 1000);
const lastReloaded = parseInt(sessionStorage.getItem(sessionStorageKey + '_time'));
console.log(appState["settingsImported"]*1000)
importedMiliseconds = parseInt((appState["settingsImported"]*1000));
lastReloaded = parseInt(sessionStorage.getItem(sessionStorageKey + '_time'));
if(importedMiliseconds > lastReloaded)
{
console.log("Cache needs to be refreshed because of setting changes");
setTimeout(() => {
resetInitializedFlag()
location.reload();
}, 500);
}
});
if (importedMilliseconds > lastReloaded) {
console.log("Cache needs to be refreshed because of setting changes");
setTimeout(() => {
clearCache();
}, 500);
}
});
}
// -----------------------------------------------------------------------------
// Display spinner and reload page if not yet initialized
function handleFirstLoad()
{
if(!pialert_common_init)
{
setTimeout(function() {
location.reload();
}, 1000);
async function handleFirstLoad(callback) {
if (!isAppInitialized()) {
await new Promise(resolve => setTimeout(resolve, 1000));
callback();
}
}
// -----------------------------------------------------------------------------
// Check if the code has been executed before by checking sessionStorage
var pialert_common_init = sessionStorage.getItem(sessionStorageKey) === "true";
function isAppInitialized() {
return arraysContainSameValues(getCache("completedCalls").split(',').filter(Boolean), completedCalls_final);
}
// Define a function that will execute the code only once
function executeOnce() {
async function executeOnce() {
showSpinner();
if (!pialert_common_init) {
resetInitializedFlag()
showSpinner()
// to keep track of completed AJAX calls
completedCalls = []
completedCalls_final = ['cacheSettings', 'cacheStrings', 'initDeviceListAll_JSON'];
// Your initialization code here
cacheSettings();
cacheStrings();
initDeviceListAll_JSON();
if (!isAppInitialized()) {
try {
await cacheStrings();
await cacheSettings();
await cacheDevices();
console.log("✅ All AJAX callbacks have completed");
onAllCallsComplete();
} catch (error) {
console.error("Error:", error);
}
}
}
// -----------------------------------------------------------------------------
// Function to handle successful completion of an AJAX call
const handleSuccess = (callName) => {
console.log(`AJAX call ${callName} successful`);
// store completed call
completedCalls.push(callName)
onAllCallsComplete();
console.log(`AJAX call successful: ${callName}`);
completedCalls.push(callName);
setCache('completedCalls', mergeUniqueArrays(getCache('completedCalls').split(','), [callName]));
};
// -----------------------------------------------------------------------------
// Function to handle failure of an AJAX call
const handleFailure = (callName, callback) => {
// Handle AJAX call failure here
console.error(`AJAX call ${callName} failed`);
// try until successful
callback()
// Implement retry logic here if needed
};
// -----------------------------------------------------------------------------
// Function to execute when all AJAX calls have completed
const onAllCallsComplete = () => {
// Check if all three AJAX calls have completed
if (arraysContainSameValues(completedCalls,completedCalls_final)) {
completedCalls = mergeUniqueArrays(getCache('completedCalls').split(','), completedCalls);
setCache('completedCalls', completedCalls);
// Set the flag in sessionStorage to indicate that the code has been executed
// and save time when last time the page was initialized
sessionStorage.setItem(sessionStorageKey, "true");
// Check if all necessary strings are initialized
if (areAllStringsInitialized()) {
sessionStorage.setItem(sessionStorageKey, "true");
const millisecondsNow = Date.now();
sessionStorage.setItem(sessionStorageKey + '_time', millisecondsNow);
console.log("init pialert_common.js");
console.log('✔ Cache initialized');
} else {
// If not all strings are initialized, retry initialization
console.log('❌ Not all strings are initialized. Retrying...');
executeOnce();
return;
}
// Call any other initialization functions here if needed
// No need for location.reload() here
};
// Function to check if all necessary strings are initialized
const areAllStringsInitialized = () => {
// Implement logic to check if all necessary strings are initialized
// Return true if all strings are initialized, false otherwise
return getString('UI_LANG') != ""
};
// Call the function to execute the code
executeOnce();
// Set timer for regular checks
setTimeout(() => {
// page refresh if configured
const refreshTime = getSetting("UI_REFRESH");
if (refreshTime && refreshTime !== "0" && refreshTime !== "") {
newTimerRefreshData(clearCache, parseInt(refreshTime)*1000);
}
// Check if page needs to refresh due to setting changes
checkSettingChanges()
}, 10000);
console.log("init common.js");

View File

@@ -1,18 +1,52 @@
// -----------------------------------------------------------------------------
// General utilities to interact with teh database
// General utilities to interact with the database
// -----------------------------------------------------------------------------
// --------------------------------------------------
// Read data and place intotarget location, callback processies the results
function readData(sqlQuery, processDataCallback, valuesArray, targetLocation) {
function readData(sqlQuery, processDataCallback, valuesArray, targetLocation, targetField, nameTransformer) {
var apiUrl = `php/server/dbHelper.php?action=read&rawSql=${encodeURIComponent(sqlQuery)}`;
$.get(apiUrl, function(data) {
// Process the JSON data using the provided callback function
data = JSON.parse(data)
var htmlResult = processDataCallback(data, valuesArray);
var htmlResult = processDataCallback(data, valuesArray, targetField, nameTransformer);
// Place the resulting HTML into the specified placeholder div
$("#" + targetLocation).replaceWith(htmlResult);
});
}
}
// --------------------------------------------------
// Check if database is locked
function checkDbLock() {
$.ajax({
url: 'log/db_is_locked.log', // Replace with the actual path to your PHP file
type: 'GET',
success: function(response) {
// console.log(response);
if (response == 0) {
// console.log('Database is not locked');
$(".header-status-locked-db").hide()
} else {
console.log('🟥 Database is locked:');
console.log(response);
$(".header-status-locked-db").show()
}
},
error: function() {
console.log('🟥 Error checking database lock status');
$(".header-status-locked-db").show()
}
});
}
setInterval(checkDbLock(), 1000);

View File

@@ -4,7 +4,7 @@ function versionUpdateUI(){
isNewVersion = getCookie("isNewVersion")
console.log(isNewVersion)
// console.log(isNewVersion)
// if the release_timestamp is older by 10 min or more as the build timestamp then there is a new release available
if(isNewVersion != "false")

409
front/js/modal.js Executable file
View File

@@ -0,0 +1,409 @@
// -----------------------------------------------------------------------------
// Modal dialog handling
// -----------------------------------------------------------------------------
var modalCallbackFunction = "";
function showModalOK(title, message, callbackFunction) {
showModalOk(title, message, callbackFunction);
}
function showModalOk(title, message, callbackFunction) {
// set captions
$("#modal-ok-title").html(title);
$("#modal-ok-message").html(message);
if (callbackFunction != null) {
$("#modal-ok-OK").click(function () {
callbackFunction();
});
}
// Show modal
$("#modal-ok").modal("show");
}
// -----------------------------------------------------------------------------
function showModalDefault(title, message, btnCancel, btnOK, callbackFunction) {
// set captions
$("#modal-default-title").html(title);
$("#modal-default-message").html(message);
$("#modal-default-cancel").html(btnCancel);
$("#modal-default-OK").html(btnOK);
modalCallbackFunction = callbackFunction;
// Show modal
$("#modal-default").modal("show");
}
// -----------------------------------------------------------------------------
function showModalDefaultStrParam(
title,
message,
btnCancel,
btnOK,
callbackFunction,
param = ""
) {
// set captions
$("#modal-str-title").html(title);
$("#modal-str-message").html(message);
$("#modal-str-cancel").html(btnCancel);
$("#modal-str-OK").html(btnOK);
$("#modal-str-OK").off("click"); //remove existing handlers
$("#modal-str-OK").on("click", function () {
$("#modal-str").modal("hide");
callbackFunction(param);
});
// Show modal
$("#modal-str").modal("show");
}
// -----------------------------------------------------------------------------
function showModalWarning(
title,
message,
btnCancel = getString("Gen_Cancel"),
btnOK = getString("Gen_Okay"),
callbackFunction = null
) {
// set captions
$("#modal-warning-title").html(title);
$("#modal-warning-message").html(message);
$("#modal-warning-cancel").html(btnCancel);
$("#modal-warning-OK").html(btnOK);
if (callbackFunction != null) {
modalCallbackFunction = callbackFunction;
}
// Show modal
$("#modal-warning").modal("show");
}
// -----------------------------------------------------------------------------
function showModalInput(
title,
message,
btnCancel = getString("Gen_Cancel"),
btnOK = getString("Gen_Okay"),
callbackFunction = null
) {
prefix = "modal-input";
// set captions
$(`#${prefix}-title`).html(title);
$(`#${prefix}-message`).html(message);
$(`#${prefix}-cancel`).html(btnCancel);
$(`#${prefix}-OK`).html(btnOK);
if (callbackFunction != null) {
modalCallbackFunction = callbackFunction;
}
// Show modal
$(`#${prefix}`).modal("show");
setTimeout(function () {
$(`#${prefix}-textarea`).focus();
}, 500);
}
// -----------------------------------------------------------------------------
function showModalFieldInput(
title,
message,
btnCancel = getString("Gen_Cancel"),
btnOK = getString("Gen_Okay"),
curValue = "",
callbackFunction = null
) {
// set captions
prefix = "modal-field-input";
$(`#${prefix}-title`).html(title);
$(`#${prefix}-message`).html(message);
$(`#${prefix}-cancel`).html(btnCancel);
$(`#${prefix}-OK`).html(btnOK);
if (callbackFunction != null) {
modalCallbackFunction = callbackFunction;
}
$(`#${prefix}-field`).val(curValue);
setTimeout(function () {
$(`#${prefix}-field`).focus();
}, 500);
// Show modal
$(`#${prefix}`).modal("show");
}
// -----------------------------------------------------------------------------
function modalDefaultOK() {
// Hide modal
$("#modal-default").modal("hide");
// timer to execute function
window.setTimeout(function () {
window[modalCallbackFunction]();
}, 100);
}
// -----------------------------------------------------------------------------
function modalDefaultInput() {
// Hide modal
$("#modal-input").modal("hide");
// timer to execute function
window.setTimeout(function () {
window[modalCallbackFunction]();
}, 100);
}
// -----------------------------------------------------------------------------
function modalDefaultFieldInput() {
// Hide modal
$("#modal-field-input").modal("hide");
// timer to execute function
window.setTimeout(function () {
modalCallbackFunction();
}, 100);
}
// -----------------------------------------------------------------------------
function modalWarningOK() {
// Hide modal
$("#modal-warning").modal("hide");
// timer to execute function
window.setTimeout(function () {
window[modalCallbackFunction]();
}, 100);
}
// -----------------------------------------------------------------------------
function showMessage(textMessage = "", timeout = 3000, colorClass = "modal_green") {
if (textMessage.toLowerCase().includes("error")) {
// show error
alert(textMessage);
} else {
// show temporary notification
$("#notification_modal").removeClass(); // remove all classes
$("#notification_modal").addClass("alert alert-dimissible notification_modal"); // add default ones
$("#notification_modal").addClass(colorClass); // add color modifiers
// message
$("#alert-message").html(textMessage);
// timeout
$("#notification_modal").fadeIn(1, function () {
window.setTimeout(function () {
$("#notification_modal").fadeOut(500);
}, timeout);
});
}
}
// -----------------------------------------------------------------------------
function showTickerAnnouncement(textMessage = "") {
if (textMessage.toLowerCase().includes("error")) {
// show error
alert(textMessage);
} else {
// show permanent notification
$("#ticker-message").html(textMessage);
$("#tickerAnnouncement").removeClass("myhidden");
// Move the tickerAnnouncement element to ticker_announcement_plc
$("#tickerAnnouncement").appendTo("#ticker_announcement_plc");
}
}
// -----------------------------------------------------------------------------
// Keyboard bindings
// -----------------------------------------------------------------------------
$(document).ready(function () {
$(document).on("keydown", function (event) {
// ESC key is pressed
if (event.keyCode === 27) {
// Trigger modal dismissal
$(".modal").modal("hide");
}
// Enter key is pressed
if (event.keyCode === 13) {
$(".modal:visible").find(".btn-modal-submit").click(); // Trigger the click event of the OK button in visible modals
}
});
});
// -----------------------------------------------------------------------------
// Backend notification Polling
// -----------------------------------------------------------------------------
// Function to check for notifications
function checkNotification() {
const notificationEndpoint = 'php/server/utilNotification.php?action=get_unread_notifications';
const phpEndpoint = 'php/server/utilNotification.php';
$.ajax({
url: notificationEndpoint,
type: 'GET',
success: function(response) {
// console.log(response);
if(response != "[]")
{
// Find the oldest unread notification with level "interrupt"
const oldestInterruptNotification = response.find(notification => notification.read === 0 && notification.level === "interrupt");
const allUnreadNotification = response.filter(notification => notification.read === 0 && notification.level === "alert");
if (oldestInterruptNotification) {
// Show modal dialog with the oldest unread notification
const decodedContent = JSON.parse(decodeURIComponent(oldestInterruptNotification.content));
showModalOK("Notification", decodedContent, function() {
// Mark the notification as read
$.ajax({
url: phpEndpoint,
type: 'GET',
data: {
action: 'mark_notification_as_read',
guid: oldestInterruptNotification.guid
},
success: function(response) {
console.log(response);
// After marking the notification as read, check for the next one
checkNotification();
},
error: function(xhr, status, error) {
console.error("Error marking notification as read:", status, error);
},
complete:function() {
hideSpinner();
}
});
});
}
handleUnreadNotifications(allUnreadNotification.length)
}
},
error: function() {
console.warn(`🟥 Error checking ${notificationEndpoint}`)
}
});
}
// Handling unread notifications favicon + bell floating number bublbe
function handleUnreadNotifications(count) {
$('#unread-notifications-bell-count').html(count);
if (count > 0) {
$('#unread-notifications-bell-count').show();
// Change the favicon to show there are notifications
$('#favicon').attr('href', 'img/NetAlertX_logo_notification.png');
// Update the title to include the count
document.title = `(${count}) ` + originalTitle;
} else {
$('#unread-notifications-bell-count').hide();
// Change the favicon back to the original
$('#favicon').attr('href', 'img/NetAlertX_logo.png');
// Revert the title to the original title
document.title = originalTitle;
}
}
// Store the original title of the document
var originalTitle = document.title;
// Start checking for notifications periodically
setInterval(checkNotification, 3000);
// --------------------------------------------------
// User notification handling methods
// --------------------------------------------------
const phpEndpoint = 'php/server/utilNotification.php';
// --------------------------------------------------
// Write a notification
function writeNotification(content, level) {
$.ajax({
url: phpEndpoint, // Change this to the path of your PHP script
type: 'GET',
data: {
action: 'write_notification',
content: content,
level: level
},
success: function(response) {
console.log('Notification written successfully.');
},
error: function(xhr, status, error) {
console.error('Error writing notification:', error);
}
});
}
// --------------------------------------------------
// Write a notification
function markNotificationAsRead(guid) {
$.ajax({
url: phpEndpoint,
type: 'GET',
data: {
action: 'mark_notification_as_read',
guid: guid
},
success: function(response) {
console.log(response);
// Perform any further actions after marking the notification as read here
showMessage(getString("Gen_Okay"))
},
error: function(xhr, status, error) {
console.error("Error marking notification as read:", status, error);
},
complete: function() {
// Perform any cleanup tasks here
}
});
}
// --------------------------------------------------
// Remove a notification
function removeNotification(guid) {
$.ajax({
url: phpEndpoint,
type: 'GET',
data: {
action: 'remove_notification',
guid: guid
},
success: function(response) {
console.log(response);
// Perform any further actions after marking the notification as read here
showMessage(getString("Gen_Okay"))
},
error: function(xhr, status, error) {
console.error("Error removing notification:", status, error);
},
complete: function() {
// Perform any cleanup tasks here
}
});
}

View File

@@ -20,7 +20,7 @@
}
// -------------------------------------------------------------------
// Get plugin type base on prefix
// Get plugin code name base on prefix
function getPluginCodeName(pluginsData, prefix)
{
var result = ""
@@ -58,6 +58,25 @@
return result;
}
// -------------------------------------------------------------------
// Get plugin config based on prefix
function getPluginConfig(pluginsData, prefix)
{
result = ""
pluginsData.forEach((plug) => {
if (plug.unique_prefix == prefix ) {
// console.log(id)
result = plug;
}
});
return result;
}
// -------------------------------------------------------------------
// Generate plugin HTML card based on prefixes in an array
function pluginCards(prefixesOfEnabledPlugins, includeSettings)
@@ -71,26 +90,27 @@
includeSettings.forEach((set) => {
includeSettings_html += `
<a href="#${prefix + '_' + set}" onclick="toggleAllSettings()">
<div class="overview-setting-value pointer" title="${prefix + '_' + set}">
<code>${getSetting(prefix + '_' + set)}</code>
</div>
</a>
<div class="col-sm-6 overview-setting-value-wrap">
<a href="#${prefix + '_' + set}" onclick="toggleAllSettings()">
<div class="overview-setting-value pointer" title="${prefix + '_' + set}">
<code>${getSetting(prefix + '_' + set)}</code>
</div>
</a>
</div>
`
});
html += `
<div class="col-sm-4 ">
<div class="small-box bg-green " >
<div class="inner ">
<a href="#${prefix}_header" onclick="toggleAllSettings('open')">
<h5 class="card-title">
<b>${getString(prefix+"_display_name")}</b>
</h5>
</a>
${includeSettings_html}
</div>
<div class="col-xs-6 col-sm-4 col-md-3 col-lg-2 col-xxl-1 padding-5px">
<div class="small-box bg-green col-sm-12 " >
<div class="inner col-sm-12">
<a href="#${prefix}_header" onclick="toggleAllSettings('open')">
<h5 class="card-title">
<b>${getString(prefix+"_display_name")}</b>
</h5>
</a>
${includeSettings_html}
</div>
<a href="#${prefix}_header" onclick="toggleAllSettings('open')">
<div class="icon"> ${getString(prefix+"_icon")} </div>
</a>
@@ -124,8 +144,7 @@
if(allOpen == false || openOrClose == 'open')
{
// open all
$('div[data-myid="collapsible"]').each(function(){$(this).attr('class', 'panel-collapse collapse in')})
$('div[data-myid="collapsible"]').each(function(){$(this).attr('style', 'height:inherit')})
openAllSettings()
$('#toggleSettings').attr('class', $('#toggleSettings').attr('class').replace(openIcon, closeIcon))
}
@@ -137,6 +156,11 @@
}
function openAllSettings() {
$('div[data-myid="collapsible"]').each(function(){$(this).attr('class', 'panel-collapse collapse in')})
$('div[data-myid="collapsible"]').each(function(){$(this).attr('style', 'height:inherit')})
}
// -------------------------------------------------------------------
// Checks if all schedules are the same
@@ -165,7 +189,376 @@
return true; // Return true if no schedules are found
}
// -------------------------------------------------------------------
// Checks if value is already encoded
function isSHA256(value) {
// Check if the value is a string and has a length of 64 characters
if (typeof value === "string" && value.length === 64) {
// Check if the value contains only hexadecimal characters
return /^[0-9a-fA-F]+$/.test(value);
} else {
return false;
}
}
// -------------------------------------------------------------------
// Validation
// -------------------------------------------------------------------
function settingsCollectedCorrectly(settingsArray, settingsJSON_DB) {
// check if the required UI_LANG setting is in the array - if not something went wrong
$.each(settingsArray, function(index, value) {
if (value[1] == "UI_LANG") {
if(isEmpty(value[3]) == true)
{
console.log(`⚠ Error: Required setting UI_LANG not found`);
showModalOk('ERROR', getString('settings_missing_block'));
return false;
}
}
});
const settingsCodeNames = settingsJSON_DB.map(setting => setting.Code_Name);
const detailedCodeNames = settingsArray.map(item => item[1]);
const missingCodeNamesOnPage = detailedCodeNames.filter(codeName => !settingsCodeNames.includes(codeName));
const missingCodeNamesInDB = settingsCodeNames.filter(codeName => !detailedCodeNames.includes(codeName));
// check if the number of settings on the page and in the DB are the same
if (missingCodeNamesOnPage.length !== missingCodeNamesInDB.length) {
console.log(`⚠ Error: The following settings are missing in the DB or on the page (Reload page to fix):`);
console.log(missingCodeNamesOnPage);
console.log(missingCodeNamesInDB);
showModalOk('ERROR', getString('settings_missing_block'));
return false;
}
// all OK
return true;
}
// -------------------------------------------------------------------
// Manipulating Editable List options
// -------------------------------------------------------------------
// ---------------------------------------------------------
function addList(element)
{
const fromId = $(element).attr('my-input-from');
const toId = $(element).attr('my-input-to');
input = $(`#${fromId}`).val();
$(`#${toId}`).append($("<option ></option>").attr("value", input).text(input));
// clear input
$(`#${fromId}`).val("");
settingsChanged();
}
// ---------------------------------------------------------
function removeFromList(element)
{
settingsChanged();
$(`#${$(element).attr('my-input')}`).find("option:last").remove();
}
// ---------------------------------------------------------
function addInterface()
{
ipMask = $('#ipMask').val();
ipInterface = $('#ipInterface').val();
full = ipMask + " --interface=" + ipInterface;
console.log(full)
if(ipMask == "" || ipInterface == "")
{
showModalOk ('Validation error', 'Specify both, the network mask and the interface');
} else {
$('#SCAN_SUBNETS').append($('<option disabled></option>').attr('value', full).text(full));
$('#ipMask').val('');
$('#ipInterface').val('');
settingsChanged();
}
}
// -------------------------------------------------------------------
// Function to remove an item from the select element
function removeOptionItem(option) {
settingsChanged();
option.remove();
}
// -------------------------------------------------------------------
// Update value of an item from the select element
function updateOptionItem(option, value) {
settingsChanged();
option.html(value);
option.val(value);
}
// -------------------------------------------------------------------
// Remove all options
function removeAllOptions(element)
{
settingsChanged();
$(`#${$(element).attr('my-input')}`).empty();
}
// -------------------------------------------------------------------
// Function to initialize remove functionality on select options
// Counter to track number of clicks
let clickCounter = 0;
// Function to initialize list interaction options
function initListInteractionOptions(selectorId) {
// Select all options within the specified selector
const $options = $(`#${selectorId} option`);
// Add class to make options interactable
$options.addClass('interactable-option');
// Attach click event listener to options
$options.on('click', function() {
const $option = $(this);
// Increment click counter
clickCounter++;
// Delay to capture multiple clicks
setTimeout(() => {
// Perform action based on click count
if (clickCounter === 1) {
// Single-click action
showModalFieldInput(
`<i class="fa-regular fa-pen-to-square"></i> ${getString('Gen_Update_Value')}`,
getString('settings_update_item_warning'),
getString('Gen_Cancel'),
getString('Gen_Update'),
$option.html(),
function() {
updateOptionItem($option, $(`#modal-field-input-field`).val())
}
);
} else if (clickCounter === 2) {
// Double-click action
removeOptionItem($option);
}
// Reset click counter
clickCounter = 0;
}, 300); // Adjust delay as needed
});
}
// -------------------------------------------------------------------
// Function to filter rows based on input text
function filterRows(inputText) {
if(!inputText)
{
inputText = ''
}
$('.table_row').each(function() {
// Check if the row id ends with '__metadata'
var idAttribute = $(this).attr('id');
if (idAttribute && idAttribute.endsWith('__metadata')) {
$(this).hide(); // Hide the row if it ends with '__metadata'
return; // Skip to the next iteration
}
var description = $(this).find('.setting_description').text().toLowerCase();
var codeName = $(this).find('.setting_name code').text().toLowerCase();
if (description.includes(inputText.toLowerCase()) || codeName.includes(inputText.toLowerCase())) {
$(this).show(); // Show the row if it matches the input text
} else {
$(this).hide(); // Hide the row if it doesn't match the input text
}
});
}
setTimeout(() => {
// Event listener for input change
$('#settingsSearch').on('input', function() {
var searchText = $(this).val();
// hide the setting overview dashboard
$('#settingsOverview').collapse('hide');
filterRows(searchText);
});
// Event listener for input focus
// var firstFocus = true;
$('#settingsSearch').on('focus', function() {
openAllSettings()
});
}, 1000);
// -----------------------------------------------------------------------------
// handling events on the backend initiated by the front end START
// -----------------------------------------------------------------------------
modalEventStatusId = 'modal-message-front-event'
// --------------------------------------------------------
// Calls a backend function to add a front-end event (specified by the attributes 'data-myevent' and 'data-myparam-plugin' on the passed element) to an execution queue
function addToExecutionQueue(element)
{
// value has to be in format event|param. e.g. run|ARPSCAN
action = `${getGuid()}|${$(element).attr('data-myevent')}|${$(element).attr('data-myparam-plugin')}`
$.ajax({
method: "POST",
url: "php/server/util.php",
data: { function: "addToExecutionQueue", action: action },
success: function(data, textStatus) {
// showModalOk ('Result', data );
// show message
showModalOk(getString("general_event_title"), `${getString("general_event_description")} <br/> <br/> <code id='${modalEventStatusId}'></code>`);
updateModalState()
}
})
}
// --------------------------------------------------------
// Updating the execution queue in in modal pop-up
function updateModalState() {
setTimeout(function() {
// Fetch the content from the log file using an AJAX request
$.ajax({
url: '/log/execution_queue.log',
type: 'GET',
success: function(data) {
// Update the content of the HTML element (e.g., a div with id 'logContent')
$('#'+modalEventStatusId).html(data);
updateModalState();
},
error: function() {
// Handle error, such as the file not being found
$('#logContent').html('Error: Log file not found.');
}
});
}, 2000);
}
// -----------------------------------------------------------------------------
// handling events on the backend initiated by the front end END
// -----------------------------------------------------------------------------
// ---------------------------------------------------------
// UNUSED?
function getParam(targetId, key, skipCache = false) {
skipCacheQuery = "";
if(skipCache)
{
skipCacheQuery = "&skipcache";
}
// get parameter value
$.get('php/server/parameters.php?action=get&defaultValue=0&parameter='+ key + skipCacheQuery, function(data) {
var result = data;
result = result.replaceAll('"', '');
document.getElementById(targetId).innerHTML = result.replaceAll('"', '');
});
}
// -----------------------------------------------------------------------------
// Show/hide the metadata settings
// -----------------------------------------------------------------------------
function toggleMetadata(element)
{
const id = $(element).attr('my-to-toggle');
$(`#${id}`).toggle();
}
// ---------------------------------------------------------
// Helper methods
// ---------------------------------------------------------
// Toggle readonly mode of the target element specified by the id in the "my-input-toggle-readonly" attribute
function overrideToggle(element) {
settingsChanged();
targetId = $(element).attr("my-input-toggle-readonly");
inputElement = $(`#${targetId}`)[0];
if (!inputElement) {
console.error("Input element not found!");
return;
}
if (inputElement.type === "text" || inputElement.type === "password") {
inputElement.readOnly = !inputElement.readOnly;
} else if (inputElement.type === "checkbox") {
inputElement.disabled = !inputElement.disabled;
} else {
console.warn("Unsupported input type. Only text, password, and checkbox inputs are supported.");
}
}
// ---------------------------------------------------------
// generate a list of options for a input select
function generateInputOptions(pluginsData, set, input, isMultiSelect = false)
{
multi = isMultiSelect ? "multiple" : "";
// optionsArray = getSettingOptions(set['Code_Name'] )
valuesArray = createArray(set['Value']);
// create unique ID
var targetLocation = set['Code_Name'] + "_initSettingDropdown";
// execute AJAX callabck + SQL query resolution
initSettingDropdown(set['Code_Name'] , valuesArray, targetLocation, generateDropdownOptions)
// main selection dropdown wrapper
input += `
<select onChange="settingsChanged()"
my-data-type="${set['Type']}"
class="form-control"
name="${set['Code_Name']}"
id="${set['Code_Name']}" ${multi}>
<option id="${targetLocation}" temporary="temporary"></option>
</select>`;
return input;
}

32
front/js/tests.js Executable file
View File

@@ -0,0 +1,32 @@
// --------------------------------------------------
// Check if database is locked
function lockDatabase(delay=20) {
$.ajax({
url: 'php/server/dbHelper.php', // Replace with the actual path to your PHP file
type: 'GET',
data: { action: 'lockDatabase', delay: delay },
success: function(response) {
console.log('Executed');
},
error: function() {
console.log('Error ocurred');
}
});
let times = delay;
let countdownInterval = setInterval(() => {
times--;
console.log(`Remaining time: ${times} seconds`);
if (times <= 0) {
clearInterval(countdownInterval);
console.log('Countdown finished');
}
}, 1000);
}

View File

@@ -1,5 +1,5 @@
/* -----------------------------------------------------------------------------
* Pi.Alert
* NetAlertX
* Open Source Network Guard / WIFI & LAN intrusion detector
*
* ui_components.js - Front module. Common UI components
@@ -13,13 +13,13 @@
// -----------------------------------------------------------------------------
function initDeviceSelectors() {
console.log(devicesList)
// console.log(devicesList)
// Retrieve device list from session variable
var devicesListAll_JSON = getCache('devicesListAll_JSON');
var devicesList = JSON.parse(devicesListAll_JSON);
console.log(devicesList);
// console.log(devicesList);
// Check if both device list exists
@@ -74,60 +74,29 @@ function initDeviceSelectors() {
}
}, 10);
}
// --------------------------------------------------------
//Initialize Select2 Elements and make them sortable
$(function () {
// Iterate over each Select2 dropdown
$('.select2').each(function() {
var selectEl = $(this).select2();
// Apply sortable functionality to the dropdown's dropdown-container
selectEl.next().children().children().children().sortable({
containment: 'parent',
update: function () {
var sortedValues = $(this).children().map(function() {
return $(this).attr('title');
}).get();
var sortedOptions = selectEl.find('option').sort(function(a, b) {
return sortedValues.indexOf($(a).text()) - sortedValues.indexOf($(b).text());
});
// Replace all options in selectEl
selectEl.empty().append(sortedOptions);
// Trigger change event on Select2
selectEl.trigger('change');
}
});
});
});
// -----------------------------------------------------------------------------
// Initiate dropdown
function initSettingDropdown(settingKey, valuesArray, targetLocation)
function initSettingDropdown(settingKey, // Identifier for the setting
valuesArray, // Array of values to be pre-selected in the dropdown
targetLocation, // ID of the HTML element where dropdown should be rendered (will be replaced)
callbackToGenerateEntries, // Callback function to generate entries based on options
targetField, // Target field or element where selected value should be applied or updated
nameTransformer) // callback to transform the name (e.g. base64)
{
var optionsHtml = ""
var targetLocation_options = settingKey + "_initSettingDropdown"
// NOTE {value} options to replace with a setting or SQL value are handled in the cacheSettings() function
optionsArray = createArray(getSettingOptions(settingKey))
// check if the result is a SQL query
if(isSQLQuery(optionsArray[0]))
{
optionsHtml += `<option id="${targetLocation_options}"></option>`;
readData(optionsArray[0], generateDropdownOptions, valuesArray, targetLocation_options);
{
readData(optionsArray[0], callbackToGenerateEntries, valuesArray, targetLocation, targetField, nameTransformer);
} else // this should be already an array, e.g. from a setting or pre-defined
{
@@ -144,12 +113,37 @@ function initSettingDropdown(settingKey, valuesArray, targetLocation)
}, 50);
}
}
// -----------------------------------------------------------------------------
// Hide elements on the page based on the supplied setting
function hideUIelements(settingKey) {
hiddenSectionsSetting = getSetting(settingKey)
if(hiddenSectionsSetting != "") // handle if settings not yet initialized
{
sectionsArray = createArray(hiddenSectionsSetting)
// remove spaces to get IDs
var newArray = $.map(sectionsArray, function(value) {
return value.replace(/\s/g, '');
});
$.each(newArray, function(index, hiddenSection) {
if($('#' + hiddenSection))
{
$('#' + hiddenSection).hide()
}
});
}
}
// -----------------------------------------------------------------------------
// Data processors
@@ -158,13 +152,25 @@ function initSettingDropdown(settingKey, valuesArray, targetLocation)
// -----------------------------------------------------------------------------
// Processor to generate options for a dropdown menu
function generateDropdownOptions(data, valuesArray) {
function generateDropdownOptions(data, valuesArray, targetField, nameTransformer) {
var optionsHtml = "";
data.forEach(function(item) {
labelName = item.name
// console.log(nameTransformer);
// console.log(labelName);
// if(nameTransformer && nameTransformer != '' && labelName != '❌None')
// {
// console.log(labelName);
// labelName = nameTransformer(labelName)
// console.log(labelName);
// }
let selected = valuesArray.includes(item.id) ? 'selected' : '';
optionsHtml += `<option value="${item.id}" ${selected}>${item.name}</option>`;
optionsHtml += `<option value="${item.id}" ${selected}>${labelName}</option>`;
});
return `${optionsHtml}`;
}
@@ -172,23 +178,139 @@ function generateDropdownOptions(data, valuesArray) {
// -----------------------------------------------------------------------------
// Processor to generate a list
function generateList(data, valuesArray) {
function generateList(data, valuesArray, targetField, nameTransformer) {
var listHtml = "";
data.forEach(function(item) {
labelName = item.name
if(nameTransformer && nameTransformer != '' && labelName != '❌None')
{
labelName = nameTransformer(labelName)
}
let selected = valuesArray.includes(item.id) ? 'selected' : '';
listHtml += `<li ${selected}>${labelName}</li>`;
});
return listHtml;
}
// -----------------------------------------------------------------------------
// Processor to generate a list in the deviceDetails page
function genListWithInputSet(data, valuesArray, targetField, nameTransformer) {
var listHtml = "";
console.log(data);
data.forEach(function(item) {
let selected = valuesArray.includes(item.id) ? 'selected' : '';
listHtml += `<li ${selected}>${item.name}</li>`;
// console.log(item);
labelName = item.name
if(nameTransformer && nameTransformer != '' && labelName != '❌None')
{
labelName = nameTransformer(labelName)
}
listHtml += `<li ${selected}>
<a href="javascript:void(0)" onclick="setTextValue('${targetField}','${item.id}')">${labelName}</a>
</li>`;
});
listHtml += "";
return listHtml;
}
// -----------------------------------------------------------------------------
// Updates the icon preview
function updateIconPreview (inputId) {
// update icon
iconInput = $(inputId)
value = iconInput.val()
iconInput.on('change input', function() {
$('#txtIconFA').html(atob(value))
});
$('#txtIconFA').html(atob(value))
}
// -----------------------------------------------------------------------------
// Generic function to copy text to clipboard
function copyToClipboard(buttonElement) {
const text = $(buttonElement).data('text');
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(() => {
showMessage('Copied to clipboard: ' + text, 1500);
}).catch(err => {
console.error('Failed to copy: ', err);
});
} else {
// Fallback to execCommand if Clipboard API is not available
const tempInput = document.createElement('input');
tempInput.value = text;
document.body.appendChild(tempInput);
tempInput.select();
try {
document.execCommand('copy');
showMessage('Copied to clipboard: ' + text, 1500);
} catch (err) {
console.error('Failed to copy: ', err);
}
document.body.removeChild(tempInput);
}
}
// -----------------------------------------------------------------------------
// initialize
// -----------------------------------------------------------------------------
initDeviceSelectors();
setTimeout(() => {
initDeviceSelectors();
// --------------------------------------------------------
//Initialize Select2 Elements and make them sortable
$(function () {
// Iterate over each Select2 dropdown
$('.select2').each(function() {
var selectEl = $(this).select2();
// Apply sortable functionality to the dropdown's dropdown-container
selectEl.next().children().children().children().sortable({
containment: 'parent',
update: function () {
var sortedValues = $(this).children().map(function() {
return $(this).attr('title');
}).get();
var sortedOptions = selectEl.find('option').sort(function(a, b) {
return sortedValues.indexOf($(a).text()) - sortedValues.indexOf($(b).text());
});
// Replace all options in selectEl
selectEl.empty().append(sortedOptions);
// Trigger change event on Select2
selectEl.trigger('change');
}
});
});
});
}, 500);
console.log("init ui_components.js")

1
front/lib/crypto/crypto-js.min.js vendored Executable file

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
<?php
#---------------------------------------------------------------------------------#
# Pi.Alert #
# NetAlertX #
# Open Source Network Guard / WIFI & LAN intrusion detector #
# #
# maintenance.php - Front module. Server side. Maintenance #
@@ -57,7 +57,7 @@ $pia_installed_skins = array('skin-black-light',
// Size and last mod of DB ------------------------------------------------------
$pia_db = str_replace('front', 'db', getcwd()).'/pialert.db';
$pia_db = str_replace('front', 'db', getcwd()).'/app.db';
$pia_db_size = number_format((filesize($pia_db) / 1000000),2,",",".") . ' MB';
$pia_db_mod = date ("F d Y H:i:s", filemtime($pia_db));
@@ -67,7 +67,7 @@ $pia_db_mod = date ("F d Y H:i:s", filemtime($pia_db));
$Pia_Archive_Path = str_replace('front', 'db', getcwd()).'/';
$Pia_Archive_count = 0;
$Pia_Archive_diskusage = 0;
$files = glob($Pia_Archive_Path."pialertdb_*.zip");
$files = glob($Pia_Archive_Path."appdb_*.zip");
if ($files){
$Pia_Archive_count = count($files);
}
@@ -78,7 +78,7 @@ $Pia_Archive_diskusage = number_format(($Pia_Archive_diskusage / 1000000),2,",",
// Find latest Backup for restore -----------------------------------------------
$latestfiles = glob($Pia_Archive_Path."pialertdb_*.zip");
$latestfiles = glob($Pia_Archive_Path."appdb_*.zip");
natsort($latestfiles);
$latestfiles = array_reverse($latestfiles,False);
@@ -161,7 +161,7 @@ $db->close();
<div class="db_info_table">
<div class="db_info_table_row">
<div class="db_info_table_cell" style="min-width: 140px"><?= lang('Maintenance_version');?>
<a href="https://github.com/jokob-sk/Pi.Alert/blob/main/docs/VERSIONS.md" target="_blank"> <span><i class="fa fa-circle-question"></i></a><span>
<a href="https://github.com/jokob-sk/NetAlertX/blob/main/docs/VERSIONS.md" target="_blank"> <span><i class="fa fa-circle-question"></i></a><span>
</div>
<div class="db_info_table_cell">
@@ -311,6 +311,8 @@ $db->close();
<option value="16"><?= lang('Device_TableHead_Location');?></option>
<option value="17"><?= lang('Device_TableHead_Vendor');?></option>
<option value="18"><?= lang('Device_TableHead_Port');?></option>
<option value="19"><?= lang('Device_TableHead_GUID');?></option>
<option value="20"><?= lang('Device_TableHead_SyncHubNodeName');?></option>
</select>
<span class="input-group-addon"><i title="<?= lang('Gen_Save');?>" class="fa fa-save pointer" onclick="saveSelectedColumns();"></i></span>
</div>
@@ -327,37 +329,37 @@ $db->close();
<div class="tab-pane" id="tab_DBTools">
<div class="db_info_table">
<div class="db_info_table_row">
<div class="db_tools_table_cell_a" style="">
<div class="db_tools_table_cell_a" >
<button type="button" class="btn btn-default pa-btn pa-btn-delete bg-red dbtools-button" id="btnDeleteMAC" onclick="askDeleteDevicesWithEmptyMACs()"><?= lang('Maintenance_Tool_del_empty_macs');?></button>
</div>
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_del_empty_macs_text');?></div>
</div>
<div class="db_info_table_row">
<div class="db_tools_table_cell_a" style="">
<div class="db_tools_table_cell_a" >
<button type="button" class="btn btn-default pa-btn pa-btn-delete bg-red dbtools-button" id="btnDeleteMAC" onclick="askDeleteAllDevices()"><?= lang('Maintenance_Tool_del_alldev');?></button>
</div>
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_del_alldev_text');?></div>
</div>
<div class="db_info_table_row">
<div class="db_tools_table_cell_a" style="">
<div class="db_tools_table_cell_a" >
<button type="button" class="btn btn-default pa-btn pa-btn-delete bg-red dbtools-button" id="btnDeleteUnknown" onclick="askDeleteUnknown()"><?= lang('Maintenance_Tool_del_unknowndev');?></button>
</div>
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_del_unknowndev_text');?></div>
</div>
<div class="db_info_table_row">
<div class="db_tools_table_cell_a" style="">
<div class="db_tools_table_cell_a" >
<button type="button" class="btn btn-default pa-btn pa-btn-delete bg-red dbtools-button" id="btnDeleteEvents" onclick="askDeleteEvents()"><?= lang('Maintenance_Tool_del_allevents');?></button>
</div>
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_del_allevents_text');?></div>
</div>
<div class="db_info_table_row">
<div class="db_tools_table_cell_a" style="">
<div class="db_tools_table_cell_a" >
<button type="button" class="btn btn-default pa-btn pa-btn-delete bg-red dbtools-button" id="btnDeleteEvents30" onclick="askDeleteEvents30()"><?= lang('Maintenance_Tool_del_allevents30');?></button>
</div>
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_del_allevents30_text');?></div>
</div>
<div class="db_info_table_row">
<div class="db_tools_table_cell_a" style="">
<div class="db_tools_table_cell_a" >
<button type="button" class="btn btn-default pa-btn pa-btn-delete bg-red dbtools-button" id="btnDeleteActHistory" onclick="askDeleteActHistory()"><?= lang('Maintenance_Tool_del_ActHistory');?></button>
</div>
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_del_ActHistory_text');?></div>
@@ -367,31 +369,31 @@ $db->close();
<div class="tab-pane" id="tab_BackupRestore">
<div class="db_info_table">
<div class="db_info_table_row">
<div class="db_tools_table_cell_a" style="">
<div class="db_tools_table_cell_a" >
<button type="button" class="btn btn-default pa-btn pa-btn-delete bg-red dbtools-button" id="btnPiaBackupDBtoArchive" onclick="askPiaBackupDBtoArchive()"><?= lang('Maintenance_Tool_backup');?></button>
</div>
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_backup_text');?></div>
</div>
<div class="db_info_table_row">
<div class="db_tools_table_cell_a" style="">
<div class="db_tools_table_cell_a" >
<button type="button" class="btn btn-default pa-btn pa-btn-delete bg-red dbtools-button" id="btnPiaRestoreDBfromArchive" onclick="askPiaRestoreDBfromArchive()"><?= lang('Maintenance_Tool_restore');?><br><?php echo $latestbackup_date;?></button>
</div>
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_restore_text');?></div>
</div>
<div class="db_info_table_row">
<div class="db_tools_table_cell_a" style="">
<div class="db_tools_table_cell_a" >
<button type="button" class="btn btn-default pa-btn pa-btn-delete bg-red dbtools-button" id="btnPiaPurgeDBBackups" onclick="askPiaPurgeDBBackups()"><?= lang('Maintenance_Tool_purgebackup');?></button>
</div>
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_purgebackup_text');?></div>
</div>
<div class="db_info_table_row">
<div class="db_tools_table_cell_a" style="">
<div class="db_tools_table_cell_a" >
<button type="button" class="btn btn-default pa-btn bg-green dbtools-button" id="btnExportCSV" onclick="askExportCSV()"><?= lang('Maintenance_Tool_ExportCSV');?></button>
</div>
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_ExportCSV_text');?></div>
</div>
<div class="db_info_table_row">
<div class="db_tools_table_cell_a" style="">
<div class="db_tools_table_cell_a" >
<button type="button" class="btn btn-default pa-btn pa-btn-delete bg-red dbtools-button" id="btnImportCSV" onclick="askImportCSV()"><?= lang('Maintenance_Tool_ImportCSV');?></button>
</div>
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_ImportCSV_text');?></div>
@@ -403,14 +405,14 @@ $db->close();
<div class="db_info_table">
<div class="log-area box box-solid box-primary">
<div class="row logs-row">
<textarea id="pialert_log" class="logs" cols="70" rows="10" wrap='off' readonly >
<textarea id="app_log" class="logs" cols="70" rows="10" wrap='off' readonly >
<?php
if(filesize("./log/pialert.log") > 2000000)
if(filesize("./log/app.log") > 2000000)
{
echo file_get_contents( "./log/pialert.log", false, null, -2000000);
echo file_get_contents( "./log/app.log", false, null, -2000000);
}
else{
echo file_get_contents( "./log/pialert.log" );
echo file_get_contents( "./log/app.log" );
}
?>
@@ -418,43 +420,43 @@ $db->close();
</div>
<div class="row logs-row" >
<div>
<div class="log-file">pialert.log <div class="logs-size"><?php echo number_format((filesize("./log/pialert.log") / 1000000),2,",",".") . ' MB';?>
<span class="span-padding"><a href="./log/pialert.log" target="_blank"><i class="fa fa-download"></i> </a></span>
<div class="log-file">app.log <div class="logs-size"><?php echo number_format((filesize("./log/app.log") / 1000000),2,",",".") . ' MB';?>
<span class="span-padding"><a href="./log/app.log" target="_blank"><i class="fa fa-download"></i> </a></span>
</div></div>
<div class="log-purge">
<button class="btn btn-primary" onclick="logManage('pialert.log','cleanLog')"><?= lang('Gen_Purge');?></button>
<button class="btn btn-primary" onclick="logManage('app.log','cleanLog')"><?= lang('Gen_Purge');?></button>
</div>
</div>
</div>
</div>
<div class="log-area box box-solid box-primary">
<div class="row logs-row">
<textarea id="pialert_front_log" class="logs" cols="70" rows="10" wrap='off' readonly><?php echo file_get_contents( "./log/pialert_front.log" ); ?>
<textarea id="app_front_log" class="logs" cols="70" rows="10" wrap='off' readonly><?php echo file_get_contents( "./log/app_front.log" ); ?>
</textarea>
</div>
<div class="row logs-row" >
<div>
<div class="log-file">pialert_front.log<div class="logs-size"><?php echo number_format((filesize("./log/pialert_front.log") / 1000000),2,",",".") . ' MB';?>
<span class="span-padding"><a href="./log/pialert_front.log"><i class="fa fa-download"></i> </a></span>
<div class="log-file">app_front.log<div class="logs-size"><?php echo number_format((filesize("./log/app_front.log") / 1000000),2,",",".") . ' MB';?>
<span class="span-padding"><a href="./log/app_front.log"><i class="fa fa-download"></i> </a></span>
</div></div>
<div class="log-purge">
<button class="btn btn-primary" onclick="logManage('pialert_front.log','cleanLog')"><?= lang('Gen_Purge');?></button>
<button class="btn btn-primary" onclick="logManage('app_front.log','cleanLog')"><?= lang('Gen_Purge');?></button>
</div>
</div>
</div>
</div>
<div class="log-area box box-solid box-primary">
<div class="row logs-row">
<textarea id="pialert_php_log" class="logs" cols="70" rows="10" wrap='off' readonly><?php echo file_get_contents( "./log/pialert.php_errors.log" ); ?>
<textarea id="app_php_log" class="logs" cols="70" rows="10" wrap='off' readonly><?php echo file_get_contents( "./log/app.php_errors.log" ); ?>
</textarea>
</div>
<div class="row logs-row" >
<div>
<div class="log-file">pialert.php_errors.log<div class="logs-size"><?php echo number_format((filesize("./log/pialert.php_errors.log") / 1000000),2,",",".") . ' MB';?>
<span class="span-padding"><a href="./log/pialert.php_errors.log"><i class="fa fa-download"></i> </a></span>
<div class="log-file">app.php_errors.log<div class="logs-size"><?php echo number_format((filesize("./log/app.php_errors.log") / 1000000),2,",",".") . ' MB';?>
<span class="span-padding"><a href="./log/app.php_errors.log"><i class="fa fa-download"></i> </a></span>
</div></div>
<div class="log-purge">
<button class="btn btn-primary" onclick="logManage('pialert.php_errors.log','cleanLog')"><?= lang('Gen_Purge');?></button>
<button class="btn btn-primary" onclick="logManage('app.php_errors.log','cleanLog')"><?= lang('Gen_Purge');?></button>
</div>
</div>
</div>
@@ -467,6 +469,7 @@ $db->close();
<div class="row logs-row" >
<div>
<div class="log-file" title="/var/log/nginx/error.log">nginx/error.log</div>
<span class="span-padding"><a href="/var/log/nginx/error.log"><i class="fa fa-download"></i> </a></span>
</div>
</div>
</div>
@@ -792,7 +795,7 @@ function scrollDown()
// Check if the parent <li> is active
if (elementToCheck.parent().hasClass("active")) {
{
var areaIDs = ['pialert_log', 'pialert_front_log', 'IP_changes_log', 'stdout_log', 'stderr_log', 'pialert_pholus_log', 'pialert_pholus_lastrun_log', 'pialert_php_log'];
var areaIDs = ['app_log', 'app_front_log', 'IP_changes_log', 'stdout_log', 'stderr_log', 'app_pholus_log', 'app_pholus_lastrun_log', 'app_php_log'];
for (let i = 0; i < areaIDs.length; i++) {
@@ -922,8 +925,10 @@ function initializeTabs () {
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
var target = $(e.target).attr("href") // activated tab
});
hideSpinner();
}, 50);
}, 50);
}
@@ -935,10 +940,10 @@ window.onload = function asyncFooter()
scrollDown();
initializeTabs();
$("#lastCommit").append('<a href="https://github.com/jokob-sk/Pi.Alert/commits" target="_blank"><img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/jokob-sk/pi.alert/main?logo=github"></a>');
$("#lastCommit").append('<a href="https://github.com/jokob-sk/NetAlertX/commits" target="_blank"><img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/jokob-sk/netalertx/main?logo=github"></a>');
$("#lastDockerUpdate").append(
'<a href="https://github.com/jokob-sk/Pi.Alert/releases" target="_blank"><img alt="Docker last pushed" src="https://img.shields.io/github/v/release/jokob-sk/Pi.Alert?color=0aa8d2&logoColor=fff&logo=GitHub&label=Latest"></a>');
'<a href="https://github.com/jokob-sk/NetAlertX/releases" target="_blank"><img alt="Docker last pushed" src="https://img.shields.io/github/v/release/jokob-sk/NetAlertX?color=0aa8d2&logoColor=fff&logo=GitHub&label=Latest"></a>');
}
@@ -948,8 +953,6 @@ window.onload = function asyncFooter()
</script>
<link rel="stylesheet" href="lib/AdminLTE/bower_components/select2/dist/css/select2.min.css">
<script src="lib/AdminLTE/bower_components/select2/dist/js/select2.full.min.js"></script>
<script src="lib/AdminLTE/bower_components/jquery-ui/jquery-ui.min.js"></script>

View File

@@ -3,25 +3,33 @@
<div class="col-md-12">
<div class="callout callout-warning">
<h4><?= lang('Gen_Warning');?></h4>
<p><?= lang('Device_MultiEdit_Backup');?></p>
</div>
<div class="box box-default">
<div class="box-header">
<h3 class="box-title"><?= lang('Gen_Selected_Devices');?></h3>
</div>
<div class="deviceSelector"></div>
</div>
<div class="deviceSelector col-md-9" style="z-index:5"></div>
<div class="callout callout-warning">
<h4><?= lang('Gen_Warning');?></h4>
<p><?= lang('Device_MultiEdit_Backup');?></p>
<div class="col-md-3">
<button type="button" class="btn btn-default" onclick="markAllSelected()">
<i class="fa-solid fa-circle-check"></i> <?= lang('Gen_Add_All');?>
</button>
<button type="button" class="btn btn-default" onclick="markAllNotSelected()">
<i class="fa-solid fa-circle-xmark"></i> <?= lang('Gen_Remove_All');?>
</button>
</div>
</div>
<div class="col-md-12">
<div class="box box-default">
@@ -65,7 +73,9 @@
// Get plugin and settings data from API endpoints
function getData(){
$.get('api/table_settings.json?nocache=' + Date.now(), function(res) {
// some race condition, need to implement delay
setTimeout(() => {
$.get('api/table_settings.json?nocache=' + Date.now(), function(res) {
settingsData = res["data"];
@@ -105,23 +115,41 @@
default:
inputType = 'text';
break;
}
// Add classes specifically for checkboxes
}
if (inputType === 'text.select') {
targetLocation = columns[j].Code_Name + "_initSettingDropdown"
initSettingDropdown(columns[j].Code_Name, [], targetLocation)
initSettingDropdown(columns[j].Code_Name, [], targetLocation, generateDropdownOptions)
input = `<select class="form-control"
// Handle Icons as tehy need a preview
if(columns[j].Code_Name == 'NEWDEV_dev_Icon')
{
input = `
<span class="input-group-addon" id="txtIconFA"></span>
<select class="form-control"
onChange="updateIconPreview('#NEWDEV_dev_Icon')"
id="${columns[j].Code_Name}"
data-my-column="${columns[j].Code_Name}"
data-my-targetColumns="${columns[j].Code_Name.replace('NEWDEV_','')}" >
<option id="${targetLocation}"></option>
</select>`
} else {
} else{
input = `<select class="form-control"
id="${columns[j].Code_Name}"
data-my-column="${columns[j].Code_Name}"
data-my-targetColumns="${columns[j].Code_Name.replace('NEWDEV_','')}" >
<option id="${targetLocation}"></option>
</select>`
}
} else {
// Add classes specifically for checkboxes
if (inputType === 'checkbox') {
inputClass = 'checkbox';
@@ -163,6 +191,9 @@
})
}, 500);
}
@@ -172,6 +203,39 @@
return $('.deviceSelector select').val().join(',');
}
// -----------------------------------------------------------------------------
// Select All
function markAllSelected() {
// Get the <select> element with the class 'deviceSelector'
var selectElement = $('.deviceSelector select');
// Iterate over each option within the select element
selectElement.find('option').each(function() {
// Mark each option as selected
$(this).prop('selected', true);
});
// Trigger the 'change' event to notify Bootstrap Select of the changes
selectElement.trigger('change');
}
// -----------------------------------------------------------------------------
// UN-Select All
function markAllNotSelected() {
// Get the <select> element with the class 'deviceSelector'
var selectElement = $('.deviceSelector select');
// Iterate over each option within the select element
selectElement.find('option').each(function() {
// Unselect each option
$(this).prop('selected', false);
});
// Trigger the 'change' event to notify Bootstrap Select of the changes
selectElement.trigger('change');
}
// -----------------------------------------------------------------------------
// Update specified field over the specified DB column and selected entry(ies)
@@ -192,7 +256,7 @@
columnValue = inputElement.is(':checked') ? 1 : 0;
} else {
// For other input types (like textboxes), simply retrieve their values
columnValue = inputElement.val();
columnValue = encodeURIComponent(inputElement.val());
}
var targetColumns = inputElement.attr('data-my-targetColumns');
@@ -226,6 +290,8 @@ function executeAction(action, whereColumnName, key, targetColumns, newTargetCol
// update API endpoints to refresh the UI
updateApi()
writeNotification(`[Multi edit] Executed "${action}" on Columns "${targetColumns}" matching "${key}"`, 'info')
} else {
showMessage(getString('Gen_LockedDB'));
}
@@ -249,9 +315,9 @@ function askDeleteSelectedDevices () {
// Delete selected devices
function deleteSelectedDevices()
{
executeAction('delete', 'dev_MAC', selectorMacs() )
macs_tmp = selectorMacs()
executeAction('delete', 'dev_MAC', macs_tmp )
writeNotification('[Multi edit] Manually deleted devices with MACs:' + macs_tmp, 'info')
}
@@ -261,8 +327,7 @@ getData();
</script>
<!-- ----------------------------------------------------------------------- -->
<script src="js/ui_components.js"></script>
<script src="js/db_methods.js"></script>
<!-- ----------------------------------------------------------------------- -->

View File

@@ -18,7 +18,7 @@
<?php require 'php/templates/notification.php'; ?>
<h1 id="pageTitle">
<i class="fa fa-network-wired"></i> <?= lang('Network_Title');?>
<span class="networkPageHelp"> <a target="_blank" href="https://github.com/jokob-sk/Pi.Alert/blob/main/docs/NETWORK_TREE.md"><i class="fa fa-circle-question"></i></a><span>
<span class="networkPageHelp"> <a target="_blank" href="https://github.com/jokob-sk/NetAlertX/blob/main/docs/NETWORK_TREE.md"><i class="fa fa-circle-question"></i></a><span>
</h1>
</section>
@@ -26,7 +26,7 @@
<div id="networkTree" class="drag"></div>
<!-- Main content ---------------------------------------------------------- -->
<section class="content">
<section class="content networkTable">
<?php
// Create top-level node (network devices) tabs
function createDeviceTabs($node_mac, $node_name, $node_status, $node_type, $node_ports_count, $icon, $activetab) {
@@ -47,15 +47,12 @@
$node_badge = circle_offline;
}
if($icon != '')
{
$icon = '<i class="fa fa-'.$icon.'"></i> ';
}
$decoded_icon = base64_decode($icon);
$idFromMac = str_replace(":", "_", $node_mac);
$str_tab_header = '<li class="'.$activetab.'">
<a href="#'.$idFromMac.'" data-mytabmac="'.$node_mac.'" id="'.$idFromMac.'_id" data-toggle="tab" >' // _id is added so it doesn't conflict with AdminLTE tab behavior
.$icon.$node_name.' ' .$str_port.$node_badge.
.'<div class="icon">'.$decoded_icon.' </div>'.$node_name.' ' .$str_port.$node_badge.
'</a>
</li>';
@@ -660,7 +657,7 @@
// Build HTML for individual nodes in the network diagram
deviceIcon = (!emptyArr.includes(nodeData.data.icon )) ?
`<div class="netIcon">
<i class="fa fa-${nodeData.data.icon}"></i>
${atob(nodeData.data.icon)}
</div>` : "";
devicePort = `<div class="netPort"
style="width:${emSize*sizeCoefficient}em;height:${emSize*sizeCoefficient}em">

View File

@@ -1,74 +1,194 @@
<?php
//------------------------------------------------------------------------------
// Pi.Alert
// NetAlertX
// Open Source Network Guard / WIFI & LAN intrusion detector
//
// db.php - Front module. Server side. DB common file
//------------------------------------------------------------------------------
# Puche 2021 / 2022+ jokob jokob@duck.com GNU GPLv3
# 2022 jokob jokob@duck.com GNU GPLv3
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// DB File Path
$DBFILE = dirname(__FILE__).'/../../../db/pialert.db';
$DBFILE = dirname(__FILE__).'/../../../db/app.db';
$DBFILE_LOCKED_FILE = dirname(__FILE__).'/../../../front/log/db_is_locked.log';
$db_locked = false;
//------------------------------------------------------------------------------
// Connect DB
//------------------------------------------------------------------------------
function SQLite3_connect ($trytoreconnect) {
global $DBFILE;
try
{
// connect to database
// return new SQLite3($DBFILE, SQLITE3_OPEN_READONLY);
return new SQLite3($DBFILE, SQLITE3_OPEN_READWRITE);
}
catch (Exception $exception)
{
// sqlite3 throws an exception when it is unable to connect
// try to reconnect one time after 3 seconds
if($trytoreconnect)
{
echo '<script>alert("Error connecting to database, will try in 3s")</script>';
sleep(3);
return SQLite3_connect(false);
function SQLite3_connect($trytoreconnect = true, $retryCount = 0) {
global $DBFILE, $DBFILE_LOCKED_FILE;
$maxRetries = 5; // Maximum number of retries
$baseDelay = 1; // Base delay in seconds
try {
// Connect to database
global $db_locked;
$db_locked = false;
// Write unlock status to the locked file
file_put_contents($DBFILE_LOCKED_FILE, '0');
return new SQLite3($DBFILE, SQLITE3_OPEN_READWRITE);
} catch (Exception $exception) {
// sqlite3 throws an exception when it is unable to connect
global $db_locked;
$db_locked = true;
// Write lock status to the locked file
file_put_contents($DBFILE_LOCKED_FILE, '1');
error_log("Failed to connect to database: " . $exception->getMessage());
// Connection failed, check if we should retry
if ($trytoreconnect && $retryCount < $maxRetries) {
// Calculate exponential backoff delay
$delay = $baseDelay * pow(2, $retryCount);
sleep($delay);
// Retry the connection with an increased retry count
return SQLite3_connect(true, $retryCount + 1);
} else {
// Maximum retries reached, hide loading spinner and show failure alert
$message = 'Failed to connect to database after ' . $retryCount . ' retries.';
write_notification($message);
return false; // Or handle the failure appropriately
}
}
}
}
//------------------------------------------------------------------------------
// ->query override to handle retries
//------------------------------------------------------------------------------
class CustomDatabaseWrapper {
private $sqlite;
private $maxRetries;
private $retryDelay;
public function __construct($filename, $flags = SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE, $maxRetries = 10, $retryDelay = 1000, $encryptionKey = null) {
$this->sqlite = new SQLite3($filename, $flags, $encryptionKey);
$this->maxRetries = $maxRetries;
$this->retryDelay = $retryDelay;
}
public function query(string $query): SQLite3Result|bool {
global $DBFILE_LOCKED_FILE;
// Check if the query is an UPDATE, DELETE, or INSERT
$queryType = strtoupper(substr(trim($query), 0, strpos(trim($query), ' ')));
$isModificationQuery = in_array($queryType, ['UPDATE', 'DELETE', 'INSERT']);
$attempts = 0;
while ($attempts < $this->maxRetries) {
$result = false;
try {
$result = $this->sqlite->query($query);
} catch (Exception $exception) {
// continue unless maxRetries reached
if($attempts > $this->maxRetries)
{
throw $exception;
}
}
if ($result !== false and $result !== null) {
$this->query_log_remove($query);
return $result;
}
$this->query_log_add($query);
$attempts++;
usleep($this->retryDelay * 1000 * $attempts); // Retry delay in milliseconds
}
// If all retries failed, throw an exception or handle the error as needed
// Add '0' to indicate that the database is not locked/execution failed
file_put_contents($DBFILE_LOCKED_FILE, '0');
$message = 'Error executing query (attempts: ' . $attempts . '), query: ' . $query;
write_notification($message);
error_log("Query failed after {$this->maxRetries} attempts: " . $this->sqlite->lastErrorMsg());
}
public function query_log_add($query)
{
global $DBFILE_LOCKED_FILE;
// Remove new lines from the query
$query = str_replace(array("\r", "\n"), ' ', $query);
// Generate a hash of the query
$queryHash = md5($query);
// Log the query being attempted along with timestamp and query hash
$executionLog = "1|" . date('Y-m-d H:i:s') . "|$queryHash|$query";
error_log("Attempting to write '$executionLog' to execution log file after failed query: $query");
file_put_contents($DBFILE_LOCKED_FILE, $executionLog . PHP_EOL, FILE_APPEND);
error_log("Execution log file content after failed query attempt: " . file_get_contents($DBFILE_LOCKED_FILE));
}
public function query_log_remove($query)
{
global $DBFILE_LOCKED_FILE;
// Remove new lines from the query
$query = str_replace(array("\r", "\n"), ' ', $query);
// Generate a hash of the query
$queryHash = md5($query);
// Remove the entry corresponding to the finished query from the execution log based on query hash
$executionLogs = file($DBFILE_LOCKED_FILE, FILE_IGNORE_NEW_LINES);
$executionLogs = array_filter($executionLogs, function($log) use ($queryHash) {
return strpos($log, $queryHash) === false;
});
file_put_contents($DBFILE_LOCKED_FILE, implode(PHP_EOL, $executionLogs));
}
// Delegate other SQLite3 methods to the $sqlite instance
public function __call($name, $arguments) {
return call_user_func_array([$this->sqlite, $name], $arguments);
}
}
//------------------------------------------------------------------------------
// Open DB
//------------------------------------------------------------------------------
function OpenDB($DBPath = null) {
global $DBFILE;
global $db;
function OpenDB (...$DBPath) {
global $DBFILE;
global $db;
// Use custom path if supplied
if ($DBPath !== null) {
$DBFILE = $DBPath;
}
// use custom path if supplied
foreach ($DBPath as $path) {
$DBFILE = $path;
}
if(strlen($DBFILE) == 0)
{
echo '<script>alert("Database not available")</script>';
die ('<div style="padding-left:150px">Database not available</div>');
}
if (strlen($DBFILE) == 0) {
$message = 'Database not available';
echo '<script>alert('.$message.')</script>';
write_notification($message);
die('<div style="padding-left:150px">'.$message.'</div>');
}
$db = SQLite3_connect(true);
if(!$db)
{
echo '<script>alert("Error connecting to the database")</script>';
die ('<div style="padding-left:150px">Error connecting to the database</div>');
}
try {
$db = new CustomDatabaseWrapper($DBFILE);
} catch (Exception $e) {
$message = "Error connecting to the database";
echo '<script>alert('.$message.'": ' . $e->getMessage() . '")</script>';
write_notification($message);
die('<div style="padding-left:150px">'.$message.'</div>');
}
$db->exec('PRAGMA journal_mode = wal;');
$db->exec('PRAGMA journal_mode = wal;');
}
// # Open DB once and keep open
// # Opening / closing DB frequently actually casues more issues
OpenDB (); // main
// Open DB once and keep open
OpenDB(); // main
?>

Some files were not shown because too many files have changed in this diff Show More