Compare commits

..

516 Commits

Author SHA1 Message Date
Hosted Weblate
d36486ef6d Merge branch 'origin/main' into Weblate. 2024-10-12 03:05:05 +02:00
Massimo Pissarello
1767776dd9 Translated using Weblate (Italian)
Currently translated at 100.0% (702 of 702 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-10-12 03:05:05 +02:00
jokob-sk
507e0469d6 Strings cleanup 2024-10-12 12:04:42 +11:00
jokob-sk
ae14229ca7 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-10-12 11:00:42 +11:00
jokob-sk
dcfeb51aa1 Ignored IPs not applied #836 2024-10-12 10:49:29 +11:00
github-actions[bot]
ab6e7d910b [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-10-11 11:53:51 +00:00
jokob-sk
d6164a005b UNIFIMP CMD set to readonly 2024-10-11 20:19:46 +11:00
jokob-sk
ca1d55b3c2 Normalizing device names #833 2024-10-11 20:14:13 +11:00
jokob-sk
c4e0abf913 Ignored IPs not applied #836 2024-10-11 20:05:23 +11:00
jokob-sk
f9e6871ab2 New Device creation int.replace issue #833 2024-10-11 19:00:08 +11:00
jokob-sk
30b8ecb743 🔎Mikrotik IP missing #835
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-10-11 07:55:57 +11:00
github-actions[bot]
506b8a17fc [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-10-10 11:53:56 +00:00
jokob-sk
43c60586f4 🌍 Arabic (ar_ar) empty file for translations added
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-10-10 08:11:09 +11:00
jokob-sk
a11d7d9c97 SYNC required + docs 2024-10-10 07:57:07 +11:00
jokob-sk
222a439212 SYNC required + docs 2024-10-10 07:55:37 +11:00
github-actions[bot]
48effdbbad [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-10-09 11:53:52 +00:00
Yannick Torrès
62a0149435 Translated using Weblate (French)
Some checks are pending
docker / docker_dev (push) Waiting to run
Currently translated at 100.0% (700 of 700 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-10-09 12:57:46 +02:00
github-actions[bot]
8702ae032e [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-10-08 11:53:55 +00:00
jokob-sk
82d2fa4125 Store order of 90 days #824
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-10-08 21:34:41 +11:00
jokob-sk
189a4ece84 Merge pull request #827 from RincewindX/patch-1
Update DEBUG_TIPS.md
2024-10-08 19:03:42 +11:00
RincewindX
29de6654a8 Update DEBUG_TIPS.md
Add section for only one device shows up
2024-10-08 09:29:43 +02:00
Norbert (Noschvie)
06008058ab Translated using Weblate (German)
Currently translated at 93.1% (652 of 700 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/de/
2024-10-08 04:59:55 +02:00
jokob-sk
efc9a974b1 Settings - UI component changes #826
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-10-08 08:52:24 +11:00
github-actions[bot]
d91141f9ac [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-10-07 11:53:46 +00:00
Massimo Pissarello
e8d2e52ee2 Translated using Weblate (Italian)
Some checks are pending
docker / docker_dev (push) Waiting to run
Currently translated at 100.0% (700 of 700 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-10-06 23:27:19 +00:00
github-actions[bot]
d64b92c273 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-10-06 11:53:55 +00:00
github-actions[bot]
32bebe3ad4 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-10-05 11:53:35 +00:00
github-actions[bot]
2d119f39c0 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-10-04 11:53:52 +00:00
jokob-sk
f9b28b647b DBCLNP chore
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-10-04 14:02:16 +10:00
jokob-sk
41a72f0292 AVAHISCAN / mDNS #815 2024-10-04 12:34:31 +10:00
jokob-sk
129cd39ef8 AVAHISCAN / mDNS #815 2024-10-04 12:07:55 +10:00
jokob-sk
68febd1350 AVAHISCAN / mDNS #815 2024-10-04 11:35:05 +10:00
jokob-sk
669ce20a84 AVAHISCAN / mDNS #815 2024-10-04 11:25:54 +10:00
jokob-sk
9427ff6453 AVAHISCAN / mDNS #815
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-10-04 10:29:13 +10:00
jokob-sk
7b2186073f AVAHISCAN / mDNS #815 2024-10-04 10:06:05 +10:00
jokob-sk
30de0f9f93 AVAHISCAN / mDNS #815 2024-10-04 10:05:06 +10:00
jokob-sk
d146b485c4 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-10-04 07:53:05 +10:00
jokob-sk
37290528fc Fix error redirect 2024-10-04 07:52:44 +10:00
github-actions[bot]
b4d1505e42 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-10-03 11:54:01 +00:00
Safeguard
afe5a2ae48 Translated using Weblate (Russian)
Some checks are pending
docker / docker_dev (push) Waiting to run
Currently translated at 100.0% (700 of 700 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-10-03 10:15:38 +02:00
gallegonovato
ef5dc885d9 Translated using Weblate (Spanish)
Currently translated at 100.0% (700 of 700 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-10-03 10:15:36 +02:00
jokob-sk
a758548fea nbtscan logging 2024-10-03 16:29:46 +10:00
jokob-sk
c6cfa398ef Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-10-03 13:46:59 +10:00
jokob-sk
677e293138 MQTT_topic_root 2024-10-03 13:45:59 +10:00
github-actions[bot]
ac259b1fab [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-10-02 11:53:48 +00:00
jokob-sk
14996d6582 MQTT_topic_root
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-10-02 16:10:19 +10:00
jokob-sk
d44744657e MQTT timestamp normalization for HomeAssistant 2024-10-02 15:51:08 +10:00
jokob-sk
615e5e4084 MQTT timestamp normalization for HomeAssistant 2024-10-02 14:36:42 +10:00
jokob-sk
dd948b5e63 Merge pull request #820 from NightMean/main
Some checks are pending
docker / docker_dev (push) Waiting to run
Update MQTT to send model as device name - thanks to @NightMean 🙏
2024-10-02 08:56:39 +10:00
jokob-sk
97a5cb6737 HomeAssistant docs + Delete listed Plugin Obj #813 2024-10-02 08:53:29 +10:00
NightMean
c6fe09d366 Update MQTT to send model as device name
Adds a device name as model for HomeAssistant that shows in Device info.
2024-10-01 22:04:28 +02:00
jokob-sk
040f2792e4 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-10-01 23:09:46 +10:00
jokob-sk
d1d6d7f1ec MQTT docs 2024-10-01 23:09:29 +10:00
github-actions[bot]
33c16c4d00 [🤖Automation] Update README with sponsors information 2024-10-01 11:53:38 +00:00
Hosted Weblate
cc8b57e790 Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-10-01 06:36:47 +02:00
Yannick Torrès
57d8e97b60 Translated using Weblate (French)
Currently translated at 100.0% (699 of 699 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-10-01 06:36:47 +02:00
jokob-sk
91ad39e991 Popup display on mobile #772 2024-10-01 14:36:24 +10:00
jokob-sk
15ed621748 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-10-01 08:42:18 +10:00
jokob-sk
50304fd63b 📊 Presence over time updates #816 2024-10-01 08:42:14 +10:00
Yannick Torrès
90689e5c69 Translated using Weblate (French)
Some checks are pending
docker / docker_dev (push) Waiting to run
Currently translated at 98.5% (689 of 699 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-09-30 12:16:48 +00:00
gallegonovato
5f4b2f114c Translated using Weblate (Spanish)
Currently translated at 100.0% (699 of 699 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-09-30 12:16:47 +00:00
github-actions[bot]
e72a87ab43 [🤖Automation] Update README with sponsors information 2024-09-30 11:53:45 +00:00
jokob-sk
044de61ab5 ⬇CSV Import work #808
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-30 10:30:09 +10:00
github-actions[bot]
e5d835cfa9 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-29 11:53:44 +00:00
jokob-sk
e2d84a1885 MQTT handling diacritics #813
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-29 11:52:29 +10:00
jokob-sk
e648acde5c General enhancements 2024-09-29 11:26:06 +10:00
jokob-sk
a17e066f34 🔃Sync enhancements 2024-09-29 11:12:38 +10:00
jokob-sk
0bdc4c4ed1 chore: 🧹Removal of DB backups functionality 2024-09-29 10:00:04 +10:00
jokob-sk
9144fd0c3a Handling checkboxes better #779 2024-09-29 09:19:54 +10:00
jokob-sk
02077d4654 CSV Export - encode quotes #808 2024-09-29 08:18:00 +10:00
github-actions[bot]
e3b2039257 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-28 11:53:47 +00:00
jokob-sk
1fa38472e1 📚Docs 2024-09-28 16:58:17 +10:00
jokob-sk
1e197ae749 chore: 🧹 Code Cleanup
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-28 11:20:57 +10:00
jokob-sk
7731a01f3c chore: 🧹 Code Cleanup 2024-09-28 10:29:43 +10:00
jokob-sk
3ce08ba97d Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-09-28 10:29:05 +10:00
jokob-sk
c58bbf21b1 chore: 🧹 Code Cleanup 2024-09-28 10:28:05 +10:00
github-actions[bot]
3780e47117 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-27 11:53:42 +00:00
jokob-sk
e8f353024f Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-09-27 16:15:36 +10:00
jokob-sk
7308797314 removing cryptography 2024-09-27 16:15:14 +10:00
jokob-sk
6e36f7d7aa Merge pull request #810 from ingoratsdorf/contrib
Some checks are pending
docker / docker_dev (push) Waiting to run
fixes to MQTT publisher
2024-09-27 12:42:47 +10:00
Ingo Ratsdorf
8d3a4500e2 Merge branch 'jokob-sk:main' into contrib 2024-09-27 14:30:58 +12:00
jokob-sk
40d6bdc2b2 Cryptography -> crypto_utils rename #809 2024-09-27 12:21:42 +10:00
Ingo Ratsdorf
b7b2e0bc65 fixes to MQTT publisher
This wasn't working for EMQX due to callback trigger delays it never connected. Also added a reconnect feature and a client id so it looks better in the EMQX connection dashboard. No confirmed to be working with Mosquitto and EMQX
2024-09-27 12:24:46 +12:00
jokob-sk
081d0f3400 Sync 2024-09-27 10:02:24 +10:00
github-actions[bot]
a7f4565954 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-26 11:53:36 +00:00
jokob-sk
15a7779d6e Sanitize input #805
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-26 08:08:24 +10:00
jokob-sk
2784f2ebeb Sanitize input #807 2024-09-26 07:32:04 +10:00
jokob-sk
d46046beea Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-09-26 07:22:02 +10:00
jokob-sk
6233f4d646 Sanitize input #805 2024-09-26 07:21:58 +10:00
github-actions[bot]
31411e0a14 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-25 11:53:41 +00:00
Hosted Weblate
8d824af3bd Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-24 23:50:28 +02:00
gallegonovato
f05f0d625a Translated using Weblate (Spanish)
Currently translated at 100.0% (698 of 698 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-09-24 23:50:28 +02:00
jokob-sk
2fec3b6607 📚Docs 2024-09-25 07:50:13 +10:00
jokob-sk
f285a28887 Cleanup 2024-09-25 07:25:31 +10:00
github-actions[bot]
11cb47fada [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-24 11:53:56 +00:00
Anonymous
d8b413b5e7 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 96.7% (675 of 698 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/zh_Hans/
2024-09-24 13:48:15 +02:00
Anonymous
656bba7ff7 Translated using Weblate (Polish)
Currently translated at 97.4% (680 of 698 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/pl/
2024-09-24 13:48:15 +02:00
Anonymous
a2cf8c1167 Translated using Weblate (Portuguese (Brazil))
Currently translated at 34.8% (243 of 698 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/pt_BR/
2024-09-24 13:48:15 +02:00
Anonymous
737cb07403 Translated using Weblate (Italian)
Currently translated at 99.1% (692 of 698 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-09-24 13:48:15 +02:00
Anonymous
3febbc21cb Translated using Weblate (Russian)
Currently translated at 99.1% (692 of 698 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-09-24 13:48:15 +02:00
Anonymous
7e14fae29c Translated using Weblate (Norwegian Bokmål)
Currently translated at 96.2% (672 of 698 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/nb_NO/
2024-09-24 13:48:14 +02:00
Anonymous
a16fe4561b Translated using Weblate (French)
Currently translated at 98.7% (689 of 698 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-09-24 13:48:14 +02:00
Anonymous
f2afe9d681 Translated using Weblate (Spanish)
Currently translated at 99.2% (693 of 698 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-09-24 13:48:14 +02:00
Anonymous
f8c0a5a1ef Translated using Weblate (German)
Currently translated at 93.4% (652 of 698 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/de/
2024-09-24 13:48:14 +02:00
github-actions[bot]
631e992411 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-23 11:54:00 +00:00
jokob-sk
feafaff218 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-23 13:33:17 +10:00
jokob-sk
f6a06842cc Overridden by ENV + Icons preview #802 2024-09-23 13:32:36 +10:00
jokob-sk
0cc3ede86c Merge pull request #801 from alnviana/patch-1
Some checks are pending
docker / docker_dev (push) Waiting to run
Fixes to work using a reverse proxy
2024-09-23 11:25:39 +10:00
Allan Viana
aa277136c6 Making table_appevents and table_notifications relative 2024-09-22 21:51:49 -03:00
Allan Viana
82ccb0c0b6 Making user_notifications relative 2024-09-22 21:18:48 -03:00
jokob-sk
30750a9449 ui components defer 2024-09-23 08:39:07 +10:00
jokob-sk
5278af48c5 Sync Hub fix + overriddenByEnv 2024-09-23 08:15:35 +10:00
github-actions[bot]
77f19c3575 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-22 11:53:38 +00:00
jokob-sk
10df7363d6 Merge pull request #798 from ingoratsdorf/contrib
Some checks are pending
docker / docker_dev (push) Waiting to run
Fixes to CSS and scripts not loading properly
2024-09-22 19:16:50 +10:00
jokob-sk
06e49f7adb 📚Docs 2024-09-22 17:05:49 +10:00
Ingo Ratsdorf
9fcbd9d64e DEFER break devicedetails page
Removed DEFER from ui_components as the device details page would not populate any more and the browser console would throw errors re function not found
2024-09-22 08:18:21 +12:00
Ingo Ratsdorf
c6888a79fd Fixes CSS typo in deviceDetails 2024-09-22 08:13:09 +12:00
github-actions[bot]
ef458903b7 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-21 11:53:41 +00:00
jokob-sk
b544734209 NEWDEV_dev_Icon preview #789
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-21 17:40:41 +10:00
github-actions[bot]
815810dc7a [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-20 11:53:33 +00:00
github-actions[bot]
552d79eee8 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-19 11:53:52 +00:00
jokob-sk
2f70e2e8d8 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-19 15:45:16 +10:00
jokob-sk
4a20b66c92 Clear NEW flag setting 2024-09-19 15:43:16 +10:00
github-actions[bot]
36cec0ab38 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-18 11:53:41 +00:00
jokob-sk
6bde0f9084 🔑 Set PWD not working #793
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-18 12:56:09 +10:00
jokob-sk
f64ef5b881 🔑 Set PWD not working #793
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-18 09:57:46 +10:00
jokob-sk
1895f68233 🔄 Sync hub 2.0.1 - init Node field #788 2024-09-18 09:27:32 +10:00
jokob-sk
d2fe53bc81 🔃 Sync hub 2.0.1 #788 2024-09-18 08:48:08 +10:00
github-actions[bot]
e9e45c34ae [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-17 11:53:54 +00:00
jokob-sk
064a51acee 🩹 Handle vendor NoneType #791
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-17 08:05:17 +10:00
github-actions[bot]
7340ce6da2 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-16 11:53:54 +00:00
github-actions[bot]
703885308a [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-15 11:53:52 +00:00
jokob-sk
71856b49a4 🩹 Handle vendor NoneType #791
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-15 08:32:35 +10:00
github-actions[bot]
86c7d26107 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-14 11:53:34 +00:00
jokob-sk
d858f4f9d0 🔄Sync hub 2.0
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-14 10:37:30 +10:00
jokob-sk
aefe470d31 🔄Sync hub 2.0 2024-09-14 09:37:27 +10:00
github-actions[bot]
99fb60c1b5 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-13 11:53:38 +00:00
Hosted Weblate
ec37e4d71b Merge branch 'origin/main' into Weblate. 2024-09-13 11:09:18 +00:00
gallegonovato
e240821d6c Translated using Weblate (Spanish)
Currently translated at 100.0% (694 of 694 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-09-13 11:09:15 +00:00
github-actions[bot]
632e441dda [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-12 11:53:59 +00:00
jokob-sk
24f7935891 📚Docs
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-12 07:55:20 +10:00
github-actions[bot]
dcc43d1f3c [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-11 11:53:35 +00:00
github-actions[bot]
8f35bf36ff [🤖Automation] Update README with sponsors information
Some checks failed
docker / docker_dev (push) Has been cancelled
2024-09-10 11:53:40 +00:00
jokob-sk
1548168eba Lang
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-10 08:26:06 +10:00
github-actions[bot]
2e35bac6ec [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-09 11:53:47 +00:00
jokob-sk
ba348fc4c2 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-09 07:30:38 +10:00
jokob-sk
d3337e75a9 ⚙ Settings/Lang cache improvements #687 + #766 2024-09-09 07:30:33 +10:00
github-actions[bot]
9e0bc043b0 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-08 11:53:36 +00:00
jokob-sk
29fdd0b115 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-08 13:57:24 +10:00
jokob-sk
48e92a186e 🧪 Override Settings via ENV variable [experimental] #687 2024-09-08 13:57:08 +10:00
github-actions[bot]
1dcb66e972 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-07 11:53:42 +00:00
jokob-sk
fa0d6d312d Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-07 09:28:36 +10:00
jokob-sk
a19fe342e7 🚀 Better upgarde message 2024-09-07 09:28:19 +10:00
jokob-sk
c4fc68cac8 Merge pull request #759 from elraro/fix-mtscan
chore: fixed mtscan and Dockerfile
2024-09-07 09:08:49 +10:00
jokob-sk
3a050c31a7 Update feature_request.yml 2024-09-07 09:06:29 +10:00
jokob-sk
2cd406a390 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-09-07 08:38:10 +10:00
jokob-sk
b086417686 💾 Cache update for proper status color + All display #779 2024-09-07 08:38:03 +10:00
Hosted Weblate
dbecbfc85f Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-06 18:09:25 +02:00
Massimo Pissarello
3f9e4c4425 Translated using Weblate (Italian)
Currently translated at 100.0% (694 of 694 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-09-06 18:09:21 +02:00
Safeguard
4fd1869bde Translated using Weblate (Russian)
Currently translated at 100.0% (694 of 694 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-09-06 18:09:19 +02:00
github-actions[bot]
78025a376c [🤖Automation] Update README with sponsors information 2024-09-06 11:53:57 +00:00
elraro
615fd08f5b chore: changed mtscan type to device_scanner 2024-09-06 00:29:10 +02:00
elraro
4839211fe1 chore: fixed mtscan 2024-09-06 00:23:17 +02:00
jokob-sk
19aaa92fa3 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-06 07:59:38 +10:00
jokob-sk
43aa40efbb ⚙ Settings #779 2024-09-06 07:59:35 +10:00
github-actions[bot]
95f48cb70d [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-05 11:53:47 +00:00
jokob-sk
8c0da1d0df Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-05 08:09:39 +10:00
jokob-sk
b0d07a6adc ⚙ Settings #779 2024-09-05 08:09:23 +10:00
github-actions[bot]
ee23ae19f7 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-04 11:53:54 +00:00
jokob-sk
0c73e49245 Merge pull request #783 from doctorixx/main
Some checks are pending
docker / docker_dev (push) Waiting to run
Update plugins docs after add telegram publisher(and fix typo) - thanks @doctorixx !
2024-09-04 07:23:14 +10:00
github-actions[bot]
899a0c3608 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-03 11:53:53 +00:00
Doctorixx
d188b640e4 Fix ordering in tip (in plugins readme) 2024-09-03 13:47:09 +03:00
Doctorixx
a95eb45924 Update plugins list (add telegram publisher) 2024-09-03 13:45:26 +03:00
jokob-sk
f737a71939 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-03 07:51:27 +10:00
jokob-sk
9df97e0e33 📡 Upgrade -> Show message 2024-09-03 07:51:17 +10:00
github-actions[bot]
4ce7077599 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-02 11:53:50 +00:00
jokob-sk
605a33330b 📡 Upgrade -> Show message
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-02 15:53:15 +10:00
jokob-sk
9bd5ff10b4 📡 Upgrade -> Show message
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-02 09:15:49 +10:00
jokob-sk
45d3be2439 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-09-02 08:16:20 +10:00
jokob-sk
46209e3e47 Authelia #780 2024-09-02 08:16:15 +10:00
github-actions[bot]
9b9836cae2 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-01 11:53:40 +00:00
jokob-sk
89be97bfb2 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-01 08:27:35 +10:00
jokob-sk
3e4f64a7c6 Refactor maintenance.php 2024-09-01 08:27:17 +10:00
github-actions[bot]
50fbd6e616 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-31 11:53:55 +00:00
jokob-sk
5a96ad2304 Refactor devices.php
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-31 17:32:10 +10:00
jokob-sk
25667014fc Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-08-31 12:57:04 +10:00
jokob-sk
955472ef5c fix HRS_TO_KEEP_NEWDEV #777 2024-08-31 12:56:46 +10:00
github-actions[bot]
e32b60cafc [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-30 11:53:37 +00:00
jokob-sk
3033c617fa Merge pull request #775 from doctorixx/main
Some checks are pending
docker / docker_dev (push) Waiting to run
Add Telegram publisher by @doctorixx 🙏
2024-08-30 07:32:07 +10:00
Doctorixx
1688836b4f Add Telegram publisher 2024-08-29 16:41:59 +03:00
github-actions[bot]
f30b6b7fc1 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-29 11:53:43 +00:00
github-actions[bot]
0c5c754f38 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-28 11:53:54 +00:00
github-actions[bot]
da21ee6477 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-27 11:53:48 +00:00
github-actions[bot]
3a268add06 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-26 11:53:54 +00:00
github-actions[bot]
03b610a6ec [🤖Automation] Update README with sponsors information
Some checks failed
docker / docker_dev (push) Has been cancelled
2024-08-25 11:53:45 +00:00
github-actions[bot]
38f70fd045 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-24 11:53:46 +00:00
jokob-sk
3473fabdbf 📚 Docs + Readme
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-24 08:23:19 +10:00
jokob-sk
46186e5d3b Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-08-24 08:10:08 +10:00
jokob-sk
e0dd3ab53e 📚 Docs + Readme 2024-08-24 08:10:00 +10:00
github-actions[bot]
c385ac68f4 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-23 11:53:58 +00:00
github-actions[bot]
e1c446b0df [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-22 11:53:54 +00:00
jokob-sk
0413ac5fb4 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-22 20:02:31 +10:00
jokob-sk
01f8dc5f6b Small fixes 2024-08-22 20:02:18 +10:00
Hosted Weblate
00451a6846 Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-21 22:09:24 +02:00
Mehdi
b181e2ada6 Translated using Weblate (French)
Currently translated at 100.0% (691 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-08-21 22:09:22 +02:00
Sylvain Pichon
73a0a49934 Translated using Weblate (French)
Currently translated at 100.0% (691 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-08-21 22:09:21 +02:00
github-actions[bot]
b3ad58f5f3 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-21 11:54:00 +00:00
Hosted Weblate
03e0061b03 Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-20 21:09:31 +02:00
Sylvain Pichon
e5a63e9caa Translated using Weblate (French)
Currently translated at 99.4% (687 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-08-20 21:09:27 +02:00
github-actions[bot]
eb3a54ff1c [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-20 11:53:54 +00:00
Hosted Weblate
b3b8196b64 Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-19 18:35:04 +02:00
Sergey Karmanov
408d8cb7c5 Translated using Weblate (Russian)
Currently translated at 100.0% (691 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-08-19 18:35:02 +02:00
Sylvain Pichon
57d94634f1 Translated using Weblate (French)
Currently translated at 75.8% (524 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-08-19 18:35:01 +02:00
github-actions[bot]
3778dcb3ad [🤖Automation] Update README with sponsors information 2024-08-19 11:53:49 +00:00
github-actions[bot]
393a0d8168 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-18 11:53:32 +00:00
Hosted Weblate
c98c22c27d Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-18 07:09:15 +00:00
Sylvain Pichon
54ae8a7b35 Translated using Weblate (French)
Currently translated at 74.6% (516 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-08-18 07:09:12 +00:00
github-actions[bot]
a2cc2b441e [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-17 11:53:59 +00:00
jokob-sk
a3c0974e77 Merge pull request #764 from ingoratsdorf/main
Some checks are pending
docker / docker_dev (push) Waiting to run
Resolved issue with Paho V2 API
2024-08-17 12:07:29 +10:00
Ingo Ratsdorf
b7fa32f70a Resolved issue with Paho V2 API
Chnaged client creation logic to V2 API as we are already using Paho2.0. Chnaged version selection from Paho version (which should not have been a user choice) to MQTT Protocol selection, which can be v3 or v5. Most modern MQQTT brokers like Mosquitta or EMQX support v5.
2024-08-17 14:00:39 +12:00
Hosted Weblate
7fd8b039ed Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-16 23:09:21 +00:00
Sylvain Pichon
303cadc68c Translated using Weblate (French)
Currently translated at 69.3% (479 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-08-17 01:09:13 +02:00
gallegonovato
61ab586bd6 Translated using Weblate (Spanish)
Currently translated at 100.0% (691 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-08-17 01:09:11 +02:00
github-actions[bot]
0c64bd392b [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-16 11:53:36 +00:00
jokob-sk
fa0e07a511 Handle offlien GitHub #763
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-16 08:53:58 +10:00
jokob-sk
d699f6744e Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-08-16 08:50:02 +10:00
jokob-sk
84f0221615 Handle offlien GitHub #763 2024-08-16 08:49:44 +10:00
Hosted Weblate
2e34b1ff41 Merge branch 'origin/main' into Weblate. 2024-08-15 22:14:16 +00:00
Sylvain Pichon
8238eccb75 Translated using Weblate (French)
Currently translated at 63.5% (439 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-08-16 00:14:10 +02:00
jokob-sk
a6f86ee44a 🧹Logo Cleanup + cs_cz 2024-08-16 08:03:39 +10:00
jokob-sk
c9e92469a4 🧹Logo Cleanup + cs_cz 2024-08-16 08:01:39 +10:00
github-actions[bot]
87fb4a105a [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-15 11:53:54 +00:00
github-actions[bot]
6f2cf76bda [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-14 11:53:57 +00:00
github-actions[bot]
09531dc207 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-13 11:53:34 +00:00
Hosted Weblate
39d7642484 Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-13 07:09:30 +02:00
Ptsa Daniel
287facb798 Translated using Weblate (Chinese (Simplified))
Currently translated at 97.9% (677 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/zh_Hans/
2024-08-13 07:09:27 +02:00
jokob-sk
c3f91cae9e Merge pull request #761 from ingoratsdorf/main
Some checks are pending
docker / docker_dev (push) Waiting to run
Fix for MQTT device tracker adding quotes to payload - thanks so much @ingoratsdorf  🙏
2024-08-13 08:35:31 +10:00
Ingo Ratsdorf
ef9aeea2d2 Fix for MQTT device tracker adding quotes to payload 2024-08-13 07:41:12 +12:00
jokob-sk
597cd48318 Merge pull request #760 from ingoratsdorf/main
Some checks are pending
docker / docker_dev (push) Waiting to run
Fixed invalid escape sequence in MQTT publisher
2024-08-13 00:01:09 +10:00
github-actions[bot]
c78db01269 [🤖Automation] Update README with sponsors information 2024-08-12 11:53:52 +00:00
Ingo Ratsdorf
bee84cf8b2 Fixed invalid escape sequence
\s is invalid in Python3 and must be \\s now
2024-08-12 22:19:04 +12:00
elraro
ae1673c1c3 chore: fixed mtscan and Dockerfile 2024-08-11 23:55:02 +02:00
github-actions[bot]
7c080302e8 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-11 11:54:00 +00:00
jokob-sk
cec177a912 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-08-11 21:13:42 +10:00
jokob-sk
fff1f36b61 Cleanup work 2024-08-11 21:13:12 +10:00
Hosted Weblate
17d16b1bda Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-10 23:41:17 +00:00
Ptsa Daniel
8199e5e714 Translated using Weblate (Chinese (Simplified))
Currently translated at 8.2% (57 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/zh_Hans/
2024-08-11 01:41:13 +02:00
Ramon Martinez
5c0e9a8af8 Translated using Weblate (Portuguese (Brazil))
Currently translated at 35.4% (245 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/pt_BR/
2024-08-11 01:41:12 +02:00
Ettore Atalan
6438165b14 Translated using Weblate (German)
Currently translated at 94.6% (654 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/de/
2024-08-11 01:41:12 +02:00
jokob-sk
b3d1a43261 Merge pull request #758 from elraro/fix-mtscan
Some checks are pending
docker / docker_dev (push) Waiting to run
fix: mtscan plugin - thank you @elraro 🙏
2024-08-11 08:07:40 +10:00
github-actions[bot]
4ef7f507ed [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-10 11:53:49 +00:00
Hosted Weblate
0e830e92ed Merge branch 'origin/main' into Weblate. 2024-08-10 13:40:07 +02:00
Ramon Martinez
552e861887 Translated using Weblate (Portuguese (Brazil))
Currently translated at 34.4% (238 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/pt_BR/
2024-08-10 13:40:05 +02:00
elraro
c88afde5f8 fix: mtscan plugin
Change the MTSCAN plugin with the correct name
2024-08-10 12:48:25 +02:00
github-actions[bot]
b4f1e6a5da [🤖Automation] Update README with sponsors information
Some checks failed
docker / docker_dev (push) Has been cancelled
2024-08-09 11:53:43 +00:00
jokob-sk
edd66e4888 Merge pull request #756 from lookflying/mtscan
Some checks are pending
docker / docker_dev (push) Waiting to run
Add MTSCAN Plugin to get device info from  Mikrotik Leases
2024-08-09 08:13:24 +10:00
github-actions[bot]
cfa0b3c387 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-08 11:53:43 +00:00
lookflying
e848112452 merge main 2024-08-08 18:50:26 +08:00
lookflying
8199bef55d mtscan works 2024-08-08 10:45:14 +08:00
jokob-sk
8a385a90d4 🔌UNIFI work 2024-08-07 22:16:09 +08:00
github-actions[bot]
2d0b5d3bdd [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-07 11:53:41 +00:00
github-actions[bot]
49450e4d1f [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-06 11:53:57 +00:00
Hosted Weblate
d921d5760f Merge branch 'origin/main' into Weblate. 2024-08-06 11:09:20 +02:00
BILLY Maxime
2c05f3f663 Translated using Weblate (French)
Currently translated at 48.1% (333 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-08-06 11:09:17 +02:00
jokob-sk
3cde177e01 🔌UNIFI work
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-06 07:36:31 +10:00
jokob-sk
4f1dc1e0d7 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-05 21:55:35 +10:00
jokob-sk
c21497c61e 🔌UNIFI work 2024-08-05 21:55:11 +10:00
github-actions[bot]
75740670df [🤖Automation] Update README with sponsors information 2024-08-05 11:53:34 +00:00
Hosted Weblate
6a161c910b Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-05 10:09:29 +02:00
Alexandre Nascimento
857f3e64b7 Translated using Weblate (Portuguese (Brazil))
Currently translated at 24.8% (172 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/pt_BR/
2024-08-05 10:09:21 +02:00
jokob-sk
239ebd40b9 🔌UNIFI work
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-05 11:56:42 +10:00
jokob-sk
7203c335e4 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-08-05 09:58:22 +10:00
jokob-sk
45489eadaf 🔌UNIFI work 2024-08-05 09:58:18 +10:00
github-actions[bot]
dd99a5de1a [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-04 11:53:43 +00:00
github-actions[bot]
cae4c0b8c1 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-03 11:53:33 +00:00
jokob-sk
7dc0a38677 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-08-03 21:07:28 +10:00
jokob-sk
1f7a38593d 🔄Cache + Settings work 2024-08-03 21:07:12 +10:00
github-actions[bot]
e066a65f1b [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-02 11:53:39 +00:00
jokob-sk
4b2b8d6dd1 📥Bare-metal install work #753
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-02 08:01:08 +10:00
jokob-sk
e22b12e5d7 📥Bare-metal install work #753 2024-08-02 07:48:42 +10:00
jokob-sk
9cc994e157 📥Bare-metal install work #753 2024-08-02 07:47:12 +10:00
github-actions[bot]
2e45cf36f2 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-01 11:53:44 +00:00
github-actions[bot]
4d329d47f3 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-31 11:53:43 +00:00
jokob-sk
dd5e0726aa Merge pull request #752 from FlyingToto/main
Some checks are pending
docker / docker_dev (push) Waiting to run
got parallel execution to work! - @FlyingToto 🥳 thanks a lot 🙏
2024-07-31 08:40:26 +10:00
ffsb
d18cfb07ff enabled multiprocessing to parse siwtches and update names... 2024-07-30 18:00:36 -04:00
FlyingToto
efea2c970e Merge branch 'jokob-sk:main' into main 2024-07-30 07:59:23 -04:00
github-actions[bot]
7378517929 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-30 11:53:53 +00:00
github-actions[bot]
aeee584939 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-29 11:53:49 +00:00
Hosted Weblate
31e686ed4b Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-29 09:09:23 +02:00
GoldBull3t
01986a712b Translated using Weblate (Portuguese (Brazil))
Currently translated at 12.4% (86 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/pt_BR/
2024-07-29 09:09:21 +02:00
github-actions[bot]
8193f7f9e5 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-28 11:53:56 +00:00
github-actions[bot]
67e467d45a [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-27 11:53:56 +00:00
github-actions[bot]
1243cf896f [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-26 11:53:35 +00:00
Hosted Weblate
b6107f6cb9 Merge branch 'origin/main' into Weblate. 2024-07-26 11:09:17 +02:00
Safeguard
4ef1bb257d Translated using Weblate (Russian)
Currently translated at 99.8% (690 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-07-26 09:09:15 +00:00
github-actions[bot]
78db3c7089 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-25 11:53:36 +00:00
github-actions[bot]
68b691df09 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-24 11:53:59 +00:00
jokob-sk
ea6e8862f8 Merge pull request #746 from adebrouvier/main
Some checks are pending
docker / docker_dev (push) Waiting to run
Add MQTT TLS support by @adebrouvier 🙏
2024-07-24 08:24:16 +10:00
Ariel Debrouvier
a31469373f Add mqtts support 2024-07-23 11:25:11 -03:00
github-actions[bot]
8b1b86eeb7 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-23 11:53:47 +00:00
github-actions[bot]
d14944c2bd [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-22 11:53:39 +00:00
Hosted Weblate
b4c9c4d803 Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-21 15:09:20 +02:00
blomusti
cfae2ea8ee Translated using Weblate (Turkish)
Currently translated at 23.5% (163 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/tr/
2024-07-21 15:09:17 +02:00
ffsb
ab08e2ce85 testing arays vs elif performance 2024-07-21 09:00:38 -04:00
github-actions[bot]
f86b374ed3 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-21 11:53:32 +00:00
jokob-sk
a69f72fd3d Merge pull request #745 from FlyingToto/main
Some checks are pending
docker / docker_dev (push) Waiting to run
minor fix: able to handle an empty omada devices list
2024-07-21 12:36:43 +10:00
jokob-sk
df40b5caf9 🔀Guess types #738 2024-07-21 12:04:42 +10:00
jokob-sk
54b6b1d408 🎨Guess icons #738 2024-07-21 11:42:59 +10:00
FlyingToto
d79acc7bad Merge branch 'jokob-sk:main' into main 2024-07-20 13:36:10 -04:00
ffsb
57d8db771a Merge branch 'main' of https://github.com/FlyingToto/NetAlertX 2024-07-20 13:35:38 -04:00
ffsb
43759b6b7d na 2024-07-20 13:28:43 -04:00
ffsb
3305828947 1.1 handle failed omada devices calls. 2024-07-20 13:26:49 -04:00
github-actions[bot]
3e35f08d6c [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-20 11:53:39 +00:00
jokob-sk
1a9b9e3bf7 🔌TZ logging fix
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-20 11:54:08 +10:00
jokob-sk
3cb68c4dee Merge pull request #742 from FlyingToto/main
fixed mylog timezone issue
2024-07-20 11:30:52 +10:00
FlyingToto
c51d1ec00e Merge branch 'jokob-sk:main' into main 2024-07-19 17:50:51 -04:00
ffsb
7f83fe82b3 fixed timezone issue. 2024-07-19 17:48:32 -04:00
github-actions[bot]
1fe56a80bd [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-19 11:53:47 +00:00
Hosted Weblate
b4a4b78700 Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-19 12:09:22 +02:00
Massimo Pissarello
9b0d956fdb Translated using Weblate (Italian)
Currently translated at 100.0% (691 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-07-19 10:09:16 +00:00
gallegonovato
37700de434 Translated using Weblate (Spanish)
Currently translated at 100.0% (691 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-07-19 10:09:15 +00:00
github-actions[bot]
d6eb994bf1 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-18 11:53:45 +00:00
Hosted Weblate
4453ea59af Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-18 10:29:26 +02:00
Joe Erd
31ecd6ac8c Translated using Weblate (German)
Currently translated at 89.8% (621 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/de/
2024-07-18 10:29:24 +02:00
Anonymous
8e8493f638 Translated using Weblate (Polish)
Currently translated at 98.6% (682 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/pl/
2024-07-18 10:29:17 +02:00
Anonymous
adf24cebb6 Translated using Weblate (Italian)
Currently translated at 99.2% (686 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-07-18 10:29:17 +02:00
Anonymous
5ac609e68e Translated using Weblate (Russian)
Currently translated at 99.1% (685 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-07-18 10:29:17 +02:00
Joe Erd
7f0debb04a Translated using Weblate (Norwegian Bokmål)
Currently translated at 97.5% (674 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/nb_NO/
2024-07-18 10:29:17 +02:00
Anonymous
a51571bd70 Translated using Weblate (Spanish)
Currently translated at 99.2% (686 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-07-18 10:29:17 +02:00
Joe Erd
3af1f67956 Translated using Weblate (German)
Currently translated at 89.7% (620 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/de/
2024-07-18 10:29:17 +02:00
Joe Erd
9143b90bdf Translated using Weblate (English (United States))
Currently translated at 100.0% (691 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/en_US/
2024-07-18 10:29:16 +02:00
jokob-sk
a892b8b5fb 📚Docs 2024-07-18 18:10:36 +10:00
jokob-sk
db621a110e PasteCSV fix + code cleanup 2024-07-18 17:53:48 +10:00
jokob-sk
4a3598e840 Merge pull request #737 from FlyingToto/main 2024-07-18 17:25:41 +10:00
Hosted Weblate
a19e268ea7 Merge branch 'origin/main' into Weblate. 2024-07-18 06:09:15 +02:00
FlyingToto
e9319cace3 Translated using Weblate (French)
Currently translated at 47.6% (328 of 688 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-07-18 04:09:11 +00:00
ffsb
74b2432729 removed gitguardian secrets 2024-07-17 21:31:10 -04:00
ffsb
d65b07685f ready for pr 2024-07-17 18:28:21 -04:00
ffsb
a8dc4099e8 0.6 works but with port=null and ssid=null 2024-07-17 17:58:43 -04:00
github-actions[bot]
9c368982ce [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-17 11:53:41 +00:00
FlyingToto
662394618b Merge branch 'jokob-sk:main' into main 2024-07-16 17:57:44 -04:00
ffsb
147166e46e 0.4 saving api to files 2024-07-16 17:47:34 -04:00
github-actions[bot]
fb8a7432cd [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-16 11:53:35 +00:00
jokob-sk
fa00fa3004 Update i-have-an-issue.yml 2024-07-16 20:31:48 +10:00
jokob-sk
294cfe80f2 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-07-16 20:27:39 +10:00
jokob-sk
b45e82b2a0 NEWDEV_LESS_NAME_CLEANUP + Internet ParentNode fix + 📚Docs 2024-07-16 20:27:15 +10:00
ffsb
bf2ce3262d 0.2 added retries 2024-07-15 16:30:24 -04:00
github-actions[bot]
f468903b00 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-15 11:53:43 +00:00
ffsb
d706a156c0 after fixing order of execution 2024-07-14 09:46:14 -04:00
ffsb
71c631d784 after fixing the order of execution. 2024-07-14 09:45:25 -04:00
github-actions[bot]
460d2f4658 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-14 11:53:49 +00:00
jokob-sk
f502d93854 📩Import Pasted CSV + 📚Docs 2024-07-14 21:37:11 +10:00
jokob-sk
68fb1b7cbb 🔌Plugin execution order 2024-07-14 20:48:10 +10:00
jokob-sk
942908d074 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-14 11:04:31 +10:00
jokob-sk
1aeed6b433 More logging od CurrentScan/Device tables + cleanup 2024-07-14 10:54:48 +10:00
github-actions[bot]
698876065c [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-13 11:53:54 +00:00
jokob-sk
7e554242c2 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-12 21:59:52 +10:00
jokob-sk
129ae92141 Italian translation fix 2024-07-12 21:59:34 +10:00
github-actions[bot]
25647023d0 [🤖Automation] Update README with sponsors information 2024-07-12 11:53:33 +00:00
Hosted Weblate
fe752192e1 Merge branch 'origin/main' into Weblate. 2024-07-12 11:09:22 +02:00
Safeguard
0ea0cd5ee0 Translated using Weblate (Russian)
Currently translated at 99.8% (687 of 688 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-07-12 11:09:16 +02:00
gallegonovato
bac78e926d Translated using Weblate (Spanish)
Currently translated at 100.0% (688 of 688 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-07-12 11:09:15 +02:00
jokob-sk
d6125ef4e2 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-11 22:35:21 +10:00
jokob-sk
bf90ee81c7 Name cleanup + nbtscan improvements 2024-07-11 22:35:04 +10:00
github-actions[bot]
ae74f1f538 [🤖Automation] Update README with sponsors information 2024-07-11 11:53:44 +00:00
jokob-sk
3ae0daad3c 🌳Network tree improvements 2024-07-11 19:28:50 +10:00
jokob-sk
8e7e0afb1e 🔌NBTSCAN plugin #693
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-11 15:56:29 +10:00
jokob-sk
d7d7306a85 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-07-11 15:31:09 +10:00
jokob-sk
4b26044427 🔌NBTSCAN plugin #693 2024-07-11 15:30:18 +10:00
jokob-sk
0a9ae5e9d9 🔌NBTSCAN plugin #693 2024-07-11 15:27:37 +10:00
github-actions[bot]
ade1d9997f [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-10 11:53:47 +00:00
jokob-sk
578b992c5a ⚙ Settings + 🔧 Maintenance improvements 2024-07-10 17:59:51 +10:00
jokob-sk
52b293a662 🔷 regex fix
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-10 12:48:05 +10:00
jokob-sk
bd52536107 ⚙ transformers fix 2024-07-10 12:22:35 +10:00
jokob-sk
9f44c0de01 ⚙ NAME_CLEANUP_REGEX #735 #728 2024-07-10 11:27:21 +10:00
jokob-sk
41b5de9292 ⚙ NAME_CLEANUP_REGEX test
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-09 23:30:09 +10:00
jokob-sk
95d5dbcf68 🔌 MQTT - do not send UNKNOWN + expose DEVICES_SQL 2024-07-09 23:09:42 +10:00
jokob-sk
0eff7cc3f1 📚 Readme 2024-07-09 22:10:36 +10:00
jokob-sk
f31c55d6c4 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-07-09 21:55:30 +10:00
jokob-sk
6049ba00c7 ⚙ Settings rework 3 - json linter 2024-07-09 21:54:55 +10:00
github-actions[bot]
8e4bd246df [🤖Automation] Update README with sponsors information 2024-07-09 11:53:46 +00:00
jokob-sk
07164429d5 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-07-09 20:28:09 +10:00
jokob-sk
cac33fde2b ⚙ Settings rework 2 2024-07-09 20:27:48 +10:00
github-actions[bot]
5f71e9fc92 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-08 11:53:49 +00:00
jokob-sk
d834708220 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks failed
docker / docker_dev (push) Has been cancelled
2024-07-07 23:11:45 +10:00
jokob-sk
6ea3d14480 ⚙ Settings rework 2024-07-07 23:11:30 +10:00
github-actions[bot]
0a11ec5379 [🤖Automation] Update README with sponsors information 2024-07-07 11:54:02 +00:00
github-actions[bot]
b65c8022d6 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-06 11:53:46 +00:00
jokob-sk
55440090fe 🔌 Omada work #708
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-06 10:22:50 +10:00
jokob-sk
75bcf42225 🔌 Omada work #708 2024-07-06 10:02:33 +10:00
jokob-sk
6db9cd2f61 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-05 23:54:22 +10:00
jokob-sk
eff98257d6 🔌 Omada work #708 2024-07-05 23:53:55 +10:00
github-actions[bot]
2f97c8fd55 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-05 11:53:39 +00:00
jokob-sk
f03f3f33b1 🐛 PHOLUS, NSLOOKUP scans could not be disabled #726 2024-07-05 20:42:40 +10:00
jokob-sk
457059cae8 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-07-05 20:33:13 +10:00
jokob-sk
5afc82f33e 🐛 ARPSCAN & INTNT scans could not be disabled #726 2024-07-05 20:32:54 +10:00
github-actions[bot]
06e24b4585 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-04 11:53:45 +00:00
jokob-sk
482902f6e4 🔌 SNMP work #718
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-04 16:55:57 +10:00
jokob-sk
6e6b99fa46 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-04 12:21:55 +10:00
jokob-sk
30f4cba3e5 🔌 Omada work #708 2024-07-04 12:21:37 +10:00
github-actions[bot]
e9c0bf151f [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-03 11:53:51 +00:00
jokob-sk
70d117cb6d 📋Copy from device #721
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-03 09:07:33 +10:00
jokob-sk
624e30842a Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-07-03 08:26:38 +10:00
jokob-sk
7c22f209d1 getValueWithMac 2024-07-03 08:26:00 +10:00
github-actions[bot]
760a3c981f [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-02 11:53:40 +00:00
jokob-sk
b86ab576bd SNMP enhancements #718
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-02 19:39:33 +10:00
jokob-sk
1b6e806830 SNMP enhancements #718 2024-07-02 19:17:52 +10:00
github-actions[bot]
612ff7c293 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-01 11:53:57 +00:00
jokob-sk
74fc7ecdbf Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-07-01 21:08:02 +10:00
jokob-sk
b6451e6e76 ▶ Ad-hoc event bug fix 2024-07-01 21:07:51 +10:00
Hosted Weblate
55e7bed5a8 Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-07-01 12:10:48 +02:00
TheOrchestratorOfChaos
10b6c9836b Translated using Weblate (Polish)
Currently translated at 99.4% (684 of 688 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/pl/
2024-07-01 12:10:30 +02:00
Massimo Pissarello
158ff2453b Translated using Weblate (Italian)
Currently translated at 100.0% (688 of 688 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-07-01 12:10:30 +02:00
gallegonovato
6b92d9f862 Translated using Weblate (Spanish)
Currently translated at 99.7% (686 of 688 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-07-01 12:10:30 +02:00
github-actions[bot]
2fb6e8fb12 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-06-30 11:53:49 +00:00
jokob-sk
15d16dcd81 📚Docs 2024-06-30 21:37:14 +10:00
jokob-sk
28a5b6af2a 📚Docs 2024-06-30 21:24:31 +10:00
jokob-sk
651b346a27 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-06-30 21:18:27 +10:00
jokob-sk
df90060adf 💻 Plugin Boilerplate update 2024-06-30 21:17:52 +10:00
Hosted Weblate
d3228b2d55 Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-06-30 06:09:38 +02:00
Massimo Pissarello
83edfa66d2 Translated using Weblate (Italian)
Currently translated at 100.0% (685 of 685 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-06-30 06:09:36 +02:00
jokob-sk
40c5be3758 📚Docs + Omada work #708 2024-06-30 12:16:43 +10:00
jokob-sk
e2d0914334 📃More logging + updated default plugins to load
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-06-29 23:42:51 +10:00
jokob-sk
0b5cf66451 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-06-29 22:54:58 +10:00
jokob-sk
974427f392 📚Docs + Removing +TZ from dev_LastConnection 2024-06-29 22:54:34 +10:00
github-actions[bot]
9d0e6a5a5d [🤖Automation] Update README with sponsors information 2024-06-29 11:53:55 +00:00
jokob-sk
08b163ebe4 🛠Maintenance refactor
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-06-29 14:39:12 +10:00
jokob-sk
709408ca2a Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-06-29 10:28:23 +10:00
jokob-sk
eae93ef6b2 📚Docs + Omada work #708 2024-06-29 10:28:14 +10:00
github-actions[bot]
7d57370741 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-06-28 11:53:58 +00:00
Hosted Weblate
43b9b0c032 Merge branch 'origin/main' into Weblate. 2024-06-28 13:09:28 +02:00
Safeguard
01bf367d40 Translated using Weblate (Russian)
Currently translated at 99.8% (682 of 683 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-06-28 13:09:23 +02:00
github-actions[bot]
67f7822d1f [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-06-27 11:53:47 +00:00
jokob-sk
f64ebae3ee 📚Docs 2024-06-27 21:52:00 +10:00
jokob-sk
d1e7606cf5 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-06-27 21:09:05 +10:00
jokob-sk
90038f1365 📚Docs 2024-06-27 21:08:45 +10:00
github-actions[bot]
e29f8f29ce [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-06-26 11:53:44 +00:00
jokob-sk
63a922eb0a Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-06-26 11:47:02 +10:00
jokob-sk
f065b830e9 🔌OMADA work #708 2024-06-26 11:46:45 +10:00
github-actions[bot]
237e73ec8e [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-06-25 11:54:00 +00:00
jokob-sk
6e78788a36 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-06-25 09:50:46 +10:00
jokob-sk
a0fac32c14 🔌OMADA work #708 2024-06-25 09:50:31 +10:00
github-actions[bot]
1ee8fcc8c3 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-06-24 11:53:35 +00:00
github-actions[bot]
042cfa62f5 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-06-23 11:53:46 +00:00
jokob-sk
a030912f48 🆕 Sorting in the Network tables #713
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-06-23 10:45:15 +10:00
jokob-sk
01e97e152c Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-06-23 09:59:16 +10:00
jokob-sk
d7c12ee8d7 📚Docs, + cur_Type 2024-06-23 09:58:56 +10:00
github-actions[bot]
9c772c5c1b [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-06-22 11:53:56 +00:00
github-actions[bot]
7cb45351ed [🤖Automation] Update README with sponsors information 2024-06-21 11:53:51 +00:00
jokob-sk
dce2443d73 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-06-21 16:44:34 +10:00
jokob-sk
a52e315732 📚Docs, QoL improvements 2024-06-21 16:44:03 +10:00
Hosted Weblate
443128db74 Merge branch 'origin/main' into Weblate. 2024-06-20 14:09:38 +00:00
Gooseman
9c92252296 Translated using Weblate (French)
Currently translated at 45.8% (313 of 683 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-06-20 16:09:19 +02:00
github-actions[bot]
036ca4d1cb [🤖Automation] Update README with sponsors information 2024-06-20 11:53:36 +00:00
github-actions[bot]
431fe4cd8d [🤖Automation] Update README with sponsors information 2024-06-19 11:53:44 +00:00
Hosted Weblate
34427689aa Merge branch 'origin/main' into Weblate. 2024-06-19 05:09:18 +02:00
Massimo Pissarello
08f3039f91 Translated using Weblate (Italian)
Currently translated at 100.0% (683 of 683 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-06-19 05:09:16 +02:00
github-actions[bot]
5514cf0f74 [🤖Automation] Update README with sponsors information 2024-06-18 11:53:45 +00:00
github-actions[bot]
607dcf54c6 [🤖Automation] Update README with sponsors information 2024-06-17 11:53:48 +00:00
Hosted Weblate
f3b0795e81 Merge branch 'origin/main' into Weblate. 2024-06-16 20:10:14 +00:00
Massimo Pissarello
11e9e1991d Translated using Weblate (Italian)
Currently translated at 100.0% (682 of 682 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-06-16 22:10:04 +02:00
github-actions[bot]
33fad4403f [🤖Automation] Update README with sponsors information 2024-06-16 11:53:37 +00:00
jokob-sk
3b7cbba32b 🎨 Device tiles setting 2024-06-16 12:23:14 +10:00
jokob-sk
5302673a96 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-06-16 09:11:38 +10:00
jokob-sk
8c4bcbca41 📚 UI not visible docs 2024-06-16 09:11:21 +10:00
Hosted Weblate
299f34709d Merge branch 'origin/main' into Weblate. 2024-06-15 17:09:20 +02:00
Massimo Pissarello
d8e00e7727 Translated using Weblate (Italian)
Currently translated at 100.0% (678 of 678 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-06-15 15:09:18 +00:00
gallegonovato
7cadc57db9 Translated using Weblate (Spanish)
Currently translated at 100.0% (678 of 678 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-06-15 15:09:17 +00:00
github-actions[bot]
fa99ae061a [🤖Automation] Update README with sponsors information 2024-06-15 11:53:45 +00:00
jokob-sk
177a66ac60 🌐 File encoding fix 2024-06-15 16:32:09 +10:00
jokob-sk
1cc471d56c 🚦COlors and icons for device status label #706 + DeviceDetails fields 2024-06-15 16:26:33 +10:00
jokob-sk
76183e504a Weblate 2024-06-15 10:59:04 +10:00
jokob-sk
3a1a6c8dac 📃 Plugin __template + OMADA SDN v0.1 #708 2024-06-15 10:54:55 +10:00
github-actions[bot]
8c8c2cba34 [🤖Automation] Update README with sponsors information 2024-06-14 11:53:46 +00:00
Hosted Weblate
dc5a9ff6d0 Merge branch 'origin/main' into Weblate. 2024-06-14 09:09:34 +02:00
Szymon Niewczas
bfdbfa5492 Translated using Weblate (Polish)
Currently translated at 100.0% (678 of 678 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/pl/
2024-06-14 09:09:32 +02:00
Massimo Pissarello
610cde92f9 Translated using Weblate (Italian)
Currently translated at 100.0% (678 of 678 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-06-14 09:09:31 +02:00
Safeguard
fdf814ded8 Translated using Weblate (Russian)
Currently translated at 99.8% (677 of 678 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-06-14 09:09:20 +02:00
github-actions[bot]
eb552ee912 [🤖Automation] Update README with sponsors information 2024-06-13 11:53:45 +00:00
Hosted Weblate
003692d51d Merge branch 'origin/main' into Weblate. 2024-06-13 06:24:03 +00:00
Szymon Niewczas
850824c41d Translated using Weblate (Polish)
Currently translated at 55.7% (378 of 678 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/pl/
2024-06-13 06:24:02 +00:00
Anonymous
877654944c Translated using Weblate (Chinese (Simplified))
Currently translated at 8.1% (55 of 678 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/zh_Hans/
2024-06-13 08:23:58 +02:00
Anonymous
8aeb2de064 Translated using Weblate (Polish)
Currently translated at 55.6% (377 of 678 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/pl/
2024-06-13 08:23:58 +02:00
Anonymous
fa8e5d92d7 Translated using Weblate (Italian)
Currently translated at 99.7% (676 of 678 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-06-13 08:23:58 +02:00
Anonymous
926c1180b6 Translated using Weblate (Russian)
Currently translated at 98.2% (666 of 678 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-06-13 08:23:58 +02:00
Anonymous
946a483455 Translated using Weblate (Norwegian Bokmål)
Currently translated at 99.7% (676 of 678 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/nb_NO/
2024-06-13 08:23:58 +02:00
Anonymous
bd3fa5c0fa Translated using Weblate (French)
Currently translated at 44.2% (300 of 678 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-06-13 08:23:58 +02:00
Anonymous
9b0cef2cc2 Translated using Weblate (Spanish)
Currently translated at 99.7% (676 of 678 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-06-13 08:23:58 +02:00
Anonymous
855fdb94f0 Translated using Weblate (German)
Currently translated at 91.7% (622 of 678 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/de/
2024-06-13 08:23:58 +02:00
jokob-sk
1b5a15ebb7 🆕MQTT device_tracker state fix attempt 2024-06-13 07:54:32 +10:00
Hosted Weblate
151667bb52 Merge branch 'origin/main' into Weblate. 2024-06-12 21:09:22 +02:00
Massimo Pissarello
3c81dd171b Translated using Weblate (Italian)
Currently translated at 100.0% (678 of 678 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-06-12 21:09:14 +02:00
github-actions[bot]
50a175bd56 [🤖Automation] Update README with sponsors information 2024-06-12 11:53:35 +00:00
jokob-sk
ff288c58e3 🆕MQTT self.mac error #703 + dos/css fixes 2024-06-12 21:34:00 +10:00
jokob-sk
307e81918e 🆕MQTT add device_tracker attributes #703 2024-06-12 19:41:13 +10:00
jokob-sk
2ca5f5d80e MQTT removed debug condition 2024-06-12 18:42:28 +10:00
jokob-sk
a6f0a364d4 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-06-12 18:35:33 +10:00
jokob-sk
d94297e093 🎨Nicer logo, 📚Notification & debug docs, 📦MQTT device_tracker feature request #702 2024-06-12 18:35:14 +10:00
github-actions[bot]
223a6556b9 [🤖Automation] Update README with sponsors information 2024-06-11 11:53:54 +00:00
github-actions[bot]
ead63a81e0 [🤖Automation] Update README with sponsors information 2024-06-10 11:53:41 +00:00
Hosted Weblate
f60962e341 Merge branch 'origin/main' into Weblate. 2024-06-10 12:09:19 +02:00
Marcus Isdahl
de2ee396c8 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (678 of 678 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/nb_NO/
2024-06-10 10:09:16 +00:00
jokob-sk
2e3626a8b3 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-06-10 09:14:39 +10:00
jokob-sk
2faa0ff9b7 🐛 Regex warnings #700 2024-06-10 09:14:24 +10:00
github-actions[bot]
4ada56d0d9 [🤖Automation] Update README with sponsors information 2024-06-09 11:53:40 +00:00
Hosted Weblate
00d33ee3e2 Merge branch 'origin/main' into Weblate. 2024-06-09 08:42:38 +02:00
gallegonovato
ead57614b6 Translated using Weblate (Spanish)
Currently translated at 100.0% (678 of 678 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-06-09 08:42:37 +02:00
Anonymous
eac915acc8 Translated using Weblate (Italian)
Currently translated at 99.5% (675 of 678 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-06-09 08:42:32 +02:00
Anonymous
697b60731a Translated using Weblate (Russian)
Currently translated at 98.5% (668 of 678 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-06-09 08:42:32 +02:00
Anonymous
54612059d7 Translated using Weblate (German)
Currently translated at 92.0% (624 of 678 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/de/
2024-06-09 08:42:32 +02:00
jokob-sk
63ca3019e1 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-06-09 13:15:54 +10:00
jokob-sk
bcddf6d0c5 🔃Settings cache refresh #698 + 📚Plugins docs 2024-06-09 13:15:38 +10:00
Hosted Weblate
1cec63601b Merge branch 'origin/main' into Weblate. 2024-06-09 00:10:24 +00:00
Marcus Isdahl
f8be8e2a1f Translated using Weblate (Norwegian Bokmål)
Currently translated at 55.4% (376 of 678 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/nb_NO/
2024-06-09 02:09:25 +02:00
gallegonovato
661414de28 Translated using Weblate (Spanish)
Currently translated at 100.0% (678 of 678 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-06-09 02:09:16 +02:00
jokob-sk
4a33eb71c6 🔃Chache refresh on settings page 2024-06-09 09:20:55 +10:00
246 changed files with 21003 additions and 8494 deletions

View File

@@ -9,20 +9,6 @@ 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
@@ -50,3 +36,17 @@ body:
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations:
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"

View File

@@ -1,5 +1,5 @@
name: Bug Report
description: 'When submitting an issue enable debug and have a look at the docs.'
description: 'When submitting an issue enable LOG_LEVEL="trace" and have a look at the docs.'
labels: ['bug 🐛']
body:
- type: checkboxes
@@ -64,7 +64,7 @@ body:
***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 /app/front/log/app.log` in the 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 trouble getting to the log files.
validations:
required: false
- type: checkboxes

View File

@@ -48,7 +48,6 @@ jobs:
with:
# 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: |

11
.gitignore vendored
View File

@@ -19,4 +19,13 @@ __pycache__/
**/last_result.log
**/script.log
**/pialert.conf_bak
**/pialert.db_bak
**/pialert.db_bak
.*.swp
front/img/account/*
**/account.php
**/account.js
front/css/account.css
docker-compose.yml.ffsb42
.env.omada.ffsb42

View File

@@ -1,8 +1,8 @@
FROM alpine:3.20 as builder
FROM alpine:3.20 AS builder
ARG INSTALL_DIR=/app
ENV PYTHONUNBUFFERED 1
ENV PYTHONUNBUFFERED=1
# Install build dependencies
RUN apk add --no-cache bash python3 python3-dev gcc musl-dev libffi-dev openssl-dev \
@@ -15,13 +15,13 @@ ENV PATH="/opt/venv/bin:$PATH"
COPY . ${INSTALL_DIR}/
RUN pip install pycryptodome requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap dnspython \
RUN pip install netifaces tplink-omada-client pycryptodome requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap dnspython librouteros \
&& 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 'speedtest-cli' \) -exec chmod 750 {} \;"
# second stage
FROM alpine:3.20 as runner
FROM alpine:3.20 AS runner
ARG INSTALL_DIR=/app
@@ -40,15 +40,20 @@ ENV S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0
RUN apk update --no-cache \
&& 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 curl arp-scan iproute2 iproute2-ss nmap nmap-scripts traceroute nbtscan avahi avahi-tools openrc dbus 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 \
&& apk add --no-cache dcron \
&& ln -s /usr/bin/awake /usr/bin/wakeonlan \
&& 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}/ ${INSTALL_DIR}/
# Add crontab file
COPY install/crontab /etc/crontabs/root
# Start all required services
RUN ${INSTALL_DIR}/dockerfiles/pre-setup.sh
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=2 \

View File

@@ -1,7 +1,7 @@
FROM debian:bookworm-slim
# default UID and GID
ENV USER=pi USER_ID=1000 USER_GID=1000 PORT=20211
ENV USER=pi USER_ID=1000 USER_GID=1000 PORT=20211
#TZ=Europe/London
# Todo, figure out why using a workdir instead of full paths don't work
@@ -33,7 +33,7 @@ COPY --chmod=775 --chown=${USER_ID}:${USER_GID} . ${INSTALL_DIR}/
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 php-openssl \
python3 python3-dev iproute2 nmap python3-pip zip systemctl usbutils traceroute
python3 python3-dev iproute2 nmap python3-pip zip systemctl usbutils traceroute nbtscan avahi avahi-tools openrc dbus
# Alternate dependencies
RUN apt-get install nginx nginx-core mtr php-fpm php8.2-fpm php-cli php8.2 php8.2-sqlite3 -y
@@ -43,7 +43,7 @@ RUN phpenmod -v 8.2 sqlite3
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 pycryptodome requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap dnspython cryptography "
RUN /bin/bash -c "source myenv/bin/activate && update-alternatives --install /usr/bin/python python /usr/bin/python3 10 && pip3 install tplink-omada-client pycryptodome requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap dnspython librouteros "
# Create a buildtimestamp.txt to later check if a new version was released
RUN date +%s > ${INSTALL_DIR}/front/buildtimestamp.txt

View File

@@ -1,43 +1,49 @@
# 💻🔍 Network security scanner & notification framework
[![GitHub Committed](https://img.shields.io/github/last-commit/jokob-sk/NetAlertX?color=40ba12&label=Pushed&logo=GitHub&logoColor=fff&style=for-the-badge)](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&style=for-the-badge)](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&style=for-the-badge)](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&style=for-the-badge)](https://github.com/jokob-sk/NetAlertX/releases)
[![Discord](https://img.shields.io/discord/1274490466481602755?color=0aa8d2&logoColor=fff&logo=Discord&style=for-the-badge)](https://discord.gg/UQnnHNYV)
# 🖧🔍 Network 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/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/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/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) |
|----------------------|----------------------| ----------------------| ----------------------|
| ![Main screen][main] | ![Screen 1][screen1] | ![Screen 5][screen5] |
| ![Main screen][main] | ![device_details 1][device_details] | ![Screen network][network] |
|----------------------|----------------------| ----------------------|
![network_setup][network_setup]
Head to [https://netalertx.com/](https://netalertx.com/) for more gifs and screenshots 📷.
<details>
<summary>📷 Click for more screenshots</summary>
| ![Screen 3][screen3] | ![Screen 4][screen4] | ![Screen 6][screen6] |
| ![presence][presence] | ![maintenance][maintenance] | ![settings][settings] |
|----------------------|----------------------|----------------------|
| ![Screen 8][screen8] | ![Report 2][report2] | ![Screen 9][screen9] |
| ![sync_hub][sync_hub] | ![report1][report1] | ![device_nmap][device_nmap] |
</details>
<details>
<summary>❓ Why use Net <b>Alert</b><sup>x</sup>?</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.
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 🔐_.
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 🔐_.
Net <b>Alert</b><sup>x</sup> 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/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/NetAlertX/tree/main/front/plugins#readme) and handle the results and notifications in Net <b>Alert</b><sup>x</sup>.
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 ❤.
@@ -56,10 +62,12 @@ Get visibility of what's going on on your WIFI/LAN network. Schedule scans for d
## Installation & Documentation
<!--- --------------------------------------------------------------------- --->
Supported browsers: Chrome, Firefox
| Docs | Link |
|-------------|-------------|
| 📥🐳 | [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) |
| 📥🗄️ | [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) |
@@ -87,17 +95,20 @@ Thank you to all the wonderful people who are sponsoring this project.
<!-- SPONSORS-LIST DO NOT MODIFY BELOW -->
| All Sponsors |
|---|
| [joel72265](https://github.com/joel72265) |
<!-- 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) |
| --- | --- | --- |
<details>
<summary>Click for more ways to donate</summary>
<hr>
| [![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) |
| --- | --- | --- |
- Bitcoin: `1N8tupjeCK12qRVU2XrV17WvKK7LCawyZM`
- Ethereum: `0x6e2749Cb42F4411bc98501406BdcD82244e3f9C7`
@@ -131,19 +142,21 @@ 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"
[follow_star]: /docs/img/Follow_Releases_and_Star.gif "Follow and Star"
[main]: ./docs/img/devices_split.png "Main screen"
[device_details]: ./docs/img/device_details.png "Screen 1"
[events]: ./docs/img/events.png "Screen 2"
[presence]: ./docs/img/presence.png "Screen 3"
[maintenance]: ./docs/img/maintenance.png "Screen 4"
[network]: ./docs/img/network.png "Screen 5"
[settings]: ./docs/img/settings.png "Screen 6"
[network_setup]: ./docs/img/network_setup.gif "Screen 6"
[help_faq]: ./docs/img/help_faq.png "Screen 7"
[sync_hub]: ./docs/img/sync_hub.png "Screen 8"
[notification_center]: ./docs/img/notification_center.png "Screen 8"
[sent_reports_text]: ./docs/img/sent_reports_text.png "Screen 8"
[device_nmap]: ./docs/img/device_nmap.png "Screen 9"
[report1]: ./docs/img/report_sample.png "Report sample 1"
[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,13 +3,12 @@
# Generated: 2022-12-30_22-19-40 #
# #
# Config file for the LAN intruder detection app: #
# https://github.com/jokob-sk/NetAlertX #
# https://github.com/jokob-sk/NetAlertX #
# #
#-----------------AUTOGENERATED FILE-----------------#
# 🔺 Use the Settings UI - only edit when necessary 🔺
# General
#---------------------------
# Scan using interface eth0
@@ -18,16 +17,23 @@
# Scan multiple interfaces (eth1 and eth0):
# SCAN_SUBNETS = [ '192.168.1.0/24 --interface=eth1', '192.168.1.0/24 --interface=eth0' ]
SCAN_SUBNETS=['192.168.1.0/24 --interface=eth1']
SCAN_SUBNETS=['192.168.1.0/24 --interface=eth0']
TIMEZONE='Europe/Berlin'
LOADED_PLUGINS = ['ARPSCAN','CSVBCKP','DBCLNP', 'INTRNT','MAINT','NEWDEV','NSLOOKUP','NTFPRCS', 'AVAHISCAN', 'SETPWD','SMTP', 'SYNC', 'VNDRPDT', 'WORKFLOWS']
DAYS_TO_KEEP_EVENTS=90
# Used for generating links in emails. Make sure not to add a trailing slash!
REPORT_DASHBOARD_URL='http://netalertx'
# Make sure at least these scanners are enabled for new installs, other defaults are taken from the config.json
INTRNT_RUN='schedule'
ARPSCAN_RUN='schedule'
NSLOOKUP_RUN='before_name_updates'
# Email
#---------------------------
# Email
#-------------------------------------
# (add SMTP to LOADED_PLUGINS to load)
#-------------------------------------
SMTP_RUN='disabled' # use 'on_notification' to enable
SMTP_SERVER='smtp.gmail.com'
SMTP_PORT=587
@@ -39,8 +45,10 @@ SMTP_PASS='password'
SMTP_SKIP_TLS=False
# Webhooks
#---------------------------
# Webhook
#-------------------------------------
# (add WEBHOOK to LOADED_PLUGINS to load)
#-------------------------------------
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
@@ -50,15 +58,19 @@ WEBHOOK_PAYLOAD='json' # webhook payload data format for the "bo
WEBHOOK_REQUEST_METHOD='GET'
# Apprise
#---------------------------
# Apprise
#-------------------------------------
# (add APPRISE to LOADED_PLUGINS to load)
#-------------------------------------
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
#---------------------------
#-------------------------------------
# (add NTFY to LOADED_PLUGINS to load)
#-------------------------------------
NTFY_RUN='disabled' # use 'on_notification' to enable
NTFY_HOST='https://ntfy.sh'
NTFY_TOPIC='replace_my_secure_topicname_91h889f28'
@@ -66,14 +78,18 @@ NTFY_USER='user'
NTFY_PASSWORD='passw0rd'
# PUSHSAFER
#---------------------------
# PUSHSAFER
#-------------------------------------
# (add PUSHSAFER to LOADED_PLUGINS to load)
#-------------------------------------
PUSHSAFER_RUN='disabled' # use 'on_notification' to enable
PUSHSAFER_TOKEN='ApiKey'
# MQTT
#---------------------------
# MQTT
#-------------------------------------
# (add MQTT to LOADED_PLUGINS to load)
#-------------------------------------
MQTT_RUN='disabled' # use 'on_notification' to enable
MQTT_BROKER='192.168.1.2'
MQTT_PORT=1883

13
back/cron_script.sh Executable file
View File

@@ -0,0 +1,13 @@
#!/bin/bash
export INSTALL_DIR=/app
LOG_FILE="${INSTALL_DIR}/front/log/execution_queue.log"
# Check if there are any entries with cron_restart_backend
if grep -q "cron_restart_backend" "$LOG_FILE"; then
# Kill all python processes and restart the server
pkill -f "python " && (python ${INSTALL_DIR}/server > /dev/null 2>&1 &) && echo 'done'
# Remove all lines containing cron_restart_backend from the log file
sed -i '/cron_restart_backend/d' "$LOG_FILE"
fi

View File

@@ -54,6 +54,7 @@ services:
- ${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/account.php:/app/front/account.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
@@ -63,7 +64,9 @@ services:
# DELETE END anyone trying to use this file: comment out / delete ABOVE lines, they are only for development purposes
# ---------------------------------------------------------------------------
environment:
# - APP_CONF_OVERRIDE={"SCAN_SUBNETS":"['192.168.1.0/24 --interface=eth1']","UI_dark_mode":"True"}
- TZ=${TZ}
- PORT=${PORT}
- PORT=${PORT}
# ❗ 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,10 +1,11 @@
[![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)
[![GitHub Committed](https://img.shields.io/github/last-commit/jokob-sk/NetAlertX?color=40ba12&label=Committed&logo=GitHub&logoColor=fff&style=for-the-badge)](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&style=for-the-badge)](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&style=for-the-badge)](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&style=for-the-badge)](https://github.com/jokob-sk/NetAlertX/releases)
[![Discord](https://img.shields.io/discord/1274490466481602755?color=0aa8d2&logoColor=fff&logo=Discord&style=for-the-badge)](https://discord.gg/UQnnHNYV)
# NetAlertX 💻🔍 Network security scanner & notification framework
# NetAlertX 🖧🔍 Network scanner & notification framework
| 🐳 [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) |
|----------------------|----------------------| ----------------------| ----------------------|
@@ -13,6 +14,8 @@
<img src="https://raw.githubusercontent.com/jokob-sk/NetAlertX/main/docs/img/GENERAL/github_social_image.jpg" width="1000px" />
</a>
Head to [https://netalertx.com/](https://netalertx.com/) for more gifs and screenshots 📷.
> [!NOTE]
> There is also an experimental 🧪 [bare-metal install](https://github.com/jokob-sk/NetAlertX/blob/main/docs/HW_INSTALL.md) method available.
@@ -38,7 +41,8 @@ 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` |
|`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` |
|`APP_CONF_OVERRIDE` | JSON override for settings, e.g. `{"SCAN_SUBNETS":"['192.168.1.0/24 --interface=eth1']","UI_dark_mode":"True"}` (Experimental 🧪) | `N/A` |
|`ALWAYS_FRESH_INSTALL` | If `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`/`netalertx-dev` image. | `N/A` |
### Docker paths
@@ -81,16 +85,18 @@ These are the most important settings to get at least some output in your Device
#### 🧭 Community guides
Use the official installation guides at first and use community content as suplementary material. Open an issue if you'd like to add your link to the list 🙏
Use the official installation guides at first and use community content as supplementary material. Open an issue if you'd like to add your link to the list 🙏
- 📄 [How to Install Pi.Alert on Your Synology NAS - Marius hosting (English)](https://mariushosting.com/how-to-install-pi-alert-on-your-synology-nas/) (Updated frequently)
- 📄 [Using the PiAlert Network Security Scanner on a Raspberry Pi - PiMyLifeUp (English)](https://pimylifeup.com/raspberry-pi-pialert/)
- [How to Setup Pi.Alert on Your Synology NAS - Digital Aloha (English)](https://www.youtube.com/watch?v=M4YhpuRFaUg)
- 📄 [시놀/헤놀에서 네트워크 스캐너 Pi.Alert Docker로 설치 및 사용하기 (Korean)](https://blog.dalso.org/article/%EC%8B%9C%EB%86%80-%ED%97%A4%EB%86%80%EC%97%90%EC%84%9C-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%8A%A4%EC%BA%90%EB%84%88-pi-alert-docker%EB%A1%9C-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%82%AC%EC%9A%A9) (July 2023)
- [Home Lab Network Monitoring - Scotti-BYTE Enterprise Consulting Services](https://www.youtube.com/watch?v=0DryhzrQSJA) (July 2024)
- 📄 [How to Install NetAlertX on Your Synology NAS - Marius hosting](https://mariushosting.com/how-to-install-pi-alert-on-your-synology-nas/) (Updated frequently)
- 📄 [Using the PiAlert Network Security Scanner on a Raspberry Pi - PiMyLifeUp](https://pimylifeup.com/raspberry-pi-pialert/)
- [How to Setup Pi.Alert on Your Synology NAS - Digital Aloha](https://www.youtube.com/watch?v=M4YhpuRFaUg)
- 📄 [防蹭网神器,网络安全助手 | 极空间部署网络扫描和通知系统『NetAlertX』](https://blog.csdn.net/qq_63499861/article/details/141105273)
- 📄 [시놀/헤놀에서 네트워크 스캐너 Pi.Alert Docker로 설치 및 사용하기](https://blog.dalso.org/article/%EC%8B%9C%EB%86%80-%ED%97%A4%EB%86%80%EC%97%90%EC%84%9C-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%8A%A4%EC%BA%90%EB%84%88-pi-alert-docker%EB%A1%9C-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%82%AC%EC%9A%A9) (July 2023)
- 📄 [网络入侵探测器Pi.Alert (Chinese)](https://codeantenna.com/a/VgUvIAjZ7J) (May 2023)
- ▶ [Pi.Alert auf Synology & Docker by - Jürgen Barth (German)](https://www.youtube.com/watch?v=-ouvA2UNu-A) (March 2023)
- ▶ [Top Docker Container for Home Server Security - VirtualizationHowto (English)](https://www.youtube.com/watch?v=tY-w-enLF6Q) (March 2023)
- ▶ [Pi.Alert or WatchYourLAN can alert you to unknown devices appearing on your WiFi or LAN network - Danie van der Merwe (English)](https://www.youtube.com/watch?v=v6an9QG2xF0) (November 2022)
- ▶ [Pi.Alert auf Synology & Docker by - Jürgen Barth](https://www.youtube.com/watch?v=-ouvA2UNu-A) (March 2023)
- ▶ [Top Docker Container for Home Server Security - VirtualizationHowto](https://www.youtube.com/watch?v=tY-w-enLF6Q) (March 2023)
- ▶ [Pi.Alert or WatchYourLAN can alert you to unknown devices appearing on your WiFi or LAN network - Danie van der Merwe](https://www.youtube.com/watch?v=v6an9QG2xF0) (November 2022)
> Ordered by last update time.

View File

@@ -38,4 +38,6 @@ touch /etc/s6-overlay/s6-rc.d/user/contents.d/{SetupOneshot,php-fpm,nginx,$APP_N
touch /etc/s6-overlay/s6-rc.d/nginx/dependencies.d/php-fpm
touch /etc/s6-overlay/s6-rc.d/$APP_NAME/dependencies.d/nginx
rm -f $0

View File

@@ -41,6 +41,16 @@ if [ "$ALWAYS_FRESH_INSTALL" = true ]; then
rm -rf "$INSTALL_DIR_OLD/db/"*
fi
# OVERRIDE settings: Handling APP_CONF_OVERRIDE
# Check if APP_CONF_OVERRIDE is set
if [ -z "$APP_CONF_OVERRIDE" ]; then
echo "APP_CONF_OVERRIDE is not set. Skipping config file creation."
else
# Save the APP_CONF_OVERRIDE env variable as a JSON file
echo "$APP_CONF_OVERRIDE" > "${INSTALL_DIR}/config/app_conf_override.json"
echo "Config file saved to ${INSTALL_DIR}/config/app_conf_override.json"
fi
# 🔻 FOR BACKWARD COMPATIBILITY - REMOVE AFTER 12/12/2024
# Check if pialert.db exists, then create a symbolic link to app.db
@@ -109,6 +119,10 @@ if [ ! -f "${INSTALL_DIR}/front/buildtimestamp.txt" ]; then
chown nginx:www-data "${INSTALL_DIR}/front/buildtimestamp.txt"
fi
# Start crond service in the background
echo "[INSTALL] Starting crond service..."
crond -f -d 8 > /dev/null 2>&1 &
echo -e "
[ENV] PATH is ${PATH}
[ENV] PORT is ${PORT}

275
docs/AUTHELIA.md Executable file
View File

@@ -0,0 +1,275 @@
(DRAFT) Authelia support
```yaml
theme: dark
default_2fa_method: "totp"
server:
address: 0.0.0.0:9091
endpoints:
enable_expvars: false
enable_pprof: false
authz:
forward-auth:
implementation: 'ForwardAuth'
authn_strategies:
- name: 'HeaderAuthorization'
schemes:
- 'Basic'
- name: 'CookieSession'
ext-authz:
implementation: 'ExtAuthz'
authn_strategies:
- name: 'HeaderAuthorization'
schemes:
- 'Basic'
- name: 'CookieSession'
auth-request:
implementation: 'AuthRequest'
authn_strategies:
- name: 'HeaderAuthRequestProxyAuthorization'
schemes:
- 'Basic'
- name: 'CookieSession'
legacy:
implementation: 'Legacy'
authn_strategies:
- name: 'HeaderLegacy'
- name: 'CookieSession'
disable_healthcheck: false
tls:
key: ""
certificate: ""
client_certificates: []
headers:
csp_template: ""
log:
## Level of verbosity for logs: info, debug, trace.
level: info
###############################################################
# The most important section
###############################################################
access_control:
## Default policy can either be 'bypass', 'one_factor', 'two_factor' or 'deny'.
default_policy: deny
networks:
- name: internal
networks:
- '192.168.0.0/18'
- '10.10.10.0/8' # Zerotier
- name: private
networks:
- '172.16.0.0/12'
rules:
- networks:
- private
domain:
- '*'
policy: bypass
- networks:
- internal
domain:
- '*'
policy: bypass
- domain:
# exclude itself from auth, should not happen as we use Traefik middleware on a case-by-case screnario
- 'auth.MYDOMAIN1.TLD'
- 'authelia.MYDOMAIN1.TLD'
- 'auth.MYDOMAIN2.TLD'
- 'authelia.MYDOMAIN2.TLD'
policy: bypass
- domain:
#All subdomains match
- 'MYDOMAIN1.TLD'
- '*.MYDOMAIN1.TLD'
policy: two_factor
- domain:
# This will not work yet as Authelio does not support multi-domain authentication
- 'MYDOMAIN2.TLD'
- '*.MYDOMAIN2.TLD'
policy: two_factor
############################################################
identity_validation:
reset_password:
jwt_secret: "[REDACTED]"
identity_providers:
oidc:
enable_client_debug_messages: true
enforce_pkce: public_clients_only
hmac_secret: [REDACTED]
lifespans:
authorize_code: 1m
id_token: 1h
refresh_token: 90m
access_token: 1h
cors:
endpoints:
- authorization
- token
- revocation
- introspection
- userinfo
allowed_origins:
- "*"
allowed_origins_from_client_redirect_uris: false
jwks:
- key: [REDACTED]
certificate_chain:
clients:
- client_id: portainer
client_name: Portainer
# generate secret with "authelia crypto hash generate pbkdf2 --random --random.length 32 --random.charset alphanumeric"
# Random Password: [REDACTED]
# Digest: [REDACTED]
client_secret: [REDACTED]
token_endpoint_auth_method: 'client_secret_post'
public: false
authorization_policy: two_factor
consent_mode: pre-configured #explicit
pre_configured_consent_duration: '6M' #Must be re-authorised every 6 Months
scopes:
- openid
#- groups #Currently not supported in Authelia V
- email
- profile
redirect_uris:
- https://portainer.MYDOMAIN1.LTD
userinfo_signed_response_alg: none
- client_id: openproject
client_name: OpenProject
# generate secret with "authelia crypto hash generate pbkdf2 --random --random.length 32 --random.charset alphanumeric"
# Random Password: [REDACTED]
# Digest: [REDACTED]
client_secret: [REDACTED]
token_endpoint_auth_method: 'client_secret_basic'
public: false
authorization_policy: two_factor
consent_mode: pre-configured #explicit
pre_configured_consent_duration: '6M' #Must be re-authorised every 6 Months
scopes:
- openid
#- groups #Currently not supported in Authelia V
- email
- profile
redirect_uris:
- https://op.MYDOMAIN.TLD
#grant_types:
# - refresh_token
# - authorization_code
#response_types:
# - code
#response_modes:
# - form_post
# - query
# - fragment
userinfo_signed_response_alg: none
##################################################################
telemetry:
metrics:
enabled: false
address: tcp://0.0.0.0:9959
totp:
disable: false
issuer: authelia.com
algorithm: sha1
digits: 6
period: 30 ## The period in seconds a one-time password is valid for.
skew: 1
secret_size: 32
webauthn:
disable: false
timeout: 60s ## Adjust the interaction timeout for Webauthn dialogues.
display_name: Authelia
attestation_conveyance_preference: indirect
user_verification: preferred
ntp:
address: "pool.ntp.org"
version: 4
max_desync: 5s
disable_startup_check: false
disable_failure: false
authentication_backend:
password_reset:
disable: false
custom_url: ""
refresh_interval: 5m
file:
path: /config/users_database.yml
watch: true
password:
algorithm: argon2
argon2:
variant: argon2id
iterations: 3
memory: 65536
parallelism: 4
key_length: 32
salt_length: 16
password_policy:
standard:
enabled: false
min_length: 8
max_length: 0
require_uppercase: true
require_lowercase: true
require_number: true
require_special: true
## zxcvbn is a well known and used password strength algorithm. It does not have tunable settings.
zxcvbn:
enabled: false
min_score: 3
regulation:
max_retries: 3
find_time: 2m
ban_time: 5m
session:
name: authelia_session
secret: [REDACTED]
expiration: 60m
inactivity: 15m
cookies:
- domain: 'MYDOMAIN1.LTD'
authelia_url: 'https://auth.MYDOMAIN1.LTD'
name: 'authelia_session'
default_redirection_url: 'https://MYDOMAIN1.LTD'
- domain: 'MYDOMAIN2.LTD'
authelia_url: 'https://auth.MYDOMAIN2.LTD'
name: 'authelia_session_other'
default_redirection_url: 'https://MYDOMAIN2.LTD'
storage:
encryption_key: [REDACTED]
local:
path: /config/db.sqlite3
notifier:
disable_startup_check: true
smtp:
address: MYOTHERDOMAIN.LTD:465
timeout: 5s
username: "USER@DOMAIN"
password: "[REDACTED]"
sender: "Authelia <postmaster@MYOTHERDOMAIN.LTD>"
identifier: NAME@MYOTHERDOMAIN.LTD
subject: "[Authelia] {title}"
startup_check_address: postmaster@MYOTHERDOMAIN.LTD
```

View File

@@ -8,10 +8,10 @@ There are 3 artifacts that can be used to backup the application:
| File | Description | Limitations |
|-----------------------|-------------------------------|-------------------------------|
| `/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/app.conf` | Configuration file | Can be overridden with the [`APP_CONF_OVERRIDE` env variable](https://github.com/jokob-sk/NetAlertX/tree/main/dockerfiles#docker-environment-variables). |
| `/config/devices.csv` | CSV file containing device information | Doesn't contain historical data |
## Data and cackup storage
## Data and backup storage
To decide on a backup strategy, check where the data is stored:

View File

@@ -17,7 +17,7 @@
| Pholus_Scan | Scan results of the Pholus python network penetration script. | ![Screen8][screen8] |
| Plugins_Events | For capturing events exposed by a plugin via the `last_result.log` file. If unique then saved into the `Plugins_Objects` table. Entries are deleted once processed and stored in the `Plugins_History` and/or `Plugins_Objects` tables. | ![Screen10][screen10] |
| Plugins_History | History of all entries from the `Plugins_Events` table | ![Screen11][screen11] |
| Plugins_Language_Strings | Language strings colelcted from the plugin `config.json` files used for string resolution in the frontend. | ![Screen12][screen12] |
| Plugins_Language_Strings | Language strings collected 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 `app.conf` and plugins coming from `config.json` files. | ![Screen16][screen16] |

View File

@@ -6,7 +6,7 @@ Please follow tips 1 - 4 to get a more detailed error.
When debugging an issue always set the highest log level:
`LOG_LEVEL='debug'`
`LOG_LEVEL='trace'`
## 2. Surfacing errors when container restarts 🔁
@@ -81,3 +81,7 @@ sudo dpkg -i libseccomp2_2.5.3-2_armhf.deb
```
The link above will probably break in time too. Go to https://packages.debian.org/sid/armhf/libseccomp2/download to find the new version number and put that in the url.
### Only Router and own device show up
Make sure that the subnet and interface in SCAN_SUBNETS are the correct ones. If your device/NAS has multiple ethernet ports, you probably need to change eth0 to something else!

View File

@@ -33,7 +33,7 @@ To edit device information:
## Session Info
- **Status**: Show device status : On-line / Off-Line
- **First Session**: Date and time of the first connection
- **Last Session**: Date and time of the last connection
- **Last Offline**: Date and time of the last last time the device was offline
- **Last IP**: Last known IP used during the last connection
- **Static IP**: Check this box to identify devices that always use the
same IP

70
docs/DEV_ENV_SETUP.md Executable file
View File

@@ -0,0 +1,70 @@
## Development environment set up
>[!NOTE]
> Replace `/development` with the path where your code files will be stored. The default container name is `netalertx` so there might be a conflict with your running containers.
## 1. Download the code:
- `mkdir /development`
- `cd /development && git clone https://github.com/jokob-sk/NetAlertX.git`
## 2. Create a DEV .env_dev file
`touch /development/.env_dev && sudo nano /development/.env_dev`
The file content should be following, with your custom values.
```yaml
#--------------------------------
#NETALERTX
#--------------------------------
TZ=Europe/Berlin
PORT=22222 # make sure this port is unique on your whole network
DEV_LOCATION=/development/NetAlertX
APP_DATA_LOCATION=/volume/docker_appdata
# ALWAYS_FRESH_INSTALL=true # uncommenting this will always delete the content of /config and /db dirs on boot to simulate a fresh install
```
## 3. Create /db and /config dirs
Create a folder `netalertx` in the `APP_DATA_LOCATION` (in this example in `/volume/docker_appdata`) with 2 subfolders `db` and `config`.
- `mkdir /volume/docker_appdata/netalertx`
- `mkdir /volume/docker_appdata/netalertx/db`
- `mkdir /volume/docker_appdata/netalertx/config`
## 4. Run the container
- `cd /development/NetAlertX && sudo docker-compose --env-file ../.env_dev `
You can then modify the python script without restarting/rebuilding the container every time. Additionally, you can trigger a plugin run via the UI:
![image](https://github.com/jokob-sk/NetAlertX/assets/96159884/3cbf2748-03c8-49e7-b801-f38c7755246b)
## 💡 Tips
A quick cheat sheet of useful commands.
### Removing the container and image
A command to stop, remove the container and the image (replace `netalertx` and `netalertx-netalertx` with the appropriate values)
- `sudo docker container stop netalertx ; sudo docker container rm netalertx ; sudo docker image rm netalertx-netalertx`
### Restart the server backend
Most code changes can be tetsed without rebuilding the container. When working on the python server backend, you only need to restart the server.
1. You can usually restart the backend via Maintenance > Logs > Restart server
![image](/docs/img/DEV_ENV_SETUP/Maintenance_Logs_Restart_server.png)
2. If above doesn't work, SSH into the container and kill & restart the main script loop
- `sudo docker exec -it netalertx /bin/bash`
- `pkill -f "python /app/server" && python /app/server & `
3. If none of the above work, restart the docker image. This is usually the last resort as sometimes the Docker engine becomes unresponsive and the whole engine needs to be restarted.

View File

@@ -1,5 +1,13 @@
# Managing File Permissions for NetAlertX on Nginx with Docker
> [!TIP]
> If you are facing permission issues, try to start the container without mapping your volumes. If that works, then the issue is permission related. You can try e.g., the following command:
> ```
> docker run -d --rm --network=host \
> -e TZ=Europe/Berlin \
> -e PORT=20211 \
> jokobsk/netalertx:latest
> ```
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.

View File

@@ -38,7 +38,7 @@ Some examples how to apply the above:
Some useful frontend JavaScript functions:
- `getDeviceDataByMacAddress(macAddress, devicesColumn)` - method to retrieve any device data (database column) based on MAC address in the frontend
- `getDeviceDataByMac(macAddress, devicesColumn)` - method to retrieve any device data (database column) based on MAC address in the frontend
- `getString(string stringKey)` - method to retrieve translated strings in the frontend
- `getSetting(string stringKey)` - method to retrieve settings in the frontend

View File

@@ -6,6 +6,7 @@ NetAlertX comes with MQTT support, allowing you to show all detected devices as
- Please note that discovery takes about ~10s per device.
- Deleting of devices is not handled automatically. Please use [MQTT Explorer](https://mqtt-explorer.com/) to delete devices in the broker (Home Assistant), if needed.
- For optimization reasons, the devices are not always fully synchronized. You can delete Plugin objects as described in the [MQTT plugin](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/_publisher_mqtt#forcing-an-update) docs to force a full synchronization.
## 🧭 Guide

View File

@@ -32,13 +32,15 @@ On almost all plugins there are 2 core settings, `<plugin>_WATCH` and `<plugin>_
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.
Click the **Read more in the docs.** Link at the top of each plugin to get more details on how the given plugin works.
## 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.
In Notification Processing settings, 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.
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. More info in the [NTFPRCS plugin](/front/plugins/notification_processing/README.md)
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.
@@ -50,4 +52,4 @@ In the Notification Processing section, you can specify blanket rules. These all
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.
2. Ignored IPs (`NEWDEV_ignored_IPs`) - List of IPs to ignore.

24
docs/PERFORMANCE.md Executable file
View File

@@ -0,0 +1,24 @@
# Performance tips
The application runs regular maintenance and DB cleanup tasks. If these tasks fail, you might encounter performance issues.
Most performance issues are caused by a big database or large log files. Enabling unnecessary plugins will also lead to performance degradation.
You can always check the size of your database and database tables under the Maintenance page.
![Db size check](/docs/img/PERFORMANCE/db_size_check.png)
> [!NOTE]
> For around 100 devices the database should be approximately `50MB` and none of the entries (rows) should exceed the value of `10 000` on a healthy system. These numbers will depend on your network activity and settings.
## Maintenance plugins
There are 2 plugins responsible for maintaining the overal health of the application. One is responsible for the database cleanup and one for other tasks, such as log cleanup.
### DB Cleanup (DBCLNP)
The database cleanup plugin. Check details and related setting in the [DB Cleanup plugin docs](/front/plugins/db_cleanup/README.md). Make sure the plugin is not failing by checking the logs. Try changing the schedule `DBCLNP_RUN_SCHD` and the timeout `DBCLNP_RUN_TIMEOUT` (increase) if the plugin is failing to execute.
### Maintenance (MAINT)
The maintenance plugin. Check details and related setting in the [Maintenance plugin docs](/front/plugins/maintenance/README.md). Make sure the plugin is not failing by checking the logs. Try changing the schedule `MAINT_RUN_SCHD` and the timeout `MAINT_RUN_TIMEOUT` (increase) if the plugin is failing to execute.

View File

@@ -1,9 +1,5 @@
## 🌟 Create a custom plugin: Overview
| ![Screen 1][screen1] | ![Screen 2][screen2] | ![Screen 3][screen3] |
|----------------------|----------------------| ----------------------|
| ![Screen 4][screen4] | ![Screen 5][screen5] |
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:
* dynamic creation of a simple UI to interact with the discovered objects,
@@ -12,7 +8,19 @@ NetAlertX comes with a plugin system to feed events from third-party scripts int
* different column types for reported values to e.g. link back to a device
* import objects into existing NetAlertX database tables
> (Currently, update/overwriting of existing objects is not supported.)
> (Currently, update/overwriting of existing objects is only supported for devices via the `CurrentScan` table.)
### 🎥 Watch the video:
[![Watch the video](/docs/img/YouTube_thumbnail.png)](https://youtu.be/cdbxlwiWhv8)
### 📸 Screenshots
| ![Screen 1][screen1] | ![Screen 2][screen2] | ![Screen 3][screen3] |
|----------------------|----------------------| ----------------------|
| ![Screen 4][screen4] | ![Screen 5][screen5] |
## Use cases
Example use cases for plugins could be:
@@ -25,24 +33,9 @@ Example use cases for plugins could be:
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.
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.
## ⚠ Disclaimer
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:
* 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)
* ...
## ❗ 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:
* 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.
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.
## Plugin file structure overview
@@ -59,10 +52,10 @@ These issues will be hopefully fixed with time, so please don't report them. Ins
More on specifics below.
### Column order and values
### Column order and values (plugins interface contract)
> [!IMPORTANT]
> Spend some time reading and trying to understand the below table. This is the interface between the Plugins and the core application.
> Spend some time reading and trying to understand the below table. This is the interface between the Plugins and the core application. The application expets 9 or 13 values The first 9 values are mandatory. The next 4 values (`HelpVal1` to `HelpVal4`) are optional. However, if you use any of these optional values (e.g., `HelpVal1`), you need to supply all optional values (e.g., `HelpVal2`, `HelpVal3`, and `HelpVal4`). If a value is not used, it should be padded with `null`.
| Order | Represented Column | Value Required | Description |
|----------------------|----------------------|----------------------|----------------------|
@@ -75,6 +68,11 @@ More on specifics below.
| 6 | `Watched_Value4` | no | As above |
| 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) |
| 9 | `HelpVal1` | no | (optional) A helper value |
| 10 | `HelpVal2` | no | (optional) A helper value |
| 11 | `HelpVal3` | no | (optional) A helper value |
| 12 | `HelpVal4` | no | (optional) A helper value |
> [!NOTE]
> De-duplication is run once an hour on the `Plugins_Objects` database table and duplicate entries with the same value in columns `Object_PrimaryID`, `Object_SecondaryID`, `Plugin` (auto-filled based on `unique_prefix` of the plugin), `UserData` (can be populated with the `"type": "textbox_save"` column type) are removed.
@@ -83,6 +81,16 @@ More on specifics below.
The `config.json` file is the manifest of the plugin. It contains mainly settings definitions and the mapping of Plugin objects to NetAlertX objects.
## Execution order
The execution order is used to specify when a plugin is executed. This is useful if a plugin has access and surfaces more information than others. If a device is detected by 2 plugins and inserted into the `CurrentScan` table, the plugin with the higher priority (e.g.: `Level_0` is a higher priority than `Level_1`) will insert it's values first. These values (devices) will be then prioritized over any values inserted later.
```json
{
"execution_order" : "Layer_0"
}
```
## Supported data sources
Currently, these data sources are supported (valid `data_source` value).
@@ -183,7 +191,7 @@ This SQL query is executed on the `app.db` SQLite database file.
> ```json
> {
> "function": "CMD",
> "type": "text",
> "type": {"dataType":"string", "elements": [{"elementType" : "input", "elementOptions" : [] ,"transformers": []}]},
> "default_value":"SELECT dv.dev_Name as Object_PrimaryID, cast(dv.dev_LastIP as VARCHAR(100)) || ':' || cast( SUBSTR(ns.Port ,0, INSTR(ns.Port , '/')) as VARCHAR(100)) as Object_SecondaryID, datetime() as DateTime, ns.Service as Watched_Value1, ns.State as Watched_Value2, 'null' as Watched_Value3, 'null' as Watched_Value4, ns.Extra as Extra FROM (SELECT * FROM Nmap_Scan) ns LEFT JOIN (SELECT dev_Name, dev_MAC, dev_LastIP FROM Devices) dv ON ns.MAC = dv.dev_MAC",
> "options": [],
> "localized": ["name", "description"],
@@ -214,7 +222,7 @@ For example for `PIHOLE` (`"unique_prefix": "PIHOLE"`) it is `EXTERNAL_PIHOLE.`.
> ...
>{
> "function": "DB_PATH",
> "type": "readonly",
> "type": {"dataType":"string", "elements": [{"elementType" : "input", "elementOptions" : [{"readonly": "true"}] ,"transformers": []}]},
> "default_value":"/etc/pihole/pihole-FTL.db",
> "options": [],
> "localized": ["name", "description"],
@@ -239,7 +247,7 @@ The actual SQL query you want to execute is then stored as a `CMD` setting, simi
>```json
>{
> "function": "CMD",
> "type": "text",
> "type": {"dataType":"string", "elements": [{"elementType" : "input", "elementOptions" : [] ,"transformers": []}]},
> "default_value":"SELECT hwaddr as Object_PrimaryID, cast('http://' || (SELECT ip FROM EXTERNAL_PIHOLE.network_addresses WHERE network_id = id ORDER BY lastseen DESC, ip LIMIT 1) as VARCHAR(100)) || ':' || cast( SUBSTR((SELECT name FROM EXTERNAL_PIHOLE.network_addresses WHERE network_id = id ORDER BY lastseen DESC, ip LIMIT 1), 0, INSTR((SELECT name FROM EXTERNAL_PIHOLE.network_addresses WHERE network_id = id ORDER BY lastseen DESC, ip LIMIT 1), '/')) as VARCHAR(100)) as Object_SecondaryID, datetime() as DateTime, macVendor as Watched_Value1, lastQuery as Watched_Value2, (SELECT name FROM EXTERNAL_PIHOLE.network_addresses WHERE network_id = id ORDER BY lastseen DESC, ip LIMIT 1) as Watched_Value3, 'null' as Watched_Value4, '' as Extra, hwaddr as ForeignKey FROM EXTERNAL_PIHOLE.network WHERE hwaddr NOT LIKE 'ip-%' AND hwaddr <> '00:00:00:00:00:00'; ",
> "options": [],
> "localized": ["name", "description"],
@@ -353,7 +361,7 @@ Plugin results are always inserted into the standard `Plugin_Objects` database t
>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. That 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 means that the `"column": "NameDoesntMatter"` is not important as there is no database source column.
>🔍 Example:
@@ -417,7 +425,7 @@ The `params` array in the `config.json` is used to enable the user to change the
```json
{
"function": "CMD",
"type": "text",
"type": {"dataType":"string", "elements": [{"elementType" : "input", "elementOptions" : [] ,"transformers": []}]},
"default_value":"python3 /app/front/plugins/website_monitor/script.py urls={urls}",
"options": [],
"localized": ["name", "description"],
@@ -500,18 +508,7 @@ Required attributes are:
| -------- | ----------- |
| `"function"` | Specifies the function the setting drives or a simple unique code name. See Supported settings function values for options. |
| `"type"` | Specifies the form control used for the setting displayed in the Settings page and what values are accepted. Supported options include: |
| | - `text` |
| | - `integer` |
| | - `boolean` |
| | - `password` |
| | - `readonly` |
| | - `integer.select` |
| | - `text.select` |
| | - `text.multiselect` |
| | - `list` |
| | - `list.select` |
| | - `integer.checkbox` |
| | - `text.template` |
| | - `{"dataType":"string", "elements": [{"elementType" : "input", "elementOptions" : [{"type":"password"}] ,"transformers": ["sha256"]}]}` |
| `"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. |
@@ -521,6 +518,60 @@ Required attributes are:
| (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. |
### UI Component Types Documentation
This section outlines the structure and types of UI components, primarily used to build HTML forms or interactive elements dynamically. Each UI component has a `"type"` which defines its structure, behavior, and rendering options.
#### UI Component JSON Structure
The UI component is defined as a JSON object containing a list of `elements`. Each element specifies how it should behave, with properties like `elementType`, `elementOptions`, and any associated `transformers` to modify the data. The example below demonstrates how a component with two elements (`span` and `select`) is structured:
```json
{
"function": "dev_Icon",
"type": {
"dataType": "string",
"elements": [
{
"elementType": "span",
"elementOptions": [
{ "cssClasses": "input-group-addon iconPreview" },
{ "getStringKey": "Gen_SelectToPreview" },
{ "customId": "NEWDEV_dev_Icon_preview" }
],
"transformers": []
},
{
"elementType": "select",
"elementHasInputValue": 1,
"elementOptions": [
{ "cssClasses": "col-xs-12" },
{
"onChange": "updateIconPreview(this)"
},
{ "customParams": "NEWDEV_dev_Icon,NEWDEV_dev_Icon_preview" }
],
"transformers": []
}
]
}
}
```
### Rendering Logic
The code snippet provided demonstrates how the elements are iterated over to generate their corresponding HTML. Depending on the `elementType`, different HTML tags (like `<select>`, `<input>`, `<textarea>`, `<button>`, etc.) are created with the respective attributes such as `onChange`, `my-data-type`, and `class` based on the provided `elementOptions`. Events can also be attached to elements like buttons or select inputs.
### Key Element Types
- **`select`**: Renders a dropdown list. Additional options like `isMultiSelect` and event handlers (e.g., `onChange`) can be attached.
- **`input`**: Handles various types of input fields, including checkboxes, text, and others, with customizable attributes like `readOnly`, `placeholder`, etc.
- **`button`**: Generates clickable buttons with custom event handlers (`onClick`), icons, or labels.
- **`textarea`**: Creates a multi-line input box for text input.
- **`span`**: Used for inline text or content with customizable classes and data attributes.
Each element may also have associated events (e.g., running a scan or triggering a notification) defined under `Events`.
##### Supported settings `function` values
@@ -554,7 +605,7 @@ You can have any `"function": "my_custom_name"` custom name, however, the ones l
> ```json
> {
> "function": "RUN",
> "type": "text.select",
> "type": {"dataType":"string", "elements": [{"elementType" : "select", "elementOptions" : [] ,"transformers": []}]},
> "default_value":"disabled",
> "options": ["disabled", "once", "schedule", "always_after_scan", "on_new_device"],
> "localized": ["name", "description"],
@@ -619,7 +670,7 @@ The UI will adjust how columns are displayed in the UI based on the resolvers de
```json
"function": "dev_DeviceType",
"type": "text.select",
"type": {"dataType":"string", "elements": [{"elementType" : "select", "elementOptions" : [] ,"transformers": []}]},
"maxLength": 30,
"default_value": "",
"options": ["{value}"],

View File

@@ -43,6 +43,7 @@ There is also an in-app Help / FAQ section that should be answering frequently a
- [Invalid JSON errors debug help](/docs/DEBUG_INVALID_JSON.md)
- [Troubleshooting Plugins](/docs/DEBUG_PLUGINS.md)
- [File Permissions](/docs/FILE_PERMISSIONS.md)
- [Performance tips](/docs/PERFORMANCE.md)
#### 🔝 Popular/Suggested
@@ -63,9 +64,11 @@ There is also an in-app Help / FAQ section that should be answering frequently a
- [Version history (legacy)](/docs/VERSIONS_HISTORY.md)
- [Reverse proxy (Nginx, Apache, SWAG)](/docs/REVERSE_PROXY.md)
- [Setting up Authelia](/docs/AUTHELIA.md) (DRAFT)
#### 👩💻For Developers👨💻
- [Setting up your DEV environment](/docs/DEV_ENV_SETUP.md)
- [Server APP code structure](/server/README.md)
- [Database structure](/docs/DATABASE.md)
- [API endpoints details](/docs/API.md)

View File

@@ -27,6 +27,29 @@ If you are running a DNS server, such as **AdGuard**, set up **Private reverse D
5. Click **Apply** to save your settings.
### Specifying the DNS in the container
You can specify the DNS server in the docker-compose to improve name resolution on your network.
```yaml
services:
netalertx:
container_name: netalertx
image: "jokobsk/netalertx:latest"
restart: unless-stopped
volumes:
- /home/netalertx/config:/app/config
- /home/netalertx/db:/app/db
- /home/netalertx/log:/app/front/log
environment:
- TZ=Europe/Berlin
- PORT=20211
network_mode: host
dns: # specifying the DNS servers used for the container
- 10.8.0.1
- 10.8.0.17
```
### Using a custom resolv.conf file
You can configure a custom **/etc/resolv.conf** file in **docker-compose.yml** and set the nameserver to your LAN DNS server (e.g.: Pi-Hole). See the relevant [resolv.conf man](https://www.man7.org/linux/man-pages/man5/resolv.conf.5.html) entry for details.

View File

@@ -1,107 +1,112 @@
# Subnets configuration
# 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).
You need to specify the network interface and the network mask. You can also configure multiple subnets and specify VLANs (see VLAN exceptions below).
> [!TIP]
> 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.
`ARPSCAN` can scan multiple networks if the network allows it. To scan networks directly, the subnets must be accessible from the network where NetAlertX is running. This means NetAlertX needs to have access to the interface attached to that subnet. You can verify this by running the following command in the container:
## Examples
`sudo arp-scan --interface=eth0 192.168.1.0/24`
In this example, `--interface=eth0 192.168.1.0/24` represents a neighboring subnet. If this command returns no results, the network is not accessible due to your network or firewall restrictions.
If direct scans are not possible, you can use [supplementing plugins](https://github.com/jokob-sk/NetAlertX/blob/main/front/plugins/README.md) that use alternate methods. Protocols used by the `SNMPDSC` or `DHCPLSS` plugins have good support and usually can be used as a workaround.
Alternatively, you can set up separate NetAlertX instances running on the subnets and synchronize the results into one instance with the [`SYNC` plugin](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/sync).
> [!TIP]
> You may need to increase the time between scans `ARPSCAN_RUN_SCHD` and the timeout `ARPSCAN_RUN_TIMEOUT` (and similar settings for related plugins) when adding more subnets. If the timeout setting is exceeded, the scan is canceled to prevent the application from hanging due to rogue plugins.
> Check [debugging plugins](/docs/DEBUG_PLUGINS.md) for more tips.
## Example Values
> [!NOTE]
> 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)
> Please use the UI to configure settings as it ensures the config file is in the correct format. Edit `app.conf` directly only when really necessary.
> ![Settings location](/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:**
* 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']`
If you get timeout messages, decrease the network mask (e.g.: from `/16` to `/24`) or increase the `TIMEOUT` setting (e.g.: `ARPSCAN_RUN_TIMEOUT` to `300` (5-minute timeout)) for the plugin and the interval between scans (e.g.: `ARPSCAN_RUN_SCHD` to `*/10 * * * *` (scans every 10 minutes)).
---
## Explanation
### Network mask
### Network Mask
**Example value: `192.168.1.0/24`**
**Example value:** `192.168.1.0/24`
The arp-scan time itself depends on the number of IP addresses to check.
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.
> The number of IPs to check depends on the [network mask](https://www.calculator.net/ip-subnet-calculator.html) you set in the `SCAN_SUBNETS` setting.
> For example, a `/24` mask results in 256 IPs to check, whereas a `/16` mask checks around 65,536 IPs. Each IP takes a couple of seconds, so an incorrect configuration could make `arp-scan` take hours 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 from `192.168.1.0` to `192.168.1.255`.
### Network interface (adapter)
### Network Interface (Adapter)
**Example value: `--interface=eth0`**
**Example value:** `--interface=eth0`
The adapter will probably be `eth0` or `eth1`. (Check `System info` > `Network Hardware` or run `iwconfig` in the container to find your interface name(s))
The adapter will probably be `eth0` or `eth1`. (Check `System Info` > `Network Hardware` or run `iwconfig` in the container to find your interface name(s)).
![Network hardware](/docs/img/SUBNETS/system_info-network_hardware.png)
> [!TIP]
> Alterantive to `iwconfig` run `ip -o link show | awk -F': ' '!/lo|vir|docker/ {print $2}'` in your container to find your interface name(s) (e.g.: `eth0`, `eth1`).
> [!TIP]
> As an alternative to `iwconfig`, run `ip -o link show | awk -F': ' '!/lo|vir|docker/ {print $2}'` in your container to find your interface name(s) (e.g.: `eth0`, `eth1`).
### VLANs
**Example value: `-vlan=107`**
**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/NetAlertX/issues/170#issuecomment-1419902988)
- Append `-vlan=107` to the interface field (e.g.: `eth0 -vlan=107`) for multiple VLANs. More details are available in this [comment](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/NetAlertX/discussions/404).
**Tested Setup:** Bare Metal → Hyper-V on Win Server 2019 → Ubuntu 22.04 VM → Docker → NetAlertX.
**Approach 1 (may cause issues):**
Configure multiple network adapters in Hyper-V with distinct VLANs connected to each one using Hyper-V's network setup. However, this action can potentially lead to the Docker host's inability to handle network traffic correctly. This might interfere with other applications such as Authentik.
**Approach 2 (working example):**
Network connections to switches are configured as trunk and allow all VLANs access to the server.
By default, Hyper-V only allows untagged packets through to the VM interface, blocking VLAN-tagged packets. To fix this, follow these steps:
1. Run the following command in PowerShell on the Hyper-V machine:
```powershell
Set-VMNetworkAdapterVlan -VMName <Docker VM Name> -Trunk -NativeVlanId 0 -AllowedVlanIdList "<comma separated list of vlans>"
```
#### VLANs on a Hyper-V setup
2. Within the VM, set up sub-interfaces for each VLAN to enable scanning. On Ubuntu 22.04, Netplan can be used. In /etc/netplan/00-installer-config.yaml, add VLAN definitions:
> Community sourced content by [mscreations](https://github.com/mscreations) from this [discussion](https://github.com/jokob-sk/NetAlertX/discussions/404).
```yaml
> [!NOTE]
> The setup this was tested on: Bare Metal -> Hyper-V on Win Server 2019 -> Ubuntu 22.04 VM -> Docker -> NetAlertX.
network:
ethernets:
eth0:
dhcp4: yes
vlans:
eth0.2:
id: 2
link: eth0
addresses: [ "192.168.2.2/24" ]
routes:
- to: 192.168.2.0/24
via: 192.168.1.1
```
**Approach 1 (may cause issues):**
3. Run `sudo netplan apply` to activate the interfaces for scanning in NetAlertX.
Configure multiple network adapters in Hyper-V with distinct VLANs connected to each one using Hyper-V's network setup. However, this action can potentially lead to the Docker host's inability to handle network traffic correctly. The issue may stem from the creation of routes for network time servers or domain controllers on every interface, thereby preventing proper synchronization of the underlying Ubuntu VM. This interference can affect the performance of other applications such as Authentik.
In this case, use `192.168.2.0/24 --interface=eth0.2` in NetAlertX.
**Approach 2 (working example)**
#### VLAN Support & Exceptions
Network connections to switches are configured as trunk and allow all VLANs access to the server.
By default Hyper-V only allows untagged packets through to the VM interface and no VLAN tagged packets get through. In order to fix this follow these steps:
1) Run the following command in Powershell on the Hyper-V machine:
```shell
Set-VMNetworkAdapterVlan -VMName <Docker VM Name> -Trunk -NativeVlanId 0 -AllowedVlanIdList "<comma separated list of vlans>"
```
(There might be other ways how adjust this.)
2) Within the VM, set up sub-interfaces for each of the VLANs so they can be scanned. On Ubuntu 22.04 Netplan can be used.
In /etc/netplan/00-installer-config.yaml, add vlan definitions:
```
network:
ethernets:
eth0:
dhcp4: yes
vlans:
eth0.2:
id: 2
link: eth0
addresses: [ "192.168.2.2/24" ]
routes:
- to: 192.168.2.0/24
via: 192.168.1.1
```
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:
![Vlan configuration example](/docs/img/SUBNETS/subnets_vlan.png)
#### Support for VLANS (& exceptions)
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.
Please note the accessibility of macvlans when configured on the same computer. This is a general networking behavior, but feel free to clarify via a PR/issue.
- 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,12 +1,51 @@
# Debugging inaccessible UI
When opening an issue please :
## 1. Port conflicts
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/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 apk add lsof`
1. `sudo lsof -i`
1. Try running the `nginx` command in the container
1. if you get `nginx: [emerg] bind() to 0.0.0.0:20211 failed (98: Address in use)` try using a different port number
![lsof ports](/docs/img/WEB_UI_PORT_DEBUG/container_port.png)
![lsof ports](/docs/img/WEB_UI_PORT_DEBUG/container_port.png)
## 2. JavaScript issues
Check for browser console (F12 browser dev console) errors + check different browsers.
## 3. Clear the app cache and cached JavaScript files
Refresh the browser cache (usually shoft + refresh), try a private window, or different browsers. Please also refresh the app cache by clicking the 🔃 (reload) button in the header of the application.
## 4. Disable proxy
If you have any reverse proxy or similar, try disabling it.
## 5. Disable your firewall
If you are using a firewall, try to temporarily disabling it.
## 6. Post your docker start details
If you haven't, post your docker compose/run command.
## 7. Check for errors in your PHP/NGINX error logs
In the container execute:
`cat /var/log/nginx/error.log`
`cat /app/front/log/app.php_errors.log`
## 8. Make sure permissions are correct
> [!TIP]
> You can try to start the container without mapping the `/app/config` and `/app/db` dirs and if the UI shows up then the issue is most likely related to your file system permissions or file ownership.
Please read the [Permissions troubleshooting guide](/docs/FILE_PERMISSIONS.md) and provide a screesnhot of the permissions and ownership in the `/app/db` and `app/config` directories.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

BIN
docs/img/YouTube_thumbnail.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 KiB

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 187 KiB

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 211 KiB

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

After

Width:  |  Height:  |  Size: 146 KiB

BIN
docs/img/multi_edit.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 KiB

After

Width:  |  Height:  |  Size: 216 KiB

BIN
docs/img/network_setup.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
docs/img/notification_center.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 KiB

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

After

Width:  |  Height:  |  Size: 180 KiB

BIN
docs/img/report_sample.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

BIN
docs/img/sent_reports_text.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

After

Width:  |  Height:  |  Size: 167 KiB

BIN
docs/img/sync_hub.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

View File

@@ -17,7 +17,7 @@ showSpinner()
$(document).ready(function() {
// Load JSON data from the provided URL
$.getJSON('/api/table_appevents.json', function(data) {
$.getJSON('api/table_appevents.json', function(data) {
// Process the JSON data and generate UI dynamically
processData(data)

View File

@@ -25,13 +25,33 @@
color:white;
background-color: black;
font-family: 'Courier New', monospace;
font-size: .85em;
}
.logs-row textarea
{
width: 100%;
}
#tab_Logging .actions{
display:contents;
position: relative;
padding: 0.4em
}
#tab_Logging .actions .toggle{
margin: 0.5em;
height: 3em;
}
.logs-row .button{
margin: 2px;
}
.logs-row
{
align-content: center;
width: 100%;
display: grid;
margin: 5px;
}
.logs-size
@@ -48,12 +68,11 @@
}
.logs-small
{
height: 100px;
height: 150px;
}
.log-file
{
width: 145px;
display: inline-grid;
font-size: 20px;
}
.log-purge
@@ -105,9 +124,28 @@
border: none;
}
@media (min-width: 768px) {
.hideOnBigScreen{
display: none;
}
}
@media (max-width: 767px) { /* on mobile */
.hideOnMobile{
display: none;
}
}
/* -----------------------------------------------------------------------------
Main Sections
----------------------------------------------------------------------------- */
.content-header h1{
font-size:24px;
}
.content-header {
padding-top: 5px;
}
@@ -209,9 +247,15 @@
.content-wrapper,
.right-side,
.main-footer {
margin-left: 150px;
margin-left: 150px;
}
#settingsPage
{
display: grid;
}
@media (max-width: 767px) {
.main-header .logo {
width: 100%;
@@ -226,6 +270,15 @@
.main-footer {
margin-left: 0px;
}
.fixed .content-wrapper, .fixed .right-side {
padding-top: 50px;
}
.main-sidebar {
padding-top: 50px;
}
.content-header #pageTitle{
display: none;
}
}
.sidebar-open .content-wrapper,
@@ -707,6 +760,18 @@ height: 50px;
.infobox_label {
font-size: 16px !important;
}
.deviceSelector
{
display: block;
}
.deviceSelector input
{
width: 100% !important;
display: inline-grid;
}
/* --------------------------------------------------------- */
/* report */
/* --------------------------------------------------------- */
@@ -731,20 +796,20 @@ height: 50px;
/* settings */
/* --------------------------------------------------------- */
@media (max-width: 767px) {
@media (max-width: 767px) { /* on mobile */
/* hide on mobile */
.setting_description {
/* color: red; */
display: none;
}
.setting_input{
/* .setting_input{
width:70%;
/* background-color: red; */
}
.setting_name
{
width:30%;
}
} */
}
@media (min-width: 768px) {
@@ -752,14 +817,14 @@ height: 50px;
/* color: green; */
display: block;
}
.setting_input{
/* .setting_input{
width:40%;
/* background-color: green; */
}
.setting_name
{
width:19%;
}
} */
}
.settingswrap
@@ -824,10 +889,10 @@ height: 50px;
}
.table_row {
#settingsPage .table_row {
padding: 3px;
width:100%;
display: flex;
/* width:100%; */
/* display: flex; */
border-bottom-width: 1px;
border-bottom-style: solid;
border-color: #606060;
@@ -847,10 +912,6 @@ height: 50px;
font-weight: 300;
}
.setting_description
{
width:40%;
}
.myhidden
{
@@ -1041,11 +1102,67 @@ input[readonly] {
margin-bottom:20px;
}
#settingsPage .select2-selection
{
width: initial;
display: inline-block;
}
#settingsPage .form-control
{
min-height: 42px;
}
#settingsPage .select2-selection
{
background-color: rgb(96, 96, 96);
}
#settingsPage .select2-container
{
width: 100% !important;
}
#settingsPage .select2-container .selection
{
width: 100% !important;
display: inline-grid;
}
/* Basic style for the div elements */
#settingsPage .setting_overriden_by_env {
position: relative;
/* width: 300px;
height: 200px; */
background-color: #f3f3f3;
border: 1px solid #ccc;
margin: 20px;
z-index: 10;
}
/* Style for the overlay */
#settingsPage .setting_overriden_by_env::after {
content: "Overridden with ENV variable";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6); /* semi-transparent black overlay */
color: white;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
font-weight: 700;
z-index: 11;
}
/* ----------------------------------------------------------------- */
/* Devices page */
/* ----------------------------------------------------------------- */
#txtIconFA {
.iconPreview {
min-width: 40px;
}
@@ -1072,18 +1189,18 @@ input[readonly] {
cursor: -webkit-grab;
}
.db_info_table_row .select2-container--default .select2-selection--multiple .select2-selection__choice
.select2-container--default .select2-selection--multiple .select2-selection__choice
{
background-color:#258744;
background-color:#258744 !important;
}
.db_info_table_row .select2-container--default .select2-selection--multiple
.select2-container--default .select2-selection--multiple
{
background-color:#606060;
background-color:#606060 !important;
}
.select2-container .select2-dropdown
{
background-color:#606060;
background-color:#606060 !important;
}
.networkPageHelp{
@@ -1102,13 +1219,20 @@ input[readonly] {
height: 1.5em !important;
}
#TileCards .tile .inner
{
color: white;
}
#dropdownIcon li svg, #dropdownIcon li i{
#dropdownIcon li svg, #dropdownIcon li i, .dropdownIcon li svg, .dropdownIcon li i, .icon-maxsize svg, .icon-maxsize i{
height: 1.5em !important;
}
#tableDevices .badge i
{
height: 1em !important;
}
/* ----------------------------------------------------------------- */
/* MODAL popups */
@@ -1227,7 +1351,29 @@ input[readonly] {
/* background-color:red; */
}
.sort-btn {
right: 5px;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
}
.networkNodeTabHeaders
{
max-width: 200px;
text-overflow: ellipsis;
overflow: hidden;
text-wrap: nowrap;
}
@media (max-width: 767px) {
.networkNodeTabHeaders .node-name
{
display: none;
}
}
/* ----------------------------------------------------------------- */
/* PLUGINS page */
@@ -1323,7 +1469,7 @@ input[readonly] {
opacity: 0.8;
background-color: #fff;
z-index: 99;
z-index: 800;
}
.pa_spinner {
@@ -1336,7 +1482,7 @@ input[readonly] {
padding: 15px;
width: 200px;
background-color: #fff;
z-index: 100;
z-index: 801;
}
#loadingSpinner

View File

@@ -100,7 +100,7 @@
<div class="col-lg-12 col-sm-12 col-xs-12">
<!-- <div class="box-transparent"> -->
<div id="navDevice" class="nav-tabs-custom">
<ul class="nav nav-tabs" style="fon t-size:16px;">
<ul class="nav nav-tabs" style="font-size:16px;">
<li> <a id="tabDetails" href="#panDetails" data-toggle="tab"> <?= lang('DevDetail_Tab_Details');?> </a></li>
<li> <a id="tabTools" href="#panTools" data-toggle="tab"> <?= lang('DevDetail_Tab_Tools');?> </a></li>
<li> <a id="tabSessions" href="#panSessions" data-toggle="tab"> <?= lang('DevDetail_Tab_Sessions');?> </a></li>
@@ -197,8 +197,8 @@
</label>
<div class="col-sm-9">
<div class="input-group">
<span class="input-group-addon" id="txtIconFA"></span>
<input class="form-control" id="txtIcon" type="text" value="--" readonly>
<span class="input-group-addon iconPreview" id="txtIconPreview" my-customid="txtIconPreview"></span>
<input class="form-control" id="txtIcon" my-customid="txtIcon" my-customparams="txtIcon,txtIconPreview" 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">
@@ -350,6 +350,18 @@
<input class="form-control" id="txtNetworkPort" type="text" value="--">
</div>
</div>
<div class="form-group" >
<label class="col-sm-3 control-label"><?= lang('DevDetail_MainInfo_SSID');?></label>
<div class="col-sm-9">
<input class="form-control" id="txtSSID" type="text" value="--">
</div>
</div>
<div class="form-group" >
<label class="col-sm-3 control-label"><?= lang('DevDetail_MainInfo_Network_Site');?></label>
<div class="col-sm-9">
<input class="form-control" id="txtNetworkSite" type="text" value="--">
</div>
</div>
@@ -681,7 +693,6 @@ if ($ENABLED_DARKMODE === True) {
var pos = -1;
var parPeriod = 'Front_Details_Period';
var parTab = 'Front_Details_Tab';
var parSessionsRows = 'Front_Details_Sessions_Rows';
var parEventsRows = 'Front_Details_Events_Rows';
var parEventsHide = 'Front_Details_Events_Hide';
@@ -724,7 +735,7 @@ function main () {
$('#chkHideConnectionEvents')[0].checked = eval(eventsHide == 'true');
// Initialize components with parameters
initializeTabs();
initializeTabsNew();
initializeiCheck();
initializeCombos();
initializeDatatables();
@@ -744,24 +755,13 @@ function main () {
// Show device icon as it changes
$('#txtIcon').on('change input', function() {
updateIconPreview('#txtIcon')
updateIconPreview(this)
});
}
// -----------------------------------------------------------------------------
function initializeTabs () {
// Activate panel
$('.nav-tabs a[id='+ tab +']').tab('show');
// When changed save new current tab
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
setParameter (parTab, $(e.target).attr('id'));
});
}
// -----------------------------------------------------------------------------
function initializeiCheck () {
// Blue
@@ -790,7 +790,6 @@ function initializeiCheck () {
// Hide / Show Events
if (event.currentTarget.id == 'chkHideConnectionEvents') {
getDeviceEvents();
setParameter (parEventsHide, event.currentTarget.checked);
} else {
// Activate save & restore
// activateSaveRestoreData();
@@ -812,20 +811,20 @@ function initializeCombos () {
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
// generateSetOptions(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' )
generateOptionsOrSetOptions("NEWDEV_dev_Icon", [], "dropdownIcon_tmp", genListWithInputSet, 'txtIcon', ["base64"])
generateOptionsOrSetOptions("NEWDEV_dev_DeviceType", [], "dropdownDeviceType_tmp", genListWithInputSet, 'txtDeviceType' )
generateOptionsOrSetOptions("NEWDEV_dev_Owner", [], "dropdownOwner_tmp", genListWithInputSet, 'txtOwner' )
generateOptionsOrSetOptions("NEWDEV_dev_Group", [], "dropdownGroup_tmp", genListWithInputSet, 'txtGroup' )
generateOptionsOrSetOptions("NEWDEV_dev_Location", [], "dropdownLocation_tmp", genListWithInputSet, 'txtLocation' )
generateOptionsOrSetOptions("NEWDEV_dev_Network_Node_MAC_ADDR", [], "dropdownNetworkNodeMac_tmp", genListWithInputSet, 'txtNetworkNodeMac' )
// Initialize static combos
initializeComboSkipRepeated ();
@@ -1014,25 +1013,6 @@ function initializeDatatables () {
"info": "<?= lang('Events_Table_info');?>",
}
});
// Save Parameters rows & order when changed
$('#tableSessions').on( 'length.dt', function ( e, settings, len ) {
setParameter (parSessionsRows, len);
// Sync Rows in both datatables
// if ( $('#tableEvents').DataTable().page.len() != len) {
// $('#tableEvents').DataTable().page.len( len ).draw();
// }
} );
$('#tableEvents').on( 'length.dt', function ( e, settings, len ) {
setParameter (parEventsRows, len);
// Sync Rows in both datatables
// if ( $('#tableSessions').DataTable().page.len() != len) {
// $('#tableSessions').DataTable().page.len( len ).draw();
// }
} );
};
@@ -1136,8 +1116,8 @@ function initializeCalendar () {
showSpinner()
} else {
setTimeout(() => {
updateIconPreview('#txtIcon')
}, 100);
updateIconPreview($('#txtIcon'))
}, 500);
hideSpinner()
}
@@ -1149,10 +1129,6 @@ function initializeCalendar () {
// -----------------------------------------------------------------------------
function periodChanged () {
// Save Parameter Period
period = $('#period').val();
setParameter (parPeriod, period);
// Requery Device data
getDeviceData(true);
getSessionsPresenceEvents();
@@ -1210,6 +1186,8 @@ function getDeviceData (readAllData=false) {
$('#txtComments').val ('--');
$('#txtNetworkNodeMac').val ('--');
$('#txtNetworkPort').val ('--');
$('#txtNetworkSite').val ('--');
$('#txtSSID').val ('--');
$('#txtFirstConnection').val ('--');
$('#txtLastConnection').val ('--');
@@ -1293,7 +1271,7 @@ function getDeviceData (readAllData=false) {
networkParentMac = deviceData['dev_Network_Node_MAC_ADDR']
if(networkParentMac)
{
networkParentMacName = getDeviceDataByMacAddress(deviceData['dev_Network_Node_MAC_ADDR'], "dev_Name")
networkParentMacName = getDeviceDataByMac(deviceData['dev_Network_Node_MAC_ADDR'], "dev_Name")
} else
{
networkParentMacName = '--'
@@ -1310,10 +1288,12 @@ function getDeviceData (readAllData=false) {
if (deviceData['dev_Favorite'] == 1) {$('#chkFavorite').iCheck('check');} else {$('#chkFavorite').iCheck('uncheck');}
$('#txtGroup').val (deviceData['dev_Group']);
$('#txtLocation').val (deviceData['dev_Location']);
$('#txtComments').val (deviceData['dev_Comments']);
$('#txtComments').val (decodeSpecialChars(deviceData['dev_Comments']));
$('#txtNetworkNodeMac').val ( networkParentMacName) ;
$('#txtNetworkNodeMac').attr ('data-mynodemac', deviceData['dev_Network_Node_MAC_ADDR']);
$('#txtNetworkPort').val (deviceData['dev_Network_Node_port']);
$('#txtNetworkSite').val (deviceData['dev_NetworkSite']);
$('#txtSSID').val (deviceData['dev_SSID']);
// disabling network node configuration if root Internet node
toggleNetworkConfiguration(mac == 'Internet')
@@ -1441,17 +1421,19 @@ function setDeviceData (direction='', refreshCallback='') {
// update data to server
$.get('php/server/devices.php?action=setDeviceData&mac='+ mac
+ '&name=' + encodeURIComponent($('#txtName').val())
+ '&owner=' + encodeURIComponent($('#txtOwner').val())
+ '&name=' + encodeURIComponent($('#txtName').val().replace(/'/g, ""))
+ '&owner=' + encodeURIComponent($('#txtOwner').val().replace(/'/g, ""))
+ '&type=' + $('#txtDeviceType').val()
+ '&vendor=' + encodeURIComponent($('#txtVendor').val())
+ '&vendor=' + encodeURIComponent($('#txtVendor').val().replace(/'/g, ""))
+ '&icon=' + encodeURIComponent($('#txtIcon').val())
+ '&favorite=' + ($('#chkFavorite')[0].checked * 1)
+ '&group=' + encodeURIComponent($('#txtGroup').val())
+ '&location=' + encodeURIComponent($('#txtLocation').val())
+ '&comments=' + encodeURIComponent($('#txtComments').val())
+ '&comments=' + encodeURIComponent(encodeSpecialChars($('#txtComments').val()))
+ '&networknode=' + $('#txtNetworkNodeMac').attr('data-mynodemac')
+ '&networknodeport=' + $('#txtNetworkPort').val()
+ '&ssid=' + $('#txtSSID').val()
+ '&networksite=' + $('#txtNetworkSite').val()
+ '&staticIP=' + ($('#chkStaticIP')[0].checked * 1)
+ '&scancycle=' + ($('#txtScanCycle').val() == "yes" ? "1" : "0")
+ '&alertevents=' + ($('#chkAlertEvents')[0].checked * 1)
@@ -1476,7 +1458,7 @@ function setDeviceData (direction='', refreshCallback='') {
somethingChanged = false;
// refresh API
updateApi()
updateApi("devices,appevents")
hideSpinner()
@@ -1661,7 +1643,7 @@ function addAsBase64 () {
$('#txtIcon').val(iconHtmlBase64);
updateIconPreview('#txtIcon')
updateIconPreview($('#txtIcon'))
}
@@ -1696,7 +1678,7 @@ function deleteDevice () {
$('#panDetails :input').attr('disabled', true);
// refresh API
updateApi()
updateApi("devices,appevents")
}
// -----------------------------------------------------------------------------
@@ -1738,7 +1720,7 @@ function setTextValue (textElement, textValue) {
if(textElement == "txtNetworkNodeMac")
{
$('#'+textElement).attr ('data-mynodemac', textValue);
$('#'+textElement).val (getDeviceDataByMacAddress(textValue, "dev_Name"));
$('#'+textElement).val (getDeviceDataByMac(textValue, "dev_Name"));
} else
{
$('#'+textElement).attr ('data-myvalue', textValue);
@@ -1825,12 +1807,6 @@ function initTable(tableId, mac){
$("#"+tableId).attr("data-mac", mac)
// Save Parameters rows & order when changed
$('#'+tableId).on( 'length.dt', function ( e, settings, len ) {
setParameter (parSessionsRows, len);
} );
}
//-----------------------------------------------------------------------------------

View File

@@ -77,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(getDeviceDataByMacAddress(getMac(), 'dev_LastIP'), '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(getDeviceDataByMac(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(getDeviceDataByMacAddress(getMac(), 'dev_LastIP'), '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(getDeviceDataByMac(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(getDeviceDataByMacAddress(getMac(), 'dev_LastIP'), '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(getDeviceDataByMac(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(getDeviceDataByMacAddress(getMac(), 'dev_LastIP'), '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(getDeviceDataByMac(getMac(), 'dev_LastIP'), 'skipdiscovery')">
<?= lang("DevDetail_Loading") ?>
</button>
@@ -155,7 +155,7 @@
$( "#tracerouteoutput" ).empty();
$.ajax({
method: "GET",
url: "./php/server/traceroute.php?action=get&ip=" + getDeviceDataByMacAddress(getMac(), 'dev_LastIP') + "",
url: "./php/server/traceroute.php?action=get&ip=" + getDeviceDataByMac(getMac(), 'dev_LastIP') + "",
beforeSend: function() { $('#tracerouteoutput').addClass("ajax_scripts_loading"); },
complete: function() { $('#tracerouteoutput').removeClass("ajax_scripts_loading"); },
success: function(data, textStatus) {
@@ -170,7 +170,7 @@
$( "#nslookupoutput" ).empty();
$.ajax({
method: "GET",
url: "./php/server/nslookup.php?action=get&ip=" + getDeviceDataByMacAddress(getMac(), 'dev_LastIP') + "",
url: "./php/server/nslookup.php?action=get&ip=" + getDeviceDataByMac(getMac(), 'dev_LastIP') + "",
beforeSend: function() { $('#nslookupoutput').addClass("ajax_scripts_loading"); },
complete: function() { $('#nslookupoutput').removeClass("ajax_scripts_loading"); },
success: function(data, textStatus) {

View File

@@ -15,8 +15,6 @@
<?php
require 'php/templates/header.php';
require 'php/templates/graph.php';
// check permissions
$dbPath = "../db/app.db";
@@ -42,77 +40,7 @@
<!-- 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">
<div class="inner"><h3 id="devicesMy"> -- </h3>
<p class="infobox_label"><?= lang('Device_Shortcut_AllDevices');?></p>
</div>
<div class="icon"><i class="fa fa-laptop text-aqua-40"></i></div>
</div>
</a>
</div>
<!-- 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">
<div class="inner"><h3 id="devicesConnected"> -- </h3>
<p class="infobox_label"><?= lang('Device_Shortcut_Connected');?></p>
</div>
<div class="icon"><i class="fa fa-plug text-green-40"></i></div>
</div>
</a>
</div>
<!-- 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">
<div class="inner"><h3 id="devicesFavorites"> -- </h3>
<p class="infobox_label"><?= lang('Device_Shortcut_Favorites');?></p>
</div>
<div class="icon"><i class="fa fa-star text-yellow-40"></i></div>
</div>
</a>
</div>
<!-- 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">
<div class="inner"><h3 id="devicesNew"> -- </h3>
<p class="infobox_label"><?= lang('Device_Shortcut_NewDevices');?></p>
</div>
<div class="icon"><i class="ion ion-plus-round text-yellow-40"></i></div>
</div>
</a>
</div>
<!-- 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_DownOnly');?></p>
</div>
<div class="icon"><i class="fa fa-warning text-red-40"></i></div>
</div>
</a>
</div>
<!-- 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">
<div class="inner"><h3 id="devicesArchived"> -- </h3>
<p class="infobox_label"><?= lang('Device_Shortcut_Archived');?></p>
</div>
<div class="icon"><i class="fa fa-eye-slash text-gray-40"></i></div>
</div>
</a>
</div>
<!-- Placeholder ------------------------------------------------------- -->
</div>
@@ -136,19 +64,37 @@
</div>
<script src="js/graph_online_history.js"></script>
<script>
var pia_js_online_history_time = [<?php pia_graph_devices_data($Pia_Graph_Device_Time); ?>];
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); ?>];
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);
$.get('api/table_online_history.json?nocache=' + Date.now(), function(res) {
// Extracting data from the JSON response
var timeStamps = [];
var onlineCounts = [];
var downCounts = [];
var offlineCounts = [];
var archivedCounts = [];
res.data.forEach(function(entry) {
var dateObj = new Date(entry.Scan_Date);
var formattedTime = dateObj.toLocaleTimeString([], {hour: '2-digit', minute: '2-digit', hour12: false});
timeStamps.push(formattedTime);
onlineCounts.push(entry.Online_Devices);
downCounts.push(entry.Down_Devices);
offlineCounts.push(entry.Offline_Devices);
archivedCounts.push(entry.Archived_Devices);
});
// Call your presenceOverTime function after data is ready
presenceOverTime(
timeStamps,
onlineCounts,
offlineCounts,
archivedCounts,
downCounts
);
}).fail(function() {
// Handle any errors in fetching the data
console.error('Error fetching online history data.');
});
</script>
<!-- datatable ------------------------------------------------------------- -->
@@ -207,127 +153,70 @@
<!-- page script ----------------------------------------------------------- -->
<script>
var deviceStatus = 'all';
var parTableRows = 'Front_Devices_Rows';
var parTableOrder = 'Front_Devices_Order';
var tableRows = 10;
var tableOrder = [[3,'desc'], [0,'asc']];
var tableRows = getCookie ("nax_parTableRows") == "" ? 10 : getCookie ("nax_parTableRows") ;
var tableOrder = getCookie ("nax_parTableOrder") == "" ? [[3,'desc'], [0,'asc']] : JSON.parse(getCookie ("nax_parTableOrder")) ;
var tableColumnHide = [];
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 = [
getString('Device_TableHead_Name'),
getString('Device_TableHead_Owner'),
getString('Device_TableHead_Type'),
getString('Device_TableHead_Icon'),
getString('Device_TableHead_Favorite'),
getString('Device_TableHead_Group'),
getString('Device_TableHead_FirstSession'),
getString('Device_TableHead_LastSession'),
getString('Device_TableHead_LastIP'),
getString('Device_TableHead_MAC'),
getString('Device_TableHead_Status'),
getString('Device_TableHead_MAC_full'),
getString('Device_TableHead_LastIPOrder'),
getString('Device_TableHead_Rowid'),
getString('Device_TableHead_Parent_MAC'),
getString('Device_TableHead_Connected_Devices'),
getString('Device_TableHead_Location'),
getString('Device_TableHead_Vendor'),
getString('Device_TableHead_Port'),
getString('Device_TableHead_GUID'),
getString('Device_TableHead_SyncHubNodeName')
];
var tableColumnOrder = [];
var tableColumnVisible = [];
// Read parameters & Initialize components
callAfterAppInitialized(main)
showSpinner();
main();
// -----------------------------------------------------------------------------
function main () {
handleLoadingDialog()
//initialize the table headers in the correct order
var availableColumns = getSettingOptions("UI_device_columns").split(",");
var headersDefaultOrder = availableColumns.map(val => getString(val));
var selectedColumns = JSON.parse(getSetting("UI_device_columns").replace(/'/g, '"'));
// generate default order lists of given length
var columnsStr = JSON.stringify(Array.from({ length: headersDefaultOrder.length }, (_, i) => i));
tableColumnOrder = Array.from({ length: headersDefaultOrder.length }, (_, i) => i);
tableColumnVisible = [];
// Initialize tableColumnVisible by including all columns from selectedColumns, preserving their order.
tableColumnVisible = selectedColumns.map(column => availableColumns.indexOf(column)).filter(index => index !== -1);
// Add any columns from availableColumns that are not in selectedColumns to the end.
const remainingColumns = availableColumns.map((column, index) => index).filter(index => !tableColumnVisible.includes(index));
// Combine both arrays.
tableColumnOrder = tableColumnVisible.concat(remainingColumns);
// Generate the full array of numbers from 0 to totalLength - 1 of tableColumnOrder
const fullArray = Array.from({ length: tableColumnOrder.length }, (_, i) => i);
// Filter out the elements already present in inputArray
const missingNumbers = fullArray.filter(num => !tableColumnVisible.includes(num));
// Concatenate the inputArray with the missingNumbers
tableColumnOrder = [...tableColumnVisible, ...missingNumbers];
// render table headers
html = '';
for(index = 0; index < tableColumnOrder.length; index++)
{
html += '<th>' + headersDefaultOrder[tableColumnOrder[index]] + '</th>';
}
$('#tableDevices tr').html(html);
// Hide UI elements as per settings
// setTimeout(() => {
hideUIelements("UI_DEV_SECTIONS")
// }, 10);
// Initialize components with parameters
initializeDatatable(getUrlAnchor('my_devices'));
// check if data outdated and show spinner if so
handleLoadingDialog()
// 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',',')
defaultValue = cookieColumnsVisibleStr == "" ? columnsStr : cookieColumnsVisibleStr;
// get visible columns
$.get('php/server/parameters.php?action=get&expireMinutes=525600&defaultValue='+defaultValue+'&parameter=Front_Devices_Columns_Visible&skipcache', function(data) {
handle_locked_DB(data)
// save which columns are in the Devices page visible
tableColumnVisible = numberArrayFromString(data);
// get from cookie if available (need to use decodeURI as saved as part of URI in PHP)
cookieColumnsOrderStr = decodeURI(getCookie("Front_Devices_Columns_Order")).replaceAll('%2C',',')
defaultValue = cookieColumnsOrderStr == "" ? columnsStr : cookieColumnsOrderStr;
// get the custom order specified by the user
$.get('php/server/parameters.php?action=get&expireMinutes=525600&defaultValue='+defaultValue+'&parameter=Front_Devices_Columns_Order&skipcache', function(data) {
handle_locked_DB(data)
// save the columns order in the Devices page
tableColumnOrder = numberArrayFromString(data);
html = '';
for(index = 0; index < tableColumnOrder.length; index++)
{
html += '<th>' + headersDefaultOrder[tableColumnOrder[index]] + '</th>';
}
$('#tableDevices tr').html(html);
// get parameter value
$.get('php/server/parameters.php?action=get&defaultValue=50&parameter='+ parTableRows, function(data) {
var result = JSON.parse(data);
result = parseInt(result, 10)
if (Number.isInteger (result) ) {
tableRows = result;
}
// get parameter value
$.get('php/server/parameters.php?action=get&defaultValue=[[3,"desc"],[0,"asc"]]&parameter='+ parTableOrder, function(data) {
var result = JSON.parse(data);
result = JSON.parse(result);
if (Array.isArray (result) ) {
tableOrder = result;
}
// Initialize components with parameters
initializeDatatable(getUrlAnchor('my'));
// check if data outdated and show spinner if so
handleLoadingDialog()
});
});
});
});
}
// -----------------------------------------------------------------------------
@@ -353,21 +242,47 @@ function getDevicesTotals(devicesData) {
if (getCache("getDevicesTotals") !== "") {
resultJSON = getCache("getDevicesTotals");
} else {
// combined query
const devices = filterDataByStatus(devicesData, 'my');
const connectedDevices = filterDataByStatus(devicesData, 'connected');
const favoritesDevices = filterDataByStatus(devicesData, 'favorites');
const newDevices = filterDataByStatus(devicesData, 'new');
const downDevices = filterDataByStatus(devicesData, 'down');
const archivedDevices = filterDataByStatus(devicesData, 'archived');
// Define filter conditions and corresponding objects
const filters = [
{ status: 'my_devices', color: 'bg-aqua', label: getString('Device_Shortcut_AllDevices'), icon: 'fa-laptop' },
{ status: 'all', color: 'bg-aqua', label: getString('Gen_All_Devices'), icon: 'fa-laptop' },
{ status: 'connected', color: 'bg-green', label: getString('Device_Shortcut_Connected'), icon: 'fa-plug' },
{ status: 'favorites', color: 'bg-yellow', label: getString('Device_Shortcut_Favorites'), icon: 'fa-star' },
{ status: 'new', color: 'bg-yellow', label: getString('Device_Shortcut_NewDevices'), icon: 'fa-plus' },
{ status: 'down', color: 'bg-red', label: getString('Device_Shortcut_DownOnly'), icon: 'fa-warning' },
{ status: 'archived', color: 'bg-gray', label: getString('Device_Shortcut_Archived'), icon: 'fa-eye-slash' },
{ status: 'offline', color: 'bg-gray', label: getString('Gen_Offline'), icon: 'fa-xmark' }
];
$('#devicesMy').html (devices.length);
$('#devicesConnected').html (connectedDevices.length);
$('#devicesFavorites').html (favoritesDevices.length);
$('#devicesNew').html (newDevices.length);
$('#devicesDown').html (downDevices.length);
$('#devicesArchived').html (archivedDevices.length);
// Initialize an empty array to store the final objects
let dataArray = [];
// Loop through each filter condition
filters.forEach(filter => {
// Calculate count dynamically based on filter condition
let count = filterDataByStatus(devicesData, filter.status).length;
// Check any condition to skip adding the object to dataArray
if (
(['', 'False'].includes(getSetting('UI_hide_empty')) || (getSetting('UI_hide_empty') == "True" && count > 0)) &&
(getSetting('UI_shown_cards') == "" || getSetting('UI_shown_cards').includes(filter.status))
) {
dataArray.push({
onclickEvent: `initializeDatatable('${filter.status}')`,
color: filter.color,
title: count,
label: filter.label,
icon: filter.icon
});
}
});
// render info boxes/tile cards
renderInfoboxes(
dataArray
)
// save to cache
setCache("getDevicesTotals", resultJSON);
@@ -376,12 +291,29 @@ function getDevicesTotals(devicesData) {
// console.log(resultJSON);
}
//------------------------------------------------------------------------------
// Render the info boxes/tiles on top
function renderInfoboxes(customData) {
$.ajax({
url: 'php/components/tile_cards.php', // PHP script URL
type: 'POST', // Use POST method to send data
dataType: 'html', // Expect HTML response
data: { items: JSON.stringify(customData) }, // Send customData as JSON
success: function(response) {
$('#TileCards').html(response); // Replace container content with fetched HTML
},
error: function(xhr, status, error) {
console.error('Error fetching infoboxes:', error);
}
});
}
// -----------------------------------------------------------------------------
// Define a function to filter data based on deviceStatus
function filterDataByStatus(data, status) {
return data.filter(function(item) {
switch (status) {
case 'my':
case 'my_devices':
to_display = getSetting('UI_MY_DEVICES');
let result = true;
@@ -398,7 +330,7 @@ function filterDataByStatus(data, status) {
result = false;
}
return result; // Include all items for 'my' status
return result; // Include all items for 'my_devices' status
case 'connected':
return item.dev_PresentLastScan === 1;
case 'favorites':
@@ -424,7 +356,7 @@ function getDeviceStatus(item)
if(item.dev_NewDevice === 1)
{
return 'New';
}
}
else if(item.dev_PresentLastScan === 1)
{
return 'On-line';
@@ -450,7 +382,7 @@ function initializeDatatable (status) {
if(!status)
{
status = 'my'
status = 'my_devices'
}
// Save status selected
@@ -458,12 +390,14 @@ function initializeDatatable (status) {
// Define color & title for the status selected
switch (deviceStatus) {
case 'my': tableTitle = getString('Device_Shortcut_AllDevices'); color = 'aqua'; break;
case 'my_devices': tableTitle = getString('Device_Shortcut_AllDevices'); color = 'aqua'; break;
case 'connected': tableTitle = getString('Device_Shortcut_Connected'); color = 'green'; break;
case 'all': tableTitle = getString('Gen_All_Devices'); color = 'aqua'; 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_DownOnly'); color = 'red'; break;
case 'down': tableTitle = getString('Device_Shortcut_DownOnly'); color = 'red'; break;
case 'archived': tableTitle = getString('Device_Shortcut_Archived'); color = 'gray'; break;
case 'offline': tableTitle = getString('Gen_Offline'); color = 'gray'; break;
default: tableTitle = getString('Device_Shortcut_Devices'); color = 'gray'; break;
}
@@ -483,6 +417,11 @@ function initializeDatatable (status) {
}
$.get('api/table_devices.json?nocache=' + Date.now(), function(result) {
// refresh devices cache
devicesListAll_JSON = result["data"]
devicesListAll_JSON_str = JSON.stringify(devicesListAll_JSON)
setCache('devicesListAll_JSON', devicesListAll_JSON_str)
// query data
getDevicesTotals(result.data);
@@ -515,7 +454,9 @@ function initializeDatatable (status) {
item.dev_Vendor || "",
item.dev_Network_Node_port || 0,
item.dev_GUID || "",
item.dev_SyncHubNodeName || ""
item.dev_SyncHubNodeName || "",
item.dev_NetworkSite || "",
item.dev_SSID || ""
];
var newRow = [];
@@ -529,10 +470,6 @@ function initializeDatatable (status) {
})
};
// TODO displayed columns
// Check if the DataTable already exists
if ($.fn.dataTable.isDataTable('#tableDevices')) {
// The DataTable exists, so destroy it
@@ -540,12 +477,12 @@ function initializeDatatable (status) {
table.clear().destroy();
}
var table=
var table =
$('#tableDevices').DataTable({
'data' : dataArray["data"],
'paging' : true,
'lengthChange' : true,
'lengthMenu' : [[10, 25, 50, 100, 500, -1], [10, 25, 50, 100, 500, getString('Device_Tablelenght_all')]],
'lengthMenu' : [[10, 25, 50, 100, 500, 100000], [10, 25, 50, 100, 500, getString('Device_Tablelenght_all')]],
'searching' : true,
'ordering' : true,
@@ -652,17 +589,27 @@ function initializeDatatable (status) {
{targets: [mapIndx(10)],
'createdCell': function (td, cellData, rowData, row, col) {
// console.log(cellData)
switch (cellData) {
case 'Down': color='red'; break;
case 'New': color='yellow'; break;
case 'On-line': color='green'; break;
case 'Off-line': color='gray text-white'; break;
case 'Archived': color='gray text-white'; break;
default: color='aqua'; break;
};
devData = getDeviceDataByMac(rowData[mapIndx(11)])
if (devData.dev_PresentLastScan == 1)
{
css = "green text-white statusOnline"
icon = '<i class="fa-solid fa-plug"></i>'
} else if (devData.dev_PresentLastScan != 1 && devData.dev_AlertDeviceDown == 1)
{
css = "red text-white statusDown"
icon = '<i class="fa-solid fa-triangle-exclamation"></i>'
} else if(devData.dev_PresentLastScan != 1)
{
css = "gray text-white statusOffline"
icon = '<i class="fa-solid fa-xmark"></i>'
} else
{
css = "gray text-white statusUnknown"
icon = '<i class="fa-solid fa-question"></i>'
}
$(td).html ('<a href="deviceDetails.php?mac='+ rowData[mapIndx(11)] +'" class="badge bg-'+ color +'">'+ cellData.replace('-', '') +'</a>');
$(td).html (`<a href="deviceDetails.php?mac=${rowData[mapIndx(11)]}" class="badge bg-${css}">${icon} ${cellData.replace('-', '')}</a>`);
} },
],
@@ -683,11 +630,11 @@ function initializeDatatable (status) {
// Save cookie Rows displayed, and Parameters rows & order
$('#tableDevices').on( 'length.dt', function ( e, settings, len ) {
setParameter (parTableRows, len);
setCookie ("nax_parTableRows", len, 129600); // save for 90 days
} );
$('#tableDevices').on( 'order.dt', function () {
setParameter (parTableOrder, JSON.stringify (table.order()) );
setCookie ("nax_parTableOrder", JSON.stringify (table.order()), 129600); // save for 90 days
setCache ('devicesList', getDevicesFromTable(table) );
} );
@@ -707,8 +654,6 @@ function initializeDatatable (status) {
// Check if any row is selected
var anyRowSelected = $('#tableDevices tr.selected').length > 0;
console.log(anyRowSelected);
// Toggle visibility of element with ID 'multiEdit'
$('#multiEdit').toggle(anyRowSelected);
}, 200);

View File

@@ -183,43 +183,31 @@
<!-- page script ----------------------------------------------------------- -->
<script>
var parPeriod = 'Front_Events_Period';
var parTableRows = 'Front_Events_Rows';
var parPeriod = 'nax_parPeriod';
var parTableRows = 'nax_parTableRows';
var eventsType = 'all';
var period = '';
var tableRows = 10;
var period = '1 day';
var tableRows = 25;
// Read parameters & Initialize components
main();
// -----------------------------------------------------------------------------
function main () {
// 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);
}
function main() {
// Get parameter value from cookies instead of server
period = getCookie(parPeriod) === "" ? "1 day" : getCookie(parPeriod);
$('#period').val(period);
// get parameter value
$.get('php/server/parameters.php?action=get&defaultValue=50&parameter='+ parTableRows, function(data) {
var result = JSON.parse(data);
result = parseInt(result, 10)
if (Number.isInteger (result) ) {
tableRows = result;
}
tableRows = getCookie(parTableRows) === "" ? 50 : parseInt(getCookie(parTableRows), 10);
// Initialize components
initializeDatatable();
// Initialize components
initializeDatatable();
// query data
getEventsTotals();
getEvents (eventsType);
});
});
// Query data
getEventsTotals();
getEvents(eventsType);
}
@@ -281,7 +269,7 @@ function initializeDatatable () {
// Save Parameter rows when changed
$('#tableEvents').on( 'length.dt', function ( e, settings, len ) {
setParameter (parTableRows, len);
setCookie(parTableRows, len)
} );
};
@@ -290,7 +278,8 @@ function initializeDatatable () {
function periodChanged () {
// Save Parameter Period
period = $('#period').val();
setParameter (parPeriod, period);
setCookie(parTableRows, period)
// Requery totals and events
getEventsTotals();

View File

@@ -147,19 +147,6 @@
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion_det" href="#collapse301">
<?= lang('HelpFAQ_Cat_Detail_301_head_a');?> "<?= lang('DevDetail_EveandAl_ScanCycle');?>" <?= lang('HelpFAQ_Cat_Detail_301_head_b');?></a>
</h4>
</div>
<div id="collapse301" class="panel-collapse collapse" style="font-size: 16px;">
<div class="panel-body">
<?= lang('HelpFAQ_Cat_Detail_301_text');?>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

BIN
front/img/NetAlertX_logo_old.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@@ -0,0 +1,365 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="200"
height="200"
viewBox="0 0 52.916667 52.916668"
version="1.1"
id="svg5"
inkscape:version="1.1.2 (b8e25be833, 2022-02-05)"
sodipodi:docname="netalertx_red_1_backup.svg"
inkscape:export-filename="C:\Users\jokob\netalertx_red_1.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="3.6203867"
inkscape:cx="154.67961"
inkscape:cy="88.664562"
inkscape:window-width="3440"
inkscape:window-height="1377"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer6"
units="px"
width="50px" />
<defs
id="defs2">
<inkscape:path-effect
effect="powermask"
id="path-effect51283"
is_visible="true"
lpeversion="1"
uri="#mask-powermask-path-effect51283"
invert="false"
hide_mask="false"
background="true"
background_color="#ffffffff" />
<inkscape:path-effect
effect="powermask"
id="path-effect51278"
is_visible="true"
lpeversion="1"
uri="#mask-powermask-path-effect51278"
invert="false"
hide_mask="false"
background="true"
background_color="#ffffffff" />
<inkscape:path-effect
effect="powermask"
id="path-effect51273"
is_visible="true"
lpeversion="1"
uri="#mask-powermask-path-effect51273"
invert="false"
hide_mask="false"
background="true"
background_color="#ffffffff" />
<inkscape:path-effect
effect="powermask"
id="path-effect48754"
is_visible="true"
lpeversion="1"
uri="#mask-powermask-path-effect48754"
invert="false"
hide_mask="false"
background="true"
background_color="#ffffffff" />
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath48972">
<path
style="fill:#000000;stroke-width:0.280643"
id="path48974"
width="56.128242"
height="56.128246"
x="-18.924671"
y="-56.198174"
transform="rotate(45.438374)"
mask="none"
sodipodi:type="rect" />
</clipPath>
<mask
maskUnits="userSpaceOnUse"
id="mask49405">
<text
xml:space="preserve"
style="font-size:60.8695px;line-height:1.25;font-family:Amiri;-inkscape-font-specification:Amiri;display:inline;stroke-width:1.52174"
x="66.930733"
y="78.642288"
id="text49409"
transform="scale(1.4861626,0.67287388)"><tspan
sodipodi:role="line"
id="tspan49407"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Tw Cen MT';-inkscape-font-specification:'Tw Cen MT';fill:#ffffff;stroke-width:1.52174"
x="66.930733"
y="78.642288">A</tspan></text>
</mask>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath50306">
<circle
style="mix-blend-mode:normal;fill:#d40000;stroke-width:0.176318"
id="circle50308"
cy="26.458334"
cx="26.458334"
r="26.458334"
clip-path="url(#clipPath48972)"
transform="matrix(1.0038771,0,0.00391255,1.0073928,-0.04603368,-0.1228191)" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath48972-7">
<path
style="fill:#000000;stroke-width:0.280643"
id="path48974-5"
width="56.128242"
height="56.128246"
x="-18.924671"
y="-56.198174"
transform="rotate(45.438374)"
mask="none"
sodipodi:type="rect" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath50306-6">
<circle
style="mix-blend-mode:normal;fill:#d40000;stroke-width:0.176318"
id="circle50308-5"
cy="26.458334"
cx="26.458334"
r="26.458334"
clip-path="url(#clipPath48972)"
transform="matrix(1.0038771,0,0.00391255,1.0073928,-0.04603368,-0.1228191)" />
</clipPath>
<mask
maskUnits="userSpaceOnUse"
id="mask-powermask-path-effect51273">
<path
style="fill:#000000"
id="path51263"
sodipodi:type="arc"
sodipodi:cx="66.211845"
sodipodi:cy="37.490814"
sodipodi:rx="3.9464016"
sodipodi:ry="1.4616301"
sodipodi:start="0"
sodipodi:end="0.031086059"
sodipodi:open="true"
sodipodi:arc-type="arc"
d="m 70.158247,37.490814 a 3.9464016,1.4616301 0 0 1 -0.0019,0.04543" />
</mask>
<mask
maskUnits="userSpaceOnUse"
id="mask-powermask-path-effect51278">
<path
style="fill:#000000"
id="path51267"
sodipodi:type="arc"
sodipodi:cx="66.211845"
sodipodi:cy="37.490814"
sodipodi:rx="3.9464016"
sodipodi:ry="1.4616301"
sodipodi:start="0"
sodipodi:end="0.031086059"
sodipodi:open="true"
sodipodi:arc-type="arc" />
</mask>
<mask
maskUnits="userSpaceOnUse"
id="mask-powermask-path-effect51283">
<path
style="fill:#000000"
id="path51271"
sodipodi:type="arc"
sodipodi:cx="66.211845"
sodipodi:cy="37.490814"
sodipodi:rx="3.9464016"
sodipodi:ry="1.4616301"
sodipodi:start="0"
sodipodi:end="0.031086059"
sodipodi:open="true"
sodipodi:arc-type="arc" />
</mask>
<filter
id="mask-powermask-path-effect51273_inverse"
inkscape:label="filtermask-powermask-path-effect51273"
style="color-interpolation-filters:sRGB"
height="100"
width="100"
x="-50"
y="-50">
<feColorMatrix
id="mask-powermask-path-effect51273_primitive1"
values="1"
type="saturate"
result="fbSourceGraphic" />
<feColorMatrix
id="mask-powermask-path-effect51273_primitive2"
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0 "
in="fbSourceGraphic" />
</filter>
</defs>
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="Red 1"
style="display:inline">
<circle
style="fill:#ff2a2a;stroke-width:0.176318"
id="path31-8"
cy="26.458334"
cx="26.458334"
r="26.458334" />
</g>
<g
inkscape:label="Black"
inkscape:groupmode="layer"
id="layer1"
style="display:inline">
<ellipse
style="fill:#000000;stroke-width:0.176146"
id="path31"
cy="26.51001"
cx="26.458334"
rx="26.458334"
ry="26.406658" />
<circle
style="display:inline;fill:#ffffff;stroke-width:0.176318"
id="path31-89"
cy="26.458334"
cx="126.45834"
r="26.458334"
mask="url(#mask49405)"
transform="translate(-99.990036,0.02979629)" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="A - Layer 2"
style="display:inline">
<rect
style="fill:#ffffff;stroke-width:0.328992"
id="rect48998"
width="26.0966"
height="6.0620313"
x="13.255443"
y="41.262722" />
</g>
<g
inkscape:groupmode="layer"
id="g48055"
inkscape:label="Red top"
style="display:inline;mix-blend-mode:normal">
<circle
style="mix-blend-mode:normal;fill:#d40000;stroke-width:0.176318"
id="circle48752"
cy="26.458334"
cx="26.458334"
r="26.458334"
clip-path="url(#clipPath48972)"
transform="matrix(1.0038771,0,0.00391255,1.0073928,-0.04603368,-0.1228191)" />
<ellipse
style="display:inline;mix-blend-mode:normal;fill:#000000;stroke-width:0.43638"
id="path50080"
clip-path="url(#clipPath50306)"
ry="13.739323"
rx="16.735666"
cy="22.874514"
cx="26.36149" />
<path
style="fill:#000000"
id="path51325"
sodipodi:type="arc"
sodipodi:cx="16.772207"
sodipodi:cy="26.090099"
sodipodi:rx="4.1291056"
sodipodi:ry="7.6004772"
sodipodi:start="0"
sodipodi:end="0.031086059"
sodipodi:arc-type="slice"
d="m 20.901313,26.090099 a 4.1291056,7.6004772 0 0 1 -0.002,0.236231 l -4.127111,-0.236231 z" />
<path
style="fill:#d40000"
id="path51717"
sodipodi:type="arc"
sodipodi:cx="26.441042"
sodipodi:cy="-26.531424"
sodipodi:rx="10.418671"
sodipodi:ry="9.5820541"
sodipodi:start="0.82219863"
sodipodi:end="2.3054129"
sodipodi:arc-type="slice"
d="m 33.532115,-19.511189 a 10.418671,9.5820541 0 0 1 -14.074736,0.09049 l 6.983663,-7.110726 z"
transform="matrix(1,0,0.0048047,-0.99998846,0,0)" />
<path
style="fill:#ffffff;stroke-width:0.276214"
d="M 145.28835,50.354872 C 127.01317,34.62734 98.057144,30.012421 73.710372,38.947003 c -6.518003,2.391924 -14.288822,6.834002 -19.265958,11.01311 -1.198654,1.006465 -2.270358,1.829935 -2.381565,1.829935 -0.111206,0 -5.210052,-5.102002 -11.33077,-11.337781 L 29.603503,29.114489 30.822139,27.851613 c 0.670251,-0.69458 2.51592,-2.384634 4.101489,-3.755674 C 50.725112,10.43241 69.462577,2.3767456 90.736164,0.10085492 95.380582,-0.39601422 106.33043,-0.31105699 111.03786,0.25837091 133.04363,2.9202648 151.46536,11.26468 167.83762,25.986722 l 3.30701,2.97369 -2.29392,2.320103 c -1.26165,1.276057 -6.58213,6.517685 -11.82329,11.648065 l -9.52936,9.327957 z"
id="path52311"
transform="scale(0.26458333)" />
<path
style="fill:#ffffff;stroke-width:0.276214"
d="M 86.40648,86.72667 73.376068,73.416681 74.667403,72.441306 c 4.72517,-3.569034 10.347316,-6.07197 16.730552,-7.448313 4.112758,-0.886786 12.327485,-0.880604 16.463455,0.01239 6.55399,1.415066 12.32233,4.049211 17.21441,7.861065 l 1.05592,0.822759 -1.33214,1.364507 c -0.73267,0.750478 -6.73901,6.678655 -13.34742,13.173726 l -12.015288,11.80922 z"
id="path52350"
transform="scale(0.26458333)"
inkscape:export-filename="C:\Users\jokob\path52350.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96" />
</g>
<g
inkscape:groupmode="layer"
id="layer6"
inkscape:label="Circle">
<path
style="fill:#000000"
id="path50026"
sodipodi:type="arc"
sodipodi:cx="71.071762"
sodipodi:cy="34.677177"
sodipodi:rx="1.7174155"
sodipodi:ry="5.5907354"
sodipodi:start="0"
sodipodi:end="0.031086059"
sodipodi:open="true"
sodipodi:arc-type="arc"
mask="url(#mask-powermask-path-effect51273)"
d="m 72.789178,34.677177 a 1.7174155,5.5907354 0 0 1 -8.3e-4,0.173766"
inkscape:path-effect="#path-effect51273" />
<path
style="fill:#ffffff;stroke-width:0.276214"
d="m 151.08883,181.46994 -2.76213,-2.60427 -48.802077,-0.009 -48.802075,-0.009 -2.292573,2.48592 c -1.260915,1.36726 -2.431589,2.48592 -2.601499,2.48592 -0.869396,0 -9.118995,-6.36599 -13.713669,-10.58246 l -2.688104,-2.46684 34.973647,-35.11455 c 19.235503,-19.313 35.0611,-35.11454 35.167986,-35.11454 0.106889,0 16.093094,15.82967 35.524894,35.17705 l 35.33055,35.17705 -2.48592,2.35505 c -3.08951,2.92687 -7.41515,6.40509 -11.09719,8.92319 -1.54594,1.05725 -2.85105,1.91728 -2.90024,1.9112 -0.0492,-0.006 -1.33242,-1.183 -2.8516,-2.61535 z m -38.4631,-38.32188 -13.050732,-13.05073 -13.050727,13.05073 -13.050725,13.05072 h 26.101452 26.101452 z"
id="path52389"
transform="scale(0.26458333)"
inkscape:export-filename="C:\Users\jokob\path52389.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96" />
<path
style="fill:#d40000;stroke-width:0.276214"
d="M 86.538548,86.634546 C 73.69451,73.514255 73.655832,73.471276 74.253912,72.984129 c 3.966911,-3.231117 10.195336,-6.133881 16.482252,-7.68157 2.339787,-0.576001 3.282272,-0.646986 8.700728,-0.655316 6.728828,-0.01035 8.365758,0.223077 13.326638,1.900338 4.59135,1.552325 7.8315,3.224336 11.49958,5.934101 l 1.61476,1.192897 -2.31005,2.336325 c -1.27053,1.284978 -7.22284,7.16236 -13.22736,13.060849 L 99.423152,99.796276 Z"
id="path52465"
transform="scale(0.26458333)" />
<path
style="fill:#d40000;stroke-width:0.276214"
d="M 145.01213,49.92143 C 129.67534,37.157691 107.61173,31.765107 86.040533,35.508132 73.800823,37.631961 63.910278,42.259414 52.74134,51.087703 l -0.683951,0.540616 -1.950068,-1.921684 C 49.034784,48.649709 44.035189,43.574887 38.997108,38.429251 l -9.160146,-9.355699 2.40156,-2.290793 C 39.310252,20.037198 49.728886,13.01193 58.630455,8.9867218 78.42597,0.03536962 99.380149,-2.3494504 120.42912,1.9533417 138.21485,5.5890676 153.70529,13.558756 168.1679,26.51451 l 2.71597,2.432989 -2.99218,3.016385 c -1.6457,1.65901 -6.90751,6.843636 -11.69291,11.521393 l -8.70072,8.505009 z"
id="path52504"
transform="scale(0.26458333)"
inkscape:export-filename="C:\Users\jokob\path52504.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,374 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="200"
height="200"
viewBox="0 0 52.916667 52.916668"
version="1.1"
id="svg5"
inkscape:version="1.1.2 (b8e25be833, 2022-02-05)"
sodipodi:docname="netalertx_red_1_backup_clened.svg"
inkscape:export-filename="C:\Users\jokob\netalertx_red_1.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="2.8284271"
inkscape:cx="132.22897"
inkscape:cy="118.44039"
inkscape:window-width="3440"
inkscape:window-height="1377"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer6"
units="px"
width="50px" />
<defs
id="defs2">
<inkscape:path-effect
effect="powermask"
id="path-effect51283"
is_visible="true"
lpeversion="1"
uri="#mask-powermask-path-effect51283"
invert="false"
hide_mask="false"
background="true"
background_color="#ffffffff" />
<inkscape:path-effect
effect="powermask"
id="path-effect51278"
is_visible="true"
lpeversion="1"
uri="#mask-powermask-path-effect51278"
invert="false"
hide_mask="false"
background="true"
background_color="#ffffffff" />
<inkscape:path-effect
effect="powermask"
id="path-effect51273"
is_visible="true"
lpeversion="1"
uri="#mask-powermask-path-effect51273"
invert="false"
hide_mask="false"
background="true"
background_color="#ffffffff" />
<inkscape:path-effect
effect="powermask"
id="path-effect48754"
is_visible="true"
lpeversion="1"
uri="#mask-powermask-path-effect48754"
invert="false"
hide_mask="false"
background="true"
background_color="#ffffffff" />
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath48972">
<path
style="fill:#000000;stroke-width:0.280643"
id="path48974"
width="56.128242"
height="56.128246"
x="-18.924671"
y="-56.198174"
transform="rotate(45.438374)"
mask="none"
sodipodi:type="rect" />
</clipPath>
<mask
maskUnits="userSpaceOnUse"
id="mask49405">
<text
xml:space="preserve"
style="font-size:60.8695px;line-height:1.25;font-family:Amiri;-inkscape-font-specification:Amiri;display:inline;stroke-width:1.52174"
x="66.930733"
y="78.642288"
id="text49409"
transform="scale(1.4861626,0.67287388)"><tspan
sodipodi:role="line"
id="tspan49407"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Tw Cen MT';-inkscape-font-specification:'Tw Cen MT';fill:#ffffff;stroke-width:1.52174"
x="66.930733"
y="78.642288">A</tspan></text>
</mask>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath50306">
<circle
style="mix-blend-mode:normal;fill:#d40000;stroke-width:0.176318"
id="circle50308"
cy="26.458334"
cx="26.458334"
r="26.458334"
clip-path="url(#clipPath48972)"
transform="matrix(1.0038771,0,0.00391255,1.0073928,-0.04603368,-0.1228191)" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath48972-7">
<path
style="fill:#000000;stroke-width:0.280643"
id="path48974-5"
width="56.128242"
height="56.128246"
x="-18.924671"
y="-56.198174"
transform="rotate(45.438374)"
mask="none"
sodipodi:type="rect" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath50306-6">
<circle
style="mix-blend-mode:normal;fill:#d40000;stroke-width:0.176318"
id="circle50308-5"
cy="26.458334"
cx="26.458334"
r="26.458334"
clip-path="url(#clipPath48972)"
transform="matrix(1.0038771,0,0.00391255,1.0073928,-0.04603368,-0.1228191)" />
</clipPath>
<mask
maskUnits="userSpaceOnUse"
id="mask-powermask-path-effect51273">
<path
id="mask-powermask-path-effect51273_box"
style="fill:#ffffff;fill-opacity:1"
d="m 71.788348,33.677177 h 2.00083 v 2.173766 h -2.00083 z" />
<path
style="fill:#000000"
id="path51263"
sodipodi:type="arc"
sodipodi:cx="66.211845"
sodipodi:cy="37.490814"
sodipodi:rx="3.9464016"
sodipodi:ry="1.4616301"
sodipodi:start="0"
sodipodi:end="0.031086059"
sodipodi:open="true"
sodipodi:arc-type="arc"
d="m 70.158247,37.490814 a 3.9464016,1.4616301 0 0 1 -0.0019,0.04543" />
</mask>
<mask
maskUnits="userSpaceOnUse"
id="mask-powermask-path-effect51278">
<path
style="fill:#000000"
id="path51267"
sodipodi:type="arc"
sodipodi:cx="66.211845"
sodipodi:cy="37.490814"
sodipodi:rx="3.9464016"
sodipodi:ry="1.4616301"
sodipodi:start="0"
sodipodi:end="0.031086059"
sodipodi:open="true"
sodipodi:arc-type="arc" />
</mask>
<mask
maskUnits="userSpaceOnUse"
id="mask-powermask-path-effect51283">
<path
style="fill:#000000"
id="path51271"
sodipodi:type="arc"
sodipodi:cx="66.211845"
sodipodi:cy="37.490814"
sodipodi:rx="3.9464016"
sodipodi:ry="1.4616301"
sodipodi:start="0"
sodipodi:end="0.031086059"
sodipodi:open="true"
sodipodi:arc-type="arc" />
</mask>
<filter
id="mask-powermask-path-effect51273_inverse"
inkscape:label="filtermask-powermask-path-effect51273"
style="color-interpolation-filters:sRGB"
height="100"
width="100"
x="-50"
y="-50">
<feColorMatrix
id="mask-powermask-path-effect51273_primitive1"
values="1"
type="saturate"
result="fbSourceGraphic" />
<feColorMatrix
id="mask-powermask-path-effect51273_primitive2"
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0 "
in="fbSourceGraphic" />
</filter>
</defs>
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="Red 1"
style="display:none">
<circle
style="fill:#ff2a2a;stroke-width:0.176318"
id="path31-8"
cy="26.458334"
cx="26.458334"
r="26.458334" />
</g>
<g
inkscape:label="Black"
inkscape:groupmode="layer"
id="layer1"
style="display:inline">
<ellipse
style="fill:#000000;stroke-width:0.176146"
id="path31"
cy="26.51001"
cx="26.458334"
rx="26.458334"
ry="26.406658" />
<circle
style="display:inline;fill:#ffffff;stroke-width:0.176318"
id="path31-89"
mask="url(#mask49405)"
transform="translate(-99.990036,0.02979629)"
r="26.458334"
cy="26.458334"
cx="126.45834" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="A - Layer 2"
style="display:none">
<rect
style="fill:#ffffff;stroke-width:0.328992"
id="rect48998"
width="26.0966"
height="6.0620313"
x="13.255443"
y="41.262722" />
</g>
<g
inkscape:groupmode="layer"
id="g48055"
inkscape:label="Red top"
style="display:none;mix-blend-mode:normal">
<circle
style="mix-blend-mode:normal;fill:#d40000;stroke-width:0.176318"
id="circle48752"
cy="26.458334"
cx="26.458334"
r="26.458334"
clip-path="url(#clipPath48972)"
transform="matrix(1.0038771,0,0.00391255,1.0073928,-0.04603368,-0.1228191)" />
<ellipse
style="display:inline;mix-blend-mode:normal;fill:#000000;stroke-width:0.43638"
id="path50080"
clip-path="url(#clipPath50306)"
ry="13.739323"
rx="16.735666"
cy="22.874514"
cx="26.36149"
transform="translate(0,0.09980904)" />
<path
style="fill:#000000"
id="path51325"
sodipodi:type="arc"
sodipodi:cx="16.772207"
sodipodi:cy="26.090099"
sodipodi:rx="4.1291056"
sodipodi:ry="7.6004772"
sodipodi:start="0"
sodipodi:end="0.031086059"
sodipodi:arc-type="slice"
d="m 20.901313,26.090099 a 4.1291056,7.6004772 0 0 1 -0.002,0.236231 l -4.127111,-0.236231 z" />
<path
style="fill:#d40000"
id="path51717"
sodipodi:type="arc"
sodipodi:cx="26.441042"
sodipodi:cy="-26.531424"
sodipodi:rx="10.418671"
sodipodi:ry="9.5820541"
sodipodi:start="0.82219863"
sodipodi:end="2.3054129"
sodipodi:arc-type="slice"
d="m 33.532115,-19.511189 a 10.418671,9.5820541 0 0 1 -14.074736,0.09049 l 6.983663,-7.110726 z"
transform="matrix(1,0,0.0048047,-0.99998846,0,0)" />
<path
style="fill:#ffffff;stroke-width:0.276214"
d="M 145.28835,50.354872 C 127.01317,34.62734 98.057144,30.012421 73.710372,38.947003 c -6.518003,2.391924 -14.288822,6.834002 -19.265958,11.01311 -1.198654,1.006465 -2.270358,1.829935 -2.381565,1.829935 -0.111206,0 -5.210052,-5.102002 -11.33077,-11.337781 L 29.603503,29.114489 30.822139,27.851613 c 0.670251,-0.69458 2.51592,-2.384634 4.101489,-3.755674 C 50.725112,10.43241 69.462577,2.3767456 90.736164,0.10085492 95.380582,-0.39601422 106.33043,-0.31105699 111.03786,0.25837091 133.04363,2.9202648 151.46536,11.26468 167.83762,25.986722 l 3.30701,2.97369 -2.29392,2.320103 c -1.26165,1.276057 -6.58213,6.517685 -11.82329,11.648065 l -9.52936,9.327957 z"
id="path52311"
transform="scale(0.26458333)" />
<path
style="fill:#ffffff;stroke-width:0.276214"
d="M 86.538548,86.634546 74.145111,73.25799 74.899337,72.758689 c 4.93766,-3.268754 10.138703,-6.508578 16.602198,-7.437693 5.484021,-0.788317 12.228205,-0.984814 16.377135,-0.09119 6.77689,1.459652 11.87156,4.340971 17.02452,7.792011 l 0.97468,0.652765 -1.37124,1.269268 c -0.86863,0.804036 -6.82647,6.676301 -13.34742,13.259175 L 99.423152,99.796276 Z"
id="path52350"
transform="scale(0.26458333)"
inkscape:export-filename="C:\Users\jokob\path52350.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
sodipodi:nodetypes="ccsssscsscc" />
</g>
<g
inkscape:groupmode="layer"
id="layer6"
inkscape:label="Circle"
style="display:inline">
<path
style="fill:#000000"
id="path50026"
sodipodi:type="arc"
sodipodi:cx="71.071762"
sodipodi:cy="34.677177"
sodipodi:rx="1.7174155"
sodipodi:ry="5.5907354"
sodipodi:start="0"
sodipodi:end="0.031086059"
sodipodi:open="true"
sodipodi:arc-type="arc"
mask="url(#mask-powermask-path-effect51273)"
d="m 72.789178,34.677177 a 1.7174155,5.5907354 0 0 1 -8.3e-4,0.173766"
inkscape:path-effect="#path-effect51273" />
<path
style="fill:#ffffff;stroke-width:0.276214"
d="m 151.08883,181.46994 -2.76213,-2.60427 -48.802077,-0.009 -48.802075,-0.009 -2.292573,2.48592 c -1.260915,1.36726 -2.431589,2.48592 -2.601499,2.48592 -0.869396,0 -9.118995,-6.36599 -13.713669,-10.58246 l -2.688104,-2.46684 34.973647,-35.11455 c 19.235503,-19.313 34.922993,-35.39075 35.029879,-35.39075 0.106889,0 16.231201,16.10588 35.663001,35.45326 l 35.33055,35.17705 -2.48592,2.35505 c -3.08951,2.92687 -7.41515,6.40509 -11.09719,8.92319 -1.54594,1.05725 -2.85105,1.91728 -2.90024,1.9112 -0.0492,-0.006 -1.33242,-1.183 -2.8516,-2.61535 z m -38.4631,-38.32188 -13.050732,-13.05073 -13.050727,13.05073 -13.050725,13.05072 h 26.101452 26.101452 z"
id="path52389"
transform="scale(0.26458333)"
inkscape:export-filename="C:\Users\jokob\path52389.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
sodipodi:nodetypes="ccccssscssscsscccccccccc" />
<path
style="fill:#d40000;stroke-width:0.276214"
d="M 86.416478,86.793237 C 73.427951,73.815968 73.387119,73.801376 73.387119,73.801376 c 3.874197,-3.341721 11.025508,-6.981646 17.312424,-8.529335 2.339787,-0.576001 4.881362,-1.25628 8.810591,-1.259564 4.438736,-0.0037 8.292516,0.857843 13.253396,2.535104 4.59135,1.552325 7.8315,3.224336 11.49958,5.934101 l 1.61476,1.192897 -2.31005,2.336325 c -1.27053,1.284978 -7.22284,7.16236 -13.22736,13.060849 L 99.423152,99.796276 C 95.128284,95.409033 87.282899,87.658907 86.416478,86.793237 Z"
id="path52465"
transform="scale(0.26458333)"
sodipodi:nodetypes="sssssscsscs" />
<path
style="fill:#d40000;stroke-width:0.074168"
d="M 38.412677,13.39572 C 34.322163,9.945267 28.437517,8.4874766 22.684204,9.4993379 19.419721,10.073478 16.752307,11.410793 13.835187,13.872492 l -0.14691,0.126732 -0.587936,-0.661605 c -0.268568,-0.30222 -1.619514,-1.65761 -2.963235,-3.048642 L 7.7265561,7.8632145 7.9975963,7.5868118 C 9.8344314,5.713635 13.005888,3.476019 15.380049,2.3878744 20.659765,-0.03196726 26.24205,-0.73479764 31.856076,0.42838695 36.599757,1.4112419 40.746004,3.5106537 44.46876,7.1557672 l 0.709881,0.6950753 -0.663694,0.69037 C 44.080041,8.9935983 42.672626,10.391271 41.3963,11.655819 L 39.075708,13.955 Z"
id="path52504"
inkscape:export-filename="C:\Users\jokob\path52504.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
sodipodi:nodetypes="ssscsccsssscsscs" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -3,11 +3,13 @@
<?php
require dirname(__FILE__).'/php/server/init.php';
require 'php/templates/security.php';
//------------------------------------------------------------------------------
// check if authenticated
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
$CookieSaveLoginName = 'NetAlertX_SaveLogin';
if ($Pia_WebProtection != 'true')
if ($nax_WebProtection != 'true')
{
header('Location: devices.php');
$_SESSION["login"] = 1;
@@ -24,7 +26,7 @@ if (isset ($_GET["action"]) && $_GET["action"] == 'logout')
}
// Password without Cookie check -> pass and set initial cookie
if (isset ($_POST["loginpassword"]) && $Pia_Password == hash('sha256',$_POST["loginpassword"]))
if (isset ($_POST["loginpassword"]) && $nax_Password == hash('sha256',$_POST["loginpassword"]))
{
header('Location: devices.php');
$_SESSION["login"] = 1;
@@ -32,7 +34,7 @@ if (isset ($_POST["loginpassword"]) && $Pia_Password == hash('sha256',$_POST["lo
}
// active Session or valid cookie (cookie not extends)
if (( isset ($_SESSION["login"]) && ($_SESSION["login"] == 1)) || (isset ($_COOKIE[$CookieSaveLoginName]) && $Pia_Password == $_COOKIE[$CookieSaveLoginName]))
if (( isset ($_SESSION["login"]) && ($_SESSION["login"] == 1)) || (isset ($_COOKIE[$CookieSaveLoginName]) && $nax_Password == $_COOKIE[$CookieSaveLoginName]))
{
header('Location: devices.php');
$_SESSION["login"] = 1;
@@ -40,7 +42,7 @@ if (( isset ($_SESSION["login"]) && ($_SESSION["login"] == 1)) || (isset ($_COOK
}
$login_headline = lang('Login_Toggle_Info_headline');
$login_info = "";
$login_info = lang('Login_Info');
$login_mode = 'danger';
$login_display_mode = 'display: block;';
$login_icon = 'fa-info';
@@ -48,7 +50,7 @@ $login_icon = 'fa-info';
// no active session, cookie not checked
if (isset ($_SESSION["login"]) == FALSE || $_SESSION["login"] != 1)
{
if ($Pia_Password == '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92')
if ($nax_Password == '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92')
{
$login_info = lang('Login_Default_PWD');
$login_mode = 'danger';
@@ -78,7 +80,7 @@ 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>Net Alert X | Log in</title>
<title>NetAlert 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 -->
@@ -91,6 +93,13 @@ if (isset ($_SESSION["login"]) == FALSE || $_SESSION["login"] != 1)
<link rel="stylesheet" href="lib/AdminLTE/dist/css/AdminLTE.min.css">
<!-- iCheck -->
<link rel="stylesheet" href="lib/AdminLTE/plugins/iCheck/square/blue.css">
<!-- Font Awesome -->
<link rel="stylesheet" href="lib/AdminLTE/bower_components/font-awesome/css/fontawesome.min.css">
<link rel="stylesheet" href="lib/AdminLTE/bower_components/font-awesome/css/solid.css">
<link rel="stylesheet" href="lib/AdminLTE/bower_components/font-awesome/css/brands.css">
<link rel="stylesheet" href="lib/AdminLTE/bower_components/font-awesome/css/v5-font-face.css">
<!-- Favicon -->
<link id="favicon" rel="icon" type="image/x-icon" href="img/NetAlertX_logo.png">
<!-- Dark-Mode Patch -->
<?php
@@ -104,7 +113,7 @@ if ($ENABLED_DARKMODE === True) {
<body class="hold-transition login-page">
<div class="login-box login-custom">
<div class="login-logo">
<a href="/index2.php">Net <b>Alert</b><sup>x</sup></a>
<a href="/index2.php">Net<b>Alert</b><sup>x</sup></a>
</div>
<!-- /.login-logo -->
<div class="login-box-body">
@@ -140,11 +149,9 @@ if ($ENABLED_DARKMODE === True) {
</div>
<!-- /.login-box-body -->
<div id="myDIV" class="box-body" style="margin-top: 50px; <?php echo $login_display_mode;?>">
<div class="alert alert-<?php echo $login_mode;?> alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true"><EFBFBD></button>
<button type="button" class="close" onclick="Passwordhinfo()" aria-hidden="true">X</button>
<h4><i class="icon fa <?php echo $login_icon;?>"></i><?php echo $login_headline;?></h4>
<p><?php echo $login_info;?></p>
</div>

View File

@@ -10,9 +10,10 @@
// -----------------------------------------------------------------------------
var timerRefreshData = ''
var emptyArr = ['undefined', "", undefined, null, 'null'];
var UI_LANG = "English";
var settingsJSON = {}
var emptyArr = ['undefined', "", undefined, null, 'null'];
var UI_LANG = "English";
const allLanguages = ["en_us", "es_es", "de_de", "fr_fr", "it_it", "ru_ru", "nb_no", "pl_pl", "pt_br", "tr_tr", "zh_cn", "cs_cz", "ar_ar"]; // needs to be same as in lang.php
var settingsJSON = {}
// -----------------------------------------------------------------------------
@@ -124,8 +125,10 @@ function cacheSettings()
settingsData.forEach((set) => {
resolvedOptions = createArray(set.Options)
resolvedOptionsOld = resolvedOptions
setPlugObj = {};
options_params = [];
resolved = ""
// proceed only if first option item contains something to resolve
if( !set.Code_Name.includes("__metadata") &&
@@ -158,7 +161,7 @@ function cacheSettings()
}
}
setCache(`pia_set_${set.Code_Name}`, set.Value)
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
@@ -179,6 +182,7 @@ function getSettingOptions (key) {
if (result == "")
{
console.log(`Setting options with key "${key}" not found`)
result = []
}
return result;
@@ -204,101 +208,146 @@ function getSetting (key) {
// -----------------------------------------------------------------------------
// Get language string
// -----------------------------------------------------------------------------
function cacheStrings()
{
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
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
// Create a promise for each language
languagesToLoad = ['en_us', getLangCode()]
const languagePromises = languagesToLoad.map((language_code) => {
return new Promise((resolveLang, rejectLang) => {
// Fetch core strings and translations
$.get(`php/templates/language/${language_code}.json?nocache=${Date.now()}`)
.done((res) => {
// Iterate over each key-value pair and store the translations
Object.entries(res).forEach(([key, value]) => {
setCache(`pia_lang_${key}_${language_code}`, value);
});
// Fetch strings and translations from plugins
$.get(`api/table_plugins_language_strings.json?nocache=${Date.now()}`)
.done((pluginRes) => {
const data = pluginRes["data"];
// Store plugin translations
data.forEach((langString) => {
setCache(`pia_lang_${langString.String_Key}_${langString.Language_Code}`, langString.String_Value);
});
// Handle successful completion of language processing
handleSuccess(`cacheStrings[${language_code}]`, resolveLang);
})
.fail((pluginError) => {
// Handle failure in plugin strings fetching
rejectLang(pluginError);
});
})
.fail((error) => {
// Handle failure in core strings fetching
rejectLang(error);
});
});
});
}
// Wait for all language promises to complete
Promise.all(languagePromises)
.then(() => {
// All languages processed successfully
resolve();
})
.catch((error) => {
// Handle failure in any of the language processing
handleFailure('cacheStrings', reject);
});
});
}
// -----------------------------------------------------------------------------
// Get translated language string
function getString (key) {
function getString(key) {
// handle initial load to make sure everything is set-up and cached
handleFirstLoad(getString)
UI_LANG = getSetting("UI_LANG");
function fetchString(key) {
lang_code = getLangCode();
lang_code = 'en_us';
let result = getCache(`pia_lang_${key}_${lang_code}`, true);
switch(UI_LANG)
{
case 'English':
lang_code = 'en_us';
break;
case 'Spanish':
lang_code = 'es_es';
break;
case 'German':
lang_code = 'de_de';
break;
case 'French':
lang_code = 'fr_fr';
break;
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);
if (isEmpty(result)) {
result = getCache(`pia_lang_${key}_en_us`, true);
}
if(isEmpty(result))
{
result = getCache(`pia_lang_${key}_en_us`, true);
return result;
}
return result;
if (isAppInitialized()) {
return fetchString(key);
} else {
callAfterAppInitialized(() => fetchString(key));
}
}
// -----------------------------------------------------------------------------
// Get current language ISO code
// below has to match exactly teh values in /front/php/templates/language/lang.php & /front/js/common.js
function getLangCode() {
UI_LANG = getSetting("UI_LANG");
let lang_code = 'en_us';
switch (UI_LANG) {
case 'English':
lang_code = 'en_us';
break;
case 'Spanish':
lang_code = 'es_es';
break;
case 'German':
lang_code = 'de_de';
break;
case 'French':
lang_code = 'fr_fr';
break;
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;
case 'Czech (cs_cz)':
lang_code = 'cs_cz';
break;
case 'Arabic (ar_ar)':
lang_code = 'ar_ar';
break;
}
return lang_code;
}
// -----------------------------------------------------------------------------
// String utilities
// -----------------------------------------------------------------------------
// ----------------------------------------------------
function jsonSyntaxHighlight(json) {
if (typeof json != 'string') {
json = JSON.stringify(json, undefined, 2);
@@ -321,6 +370,7 @@ function jsonSyntaxHighlight(json) {
});
}
// ----------------------------------------------------
function isValidBase64(str) {
// Base64 characters set
var base64CharacterSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
@@ -330,6 +380,46 @@ function isValidBase64(str) {
return invalidCharacters === '';
}
// ----------------------------------------------------
function isValidJSON(jsonString) {
try {
JSON.parse(jsonString);
return true;
} catch (e) {
return false;
}
}
// ----------------------------------------------------
// method to sanitize input so that HTML and other things don't break
function encodeSpecialChars(str) {
return str
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;');
}
// ----------------------------------------------------
function decodeSpecialChars(str) {
return str
.replace(/&amp;/g, '&')
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&quot;/g, '"')
.replace(/&#039;/g, '\'');
}
// ----------------------------------------------------
// base64 conversion of UTF8 chars
function utf8ToBase64(str) {
// Convert the string to a Uint8Array using TextEncoder
const utf8Bytes = new TextEncoder().encode(str);
// Convert the Uint8Array to a base64-encoded string
return btoa(String.fromCharCode(...utf8Bytes));
}
// -----------------------------------------------------------------------------
// General utilities
@@ -358,6 +448,7 @@ function handle_locked_DB(data)
showSpinner()
setTimeout(function() {
console.warn("Database locked - reload")
location.reload();
}, 5000);
}
@@ -370,29 +461,6 @@ function numberArrayFromString(data)
return data.replace(/\[|\]/g, '').split(',').map(Number);
}
// -----------------------------------------------------------------------------
function setParameter (parameter, value) {
// Retry
$.get('php/server/parameters.php?action=set&parameter=' + parameter +
'&value='+ value,
function(data) {
if (data != "OK") {
// Retry
sleep (200);
$.get('php/server/parameters.php?action=set&parameter=' + parameter +
'&value='+ value,
function(data) {
if (data != "OK") {
// alert (data);
} else {
// alert ("OK. Second attempt");
};
} );
};
} );
}
// -----------------------------------------------------------------------------
function saveData(functionName, id, value) {
$.ajax({
@@ -577,17 +645,11 @@ function debugTimer () {
// -----------------------------------------------------------------------------
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;
// Get the current time since the page was loaded
var timeSincePageLoad = performance.now();
// Convert milliseconds to seconds
var secondsAgo = Math.floor(timeDifference / 1000);
var secondsAgo = Math.floor(timeSincePageLoad / 1000);
return secondsAgo;
}
@@ -628,7 +690,7 @@ function openUrl(urls) {
// -----------------------------------------------------------------------------
function navigateToDeviceWithIp (ip) {
$.get('api/table_devices.json', function(res) {
$.get('api/table_devices.json?nocache=' + Date.now(), function(res) {
devices = res["data"];
@@ -649,7 +711,7 @@ function navigateToDeviceWithIp (ip) {
// -----------------------------------------------------------------------------
function getNameByMacAddress(macAddress) {
return getDeviceDataByMacAddress(macAddress, "dev_Name")
return getDeviceDataByMac(macAddress, "dev_Name")
}
// -----------------------------------------------------------------------------
@@ -743,10 +805,14 @@ function isRandomMAC(mac)
// ---------------------------------------------------------
// Generate an array object from a string representation of an array
function createArray(input) {
// Empty array
if (input === '[]') {
return [];
// Is already array, return
if (Array.isArray(input)) {
return input;
}
// Empty array
if (input === '[]' || input === '') {
return [];
}
// Regex pattern for brackets
const patternBrackets = /(^\s*\[)|(\]\s*$)/g;
@@ -798,7 +864,7 @@ function isRandomMAC(mac)
// -----------------------------------------------------------------------------
// A function to get a device property using the mac address as key and DB column nakme as parameter
// for the value to be returned
function getDeviceDataByMacAddress(macAddress, dbColumn) {
function getDeviceDataByMac(macAddress, dbColumn) {
const sessionDataKey = 'devicesListAll_JSON';
const devicesCache = getCache(sessionDataKey);
@@ -813,7 +879,14 @@ function getDeviceDataByMacAddress(macAddress, dbColumn) {
for (const device of devices) {
if (device["dev_MAC"].toLowerCase() === macAddress.toLowerCase()) {
if(dbColumn)
{
return device[dbColumn];
}
else
{
return device
}
}
}
@@ -821,15 +894,15 @@ function getDeviceDataByMacAddress(macAddress, dbColumn) {
}
// -----------------------------------------------------------------------------
// Cache teh devices as one JSON
// Cache the devices as one JSON
function cacheDevices()
{
return new Promise((resolve, reject) => {
if(!getCache('completedCalls').includes('cacheDevices'))
{
$.get('api/table_devices.json', function(data) {
// if(!getCache('completedCalls').includes('cacheDevices'))
// {
$.get('api/table_devices.json?nocache=' + Date.now(), function(data) {
// console.log(data)
@@ -852,7 +925,8 @@ function cacheDevices()
// 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
@@ -904,6 +978,8 @@ function showSpinner(stringKey='Loading')
text = getString(stringKey)
}
text = isEmpty(text) ? "Loading" : text;
if($("#loadingSpinner").length)
{
$("#loadingSpinner").show();
@@ -934,11 +1010,12 @@ function hideSpinner()
// --------------------------------------------------------
// Calls a backend function to add a front-end event to an execution queue
function updateApi()
function updateApi(apiEndpoints)
{
// value has to be in format event|param. e.g. run|ARPSCAN
action = `update_api|devices,appevents`
action = `${getGuid()}|update_api|${apiEndpoints}`
$.ajax({
method: "POST",
@@ -1078,6 +1155,54 @@ function arraysContainSameValues(arr1, arr2) {
}
}
// -----------------------------------------------------------------------------
// 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()
}
});
}
}
// -----------------------------------------------------------------------------
// apply dark mode
$(document).ready(function() {
// Assume getSetting is a function that returns true or false for dark mode
if (getSetting("UI_dark_mode") === "True") {
// Add the dark mode stylesheet
setCookie("UI_dark_mode", "True")
$('head').append('<link rel="stylesheet" href="css/dark-patch.css">');
// Set the background image for dark mode
$('body').attr('style', 'background-image: url(\'img/boxed-bg-dark.png\');');
} else {
setCookie("UI_dark_mode", "False")
// Set the background image for light mode
$('body').attr('style', 'background-image: url(\'img/background.png\');');
}
});
// -----------------------------------------------------------------------------
// initialize
// -----------------------------------------------------------------------------
@@ -1087,6 +1212,8 @@ function arraysContainSameValues(arr1, arr2) {
const sessionStorageKey = "myScriptExecuted_common_js";
var completedCalls = []
var completedCalls_final = ['cacheSettings', 'cacheStrings', 'cacheDevices'];
var completedCallsCount = 0;
var completedCallsCount_final;
// -----------------------------------------------------------------------------
// Clearing all the caches
@@ -1095,8 +1222,9 @@ function clearCache() {
sessionStorage.clear();
localStorage.clear();
setTimeout(() => {
window.location.reload();
}, 500);
console.warn("clearChache called");
window.location.reload();
}, 500);
}
// -----------------------------------------------------------------------------
@@ -1124,10 +1252,28 @@ async function handleFirstLoad(callback) {
}
}
// -----------------------------------------------------------------------------
// Execute callback once app initialized
function callAfterAppInitialized(callback) {
if (!isAppInitialized()) {
setTimeout(() => {
callAfterAppInitialized(callback)
}, 500);
} else
{
callback();
}
}
// -----------------------------------------------------------------------------
// Check if the code has been executed before by checking sessionStorage
function isAppInitialized() {
return arraysContainSameValues(getCache("completedCalls").split(',').filter(Boolean), completedCalls_final);
// return arraysContainSameValues(getCache("completedCalls").split(',').filter(Boolean), completedCalls_final);
// loading settings + 1 (or 2 language files if not english) + device cache.
completedCallsCount_final = getLangCode() == 'en_us' ? 3 : 4 ;
return (parseInt(getCache("completedCallsCount")) >= completedCallsCount_final);
}
// Define a function that will execute the code only once
@@ -1136,9 +1282,10 @@ async function executeOnce() {
if (!isAppInitialized()) {
try {
await cacheStrings();
await cacheSettings();
await cacheDevices();
await cacheSettings();
await cacheStrings();
console.log("✅ All AJAX callbacks have completed");
onAllCallsComplete();
} catch (error) {
@@ -1151,8 +1298,20 @@ async function executeOnce() {
// Function to handle successful completion of an AJAX call
const handleSuccess = (callName) => {
console.log(`AJAX call successful: ${callName}`);
completedCalls.push(callName);
setCache('completedCalls', mergeUniqueArrays(getCache('completedCalls').split(','), [callName]));
// completedCalls.push(callName);
// setCache('completedCalls', mergeUniqueArrays(getCache('completedCalls').split(','), [callName]));
val = getCache('completedCallsCount');
if(val == "")
{
val = 0;
} else
{
val = parseInt(val)
}
setCache('completedCallsCount', val + 1)
};
// -----------------------------------------------------------------------------
@@ -1175,6 +1334,10 @@ const onAllCallsComplete = () => {
sessionStorage.setItem(sessionStorageKey + '_time', millisecondsNow);
console.log('✔ Cache initialized');
// setTimeout(() => {
// location.reload()
// }, 10);
} else {
// If not all strings are initialized, retry initialization
console.log('❌ Not all strings are initialized. Retrying...');
@@ -1184,25 +1347,25 @@ const onAllCallsComplete = () => {
// 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') != ""
return getString('UI_LANG_name') != ""
};
// Call the function to execute the code
executeOnce();
// Set timer for regular checks
// Set timer for regular UI refresh if enabled
setTimeout(() => {
// page refresh if configured
const refreshTime = getSetting("UI_REFRESH");
if (refreshTime && refreshTime !== "0" && refreshTime !== "") {
console.log("Refreshing page becasue UI_REFRESH setting enabled.");
newTimerRefreshData(clearCache, parseInt(refreshTime)*1000);
}

View File

@@ -2,51 +2,108 @@
// General utilities to interact with the database
// -----------------------------------------------------------------------------
// // Call to render lists
// renderList(
// options,
// callbackToGenerateEntries,
// valuesArray,
// placeholder,
// targetField,
// transformers
// );
// --------------------------------------------------
// Read data and place intotarget location, callback processies the results
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
function renderList(
options,
processDataCallback,
valuesArray,
placeholder,
targetField,
transformers
) {
// Check if there are options provided
if (options.length > 0) {
// Determine if the first option's name is an SQL query
const sqlQuery = isSQLQuery(options[0].name) ? options[0].name : "";
data = JSON.parse(data)
// If there is an SQL query, fetch additional options
if (sqlQuery) {
// remove first item containing the SQL query
options.shift();
var htmlResult = processDataCallback(data, valuesArray, targetField, nameTransformer);
const apiUrl = `php/server/dbHelper.php?action=read&rawSql=${encodeURIComponent(sqlQuery)}`;
// Place the resulting HTML into the specified placeholder div
$("#" + targetLocation).replaceWith(htmlResult);
});
$.get(apiUrl, function (sqlOptionsData) {
// Parse the returned SQL data
const sqlOption = JSON.parse(sqlOptionsData);
// Concatenate options from SQL query with the supplied options
options = options.concat(sqlOption);
// Process the combined options
setTimeout(() => {
processDataCallback(
options,
valuesArray,
targetField,
transformers,
placeholder
);
}, 1);
});
} else {
// No SQL query, directly process the supplied options
setTimeout(() => {
processDataCallback(
options,
valuesArray,
targetField,
transformers,
placeholder
);
}, 1);
}
} else {
// No options provided, directly process with empty options
setTimeout(() => {
processDataCallback(
options,
valuesArray,
targetField,
transformers,
placeholder
);
}, 1);
}
}
// --------------------------------------------------
// 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()
}
});
$.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

@@ -1,13 +1,17 @@
function pia_draw_graph_online_history(pia_js_graph_online_history_time, pia_js_graph_online_history_ondev, pia_js_graph_online_history_dodev, pia_js_graph_online_history_ardev) {
var xValues = pia_js_graph_online_history_time;
// alert("dev presence")
function presenceOverTime(
timeStamp,
onlineCount,
offlineCount,
archivedCount,
downCount
) {
var xValues = timeStamp;
// Data object for online status
onlineData = {
label: 'Online',
data: pia_js_graph_online_history_ondev,
borderColor: "rgba(0, 166, 89)",
data: onlineCount,
borderColor: "#00000",
fill: true,
backgroundColor: "rgba(0, 166, 89, .6)",
pointStyle: 'circle',
@@ -15,20 +19,29 @@ function pia_draw_graph_online_history(pia_js_graph_online_history_time, pia_js_
pointHoverRadius: 3
};
// Data object for down status
downData = {
label: 'Down',
data: downCount,
borderColor: "#00000",
fill: true,
backgroundColor: "#dd4b39",
};
// Data object for offline status
offlineData = {
label: 'Offline/Down',
data: pia_js_graph_online_history_dodev,
borderColor: "rgba(222, 74, 56)",
label: 'Offline',
data: offlineCount,
borderColor: "#00000",
fill: true,
backgroundColor: "rgba(222, 74, 56, .6)",
backgroundColor: "#b2b6be",
};
// Data object for archived status
archivedData = {
label: 'Archived',
data: pia_js_graph_online_history_ardev,
borderColor: "rgba(220,220,220)",
data: archivedCount,
borderColor: "#00000",
fill: true,
backgroundColor: "rgba(220,220,220, .6)",
};
@@ -42,23 +55,27 @@ function pia_draw_graph_online_history(pia_js_graph_online_history_time, pia_js_
// Check if 'online' status should be displayed
if(showStats.includes("online"))
{
datasets.push(onlineData); // Add onlineData to datasets array
datasets.push(onlineData);
}
// Check if 'down' status should be displayed
if(showStats.includes("down"))
{
datasets.push(downData);
}
// Check if 'offline' status should be displayed
if(showStats.includes("offline"))
{
datasets.push(offlineData); // Add offlineData to datasets array
datasets.push(offlineData);
}
// Check if 'archived' status should be displayed
if(showStats.includes("archived"))
{
datasets.push(archivedData); // Add archivedData to datasets array
datasets.push(archivedData);
}
new Chart("OnlineChart", {
type: "bar",
scaleIntegersOnly: true,

View File

@@ -242,6 +242,18 @@ $(document).ready(function () {
});
// -----------------------------------------------------------------------------
// Escape text
function safeDecodeURIComponent(content) {
try {
return decodeURIComponent(content);
} catch (error) {
console.warn('Failed to decode URI component:', error);
return content; // Return the original content if decoding fails
}
}
// -----------------------------------------------------------------------------
// Backend notification Polling
// -----------------------------------------------------------------------------
@@ -266,7 +278,9 @@ function checkNotification() {
if (oldestInterruptNotification) {
// Show modal dialog with the oldest unread notification
const decodedContent = JSON.parse(decodeURIComponent(oldestInterruptNotification.content));
console.log(oldestInterruptNotification.content);
const decodedContent = safeDecodeURIComponent(oldestInterruptNotification.content);
showModalOK("Notification", decodedContent, function() {
// Mark the notification as read
@@ -281,6 +295,7 @@ function checkNotification() {
console.log(response);
// After marking the notification as read, check for the next one
checkNotification();
hideSpinner();
},
error: function(xhr, status, error) {
console.error("Error marking notification as read:", status, error);
@@ -337,7 +352,7 @@ const phpEndpoint = 'php/server/utilNotification.php';
// --------------------------------------------------
// Write a notification
function writeNotification(content, level) {
function write_notification(content, level) {
$.ajax({
url: phpEndpoint, // Change this to the path of your PHP script

File diff suppressed because it is too large Load Diff

View File

@@ -11,16 +11,7 @@
// -----------------------------------------------------------------------------
// Initialize device selectors / pickers fields
// -----------------------------------------------------------------------------
function initDeviceSelectors() {
// console.log(devicesList)
// Retrieve device list from session variable
var devicesListAll_JSON = getCache('devicesListAll_JSON');
var devicesList = JSON.parse(devicesListAll_JSON);
// console.log(devicesList);
function initDeviceSelectors(devicesListAll_JSON) {
// Check if both device list exists
if (devicesListAll_JSON) {
@@ -77,173 +68,66 @@ function initDeviceSelectors() {
}
// -----------------------------------------------------------------------------
// 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 the name (e.g. base64)
{
var optionsHtml = ""
// 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]))
{
readData(optionsArray[0], callbackToGenerateEntries, valuesArray, targetLocation, targetField, nameTransformer);
} else // this should be already an array, e.g. from a setting or pre-defined
{
optionsArray.forEach(option => {
let selected = valuesArray.includes(option) ? 'selected' : '';
optionsHtml += `<option value="${option}" ${selected}>${option}</option>`;
});
// Replace the specified placeholder div with the resulting HTML
setTimeout(() => {
$("#" + targetLocation).replaceWith(optionsHtml);
}, 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
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// Processor to generate options for a dropdown menu
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}>${labelName}</option>`;
});
return `${optionsHtml}`;
}
// -----------------------------------------------------------------------------
// Processor to generate a list
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' : '';
// 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>`;
});
return listHtml;
}
// -----------------------------------------------------------------------------
// ----------------------------------------------
// Updates the icon preview
function updateIconPreview (inputId) {
// update icon
iconInput = $(inputId)
function updateIconPreview(elem) {
// Retrieve and parse custom parameters from the element
let params = $(elem).attr("my-customparams")?.split(',').map(param => param.trim());
value = iconInput.val()
// console.log(params);
iconInput.on('change input', function() {
$('#txtIconFA').html(atob(value))
});
if (params && params.length >= 2) {
var inputElementID = params[0];
var targetElementID = params[1];
} else {
console.error("Invalid parameters passed to updateIconPreview function");
return;
}
$('#txtIconFA').html(atob(value))
// Get the input element using the inputElementID
let iconInput = $("#" + inputElementID);
if (iconInput.length === 0) {
console.error("Icon input element not found");
return;
}
// Get the initial value and update the target element
let value = iconInput.val();
if (!value) {
console.error("Input value is empty or not defined");
return;
}
if (!targetElementID) {
targetElementID = "txtIcon";
}
// Check if the target element exists, if not find an element with matching custom attribute
let targetElement = $('#' + targetElementID);
if (targetElement.length === 0) {
// Look for an element with my-custom-id attribute equal to targetElementID
targetElement = $('[my-customid="' + targetElementID + '"]');
if (targetElement.length === 0) {
console.error("Neither target element with ID nor element with custom attribute found");
return;
}
}
// Update the target element with decoded base64 value
targetElement.html(atob(value));
// Add event listener to update the icon on input change
iconInput.on('change input', function () {
let newValue = $(this).val();
$('#' + targetElementID).html(atob(newValue));
});
}
// -----------------------------------------------------------------------------
// Generic function to copy text to clipboard
function copyToClipboard(buttonElement) {
@@ -270,47 +154,156 @@ function copyToClipboard(buttonElement) {
}
}
// -----------------------------------------------------------------------------
// Simple Sortable Table columns
// -----------------------------------------------------------------------------
function sortColumn(element) {
var th = $(element).closest('th');
var table = th.closest('table');
var columnIndex = th.index();
var ascending = !th.data('asc');
sortTable(table, columnIndex, ascending);
th.data('asc', ascending);
}
function sortTable(table, columnIndex, ascending) {
var tbody = table.find('tbody');
var rows = tbody.find('tr').toArray().sort(comparer(columnIndex));
if (!ascending) {
rows = rows.reverse();
}
for (var i = 0; i < rows.length; i++) {
tbody.append(rows[i]);
}
}
function comparer(index) {
return function(a, b) {
var valA = getCellValue(a, index);
var valB = getCellValue(b, index);
return $.isNumeric(valA) && $.isNumeric(valB) ? valA - valB : valA.localeCompare(valB);
};
}
function getCellValue(row, index) {
return $(row).children('td').eq(index).text();
}
// -----------------------------------------------------------------------------
// 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_settingEvent(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);
}
// -----------------------------------------------------------------------------
// initialize
// -----------------------------------------------------------------------------
function initSelect2() {
setTimeout(() => {
// Retrieve device list from session variable
var devicesListAll_JSON = getCache('devicesListAll_JSON');
initDeviceSelectors();
// check if cache ready
if(isValidJSON(devicesListAll_JSON))
{
// prepare HTML DOM before initializing the frotend
initDeviceSelectors(devicesListAll_JSON)
// --------------------------------------------------------
//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');
}
});
// --------------------------------------------------------
//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);
} else // cache not ready try later
{
setTimeout(() => {
initSelect2()
}, 1000);
}
}
// init select2 after dom laoded
window.addEventListener("load", function() {
// try to initialize select2
setTimeout(() => {
initSelect2()
}, 1000);
});
console.log("init ui_components.js")

View File

@@ -1034,7 +1034,7 @@ var mouse = $.widget("ui.mouse", {
return this.mouseDelayMet;
},
// These are placeholder methods, to be overriden by extending plugin
// These are placeholder methods, to be overridden by extending plugin
_mouseStart: function(/* event */) {},
_mouseDrag: function(/* event */) {},
_mouseStop: function(/* event */) {},

View File

@@ -11,25 +11,7 @@
# cvc90 2023 https://github.com/cvc90 GNU GPLv3 #
#---------------------------------------------------------------------------------#
// Skin selector config ----------------------------------------------------
//
// For security reasons, new language files must be entered into this array.
// The files in the language directory are compared with this array and only
// then accepted.
//
$pia_installed_skins = array('skin-black-light',
'skin-black',
'skin-blue-light',
'skin-blue',
'skin-green-light',
'skin-green',
'skin-purple-light',
'skin-purple',
'skin-red-light',
'skin-red',
'skin-yellow-light',
'skin-yellow');
//------------------------------------------------------------------------------
?>
@@ -38,7 +20,7 @@ $pia_installed_skins = array('skin-black-light',
require 'php/templates/header.php';
?>
<!-- Page ------------------------------------------------------------------ -->
<div class="content-wrapper">
<div class="content-wrapper" id="maintenancePage">
<!-- Content header--------------------------------------------------------- -->
<section class="content-header">
@@ -57,74 +39,17 @@ $pia_installed_skins = array('skin-black-light',
// Size and last mod of 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));
$nax_db = str_replace('front', 'db', getcwd()).'/app.db';
$nax_db_size = number_format((filesize($nax_db) / 1000000),2,",",".") . ' MB';
$nax_db_mod = date ("F d Y H:i:s", filemtime($nax_db));
// Count and Calc Backups -------------------------------------------------------
$Pia_Archive_Path = str_replace('front', 'db', getcwd()).'/';
$Pia_Archive_count = 0;
$Pia_Archive_diskusage = 0;
$files = glob($Pia_Archive_Path."appdb_*.zip");
if ($files){
$Pia_Archive_count = count($files);
}
foreach ($files as $result) {
$Pia_Archive_diskusage = $Pia_Archive_diskusage + filesize($result);
}
$Pia_Archive_diskusage = number_format(($Pia_Archive_diskusage / 1000000),2,",",".") . ' MB';
// Find latest Backup for restore -----------------------------------------------
$latestfiles = glob($Pia_Archive_Path."appdb_*.zip");
natsort($latestfiles);
$latestfiles = array_reverse($latestfiles,False);
$latestbackup = 'none';
$latestbackup_date = 'no backup';
if (count($latestfiles) > 0)
{
$latestbackup = $latestfiles[0];
$latestbackup_date = date ("Y-m-d H:i:s", filemtime($latestbackup));
}
// Skin selector -----------------------------------------------------------------
if (isset($_POST['submit']) && submit && isset($_POST['skinselector_set'])) {
$pia_skin_set_dir = '../db/';
$pia_skin_selector = htmlspecialchars($_POST['skinselector']);
if (in_array($pia_skin_selector, $pia_installed_skins)) {
foreach ($pia_installed_skins as $file) {
unlink ($pia_skin_set_dir.'/setting_'.$file);
}
foreach ($pia_installed_skins as $file) {
if (file_exists($pia_skin_set_dir.'/setting_'.$file)) {
$pia_skin_error = True;
break;
} else {
$pia_skin_error = False;
}
}
if ($pia_skin_error == False) {
$testskin = fopen($pia_skin_set_dir.'setting_'.$pia_skin_selector, 'w');
$pia_skin_test = '';
echo("<meta http-equiv='refresh' content='1'>");
} else {
$pia_skin_test = '';
echo("<meta http-equiv='refresh' content='1'>");
}
}
}
// Table sizes -----------------------------------------------------------------
$tableSizesHTML = "";
// Open a connection to the SQLite database
$db = new SQLite3($pia_db);
$db = new SQLite3($nax_db);
// Retrieve the table names from sqlite_master
$query = "SELECT name FROM sqlite_master WHERE type='table'";
@@ -142,10 +67,6 @@ while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$db->close();
// Language selector -----------------------------------------------------------------
?>
<div class="row">
@@ -183,13 +104,13 @@ $db->close();
<div class="db_info_table_row">
<div class="db_info_table_cell" style="min-width: 140px"><?= lang('Maintenance_database_path');?></div>
<div class="db_info_table_cell">
<?php echo $pia_db;?>
<?php echo $nax_db;?>
</div>
</div>
<div class="db_info_table_row">
<div class="db_info_table_cell"><?= lang('Maintenance_database_size');?></div>
<div class="db_info_table_cell">
<?php echo $pia_db_size;?>
<?php echo $nax_db_size;?>
</div>
</div>
<div class="db_info_table_row">
@@ -201,15 +122,9 @@ $db->close();
<div class="db_info_table_row">
<div class="db_info_table_cell"><?= lang('Maintenance_database_lastmod');?></div>
<div class="db_info_table_cell">
<?php echo $pia_db_mod;?>
<?php echo $nax_db_mod;?>
</div>
</div>
<div class="db_info_table_row">
<div class="db_info_table_cell"><?= lang('Maintenance_database_backup');?></div>
<div class="db_info_table_cell">
<?php echo $Pia_Archive_count.' '.lang('Maintenance_database_backup_found').' / '.lang('Maintenance_database_backup_total').': '.$Pia_Archive_diskusage;?>
</div>
</div>
</div>
</div>
</div>
<!-- /.box-body -->
@@ -219,13 +134,7 @@ $db->close();
<div class="nav-tabs-custom">
<ul class="nav nav-tabs">
<li class="active">
<a id="tab_Settings_id" href="#tab_Settings" data-toggle="tab">
<i class="fa fa-cogs"></i>
<?= lang('Maintenance_Tools_Tab_UISettings');?>
</a>
</li>
<li>
<li class="active">
<a id="tab_DBTools_id" href="#tab_DBTools" data-toggle="tab">
<i class="fa fa-toolbox"></i>
<?= lang('Maintenance_Tools_Tab_Tools');?>
@@ -251,82 +160,7 @@ $db->close();
</li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="tab_Settings">
<div class="db_info_table">
<div class="db_info_table_row">
<div class="db_tools_table_cell_a" style="text-align: center;">
<form method="post" action="maintenance.php">
<div style="display: inline-block; text-align: center;">
<select name="skinselector" class="form-control bg-green" style="width:160px; margin-bottom:5px;">
<option value=""><?= lang('Maintenance_themeselector_empty');?></option>
<option value="skin-black-light">black light</option>
<option value="skin-black">black</option>
<option value="skin-blue-light">blue light</option>
<option value="skin-blue">blue</option>
<option value="skin-green-light">green light</option>
<option value="skin-green">green</option>
<option value="skin-purple-light">purple light</option>
<option value="skin-purple">purple</option>
<option value="skin-red-light">red light</option>
<option value="skin-red">red</option>
<option value="skin-yellow-light">yellow light</option>
<option value="skin-yellow">yellow</option>
</select></div>
<div style="display: block;"><input type="submit" name="skinselector_set" value="<?= lang('Maintenance_themeselector_apply');?>" class="btn bg-green" style="width:160px;">
<?php // echo $pia_skin_test; ?>
</div>
</form>
</div>
<div class="db_info_table_cell" style="padding: 10px; height:40px; text-align:left; vertical-align: middle;">
<?= lang('Maintenance_themeselector_text'); ?>
</div>
</div>
<div class="db_info_table_row">
<div class="db_tools_table_cell_a">
<button type="button" class="btn bg-green dbtools-button" id="btnToggleDarkmode" onclick="askToggleDarkmode()"><?= lang('Maintenance_Tool_darkmode');?></button>
</div>
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_darkmode_text');?></div>
</div>
<div class="db_info_table_row">
<div class="db_tools_table_cell_a">
<div class="form-group" >
<div class="input-group" >
<select id="columnsSelect" class="form-control select2 select2-hidden-accessible" multiple="" style="width: 100%;" tabindex="-1" aria-hidden="true">
<option value="0"><?= lang('Device_TableHead_Name');?></option>
<option value="1"><?= lang('Device_TableHead_Owner');?></option>
<option value="2"><?= lang('Device_TableHead_Type');?></option>
<option value="3"><?= lang('Device_TableHead_Icon');?></option>
<option value="4"><?= lang('Device_TableHead_Favorite');?></option>
<option value="5"><?= lang('Device_TableHead_Group');?></option>
<option value="6"><?= lang('Device_TableHead_FirstSession');?></option>
<option value="7"><?= lang('Device_TableHead_LastSession');?></option>
<option value="8"><?= lang('Device_TableHead_LastIP');?></option>
<option value="9"><?= lang('Device_TableHead_MAC');?></option>
<option value="10"><?= lang('Device_TableHead_Status');?></option>
<option value="11"><?= lang('Device_TableHead_MAC_full');?></option>
<option value="12"><?= lang('Device_TableHead_LastIPOrder');?></option>
<option value="13"><?= lang('Device_TableHead_Rowid');?></option>
<option value="14"><?= lang('Device_TableHead_Parent_MAC');?></option>
<option value="15"><?= lang('Device_TableHead_Connected_Devices');?></option>
<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>
</div>
</div>
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_displayed_columns_text');?></div>
</div>
</div>
</div>
<div class="tab-pane" id="tab_DBTools">
<div class="tab-pane active" id="tab_DBTools">
<div class="db_info_table">
<div class="db_info_table_row">
<div class="db_tools_table_cell_a" >
@@ -368,27 +202,9 @@ $db->close();
</div>
<div class="tab-pane" id="tab_BackupRestore">
<div class="db_info_table">
<div class="db_info_table_row">
<div class="db_info_table_row">
<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" >
<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" >
<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" >
<button type="button" class="btn btn-default pa-btn bg-green dbtools-button" id="btnExportCSV" onclick="askExportCSV()"><?= lang('Maintenance_Tool_ExportCSV');?></button>
<button type="button" class="btn btn-default pa-btn bg-green dbtools-button" id="btnExportCSV" onclick="ExportCSV()"><?= lang('Maintenance_Tool_ExportCSV');?></button>
</div>
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_ExportCSV_text');?></div>
</div>
@@ -398,132 +214,60 @@ $db->close();
</div>
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_ImportCSV_text');?></div>
</div>
<div class="db_info_table_row">
<div class="db_tools_table_cell_a" >
<button type="button" class="btn btn-default pa-btn pa-btn-delete bg-red dbtools-button" id="btnImportPastedCSV" onclick="askImportPastedCSV()"><?= lang('Maintenance_Tool_ImportPastedCSV');?></button>
</div>
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_ImportPastedCSV_text');?></div>
</div>
</div>
</div>
<!-- ---------------------------Logging-------------------------------------------- -->
<div class="tab-pane" id="tab_Logging">
<div class="db_info_table">
<div class="log-area box box-solid box-primary">
<div class="row logs-row">
<textarea id="app_log" class="logs" cols="70" rows="10" wrap='off' readonly >
<?php
if(filesize("./log/app.log") > 2000000)
{
echo file_get_contents( "./log/app.log", false, null, -2000000);
}
else{
echo file_get_contents( "./log/app.log" );
}
?>
</textarea>
</div>
<div class="row logs-row" >
<div>
<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('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="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">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('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="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">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('app.php_errors.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="nginx_error_log" class="logs logs-small" cols="70" rows="10" wrap='off' readonly><?php echo file_get_contents( "/var/log/nginx/error.log" ); ?>
</textarea>
</div>
<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>
<div class="log-area box box-solid box-primary">
<div class="row logs-row">
<textarea id="stdout_log" class="logs logs-small" cols="70" rows="10" wrap='off' readonly><?php echo file_get_contents( "./log/stdout.log" ); ?>
</textarea>
</div>
<div class="row logs-row" >
<div>
<div class="log-file">stdout.log<div class="logs-size"><?php echo number_format((filesize("./log/stdout.log") / 1000000),2,",",".") . ' MB';?>
<span class="span-padding"><a href="./log/stdout.log"><i class="fa fa-download"></i> </a></span>
</div></div>
<div class="log-purge">
<button class="btn btn-primary" onclick="logManage('stdout.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="stderr_log" class="logs logs-small" cols="70" rows="10" wrap='off' readonly><?php echo file_get_contents( "./log/stderr.log" ); ?>
</textarea>
</div>
<div class="row logs-row" >
<div>
<div class="log-file">stderr.log<div class="logs-size"><?php echo number_format((filesize("./log/stderr.log") / 1000000),2,",",".") . ' MB';?>
<span class="span-padding"><a href="./log/stderr.log"><i class="fa fa-download"></i> </a></span>
</div></div>
<div class="log-purge">
<button class="btn btn-primary" onclick="logManage('stderr.log','cleanLog')"><?= lang('Gen_Purge');?></button>
</div>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row actions">
<div class="col-sm-2">
<div class="form-check toggle">
<label class="form-check-label pointer" for="logsAutoRefresh">
<input class="form-check-input" type="checkbox" id="logsAutoRefresh" onchange="toggleAutoRefresh()" />
Auto-refresh
</label>
</div>
</div>
<!-- ---------------------------Bulk edit -------------------------------------------- -->
<div class="tab-pane" id="tab_multiEdit">
<div class="db_info_table">
<div class="box box-solid">
<?php
require 'multiEditCore.php';
?>
<div class="col-sm-2">
<div class="form-check toggle">
<label class="form-check-label pointer" for="logsAutoScroll">
<input class="form-check-input" type="checkbox" checked id="logsAutoScroll" />
Auto-scroll
</label>
</div>
</div>
<div class="col-sm-8">
<div class="form-inline toggle">
<input class="form-control" type="text" id="logsFilter" oninput="applyFilter()" placeholder="Filter lines with text..." />
</div>
</div>
</div>
</div>
<div class="db_info_table">
<div id="logsPlc"></div>
</div>
</div>
<!-- ---------------------------Bulk edit -------------------------------------------- -->
<div class="tab-pane" id="tab_multiEdit">
<div class="db_info_table">
<div class="box box-solid">
<?php
require 'multiEditCore.php';
?>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- ------------------------------------------------------------------------------ -->
</div>
<!-- ------------------------------------------------------------------------------ -->
</div>
@@ -554,84 +298,99 @@ $db->close();
<script>
var emptyArr = ['undefined', "", undefined, null];
var selectedTab = 'tab_Settings_id';
var selectedTab = 'tab_DBTools_id';
initializeTabs();
// -----------------------------------------------------------
// delete devices with emty macs
function askDeleteDevicesWithEmptyMACs () {
// Ask
showModalWarning('<?= lang('Maintenance_Tool_del_empty_macs_noti');?>', '<?= lang('Maintenance_Tool_del_empty_macs_noti_text');?>',
'Cancel', 'Delete', 'deleteDevicesWithEmptyMACs');
}
// -----------------------------------------------------------
function deleteDevicesWithEmptyMACs()
{
// Delete device
$.get('php/server/devices.php?action=deleteAllWithEmptyMACs', function(msg) {
showMessage (msg);
write_notification(`[Maintenance] All devices witout a Mac manually deleted`, 'info')
});
}
// -----------------------------------------------------------
// delete all devices
function askDeleteAllDevices () {
// Ask
showModalWarning('<?= lang('Maintenance_Tool_del_alldev_noti');?>', '<?= lang('Maintenance_Tool_del_alldev_noti_text');?>',
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Delete');?>', 'deleteAllDevices');
}
// -----------------------------------------------------------
function deleteAllDevices()
{
// Delete device
$.get('php/server/devices.php?action=deleteAllDevices', function(msg) {
showMessage (msg);
write_notification(`[Maintenance] All devices manually deleted`, 'info')
});
}
// -----------------------------------------------------------
// delete all (unknown) devices
function askDeleteUnknown () {
// Ask
showModalWarning('<?= lang('Maintenance_Tool_del_unknowndev_noti');?>', '<?= lang('Maintenance_Tool_del_unknowndev_noti_text');?>',
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Delete');?>', 'deleteUnknownDevices');
}
// -----------------------------------------------------------
function deleteUnknownDevices()
{
// Execute
$.get('php/server/devices.php?action=deleteUnknownDevices', function(msg) {
showMessage (msg);
write_notification(`[Maintenance] Unknown devices manually deleted`, 'info')
});
}
// -----------------------------------------------------------
// delete all Events
function askDeleteEvents () {
// Ask
showModalWarning('<?= lang('Maintenance_Tool_del_allevents_noti');?>', '<?= lang('Maintenance_Tool_del_allevents_noti_text');?>',
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Delete');?>', 'deleteEvents');
}
// -----------------------------------------------------------
function deleteEvents()
{
// Execute
$.get('php/server/devices.php?action=deleteEvents', function(msg) {
showMessage (msg);
write_notification(`[Maintenance] Events manually deleted (all)`, 'info')
});
}
// -----------------------------------------------------------
// delete all Events older than 30 days
function askDeleteEvents30 () {
// Ask
showModalWarning('<?= lang('Maintenance_Tool_del_allevents30_noti');?>', '<?= lang('Maintenance_Tool_del_allevents30_noti_text');?>',
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Delete');?>', 'deleteEvents30');
}
// -----------------------------------------------------------
function deleteEvents30()
{
// Execute
$.get('php/server/devices.php?action=deleteEvents30', function(msg) {
showMessage (msg);
write_notification(`[Maintenance] Events manually deleted (last 30 days kep)`, 'info')
});
}
// -----------------------------------------------------------
// delete History
function askDeleteActHistory () {
// Ask
@@ -646,60 +405,47 @@ function deleteActHistory()
});
}
// Backup DB to Archive
function askPiaBackupDBtoArchive () {
// -----------------------------------------------------------
// Restart Backend Python Server
function askRestartBackend() {
// Ask
showModalWarning('<?= lang('Maintenance_Tool_backup_noti');?>', '<?= lang('Maintenance_Tool_backup_noti_text');?>',
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Backup');?>', 'PiaBackupDBtoArchive');
}
function PiaBackupDBtoArchive()
{
// Execute
$.get('php/server/devices.php?action=PiaBackupDBtoArchive', function(msg) {
showMessage (msg);
});
showModalWarning('<?= lang('Maint_RestartServer');?>', '<?= lang('Maint_Restart_Server_noti_text');?>',
'<?= lang('Gen_Cancel');?>', '<?= lang('Maint_RestartServer');?>', 'restartBackend');
}
// Restore DB from Archive
function askPiaRestoreDBfromArchive () {
// Ask
showModalWarning('<?= lang('Maintenance_Tool_restore_noti');?>', '<?= lang('Maintenance_Tool_restore_noti_text');?>',
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Restore');?>', 'PiaRestoreDBfromArchive');
}
function PiaRestoreDBfromArchive()
{
// -----------------------------------------------------------
function restartBackend() {
modalEventStatusId = 'modal-message-front-event'
// Execute
$.get('php/server/devices.php?action=PiaRestoreDBfromArchive', function(msg) {
showMessage (msg);
});
}
// Purge Backups
function askPiaPurgeDBBackups() {
// Ask
showModalWarning('<?= lang('Maintenance_Tool_purgebackup_noti');?>', '<?= lang('Maintenance_Tool_purgebackup_noti_text');?>',
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Purge');?>', 'PiaPurgeDBBackups');
}
function PiaPurgeDBBackups()
{
// Execute
$.get('php/server/devices.php?action=PiaPurgeDBBackups', function(msg) {
showMessage (msg);
});
$.ajax({
method: "POST",
url: "php/server/util.php",
data: { function: "addToExecutionQueue", action: `${getGuid()}|cron_restart_backend` },
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()
write_notification('[Maintenance] App manually restarted', 'info')
}
})
}
// -----------------------------------------------------------
// Export CSV
function askExportCSV() {
// Ask
showModalWarning('<?= lang('Maintenance_Tool_ExportCSV_noti');?>', '<?= lang('Maintenance_Tool_ExportCSV_noti_text');?>',
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Okay');?>', 'ExportCSV');
}
function ExportCSV()
{
// Execute
openInNewTab("php/server/devices.php?action=ExportCSV")
}
// -----------------------------------------------------------
// Import CSV
function askImportCSV() {
// Ask
@@ -711,46 +457,34 @@ function ImportCSV()
// Execute
$.get('php/server/devices.php?action=ImportCSV', function(msg) {
showMessage (msg);
write_notification(`[Maintenance] Devices imported from CSV file`, 'info')
});
}
// -----------------------------------------------------------
// Import pasted CSV
function askImportPastedCSV() {
// --------------------------------------------------------
// Switch Darkmode
function askToggleDarkmode() {
// Ask
showModalWarning('<?= lang('Maintenance_Tool_darkmode_noti');?>', '<?= lang('Maintenance_Tool_darkmode_noti_text');?>',
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Switch');?>', 'ToggleDarkmode');
// Add new icon as base64 string
showModalInput ('<i class="fa fa-square-plus pointer"></i> <?= lang('Maintenance_Tool_ImportCSV_noti');?>', '<?= lang('Maintenance_Tool_ImportPastedCSV_noti_text');?>',
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Okay');?>', 'ImportPastedCSV');
}
// --------------------------------------------------------
function ToggleDarkmode()
function ImportPastedCSV()
{
// get parameter Front_Dark_Mode_Enabled value
$.get('php/server/parameters.php?action=get&defaultValue=false&expireMinutes=525600&parameter=Front_Dark_Mode_Enabled', function(data) {
var result = JSON.parse(data);
if (result) {
darkModeEnabled = result == 'true';
var csv = $('#modal-input-textarea').val();
// invert value
darkModeEnabled = !darkModeEnabled;
csvBase64 = utf8ToBase64(csv);
// save inverted value
$.get('php/server/parameters.php?action=set&parameter=Front_Dark_Mode_Enabled&expireMinutes=525600&value='+ darkModeEnabled,
function(data) {
if (data != "OK") {
showMessage (data);
setTimeout(function (){location.reload()}, 1000);
} else {
showMessage (data);
};
} );
}
$.post('php/server/devices.php?action=ImportCSV', { content: csvBase64 }, function(msg) {
showMessage(msg);
write_notification(`[Maintenance] Devices imported from pasted content`, 'info');
});
}
// --------------------------------------------------------
// Clean log file
@@ -780,176 +514,158 @@ function performLogManage() {
data: { function: logFileAction, settings: targetLogFile },
success: function(data, textStatus) {
showModalOk ('Result', data );
write_notification(`[Maintenance] Log file "${targetLogFile}" manually purged`, 'info')
}
})
}
// --------------------------------------------------------
// scroll down the log areas
function scrollDown()
{
setTimeout(() => {
function scrollDown() {
var elementToCheck = $("#tab_Logging_id");
// Check if the parent <li> is active
if (elementToCheck.parent().hasClass("active")) {
{
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++) {
var textAreas = $("#logsPlc textarea");
var tempArea = $('#' + areaIDs[i]);
if (tempArea.length > 0)
{
$(tempArea[0]).scrollTop(tempArea[0].scrollHeight);
}
}
}
textAreas.each(function() {
$(this).scrollTop(this.scrollHeight);
});
}
}, 200);
}
// --------------------------------------------------------
// Manage displayed columns
// --------------------------------------------------------
colDefaultOrder = ['0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17'];
colDefaultOrderTxt = '[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]';
function saveSelectedColumns () {
$.get('php/server/parameters.php?action=set&expireMinutes=525600&value=['+ $('#columnsSelect').val().toString() +']&parameter=Front_Devices_Columns_Visible', function(data) {
// save full order of all columns to simplify mapping later on
colDisplayed = $('#columnsSelect').val();
colNewOrder = colDisplayed;
// append the remaining columns in the previous order
for(i = 0; i < colDefaultOrder.length; i++)
{
if(!colDisplayed.includes(colDefaultOrder[i]))
{
colNewOrder.push(colDefaultOrder[i])
}
}
// save the setting in the DB
$.get('php/server/parameters.php?action=set&expireMinutes=525600&value=['+ colNewOrder.toString() +']&parameter=Front_Devices_Columns_Order', function(data) {
showMessage(data);
});
});
}
// --------------------------------------------------------
function initializeSelectedColumns () {
$.get('php/server/parameters.php?action=get&expireMinutes=525600&defaultValue='+colDefaultOrderTxt+'&parameter=Front_Devices_Columns_Visible', function(data) {
handle_locked_DB(data)
tableColumnShow = numberArrayFromString(data);
for(i=0; i < tableColumnShow.length; i++)
{
// create the option and append to Select2
var option = new Option($('#columnsSelect option[value='+tableColumnShow[i]+']').html(), tableColumnShow[i] , true, true);
$("#columnsSelect").append(option).trigger('change');
}
});
}
// --------------------------------------------------------
// General initialization
// --------------------------------------------------------
function initializeTabs () {
setTimeout(function() {
key = "activeMaintenanceTab"
function initializeTabs() {
setTimeout(() => {
const key = "activeMaintenanceTab";
// default selection
selectedTab = "tab_Settings"
let selectedTab = "tab_DBTools_id";
// the #target from the url
target = window.location.hash.substr(1)
// the #target from the URL
let target = window.location.hash.substr(1);
console.log(selectedTab);
// get only the part between #...?
if(target.includes('?'))
{
target = target.split('?')[0]
if (target.includes('?')) {
target = target.split('?')[0];
}
console.log(target);
// update cookie if target specified
if(target != "")
{
if (!selectedTab.endsWith("_id")) {
selectedTab = target + "_id";
}
setCache(key, selectedTab) // _id is added so it doesn't conflict with AdminLTE tab behavior
if (target) {
selectedTab = target.endsWith("_id") ? target : `${target}_id`;
setCache(key, selectedTab); // _id is added so it doesn't conflict with AdminLTE tab behavior
}
// get the tab id from the cookie (already overriden by the target)
if(!emptyArr.includes(getCache(key)))
{
selectedTab = getCache(key);
// get the tab id from the cookie (already overridden by the target)
const cachedTab = getCache(key);
if (cachedTab && !emptyArr.includes(cachedTab)) {
selectedTab = cachedTab;
}
// Activate panel
$('.nav-tabs a[id='+ selectedTab +']').tab('show');
// When changed save new current tab
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
setCache(key, $(e.target).attr('id'))
$('a[data-toggle="tab"]').on('shown.bs.tab', (e) => {
const newTabId = $(e.target).attr('id');
setCache(key, newTabId);
});
// events on tab change
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
var target = $(e.target).attr("href") // activated tab
$('a[data-toggle="tab"]').on('shown.bs.tab', (e) => {
const newTarget = $(e.target).attr("href"); // activated tab
});
hideSpinner();
}, 50);
}
//------------------------------------------------------------------------------
// Logs render functionality
//------------------------------------------------------------------------------
// load footer asynchronously not to block the page load/other sections
window.onload = function asyncFooter()
{
initializeSelectedColumns();
scrollDown();
initializeTabs();
//------------------------------------------------------------------------------
// Manages the auto-refresh functionality for the logs
let intervalId;
$("#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/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>');
function toggleAutoRefresh() {
const checkbox = $('#logsAutoRefresh')[0];
if (checkbox.checked) {
intervalId = setInterval(renderLogs, 1000);
} else {
clearInterval(intervalId);
}
}
// scroll to the latest log entrie sat teh bottom of the file
//------------------------------------------------------------------------------
// Manages the filter application on the logs
function applyFilter() {
const filterText = $("#logsFilter").val().toLowerCase();
$(".logs").each(function() {
const originalText = $(this).data('originalText') || $(this).val();
if (!$(this).data('originalText')) {
$(this).data('originalText', originalText);
}
const filteredLines = originalText.split('\n').filter(line =>
line.toLowerCase().includes(filterText)
);
$(this).val(filteredLines.join('\n'));
});
}
//------------------------------------------------------------------------------
// Renders all the logs
function renderLogs(customData) {
$.ajax({
url: 'php/components/logs.php', // PHP script URL
type: 'POST', // Use POST method to send data
dataType: 'html', // Expect HTML response
// data: { items: JSON.stringify(customData) }, // Send customData as JSON
success: function(response) {
$('#logsPlc').html(response); // Replace container content with fetched HTML
applyFilter();
if($('#logsAutoScroll')[0].checked)
{
scrollDown(); // scroll down the logs
}
},
error: function(xhr, status, error) {
console.error('Error fetching infoboxes:', error);
}
});
}
//------------------------------------------------------------------------------
// Init
window.onload = function asyncFooter() {
renderLogs();
// initializeTabs();
try {
$("#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/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>');
} catch (error) {
console.error('Failed to load GitHub badges:', error);
}
};
</script>

View File

@@ -1,7 +1,5 @@
<div class="col-md-12">
<div class="callout callout-warning">
<h4><?= lang('Gen_Warning');?></h4>
@@ -15,7 +13,7 @@
<h3 class="box-title"><?= lang('Gen_Selected_Devices');?></h3>
</div>
<div class="deviceSelector col-md-9" style="z-index:5"></div>
<div class="deviceSelector col-md-9 col-sm-12" style="z-index:5"></div>
<div class="col-md-3">
<button type="button" class="btn btn-default" onclick="markAllSelected()">
@@ -102,34 +100,56 @@
// Append form groups to the column
for (let j = i * elementsPerColumn; j < Math.min((i + 1) * elementsPerColumn, columns.length); j++) {
let inputType;
const setTypeObject = JSON.parse(columns[j].Type.replace(/'/g, '"'));
switch (columns[j].Type) {
case 'integer.checkbox':
case 'checkbox':
inputType = 'checkbox';
break;
case 'text.select':
inputType = 'text.select';
break;
default:
inputType = 'text';
break;
}
if (inputType === 'text.select') {
// get the element with the input value(s)
let elements = setTypeObject.elements.filter(element => element.elementHasInputValue === 1);
targetLocation = columns[j].Code_Name + "_initSettingDropdown"
// if none found, take last
if(elements.length == 0)
{
elementWithInputValue = setTypeObject.elements[setTypeObject.elements.length - 1]
} else
{
elementWithInputValue = elements[0]
}
initSettingDropdown(columns[j].Code_Name, [], targetLocation, generateDropdownOptions)
const { elementType, elementOptions = [], transformers = [] } = elementWithInputValue;
const {
inputType,
readOnly,
isMultiSelect,
isOrdeable,
cssClasses,
placeholder,
suffix,
sourceIds,
separator,
editable,
valRes,
getStringKey,
onClick,
onChange,
customParams,
customId
} = handleElementOptions('none', elementOptions, transformers, val = "");
// Handle Icons as tehy need a preview
// render based on element type
if (elementType === 'select') {
targetLocation = columns[j].Code_Name + "_generateSetOptions"
generateOptionsOrSetOptions(columns[j].Code_Name, [], targetLocation, generateOptions)
console.log(columns[j].Code_Name)
// Handle Icons as they need a preview
if(columns[j].Code_Name == 'NEWDEV_dev_Icon')
{
input = `
<span class="input-group-addon" id="txtIconFA"></span>
<span class="input-group-addon iconPreview" my-customid="NEWDEV_dev_Icon_preview"></span>
<select class="form-control"
onChange="updateIconPreview('#NEWDEV_dev_Icon')"
onChange="updateIconPreview(this)"
my-customparams="NEWDEV_dev_Icon,NEWDEV_dev_Icon_preview"
id="${columns[j].Code_Name}"
data-my-column="${columns[j].Code_Name}"
data-my-targetColumns="${columns[j].Code_Name.replace('NEWDEV_','')}" >
@@ -147,18 +167,15 @@
}
} else {
} else if (elementType === 'input'){
// Add classes specifically for checkboxes
if (inputType === 'checkbox') {
inputClass = 'checkbox';
} else {
inputClass = 'form-control';
}
inputType === 'checkbox' ? inputClass = 'checkbox' : inputClass = 'form-control';
input = `<input class="${inputClass}"
id="${columns[j].Code_Name}"
my-customid="${columns[j].Code_Name}"
data-my-column="${columns[j].Code_Name}"
data-my-targetColumns="${columns[j].Code_Name.replace('NEWDEV_','')}"
type="${inputType}">`
@@ -288,9 +305,9 @@ function executeAction(action, whereColumnName, key, targetColumns, newTargetCol
window.onbeforeunload = null;
// update API endpoints to refresh the UI
updateApi()
updateApi("devices,appevents")
writeNotification(`[Multi edit] Executed "${action}" on Columns "${targetColumns}" matching "${key}"`, 'info')
write_notification(`[Multi edit] Executed "${action}" on Columns "${targetColumns}" matching "${key}"`, 'info')
} else {
showMessage(getString('Gen_LockedDB'));
@@ -317,7 +334,7 @@ function deleteSelectedDevices()
{
macs_tmp = selectorMacs()
executeAction('delete', 'dev_MAC', macs_tmp )
writeNotification('[Multi edit] Manually deleted devices with MACs:' + macs_tmp, 'info')
write_notification('[Multi edit] Manually deleted devices with MACs:' + macs_tmp, 'info')
}

View File

@@ -7,6 +7,7 @@
define('badge_offline', '<div class="badge bg-red text-white" style="width: 60px;">Offline</div>');
define('circle_online', '<div class="badge bg-green text-white" style="width: 10px; height: 10px; padding:2px; margin-top: -25px;">&nbsp;</div>');
define('circle_offline', '<div class="badge bg-red text-white" style="width: 10px; height: 10px; padding:2px; margin-top: -25px;">&nbsp;</div>');
define('sortable_column', ' <span class="sort-btn" onclick="sortColumn(this)"><i class="fa-solid fa-arrow-up-short-wide"></i></span>');
?>
@@ -49,10 +50,10 @@
$decoded_icon = base64_decode($icon);
$idFromMac = str_replace(":", "_", $node_mac);
$str_tab_header = '<li class="'.$activetab.'">
$str_tab_header = '<li class="networkNodeTabHeaders '.$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
.'<div class="icon">'.$decoded_icon.' </div>'.$node_name.' ' .$str_port.$node_badge.
<a href="#'.$idFromMac.'" data-mytabmac="'.$node_mac.'" id="'.$idFromMac.'_id" data-toggle="tab" title="'.$node_name.' ">' // _id is added so it doesn't conflict with AdminLTE tab behavior
.'<div class="icon">'.$decoded_icon.' </div> <span class="node-name">'.$node_name.'</span>' .$str_port.$node_badge.
'</a>
</li>';
@@ -140,13 +141,18 @@
';
$str_table = ' <table class="table table-striped">
<thead>
<tr>
<th class="col-sm-1" >Port</th>
<th class="col-sm-1" >'.lang('Network_Table_State').'</th>
<th class="col-sm-2" >'.lang('Network_Table_Hostname').sortable_column.'</th>
<th class="col-sm-1" >'.lang('Network_Table_IP').sortable_column.'</th>
<th class="col-sm-3" >'.lang('Network_ManageLeaf').'</th>
</tr>
</thead>
<tbody>
<tr>
<th class="col-sm-1" >Port</th>
<th class="col-sm-1" >'.lang('Network_Table_State').'</th>
<th class="col-sm-2" >'.lang('Network_Table_Hostname').'</th>
<th class="col-sm-1" >'.lang('Network_Table_IP').'</th>
<th class="col-sm-3" >'.lang('Network_ManageLeaf').'</th>
</tr>';
// Prepare Array for Devices with Port value
@@ -353,12 +359,17 @@
<?php
// Get all Unassigned / unconnected nodes
$func_sql = 'SELECT dev_MAC as mac,
dev_PresentLastScan as online,
dev_Name as name,
dev_LastIP as last_ip,
dev_Network_Node_MAC_ADDR
FROM Devices WHERE (dev_Network_Node_MAC_ADDR is null or dev_Network_Node_MAC_ADDR = "" or dev_Network_Node_MAC_ADDR = " " or dev_Network_Node_MAC_ADDR = "undefined") and dev_MAC not like "%internet%" order by name asc';
$func_sql = 'SELECT
dev_MAC AS mac,
dev_PresentLastScan AS online,
dev_Name AS name,
dev_LastIP AS last_ip,
dev_Network_Node_MAC_ADDR
FROM Devices
WHERE dev_Network_Node_MAC_ADDR IS NULL
OR dev_Network_Node_MAC_ADDR IN ("", " ", "undefined", "null")
AND dev_MAC NOT LIKE "%internet%"
ORDER BY name ASC;';
global $db;
$func_result = $db->query($func_sql);
@@ -383,13 +394,18 @@
<i class="fa fa-laptop"></i> '.lang('Network_UnassignedDevices').'
</h3>
<table class="table table-striped">
<thead>
<tr>
<th class="col-sm-1" ></th>
<th class="col-sm-1" >'.lang('Network_Table_State').'</th>
<th class="col-sm-2" >'.lang('Network_Table_Hostname').sortable_column.'</th>
<th class="col-sm-1" >'.lang('Network_Table_IP').sortable_column.'</th>
<th class="col-sm-3" >'.lang('Network_Assign').'</th>
</tr>
</thead>
<tbody>
<tr>
<th class="col-sm-1" ></th>
<th class="col-sm-1" >'.lang('Network_Table_State').'</th>
<th class="col-sm-2" >'.lang('Network_Table_Hostname').'</th>
<th class="col-sm-1" >'.lang('Network_Table_IP').'</th>
<th class="col-sm-3" >'.lang('Network_Assign').'</th>
</tr>';
$str_table_rows = "";
@@ -453,7 +469,7 @@
<script src="lib/treeviz/require.js"></script>
<script>
<script defer>
$.get('php/server/devices.php?action=getDevicesList&status=all&forceDefaultOrder', function(data) {
rawData = JSON.parse (data)
@@ -517,8 +533,10 @@
for(var i in list)
{
//... of the current node
if(list[i].parentMac == node.mac && !hiddenMacs.includes(list[i].parentMac))
if(list[i].parentMac.toLowerCase() == node.mac.toLowerCase() && !hiddenMacs.includes(list[i].parentMac))
{
visibleNodesCount++
// and process them
@@ -535,7 +553,6 @@
{
parentNodesCount++
}
return {
name: node.name,
@@ -559,7 +576,6 @@
function getHierarchy()
{
for(i in deviceListGlobal)
{
if(deviceListGlobal[i].mac == 'Internet')
@@ -604,10 +620,10 @@
}
// ---------------------------------------------------------------------------
// Handle network node click - select correct tab in teh bottom table
// Handle network node click - select correct tab in the bottom table
function handleNodeClick(event)
{
console.log(event.target.offsetParent.offsetParent)
// console.log(event.target.offsetParent.offsetParent)
const targetTabMAC = $(event.target.offsetParent.offsetParent).attr("data-mytreemacmain");
@@ -619,14 +635,24 @@
// ---------------------------------------------------------------------------
var myTree;
var visibleTreeArea = $(window).height()-135;
var treeAreaHeight = visibleTreeArea > 800 ? 800 : visibleTreeArea;
var visibleTreeArea = $(window).height()-155;
var nodeWidth = 160;
var emSize;
var nodeHeight;
var sizeCoefficient = 1
function initTree(myHierarchy)
{
console.log(myHierarchy)
// calculate the drawing area based on teh tree width and available screen size
var treeAreaHeight = visibleTreeArea > 800 ? 800 : visibleTreeArea;
let screenWidth = $('.content-header').width();
let treeWidth = (nodeWidth + 20) * parentNodesCount;
let treeAreaWidth = screenWidth < treeWidth ? treeWidth : screenWidth;
// init the drawing area size
$("#networkTree").attr('style', `height:${treeAreaHeight}px; width:${treeAreaWidth}px`)
if(myHierarchy.type == "")
{
@@ -643,7 +669,7 @@
// nodeHeight = ((emSize*100*0.30).toFixed(0))
nodeHeight = ((emSize*100*0.30).toFixed(0))
$("#networkTree").attr('style', `height:${treeAreaHeight}px; width:${$('.content-header').width()}px`)
console.log(Treeviz);
myTree = Treeviz.create({
htmlId: "networkTree",
@@ -652,7 +678,9 @@
(!emptyArr.includes(nodeData.data.port )) ? port = nodeData.data.port : port = "";
(port == "" || port == 0 ) ? portBckgIcon = `<i class="fa fa-wifi"></i>` : portBckgIcon = `<i class="fa fa-ethernet"></i>`;
(port == "" || port == 0 || port == 'None' ) ? portBckgIcon = `<i class="fa fa-wifi"></i>` : portBckgIcon = `<i class="fa fa-ethernet"></i>`;
portHtml = (port == "" || port == 0 || port == 'None' ) ? "" : port
// Build HTML for individual nodes in the network diagram
deviceIcon = (!emptyArr.includes(nodeData.data.icon )) ?
@@ -661,7 +689,7 @@
</div>` : "";
devicePort = `<div class="netPort"
style="width:${emSize*sizeCoefficient}em;height:${emSize*sizeCoefficient}em">
${port}</div>
${portHtml}</div>
<div class="portBckgIcon"
style="margin-left:-${emSize*sizeCoefficient}em;">
${portBckgIcon}
@@ -692,7 +720,7 @@
>
<div class="netNodeText">
<strong>${devicePort} ${deviceIcon}
<span class="spanNetworkTree anonymizeDev">${nodeData.data.name}</span>
<span class="spanNetworkTree anonymizeDev" >${nodeData.data.name}</span>
</strong>
${collapseExpandHtml}
</div>
@@ -707,8 +735,8 @@
secondaryAxisNodeSpacing: 0.3,
nodeHeight: nodeHeight.toString(),
marginTop: '5',
hasZoom: false,
hasPan: false,
hasZoom: true,
hasPan: true,
// marginLeft: '15',
idKey: "id",
hasFlatData: false,
@@ -717,8 +745,8 @@
onNodeClick: (nodeData) => handleNodeClick(nodeData),
relationnalField: "children",
});
console.log(myHierarchy)
myTree.refresh(myHierarchy);
@@ -755,7 +783,7 @@
setCache(key, target.replaceAll(":","_")+'_id') // _id is added so it doesn't conflict with AdminLTE tab behavior
}
// get the tab id from the cookie (already overriden by the target)
// get the tab id from the cookie (already overridden by the target)
if(!emptyArr.includes(getCache(key)))
{
selectedTab = getCache(key);
@@ -852,7 +880,6 @@
// init Assign/Unassign buttons
initButtons()
</script>

98
front/php/components/logs.php Executable file
View File

@@ -0,0 +1,98 @@
<?php
require '../server/init.php';
//------------------------------------------------------------------------------
// check if authenticated
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
// Function to render the log area component
function renderLogArea($params) {
$fileName = isset($params['fileName']) ? $params['fileName'] : '';
$filePath = isset($params['filePath']) ? $params['filePath'] : '';
$textAreaCssClass = isset($params['textAreaCssClass']) ? $params['textAreaCssClass'] : '';
$buttons = isset($params['buttons']) ? $params['buttons'] : [];
$content = "";
if (filesize($filePath) > 2000000) {
$content = file_get_contents($filePath, false, null, -2000000);
} else {
$content = file_get_contents($filePath);
}
// Prepare the download button HTML if filePath starts with /app/front
$downloadButtonHtml = '';
if (strpos($filePath, '/app/front') === 0) {
$downloadButtonHtml = '
<span class="span-padding">
<a href="' . htmlspecialchars(str_replace('/app/front', '', $filePath)) . '" target="_blank">
<i class="fa fa-download"></i>
</a>
</span>';
}
// Prepare buttons HTML
$buttonsHtml = '';
$totalButtons = count($buttons);
if ($totalButtons > 0) {
$colClass = 12 / $totalButtons;
// Use $colClass in your HTML generation or further logic
} else {
// Handle case where $buttons array is empty
$colClass = 12;
}
foreach ($buttons as $button) {
$labelStringCode = isset($button['labelStringCode']) ? $button['labelStringCode'] : '';
$event = isset($button['event']) ? $button['event'] : '';
$buttonsHtml .= '
<div class="button-wrap col-sm-' . $colClass . ' col-xs-' . $colClass . '">
<button class="btn btn-primary col-sm-12 col-xs-12" onclick="' . htmlspecialchars($event) . '">' . lang($labelStringCode) . '</button>
</div>';
}
// Render the log area HTML
$html = '
<div class="log-area box box-solid box-primary">
<div class="row logs-row col-sm-12 col-xs-12">
<textarea class="' . htmlspecialchars($textAreaCssClass) . '" cols="70" rows="20" wrap="off" readonly>'
. htmlspecialchars($content) .
'</textarea>
</div>
<div class="row logs-row">
<div class="log-file col-sm-6 col-xs-12">' . htmlspecialchars($fileName) . '
<div class="logs-size">' . number_format((filesize($filePath) / 1000000), 2, ",", ".") . ' MB'
. $downloadButtonHtml .
'</div>
</div>
<div class="col-sm-6 col-xs-12">'
. $buttonsHtml .
'</div>
</div>
</div>';
return $html;
}
// Load default data from JSON file
$defaultDataFile = 'logs_defaults.json';
$defaultData = file_exists($defaultDataFile) ? json_decode(file_get_contents($defaultDataFile), true) : [];
// Check if JSON data is submitted via POST
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['items'])) {
$items = json_decode($_POST['items'], true);
} else {
$items = $defaultData;
}
// Render the log areas with the retrieved or default data
$html = '';
foreach ($items as $item) {
$html .= renderLogArea($item);
}
echo $html;
exit();
?>

View File

@@ -0,0 +1,98 @@
[
{
"buttons": [
{
"labelStringCode": "Maint_PurgeLog",
"event": "logManage('app.log', 'cleanLog')"
},
{
"labelStringCode": "Maint_RestartServer",
"event": "askRestartBackend()"
}
],
"fileName": "app.log",
"filePath": "/app/front/log/app.log",
"textAreaCssClass": "logs"
},
{
"buttons": [
{
"labelStringCode": "Maint_PurgeLog",
"event": "logManage('app_front.log', 'cleanLog')"
}
],
"fileName": "app_front.log",
"filePath": "/app/front/log/app_front.log",
"textAreaCssClass": "logs logs-small"
},
{
"buttons": [
{
"labelStringCode": "Maint_PurgeLog",
"event": "logManage('app.php_errors.log', 'cleanLog')"
}
],
"fileName": "app.php_errors.log",
"filePath": "/app/front/log/app.php_errors.log",
"textAreaCssClass": "logs logs-small"
},
{
"buttons": [
{
"labelStringCode": "Maint_PurgeLog",
"event": "logManage('execution_queue.log', 'cleanLog')"
}
],
"fileName": "execution_queue.log",
"filePath": "/app/front/log/execution_queue.log",
"textAreaCssClass": "logs logs-small"
},
{
"buttons": [
],
"fileName": "nginx/error.log",
"filePath": "/var/log/nginx/error.log",
"textAreaCssClass": "logs logs-small"
},
{
"buttons": [
{
"labelStringCode": "Maint_PurgeLog",
"event": "logManage('app_front.log', 'cleanLog')"
}
],
"fileName": "app_front.log",
"filePath": "/app/front/log/app_front.log",
"textAreaCssClass": "logs logs-small"
},
{
"buttons": [
],
"fileName": "db_is_locked.log",
"filePath": "/app/front/log/db_is_locked.log",
"textAreaCssClass": "logs logs-small"
},
{
"buttons": [
{
"labelStringCode": "Maint_PurgeLog",
"event": "logManage('stdout.log', 'cleanLog')"
}
],
"fileName": "stdout.log",
"filePath": "/app/front/log/stdout.log",
"textAreaCssClass": "logs logs-small"
},
{
"buttons": [
{
"labelStringCode": "Maint_PurgeLog",
"event": "logManage('stderr.log', 'cleanLog')"
}
],
"fileName": "stderr.log",
"filePath": "/app/front/log/stderr.log",
"textAreaCssClass": "logs logs-small"
}
]

View File

@@ -0,0 +1,48 @@
<?php
//------------------------------------------------------------------------------
// check if authenticated
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
function renderInfobox($params) {
$onclickEvent = isset($params['onclickEvent']) ? $params['onclickEvent'] : '';
$color = isset($params['color']) ? $params['color'] : '';
$title = isset($params['title']) ? $params['title'] : '';
$label = isset($params['label']) ? $params['label'] : '';
$icon = isset($params['icon']) ? $params['icon'] : '';
return '
<div class="tile col-lg-2 col-sm-4 col-xs-6">
<a href="#" onclick="javascript: ' . htmlspecialchars($onclickEvent) . ';">
<div class="small-box ' . htmlspecialchars($color) . '">
<div class="inner">
<h3>' . htmlspecialchars($title) . '</h3>
<p class="infobox_label">' . htmlspecialchars($label) . '</p>
</div>
<div class="icon">
<i class="fa ' . htmlspecialchars($icon) . ' text-aqua-40"></i>
</div>
</div>
</a>
</div>';
}
// Load default data from JSON file
$defaultDataFile = 'tile_cards_defaults.json';
$defaultData = file_exists($defaultDataFile) ? json_decode(file_get_contents($defaultDataFile), true) : [];
// Check if 'items' parameter exists and is valid JSON
$items = isset($_POST['items']) ? json_decode($_POST['items'], true) : [];
// Use default data if 'items' is not provided or cannot be decoded
if (empty($items)) {
$items = $defaultData;
}
$html = '';
foreach ($items as $item) {
$html .= renderInfobox($item);
}
echo $html;
exit();
?>

View File

@@ -0,0 +1,17 @@
[
{
"onclickEvent": "handleClick(1)",
"color": "bg-primary",
"title": "Default Infobox 1",
"label": "Default label for Infobox 1",
"icon": "fa-bell"
},
{
"onclickEvent": "handleClick(2)",
"color": "bg-success",
"title": "Default Infobox 2",
"label": "Default label for Infobox 2",
"icon": "fa-envelope"
}
]

View File

@@ -1,7 +0,0 @@
<?php
// Cache the contents to a cache file
$cached = fopen($cachefile, 'w');
fwrite($cached, ob_get_contents());
fclose($cached);
ob_end_flush(); // Send the output to the browser
?>

View File

@@ -1,15 +0,0 @@
<?php
$url = $_SERVER["SCRIPT_NAME"];
$break = Explode('/', $url);
$file = $break[count($break) - 1];
$cachefile = 'cached-'.substr_replace($file ,"",-4).'.html';
$cachetime = 18000;
// Serve from the cache if it is younger than $cachetime
if (file_exists($cachefile) && time() - $cachetime < filemtime($cachefile)) {
echo "<!-- Cached copy, generated ".date('H:i', filemtime($cachefile))." -->\n";
readfile($cachefile);
exit;
}
ob_start(); // Start the output buffer
?>

View File

@@ -13,6 +13,10 @@
$DBFILE = dirname(__FILE__).'/../../../db/app.db';
$DBFILE_LOCKED_FILE = dirname(__FILE__).'/../../../front/log/db_is_locked.log';
//------------------------------------------------------------------------------
// check if authenticated
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
$db_locked = false;
//------------------------------------------------------------------------------

View File

@@ -3,16 +3,18 @@
// NetAlertX
// Open Source Network Guard / WIFI & LAN intrusion detector
//
// parameters.php - Front module. Server side. Manage Parameters
//------------------------------------------------------------------------------
# Puche 2022+ jokob jokob@duck.com GNU GPLv3
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// External files
require dirname(__FILE__).'/init.php';
// External files
require dirname(__FILE__).'/init.php';
//------------------------------------------------------------------------------
// check if authenticated
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
//------------------------------------------------------------------------------
// Action selector

View File

@@ -11,6 +11,10 @@
// External files
require dirname(__FILE__).'/init.php';
//------------------------------------------------------------------------------
// check if authenticated
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
//------------------------------------------------------------------------------
// Action selector
//------------------------------------------------------------------------------
@@ -152,6 +156,8 @@ function setDeviceData() {
dev_Comments = "'. quotes($_REQUEST['comments']) .'",
dev_Network_Node_MAC_ADDR = "'. quotes($_REQUEST['networknode']).'",
dev_Network_Node_port = "'. quotes($_REQUEST['networknodeport']).'",
dev_SSID = "'. quotes($_REQUEST['ssid']).'",
dev_NetworkSite = "'. quotes($_REQUEST['networksite']).'",
dev_StaticIP = "'. quotes($_REQUEST['staticIP']) .'",
dev_ScanCycle = "'. quotes($_REQUEST['scancycle']) .'",
dev_AlertEvents = "'. quotes($_REQUEST['alertevents']) .'",
@@ -422,54 +428,76 @@ function ExportCSV() {
$func_result = $db->query("SELECT * FROM Devices");
// prepare CSV header row
// header array with column names
$columns = getDevicesColumns();
// wrap the headers with " (quotes)
$resultCSV = '"'.implode('","', $columns).'"';
//and append a new line
$resultCSV = $resultCSV."\n";
$resultCSV = '"'.implode('","', $columns).'"'."\n";
// retrieve the devices from the DB
while ($row = $func_result -> fetchArray (SQLITE3_ASSOC)) {
while ($row = $func_result->fetchArray(SQLITE3_ASSOC)) {
// loop through columns and add values to the string
$index = 0;
foreach ($columns as $columnName) {
// Escape special chars (e.g.quotes) inside fields by replacing them with html definitions
$fieldValue = encodeSpecialChars($row[$columnName]);
// add quotes around the value to prevent issues with commas in fields
$resultCSV = $resultCSV.'"'.$row[$columnName].'"';
$resultCSV .= '"'.$fieldValue.'"';
// detect last loop - skip as no comma needed
if ($index != count($columns) - 1 )
{
$resultCSV = $resultCSV.',';
if ($index != count($columns) - 1) {
$resultCSV .= ',';
}
$index++;
}
//$resultCSV = $resultCSV.implode(",", [$row["dev_MAC"], $row["dev_Name"]]);
$resultCSV = $resultCSV."\n";
// add a new line for the next row
$resultCSV .= "\n";
}
//write the built CSV string
echo $resultCSV;
}
//------------------------------------------------------------------------------
// Import CSV of devices
//------------------------------------------------------------------------------
function ImportCSV() {
$file = '../../../config/devices.csv';
if (file_exists($file)) {
global $db;
$skipped = "";
$error = "";
global $db;
$file = '../../../config/devices.csv';
$data = "";
$skipped = "";
$error = "";
// check if content passed in query string
if(isset ($_POST['content']) && !empty ($_POST['content']))
{
// Decode the Base64 string
// $data = base64_decode($_POST['content']);
$data = base64_decode($_POST['content'], true); // The second parameter ensures safe decoding
// // Ensure the decoded data is treated as UTF-8 text
// $data = mb_convert_encoding($data, 'UTF-8', 'UTF-8');
} else if (file_exists($file)) { // try to get the data form the file
// Read the CSV file
$data = file_get_contents($file);
} else {
echo lang('BackDevices_DBTools_ImportCSVMissing');
}
if($data != "")
{
// data cleanup - new lines breaking the CSV
$data = preg_replace_callback('/"([^"]*)"/', function($matches) {
// Replace all \n within the quotes with a space
return str_replace("\n", " ", $matches[0]); // Replace with a space
}, $data);
$lines = explode("\n", $data);
// Get the column headers from the first line of the CSV
@@ -515,8 +543,6 @@ function ImportCSV() {
// An error occurred while writing to the DB, display the last error message
echo lang('BackDevices_DBTools_ImportCSVError') . "\n" . $error . "\n" . $sql . "\n\n" . $result;
}
} else {
echo lang('BackDevices_DBTools_ImportCSVMissing');
}
}
@@ -592,7 +618,9 @@ function getDevicesList() {
array("dev_Vendor", 17, 17),
array("dev_Network_Node_port", 18, 18),
array("dev_GUID", 19, 19),
array("dev_SyncHubNodeName", 20, 20)
array("dev_SyncHubNodeName", 20, 20),
array("dev_NetworkSite", 21, 21),
array("dev_SSID", 22, 22)
);
if($forceDefaultOrder == FALSE)
@@ -663,7 +691,9 @@ function getDevicesList() {
handleNull($row['dev_Vendor']),
handleNull($row['dev_Network_Node_port']),
handleNull($row['dev_GUID']),
handleNull($row['dev_SyncHubNodeName'])
handleNull($row['dev_SyncHubNodeName']),
handleNull($row['dev_NetworkSite']),
handleNull($row['dev_SSID'])
);
$newOrder = array();
@@ -895,18 +925,11 @@ function copyFromDevice() {
$MAC_FROM = $_REQUEST['macFrom'];
$MAC_TO = $_REQUEST['macTo'];
if ((false === filter_var($MAC_FROM , FILTER_VALIDATE_MAC) && $MAC_FROM != "Internet" && $MAC_FROM != "") ) {
throw new Exception('Invalid mac address');
}
if ((false === filter_var($MAC_TO , FILTER_VALIDATE_MAC) && $MAC_TO != "Internet" && $MAC_TO != "") ) {
throw new Exception('Invalid mac address');
}
global $db;
// clean-up temporary table
$sql = "DROP TABLE temp_devices ";
$sql = "DROP TABLE IF EXISTS temp_devices ";
$result = $db->query($sql);
// create temporary table with the source data

View File

@@ -8,9 +8,12 @@
# Puche 2021 / 2022+ jokob jokob@duck.com GNU GPLv3
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// External files
require dirname(__FILE__).'/init.php';
// External files
require dirname(__FILE__).'/init.php';
//------------------------------------------------------------------------------
// check if authenticated
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
//------------------------------------------------------------------------------
// Action selector
@@ -72,7 +75,7 @@ function getEventsTotals() {
$resultJSON = getCache("getEventsTotals".$days);
} else
{
// one query to get all numbers, whcih is quicker than multiple queries
// one query to get all numbers, which is quicker than multiple queries
$sql = "select
(SELECT Count(*) FROM Events WHERE eve_DateTime >= date('now', '".$periodDateSQL."')) as all_events,
(SELECT Count(*) FROM Sessions as sessions WHERE ( ses_DateTimeConnection >= date('now', '".$periodDateSQL."') OR ses_DateTimeDisconnection >= date('now', '".$periodDateSQL."') OR ses_StillConnected = 1 )) as sessions,
@@ -334,24 +337,40 @@ function getEventsCalendar() {
$endDate = '"'. $_REQUEST ['end'] .'"';
// SQL
$SQL = 'SELECT ses_MAC, ses_EventTypeConnection, ses_DateTimeConnection,
ses_EventTypeDisconnection, ses_DateTimeDisconnection, ses_IP, ses_AdditionalInfo, ses_StillConnected,
CASE
WHEN ses_EventTypeConnection = "<missing event>" THEN
IFNULL ((SELECT MAX(ses_DateTimeDisconnection) FROM Sessions AS SES2 WHERE SES2.ses_MAC = SES1.ses_MAC AND SES2.ses_DateTimeDisconnection < SES1.ses_DateTimeDisconnection), DATETIME(ses_DateTimeDisconnection, "-1 hour"))
ELSE ses_DateTimeConnection
END AS ses_DateTimeConnectionCorrected,
$SQL = 'SELECT SES1.ses_MAC, SES1.ses_EventTypeConnection, SES1.ses_DateTimeConnection,
SES1.ses_EventTypeDisconnection, SES1.ses_DateTimeDisconnection, SES1.ses_IP,
SES1.ses_AdditionalInfo, SES1.ses_StillConnected,
CASE
WHEN SES1.ses_EventTypeConnection = "<missing event>" THEN
IFNULL (
(SELECT MAX(SES2.ses_DateTimeDisconnection)
FROM Sessions AS SES2
WHERE SES2.ses_MAC = SES1.ses_MAC
AND SES2.ses_DateTimeDisconnection < SES1.ses_DateTimeDisconnection
AND SES2.ses_DateTimeDisconnection BETWEEN Date('. $startDate .') AND Date('. $endDate .')
),
DATETIME(SES1.ses_DateTimeDisconnection, "-1 hour")
)
ELSE SES1.ses_DateTimeConnection
END AS ses_DateTimeConnectionCorrected,
CASE
WHEN ses_EventTypeDisconnection = "<missing event>" THEN
(SELECT MIN(ses_DateTimeConnection) FROM Sessions AS SES2 WHERE SES2.ses_MAC = SES1.ses_MAC AND SES2.ses_DateTimeConnection > SES1.ses_DateTimeConnection)
ELSE ses_DateTimeDisconnection
END AS ses_DateTimeDisconnectionCorrected
CASE
WHEN SES1.ses_EventTypeDisconnection = "<missing event>" THEN
(SELECT MIN(SES2.ses_DateTimeConnection)
FROM Sessions AS SES2
WHERE SES2.ses_MAC = SES1.ses_MAC
AND SES2.ses_DateTimeConnection > SES1.ses_DateTimeConnection
AND SES2.ses_DateTimeConnection BETWEEN Date('. $startDate .') AND Date('. $endDate .')
)
ELSE SES1.ses_DateTimeDisconnection
END AS ses_DateTimeDisconnectionCorrected
FROM Sessions AS SES1
WHERE (SES1.ses_DateTimeConnection BETWEEN Date('. $startDate .') AND Date('. $endDate .'))
OR (SES1.ses_DateTimeDisconnection BETWEEN Date('. $startDate .') AND Date('. $endDate .'))
OR SES1.ses_StillConnected = 1';
FROM Sessions AS SES1
WHERE ( ses_DateTimeConnectionCorrected <= Date('. $endDate .')
AND (ses_DateTimeDisconnectionCorrected >= Date('. $startDate .') OR ses_StillConnected = 1 )) ';
$result = $db->query($SQL);
// arrays of rows

View File

@@ -15,6 +15,10 @@
// Get init.php
require dirname(__FILE__).'/../server/init.php';
//------------------------------------------------------------------------------
// check if authenticated
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
// Perform a test with the PING command
$output = shell_exec("curl ipinfo.io");

View File

@@ -2,6 +2,10 @@
require 'util.php';
//------------------------------------------------------------------------------
// check if authenticated
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
$PIA_HOST_IP = $_REQUEST['scan'];
$PIA_SCAN_MODE = $_REQUEST['mode'];

View File

@@ -15,6 +15,11 @@
// Get init.php
require dirname(__FILE__).'/../server/init.php';
//------------------------------------------------------------------------------
// check if authenticated
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
// Get IP
$ip = $_GET['ip'];

View File

@@ -1,144 +0,0 @@
<?php
//------------------------------------------------------------------------------
// NetAlertX
// Open Source Network Guard / WIFI & LAN intrusion detector
//
// parameters.php - Front module. Server side. Manage Parameters
//------------------------------------------------------------------------------
# Puche 2021 / 2022+ jokob jokob@duck.com GNU GPLv3
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// External files
require dirname(__FILE__).'/init.php';
//------------------------------------------------------------------------------
// Action selector
//------------------------------------------------------------------------------
// Set maximum execution time to 15 seconds
ini_set ('max_execution_time','15');
$skipCache = FALSE;
$expireMinutes = 5;
$defaultValue = '';
if (isset ($_REQUEST['skipcache'])) {
$skipCache = TRUE;
}
if (isset ($_REQUEST['defaultValue'])) {
$defaultValue = $_REQUEST['defaultValue'];
}
if (isset ($_REQUEST['expireMinutes'])) {
$expireMinutes = $_REQUEST['expireMinutes'];
}
// Action functions
if (isset ($_REQUEST['action']) && !empty ($_REQUEST['action'])) {
$action = $_REQUEST['action'];
switch ($action) {
case 'get': getParameter($skipCache, $defaultValue, $expireMinutes); break;
case 'set': setParameter($expireMinutes); break;
default: logServerConsole ('Action: '. $action); break;
}
}
//------------------------------------------------------------------------------
// Get Parameter Value
//------------------------------------------------------------------------------
function getParameter($skipCache, $defaultValue, $expireMinutes) {
$parameter = $_REQUEST['parameter'];
$value = "";
// get the value from the cache if available
$cachedValue = getCache($parameter);
if($cachedValue != "")
{
$value = $cachedValue;
}
// query the database if no cache entry found or requesting live data (skipping cache)
if($skipCache || $value == "" )
{
global $db;
$sql = 'SELECT par_Value FROM Parameters
WHERE par_ID="'. quotes($parameter) .'"';
$result = $db->query($sql);
$row = $result -> fetchArray (SQLITE3_NUM);
if($row != NULL && count($row) == 1)
{
$value = $row[0];
} else{
$value = $defaultValue;
// Nothing found in the DB, Insert new value
insertNew($parameter, $value);
}
// update cache
setCache($parameter, $value, $expireMinutes);
}
// return value
echo (json_encode ($value));
}
//------------------------------------------------------------------------------
// Set Parameter Value
//------------------------------------------------------------------------------
function setParameter($expireMinutes) {
$parameter = $_REQUEST['parameter'];
$value = $_REQUEST['value'];
global $db;
// Update value
$sql = 'UPDATE Parameters SET par_Value="'. quotes ($value) .'"
WHERE par_ID="'. quotes($parameter) .'"';
$result = $db->query($sql);
if (! $result == TRUE) {
echo "Error updating parameter\n\n$sql \n\n". $db->lastErrorMsg();
return;
}
$changes = $db->changes();
if ($changes == 0) {
// Insert new value
insertNew($parameter, $value);
}
// update cache
setCache($parameter, $value, $expireMinutes);
echo 'OK';
}
function insertNew($parameter, $value)
{
global $db;
// Insert new value
$sql = 'INSERT INTO Parameters (par_ID, par_Value)
VALUES ("'. quotes($parameter) .'",
"'. quotes($value) .'")';
$result = $db->query($sql);
if (! $result == TRUE) {
echo "Error creating parameter\n\n$sql \n\n". $db->lastErrorMsg();
return;
}
}
?>

View File

@@ -1,5 +1,10 @@
<?php
require dirname(__FILE__).'/../server/init.php';
//------------------------------------------------------------------------------
// check if authenticated
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
exec('../../../back/speedtest-cli --secure --simple', $output);
echo '<h4>'. lang('Speedtest_Results') .'</h4>';

View File

@@ -15,6 +15,10 @@
// Get init.php
require dirname(__FILE__).'/../server/init.php';
//------------------------------------------------------------------------------
// check if authenticated
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
// Get IP
$ip = $_GET['ip'];

View File

@@ -11,6 +11,10 @@
require dirname(__FILE__).'/../templates/timezone.php';
require dirname(__FILE__).'/../templates/skinUI.php';
//------------------------------------------------------------------------------
// check if authenticated
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
$FUNCTION = [];
$SETTINGS = [];
$ACTION = "";
@@ -28,6 +32,7 @@ if(array_key_exists('settings', $_REQUEST) != FALSE)
// call functions based on requested params
switch ($FUNCTION) {
case 'savesettings':
saveSettings();
@@ -224,6 +229,8 @@ function displayMessage($message, $logAlert = FALSE, $logConsole = TRUE, $logFil
}
// ----------------------------------------------------------------------------------------
// Adds an action to perform into the execution_queue.log file
function addToExecutionQueue($action)
{
@@ -243,6 +250,7 @@ function addToExecutionQueue($action)
}
// ----------------------------------------------------------------------------------------
function cleanLog($logFile)
{
@@ -250,7 +258,7 @@ function cleanLog($logFile)
$path = "";
$allowedFiles = ['app.log', 'app_front.log', 'IP_changes.log', 'stdout.log', 'stderr.log', "pholus_lastrun.log", 'app.php_errors.log'];
$allowedFiles = ['app.log', 'app_front.log', 'IP_changes.log', 'stdout.log', 'stderr.log', "pholus_lastrun.log", 'app.php_errors.log', 'execution_queue.log'];
if(in_array($logFile, $allowedFiles))
{
@@ -302,7 +310,7 @@ function saveSettings()
$txt = $txt."# Generated: ".$timestamp." #\n";
$txt = $txt."# #\n";
$txt = $txt."# Config file for the LAN intruder detection app: #\n";
$txt = $txt."# https://github.com/jokob-sk/NetAlertX #\n";
$txt = $txt."# https://github.com/jokob-sk/NetAlertX #\n";
$txt = $txt."# #\n";
$txt = $txt."#-----------------AUTOGENERATED FILE-----------------#\n";
@@ -322,56 +330,57 @@ function saveSettings()
$txt .= "\n#---------------------------\n";
foreach ($decodedSettings as $setting) {
$settingGroup = $setting[0];
$settingKey = $setting[1];
$settingType = $setting[2];
$settingValue = $setting[3];
// sanity check
if($settingKey == "UI_LANG" && $settingValue == "")
{
$settingGroup = $setting[0];
$settingKey = $setting[1];
$dataType = $setting[2];
$settingValue = $setting[3];
// // Parse the settingType JSON
// $settingType = json_decode($settingTypeJson, true);
// Sanity check
if($settingKey == "UI_LANG" && $settingValue == "") {
echo "🔴 Error: important settings missing. Refresh the page with 🔃 on the top and try again.";
return;
}
}
if ($group == $settingGroup) {
if ($dataType == 'string' ) {
$val = encode_single_quotes($settingValue);
$txt .= $settingKey . "='" . $val . "'\n";
} elseif ($dataType == 'integer') {
$txt .= $settingKey . "=" . $settingValue . "\n";
} elseif ($dataType == 'json') {
$txt .= $settingKey . "=" . $settingValue . "\n";
} elseif ($dataType == 'boolean') {
$val = ($settingValue === true || $settingValue === 1 || strtolower($settingValue) === 'true') ? "True" : "False";
$txt .= $settingKey . "=" . $val . "\n";
} elseif ($dataType == 'array' ) {
$temp = '';
if(is_array($settingValue) == FALSE)
{
$settingValue = json_decode($settingValue);
}
// skipping __metadata entries (?)
if (count($setting) > 3 && is_array($settingValue) == true) {
foreach ($settingValue as $val) {
$temp .= "'" . encode_single_quotes($val) . "',";
}
if ($group == $settingGroup) {
if ($settingType == 'text' || $settingType == 'password' || $settingType == 'password.SHA256' || $settingType == 'readonly' || $settingType == 'text.select') {
$val = encode_single_quotes($settingValue);
$txt .= $settingKey . "='" . $val . "'\n";
} elseif ($settingType == 'integer' || $settingType == 'integer.select') {
$txt .= $settingKey . "=" . $settingValue . "\n";
} elseif ($settingType == 'boolean' || $settingType == 'integer.checkbox') {
$temp = substr_replace($temp, "", -1); // remove last comma ','
}
if ($settingValue === true || $settingValue === 1 || strtolower($settingValue) === 'true') {
$val = "True";
} else {
$val = "False";
}
$txt .= $settingKey . "=" . $val . "\n";
} elseif ($settingType == 'text.multiselect' || $settingType == 'subnets' || $settingType == 'list' || $settingType == 'list.select') {
$temp = '';
if(is_array($settingValue) == FALSE)
{
$settingValue = json_decode($settingValue);
}
if (count($setting) > 3 && is_array($settingValue) == true) {
foreach ($settingValue as $val) {
$temp .= "'" . encode_single_quotes($val) . "',";
}
$temp = substr_replace($temp, "", -1); // remove last comma ','
}
$temp = '['.$temp.']'; // wrap brackets
$txt .= $settingKey . "=" . $temp . "\n";
} elseif ($settingType == 'json') {
$txt .= $settingKey . "=" . $settingValue . "\n";
}
}
}
$temp = '['.$temp.']'; // wrap brackets
$txt .= $settingKey . "=" . $temp . "\n";
} else {
$txt .= $settingKey . "='⭕Not handled⭕'\n";
}
}
}
}
@@ -479,7 +488,7 @@ function getDateFromPeriod () {
$days = "3650"; //10 years
break;
default:
$days = "1";
$days = "1";
}
$periodDateSQL = "-".$days." day";
@@ -515,6 +524,25 @@ function handleNull ($text, $default = "") {
}
// -------------------------------------------------------------------------------------------
// Encode special chars
function encodeSpecialChars($str) {
return str_replace(
['&', '<', '>', '"', "'"],
['&amp;', '&lt;', '&gt;', '&quot;', '&#039;'],
$str
);
}
// -------------------------------------------------------------------------------------------
// Decode special chars
function decodeSpecialChars($str) {
return str_replace(
['&amp;', '&lt;', '&gt;', '&quot;', '&#039;'],
['&', '<', '>', '"', "'"],
$str
);
}
// -------------------------------------------------------------------------------------------
@@ -546,7 +574,9 @@ function getDevicesColumns(){
"dev_Network_Node_MAC_ADDR",
"dev_Icon",
"dev_GUID",
"dev_SyncHubNodeName"
"dev_SyncHubNodeName",
"dev_NetworkSite",
"dev_SSID"
];
return $columns;

View File

@@ -1,13 +0,0 @@
<!-- utils needing a DB connection -->
<?php
require dirname(__FILE__).'/init.php';
// Action functions
if (isset ($_REQUEST['key']))
{
echo lang($_REQUEST['key']);
}
?>

View File

@@ -1,9 +1,12 @@
<?php
require dirname(__FILE__).'/../templates/timezone.php';
//------------------------------------------------------------------------------
// check if authenticated
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
// ----------------------------------------------------------------------------------------
// Check if the action parameter is set in the GET request
if (isset($_GET['action'])) {
// Collect GUID if provided
@@ -46,6 +49,8 @@ if (isset($_GET['action'])) {
}
}
// ----------------------------------------------------------------------------------------
// Generates a random GUID
function generate_guid() {
if (function_exists('com_create_guid') === true) {
return trim(com_create_guid(), '{}');
@@ -54,8 +59,10 @@ function generate_guid() {
mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535),
mt_rand(16384, 20479), mt_rand(32768, 49151), mt_rand(0, 65535),
mt_rand(0, 65535), mt_rand(0, 65535));
}
}
// ----------------------------------------------------------------------------------------
// Logs a notification in in-app notification system
function write_notification($content, $level = "interrupt") {
$NOTIFICATION_API_FILE = '/app/front/api/user_notifications.json';
@@ -87,6 +94,8 @@ function write_notification($content, $level = "interrupt") {
file_put_contents($NOTIFICATION_API_FILE, json_encode($notifications));
}
// ----------------------------------------------------------------------------------------
// Removes a notification based on GUID
function remove_notification($guid) {
$NOTIFICATION_API_FILE = '/app/front/api/user_notifications.json';
@@ -102,6 +111,8 @@ function remove_notification($guid) {
file_put_contents($NOTIFICATION_API_FILE, json_encode(array_values($filtered_notifications)));
}
// ----------------------------------------------------------------------------------------
// Deletes all notifications
function notifications_clear() {
$NOTIFICATION_API_FILE = '/app/front/api/user_notifications.json';
@@ -109,6 +120,8 @@ function notifications_clear() {
file_put_contents($NOTIFICATION_API_FILE, json_encode(array()));
}
// ----------------------------------------------------------------------------------------
// Mark a notification read based on GUID
function mark_notification_as_read($guid) {
$NOTIFICATION_API_FILE = '/app/front/api/user_notifications.json';
$max_attempts = 3;
@@ -152,10 +165,12 @@ function mark_notification_as_read($guid) {
echo "Failed to read notification file after $max_attempts attempts.";
}
// ----------------------------------------------------------------------------------------
function notifications_mark_all_read() {
mark_notification_as_read(null);
}
// ----------------------------------------------------------------------------------------
function get_unread_notifications() {
$NOTIFICATION_API_FILE = '/app/front/api/user_notifications.json';

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