Compare commits

...

285 Commits

Author SHA1 Message Date
Jokob @NetAlertX
3f80d2e57f feat(plugins): Implement /plugins/stats endpoint for per-plugin row counts with optional foreignKey filtering
Some checks failed
🐳 ⚠ docker-unsafe from next_release branch / docker_dev_unsafe (push) Has been cancelled
2026-03-27 21:35:41 +00:00
Jokob @NetAlertX
b18cf98266 feat(plugins): Enhance plugin counts handling with fail-open support and improved comments 2026-03-27 10:59:22 +00:00
Jokob @NetAlertX
77369c3ce8 feat(plugins): Optimize plugin badge fetching and rendering to prevent flicker and enhance visibility 2026-03-27 10:41:18 +00:00
Jokob @NetAlertX
cd0a3f6de0 feat(plugins): Refactor auto-hide functionality to leverage Bootstrap's tab management for improved visibility handling 2026-03-27 10:12:12 +00:00
Jokob @NetAlertX
13e91731be feat(plugins): Improve auto-hide functionality for empty plugin tabs by ensuring proper visibility handling and Bootstrap integration 2026-03-27 09:49:21 +00:00
Jokob @NetAlertX
7ef19b1c12 feat(plugins): Implement auto-hide functionality for empty plugin tabs 2026-03-27 09:26:25 +00:00
Jokob @NetAlertX
4daead1f8f feat(plugins): Enhance badge fetching with conditional JSON and GraphQL support 2026-03-27 08:08:44 +00:00
Jokob @NetAlertX
48454f6f2f feat(plugins): Optimize badge fetching by using lightweight JSON instead of GraphQL 2026-03-27 07:30:13 +00:00
Jokob @NetAlertX
7305fd78e3 fix(pagination): Ensure page number is always at least 1 in apply_common_pagination 2026-03-27 06:51:17 +00:00
Jokob @NetAlertX
ec3e4c8988 feat(api): Enhance session events API with pagination, sorting, and filtering
- Added support for pagination (page and limit) in the session events endpoint.
- Implemented sorting functionality based on specified columns and directions.
- Introduced free-text search capability for session events.
- Updated SQL queries to retrieve all events and added a new SQL constant for events.
- Refactored GraphQL types and helpers to support new plugin and event queries.
- Created new GraphQL resolvers for plugins and events with pagination and filtering.
- Added comprehensive tests for new GraphQL endpoints and session events functionality.
2026-03-26 20:57:10 +00:00
jokob-sk
250e533655 DOCS: pin mkdocs version
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-03-25 06:26:57 +11:00
jokob-sk
37730301f4 BE: lazy SQL execution caused devIsSleeping to be missing and tiles not show #1569 #1250
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-03-23 09:55:45 +11:00
Jokob @NetAlertX
7278ee8cfa Refactor getTotals method to clarify API contract and ensure stable response structure #1569 #1561 2026-03-21 21:28:42 +00:00
Jokob @NetAlertX
fa22523a0b Refactor device tiles SQL logic to use get_sql_devices_tiles function for improved maintainability Feature Request - Flapping and Sleeping nuances
Fixes #1567
2026-03-21 21:10:37 +00:00
Jokob @NetAlertX
7569923481 Refactor column name replacements to include variations for ObjectPrimaryID and ObjectSecondaryID 2026-03-21 20:55:24 +00:00
Jokob @NetAlertX
d7c7bd2cd2 Enhance SQL templates to prevent duplicate notifications for 'Down Reconnected' devices in event section 2026-03-18 09:57:20 +00:00
Jokob @NetAlertX
b311113575 Fix Spanish translations and improve HTML attributes in config files and report 2026-03-17 11:58:53 +00:00
Jokob @NetAlertX
43984132c4 Fix Spanish translations in config.json files for internet_speedtest, nmap_scan, and snmp_discovery plugins 2026-03-17 09:46:27 +00:00
Jokob @NetAlertX
0a7ecb5b7c Update config.json files to add 'ordeable' option and refactor cacheStrings function for consistency 2026-03-17 09:22:25 +00:00
Jokob @NetAlertX
c7399215ec Refactor event and session column names to camelCase
- Updated test cases to reflect new column names (eve_MAC -> eveMac, eve_DateTime -> eveDateTime, etc.) across various test files.
- Modified SQL table definitions in the database cleanup and migration tests to use camelCase naming conventions.
- Implemented migration tests to ensure legacy column names are correctly renamed to camelCase equivalents.
- Ensured that existing data is preserved during the migration process and that views referencing old column names are dropped before renaming.
- Verified that the migration function is idempotent, allowing for safe re-execution without data loss.
2026-03-16 10:11:22 +00:00
Jokob @NetAlertX
0bb6db155b Merge branch 'next_release' of https://github.com/netalertx/NetAlertX into next_release 2026-03-15 01:42:23 +00:00
Jokob @NetAlertX
7221b4ba96 Keep all local changes while resolving conflicts 2026-03-15 01:19:34 +00:00
Jokob @NetAlertX
c4904739b2 Merge pull request #1559 from netalertx/main
sync
2026-03-15 12:15:19 +11:00
Jokob @NetAlertX
67cab9d606 Merge branch 'main' of https://github.com/netalertx/NetAlertX 2026-03-14 23:27:45 +00:00
Jokob @NetAlertX
f75c53fc5d Implement notification text templates and update related settings for customizable notifications 2026-03-14 23:27:29 +00:00
Jokob @NetAlertX
bff87f4d61 Merge pull request #1552 from MrMeatikins/fix-arp-flux-docs-issue-1546
docs: Clarify ARP flux sysctl limitations with host networking
2026-03-14 09:05:44 +11:00
Jokob @NetAlertX
6f7d2c3253 Rename db_count to dbCount in GraphQL response handling for consistency 2026-03-13 13:17:30 +00:00
Hosted Weblate
0766fb2de6 Merge branch 'origin/main' into Weblate. 2026-03-13 14:08:47 +01:00
大王叫我来巡山
d19cb3d679 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 97.7% (787 of 805 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/zh_Hans/
2026-03-13 14:08:45 +01:00
Massimo Pissarello
9b71c210b2 Translated using Weblate (Italian)
Currently translated at 100.0% (805 of 805 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2026-03-13 14:08:44 +01:00
Jokob @NetAlertX
c9cb1f3fba Add db_count to DeviceResult and update GraphQL response handling; localize Device_NoMatch_Title in multiple languages 2026-03-13 13:08:26 +00:00
Jokob @NetAlertX
78a8030c6a Merge branch 'main' of https://github.com/netalertx/NetAlertX 2026-03-13 12:52:27 +00:00
Jokob @NetAlertX
b5b0bcc766 work on stale cache #1554 2026-03-13 12:52:22 +00:00
mid
13515603e4 Translated using Weblate (Japanese)
Currently translated at 100.0% (805 of 805 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ja/
2026-03-11 12:09:48 +01:00
Sylvain Pichon
518608cffc Translated using Weblate (French)
Currently translated at 99.5% (801 of 805 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2026-03-11 12:09:47 +01:00
Meatloaf Bot
df3ca50c5c Address CodeRabbit review: Clarify sysctl behavior in host network mode 2026-03-10 12:04:30 -04:00
Meatloaf-bot
93fc126da2 docs: clarify ARP flux sysctl limitations with host networking 2026-03-09 19:27:40 -04:00
jokob-sk
a60ec9ed3a Merge branch 'main' of github.com:netalertx/NetAlertX 2026-03-09 21:00:04 +11:00
jokob-sk
e1d206ca74 BE: new_online defined incorrectly
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-03-09 20:59:51 +11:00
Jokob @NetAlertX
2771a6e9c2 Merge branch 'main' of https://github.com/netalertx/NetAlertX 2026-03-08 07:58:00 +00:00
Jokob @NetAlertX
aba1ddd3df Handle JSON decoding errors in _get_data function 2026-03-08 07:57:52 +00:00
Sylvain Pichon
165c9d3baa Translated using Weblate (French)
Currently translated at 99.2% (799 of 805 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2026-03-08 06:09:50 +00:00
Safeguard
0b0c88f712 Translated using Weblate (Russian)
Currently translated at 100.0% (805 of 805 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2026-03-08 06:09:47 +00:00
Jokob @NetAlertX
d49abd9d02 Enhance code standards, update contributing guidelines, and add tests for SYNC plugin functionality 2026-03-07 21:34:38 +00:00
Jokob @NetAlertX
abf024d4d3 Merge branch 'main' of https://github.com/netalertx/NetAlertX 2026-03-06 22:34:25 +00:00
Jokob @NetAlertX
4eb5947ceb Update language folder path to include all language definitions 2026-03-06 22:34:19 +00:00
Safeguard
1d1a8045a0 Translated using Weblate (Russian)
Currently translated at 99.7% (803 of 805 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2026-03-06 13:09:47 +00:00
Jokob @NetAlertX
f8c09d35a7 Enhance scan ETA display logic to reload data for newly discovered devices after scanning finishes 2026-03-05 20:24:57 +00:00
jokob-sk
d8d090404e Merge branch 'main' of github.com:netalertx/NetAlertX 2026-03-05 18:51:05 +11:00
jokob-sk
5a6de6d832 LNG: moved languages.json so weblate skips it
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-03-05 18:50:21 +11:00
Hosted Weblate
05b63cb730 Merge branch 'origin/main' into Weblate. 2026-03-05 08:33:52 +01:00
Safeguard
2921614eac Translated using Weblate (Russian)
Currently translated at 99.0% (797 of 805 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2026-03-05 08:33:51 +01:00
Massimo Pissarello
17d95d802f Translated using Weblate (Italian)
Currently translated at 100.0% (805 of 805 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2026-03-05 08:33:50 +01:00
jokob-sk
a0048980b8 LNG: Indonesian
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-03-05 18:33:36 +11:00
Jokob @NetAlertX
89811cd133 Merge pull request #1544 from adamoutler/built-in-tests
Improve built-in test used during system startup - thanks @adamoutler 🙏
2026-03-05 06:48:46 +11:00
Adam Outler
b854206599 Address review comments from PR #1544 2026-03-04 14:36:31 +00:00
Adam Outler
a532c98115 Update test/docker_tests/test_entrypoint.py
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-03-03 23:22:11 -05:00
Adam Outler
da23880eb1 Update docs/docker-troubleshooting/arp-flux-sysctls.md
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-03-03 23:20:40 -05:00
Jokob @NetAlertX
c73ce839f2 Refactor ensure_future_datetime to simplify logic and remove max_retries parameter 2026-03-04 03:07:37 +00:00
Adam Outler
5c0f29b97c coderabbit suggestions 2026-03-04 01:33:43 +00:00
Adam Outler
f1496b483b Fix docker compose unit test to remove ARP FLUX warning. 2026-03-04 01:13:39 +00:00
Jokob @NetAlertX
ba26f34191 Enhance device section UI with collapsible filters and default collapse on mobile 2026-03-03 21:40:19 +00:00
Jokob @NetAlertX
37f8a44cb3 Update devIpLong field to String and handle empty string coercion for Int fields in devices data 2026-03-03 21:25:09 +00:00
Jokob @NetAlertX
76a259d9e5 Fix DataTable redraw logic and update empty message handling 2026-03-03 21:20:22 +00:00
Jokob @NetAlertX
1923a063f0 Merge branch 'main' of https://github.com/netalertx/NetAlertX 2026-03-03 12:33:08 +00:00
Jokob @NetAlertX
01b6b9f04a whitespace 2026-03-03 12:32:07 +00:00
Jokob @NetAlertX
ea77112315 next scan dsiplay DRY 2026-03-03 12:31:50 +00:00
Hosted Weblate
b19973130e Merge branch 'origin/main' into Weblate. 2026-03-03 07:37:53 +01:00
mid
ffbcc2ad25 Translated using Weblate (Japanese)
Currently translated at 99.8% (804 of 805 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ja/
2026-03-03 07:37:52 +01:00
Jokob @NetAlertX
c533c2267c Merge branch 'main' of https://github.com/netalertx/NetAlertX 2026-03-03 06:37:44 +00:00
Jokob @NetAlertX
ac407bd86e Update next scan message for clarity in device management 2026-03-03 06:37:37 +00:00
Hosted Weblate
1da3c146d2 Merge branch 'origin/main' into Weblate. 2026-03-03 07:36:42 +01:00
mid
9fe8090a1b Translated using Weblate (Japanese)
Currently translated at 100.0% (805 of 805 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ja/
2026-03-03 07:36:42 +01:00
Massimo Pissarello
3ba1b69c1e Translated using Weblate (Italian)
Currently translated at 100.0% (805 of 805 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2026-03-03 07:36:42 +01:00
Jokob @NetAlertX
da4d8a9675 Merge branch 'main' of https://github.com/netalertx/NetAlertX 2026-03-03 06:36:36 +00:00
Jokob @NetAlertX
0f20fb38f0 Enhance scanning state handling and localization updates across multiple language files 2026-03-03 06:36:31 +00:00
Hosted Weblate
8361f0ac99 Merge branch 'origin/main' into Weblate. 2026-03-03 07:11:04 +01:00
Massimo Pissarello
99de69e30d Translated using Weblate (Italian)
Currently translated at 98.7% (794 of 804 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2026-03-03 07:11:02 +01:00
mid
4637ec6350 Translated using Weblate (Japanese)
Currently translated at 99.8% (803 of 804 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ja/
2026-03-03 07:11:00 +01:00
Jokob @NetAlertX
2a4e6ba5e1 Merge branch 'main' of https://github.com/netalertx/NetAlertX 2026-03-03 06:10:41 +00:00
Jokob @NetAlertX
5be7bbe07d Enhance scan ETA display with current scanning state and add localization for 'Scanning...' message 2026-03-03 06:09:56 +00:00
Hosted Weblate
e8c43af7b6 Merge branch 'origin/main' into Weblate. 2026-03-03 05:07:58 +01:00
Adam Stańczyk
27f34963be Translated using Weblate (Polish)
Currently translated at 84.7% (677 of 799 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/pl/
2026-03-03 05:07:56 +01:00
HAMAD ABDULLA
594c2fe015 Translated using Weblate (Arabic)
Currently translated at 84.9% (679 of 799 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ar/
2026-03-03 05:07:54 +01:00
Safeguard
14362d20bd Translated using Weblate (Russian)
Currently translated at 98.7% (789 of 799 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2026-03-03 05:07:53 +01:00
ssantos
4f239be8a3 Translated using Weblate (Portuguese (Portugal))
Currently translated at 64.5% (516 of 799 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/pt_PT/
2026-03-03 05:07:52 +01:00
Marcus Isdahl
5a65d807a8 Translated using Weblate (Norwegian Bokmål)
Currently translated at 69.8% (558 of 799 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/nb_NO/
2026-03-03 05:07:49 +01:00
ButterflyOfFire
f3bf37bb24 Translated using Weblate (French)
Currently translated at 98.8% (790 of 799 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2026-03-03 05:07:47 +01:00
大王叫我来巡山
b7e1cb1f9d Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 98.4% (787 of 799 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/zh_Hans/
2026-03-03 05:07:45 +01:00
Ptsa Daniel
b4510663f7 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 98.4% (787 of 799 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/zh_Hans/
2026-03-03 05:07:44 +01:00
Anonymous
dd564b235b Translated using Weblate (Spanish)
Currently translated at 98.2% (785 of 799 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2026-03-03 05:07:43 +01:00
mid
04db68ea6c Translated using Weblate (Japanese)
Currently translated at 98.8% (790 of 799 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ja/
2026-03-03 05:07:42 +01:00
GoldBull3t
550f59b34f Translated using Weblate (Portuguese (Brazil))
Currently translated at 50.8% (406 of 799 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/pt_BR/
2026-03-03 05:07:41 +01:00
blomusti
6e8a3d8a58 Translated using Weblate (Turkish)
Currently translated at 56.4% (451 of 799 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/tr/
2026-03-03 05:07:40 +01:00
Deleted User
c89b2ded26 Translated using Weblate (Ukrainian)
Currently translated at 97.6% (780 of 799 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/uk/
2026-03-03 05:07:39 +01:00
Anonymous
9f964be0c3 Translated using Weblate (German)
Currently translated at 78.8% (630 of 799 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/de/
2026-03-03 05:07:39 +01:00
anton garcias
d2bc8410a7 Translated using Weblate (Catalan)
Currently translated at 98.8% (790 of 799 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ca/
2026-03-03 05:07:38 +01:00
Jokob @NetAlertX
ab74307ed1 Add next scan ETA display and update app state with scan timing information 2026-03-03 04:07:22 +00:00
Adam Outler
8ab9d9f395 Update docs 2026-03-02 19:43:38 +00:00
Adam Outler
c1d53ff93f Update docker compose and unit tests 2026-03-02 19:43:28 +00:00
Adam Outler
a329c5b541 Tidy up plugin logic 2026-03-02 19:42:29 +00:00
Adam Outler
0555105473 Detect sysctls only, don't modify sysctls; allow user to modify. 2026-03-02 19:42:00 +00:00
Adam Outler
b0aa5d0e45 Fix startup script matching for skips 2026-03-02 19:41:06 +00:00
Adam Outler
93df52f70c Fix healthcheck for non-0.0.0.0. will pass as long as reachable. 2026-03-02 19:39:23 +00:00
jokob-sk
95f411d92a DOCS: statuses
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-03-02 21:51:54 +11:00
Jokob @NetAlertX
bc4f419927 Enhance device MAC address handling in tests to ensure lowercase normalization and skip tests when web protection is disabled 2026-03-02 10:42:36 +00:00
Jokob @NetAlertX
3a73817048 Enhance device down event handling for sleeping devices and improve down alerts query 2026-03-02 10:05:37 +00:00
Hosted Weblate
67aa46f1cf Merge branch 'origin/main' into Weblate. 2026-03-02 10:54:18 +01:00
Massimo Pissarello
da63acb675 Translated using Weblate (Italian)
Currently translated at 100.0% (794 of 794 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2026-03-02 10:54:18 +01:00
jokob-sk
50125f0700 DOCS: statuses
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-03-02 20:54:09 +11:00
Jokob @NetAlertX
6724d250d4 Refactor network tree data structure and improve device status handling
- Updated the network tree data structure to use consistent naming conventions for device properties (e.g., devName, devMac).
- Enhanced the initTree function to utilize the new property names and improved the rendering of device nodes.
- Refactored the getStatusBadgeParts function to include additional parameters for archived and new device statuses.
- Introduced convenience functions (badgeFromDevice and badgeFromDataAttrs) to streamline badge generation from device objects and data attributes.
- Updated various language files to include new status labels and ensure consistency across translations.
- Modified the renderSmallBox function to allow for custom icon HTML, improving flexibility in UI components.
2026-03-02 09:35:42 +00:00
Jokob @NetAlertX
3e237bb452 Normalize MAC addresses in SQL queries and add devCanSleep column to device schema 2026-03-02 06:03:18 +00:00
Jokob @NetAlertX
15807b7ab9 Add unit and integration tests for device down event handling and sleeping suppression 2026-03-02 05:53:28 +00:00
Jokob @NetAlertX
0497c2891e Fix formatting issues in DATABASE.md for improved readability 2026-03-02 04:35:36 +00:00
Jokob @NetAlertX
8e6efc3008 sleeping devices status #1519 2026-03-02 04:35:07 +00:00
jokob-sk
deb0d16c3d LNG: PRAGMA_JOURNAL_SIZE_LIMIT
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-03-01 18:38:38 +11:00
jokob-sk
a94f3d7222 DOCS: PRAGMA_JOURNAL_SIZE_LIMIT
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-03-01 17:47:15 +11:00
Jokob @NetAlertX
d9608b4760 Add database performance tuning guidelines and user-configurable WAL size limit 2026-03-01 06:43:07 +00:00
Jokob @NetAlertX
584aba2c7b Set journal size limit to 10 MB for SQLite connections to prevent unbounded WAL growth 2026-03-01 06:19:39 +00:00
Jokob @NetAlertX
ea5585a8ef Add database cleanup for Sessions and optimize queries
- Implemented deletion of Sessions older than DAYS_TO_KEEP_EVENTS.
- Added index for Plugins_History to improve query performance.
- Introduced unit tests for Sessions trimming and database analysis.
2026-03-01 06:07:57 +00:00
Anonymous
c1adfd35f3 Translated using Weblate (Arabic)
Currently translated at 85.8% (680 of 792 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ar/
2026-03-01 05:09:57 +00:00
Anonymous
66532c54a1 Translated using Weblate (German)
Currently translated at 79.6% (631 of 792 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/de/
2026-03-01 05:09:55 +00:00
Anonymous
a6ce4174fe Translated using Weblate (Norwegian Bokmål)
Currently translated at 70.5% (559 of 792 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/nb_NO/
2026-03-01 05:09:54 +00:00
Anonymous
247a967e9b Translated using Weblate (Polish)
Currently translated at 85.6% (678 of 792 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/pl/
2026-03-01 05:09:52 +00:00
Anonymous
dbe65b2a27 Translated using Weblate (Turkish)
Currently translated at 57.0% (452 of 792 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/tr/
2026-03-01 05:09:50 +00:00
Anonymous
563cb4ba20 Translated using Weblate (Portuguese (Brazil))
Currently translated at 51.3% (407 of 792 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/pt_BR/
2026-03-01 05:09:49 +00:00
大王叫我来巡山
3d4aba4b39 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.3% (787 of 792 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/zh_Hans/
2026-03-01 05:09:47 +00:00
Jokob @NetAlertX
b96ace0447 Merge branch 'main' of https://github.com/netalertx/NetAlertX 2026-03-01 04:55:40 +00:00
Jokob @NetAlertX
e15c68d189 feat: enhance cacheStrings function to re-fetch plugin language strings on initialization 2026-03-01 04:55:35 +00:00
jokob-sk
f5e411d5d5 chore: jokob-sk->netalertx
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-28 16:00:37 +11:00
jokob-sk
f727580798 Merge branch 'main' of github.com:netalertx/NetAlertX 2026-02-28 15:58:52 +11:00
jokob-sk
11499a6890 chore: jokob-sk->netalertx
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-28 15:58:46 +11:00
Jokob @NetAlertX
85badb0760 Merge branch 'main' of https://github.com/netalertx/NetAlertX 2026-02-28 01:51:22 +00:00
Jokob @NetAlertX
814ba02d1c feat: implement languages endpoint and refactor language handling to use languages.json 2026-02-28 01:51:12 +00:00
Jokob @NetAlertX
e57fd2e81e fix: update body text color in dark theme and remove unnecessary console log 2026-02-28 01:02:21 +00:00
jokob-sk
4dc2a63ebb DOCS: flapping/unstable status addition
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-28 11:37:11 +11:00
jokob-sk
6b320877ec Merge branch 'main' of github.com:netalertx/NetAlertX 2026-02-28 11:30:24 +11:00
jokob-sk
43667a3bc4 DOCS: flapping/unstable status addition
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-28 11:30:13 +11:00
Jokob @NetAlertX
4d0b7c944f Merge branch 'main' of https://github.com/netalertx/NetAlertX 2026-02-28 00:24:37 +00:00
jokob-sk
9894009455 Merge branch 'main' of github.com:netalertx/NetAlertX 2026-02-28 11:24:08 +11:00
jokob-sk
0e18e34918 DOCS: flapping/unstable status addition
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-28 11:23:56 +11:00
Jokob @NetAlertX
d9c263d506 feat: Update cache handling to normalize legacy device data format and improve logging 2026-02-28 00:13:22 +00:00
Jokob @NetAlertX
58e32a5b43 feat: Refactor device column management and integrate new device-columns.js for centralized field definitions 2026-02-28 00:06:04 +00:00
jokob-sk
24e2036bde DOCS: flappin/usntable status addition
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-28 10:31:06 +11:00
Jokob @NetAlertX
b74b803d6c feat: Add devFlapping attribute to device management and update related UI components 2026-02-27 23:29:55 +00:00
Jokob @NetAlertX
173ffbe3b2 feat: Add cache clearing logic for imported settings in state update 2026-02-27 21:31:36 +00:00
Jokob @NetAlertX
d2ebe0d452 Merge branch 'main' of https://github.com/netalertx/NetAlertX 2026-02-27 10:08:56 +00:00
Jokob @NetAlertX
4c0d5c7376 refactor: Consolidate tab initialization logic using shared utility function 2026-02-27 10:07:55 +00:00
jokob-sk
686a713aa8 FE: lower case MAC issues #1538
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-27 14:35:35 +11:00
Jokob @NetAlertX
9d64665599 fix: Remove trailing whitespace and clean up formatting in version.php 2026-02-26 04:21:57 +00:00
Jokob @NetAlertX
63cef590d6 Refactor network API calls to use centralized authentication context and improve cache handling
- Removed redundant getApiToken function and replaced its usage with getAuthContext in network-api.js, network-events.js, and network-init.js.
- Updated cache handling in network-events.js and network-init.js to use CACHE_KEYS constants for better maintainability.
- Introduced cache.js for centralized cache management functions and constants, including cache initialization and retrieval.
- Added app-init.js for application lifecycle management, including cache orchestration and initialization checks.
- Created app_config.php to securely fetch API token and GraphQL port from configuration.
- Improved error handling and logging throughout the codebase for better debugging and maintenance.
2026-02-26 04:21:29 +00:00
Jokob @NetAlertX
00042ab594 refactor: Clean up whitespace and improve API token verification in network initialization 2026-02-25 21:59:51 +00:00
Jokob @NetAlertX
786cc5ee33 feat: Implement network topology management with API integration
- Added network-api.js for handling API calls related to network devices and nodes.
- Introduced network-events.js to manage event handlers for node interactions and window resizing.
- Created network-init.js for initializing network topology on page load and fetching device data.
- Developed network-tabs.js for rendering network tabs and managing tab content.
- Implemented network-tree.js for constructing and rendering the tree hierarchy of network devices.
- Enhanced error handling and user feedback for API calls and data loading processes.
- Included caching mechanisms for user preferences regarding device visibility.
2026-02-25 21:59:40 +00:00
大王叫我来巡山
0b32a06178 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.4% (787 of 791 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/zh_Hans/
2026-02-24 04:09:55 +01:00
anton garcias
1fa381429d Translated using Weblate (Catalan)
Currently translated at 100.0% (791 of 791 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ca/
2026-02-24 04:09:54 +01:00
Massimo Pissarello
fae61174a7 Translated using Weblate (Italian)
Currently translated at 100.0% (791 of 791 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2026-02-24 04:09:52 +01:00
Sylvain Pichon
d06301ac80 Translated using Weblate (French)
Currently translated at 100.0% (791 of 791 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2026-02-24 04:09:51 +01:00
Marco Rios
f4bc9c93c3 Translated using Weblate (Spanish)
Currently translated at 99.3% (786 of 791 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2026-02-24 04:09:49 +01:00
mid
0172ab4311 Translated using Weblate (Japanese)
Currently translated at 100.0% (791 of 791 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ja/
2026-02-24 04:09:46 +01:00
jokob-sk
f1fc9f24b1 FE: README
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-24 07:53:58 +11:00
jokob-sk
c192f2c032 FE: mixed case on MACs work
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-24 07:27:30 +11:00
jokob-sk
a309f99c3d Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2026-02-24 07:08:43 +11:00
jokob-sk
54e9d52126 DOCS: readme
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-24 07:08:29 +11:00
jokob-sk
8fc78f02e9 BE: Better arpo-scan accuracy w/ system optimization
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-24 07:07:55 +11:00
Jokob @NetAlertX
123f715241 Merge pull request #1533 from adamoutler/llm-docs
Add LLMs.txt
2026-02-23 15:01:37 +11:00
Jokob @NetAlertX
446545e7eb Merge pull request #1534 from MrMeatikins/feat/docker-install-docs
Docs: Add Docker install instructions for MCP Agents
2026-02-23 15:00:26 +11:00
MrMeatikins
14625926f9 Revert env variables per jokob-sk review
Co-authored-by: jokob-sk <jokob.sk@gmail.com>
2026-02-22 22:37:24 -05:00
MrMeatikins
c7e754966e Simplify README to link official docs 2026-02-22 22:22:21 -05:00
MrMeatikins
4316a436eb Apply CodeRabbit suggestions 2026-02-22 22:20:28 -05:00
Adam Outler
fe22659794 coderabbit suggested changes 2026-02-23 03:15:21 +00:00
Adam Outler
cb0b3b607d Update front/llms.txt
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-02-22 22:11:40 -05:00
Adam Outler
53b2596902 Add LLMs.txt 2026-02-23 03:04:43 +00:00
jokob-sk
1a364e2fe2 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2026-02-22 23:13:15 +11:00
jokob-sk
2f1e5068e3 BE+FE: Unstable devices list (3 status changes in 1h)
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-22 23:12:46 +11:00
Jokob @NetAlertX
57118bc9bd Merge pull request #1500 from netalertx/next_release
Next release - deep link support after log in and refactor of index.php
2026-02-22 16:22:08 +11:00
Jokob @NetAlertX
25a81556e3 Refactor: Simplify login redirection logic and clean up UI test code 2026-02-22 05:20:05 +00:00
Jokob @NetAlertX
39f617be5f Refactor: Remove unused is_https_request function and related comments; clean up test_login function by removing unnecessary password list 2026-02-22 05:11:09 +00:00
Jokob @NetAlertX
c4c966ffa7 Refactor: Remove unused Remember Me schemas and related comments 2026-02-22 05:07:37 +00:00
Jokob @NetAlertX
f88aefe022 Refactor: Remove unused call_api function and related comments 2026-02-22 05:00:00 +00:00
Jokob @NetAlertX
54db347b94 Refactor: Clean up whitespace in deep link handling functions and tests 2026-02-22 04:54:43 +00:00
Jokob @NetAlertX
2ae87fca38 Refactor login functionality: Remove Remember Me feature and update tests for deep link support 2026-02-22 04:54:34 +00:00
Jokob @NetAlertX
8224363c45 Refactor authentication: Remove Remember Me API endpoints and schemas; implement cookie-based Remember Me functionality 2026-02-22 04:44:57 +00:00
Jokob @NetAlertX
eb399ec193 BE: Clean up whitespace in call_api function 2026-02-22 03:49:21 +00:00
Jokob @NetAlertX
70645e7ef3 server-side remember-me 2026-02-22 03:47:29 +00:00
Jokob @NetAlertX
0e94dcb091 Merge pull request #1530 from netalertx/main
sync
2026-02-22 14:21:47 +11:00
jokob-sk
a26137800d BE: # ---------------------------------------------------------------------------------#
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-22 11:44:20 +11:00
jokob-sk
63810bc536 BE: Parameters table, app.sql duplicate removal
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-22 11:17:34 +11:00
jokob-sk
57d451fcf4 BE: Parameters table, app.sql duplicate removal
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-22 10:28:30 +11:00
jokob-sk
bf6218e836 FE: mixed case on MACs broke node expansion/collapse
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-22 09:50:45 +11:00
jokob-sk
e9efabd562 FE: mixed case on MACs broke node expansion/collapse
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-22 09:47:00 +11:00
jokob-sk
eb0f705587 BE: devices.csv import from file did nt work becasue of too strict validation
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-22 08:30:40 +11:00
jokob-sk
2559702a6a BE+FE: better VLAN/SSID handling
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-22 08:08:48 +11:00
jokob-sk
6bbfc0637c BE+FE: better VLAN/SSID handling
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-21 23:55:53 +11:00
jokob-sk
688d49b5ae Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2026-02-21 14:19:09 +11:00
jokob-sk
ab7df4384e INS: handle LOADED_PLUGINS env variable
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-21 14:18:11 +11:00
Safeguard
2018636bf8 Translated using Weblate (Russian)
Currently translated at 100.0% (790 of 790 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2026-02-20 09:09:51 +01:00
jokob-sk
50f341e84f BE: force upgrade of unifi-sm-api>=0.2.3 #1524
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-20 07:44:49 +11:00
PlanBot
32c21b01bb feat(docs): Update Docker install guide and templates
- Add --force-recreate to install commands for easier version switching

- Remove debug flags (ALWAYS_FRESH_INSTALL, NETALERTX_DEBUG) from templates

- Link to official DOCKER_COMPOSE environment variable docs
2026-02-19 12:30:50 -05:00
jokob-sk
05c332867b BE: force upgrade of unifi-sm-api>=0.2.2 #1524
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-19 14:22:23 +11:00
jokob-sk
12b0d911ff DOCS: UNIFIAPI
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-19 14:10:47 +11:00
jokob-sk
04884a264b DOCS: bug #1524
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-19 09:09:31 +11:00
jokob-sk
2742414123 BE: /health endpoint
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-18 22:29:12 +11:00
jokob-sk
876cd4bbe1 BE: psutils missing
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-18 13:08:34 +11:00
jokob-sk
91775deaa3 BE: psutil missing
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-18 12:04:03 +11:00
jokob-sk
7075091569 BE: psutil missing
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-18 11:35:18 +11:00
jokob-sk
f63658af7d Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2026-02-18 11:17:43 +11:00
jokob-sk
774c123804 BE: psutil missing
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-18 11:17:25 +11:00
Jokob @NetAlertX
32e2d571a0 Merge pull request #1521 from netalertx/chore_timestamps
feat: add health check endpoint and related schemas with tests
2026-02-18 10:35:53 +11:00
Jokob @NetAlertX
f2af4ffdb8 Merge branch 'chore_timestamps' of https://github.com/netalertx/NetAlertX into chore_timestamps 2026-02-17 23:17:05 +00:00
Jokob @NetAlertX
bc97a80375 fix: update health check response and schema to handle nullable memory and storage usage 2026-02-17 23:16:21 +00:00
Jokob @NetAlertX
fa36adb015 Merge branch 'main' into chore_timestamps 2026-02-18 10:05:25 +11:00
Jokob @NetAlertX
264cae3338 feat: add health check endpoint and related schemas with tests 2026-02-17 23:01:49 +00:00
jokob-sk
b594472f30 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2026-02-18 09:20:37 +11:00
jokob-sk
6d98ee9c2a DOCS: migration
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-18 09:20:19 +11:00
Sylvain Pichon
1181b56b16 Translated using Weblate (French)
Currently translated at 100.0% (790 of 790 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2026-02-17 07:09:46 +00:00
jokob-sk
4b58f3b23f BE+FE: refactor timezone UTC additional work #1506
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-16 13:17:31 +11:00
jokob-sk
e61bf097ac BE+FE: refactor timezone UTC additional work #1506
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-15 16:52:15 +11:00
jokob-sk
64dbf8a3ba BE: lint
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-15 16:31:56 +11:00
jokob-sk
5685a67483 BE: lint
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-15 16:25:11 +11:00
jokob-sk
c1e6a69e05 BE+FE: legacy sync endpoint removal - see release notes
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-15 16:20:34 +11:00
jokob-sk
3587169791 BE+FE: refactor timezone UTC additional work #1506
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-15 16:13:53 +11:00
jokob-sk
fd71527b09 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2026-02-15 13:59:31 +11:00
jokob-sk
9676111ceb BE: Events deduplication and uniqueness
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-15 13:59:15 +11:00
Sylvain Pichon
60036a49c2 Translated using Weblate (French)
Currently translated at 99.8% (789 of 790 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2026-02-15 01:09:58 +01:00
batman
60ccfc734d Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.2% (784 of 790 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/zh_Hans/
2026-02-15 01:09:56 +01:00
mid
c91532f3de Translated using Weblate (Japanese)
Currently translated at 96.2% (760 of 790 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ja/
2026-02-15 01:09:54 +01:00
ود علم الهدي
aeaab6d408 Translated using Weblate (Arabic)
Currently translated at 86.5% (684 of 790 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ar/
2026-02-15 01:09:51 +01:00
Massimo Pissarello
5e492bc81e Translated using Weblate (Italian)
Currently translated at 100.0% (790 of 790 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2026-02-15 01:09:48 +01:00
Максим Горпиніч
db689ac269 Translated using Weblate (Ukrainian)
Currently translated at 98.8% (781 of 790 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/uk/
2026-02-15 01:09:47 +01:00
Safeguard
bb39bde9dd Translated using Weblate (Russian)
Currently translated at 99.8% (789 of 790 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2026-02-15 01:09:45 +01:00
jokob-sk
46781ed71a DOCS: dummy devices
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-15 07:50:33 +11:00
jokob-sk
a313b0ccc5 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2026-02-14 10:43:39 +11:00
jokob-sk
2765e441a5 BE+FE: Check if current mac != parent mac for network page setup #1513
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-14 10:43:24 +11:00
Jokob @NetAlertX
eb35e80916 Merge pull request #1510 from adamoutler/proxy-docs
Create new Reverse Proxy.md, remove old
2026-02-13 07:20:38 +11:00
Adam Outler
4e7df766eb Improve explanation of reverse proxy benefits
Clarified the importance of using a reverse proxy for securing API access.
2026-02-12 14:51:27 -05:00
jokob-sk
e741ff51b5 LANG: Vietnamese (vi_vn)
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-12 19:20:44 +11:00
Adam Outler
a81255fb18 Remove Backend API URL section from SKILL.md
Removed section about Backend API URL configuration.
2026-02-12 01:49:54 -05:00
Adam Outler
5caa240fcd Create new Reverse Proxy.md, remove old 2026-02-12 02:28:07 +00:00
jokob-sk
888d39d2fb DOCS: ADVISORIES
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-11 17:56:08 +11:00
jokob-sk
b57d36607a BE+FE: refactor timezone UTC #1506
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-11 16:15:49 +11:00
jokob-sk
70c3530a5c Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2026-02-11 15:33:52 +11:00
Jokob @NetAlertX
7af850cb56 Merge pull request #1508 from netalertx/chore_timestamps
timestamp cleanup
2026-02-11 15:23:56 +11:00
Jokob @NetAlertX
9ac8f6fe34 fixes 2026-02-11 04:21:03 +00:00
Jokob @NetAlertX
933004e792 fixes 2026-02-11 03:56:37 +00:00
Jokob @NetAlertX
45157b6156 timestamp cleanup 2026-02-11 01:55:02 +00:00
jokob-sk
a560009611 TEST: fixing totals assert check dynamically
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-11 10:25:19 +11:00
jokob-sk
e0d4e9ea9c GIT: ignore
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-11 10:04:56 +11:00
jokob-sk
249d12ded4 suggestions 2026-02-11 09:10:37 +11:00
jokob-sk
e899f657c5 BE+FE: refactor totals retrieval + LUCIRPC old field name
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-10 07:39:11 +11:00
jokob-sk
3036cd04fc add redirect after log in to support deep links
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-09 12:49:50 +11:00
jokob-sk
3d3abe7e53 add redirect after log in to support deep links
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-09 10:22:03 +11:00
jokob-sk
a088f4580a add redirect after log in to support deep links
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-09 10:11:21 +11:00
jokob-sk
75c7d6c015 add redirect after log in to support deep links
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-09 09:41:20 +11:00
Jokob @NetAlertX
d434cc5315 Merge pull request #1499 from netalertx/main
sync
2026-02-09 09:38:55 +11:00
Safeguard
cedbd59897 Translated using Weblate (Russian)
Currently translated at 100.0% (790 of 790 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2026-02-08 15:09:45 +00:00
Jokob @NetAlertX
b703397543 Merge pull request #1497 from adamoutler/improve-403-message
Add descriptive 403 for /server endpoint
2026-02-08 13:47:19 +11:00
Adam Outler
9c4e02f565 Add 403 message which describes the problem 2026-02-08 02:33:11 +00:00
Jokob @NetAlertX
3510afec7a Merge pull request #1494 from adamoutler/separate-app.sql
move app.
2026-02-08 08:35:25 +11:00
Adam Outler
ed44c68d54 Update scripts/db_cleanup/regenerate-database.sh
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-02-07 10:29:57 -05:00
Adam Outler
30c832b14e move app. 2026-02-07 15:20:49 +00:00
jokob-sk
d7f17c8e78 FIX: lowercase MAC normalization across project v0.4
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-07 14:12:51 +11:00
jokob-sk
8538c87fef FIX: lowercase MAC normalization across project v0.3
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-07 14:08:14 +11:00
jokob-sk
1bacb59044 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2026-02-07 14:02:59 +11:00
jokob-sk
827b5d2ad3 FIX: lowercase MAC normalization across project v0.2
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-07 14:02:54 +11:00
Jokob @NetAlertX
e70bbdb78e Merge pull request #1490 from adamoutler/testing-resilliancy
Enhance Testing Resilliancy
2026-02-07 13:45:17 +11:00
jokob-sk
946ad00253 FIX: lowercase MAC normalization across project v0.1
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-07 13:44:50 +11:00
jokob-sk
3734c43284 DOCS: Multiple NICs on Same Host Reporting Same IP
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-07 10:55:10 +11:00
jokob-sk
0ce4e5f70c BE+FE: work on bulk deleting devices and code cleanup #1493
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-07 10:37:31 +11:00
jokob-sk
6bc2de6e24 TEST: scan processing - de;eted
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-06 18:54:15 +11:00
jokob-sk
09b42166cc TEST: scan processing 9
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-06 18:48:40 +11:00
jokob-sk
dbe490a042 TEST: scan processing 8
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-06 18:43:53 +11:00
jokob-sk
5996e70f60 TEST: scan processing 7
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-06 18:39:08 +11:00
jokob-sk
15366a7f2e TEST: scan processing 6 + css fixes
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-06 18:34:25 +11:00
jokob-sk
d5d1684ef9 TEST: scan processing 5
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-06 18:21:24 +11:00
jokob-sk
c1141fc9a8 TEST: scan processing 4
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-06 18:12:16 +11:00
jokob-sk
d38dcda35b TEST: scan processing 3
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-06 18:06:57 +11:00
jokob-sk
ac5224747e TEST: scan processing 2
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-06 18:03:17 +11:00
jokob-sk
5c23bde21c TEST: scan processing 1
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-06 17:57:03 +11:00
jokob-sk
8e83d9b67d BE: Removal of debug code taht was causing devices to appear online #1489
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-06 14:18:15 +11:00
jokob-sk
30c004eb77 GIT: static code check for disabled CurrentScan cleanup - test
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-06 14:13:53 +11:00
Adam Outler
c074ce1b11 fix Potential UnboundLocalError 2026-02-05 20:45:45 +00:00
Adam Outler
5e40ea83d9 Update .gitignore
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-02-05 15:41:46 -05:00
Adam Outler
2124c2e1e2 enhance testing resilliancy 2026-02-05 16:37:32 +00:00
jokob-sk
1b6dc94bae Deleting Plugin Objects was not possible #1486
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-05 11:57:37 +11:00
jokob-sk
76d37edc63 jokob-sk/netalertx -> netalertx/netalertx
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2026-02-04 21:21:05 +11:00
347 changed files with 16356 additions and 8762 deletions

View File

@@ -35,6 +35,7 @@ RUN apk add --no-cache \
shadow \ shadow \
python3 \ python3 \
python3-dev \ python3-dev \
py3-psutil \
gcc \ gcc \
musl-dev \ musl-dev \
libffi-dev \ libffi-dev \
@@ -136,7 +137,7 @@ ENV LANG=C.UTF-8
RUN apk add --no-cache bash mtr libbsd zip lsblk tzdata curl arp-scan iproute2 iproute2-ss nmap fping \ RUN apk add --no-cache bash mtr libbsd zip lsblk tzdata curl arp-scan iproute2 iproute2-ss nmap fping \
nmap-scripts traceroute nbtscan net-tools net-snmp-tools bind-tools awake ca-certificates \ nmap-scripts traceroute nbtscan net-tools net-snmp-tools bind-tools awake ca-certificates \
sqlite php83 php83-fpm php83-cgi php83-curl php83-sqlite3 php83-session python3 envsubst \ sqlite php83 php83-fpm php83-cgi php83-curl php83-sqlite3 php83-session python3 py3-psutil envsubst \
nginx supercronic shadow su-exec jq && \ nginx supercronic shadow su-exec jq && \
rm -Rf /var/cache/apk/* && \ rm -Rf /var/cache/apk/* && \
rm -Rf /etc/nginx && \ rm -Rf /etc/nginx && \

1
.env
View File

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

View File

@@ -5,6 +5,15 @@ description: NetAlertX coding standards and conventions. Use this when writing c
# Code Standards # Code Standards
- ask me to review before going to each next step (mention n step out of x) (AI only)
- before starting, prepare implementation plan (AI only)
- ask me to review it and ask any clarifying questions first
- add test creation as last step - follow repo architecture patterns - do not place in the root of /test
- code has to be maintainable, no duplicate code
- follow DRY principle - maintainability of code is more important than speed of implementation
- code files should be less than 500 LOC for better maintainability
- DB columns must not contain underscores, use camelCase instead (e.g., deviceInstanceId, not device_instance_id)
## File Length ## File Length
Keep code files under 500 lines. Split larger files into modules. Keep code files under 500 lines. Split larger files into modules.
@@ -42,14 +51,21 @@ Nested subprocess calls need their own timeout—outer timeout won't save you.
## Time Utilities ## Time Utilities
```python ```python
from utils.datetime_utils import timeNowDB from utils.datetime_utils import timeNowUTC
timestamp = timeNowDB() timestamp = timeNowUTC()
``` ```
This is the ONLY function that calls datetime.datetime.now() in the entire codebase.
⚠️ CRITICAL: ALL database timestamps MUST be stored in UTC
This is the SINGLE SOURCE OF TRUTH for current time in NetAlertX
Use timeNowUTC() for DB writes (returns UTC string by default)
Use timeNowUTC(as_string=False) for datetime operations (scheduling, comparisons, logging)
## String Sanitization ## String Sanitization
Use sanitizers from `server/helper.py` before storing user input. Use sanitizers from `server/helper.py` before storing user input. MAC addresses are always lowercased and normalized. IP addresses should be validated.
## Devcontainer Constraints ## Devcontainer Constraints

View File

@@ -37,11 +37,3 @@ Define in plugin's `config.json` manifest under the settings section.
## Environment Override ## Environment Override
Use `APP_CONF_OVERRIDE` environment variable for settings that must be set before startup. Use `APP_CONF_OVERRIDE` environment variable for settings that must be set before startup.
## Backend API URL
For Codespaces, set `BACKEND_API_URL` to your Codespace URL:
```
BACKEND_API_URL=https://something-20212.app.github.dev/
```

View File

@@ -17,6 +17,23 @@ jobs:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: 🚨 Ensure DELETE FROM CurrentScan is not commented out
run: |
echo "🔍 Checking that DELETE FROM CurrentScan is not commented out..."
MATCHES=$(grep -RInE '^[[:space:]]*#[[:space:]]*db\.sql\.execute\("DELETE FROM CurrentScan"\)' \
--include="*.py" .) || true
if [ -n "$MATCHES" ]; then
echo "❌ Found commented-out DELETE FROM CurrentScan call:"
echo "$MATCHES"
echo
echo "This line must NOT be commented out in committed code."
exit 1
else
echo "✅ DELETE FROM CurrentScan is active."
fi
- name: Check for incorrect absolute '/php/' URLs in frontend code - name: Check for incorrect absolute '/php/' URLs in frontend code
run: | run: |
echo "🔍 Checking for incorrect absolute '/php/' URLs (should be 'php/' or './php/')..." echo "🔍 Checking for incorrect absolute '/php/' URLs (should be 'php/' or './php/')..."

View File

@@ -22,8 +22,10 @@ jobs:
- name: Install MkDocs - name: Install MkDocs
run: | run: |
pip install mkdocs mkdocs-material pip install \
pip install mkdocs-github-admonitions-plugin mkdocs==1.6.0 \
mkdocs-material==9.5.21 \
mkdocs-github-admonitions-plugin==0.0.4
- name: Build MkDocs - name: Build MkDocs
run: mkdocs build run: mkdocs build

View File

@@ -3,8 +3,12 @@ name: 🧪 Manual Test Suite Selector
on: on:
workflow_dispatch: workflow_dispatch:
inputs: inputs:
run_authoritative: run_all:
description: '📂 authoritative_fields/ (Logic, Locks, IPs)' description: '✅ Run ALL tests (overrides individual selectors)'
type: boolean
default: false
run_scan:
description: '📂 scan/ (Scan, Logic, Locks, IPs)'
type: boolean type: boolean
default: true default: true
run_api: run_api:
@@ -12,7 +16,7 @@ on:
type: boolean type: boolean
default: false default: false
run_backend: run_backend:
description: '📂 backend/ (SQL Builder & Security)' description: '📂 backend/ & db/ (SQL Builder, Security & Migration)'
type: boolean type: boolean
default: false default: false
run_docker_env: run_docker_env:
@@ -23,6 +27,10 @@ on:
description: '📂 ui/ (Selenium & Dashboard)' description: '📂 ui/ (Selenium & Dashboard)'
type: boolean type: boolean
default: false default: false
run_plugins:
description: '📂 plugins/ (Sync insert schema-aware logic)'
type: boolean
default: false
run_root_files: run_root_files:
description: '📄 Root Test Files (WOL, Atomicity, etc.)' description: '📄 Root Test Files (WOL, Atomicity, etc.)'
type: boolean type: boolean
@@ -42,12 +50,20 @@ jobs:
id: builder id: builder
run: | run: |
PATHS="" PATHS=""
# run_all overrides everything
if [ "${{ github.event.inputs.run_all }}" == "true" ]; then
echo "final_paths=test/" >> $GITHUB_OUTPUT
exit 0
fi
# Folder Mapping with 'test/' prefix # Folder Mapping with 'test/' prefix
if [ "${{ github.event.inputs.run_authoritative }}" == "true" ]; then PATHS="$PATHS test/authoritative_fields/"; fi if [ "${{ github.event.inputs.run_scan }}" == "true" ]; then PATHS="$PATHS test/scan/"; fi
if [ "${{ github.event.inputs.run_api }}" == "true" ]; then PATHS="$PATHS test/api_endpoints/ test/server/"; fi if [ "${{ github.event.inputs.run_api }}" == "true" ]; then PATHS="$PATHS test/api_endpoints/ test/server/"; fi
if [ "${{ github.event.inputs.run_backend }}" == "true" ]; then PATHS="$PATHS test/backend/"; fi if [ "${{ github.event.inputs.run_backend }}" == "true" ]; then PATHS="$PATHS test/backend/ test/db/"; fi
if [ "${{ github.event.inputs.run_docker_env }}" == "true" ]; then PATHS="$PATHS test/docker_tests/"; fi if [ "${{ github.event.inputs.run_docker_env }}" == "true" ]; then PATHS="$PATHS test/docker_tests/"; fi
if [ "${{ github.event.inputs.run_ui }}" == "true" ]; then PATHS="$PATHS test/ui/"; fi if [ "${{ github.event.inputs.run_ui }}" == "true" ]; then PATHS="$PATHS test/ui/"; fi
if [ "${{ github.event.inputs.run_plugins }}" == "true" ]; then PATHS="$PATHS test/plugins/"; fi
# Root Files Mapping (files sitting directly in /test/) # Root Files Mapping (files sitting directly in /test/)
if [ "${{ github.event.inputs.run_root_files }}" == "true" ]; then if [ "${{ github.event.inputs.run_root_files }}" == "true" ]; then

2
.gitignore vendored
View File

@@ -24,6 +24,8 @@ front/api/*
/api/* /api/*
**/plugins/**/*.log **/plugins/**/*.log
**/plugins/cloud_services/* **/plugins/cloud_services/*
**/plugins/cloud_connector/*
**/plugins/heartbeat/*
**/%40eaDir/ **/%40eaDir/
**/@eaDir/ **/@eaDir/

View File

@@ -1,23 +1,38 @@
# 🤝 Contributing to NetAlertX # Contributing to NetAlertX
First off, **thank you** for taking the time to contribute! NetAlertX is built and improved with the help of passionate people like you. First off, **thank you** for taking the time to contribute! NetAlertX is built and improved with the help of passionate people like you.
--- ---
## 📂 Issues, Bugs, and Feature Requests ## Issues, Bugs, and Feature Requests
Please use the [GitHub Issue Tracker](https://github.com/jokob-sk/NetAlertX/issues) for: Please use the [GitHub Issue Tracker](https://github.com/netalertx/NetAlertX/issues) for:
- Bug reports 🐞 - Bug reports
- Feature requests 💡 - Feature requests
- Documentation feedback 📖 - Documentation feedback
Before opening a new issue: Before opening a new issue:
- 🛑 [Check Common Issues & Debug Tips](https://docs.netalertx.com/DEBUG_TIPS#common-issues) - [Check Common Issues & Debug Tips](https://docs.netalertx.com/DEBUG_TIPS#common-issues)
- 🔍 [Search Closed Issues](https://github.com/jokob-sk/NetAlertX/issues?q=is%3Aissue+is%3Aclosed) - [Search Closed Issues](https://github.com/netalertx/NetAlertX/issues?q=is%3Aissue+is%3Aclosed)
--- ---
## 🚀 Submitting Pull Requests (PRs) ## Use of AI
Use of AI-assisted tools is permitted, provided all generated code is reviewed, understood, and verified before submission.
- All AI-generated code must meet the project's **quality, security, and performance standards**.
- Contributors are responsible for **fully understanding** any code they submit, regardless of how it was produced.
- Prefer **clarity and maintainability over cleverness or brevity**. Readable code is always favored over dense or obfuscated implementations.
- Follow the **DRY (Don't Repeat Yourself) principle** where appropriate, without sacrificing readability.
- Do not submit code that you cannot confidently explain or debug.
All changes must pass the **full test suite** before opening a PR.
---
## Submitting Pull Requests (PRs)
We welcome PRs to improve the code, docs, or UI! We welcome PRs to improve the code, docs, or UI!
@@ -28,10 +43,23 @@ Please:
- Provide a clear title and description for your PR - Provide a clear title and description for your PR
- If relevant, add or update tests and documentation - If relevant, add or update tests and documentation
- For plugins, refer to the [Plugin Dev Guide](https://docs.netalertx.com/PLUGINS_DEV) - For plugins, refer to the [Plugin Dev Guide](https://docs.netalertx.com/PLUGINS_DEV)
- Switch the PR to DRAFT mode if still being worked on
- Keep PRs **focused and minimal** — avoid unrelated changes in a single PR
- PRs that do not meet these guidelines may be closed without review
## Commit Messages
- Use clear, descriptive commit messages
- Explain *why* a change was made, not just *what* changed
- Reference related issues where applicable
## Code Quality
- Read and follow the [code standards](/.github/skills/code-standards/SKILL.md)
--- ---
## 🌟 First-Time Contributors ## First-Time Contributors
New to open source? Check out these resources: New to open source? Check out these resources:
- [How to Fork and Submit a PR](https://opensource.guide/how-to-contribute/) - [How to Fork and Submit a PR](https://opensource.guide/how-to-contribute/)
@@ -39,15 +67,15 @@ New to open source? Check out these resources:
--- ---
## 🔐 Code of Conduct ## Code of Conduct
By participating, you agree to follow our [Code of Conduct](./CODE_OF_CONDUCT.md), which ensures a respectful and welcoming community. By participating, you agree to follow our [Code of Conduct](./CODE_OF_CONDUCT.md), which ensures a respectful and welcoming community.
--- ---
## 📬 Contact ## Contact
If you have more in-depth questions or want to discuss contributing in other ways, feel free to reach out at: If you have more in-depth questions or want to discuss contributing in other ways, feel free to reach out at:
📧 [jokob@duck.com](mailto:jokob@duck.com?subject=NetAlertX%20Contribution) [jokob.sk@gmail.com](mailto:jokob.sk@gmail.com?subject=NetAlertX%20Contribution)
We appreciate every contribution, big or small! 💙 We appreciate every contribution, big or small! 💙

View File

@@ -32,6 +32,7 @@ RUN apk add --no-cache \
shadow \ shadow \
python3 \ python3 \
python3-dev \ python3-dev \
py3-psutil \
gcc \ gcc \
musl-dev \ musl-dev \
libffi-dev \ libffi-dev \
@@ -133,7 +134,7 @@ ENV LANG=C.UTF-8
RUN apk add --no-cache bash mtr libbsd zip lsblk tzdata curl arp-scan iproute2 iproute2-ss nmap fping \ RUN apk add --no-cache bash mtr libbsd zip lsblk tzdata curl arp-scan iproute2 iproute2-ss nmap fping \
nmap-scripts traceroute nbtscan net-tools net-snmp-tools bind-tools awake ca-certificates \ nmap-scripts traceroute nbtscan net-tools net-snmp-tools bind-tools awake ca-certificates \
sqlite php83 php83-fpm php83-cgi php83-curl php83-sqlite3 php83-session python3 envsubst \ sqlite php83 php83-fpm php83-cgi php83-curl php83-sqlite3 php83-session python3 py3-psutil envsubst \
nginx supercronic shadow su-exec jq && \ nginx supercronic shadow su-exec jq && \
rm -Rf /var/cache/apk/* && \ rm -Rf /var/cache/apk/* && \
rm -Rf /etc/nginx && \ rm -Rf /etc/nginx && \

View File

@@ -10,6 +10,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
python3 \ python3 \
python3-dev \ python3-dev \
python3-pip \ python3-pip \
python3-psutil \
python3-venv \ python3-venv \
gcc \ gcc \
git \ git \

View File

@@ -1,6 +1,6 @@
[![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 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) [![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) [![GitHub Release](https://img.shields.io/github/v/release/netalertx/NetAlertX?color=0aa8d2&logoColor=fff&logo=GitHub&style=for-the-badge)](https://github.com/netalertx/NetAlertX/releases)
[![Discord](https://img.shields.io/discord/1274490466481602755?color=0aa8d2&logoColor=fff&logo=Discord&style=for-the-badge)](https://discord.gg/NczTUTWyRr) [![Discord](https://img.shields.io/discord/1274490466481602755?color=0aa8d2&logoColor=fff&logo=Discord&style=for-the-badge)](https://discord.gg/NczTUTWyRr)
[![Home Assistant](https://img.shields.io/badge/Repo-blue?logo=home-assistant&style=for-the-badge&color=0aa8d2&logoColor=fff&label=Add)](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Falexbelgium%2Fhassio-addons) [![Home Assistant](https://img.shields.io/badge/Repo-blue?logo=home-assistant&style=for-the-badge&color=0aa8d2&logoColor=fff&label=Add)](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Falexbelgium%2Fhassio-addons)
@@ -56,14 +56,14 @@ docker run -d \
--tmpfs /tmp:uid=20211,gid=20211,mode=1700 \ --tmpfs /tmp:uid=20211,gid=20211,mode=1700 \
-e PORT=20211 \ -e PORT=20211 \
-e APP_CONF_OVERRIDE='{"GRAPHQL_PORT":"20214"}' \ -e APP_CONF_OVERRIDE='{"GRAPHQL_PORT":"20214"}' \
ghcr.io/jokob-sk/netalertx:latest ghcr.io/netalertx/netalertx:latest
``` ```
Note: Your `/local_data_dir` should contain a `config` and `db` folder. Note: Your `/local_data_dir` should contain a `config` and `db` folder.
To deploy a containerized instance directly from the source repository, execute the following BASH sequence: To deploy a containerized instance directly from the source repository, execute the following BASH sequence:
```bash ```bash
git clone https://github.com/jokob-sk/NetAlertX.git git clone https://github.com/netalertx/NetAlertX.git
cd NetAlertX cd NetAlertX
docker compose up --force-recreate --build docker compose up --force-recreate --build
# To customize: edit docker-compose.yaml and run that last command again # To customize: edit docker-compose.yaml and run that last command again
@@ -168,9 +168,9 @@ Get notified about a new release, what new functionality you can use and about b
### 🔀 Other Alternative Apps ### 🔀 Other Alternative Apps
- [Fing](https://www.fing.com/) - Network scanner app for your Internet security (Commercial, Phone App, Proprietary hardware) - [Fing](https://www.fing.com/) - Network scanner app for your Internet security (Commercial, Phone App, Proprietary hardware)
- [NetBox](https://netboxlabs.com/) - Network management software (Commercial) - [NetBox](https://netboxlabs.com/) - The gold standard for Network Source of Truth (NSoT) and IPAM.
- [Zabbix](https://www.zabbix.com/) or [Nagios](https://www.nagios.org/) - Strong focus on infrastructure monitoring. - [Zabbix](https://www.zabbix.com/) or [Nagios](https://www.nagios.org/) - Strong focus on infrastructure monitoring.
- [NetAlertX](https://netalertx.com) - The streamlined, discovery-focused alternative for real-time asset intelligence. - [NetAlertX](https://netalertx.com) - The streamlined, discovery-focused choice for real-time asset intelligence and noise-free alerting.
### 💙 Donations ### 💙 Donations
@@ -207,6 +207,7 @@ Proudly using [Weblate](https://hosted.weblate.org/projects/pialert/). Help out
### License ### License
> GPL 3.0 | [Read more here](LICENSE.txt) | Source of the [animated GIF (Loading Animation)](https://commons.wikimedia.org/wiki/File:Loading_Animation.gif) | Source of the [selfhosted Fonts](https://github.com/adobe-fonts/source-sans) > GPL 3.0 | [Read more here](LICENSE.txt) | Source of the [animated GIF (Loading Animation)](https://commons.wikimedia.org/wiki/File:Loading_Animation.gif) | Source of the [selfhosted Fonts](https://github.com/adobe-fonts/source-sans)
_All product names, logos, and brands are property of their respective owners. All company, product and service names used in this website are for identification purposes only. Use of these names, logos, and brands does not imply endorsement._
<!--- --------------------------------------------------------------------- ---> <!--- --------------------------------------------------------------------- --->
[main]: ./docs/img/devices_split.png "Main screen" [main]: ./docs/img/devices_split.png "Main screen"

View File

@@ -3,7 +3,7 @@
# Generated: 2022-12-30_22-19-40 # # Generated: 2022-12-30_22-19-40 #
# # # #
# Config file for the LAN intruder detection app: # # Config file for the LAN intruder detection app: #
# https://github.com/jokob-sk/NetAlertX # # https://github.com/netalertx/NetAlertX #
# # # #
#-----------------AUTOGENERATED FILE-----------------# #-----------------AUTOGENERATED FILE-----------------#

View File

@@ -1,427 +0,0 @@
CREATE TABLE sqlite_stat1(tbl,idx,stat);
CREATE TABLE Events (eve_MAC STRING (50) NOT NULL COLLATE NOCASE, eve_IP STRING (50) NOT NULL COLLATE NOCASE, eve_DateTime DATETIME NOT NULL, eve_EventType STRING (30) NOT NULL COLLATE NOCASE, eve_AdditionalInfo STRING (250) DEFAULT (''), eve_PendingAlertEmail BOOLEAN NOT NULL CHECK (eve_PendingAlertEmail IN (0, 1)) DEFAULT (1), eve_PairEventRowid INTEGER);
CREATE TABLE Sessions (ses_MAC STRING (50) COLLATE NOCASE, ses_IP STRING (50) COLLATE NOCASE, ses_EventTypeConnection STRING (30) COLLATE NOCASE, ses_DateTimeConnection DATETIME, ses_EventTypeDisconnection STRING (30) COLLATE NOCASE, ses_DateTimeDisconnection DATETIME, ses_StillConnected BOOLEAN, ses_AdditionalInfo STRING (250));
CREATE TABLE IF NOT EXISTS "Online_History" (
"Index" INTEGER,
"Scan_Date" TEXT,
"Online_Devices" INTEGER,
"Down_Devices" INTEGER,
"All_Devices" INTEGER,
"Archived_Devices" INTEGER,
"Offline_Devices" INTEGER,
PRIMARY KEY("Index" AUTOINCREMENT)
);
CREATE TABLE sqlite_sequence(name,seq);
CREATE TABLE Devices (
devMac STRING (50) PRIMARY KEY NOT NULL COLLATE NOCASE,
devName STRING (50) NOT NULL DEFAULT "(unknown)",
devOwner STRING (30) DEFAULT "(unknown)" NOT NULL,
devType STRING (30),
devVendor STRING (250),
devFavorite BOOLEAN CHECK (devFavorite IN (0, 1)) DEFAULT (0) NOT NULL,
devGroup STRING (10),
devComments TEXT,
devFirstConnection DATETIME NOT NULL,
devLastConnection DATETIME NOT NULL,
devLastIP STRING (50) NOT NULL COLLATE NOCASE,
devPrimaryIPv4 TEXT,
devPrimaryIPv6 TEXT,
devVlan TEXT,
devForceStatus TEXT,
devStaticIP BOOLEAN DEFAULT (0) NOT NULL CHECK (devStaticIP IN (0, 1)),
devScan INTEGER DEFAULT (1) NOT NULL,
devLogEvents BOOLEAN NOT NULL DEFAULT (1) CHECK (devLogEvents IN (0, 1)),
devAlertEvents BOOLEAN NOT NULL DEFAULT (1) CHECK (devAlertEvents IN (0, 1)),
devAlertDown BOOLEAN NOT NULL DEFAULT (0) CHECK (devAlertDown IN (0, 1)),
devSkipRepeated INTEGER DEFAULT 0 NOT NULL,
devLastNotification DATETIME,
devPresentLastScan BOOLEAN NOT NULL DEFAULT (0) CHECK (devPresentLastScan IN (0, 1)),
devIsNew BOOLEAN NOT NULL DEFAULT (1) CHECK (devIsNew IN (0, 1)),
devLocation STRING (250) COLLATE NOCASE,
devIsArchived BOOLEAN NOT NULL DEFAULT (0) CHECK (devIsArchived IN (0, 1)),
devParentMAC TEXT,
devParentPort INTEGER,
devParentRelType TEXT,
devIcon TEXT,
devGUID TEXT,
devSite TEXT,
devSSID TEXT,
devSyncHubNode TEXT,
devSourcePlugin TEXT,
devMacSource TEXT,
devNameSource TEXT,
devFQDNSource TEXT,
devLastIPSource TEXT,
devVendorSource TEXT,
devSSIDSource TEXT,
devParentMACSource TEXT,
devParentPortSource TEXT,
devParentRelTypeSource TEXT,
devVlanSource TEXT,
"devCustomProps" TEXT);
CREATE TABLE IF NOT EXISTS "Settings" (
"setKey" TEXT,
"setName" TEXT,
"setDescription" TEXT,
"setType" TEXT,
"setOptions" TEXT,
"setGroup" TEXT,
"setValue" TEXT,
"setEvents" TEXT,
"setOverriddenByEnv" INTEGER
);
CREATE TABLE IF NOT EXISTS "Parameters" (
"par_ID" TEXT PRIMARY KEY,
"par_Value" TEXT
);
CREATE TABLE Plugins_Objects(
"Index" INTEGER,
Plugin TEXT NOT NULL,
Object_PrimaryID TEXT NOT NULL,
Object_SecondaryID TEXT NOT NULL,
DateTimeCreated TEXT NOT NULL,
DateTimeChanged TEXT NOT NULL,
Watched_Value1 TEXT NOT NULL,
Watched_Value2 TEXT NOT NULL,
Watched_Value3 TEXT NOT NULL,
Watched_Value4 TEXT NOT NULL,
Status TEXT NOT NULL,
Extra TEXT NOT NULL,
UserData TEXT NOT NULL,
ForeignKey TEXT NOT NULL,
SyncHubNodeName TEXT,
"HelpVal1" TEXT,
"HelpVal2" TEXT,
"HelpVal3" TEXT,
"HelpVal4" TEXT,
ObjectGUID TEXT,
PRIMARY KEY("Index" AUTOINCREMENT)
);
CREATE TABLE Plugins_Events(
"Index" INTEGER,
Plugin TEXT NOT NULL,
Object_PrimaryID TEXT NOT NULL,
Object_SecondaryID TEXT NOT NULL,
DateTimeCreated TEXT NOT NULL,
DateTimeChanged TEXT NOT NULL,
Watched_Value1 TEXT NOT NULL,
Watched_Value2 TEXT NOT NULL,
Watched_Value3 TEXT NOT NULL,
Watched_Value4 TEXT NOT NULL,
Status TEXT NOT NULL,
Extra TEXT NOT NULL,
UserData TEXT NOT NULL,
ForeignKey TEXT NOT NULL,
SyncHubNodeName TEXT,
"HelpVal1" TEXT,
"HelpVal2" TEXT,
"HelpVal3" TEXT,
"HelpVal4" TEXT, "ObjectGUID" TEXT,
PRIMARY KEY("Index" AUTOINCREMENT)
);
CREATE TABLE Plugins_History(
"Index" INTEGER,
Plugin TEXT NOT NULL,
Object_PrimaryID TEXT NOT NULL,
Object_SecondaryID TEXT NOT NULL,
DateTimeCreated TEXT NOT NULL,
DateTimeChanged TEXT NOT NULL,
Watched_Value1 TEXT NOT NULL,
Watched_Value2 TEXT NOT NULL,
Watched_Value3 TEXT NOT NULL,
Watched_Value4 TEXT NOT NULL,
Status TEXT NOT NULL,
Extra TEXT NOT NULL,
UserData TEXT NOT NULL,
ForeignKey TEXT NOT NULL,
SyncHubNodeName TEXT,
"HelpVal1" TEXT,
"HelpVal2" TEXT,
"HelpVal3" TEXT,
"HelpVal4" TEXT, "ObjectGUID" TEXT,
PRIMARY KEY("Index" AUTOINCREMENT)
);
CREATE TABLE Plugins_Language_Strings(
"Index" INTEGER,
Language_Code TEXT NOT NULL,
String_Key TEXT NOT NULL,
String_Value TEXT NOT NULL,
Extra TEXT NOT NULL,
PRIMARY KEY("Index" AUTOINCREMENT)
);
CREATE TABLE CurrentScan (
scanMac STRING(50) NOT NULL COLLATE NOCASE,
scanLastIP STRING(50) NOT NULL COLLATE NOCASE,
scanVendor STRING(250),
scanSourcePlugin STRING(10),
scanName STRING(250),
scanLastQuery STRING(250),
scanLastConnection STRING(250),
scanSyncHubNode STRING(50),
scanSite STRING(250),
scanSSID STRING(250),
scanVlan STRING(250),
scanParentMAC STRING(250),
scanParentPort STRING(250),
scanType STRING(250),
UNIQUE(scanMac)
);
CREATE TABLE IF NOT EXISTS "AppEvents" (
"Index" INTEGER PRIMARY KEY AUTOINCREMENT,
"GUID" TEXT UNIQUE,
"AppEventProcessed" BOOLEAN,
"DateTimeCreated" TEXT,
"ObjectType" TEXT,
"ObjectGUID" TEXT,
"ObjectPlugin" TEXT,
"ObjectPrimaryID" TEXT,
"ObjectSecondaryID" TEXT,
"ObjectForeignKey" TEXT,
"ObjectIndex" TEXT,
"ObjectIsNew" BOOLEAN,
"ObjectIsArchived" BOOLEAN,
"ObjectStatusColumn" TEXT,
"ObjectStatus" TEXT,
"AppEventType" TEXT,
"Helper1" TEXT,
"Helper2" TEXT,
"Helper3" TEXT,
"Extra" TEXT
);
CREATE TABLE IF NOT EXISTS "Notifications" (
"Index" INTEGER,
"GUID" TEXT UNIQUE,
"DateTimeCreated" TEXT,
"DateTimePushed" TEXT,
"Status" TEXT,
"JSON" TEXT,
"Text" TEXT,
"HTML" TEXT,
"PublishedVia" TEXT,
"Extra" TEXT,
PRIMARY KEY("Index" AUTOINCREMENT)
);
CREATE INDEX IDX_eve_DateTime ON Events (eve_DateTime);
CREATE INDEX IDX_eve_EventType ON Events (eve_EventType COLLATE NOCASE);
CREATE INDEX IDX_eve_MAC ON Events (eve_MAC COLLATE NOCASE);
CREATE INDEX IDX_eve_PairEventRowid ON Events (eve_PairEventRowid);
CREATE INDEX IDX_ses_EventTypeDisconnection ON Sessions (ses_EventTypeDisconnection COLLATE NOCASE);
CREATE INDEX IDX_ses_EventTypeConnection ON Sessions (ses_EventTypeConnection COLLATE NOCASE);
CREATE INDEX IDX_ses_DateTimeDisconnection ON Sessions (ses_DateTimeDisconnection);
CREATE INDEX IDX_ses_MAC ON Sessions (ses_MAC COLLATE NOCASE);
CREATE INDEX IDX_ses_DateTimeConnection ON Sessions (ses_DateTimeConnection);
CREATE INDEX IDX_dev_PresentLastScan ON Devices (devPresentLastScan);
CREATE INDEX IDX_dev_FirstConnection ON Devices (devFirstConnection);
CREATE INDEX IDX_dev_AlertDeviceDown ON Devices (devAlertDown);
CREATE INDEX IDX_dev_StaticIP ON Devices (devStaticIP);
CREATE INDEX IDX_dev_ScanCycle ON Devices (devScan);
CREATE INDEX IDX_dev_Favorite ON Devices (devFavorite);
CREATE INDEX IDX_dev_LastIP ON Devices (devLastIP);
CREATE INDEX IDX_dev_NewDevice ON Devices (devIsNew);
CREATE INDEX IDX_dev_Archived ON Devices (devIsArchived);
CREATE VIEW Events_Devices AS
SELECT *
FROM Events
LEFT JOIN Devices ON eve_MAC = devMac
/* Events_Devices(eve_MAC,eve_IP,eve_DateTime,eve_EventType,eve_AdditionalInfo,eve_PendingAlertEmail,eve_PairEventRowid,devMac,devName,devOwner,devType,devVendor,devFavorite,devGroup,devComments,devFirstConnection,devLastConnection,devLastIP,devStaticIP,devScan,devLogEvents,devAlertEvents,devAlertDown,devSkipRepeated,devLastNotification,devPresentLastScan,devIsNew,devLocation,devIsArchived,devParentMAC,devParentPort,devIcon,devGUID,devSite,devSSID,devSyncHubNode,devSourcePlugin,devCustomProps) */;
CREATE VIEW LatestEventsPerMAC AS
WITH RankedEvents AS (
SELECT
e.*,
ROW_NUMBER() OVER (PARTITION BY e.eve_MAC ORDER BY e.eve_DateTime DESC) AS row_num
FROM Events AS e
)
SELECT
e.*,
d.*,
c.*
FROM RankedEvents AS e
LEFT JOIN Devices AS d ON e.eve_MAC = d.devMac
INNER JOIN CurrentScan AS c ON e.eve_MAC = c.scanMac
WHERE e.row_num = 1
/* LatestEventsPerMAC(eve_MAC,eve_IP,eve_DateTime,eve_EventType,eve_AdditionalInfo,eve_PendingAlertEmail,eve_PairEventRowid,row_num,devMac,devName,devOwner,devType,devVendor,devFavorite,devGroup,devComments,devFirstConnection,devLastConnection,devLastIP,devStaticIP,devScan,devLogEvents,devAlertEvents,devAlertDown,devSkipRepeated,devLastNotification,devPresentLastScan,devIsNew,devLocation,devIsArchived,devParentMAC,devParentPort,devIcon,devGUID,devSite,devSSID,devSyncHubNode,devSourcePlugin,devCustomProps,scanMac,scanLastIP,scanVendor,scanSourcePlugin,scanName,scanLastQuery,scanLastConnection,scanSyncHubNode,scanSite,scanSSID,scanParentMAC,scanParentPort,scanType) */;
CREATE VIEW Sessions_Devices AS SELECT * FROM Sessions LEFT JOIN "Devices" ON ses_MAC = devMac
/* Sessions_Devices(ses_MAC,ses_IP,ses_EventTypeConnection,ses_DateTimeConnection,ses_EventTypeDisconnection,ses_DateTimeDisconnection,ses_StillConnected,ses_AdditionalInfo,devMac,devName,devOwner,devType,devVendor,devFavorite,devGroup,devComments,devFirstConnection,devLastConnection,devLastIP,devStaticIP,devScan,devLogEvents,devAlertEvents,devAlertDown,devSkipRepeated,devLastNotification,devPresentLastScan,devIsNew,devLocation,devIsArchived,devParentMAC,devParentPort,devIcon,devGUID,devSite,devSSID,devSyncHubNode,devSourcePlugin,devCustomProps) */;
CREATE VIEW Convert_Events_to_Sessions AS SELECT EVE1.eve_MAC,
EVE1.eve_IP,
EVE1.eve_EventType AS eve_EventTypeConnection,
EVE1.eve_DateTime AS eve_DateTimeConnection,
CASE WHEN EVE2.eve_EventType IN ('Disconnected', 'Device Down') OR
EVE2.eve_EventType IS NULL THEN EVE2.eve_EventType ELSE '<missing event>' END AS eve_EventTypeDisconnection,
CASE WHEN EVE2.eve_EventType IN ('Disconnected', 'Device Down') THEN EVE2.eve_DateTime ELSE NULL END AS eve_DateTimeDisconnection,
CASE WHEN EVE2.eve_EventType IS NULL THEN 1 ELSE 0 END AS eve_StillConnected,
EVE1.eve_AdditionalInfo
FROM Events AS EVE1
LEFT JOIN
Events AS EVE2 ON EVE1.eve_PairEventRowID = EVE2.RowID
WHERE EVE1.eve_EventType IN ('New Device', 'Connected','Down Reconnected')
UNION
SELECT eve_MAC,
eve_IP,
'<missing event>' AS eve_EventTypeConnection,
NULL AS eve_DateTimeConnection,
eve_EventType AS eve_EventTypeDisconnection,
eve_DateTime AS eve_DateTimeDisconnection,
0 AS eve_StillConnected,
eve_AdditionalInfo
FROM Events AS EVE1
WHERE (eve_EventType = 'Device Down' OR
eve_EventType = 'Disconnected') AND
EVE1.eve_PairEventRowID IS NULL
/* Convert_Events_to_Sessions(eve_MAC,eve_IP,eve_EventTypeConnection,eve_DateTimeConnection,eve_EventTypeDisconnection,eve_DateTimeDisconnection,eve_StillConnected,eve_AdditionalInfo) */;
CREATE TRIGGER "trg_insert_devices"
AFTER INSERT ON "Devices"
WHEN NOT EXISTS (
SELECT 1 FROM AppEvents
WHERE AppEventProcessed = 0
AND ObjectType = 'Devices'
AND ObjectGUID = NEW.devGUID
AND ObjectStatus = CASE WHEN NEW.devPresentLastScan = 1 THEN 'online' ELSE 'offline' END
AND AppEventType = 'insert'
)
BEGIN
INSERT INTO "AppEvents" (
"GUID",
"DateTimeCreated",
"AppEventProcessed",
"ObjectType",
"ObjectGUID",
"ObjectPrimaryID",
"ObjectSecondaryID",
"ObjectStatus",
"ObjectStatusColumn",
"ObjectIsNew",
"ObjectIsArchived",
"ObjectForeignKey",
"ObjectPlugin",
"AppEventType"
)
VALUES (
lower(
hex(randomblob(4)) || '-' || hex(randomblob(2)) || '-' || '4' ||
substr(hex( randomblob(2)), 2) || '-' ||
substr('AB89', 1 + (abs(random()) % 4) , 1) ||
substr(hex(randomblob(2)), 2) || '-' ||
hex(randomblob(6))
)
,
DATETIME('now'),
FALSE,
'Devices',
NEW.devGUID, -- ObjectGUID
NEW.devMac, -- ObjectPrimaryID
NEW.devLastIP, -- ObjectSecondaryID
CASE WHEN NEW.devPresentLastScan = 1 THEN 'online' ELSE 'offline' END, -- ObjectStatus
'devPresentLastScan', -- ObjectStatusColumn
NEW.devIsNew, -- ObjectIsNew
NEW.devIsArchived, -- ObjectIsArchived
NEW.devGUID, -- ObjectForeignKey
'DEVICES', -- ObjectForeignKey
'insert'
);
END;
CREATE TRIGGER "trg_update_devices"
AFTER UPDATE ON "Devices"
WHEN NOT EXISTS (
SELECT 1 FROM AppEvents
WHERE AppEventProcessed = 0
AND ObjectType = 'Devices'
AND ObjectGUID = NEW.devGUID
AND ObjectStatus = CASE WHEN NEW.devPresentLastScan = 1 THEN 'online' ELSE 'offline' END
AND AppEventType = 'update'
)
BEGIN
INSERT INTO "AppEvents" (
"GUID",
"DateTimeCreated",
"AppEventProcessed",
"ObjectType",
"ObjectGUID",
"ObjectPrimaryID",
"ObjectSecondaryID",
"ObjectStatus",
"ObjectStatusColumn",
"ObjectIsNew",
"ObjectIsArchived",
"ObjectForeignKey",
"ObjectPlugin",
"AppEventType"
)
VALUES (
lower(
hex(randomblob(4)) || '-' || hex(randomblob(2)) || '-' || '4' ||
substr(hex( randomblob(2)), 2) || '-' ||
substr('AB89', 1 + (abs(random()) % 4) , 1) ||
substr(hex(randomblob(2)), 2) || '-' ||
hex(randomblob(6))
)
,
DATETIME('now'),
FALSE,
'Devices',
NEW.devGUID, -- ObjectGUID
NEW.devMac, -- ObjectPrimaryID
NEW.devLastIP, -- ObjectSecondaryID
CASE WHEN NEW.devPresentLastScan = 1 THEN 'online' ELSE 'offline' END, -- ObjectStatus
'devPresentLastScan', -- ObjectStatusColumn
NEW.devIsNew, -- ObjectIsNew
NEW.devIsArchived, -- ObjectIsArchived
NEW.devGUID, -- ObjectForeignKey
'DEVICES', -- ObjectForeignKey
'update'
);
END;
CREATE TRIGGER "trg_delete_devices"
AFTER DELETE ON "Devices"
WHEN NOT EXISTS (
SELECT 1 FROM AppEvents
WHERE AppEventProcessed = 0
AND ObjectType = 'Devices'
AND ObjectGUID = OLD.devGUID
AND ObjectStatus = CASE WHEN OLD.devPresentLastScan = 1 THEN 'online' ELSE 'offline' END
AND AppEventType = 'delete'
)
BEGIN
INSERT INTO "AppEvents" (
"GUID",
"DateTimeCreated",
"AppEventProcessed",
"ObjectType",
"ObjectGUID",
"ObjectPrimaryID",
"ObjectSecondaryID",
"ObjectStatus",
"ObjectStatusColumn",
"ObjectIsNew",
"ObjectIsArchived",
"ObjectForeignKey",
"ObjectPlugin",
"AppEventType"
)
VALUES (
lower(
hex(randomblob(4)) || '-' || hex(randomblob(2)) || '-' || '4' ||
substr(hex( randomblob(2)), 2) || '-' ||
substr('AB89', 1 + (abs(random()) % 4) , 1) ||
substr(hex(randomblob(2)), 2) || '-' ||
hex(randomblob(6))
)
,
DATETIME('now'),
FALSE,
'Devices',
OLD.devGUID, -- ObjectGUID
OLD.devMac, -- ObjectPrimaryID
OLD.devLastIP, -- ObjectSecondaryID
CASE WHEN OLD.devPresentLastScan = 1 THEN 'online' ELSE 'offline' END, -- ObjectStatus
'devPresentLastScan', -- ObjectStatusColumn
OLD.devIsNew, -- ObjectIsNew
OLD.devIsArchived, -- ObjectIsArchived
OLD.devGUID, -- ObjectForeignKey
'DEVICES', -- ObjectForeignKey
'delete'
);
END;

View File

@@ -19,6 +19,9 @@ services:
- CHOWN # Required for root-entrypoint to chown /data + /tmp before dropping privileges - CHOWN # Required for root-entrypoint to chown /data + /tmp before dropping privileges
- SETUID # Required for root-entrypoint to switch to non-root user - SETUID # Required for root-entrypoint to switch to non-root user
- SETGID # Required for root-entrypoint to switch to non-root group - SETGID # Required for root-entrypoint to switch to non-root group
sysctls: # ARP flux mitigation for host networking accuracy
net.ipv4.conf.all.arp_ignore: 1
net.ipv4.conf.all.arp_announce: 2
volumes: volumes:
- type: volume # Persistent Docker-managed Named Volume for storage - type: volume # Persistent Docker-managed Named Volume for storage

View File

@@ -0,0 +1,56 @@
### Build an MSP Wallboard for Network Monitoring
For Managed Service Providers (MSPs) and Network Operations Centers (NOC), "Eyes on Glass" monitoring requires a UI that is both self-healing (auto-refreshing) and focused only on critical data. By leveraging the **UI Settings Plugin**, you can transform NetAlertX from a management tool into a dedicated live monitor.
![filters](./img/ADVISORIES/filters.png)
---
### 1. Configure Auto-Refresh for Live Monitoring
Static dashboards are the enemy of real-time response. NetAlertX allows you to force the UI to pull fresh data without manual page reloads.
* **Setting:** Locate the `UI_REFRESH` (or similar "Auto-refresh UI") setting within the **UI Settings plugin**.
* **Optimal Interval:** Set this between **60 to 120 seconds**.
* *Note:* Refreshing too frequently (e.g., <30s) on large networks can lead to high browser and server CPU usage.
![ui_customization_settings](./img/ADVISORIES/ui_customization_settings.png)
### 2. Streamlining the Dashboard (MSP Mode)
An MSP's focus is on what is *broken*, not what is working. Hide the noise to increase reaction speed.
* **Hide Unnecessary Blocks:** Under UI Settings, disable dashboard blocks that don't provide immediate utility, such as **Online presence** or **Tiles**.
* **Hide virtual connections:** You can specify which relationships shoudl be hidden from the main view to remove any virtual devices that are not essential from your views.
* **Browser Full-Screen:** Use the built-in "Full Screen" toggle in the top bar to remove browser chrome (URL bars/tabs) for a cleaner "Wallboard" look.
### 3. Creating Custom NOC Views
Use the UI Filters in tandem with UI Settings to create custom views.
![NetAlertX NOC dashboard showing offline network devices for MSP monitoring](./img/ADVISORIES/down_devices.png)
| Feature | NOC/MSP Application |
| --- | --- |
| **Site-Specific Nodes** | Filter the view by a specific "Sync Node" or "Location" filter to monitor a single client site. |
| **Filter by Criticality** | Filter devices where `Group == "Infrastructure"` or `"Server"`. (depending on your predefined values) |
| **Predefined "Down" View** | Bookmark the URL with the `/devices.php#down` path to ensure the dashboard always loads into an "Alert Only" mode. |
### 4. Browser & Cache Stability
Because the UI is a web application, long-running sessions can occasionally experience cache drift.
* **Cache Refresh:** If you notice the "Show # Entries" resetting or icons failing to load after days of uptime, use the **Reload** icon in the application header (not the browser refresh) to clear the internal app cache.
* **Dedicated Hardware:** For 24/7 monitoring, use a dedicated thin client or Raspberry Pi running in "Kiosk Mode" to prevent OS-level popups from obscuring the dashboard.
> [!TIP]
> [NetAlertX - Detailed Dashboard Guide](https://www.youtube.com/watch?v=umh1c_40HW8)
> This video provides a visual walkthrough of the NetAlertX dashboard features, including how to map and visualize devices which is crucial for setting up a clear "Eyes on Glass" monitoring environment.
### Summary Checklist
* [ ] **Automate Refresh:** Set `UI_REFRESH` to **60-120s** in UI Settings to ensure the dashboard stays current without manual intervention.
* [ ] **Filter for Criticality:** Bookmark the **`/devices.php#down`** view to instantly focus on offline assets rather than the entire inventory.
* [ ] **Remove UI Noise:** Use UI Settings to hide non-essential dashboard blocks (e.g., **Tiles** or remove **Virtual Connections** devices) to maximize screen real estate for alerts.
* [ ] **Segment by Site:** Use **Location** or **Sync Node** filters to create dedicated views for specific client networks or physical branches.
* [ ] **Ensure Stability:** Run on a dedicated "Kiosk" browser and use the internal **Reload icon** occasionally to maintain a clean application cache.

View File

@@ -0,0 +1,121 @@
## ADVISORY: Best Practices for Monitoring Multiple Networks with NetAlertX
### 1. Define Monitoring Scope & Architecture
Effective multi-network monitoring starts with understanding how NetAlertX "sees" your traffic.
* **A. Understand Network Accessibility:** Local ARP-based scanning (**ARPSCAN**) only discovers devices on directly accessible subnets due to Layer 2 limitations. It cannot traverse VPNs or routed borders without specific configuration.
* **B. Plan Subnet & Scan Interfaces:** Explicitly configure each accessible segment in `SCAN_SUBNETS` with the corresponding interfaces.
* **C. Remote & Inaccessible Networks:** For networks unreachable via ARP, use these strategies:
* **Alternate Plugins:** Supplement discovery with [SNMPDSC](SNMPDSC) or [DHCP lease imports](https://docs.netalertx.com/PLUGINS/?h=DHCPLSS#available-plugins).
* **Centralized Multi-Tenant Management using Sync Nodes:** Run secondary NetAlertX instances on isolated networks and aggregate data using the **SYNC plugin**.
* **Manual Entry:** For static assets where only ICMP (ping) status is needed.
> [!TIP]
> Explore the [remote networks](./REMOTE_NETWORKS.md) documentation for more details on how to set up the approaches menationed above.
---
### 2. Automating IT Asset Inventory with Workflows
[Workflows](./WORKFLOWS.md) are the "engine" of NetAlertX, reducing manual overhead as your device list grows.
* **A. Logical Ownership & VLAN Tagging:** Create a workflow triggered on **Device Creation** to:
1. Inspect the IP/Subnet.
2. Set `devVlan` or `devOwner` custom fields automatically.
* **B. Auto-Grouping:** Use conditional logic to categorize devices.
* *Example:* If `devLastIP == 10.10.20.*`, then `Set devLocation = "BranchOffice"`.
```json
{
"name": "Assign Location - BranchOffice",
"trigger": {
"object_type": "Devices",
"event_type": "update"
},
"conditions": [
{
"logic": "AND",
"conditions": [
{
"field": "devLastIP",
"operator": "contains",
"value": "10.10.20."
}
]
}
],
"actions": [
{
"type": "update_field",
"field": "devLocation",
"value": "BranchOffice"
}
]
}
```
* **C. Sync Node Tracking:** When using multiple instances, ensure all synchub nodes have a descriptive `SYNC_node_name` name to distinguish between sites.
> [!TIP]
> Always test new workflows in a "Staging" instance. A misconfigured workflow can trigger thousands of unintended updates across your database.
---
### 3. Notification Strategy: Low Noise, High Signal
A multi-network environment can generate significant "alert fatigue." Use a layered filtering approach.
| Level | Strategy | Recommended Action |
| --- | --- | --- |
| **Device** | Silence Flapping | Use "Skip repeated notifications" for unstable IoT devices. |
| **Plugin** | Tune Watchers | Only enable `_WATCH` on reliable plugins (e.g., ICMP/SNMP). |
| **Global** | Filter Sections | Limit `NTFPRCS_INCLUDED_SECTIONS` to `new_devices` and `down_devices`. |
> [!TIP]
> **Ignore Rules:** Maintain strict **Ignored MAC** (`NEWDEV_ignored_MACs`) and **Ignored IP** (`NEWDEV_ignored_IPs`) lists for guest networks or broadcast scanners to keep your logs clean.
---
### 4. UI Filters for Multi-Network Clarity
Don't let a massive device list overwhelm you. Use the [Multi-edit features](./DEVICES_BULK_EDITING.md) to categorize devices and create focused views:
* **By Zone:** Filter by "Location", "Site" or "Sync Node" you et up in Section 2.
* **By Criticality:** Use custom the device Type field to separate "Core Infrastructure" from "Ephemeral Clients."
* **By Status:** Use predefined views specifically for "Devices currently Down" to act as a Network Operations Center (NOC) dashboard.
> [!TIP]
> If you are providing services as a Managed Service Provider (MSP) customize your default UI to be exactly how you need it, by hiding parts of the UI that you are not interested in, or by configuring a auto-refreshed screen monitoring your most important clients. See the [Eyes on glass](./ADVISORY_EYES_ON_GLASS.md) advisory for more details.
---
### 5. Operational Stability & Sync Health
* **Health Checks:** Regularly monitor the [Logs](https://docs.netalertx.com/LOGGING/?h=logs) to ensure remote nodes are reporting in.
* **Backups:** Use the **CSV Devices Backup** plugin. Standardize your workflow templates and [back up](./BACKUPS.md) you `/config` folders so that if a node fails, you can redeploy it with the same logic instantly.
### 6. Optimize Performance
As your environment grows, tuning the underlying engine is vital to maintain a snappy UI and reliable discovery cycles.
* **Plugin Scheduling:** Avoid "Scan Storms" by staggering plugin execution. Running intensive tasks like `NMAP` or `MASS_DNS` simultaneously can spike CPU and cause database locks.
* **Database Health:** Large-scale monitoring generates massive event logs. Use the **[DBCLNP (Database Cleanup)](https://www.google.com/search?q=https://docs.netalertx.com/PLUGINS/%23dbclnp)** plugin to prune old records and keep the SQLite database performant.
* **Resource Management:** For high-device counts, consider increasing the memory limit for the container and utilizing `tmpfs` for temporary files to reduce SD card/disk I/O bottlenecks.
> [!IMPORTANT]
> For a deep dive into hardware requirements, database vacuuming, and specific environment variables for high-load instances, refer to the full **[Performance Optimization Guide](https://docs.netalertx.com/PERFORMANCE/)**.
---
### Summary Checklist
* [ ] **Discovery:** Are all subnets explicitly defined?
* [ ] **Automation:** Do new devices get auto-assigned to a VLAN/Owner?
* [ ] **Noise Control:** Are transient "Down" alerts delayed via `NTFPRCS_alert_down_time`?
* [ ] **Remote Sites:** Is the SYNC plugin authenticated and heartbeat-active?

View File

@@ -58,12 +58,12 @@ The Events API provides access to **device event logs**, allowing creation, retr
"success": true, "success": true,
"events": [ "events": [
{ {
"eve_MAC": "00:11:22:33:44:55", "eveMac": "00:11:22:33:44:55",
"eve_IP": "192.168.1.10", "eveIp": "192.168.1.10",
"eve_DateTime": "2025-08-24T12:00:00Z", "eveDateTime": "2025-08-24T12:00:00Z",
"eve_EventType": "Device Down", "eveEventType": "Device Down",
"eve_AdditionalInfo": "", "eveAdditionalInfo": "",
"eve_PendingAlertEmail": 1 "evePendingAlertEmail": 1
} }
] ]
} }
@@ -102,11 +102,11 @@ The Events API provides access to **device event logs**, allowing creation, retr
"count": 5, "count": 5,
"events": [ "events": [
{ {
"eve_DateTime": "2025-12-07 12:00:00", "eveDateTime": "2025-12-07 12:00:00",
"eve_EventType": "New Device", "eveEventType": "New Device",
"eve_MAC": "AA:BB:CC:DD:EE:FF", "eveMac": "AA:BB:CC:DD:EE:FF",
"eve_IP": "192.168.1.100", "eveIp": "192.168.1.100",
"eve_AdditionalInfo": "Device detected" "eveAdditionalInfo": "Device detected"
} }
] ]
} }
@@ -127,9 +127,9 @@ The Events API provides access to **device event logs**, allowing creation, retr
"count": 10, "count": 10,
"events": [ "events": [
{ {
"eve_DateTime": "2025-12-07 12:00:00", "eveDateTime": "2025-12-07 12:00:00",
"eve_EventType": "Device Down", "eveEventType": "Device Down",
"eve_MAC": "AA:BB:CC:DD:EE:FF" "eveMac": "AA:BB:CC:DD:EE:FF"
} }
] ]
} }
@@ -159,9 +159,9 @@ The Events API provides access to **device event logs**, allowing creation, retr
1. Total events in the period 1. Total events in the period
2. Total sessions 2. Total sessions
3. Missing sessions 3. Missing sessions
4. Voided events (`eve_EventType LIKE 'VOIDED%'`) 4. Voided events (`eveEventType LIKE 'VOIDED%'`)
5. New device events (`eve_EventType LIKE 'New Device'`) 5. New device events (`eveEventType LIKE 'New Device'`)
6. Device down events (`eve_EventType LIKE 'Device Down'`) 6. Device down events (`eveEventType LIKE 'Device Down'`)
--- ---
@@ -187,7 +187,7 @@ Event endpoints are available as **MCP Tools** for AI assistant integration:
``` ```
* Events are stored in the **Events table** with the following fields: * Events are stored in the **Events table** with the following fields:
`eve_MAC`, `eve_IP`, `eve_DateTime`, `eve_EventType`, `eve_AdditionalInfo`, `eve_PendingAlertEmail`. `eveMac`, `eveIp`, `eveDateTime`, `eveEventType`, `eveAdditionalInfo`, `evePendingAlertEmail`.
* Event creation automatically logs activity for debugging. * Event creation automatically logs activity for debugging.

View File

@@ -4,6 +4,10 @@ GraphQL queries are **read-optimized for speed**. Data may be slightly out of da
* Devices * Devices
* Settings * Settings
* Events
* PluginsObjects
* PluginsHistory
* PluginsEvents
* Language Strings (LangStrings) * Language Strings (LangStrings)
## Endpoints ## Endpoints
@@ -254,11 +258,160 @@ curl 'http://host:GRAPHQL_PORT/graphql' \
--- ---
## Plugin Tables (Objects, Events, History)
Three queries expose the plugin database tables with server-side pagination, filtering, and search:
* `pluginsObjects` — current plugin object state
* `pluginsEvents` — unprocessed plugin events
* `pluginsHistory` — historical plugin event log
All three share the same `PluginQueryOptionsInput` and return the same `PluginEntry` shape.
### Sample Query
```graphql
query GetPluginObjects($options: PluginQueryOptionsInput) {
pluginsObjects(options: $options) {
dbCount
count
entries {
index plugin objectPrimaryId objectSecondaryId
dateTimeCreated dateTimeChanged
watchedValue1 watchedValue2 watchedValue3 watchedValue4
status extra userData foreignKey
syncHubNodeName helpVal1 helpVal2 helpVal3 helpVal4 objectGuid
}
}
}
```
### Query Parameters (`PluginQueryOptionsInput`)
| Parameter | Type | Description |
| ------------ | ----------------- | ------------------------------------------------------ |
| `page` | Int | Page number (1-based). |
| `limit` | Int | Rows per page (max 1000). |
| `sort` | [SortOptionsInput] | Sorting options (`field`, `order`). |
| `search` | String | Free-text search across key columns. |
| `filters` | [FilterOptionsInput] | Column-value exact-match filters. |
| `plugin` | String | Plugin prefix to scope results (e.g. `"ARPSCAN"`). |
| `foreignKey` | String | Foreign key filter (e.g. device MAC). |
| `dateFrom` | String | Start of date range filter on `dateTimeCreated`. |
| `dateTo` | String | End of date range filter on `dateTimeCreated`. |
### Response Fields
| Field | Type | Description |
| --------- | ------------- | ------------------------------------------------------------- |
| `dbCount` | Int | Total rows for the requested plugin (before search/filters). |
| `count` | Int | Total rows after all filters (before pagination). |
| `entries` | [PluginEntry] | Paginated list of plugin entries. |
### `curl` Example
```sh
curl 'http://host:GRAPHQL_PORT/graphql' \
-X POST \
-H 'Authorization: Bearer API_TOKEN' \
-H 'Content-Type: application/json' \
--data '{
"query": "query GetPluginObjects($options: PluginQueryOptionsInput) { pluginsObjects(options: $options) { dbCount count entries { index plugin objectPrimaryId status foreignKey } } }",
"variables": {
"options": {
"plugin": "ARPSCAN",
"page": 1,
"limit": 25
}
}
}'
```
### Badge Prefetch (Batched Counts)
Use GraphQL aliases to fetch counts for all plugins in a single request:
```graphql
query BadgeCounts {
ARPSCAN: pluginsObjects(options: {plugin: "ARPSCAN", page: 1, limit: 1}) { dbCount }
INTRNT: pluginsObjects(options: {plugin: "INTRNT", page: 1, limit: 1}) { dbCount }
}
```
---
## Events Query
Access the Events table with server-side pagination, filtering, and search.
### Sample Query
```graphql
query GetEvents($options: EventQueryOptionsInput) {
events(options: $options) {
dbCount
count
entries {
eveMac
eveIp
eveDateTime
eveEventType
eveAdditionalInfo
evePendingAlertEmail
}
}
}
```
### Query Parameters (`EventQueryOptionsInput`)
| Parameter | Type | Description |
| ----------- | ------------------ | ------------------------------------------------ |
| `page` | Int | Page number (1-based). |
| `limit` | Int | Rows per page (max 1000). |
| `sort` | [SortOptionsInput] | Sorting options (`field`, `order`). |
| `search` | String | Free-text search across key columns. |
| `filters` | [FilterOptionsInput] | Column-value exact-match filters. |
| `eveMac` | String | Filter by device MAC address. |
| `eventType` | String | Filter by event type (e.g. `"New Device"`). |
| `dateFrom` | String | Start of date range filter on `eveDateTime`. |
| `dateTo` | String | End of date range filter on `eveDateTime`. |
### Response Fields
| Field | Type | Description |
| --------- | ------------ | ------------------------------------------------------------ |
| `dbCount` | Int | Total rows in the Events table (before any filters). |
| `count` | Int | Total rows after all filters (before pagination). |
| `entries` | [EventEntry] | Paginated list of event entries. |
### `curl` Example
```sh
curl 'http://host:GRAPHQL_PORT/graphql' \
-X POST \
-H 'Authorization: Bearer API_TOKEN' \
-H 'Content-Type: application/json' \
--data '{
"query": "query GetEvents($options: EventQueryOptionsInput) { events(options: $options) { dbCount count entries { eveMac eveIp eveDateTime eveEventType } } }",
"variables": {
"options": {
"eveMac": "00:11:22:33:44:55",
"page": 1,
"limit": 50
}
}
}'
```
---
## Notes ## Notes
* Device, settings, and LangStrings queries can be combined in **one request** since GraphQL supports batching. * Device, settings, LangStrings, plugin, and event queries can be combined in **one request** since GraphQL supports batching.
* The `fallback_to_en` feature ensures UI always has a value even if a translation is missing. * The `fallback_to_en` feature ensures UI always has a value even if a translation is missing.
* Data is **cached in memory** per JSON file; changes to language or plugin files will only refresh after the cache detects a file modification. * Data is **cached in memory** per JSON file; changes to language or plugin files will only refresh after the cache detects a file modification.
* The `setOverriddenByEnv` flag helps identify setting values that are locked at container runtime. * The `setOverriddenByEnv` flag helps identify setting values that are locked at container runtime.
* Plugin queries scope `dbCount` to the requested `plugin`/`foreignKey` so badge counts reflect per-plugin totals.
* The schema is **read-only** — updates must be performed through other APIs or configuration management. See the other [API](API.md) endpoints for details. * The schema is **read-only** — updates must be performed through other APIs or configuration management. See the other [API](API.md) endpoints for details.

View File

@@ -149,7 +149,7 @@ You can access the following files:
| File name | Description | | File name | Description |
|----------------------|----------------------| |----------------------|----------------------|
| `notification_json_final.json` | The json version of the last notification (e.g. used for webhooks - [sample JSON](https://github.com/jokob-sk/NetAlertX/blob/main/front/report_templates/webhook_json_sample.json)). | | `notification_json_final.json` | The json version of the last notification (e.g. used for webhooks - [sample JSON](https://github.com/netalertx/NetAlertX/blob/main/front/report_templates/webhook_json_sample.json)). |
| `table_devices.json` | All of the available Devices detected by the app. | | `table_devices.json` | All of the available Devices detected by the app. |
| `table_plugins_events.json` | The list of the unprocessed (pending) notification events (plugins_events DB table). | | `table_plugins_events.json` | The list of the unprocessed (pending) notification events (plugins_events DB table). |
| `table_plugins_history.json` | The list of notification events history. | | `table_plugins_history.json` | The list of notification events history. |

View File

@@ -106,12 +106,12 @@ curl -X DELETE "http://<server_ip>:<GRAPHQL_PORT>/sessions/delete" \
"success": true, "success": true,
"sessions": [ "sessions": [
{ {
"ses_MAC": "AA:BB:CC:DD:EE:FF", "sesMac": "AA:BB:CC:DD:EE:FF",
"ses_Connection": "2025-08-01 10:00", "sesDateTimeConnection": "2025-08-01 10:00",
"ses_Disconnection": "2025-08-01 12:00", "sesDateTimeDisconnection": "2025-08-01 12:00",
"ses_Duration": "2h 0m", "sesDuration": "2h 0m",
"ses_IP": "192.168.1.10", "sesIp": "192.168.1.10",
"ses_Info": "" "sesAdditionalInfo": ""
} }
] ]
} }
@@ -194,12 +194,12 @@ curl -X GET "http://<server_ip>:<GRAPHQL_PORT>/sessions/calendar?start=2025-08-0
"success": true, "success": true,
"sessions": [ "sessions": [
{ {
"ses_MAC": "AA:BB:CC:DD:EE:FF", "sesMac": "AA:BB:CC:DD:EE:FF",
"ses_Connection": "2025-08-01 10:00", "sesDateTimeConnection": "2025-08-01 10:00",
"ses_Disconnection": "2025-08-01 12:00", "sesDateTimeDisconnection": "2025-08-01 12:00",
"ses_Duration": "2h 0m", "sesDuration": "2h 0m",
"ses_IP": "192.168.1.10", "sesIp": "192.168.1.10",
"ses_Info": "" "sesAdditionalInfo": ""
} }
] ]
} }
@@ -224,15 +224,33 @@ curl -X GET "http://<server_ip>:<GRAPHQL_PORT>/sessions/AA:BB:CC:DD:EE:FF?period
* `type` → Event type (`all`, `sessions`, `missing`, `voided`, `new`, `down`) * `type` → Event type (`all`, `sessions`, `missing`, `voided`, `new`, `down`)
Default: `all` Default: `all`
* `period` → Period to retrieve events (`7 days`, `1 month`, etc.) * `period` → Period to retrieve events (`7 days`, `1 month`, etc.)
* `page` → Page number, 1-based (default: `1`)
* `limit` → Rows per page, max 1000 (default: `100`)
* `search` → Free-text search filter across all columns
* `sortCol` → Column index to sort by, 0-based (default: `0`)
* `sortDir` → Sort direction: `asc` or `desc` (default: `desc`)
**Example:** **Example:**
``` ```
/sessions/session-events?type=all&period=7 days /sessions/session-events?type=all&period=7 days&page=1&limit=25&sortCol=3&sortDir=desc
``` ```
**Response:** **Response:**
Returns a list of events or sessions with formatted connection, disconnection, duration, and IP information.
```json
{
"data": [...],
"total": 150,
"recordsFiltered": 150
}
```
| Field | Type | Description |
| ----------------- | ---- | ------------------------------------------------- |
| `data` | list | Paginated rows (each row is a list of values). |
| `total` | int | Total rows before search filter. |
| `recordsFiltered` | int | Total rows after search filter (before paging). |
#### `curl` Example #### `curl` Example

View File

@@ -13,7 +13,7 @@ There are four key artifacts you can use to back up your NetAlertX configuration
| File | Description | Limitations | | File | Description | Limitations |
| ------------------------ | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | ------------------------ | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/db/app.db` | The application database | Might be in an uncommitted state or corrupted | | `/db/app.db` | The application database | Might be in an uncommitted state or corrupted |
| `/config/app.conf` | Configuration file | Can be overridden using the [`APP_CONF_OVERRIDE`](https://github.com/jokob-sk/NetAlertX/tree/main/dockerfiles#docker-environment-variables) variable | | `/config/app.conf` | Configuration file | Can be overridden using the [`APP_CONF_OVERRIDE`](https://github.com/netalertx/NetAlertX/tree/main/dockerfiles#docker-environment-variables) variable |
| `/config/devices.csv` | CSV file containing device data | Does not include historical data | | `/config/devices.csv` | CSV file containing device data | Does not include historical data |
| `/config/workflows.json` | JSON file containing your workflows | N/A | | `/config/workflows.json` | JSON file containing your workflows | N/A |
@@ -37,7 +37,7 @@ This includes settings for:
### Device Data ### Device Data
Stored in `/data/config/devices_<timestamp>.csv` or `/data/config/devices.csv`, created by the [CSV Backup `CSVBCKP` Plugin](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/csv_backup). Stored in `/data/config/devices_<timestamp>.csv` or `/data/config/devices.csv`, created by the [CSV Backup `CSVBCKP` Plugin](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/csv_backup).
Contains: Contains:
* Device names, icons, and categories * Device names, icons, and categories

View File

@@ -120,3 +120,23 @@ With `ARPSCAN` scans some devices might flip IP addresses after each scan trigge
See how to prevent IP flipping in the [ARPSCAN plugin guide](/front/plugins/arp_scan/README.md). See how to prevent IP flipping in the [ARPSCAN plugin guide](/front/plugins/arp_scan/README.md).
Alternatively adjust your [notification settings](./NOTIFICATIONS.md) to prevent false positives by filtering out events or devices. Alternatively adjust your [notification settings](./NOTIFICATIONS.md) to prevent false positives by filtering out events or devices.
#### Multiple NICs on Same Host Reporting Same IP
On systems with multiple NICs (like a Proxmox server), each NIC has its own MAC address. Sometimes NetAlertX can incorrectly assign the same IP to all NICs, causing false device mappings. This is due to the way ARP responses are handled by the OS and cannot be overridden directly in NetAlertX.
**Resolution (Linux-based systems, e.g., Proxmox):**
Run the following commands on the host to fix ARP behavior:
```bash
sudo sysctl -w net.ipv4.conf.all.arp_ignore=1
sudo sysctl -w net.ipv4.conf.all.arp_announce=2
```
This ensures each NIC responds correctly to ARP requests and prevents NetAlertX from misassigning IPs.
> For setups with multiple interfaces on the same switch, consider [workflows](./WORKFLOWS.md), [device exclusions](./NOTIFICATIONS.md), or [dummy devices](./DEVICE_MANAGEMENT.md) as additional workarounds.
> See [Feature Requests](https://github.com/netalertx/netalertx/issues) for reporting edge cases.

View File

@@ -23,6 +23,7 @@
| `devLogEvents` | Whether events related to the device should be logged. | `0` | | `devLogEvents` | Whether events related to the device should be logged. | `0` |
| `devAlertEvents` | Whether alerts should be generated for events. | `1` | | `devAlertEvents` | Whether alerts should be generated for events. | `1` |
| `devAlertDown` | Whether an alert should be sent when the device goes down. | `0` | | `devAlertDown` | Whether an alert should be sent when the device goes down. | `0` |
| `devCanSleep` | Whether the device can enter a sleep window. When `1`, offline periods within the `NTFPRCS_sleep_time` window are shown as **Sleeping** instead of **Down** and no down alert is fired. | `0` |
| `devSkipRepeated` | Whether to skip repeated alerts for this device. | `1` | | `devSkipRepeated` | Whether to skip repeated alerts for this device. | `1` |
| `devLastNotification` | Timestamp of the last notification sent for this device. | `2025-03-22 12:07:26+11:00` | | `devLastNotification` | Timestamp of the last notification sent for this device. | `2025-03-22 12:07:26+11:00` |
| `devPresentLastScan` | Whether the device was present during the last scan. | `1` | | `devPresentLastScan` | Whether the device was present during the last scan. | `1` |
@@ -42,6 +43,12 @@
| `devParentRelType` | The type of relationship between the current device and it's parent node. By default, selecting `nic` will hide it from lists. | `nic` | | `devParentRelType` | The type of relationship between the current device and it's parent node. By default, selecting `nic` will hide it from lists. | `nic` |
| `devReqNicsOnline` | If all NICs are required to be online to mark teh current device online. | `0` | | `devReqNicsOnline` | If all NICs are required to be online to mark teh current device online. | `0` |
> [!NOTE]
> `DevicesView` extends the `Devices` table with two computed fields that are never persisted:
> - `devIsSleeping` (`1` when `devCanSleep=1`, device is offline, and `devLastConnection` is within the `NTFPRCS_sleep_time` window).
> - `devFlapping` (`1` when the device has changed state more than the flap threshold times in the trailing window).
> - `devStatus` — derived string: `On-line`, `Sleeping`, `Down`, or `Off-line`.
To understand how values of these fields influuence application behavior, such as Notifications or Network topology, see also: To understand how values of these fields influuence application behavior, such as Notifications or Network topology, see also:

View File

@@ -43,7 +43,7 @@ Input data from the plugin might cause mapping issues in specific edge cases. Lo
17:31:05 [Scheduler] run for PIHOLE: YES 17:31:05 [Scheduler] run for PIHOLE: YES
17:31:05 [Plugin utils] --------------------------------------------- 17:31:05 [Plugin utils] ---------------------------------------------
17:31:05 [Plugin utils] display_name: PiHole (Device sync) 17:31:05 [Plugin utils] display_name: PiHole (Device sync)
17:31:05 [Plugins] CMD: SELECT n.hwaddr AS Object_PrimaryID, {s-quote}null{s-quote} AS Object_SecondaryID, datetime() AS DateTime, na.ip AS Watched_Value1, n.lastQuery AS Watched_Value2, na.name AS Watched_Value3, n.macVendor AS Watched_Value4, {s-quote}null{s-quote} AS Extra, n.hwaddr AS ForeignKey FROM EXTERNAL_PIHOLE.Network AS n LEFT JOIN EXTERNAL_PIHOLE.Network_Addresses AS na ON na.network_id = n.id WHERE n.hwaddr NOT LIKE {s-quote}ip-%{s-quote} AND n.hwaddr is not {s-quote}00:00:00:00:00:00{s-quote} AND na.ip is not null 17:31:05 [Plugins] CMD: SELECT n.hwaddr AS objectPrimaryId, {s-quote}null{s-quote} AS objectSecondaryId, datetime() AS DateTime, na.ip AS watchedValue1, n.lastQuery AS watchedValue2, na.name AS watchedValue3, n.macVendor AS watchedValue4, {s-quote}null{s-quote} AS Extra, n.hwaddr AS ForeignKey FROM EXTERNAL_PIHOLE.Network AS n LEFT JOIN EXTERNAL_PIHOLE.Network_Addresses AS na ON na.network_id = n.id WHERE n.hwaddr NOT LIKE {s-quote}ip-%{s-quote} AND n.hwaddr is not {s-quote}00:00:00:00:00:00{s-quote} AND na.ip is not null
17:31:05 [Plugins] setTyp: subnets 17:31:05 [Plugins] setTyp: subnets
17:31:05 [Plugin utils] Flattening the below array 17:31:05 [Plugin utils] Flattening the below array
17:31:05 ['192.168.1.0/24 --interface=eth1'] 17:31:05 ['192.168.1.0/24 --interface=eth1']
@@ -52,7 +52,7 @@ Input data from the plugin might cause mapping issues in specific edge cases. Lo
17:31:05 [Plugins] Convert to Base64: True 17:31:05 [Plugins] Convert to Base64: True
17:31:05 [Plugins] base64 value: b'MTkyLjE2OC4xLjAvMjQgLS1pbnRlcmZhY2U9ZXRoMQ==' 17:31:05 [Plugins] base64 value: b'MTkyLjE2OC4xLjAvMjQgLS1pbnRlcmZhY2U9ZXRoMQ=='
17:31:05 [Plugins] Timeout: 10 17:31:05 [Plugins] Timeout: 10
17:31:05 [Plugins] Executing: SELECT n.hwaddr AS Object_PrimaryID, 'null' AS Object_SecondaryID, datetime() AS DateTime, na.ip AS Watched_Value1, n.lastQuery AS Watched_Value2, na.name AS Watched_Value3, n.macVendor AS Watched_Value4, 'null' AS Extra, n.hwaddr AS ForeignKey FROM EXTERNAL_PIHOLE.Network AS n LEFT JOIN EXTERNAL_PIHOLE.Network_Addresses AS na ON na.network_id = n.id WHERE n.hwaddr NOT LIKE 'ip-%' AND n.hwaddr is not '00:00:00:00:00:00' AND na.ip is not null 17:31:05 [Plugins] Executing: SELECT n.hwaddr AS objectPrimaryId, 'null' AS objectSecondaryId, datetime() AS DateTime, na.ip AS watchedValue1, n.lastQuery AS watchedValue2, na.name AS watchedValue3, n.macVendor AS watchedValue4, 'null' AS Extra, n.hwaddr AS ForeignKey FROM EXTERNAL_PIHOLE.Network AS n LEFT JOIN EXTERNAL_PIHOLE.Network_Addresses AS na ON na.network_id = n.id WHERE n.hwaddr NOT LIKE 'ip-%' AND n.hwaddr is not '00:00:00:00:00:00' AND na.ip is not null
🔻 🔻
17:31:05 [Plugins] SUCCESS, received 2 entries 17:31:05 [Plugins] SUCCESS, received 2 entries
17:31:05 [Plugins] sqlParam entries: [(0, 'PIHOLE', '01:01:01:01:01:01', 'null', 'null', '2023-12-25 06:31:05', '172.30.0.1', 0, 'aaaa', 'vvvvvvvvv', 'not-processed', 'null', 'null', '01:01:01:01:01:01'), (0, 'PIHOLE', '02:42:ac:1e:00:02', 'null', 'null', '2023-12-25 06:31:05', '172.30.0.2', 0, 'dddd', 'vvvvv2222', 'not-processed', 'null', 'null', '02:42:ac:1e:00:02')] 17:31:05 [Plugins] sqlParam entries: [(0, 'PIHOLE', '01:01:01:01:01:01', 'null', 'null', '2023-12-25 06:31:05', '172.30.0.1', 0, 'aaaa', 'vvvvvvvvv', 'not-processed', 'null', 'null', '01:01:01:01:01:01'), (0, 'PIHOLE', '02:42:ac:1e:00:02', 'null', 'null', '2023-12-25 06:31:05', '172.30.0.2', 0, 'dddd', 'vvvvv2222', 'not-processed', 'null', 'null', '02:42:ac:1e:00:02')]

View File

@@ -21,7 +21,7 @@ docker run \
--tmpfs /tmp:uid=20211,gid=20211,mode=1700 \ --tmpfs /tmp:uid=20211,gid=20211,mode=1700 \
-e PORT=20211 \ -e PORT=20211 \
-e APP_CONF_OVERRIDE='{"GRAPHQL_PORT":"20214"}' \ -e APP_CONF_OVERRIDE='{"GRAPHQL_PORT":"20214"}' \
ghcr.io/jokob-sk/netalertx:latest ghcr.io/netalertx/netalertx:latest
``` ```
@@ -34,11 +34,11 @@ Note: Your `/local_data_dir` should contain a `config` and `db` folder.
If possible, check if your issue got fixed in the `_dev` image before opening a new issue. The container is: If possible, check if your issue got fixed in the `_dev` image before opening a new issue. The container is:
`ghcr.io/jokob-sk/netalertx-dev:latest` `ghcr.io/netalertx/netalertx-dev:latest`
> ⚠ Please backup your DB and config beforehand! > ⚠ Please backup your DB and config beforehand!
Please also search [open issues](https://github.com/jokob-sk/NetAlertX/issues). Please also search [open issues](https://github.com/netalertx/NetAlertX/issues).
## 4. Disable restart behavior ## 4. Disable restart behavior

View File

@@ -8,13 +8,17 @@ This set of settings allows you to group Devices under different views. The Arch
## Status Colors ## Status Colors
![Sattus colors](./img/DEVICE_MANAGEMENT/device_management_status_colors.png) | Icon | Status | Image | Description |
|-----------|------------------------|-----------------------------------------------------------------------|-----------------------------------------------------------------------------------------------|
1. 🔌 Online (Green) = A device that is no longer marked as a "New Device". | <i class="fa-solid fa-plug"></i> | Online (Green) | ![Status color - online](./img/DEVICE_MANAGEMENT/device_management_status_online.png) | A device that is no longer marked as a "New Device". |
2. 🔌 New (Green) = A newly discovered device that is online and is still marked as a "New Device". | <i class="fa-solid fa-plug"></i> | New (Green) | ![Status color - new online](./img/DEVICE_MANAGEMENT/device_management_status_new_online.png) | A newly discovered device that is online and is still marked as a "New Device". |
3. ✖ New (Grey) = Same as No.2 but device is now offline. | <i class="fa-solid fa-plug-circle-exclamation"></i> | Online (Orange) | ![Status color - flapping online](./img/DEVICE_MANAGEMENT/device_management_status_flapping_online.png) | The device is online, but unstable and flapping (3 status changes in the last hour). |
4. ✖ Offline (Grey) = A device that was not detected online in the last scan. | <i class="fa-solid fa-xmark"></i> | New (Grey) | ![Status color - new offline](./img/DEVICE_MANAGEMENT/device_management_status_new_offline.png) | Same as "New (Green)" but the device is now offline. |
5. ⚠ Down (Red) = A device that has "Alert Down" marked and has been offline for the time set in the Setting `NTFPRCS_alert_down_time`. | <i class="fa-solid fa-box-archive"></i> | New (Grey) | ![Status color - new archived](./img/DEVICE_MANAGEMENT/device_management_status_archived_new.png) | Same as "New (Green)" but the device is now offline and archived. |
| <i class="fa-solid fa-xmark"></i> | Offline (Grey) | ![Status color - offline](./img/DEVICE_MANAGEMENT/device_management_status_offline.png) | A device that was not detected online in the last scan. |
| <i class="fa-solid fa-box-archive"></i> | Archived (Grey) | ![Status color - archived](./img/DEVICE_MANAGEMENT/device_management_status_archived.png) | A device that was not detected online in the last scan. |
| <i class="fa-solid fa-moon"></i> | Sleeping (Aqua) | ![Status color - sleeping](./img/DEVICE_MANAGEMENT/device_management_status_sleeping.png) | A device with **Can Sleep** enabled that has gone offline within the `NTFPRCS_sleep_time` window. No down alert is fired while the device is in this state. See [Notifications](./NOTIFICATIONS.md#device-settings). |
| <i class="fa-solid fa-triangle-exclamation"></i> | Down (Red) | ![Status color - down](./img/DEVICE_MANAGEMENT/device_management_status_down.png) | A device marked as "Alert Down" and offline for the duration set in `NTFPRCS_alert_down_time`.|
See also [Notification guide](./NOTIFICATIONS.md). See also [Notification guide](./NOTIFICATIONS.md).

View File

@@ -39,9 +39,24 @@ The **MAC** field and the **Last IP** field will then become editable.
![Save Dummy Device](./img/DEVICE_MANAGEMENT/DeviceEdit_SaveDummyDevice.png) ![Save Dummy Device](./img/DEVICE_MANAGEMENT/DeviceEdit_SaveDummyDevice.png)
> [!NOTE] ## Dummy or Manually Created Device Status
>
> You can couple this with the `ICMP` plugin which can be used to monitor the status of these devices, if they are actual devices reachable with the `ping` command. If not, you can use a loopback IP address so they appear online, such as `0.0.0.0` or `127.0.0.1`. You can control a dummy devices status either via `ICMP` (automatic) or the `Force Status` field (manual). Choose based on whether the device is real and how important **data hygiene** is.
### `ICMP` (Real Devices)
Use a real IP that responds to ping so status is updated automatically.
### `Force Status` (Best for Data Hygiene)
Manually set the status when the device is not reachable or is purely logical.
This keeps your data clean and avoids fake IPs.
### Loopback IP (`127.0.0.1`, `0.0.0.0`)
Use when you want the device to always appear online via `ICMP`.
Note this simulates reachability and introduces artificial data. This approach might be preferred, if you want to filter and distinguish dummy devices based on IP when filtering your asset lists.
## Copying data from an existing device. ## Copying data from an existing device.

View File

@@ -43,7 +43,7 @@ The following steps will guide you to set up your environment for local developm
### 1. Download the code: ### 1. Download the code:
- `mkdir /development` - `mkdir /development`
- `cd /development && git clone https://github.com/jokob-sk/NetAlertX.git` - `cd /development && git clone https://github.com/netalertx/NetAlertX.git`
### 2. Create a DEV .env_dev file ### 2. Create a DEV .env_dev file
@@ -77,7 +77,7 @@ Create a folder `netalertx` in the `APP_DATA_LOCATION` (in this example in `/vol
You can then modify the python script without restarting/rebuilding the container every time. Additionally, you can trigger a plugin run via the UI: 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) ![image](https://github.com/netalertx/NetAlertX/assets/96159884/3cbf2748-03c8-49e7-b801-f38c7755246b)
## Tips ## Tips

View File

@@ -17,7 +17,7 @@ services:
netalertx: netalertx:
#use an environmental variable to set host networking mode if needed #use an environmental variable to set host networking mode if needed
container_name: netalertx # The name when you docker contiainer ls container_name: netalertx # The name when you docker contiainer ls
image: ghcr.io/jokob-sk/netalertx:latest image: ghcr.io/netalertx/netalertx:latest
network_mode: ${NETALERTX_NETWORK_MODE:-host} # Use host networking for ARP scanning and other services network_mode: ${NETALERTX_NETWORK_MODE:-host} # Use host networking for ARP scanning and other services
read_only: true # Make the container filesystem read-only read_only: true # Make the container filesystem read-only
@@ -30,6 +30,17 @@ services:
- CHOWN # Required for root-entrypoint to chown /data + /tmp before dropping privileges - CHOWN # Required for root-entrypoint to chown /data + /tmp before dropping privileges
- SETUID # Required for root-entrypoint to switch to non-root user - SETUID # Required for root-entrypoint to switch to non-root user
- SETGID # Required for root-entrypoint to switch to non-root group - SETGID # Required for root-entrypoint to switch to non-root group
# --- ARP FLUX MITIGATION ---
# Note: When using `network_mode: host`, these sysctls require the
# NET_ADMIN capability to be applied to the host namespace.
#
# If your environment restricts capabilities, or you prefer to configure
# them on the Host OS, REMOVE the sysctls block below and apply via:
# sudo sysctl -w net.ipv4.conf.all.arp_ignore=1 net.ipv4.conf.all.arp_announce=2
# ---------------------------
sysctls: # ARP flux mitigation (reduces duplicate/ambiguous ARP behavior on host networking)
net.ipv4.conf.all.arp_ignore: 1
net.ipv4.conf.all.arp_announce: 2
volumes: volumes:
- type: volume # Persistent Docker-managed named volume for config + database - type: volume # Persistent Docker-managed named volume for config + database

View File

@@ -1,6 +1,6 @@
[![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 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) [![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) [![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/netalertx/NetAlertX/releases)
[![Discord](https://img.shields.io/discord/1274490466481602755?color=0aa8d2&logoColor=fff&logo=Discord&style=for-the-badge)](https://discord.gg/NczTUTWyRr) [![Discord](https://img.shields.io/discord/1274490466481602755?color=0aa8d2&logoColor=fff&logo=Discord&style=for-the-badge)](https://discord.gg/NczTUTWyRr)
[![Home Assistant](https://img.shields.io/badge/Repo-blue?logo=home-assistant&style=for-the-badge&color=0aa8d2&logoColor=fff&label=Add)](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Falexbelgium%2Fhassio-addons) [![Home Assistant](https://img.shields.io/badge/Repo-blue?logo=home-assistant&style=for-the-badge&color=0aa8d2&logoColor=fff&label=Add)](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Falexbelgium%2Fhassio-addons)
@@ -31,7 +31,7 @@ docker run -d --rm --network=host \
--tmpfs /tmp:uid=${NETALERTX_UID:-20211},gid=${NETALERTX_GID:-20211},mode=1700 \ --tmpfs /tmp:uid=${NETALERTX_UID:-20211},gid=${NETALERTX_GID:-20211},mode=1700 \
-e PORT=20211 \ -e PORT=20211 \
-e APP_CONF_OVERRIDE={"GRAPHQL_PORT":"20214"} \ -e APP_CONF_OVERRIDE={"GRAPHQL_PORT":"20214"} \
ghcr.io/jokob-sk/netalertx:latest ghcr.io/netalertx/netalertx:latest
``` ```
> Runtime UID/GID: The image defaults to a service user `netalertx` (UID/GID 20211). A separate readonly lock owner also uses UID/GID 20211 for 004/005 immutability. You can override the runtime UID/GID at build (ARG) or run (`--user` / compose `user:`) but must align writable mounts (`/data`, `/tmp*`) and tmpfs `uid/gid` to that choice. > Runtime UID/GID: The image defaults to a service user `netalertx` (UID/GID 20211). A separate readonly lock owner also uses UID/GID 20211 for 004/005 immutability. You can override the runtime UID/GID at build (ARG) or run (`--user` / compose `user:`) but must align writable mounts (`/data`, `/tmp*`) and tmpfs `uid/gid` to that choice.
@@ -96,7 +96,7 @@ sudo chmod -R a+rwx /local_data_dir
### Initial setup ### Initial setup
- If unavailable, the app generates a default `app.conf` and `app.db` file on the first run. - If unavailable, the app generates a default `app.conf` and `app.db` file on the first run.
- The preferred way is to manage the configuration via the Settings section in the UI, if UI is inaccessible you can modify [app.conf](https://github.com/jokob-sk/NetAlertX/tree/main/back) in the `/data/config/` folder directly - The preferred way is to manage the configuration via the Settings section in the UI, if UI is inaccessible you can modify [app.conf](https://github.com/netalertx/NetAlertX/tree/main/back) in the `/data/config/` folder directly
#### Setting up scanners #### Setting up scanners
@@ -116,7 +116,7 @@ You can read or watch several [community configuration guides](https://docs.neta
#### Common issues #### Common issues
- Before creating a new issue, please check if a similar issue was [already resolved](https://github.com/jokob-sk/NetAlertX/issues?q=is%3Aissue+is%3Aclosed). - Before creating a new issue, please check if a similar issue was [already resolved](https://github.com/netalertx/NetAlertX/issues?q=is%3Aissue+is%3Aclosed).
- Check also common issues and [debugging tips](https://docs.netalertx.com/DEBUG_TIPS). - Check also common issues and [debugging tips](https://docs.netalertx.com/DEBUG_TIPS).
## 💙 Support me ## 💙 Support me

View File

@@ -35,9 +35,9 @@ services:
netalertx: netalertx:
container_name: netalertx container_name: netalertx
# Use this line for stable release # Use this line for stable release
image: "ghcr.io/jokob-sk/netalertx:latest" image: "ghcr.io/netalertx/netalertx:latest"
# Or, use this for the latest development build # Or, use this for the latest development build
# image: "ghcr.io/jokob-sk/netalertx-dev:latest" # image: "ghcr.io/netalertx/netalertx-dev:latest"
network_mode: "host" network_mode: "host"
restart: unless-stopped restart: unless-stopped
cap_drop: # Drop all capabilities for enhanced security cap_drop: # Drop all capabilities for enhanced security

View File

@@ -44,7 +44,7 @@ Use the following Compose snippet to deploy NetAlertX with a **static LAN IP** a
```yaml ```yaml
services: services:
netalertx: netalertx:
image: ghcr.io/jokob-sk/netalertx:latest image: ghcr.io/netalertx/netalertx:latest
... ...
networks: networks:
swarm-ipvlan: swarm-ipvlan:

View File

@@ -32,12 +32,22 @@ NetAlertX is a lightweight, flexible platform for monitoring networks, tracking
![Event-Driven Alerts](./img/FEATURES/Event-Driven_Alerts.png) ![Event-Driven Alerts](./img/FEATURES/Event-Driven_Alerts.png)
- **Real-Time Notifications**: Receive immediate alerts for new devices, disconnected devices, or unexpected changes. - **Real-Time Notifications**: Receive immediate alerts for new devices, disconnected devices, or unexpected changes.
- **Customizable Triggers**: Define rules based on device type, IP ranges, presence, or other network parameters. - **Customizable Filters and Rules**: Define rules based on device type, IP ranges, presence, or other network parameters.
- **Alert Deduplication & Suppression**: Avoid unnecessary noise with smart alert handling. - **Alert Deduplication & Suppression**: Avoid unnecessary noise with smart alert handling.
- **Historical Logs**: Maintain a complete timeline of network events for review and reporting. - **Historical Logs**: Maintain a complete timeline of network events for review and reporting.
--- ---
## Workflows for implementing Business rules
![orkflows](./img/WORKFLOWS/workflows.png)
- **Custom rules**: Cretae custom flows and update device information based to scan results.
- **Customizable Triggers**: Define rules based on any device data, including device type, IP ranges, presence, or other network parameters.
- **Automated Updates**: Automate repetitive tasks, making network management more efficient.
---
## Multi-Channel Notification ## Multi-Channel Notification
![Multi-Channel Notification](./img/FEATURES/Multi-Channel_Notifications.png) ![Multi-Channel Notification](./img/FEATURES/Multi-Channel_Notifications.png)

View File

@@ -12,7 +12,7 @@ docker run --rm --network=host \
-v /etc/localtime:/etc/localtime:ro \ -v /etc/localtime:/etc/localtime:ro \
--tmpfs /tmp:uid=20211,gid=20211,mode=1700 \ --tmpfs /tmp:uid=20211,gid=20211,mode=1700 \
-e PORT=20211 \ -e PORT=20211 \
ghcr.io/jokob-sk/netalertx:latest ghcr.io/netalertx/netalertx:latest
``` ```
> [!WARNING] > [!WARNING]
@@ -70,7 +70,7 @@ If you use a custom `PUID` (e.g. `0`) and `GUID` (e.g. `100`) make sure you also
docker run -it --rm --name netalertx --user "0" \ docker run -it --rm --name netalertx --user "0" \
-v /local_data_dir:/data \ -v /local_data_dir:/data \
--tmpfs /tmp:uid=20211,gid=20211,mode=1700 \ --tmpfs /tmp:uid=20211,gid=20211,mode=1700 \
ghcr.io/jokob-sk/netalertx:latest ghcr.io/netalertx/netalertx:latest
``` ```
2. Wait for logs showing **permissions being fixed**. The container will then **hang intentionally**. 2. Wait for logs showing **permissions being fixed**. The container will then **hang intentionally**.
@@ -95,7 +95,7 @@ docker run -it --rm --name netalertx --user "0" \
services: services:
netalertx: netalertx:
container_name: netalertx container_name: netalertx
image: "ghcr.io/jokob-sk/netalertx" image: "ghcr.io/netalertx/netalertx"
network_mode: "host" network_mode: "host"
cap_drop: # Drop all capabilities for enhanced security cap_drop: # Drop all capabilities for enhanced security
- ALL - ALL

View File

@@ -77,6 +77,6 @@ After increasing the ARP timeout and adding ICMP scanning (on select IP ranges),
**Tip:** Each environment is unique. Consider fine-tuning scan settings based on your network size, device behavior, and desired detection accuracy. **Tip:** Each environment is unique. Consider fine-tuning scan settings based on your network size, device behavior, and desired detection accuracy.
Let us know in the [NetAlertX Discussions](https://github.com/jokob-sk/NetAlertX/discussions) if you have further feedback or edge cases. Let us know in the [NetAlertX Discussions](https://github.com/netalertx/NetAlertX/discussions) if you have further feedback or edge cases.
See also [Remote Networks](./REMOTE_NETWORKS.md) for more advanced setups. See also [Remote Networks](./REMOTE_NETWORKS.md) for more advanced setups.

View File

@@ -43,4 +43,4 @@ Some useful frontend JavaScript functions:
- `getSetting(string stringKey)` - method to retrieve settings in the frontend - `getSetting(string stringKey)` - method to retrieve settings in the frontend
Check the [common.js](https://github.com/jokob-sk/NetAlertX/blob/main-2023-06-10/front/js/common.js) file for more frontend functions. Check the [common.js](https://github.com/netalertx/NetAlertX/blob/main-2023-06-10/front/js/common.js) file for more frontend functions.

View File

@@ -4,7 +4,7 @@ This page provides an overview of community-contributed scripts for NetAlertX. T
## Community Scripts ## Community Scripts
You can find all scripts in this [scripts GitHub folder](https://github.com/jokob-sk/NetAlertX/tree/main/scripts). You can find all scripts in this [scripts GitHub folder](https://github.com/netalertx/NetAlertX/tree/main/scripts).
| Script Name | Description | Author | Version | Release Date | | Script Name | Description | Author | Version | Release Date |
|------------|-------------|--------|---------|--------------| |------------|-------------|--------|---------|--------------|
@@ -17,5 +17,5 @@ You can find all scripts in this [scripts GitHub folder](https://github.com/joko
> [!NOTE] > [!NOTE]
> These scripts are community-supplied and not actively maintained. Use at your own discretion. > These scripts are community-supplied and not actively maintained. Use at your own discretion.
For detailed usage instructions, refer to each script's documentation in each [scripts GitHub folder](https://github.com/jokob-sk/NetAlertX/tree/main/scripts). For detailed usage instructions, refer to each script's documentation in each [scripts GitHub folder](https://github.com/netalertx/NetAlertX/tree/main/scripts).

View File

@@ -9,7 +9,7 @@ NetAlertX comes with MQTT support, allowing you to show all detected devices as
- Please note that discovery takes about ~10s per device. - 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. - 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. - For optimization reasons, the devices are not always fully synchronized. You can delete Plugin objects as described in the [MQTT plugin](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/_publisher_mqtt#forcing-an-update) docs to force a full synchronization.
## 🧭 Guide ## 🧭 Guide

View File

@@ -40,7 +40,7 @@ Some facts about what and where something will be changed/installed by the HW in
- **EXPERIMENTAL** and not recommended way to install NetAlertX. - **EXPERIMENTAL** and not recommended way to install NetAlertX.
> [!TIP] > [!TIP]
> If the below fails try grabbing and installing one of the [previous releases](https://github.com/jokob-sk/NetAlertX/releases) and run the installation from the zip package. > If the below fails try grabbing and installing one of the [previous releases](https://github.com/netalertx/NetAlertX/releases) and run the installation from the zip package.
These commands will download the `install.debian12.sh` script from the GitHub repository, make it executable with `chmod`, and then run it using `./install.debian12.sh`. These commands will download the `install.debian12.sh` script from the GitHub repository, make it executable with `chmod`, and then run it using `./install.debian12.sh`.

View File

@@ -102,7 +102,7 @@ Before opening a new issue:
* 📘 [Common Issues](./COMMON_ISSUES.md) * 📘 [Common Issues](./COMMON_ISSUES.md)
* 🧰 [Debugging Tips](./DEBUG_TIPS.md) * 🧰 [Debugging Tips](./DEBUG_TIPS.md)
* ✅ [Browse resolved GitHub issues](https://github.com/jokob-sk/NetAlertX/issues?q=is%3Aissue+is%3Aclosed) * ✅ [Browse resolved GitHub issues](https://github.com/netalertx/NetAlertX/issues?q=is%3Aissue+is%3Aclosed)
--- ---

View File

@@ -17,10 +17,10 @@ If facing issues, please spend a few minutes searching.
- Check [common issues](./COMMON_ISSUES.md) - Check [common issues](./COMMON_ISSUES.md)
- Have a look at [Community guides](./COMMUNITY_GUIDES.md) - Have a look at [Community guides](./COMMUNITY_GUIDES.md)
- [Search closed or open issues or discussions](https://github.com/jokob-sk/NetAlertX/issues?q=is%3Aissue) - [Search closed or open issues or discussions](https://github.com/netalertx/NetAlertX/issues?q=is%3Aissue)
- Check [Discord](https://discord.gg/NczTUTWyRr) - Check [Discord](https://discord.gg/NczTUTWyRr)
> [!NOTE] > [!NOTE]
> If you can't find a solution anywhere, ask in Discord if you think it's a quick question, otherwise open a new [issue](https://github.com/jokob-sk/NetAlertX/issues/new?template=setup-help.yml). Please fill in as much as possible to speed up the help process. > If you can't find a solution anywhere, ask in Discord if you think it's a quick question, otherwise open a new [issue](https://github.com/netalertx/NetAlertX/issues/new?template=setup-help.yml). Please fill in as much as possible to speed up the help process.
> >

View File

@@ -215,7 +215,7 @@ services:
### 1.3 Migration from NetAlertX `v25.10.1` ### 1.3 Migration from NetAlertX `v25.10.1`
Starting from v25.10.1, the container uses a [more secure, read-only runtime environment](./SECURITY_FEATURES.md), which requires all writable paths (e.g., logs, API cache, temporary data) to be mounted as `tmpfs` or permanent writable volumes, with sufficient access [permissions](./FILE_PERMISSIONS.md). The data location has also hanged from `/app/db` and `/app/config` to `/data/db` and `/data/config`. See detailed steps below. Starting from `v25.10.1`, the container uses a [more secure, read-only runtime environment](./SECURITY_FEATURES.md), which requires all writable paths (e.g., logs, API cache, temporary data) to be mounted as `tmpfs` or permanent writable volumes, with sufficient access [permissions](./FILE_PERMISSIONS.md). The data location has also hanged from `/app/db` and `/app/config` to `/data/db` and `/data/config`. See detailed steps below.
#### STEPS: #### STEPS:
@@ -248,7 +248,7 @@ services:
services: services:
netalertx: netalertx:
container_name: netalertx container_name: netalertx
image: "ghcr.io/jokob-sk/netalertx" # 🆕 This has changed image: "ghcr.io/jokob-sk/netalertx:25.11.29" # 🆕 This has changed
network_mode: "host" network_mode: "host"
cap_drop: # 🆕 New line cap_drop: # 🆕 New line
- ALL # 🆕 New line - ALL # 🆕 New line
@@ -318,7 +318,7 @@ As per user feedback, weve re-introduced the ability to control which user th
services: services:
netalertx: netalertx:
container_name: netalertx container_name: netalertx
image: "ghcr.io/jokob-sk/netalertx" image: "ghcr.io/netalertx/netalertx"
network_mode: "host" network_mode: "host"
cap_drop: cap_drop:
- ALL - ALL

View File

@@ -1,5 +1,8 @@
# Notifications 📧 # Notifications 📧
> [!TIP]
> Want to customize how devices appear in text notifications? See [Notification Text Templates](NOTIFICATION_TEMPLATES.md).
There are 4 ways how to influence notifications: There are 4 ways how to influence notifications:
1. On the device itself 1. On the device itself
@@ -19,11 +22,12 @@ The following device properties influence notifications. You can:
1. **Alert Events** - Enables alerts of connections, disconnections, IP changes (down and down reconnected notifications are still sent even if this is disabled). 1. **Alert Events** - Enables alerts of connections, disconnections, IP changes (down and down reconnected notifications are still sent even if this is disabled).
2. **Alert Down** - Alerts when a device goes down. This setting overrides a disabled **Alert Events** setting, so you will get a notification of a device going down even if you don't have **Alert Events** ticked. Disabling this will disable down and down reconnected notifications on the device. 2. **Alert Down** - Alerts when a device goes down. This setting overrides a disabled **Alert Events** setting, so you will get a notification of a device going down even if you don't have **Alert Events** ticked. Disabling this will disable down and down reconnected notifications on the device.
3. **Skip repeated notifications**, if for example you know there is a temporary issue and want to pause the same notification for this device for a given time. 3. **Can Sleep** - Marks the device as sleep-capable (e.g. a battery-powered sensor that deep-sleeps between readings). When enabled, offline periods within the **Alert down after (sleep)** (`NTFPRCS_sleep_time`) global window are shown as **Sleeping** (aqua badge 🌙) instead of **Down**, and no down alert is fired during that window. Once the window expires the device falls back to normal down-alert logic. ⚠ Requires **Alert Down** to be enabled — sleeping suppresses the alert during the window only.
4. **Require NICs Online** - Indicates whether this device should be considered online only if all associated NICs (devices with the `nic` relationship type) are online. If disabled, the device is considered online if any NIC is online. If a NIC is online it sets the parent (this) device's status to online irrespectivelly of the detected device's status. The Relationship type is set on the childern device. 4. **Skip repeated notifications**, if for example you know there is a temporary issue and want to pause the same notification for this device for a given time.
5. **Require NICs Online** - Indicates whether this device should be considered online only if all associated NICs (devices with the `nic` relationship type) are online. If disabled, the device is considered online if any NIC is online. If a NIC is online it sets the parent (this) device's status to online irrespectivelly of the detected device's status. The Relationship type is set on the childern device.
> [!NOTE] > [!NOTE]
> Please read through the [NTFPRCS plugin](https://github.com/jokob-sk/NetAlertX/blob/main/front/plugins/notification_processing/README.md) documentation to understand how device and global settings influence the notification processing. > Please read through the [NTFPRCS plugin](https://github.com/netalertx/NetAlertX/blob/main/front/plugins/notification_processing/README.md) documentation to understand how device and global settings influence the notification processing.
## Plugin settings 🔌 ## Plugin settings 🔌
@@ -32,7 +36,7 @@ The following device properties influence notifications. You can:
On almost all plugins there are 2 core settings, `<plugin>_WATCH` and `<plugin>_REPORT_ON`. On almost all plugins there are 2 core settings, `<plugin>_WATCH` and `<plugin>_REPORT_ON`.
1. `<plugin>_WATCH` specifies the columns which the app should watch. If watched columns change the device state is considered changed. This changed status is then used to decide to send out notifications based on the `<plugin>_REPORT_ON` setting. 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. 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 `watchedValue1`, then a notification is triggered if `watchedValue1` is changed from the previous value, but no notification is send if `watchedValue2` 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. Click the **Read more in the docs.** Link at the top of each plugin to get more details on how the given plugin works.
@@ -42,10 +46,11 @@ Click the **Read more in the docs.** Link at the top of each plugin to get more
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. 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 `down_reconnected` set. Including `plugin` (dependenton the Plugin `<plugin>_WATCH` and `<plugin>_REPORT_ON` settings) and `events` (dependent on the on-device **Alert Events** setting) might be too noisy for most setups. More info in the [NTFPRCS plugin](https://github.com/jokob-sk/NetAlertX/blob/main/front/plugins/notification_processing/README.md) on what events these selections include. 1. Notify on (`NTFPRCS_INCLUDED_SECTIONS`) allows you to specify which events trigger notifications. Usual setups will have `new_devices`, `down_devices`, and possibly `down_reconnected` set. Including `plugin` (dependenton the Plugin `<plugin>_WATCH` and `<plugin>_REPORT_ON` settings) and `events` (dependent on the on-device **Alert Events** setting) might be too noisy for most setups. More info in the [NTFPRCS plugin](https://github.com/netalertx/NetAlertX/blob/main/front/plugins/notification_processing/README.md) on what events these selections include.
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. 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. Alert down after (sleep) (`NTFPRCS_sleep_time`) sets the **sleep window** in minutes. If a device has **Can Sleep** enabled and goes offline, it is shown as **Sleeping** (aqua 🌙 badge) for this many minutes before down-alert logic kicks in. Default is `30` minutes. Changing this setting takes effect after saving — no restart required.
You can filter out unwanted notifications globally. This could be because of a misbehaving device (GoogleNest/GoogleHub (See also [ARPSAN docs and the `--exclude-broadcast` flag](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/arp_scan#ip-flipping-on-google-nest-devices))) which flips between IP addresses, or because you want to ignore new device notifications of a certain pattern. You can filter out unwanted notifications globally. This could be because of a misbehaving device (GoogleNest/GoogleHub (See also [ARPSAN docs and the `--exclude-broadcast` flag](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/arp_scan#ip-flipping-on-google-nest-devices))) which flips between IP addresses, or because you want to ignore new device notifications of a certain pattern.
1. Events Filter (`NTFPRCS_event_condition`) - Filter out Events from notifications. 1. Events Filter (`NTFPRCS_event_condition`) - Filter out Events from notifications.
2. New Devices Filter (`NTFPRCS_new_dev_condition`) - Filter out New Devices from notifications, but log and keep a new device in the system. 2. New Devices Filter (`NTFPRCS_new_dev_condition`) - Filter out New Devices from notifications, but log and keep a new device in the system.

View File

@@ -0,0 +1,100 @@
# Notification Text Templates
> Customize how devices and events appear in **text** notifications (email previews, push notifications, Apprise messages).
By default, NetAlertX formats each device as a vertical list of `Header: Value` pairs. Text templates let you define a **single-line format per device** using `{FieldName}` placeholders — ideal for mobile notification previews and high-volume alerts.
HTML email tables are **not affected** by these templates.
## Quick Start
1. Go to **Settings → Notification Processing**.
2. Set a template string for the section you want to customize, e.g.:
- **Text Template: New Devices** → `{devName} ({eveMac}) - {eveIp}`
3. Save. The next notification will use your format.
**Before (default):**
```
🆕 New devices
---------
devName: MyPhone
eveMac: aa:bb:cc:dd:ee:ff
devVendor: Apple
eveIp: 192.168.1.42
eveDateTime: 2025-01-15 10:30:00
eveEventType: New Device
devComments:
```
**After (with template `{devName} ({eveMac}) - {eveIp}`):**
```
🆕 New devices
---------
MyPhone (aa:bb:cc:dd:ee:ff) - 192.168.1.42
```
## Settings Reference
| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `NTFPRCS_TEXT_SECTION_HEADERS` | Boolean | `true` | Show/hide section titles (e.g. `🆕 New devices \n---------`). |
| `NTFPRCS_TEXT_TEMPLATE_new_devices` | String | *(empty)* | Template for new device rows. |
| `NTFPRCS_TEXT_TEMPLATE_down_devices` | String | *(empty)* | Template for down device rows. |
| `NTFPRCS_TEXT_TEMPLATE_down_reconnected` | String | *(empty)* | Template for reconnected device rows. |
| `NTFPRCS_TEXT_TEMPLATE_events` | String | *(empty)* | Template for event rows. |
| `NTFPRCS_TEXT_TEMPLATE_plugins` | String | *(empty)* | Template for plugin event rows. |
When a template is **empty**, the section uses the original vertical `Header: Value` format (full backward compatibility).
## Template Syntax
Use `{FieldName}` to insert a value from the notification data. Field names are **case-sensitive** and must match the column names exactly.
```
{devName} ({eveMac}) connected at {eveDateTime}
```
- No loops, conditionals, or nesting — just simple string replacement.
- If a `{FieldName}` does not exist in the data, it is left as-is in the output (safe failure). For example, `{NonExistent}` renders literally as `{NonExistent}`.
## Variable Availability by Section
All four device sections (`new_devices`, `down_devices`, `down_reconnected`, `events`) share the same unified field names.
### `new_devices`, `down_devices`, `down_reconnected`, and `events`
| Variable | Description |
|----------|-------------|
| `{devName}` | Device display name |
| `{eveMac}` | Device MAC address |
| `{devVendor}` | Device vendor/manufacturer |
| `{eveIp}` | Device IP address |
| `{eveDateTime}` | Event timestamp |
| `{eveEventType}` | Type of event (e.g. `New Device`, `Connected`, `Device Down`) |
| `{devComments}` | Device comments |
**Example (new_devices/events):** `{devName} ({eveMac}) - {eveIp} [{eveEventType}]`
**Example (down_devices):** `{devName} ({eveMac}) {devVendor} - went down at {eveDateTime}`
**Example (down_reconnected):** `{devName} ({eveMac}) reconnected at {eveDateTime}`
### `plugins`
| Variable | Description |
|----------|-------------|
| `{plugin}` | Plugin code name |
| `{objectPrimaryId}` | Primary identifier of the object |
| `{objectSecondaryId}` | Secondary identifier |
| `{dateTimeChanged}` | Timestamp of change |
| `{watchedValue1}` | First watched value |
| `{watchedValue2}` | Second watched value |
| `{watchedValue3}` | Third watched value |
| `{watchedValue4}` | Fourth watched value |
| `{status}` | Plugin event status |
**Example:** `{plugin}: {objectPrimaryId} - {status}`
## Section Headers Toggle
Set **Text Section Headers** (`NTFPRCS_TEXT_SECTION_HEADERS`) to `false` to remove the section title separators from text notifications. This is useful when you want compact output without the `🆕 New devices \n---------` banners.

View File

@@ -48,6 +48,36 @@ Two plugins help maintain the systems performance:
--- ---
## Database Performance Tuning
The application automatically maintains database performance as data accumulates. However, you can adjust settings to balance CPU usage, disk usage, and responsiveness.
### **WAL Size Tuning (Storage vs. CPU Tradeoff)**
The SQLite Write-Ahead Log (WAL) is a temporary file that grows during normal operation. On systems with constrained resources (NAS, Raspberry Pi), controlling WAL size is important.
**Setting:** **`PRAGMA_JOURNAL_SIZE_LIMIT`** (default: **50 MB**)
| Setting | Effect | Use Case |
|---------|--------|----------|
| **1020 MB** | Smaller storage footprint; more frequent disk operations | NAS with SD card (storage priority) |
| **50 MB** (default) | Balanced; recommended for most setups | General use |
| **75100 MB** | Smoother performance; larger WAL on disk | High-speed NAS or servers |
**Recommendation:** For NAS devices with SD cards, leave at default (50 MB) or increase slightly (75 MB). Avoid very low values (< 10 MB) as they cause frequent disk thrashing and CPU spikes.
### **Automatic Cleanup**
The DB cleanup plugin (`DBCLNP`) automatically optimizes query performance and trims old data:
- **Deletes old events** Controlled by `DAYS_TO_KEEP_EVENTS` (default: 90 days)
- **Trims plugin history** Keeps recent entries only (controlled by `PLUGINS_KEEP_HIST`)
- **Optimizes queries** Updates database statistics so queries remain fast
**If cleanup fails**, performance degrades quickly. Check **Maintenance → Logs** for errors. If you see frequent failures, increase the timeout (`DBCLNP_RUN_TIMEOUT`).
---
## Scan Frequency and Coverage ## Scan Frequency and Coverage
Frequent scans increase resource usage, network traffic, and database read/write cycles. Frequent scans increase resource usage, network traffic, and database read/write cycles.
@@ -80,9 +110,9 @@ services:
netalertx: netalertx:
container_name: netalertx container_name: netalertx
# Use this line for the stable release # Use this line for the stable release
image: "ghcr.io/jokob-sk/netalertx:latest" image: "ghcr.io/netalertx/netalertx:latest"
# Or use this line for the latest development build # Or use this line for the latest development build
# image: "ghcr.io/jokob-sk/netalertx-dev:latest" # image: "ghcr.io/netalertx/netalertx-dev:latest"
network_mode: "host" network_mode: "host"
restart: unless-stopped restart: unless-stopped

View File

@@ -17,7 +17,7 @@ To use this approach make sure the Web UI password in **Pi-hole** is set.
| `PIHOLEAPI_API_MAXCLIENTS` | Maximum number of devices to request from Pi-hole. Defaults are usually fine. | `500` | | `PIHOLEAPI_API_MAXCLIENTS` | Maximum number of devices to request from Pi-hole. Defaults are usually fine. | `500` |
| `PIHOLEAPI_FAKE_MAC` | Generate FAKE MAC from IP. | `False` | | `PIHOLEAPI_FAKE_MAC` | Generate FAKE MAC from IP. | `False` |
Check the [PiHole API plugin readme](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/pihole_api_scan/) for details and troubleshooting. Check the [PiHole API plugin readme](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/pihole_api_scan/) for details and troubleshooting.
### docker-compose changes ### docker-compose changes
@@ -35,7 +35,7 @@ No changes needed
| `DHCPLSS_RUN_SCHD` | If you run multiple device scanner plugins, align the schedules of all plugins to the same value. | `*/5 * * * *` | | `DHCPLSS_RUN_SCHD` | If you run multiple device scanner plugins, align the schedules of all plugins to the same value. | `*/5 * * * *` |
| `DHCPLSS_paths_to_check` | You need to map the value in this setting in the `docker-compose.yml` file. The in-container path must contain `pihole` so it's parsed correctly. | `['/etc/pihole/dhcp.leases']` | | `DHCPLSS_paths_to_check` | You need to map the value in this setting in the `docker-compose.yml` file. The in-container path must contain `pihole` so it's parsed correctly. | `['/etc/pihole/dhcp.leases']` |
Check the [DHCPLSS plugin readme](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/dhcp_leases#overview) for details Check the [DHCPLSS plugin readme](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/dhcp_leases#overview) for details
### docker-compose changes ### docker-compose changes
@@ -54,7 +54,7 @@ Check the [DHCPLSS plugin readme](https://github.com/jokob-sk/NetAlertX/tree/mai
| `PIHOLE_RUN_SCHD` | If you run multiple device scanner plugins, align the schedules of all plugins to the same value. | `*/5 * * * *` | | `PIHOLE_RUN_SCHD` | If you run multiple device scanner plugins, align the schedules of all plugins to the same value. | `*/5 * * * *` |
| `PIHOLE_DB_PATH` | You need to map the value in this setting in the `docker-compose.yml` file. | `/etc/pihole/pihole-FTL.db` | | `PIHOLE_DB_PATH` | You need to map the value in this setting in the `docker-compose.yml` file. | `/etc/pihole/pihole-FTL.db` |
Check the [PiHole plugin readme](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/pihole_scan) for details Check the [PiHole plugin readme](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/pihole_scan) for details
### docker-compose changes ### docker-compose changes

View File

@@ -45,51 +45,51 @@ Device-detecting plugins insert values into the `CurrentScan` database table. T
| ID | Plugin docs | Type | Description | Features | Required | | ID | Plugin docs | Type | Description | Features | Required |
| --------------- | ------------------------------------------------------------------------------------------------------------------ | -------- | ----------------------------------------- | -------- | -------- | | --------------- | ------------------------------------------------------------------------------------------------------------------ | -------- | ----------------------------------------- | -------- | -------- |
| `APPRISE` | [_publisher_apprise](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/_publisher_apprise/) | ▶️ | Apprise notification proxy | | | | `APPRISE` | [_publisher_apprise](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/_publisher_apprise/) | ▶️ | Apprise notification proxy | | |
| `ARPSCAN` | [arp_scan](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/arp_scan/) | 🔍 | ARP-scan on current network | | | | `ARPSCAN` | [arp_scan](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/arp_scan/) | 🔍 | ARP-scan on current network | | |
| `AVAHISCAN` | [avahi_scan](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/avahi_scan/) | 🆎 | Avahi (mDNS-based) name resolution | | | | `AVAHISCAN` | [avahi_scan](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/avahi_scan/) | 🆎 | Avahi (mDNS-based) name resolution | | |
| `ASUSWRT` | [asuswrt_import](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/asuswrt_import/) | 🔍 | Import connected devices from AsusWRT | | | | `ASUSWRT` | [asuswrt_import](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/asuswrt_import/) | 🔍 | Import connected devices from AsusWRT | | |
| `CSVBCKP` | [csv_backup](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/csv_backup/) | ⚙ | CSV devices backup | | | | `CSVBCKP` | [csv_backup](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/csv_backup/) | ⚙ | CSV devices backup | | |
| `CUSTPROP` | [custom_props](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/custom_props/) | ⚙ | Managing custom device properties values | | Yes | | `CUSTPROP` | [custom_props](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/custom_props/) | ⚙ | Managing custom device properties values | | Yes |
| `DBCLNP` | [db_cleanup](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/db_cleanup/) | ⚙ | Database cleanup | | Yes\* | | `DBCLNP` | [db_cleanup](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/db_cleanup/) | ⚙ | Database cleanup | | Yes\* |
| `DDNS` | [ddns_update](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/ddns_update/) | ⚙ | DDNS update | | | | `DDNS` | [ddns_update](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/ddns_update/) | ⚙ | DDNS update | | |
| `DHCPLSS` | [dhcp_leases](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/dhcp_leases/) | 🔍/📥/🆎 | Import devices from DHCP leases | | | | `DHCPLSS` | [dhcp_leases](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/dhcp_leases/) | 🔍/📥/🆎 | Import devices from DHCP leases | | |
| `DHCPSRVS` | [dhcp_servers](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/dhcp_servers/) | ♻ | DHCP servers | | | | `DHCPSRVS` | [dhcp_servers](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/dhcp_servers/) | ♻ | DHCP servers | | |
| `DIGSCAN` | [dig_scan](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/dig_scan/) | 🆎 | Dig (DNS) Name resolution | | | | `DIGSCAN` | [dig_scan](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/dig_scan/) | 🆎 | Dig (DNS) Name resolution | | |
| `FREEBOX` | [freebox](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/freebox/) | 🔍/♻/🆎 | Pull data and names from Freebox/Iliadbox | | | | `FREEBOX` | [freebox](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/freebox/) | 🔍/♻/🆎 | Pull data and names from Freebox/Iliadbox | | |
| `ICMP` | [icmp_scan](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/icmp_scan/) | ♻ | ICMP (ping) status checker | | | | `ICMP` | [icmp_scan](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/icmp_scan/) | ♻ | ICMP (ping) status checker | | |
| `INTRNT` | [internet_ip](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/internet_ip/) | 🔍 | Internet IP scanner | | | | `INTRNT` | [internet_ip](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/internet_ip/) | 🔍 | Internet IP scanner | | |
| `INTRSPD` | [internet_speedtest](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/internet_speedtest/) | ♻ | Internet speed test | | | | `INTRSPD` | [internet_speedtest](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/internet_speedtest/) | ♻ | Internet speed test | | |
| `IPNEIGH` | [ipneigh](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/ipneigh/) | 🔍 | Scan ARP (IPv4) and NDP (IPv6) tables | | | | `IPNEIGH` | [ipneigh](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/ipneigh/) | 🔍 | Scan ARP (IPv4) and NDP (IPv6) tables | | |
| `LUCIRPC` | [luci_import](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/luci_import/) | 🔍 | Import connected devices from OpenWRT | | | | `LUCIRPC` | [luci_import](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/luci_import/) | 🔍 | Import connected devices from OpenWRT | | |
| `MAINT` | [maintenance](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/maintenance/) | ⚙ | Maintenance of logs, etc. | | | | `MAINT` | [maintenance](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/maintenance/) | ⚙ | Maintenance of logs, etc. | | |
| `MQTT` | [_publisher_mqtt](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/_publisher_mqtt/) | ▶️ | MQTT for synching to Home Assistant | | | | `MQTT` | [_publisher_mqtt](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/_publisher_mqtt/) | ▶️ | MQTT for synching to Home Assistant | | |
| `MTSCAN` | [mikrotik_scan](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/mikrotik_scan/) | 🔍 | Mikrotik device import & sync | | | | `MTSCAN` | [mikrotik_scan](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/mikrotik_scan/) | 🔍 | Mikrotik device import & sync | | |
| `NBTSCAN` | [nbtscan_scan](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/nbtscan_scan/) | 🆎 | Nbtscan (NetBIOS-based) name resolution | | | | `NBTSCAN` | [nbtscan_scan](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/nbtscan_scan/) | 🆎 | Nbtscan (NetBIOS-based) name resolution | | |
| `NEWDEV` | [newdev_template](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/newdev_template/) | ⚙ | New device template | | Yes | | `NEWDEV` | [newdev_template](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/newdev_template/) | ⚙ | New device template | | Yes |
| `NMAP` | [nmap_scan](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/nmap_scan/) | ♻ | Nmap port scanning & discovery | | | | `NMAP` | [nmap_scan](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/nmap_scan/) | ♻ | Nmap port scanning & discovery | | |
| `NMAPDEV` | [nmap_dev_scan](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/nmap_dev_scan/) | 🔍 | Nmap dev scan on current network | | | | `NMAPDEV` | [nmap_dev_scan](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/nmap_dev_scan/) | 🔍 | Nmap dev scan on current network | | |
| `NSLOOKUP` | [nslookup_scan](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/nslookup_scan/) | 🆎 | NSLookup (DNS-based) name resolution | | | | `NSLOOKUP` | [nslookup_scan](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/nslookup_scan/) | 🆎 | NSLookup (DNS-based) name resolution | | |
| `NTFPRCS` | [notification_processing](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/notification_processing/) | ⚙ | Notification processing | | Yes | | `NTFPRCS` | [notification_processing](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/notification_processing/) | ⚙ | Notification processing | | Yes |
| `NTFY` | [_publisher_ntfy](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/_publisher_ntfy/) | ▶️ | NTFY notifications | | | | `NTFY` | [_publisher_ntfy](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/_publisher_ntfy/) | ▶️ | NTFY notifications | | |
| `OMDSDN` | [omada_sdn_imp](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/omada_sdn_imp/) | 📥/🆎 ❌ | UNMAINTAINED use `OMDSDNOPENAPI` | 🖧 🔄 | | | `OMDSDN` | [omada_sdn_imp](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/omada_sdn_imp/) | 📥/🆎 ❌ | UNMAINTAINED use `OMDSDNOPENAPI` | 🖧 🔄 | |
| `OMDSDNOPENAPI` | [omada_sdn_openapi](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/omada_sdn_openapi/) | 📥/🆎 | OMADA TP-Link import via OpenAPI | 🖧 | | | `OMDSDNOPENAPI` | [omada_sdn_openapi](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/omada_sdn_openapi/) | 📥/🆎 | OMADA TP-Link import via OpenAPI | 🖧 | |
| `PIHOLE` | [pihole_scan](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/pihole_scan/) | 🔍/🆎/📥 | Pi-hole device import & sync | | | | `PIHOLE` | [pihole_scan](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/pihole_scan/) | 🔍/🆎/📥 | Pi-hole device import & sync | | |
| `PIHOLEAPI` | [pihole_api_scan](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/pihole_api_scan/) | 🔍/🆎/📥 | Pi-hole device import & sync via API v6+ | | | | `PIHOLEAPI` | [pihole_api_scan](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/pihole_api_scan/) | 🔍/🆎/📥 | Pi-hole device import & sync via API v6+ | | |
| `PUSHSAFER` | [_publisher_pushsafer](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/_publisher_pushsafer/) | ▶️ | Pushsafer notifications | | | | `PUSHSAFER` | [_publisher_pushsafer](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/_publisher_pushsafer/) | ▶️ | Pushsafer notifications | | |
| `PUSHOVER` | [_publisher_pushover](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/_publisher_pushover/) | ▶️ | Pushover notifications | | | | `PUSHOVER` | [_publisher_pushover](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/_publisher_pushover/) | ▶️ | Pushover notifications | | |
| `SETPWD` | [set_password](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/set_password/) | ⚙ | Set password | | Yes | | `SETPWD` | [set_password](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/set_password/) | ⚙ | Set password | | Yes |
| `SMTP` | [_publisher_email](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/_publisher_email/) | ▶️ | Email notifications | | | | `SMTP` | [_publisher_email](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/_publisher_email/) | ▶️ | Email notifications | | |
| `SNMPDSC` | [snmp_discovery](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/snmp_discovery/) | 🔍/📥 | SNMP device import & sync | | | | `SNMPDSC` | [snmp_discovery](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/snmp_discovery/) | 🔍/📥 | SNMP device import & sync | | |
| `SYNC` | [sync](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/sync/) | 🔍/⚙/📥 | Sync & import from NetAlertX instances | 🖧 🔄 | Yes | | `SYNC` | [sync](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/sync/) | 🔍/⚙/📥 | Sync & import from NetAlertX instances | 🖧 🔄 | Yes |
| `TELEGRAM` | [_publisher_telegram](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/_publisher_telegram/) | ▶️ | Telegram notifications | | | | `TELEGRAM` | [_publisher_telegram](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/_publisher_telegram/) | ▶️ | Telegram notifications | | |
| `UI` | [ui_settings](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/ui_settings/) | ♻ | UI specific settings | | Yes | | `UI` | [ui_settings](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/ui_settings/) | ♻ | UI specific settings | | Yes |
| `UNFIMP` | [unifi_import](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/unifi_import/) | 🔍/📥/🆎 | UniFi device import & sync | 🖧 | | | `UNFIMP` | [unifi_import](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/unifi_import/) | 🔍/📥/🆎 | UniFi device import & sync | 🖧 | |
| `UNIFIAPI` | [unifi_api_import](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/unifi_api_import/) | 🔍/📥/🆎 | UniFi device import (SM API, multi-site) | | | | `UNIFIAPI` | [unifi_api_import](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/unifi_api_import/) | 🔍/📥/🆎 | UniFi device import (SM API, multi-site) | | |
| `VNDRPDT` | [vendor_update](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/vendor_update/) | ⚙ | Vendor database update | | | | `VNDRPDT` | [vendor_update](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/vendor_update/) | ⚙ | Vendor database update | | |
| `WEBHOOK` | [_publisher_webhook](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/_publisher_webhook/) | ▶️ | Webhook notifications | | | | `WEBHOOK` | [_publisher_webhook](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/_publisher_webhook/) | ▶️ | Webhook notifications | | |
| `WEBMON` | [website_monitor](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/website_monitor/) | ♻ | Website down monitoring | | | | `WEBMON` | [website_monitor](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/website_monitor/) | ♻ | Website down monitoring | | |
| `WOL` | [wake_on_lan](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/wake_on_lan/) | ♻ | Automatic wake-on-lan | | | | `WOL` | [wake_on_lan](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/wake_on_lan/) | ♻ | Automatic wake-on-lan | | |
> \* The database cleanup plugin (`DBCLNP`) is not _required_ but the app will become unusable after a while if not executed. > \* The database cleanup plugin (`DBCLNP`) is not _required_ but the app will become unusable after a while if not executed.

View File

@@ -34,7 +34,7 @@ NetAlertX comes with a plugin system to feed events from third-party scripts int
### 🐛 Troubleshooting ### 🐛 Troubleshooting
- **[Debugging Plugins](DEBUG_PLUGINS.md)** - Troubleshoot plugin issues - **[Debugging Plugins](DEBUG_PLUGINS.md)** - Troubleshoot plugin issues
- **[Plugin Examples](../front/plugins)** - Study existing plugins as reference implementations - **[Plugin Examples](https://github.com/netalertx/NetAlertX/tree/main/front/plugins)** - Study existing plugins as reference implementations
### 🎥 Video Tutorial ### 🎥 Video Tutorial
@@ -179,13 +179,13 @@ Quick reference:
| Column | Name | Required | Example | | Column | Name | Required | Example |
|--------|------|----------|---------| |--------|------|----------|---------|
| 0 | Object_PrimaryID | **YES** | `"device_name"` or `"192.168.1.1"` | | 0 | objectPrimaryId | **YES** | `"device_name"` or `"192.168.1.1"` |
| 1 | Object_SecondaryID | no | `"secondary_id"` or `null` | | 1 | objectSecondaryId | no | `"secondary_id"` or `null` |
| 2 | DateTime | **YES** | `"2023-01-02 15:56:30"` | | 2 | DateTime | **YES** | `"2023-01-02 15:56:30"` |
| 3 | Watched_Value1 | **YES** | `"online"` or `"200"` | | 3 | watchedValue1 | **YES** | `"online"` or `"200"` |
| 4 | Watched_Value2 | no | `"ip_address"` or `null` | | 4 | watchedValue2 | no | `"ip_address"` or `null` |
| 5 | Watched_Value3 | no | `null` | | 5 | watchedValue3 | no | `null` |
| 6 | Watched_Value4 | no | `null` | | 6 | watchedValue4 | no | `null` |
| 7 | Extra | no | `"additional data"` or `null` | | 7 | Extra | no | `"additional data"` or `null` |
| 8 | ForeignKey | no | `"aa:bb:cc:dd:ee:ff"` or `null` | | 8 | ForeignKey | no | `"aa:bb:cc:dd:ee:ff"` or `null` |
@@ -243,7 +243,7 @@ Control which rows display in the UI:
{ {
"data_filters": [ "data_filters": [
{ {
"compare_column": "Object_PrimaryID", "compare_column": "objectPrimaryId",
"compare_operator": "==", "compare_operator": "==",
"compare_field_id": "txtMacFilter", "compare_field_id": "txtMacFilter",
"compare_js_template": "'{value}'.toString()", "compare_js_template": "'{value}'.toString()",
@@ -267,7 +267,7 @@ To import plugin data into NetAlertX tables for device discovery or notification
"mapped_to_table": "CurrentScan", "mapped_to_table": "CurrentScan",
"database_column_definitions": [ "database_column_definitions": [
{ {
"column": "Object_PrimaryID", "column": "objectPrimaryId",
"mapped_to_column": "scanMac", "mapped_to_column": "scanMac",
"show": true, "show": true,
"type": "device_mac", "type": "device_mac",
@@ -345,7 +345,7 @@ See [PLUGINS_DEV_SETTINGS.md](PLUGINS_DEV_SETTINGS.md) for complete settings doc
### Plugin Output Format ### Plugin Output Format
``` ```
Object_PrimaryID|Object_SecondaryID|DateTime|Watched_Value1|Watched_Value2|Watched_Value3|Watched_Value4|Extra|ForeignKey objectPrimaryId|objectSecondaryId|DateTime|watchedValue1|watchedValue2|watchedValue3|watchedValue4|Extra|ForeignKey
``` ```
9 required columns, 4 optional helpers = 13 max 9 required columns, 4 optional helpers = 13 max

View File

@@ -77,7 +77,7 @@ It also describes plugin output expectations and the main plugin categories.
* `database_column_definitions` * `database_column_definitions`
* `mapped_to_table` * `mapped_to_table`
**Example:** `Object_PrimaryID → devMAC` **Example:** `objectPrimaryId → devMAC`
--- ---
@@ -88,9 +88,9 @@ Output values are pipe-delimited in a fixed order.
#### Identifiers #### Identifiers
* `Object_PrimaryID` and `Object_SecondaryID` uniquely identify records (for example, `MAC|IP`). * `objectPrimaryId` and `objectSecondaryId` uniquely identify records (for example, `MAC|IP`).
#### Watched Values (`Watched_Value14`) #### Watched Values (`watchedValue14`)
* Used by the core to detect changes between runs. * Used by the core to detect changes between runs.
* Changes in these fields can trigger notifications. * Changes in these fields can trigger notifications.
@@ -114,7 +114,7 @@ Output values are pipe-delimited in a fixed order.
### 7. Persistence ### 7. Persistence
* Parsed data is **upserted** into the database. * Parsed data is **upserted** into the database.
* Conflicts are resolved using the combined key: `Object_PrimaryID + Object_SecondaryID`. * Conflicts are resolved using the combined key: `objectPrimaryId + objectSecondaryId`.
--- ---

View File

@@ -107,7 +107,7 @@ Query the NetAlertX SQLite database and display results.
{ {
"function": "CMD", "function": "CMD",
"type": {"dataType": "string", "elements": [{"elementType": "input", "elementOptions": [], "transformers": []}]}, "type": {"dataType": "string", "elements": [{"elementType": "input", "elementOptions": [], "transformers": []}]},
"default_value": "SELECT dv.devName as Object_PrimaryID, cast(dv.devLastIP 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, dv.devMac as ForeignKey FROM (SELECT * FROM Nmap_Scan) ns LEFT JOIN (SELECT devName, devMac, devLastIP FROM Devices) dv ON ns.MAC = dv.devMac", "default_value": "SELECT dv.devName as objectPrimaryId, cast(dv.devLastIP as VARCHAR(100)) || ':' || cast(SUBSTR(ns.Port, 0, INSTR(ns.Port, '/')) as VARCHAR(100)) as objectSecondaryId, datetime() as DateTime, ns.Service as watchedValue1, ns.State as watchedValue2, null as watchedValue3, null as watchedValue4, ns.Extra as Extra, dv.devMac as ForeignKey FROM (SELECT * FROM Nmap_Scan) ns LEFT JOIN (SELECT devName, devMac, devLastIP FROM Devices) dv ON ns.MAC = dv.devMac",
"localized": ["name"], "localized": ["name"],
"name": [{"language_code": "en_us", "string": "SQL to run"}], "name": [{"language_code": "en_us", "string": "SQL to run"}],
"description": [{"language_code": "en_us", "string": "This SQL query populates the plugin table"}] "description": [{"language_code": "en_us", "string": "This SQL query populates the plugin table"}]
@@ -118,13 +118,13 @@ Query the NetAlertX SQLite database and display results.
```sql ```sql
SELECT SELECT
e.EventValue as Object_PrimaryID, e.EventValue as objectPrimaryId,
d.devName as Object_SecondaryID, d.devName as objectSecondaryId,
e.EventDateTime as DateTime, e.EventDateTime as DateTime,
e.EventType as Watched_Value1, e.EventType as watchedValue1,
d.devLastIP as Watched_Value2, d.devLastIP as watchedValue2,
null as Watched_Value3, null as watchedValue3,
null as Watched_Value4, null as watchedValue4,
e.EventDetails as Extra, e.EventDetails as Extra,
d.devMac as ForeignKey d.devMac as ForeignKey
FROM FROM
@@ -181,7 +181,7 @@ Then set data source and query:
```json ```json
{ {
"function": "CMD", "function": "CMD",
"default_value": "SELECT hwaddr as Object_PrimaryID, cast('http://' || (SELECT ip FROM EXTERNAL_PIHOLE.network_addresses WHERE network_id = id ORDER BY lastseen DESC LIMIT 1) as VARCHAR(100)) || ':' || cast(SUBSTR((SELECT name FROM EXTERNAL_PIHOLE.network_addresses WHERE network_id = id ORDER BY lastseen DESC LIMIT 1), 0, INSTR((SELECT name FROM EXTERNAL_PIHOLE.network_addresses WHERE network_id = id ORDER BY lastseen DESC 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 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'", "default_value": "SELECT hwaddr as objectPrimaryId, cast('http://' || (SELECT ip FROM EXTERNAL_PIHOLE.network_addresses WHERE network_id = id ORDER BY lastseen DESC LIMIT 1) as VARCHAR(100)) || ':' || cast(SUBSTR((SELECT name FROM EXTERNAL_PIHOLE.network_addresses WHERE network_id = id ORDER BY lastseen DESC LIMIT 1), 0, INSTR((SELECT name FROM EXTERNAL_PIHOLE.network_addresses WHERE network_id = id ORDER BY lastseen DESC LIMIT 1), '/')) as VARCHAR(100)) as objectSecondaryId, datetime() as DateTime, macVendor as watchedValue1, lastQuery as watchedValue2, (SELECT name FROM EXTERNAL_PIHOLE.network_addresses WHERE network_id = id ORDER BY lastseen DESC LIMIT 1) as watchedValue3, null as watchedValue4, '' as Extra, hwaddr as ForeignKey FROM EXTERNAL_PIHOLE.network WHERE hwaddr NOT LIKE 'ip-%' AND hwaddr <> '00:00:00:00:00:00'",
"localized": ["name"], "localized": ["name"],
"name": [{"language_code": "en_us", "string": "SQL to run"}] "name": [{"language_code": "en_us", "string": "SQL to run"}]
} }

View File

@@ -18,19 +18,19 @@ Plugins communicate with NetAlertX by writing results to a **pipe-delimited log
## Column Specification ## Column Specification
> [!NOTE] > [!NOTE]
> The order of columns is **FIXED** and cannot be changed. All 9 mandatory columns must be provided. If you use any optional column (`HelpVal1`), you must supply all optional columns (`HelpVal1` through `HelpVal4`). > The order of columns is **FIXED** and cannot be changed. All 9 mandatory columns must be provided. If you use any optional column (`helpVal1`), you must supply all optional columns (`helpVal1` through `helpVal4`).
### Mandatory Columns (08) ### Mandatory Columns (08)
| Order | Column Name | Type | Required | Description | | Order | Column Name | Type | Required | Description |
|-------|-------------|------|----------|-------------| |-------|-------------|------|----------|-------------|
| 0 | `Object_PrimaryID` | string | **YES** | The primary identifier for grouping. Examples: device MAC, hostname, service name, or any unique ID | | 0 | `objectPrimaryId` | string | **YES** | The primary identifier for grouping. Examples: device MAC, hostname, service name, or any unique ID |
| 1 | `Object_SecondaryID` | string | no | Secondary identifier for relationships (e.g., IP address, port, sub-ID). Use `null` if not needed | | 1 | `objectSecondaryId` | string | no | Secondary identifier for relationships (e.g., IP address, port, sub-ID). Use `null` if not needed |
| 2 | `DateTime` | string | **YES** | Timestamp when the event/data was collected. Format: `YYYY-MM-DD HH:MM:SS` | | 2 | `DateTime` | string | **YES** | Timestamp when the event/data was collected. Format: `YYYY-MM-DD HH:MM:SS` |
| 3 | `Watched_Value1` | string | **YES** | Primary watched value. Changes trigger notifications. Examples: IP address, status, version | | 3 | `watchedValue1` | string | **YES** | Primary watched value. Changes trigger notifications. Examples: IP address, status, version |
| 4 | `Watched_Value2` | string | no | Secondary watched value. Use `null` if not needed | | 4 | `watchedValue2` | string | no | Secondary watched value. Use `null` if not needed |
| 5 | `Watched_Value3` | string | no | Tertiary watched value. Use `null` if not needed | | 5 | `watchedValue3` | string | no | Tertiary watched value. Use `null` if not needed |
| 6 | `Watched_Value4` | string | no | Quaternary watched value. Use `null` if not needed | | 6 | `watchedValue4` | string | no | Quaternary watched value. Use `null` if not needed |
| 7 | `Extra` | string | no | Any additional metadata to display in UI and notifications. Use `null` if not needed | | 7 | `Extra` | string | no | Any additional metadata to display in UI and notifications. Use `null` if not needed |
| 8 | `ForeignKey` | string | no | Foreign key linking to parent object (usually MAC address for device relationship). Use `null` if not needed | | 8 | `ForeignKey` | string | no | Foreign key linking to parent object (usually MAC address for device relationship). Use `null` if not needed |
@@ -38,10 +38,10 @@ Plugins communicate with NetAlertX by writing results to a **pipe-delimited log
| Order | Column Name | Type | Required | Description | | Order | Column Name | Type | Required | Description |
|-------|-------------|------|----------|-------------| |-------|-------------|------|----------|-------------|
| 9 | `HelpVal1` | string | *conditional* | Helper value 1. If used, all help values must be supplied | | 9 | `helpVal1` | string | *conditional* | Helper value 1. If used, all help values must be supplied |
| 10 | `HelpVal2` | string | *conditional* | Helper value 2. If used, all help values must be supplied | | 10 | `helpVal2` | string | *conditional* | Helper value 2. If used, all help values must be supplied |
| 11 | `HelpVal3` | string | *conditional* | Helper value 3. If used, all help values must be supplied | | 11 | `helpVal3` | string | *conditional* | Helper value 3. If used, all help values must be supplied |
| 12 | `HelpVal4` | string | *conditional* | Helper value 4. If used, all help values must be supplied | | 12 | `helpVal4` | string | *conditional* | Helper value 4. If used, all help values must be supplied |
## Usage Guide ## Usage Guide
@@ -58,15 +58,15 @@ Watched values are fields that the NetAlertX core monitors for **changes between
**How to use them:** **How to use them:**
- `Watched_Value1`: Always required; primary indicator of status/state - `watchedValue1`: Always required; primary indicator of status/state
- `Watched_Value24`: Optional; use for secondary/tertiary state information - `watchedValue24`: Optional; use for secondary/tertiary state information
- Leave unused ones as `null` - Leave unused ones as `null`
**Example:** **Example:**
- Device scanner: `Watched_Value1 = "online"` or `"offline"` - Device scanner: `watchedValue1 = "online"` or `"offline"`
- Port scanner: `Watched_Value1 = "80"` (port number), `Watched_Value2 = "open"` (state) - Port scanner: `watchedValue1 = "80"` (port number), `watchedValue2 = "open"` (state)
- Service monitor: `Watched_Value1 = "200"` (HTTP status), `Watched_Value2 = "0.45"` (response time) - Service monitor: `watchedValue1 = "200"` (HTTP status), `watchedValue2 = "0.45"` (response time)
### Foreign Key ### Foreign Key
@@ -110,14 +110,14 @@ https://google.com|null|2023-01-02 15:56:30|200|0.7898||null|null
Missing pipe Missing pipe
``` ```
**Missing mandatory Watched_Value1** (column 3): **Missing mandatory watchedValue1** (column 3):
```csv ```csv
https://duckduckgo.com|192.168.1.1|2023-01-02 15:56:30|null|0.9898|null|null|Best|null https://duckduckgo.com|192.168.1.1|2023-01-02 15:56:30|null|0.9898|null|null|Best|null
Must not be null Must not be null
``` ```
**Incomplete optional columns** (has HelpVal1 but missing HelpVal24): **Incomplete optional columns** (has helpVal1 but missing helpVal24):
```csv ```csv
device|null|2023-01-02 15:56:30|status|null|null|null|null|null|helper1 device|null|2023-01-02 15:56:30|status|null|null|null|null|null|helper1
@@ -146,19 +146,19 @@ plugin_objects = Plugin_Objects("YOURPREFIX")
# Add objects # Add objects
plugin_objects.add_object( plugin_objects.add_object(
Object_PrimaryID="device_id", objectPrimaryId="device_id",
Object_SecondaryID="192.168.1.1", objectSecondaryId="192.168.1.1",
DateTime="2023-01-02 15:56:30", DateTime="2023-01-02 15:56:30",
Watched_Value1="online", watchedValue1="online",
Watched_Value2=None, watchedValue2=None,
Watched_Value3=None, watchedValue3=None,
Watched_Value4=None, watchedValue4=None,
Extra="Additional data", Extra="Additional data",
ForeignKey="aa:bb:cc:dd:ee:ff", ForeignKey="aa:bb:cc:dd:ee:ff",
HelpVal1=None, helpVal1=None,
HelpVal2=None, helpVal2=None,
HelpVal3=None, helpVal3=None,
HelpVal4=None helpVal4=None
) )
# Write results (handles formatting, sanitization, and file creation) # Write results (handles formatting, sanitization, and file creation)
@@ -177,7 +177,7 @@ The library automatically:
The core runs **de-duplication once per hour** on the `Plugins_Objects` table: The core runs **de-duplication once per hour** on the `Plugins_Objects` table:
- **Duplicate Detection Key:** Combination of `Object_PrimaryID`, `Object_SecondaryID`, `Plugin` (auto-filled from `unique_prefix`), and `UserData` - **Duplicate Detection Key:** Combination of `objectPrimaryId`, `objectSecondaryId`, `Plugin` (auto-filled from `unique_prefix`), and `UserData`
- **Resolution:** Oldest duplicate entries are removed, newest are kept - **Resolution:** Oldest duplicate entries are removed, newest are kept
- **Use Case:** Prevents duplicate notifications when the same object is detected multiple times - **Use Case:** Prevents duplicate notifications when the same object is detected multiple times
@@ -213,9 +213,9 @@ Before writing your plugin's `script.py`, ensure:
- [ ] **9 or 13 columns** in each output line (8 or 12 pipe separators) - [ ] **9 or 13 columns** in each output line (8 or 12 pipe separators)
- [ ] **Mandatory columns filled:** - [ ] **Mandatory columns filled:**
- Column 0: `Object_PrimaryID` (not null) - Column 0: `objectPrimaryId` (not null)
- Column 2: `DateTime` in `YYYY-MM-DD HH:MM:SS` format - Column 2: `DateTime` in `YYYY-MM-DD HH:MM:SS` format
- Column 3: `Watched_Value1` (not null) - Column 3: `watchedValue1` (not null)
- [ ] **Null values as literal string** `null` (not empty string or special chars) - [ ] **Null values as literal string** `null` (not empty string or special chars)
- [ ] **No extra pipes or misaligned columns** - [ ] **No extra pipes or misaligned columns**
- [ ] **If using optional helpers** (columns 912), all 4 must be present - [ ] **If using optional helpers** (columns 912), all 4 must be present

View File

@@ -68,13 +68,13 @@ try:
# Add an object to results # Add an object to results
plugin_objects.add_object( plugin_objects.add_object(
Object_PrimaryID="example_id", objectPrimaryId="example_id",
Object_SecondaryID=None, objectSecondaryId=None,
DateTime="2023-01-02 15:56:30", DateTime="2023-01-02 15:56:30",
Watched_Value1="value1", watchedValue1="value1",
Watched_Value2=None, watchedValue2=None,
Watched_Value3=None, watchedValue3=None,
Watched_Value4=None, watchedValue4=None,
Extra="additional_data", Extra="additional_data",
ForeignKey=None ForeignKey=None
) )

View File

@@ -16,7 +16,7 @@ Each column definition specifies:
```json ```json
{ {
"column": "Object_PrimaryID", "column": "objectPrimaryId",
"mapped_to_column": "devMac", "mapped_to_column": "devMac",
"mapped_to_column_data": null, "mapped_to_column_data": null,
"css_classes": "col-sm-2", "css_classes": "col-sm-2",
@@ -39,7 +39,7 @@ Each column definition specifies:
| Property | Type | Required | Description | | Property | Type | Required | Description |
|----------|------|----------|-------------| |----------|------|----------|-------------|
| `column` | string | **YES** | Source column name from data contract (e.g., `Object_PrimaryID`, `Watched_Value1`) | | `column` | string | **YES** | Source column name from data contract (e.g., `objectPrimaryId`, `watchedValue1`) |
| `mapped_to_column` | string | no | Target database column if mapping to a table like `CurrentScan` | | `mapped_to_column` | string | no | Target database column if mapping to a table like `CurrentScan` |
| `mapped_to_column_data` | object | no | Static value to map instead of using column data | | `mapped_to_column_data` | object | no | Static value to map instead of using column data |
| `css_classes` | string | no | Bootstrap CSS classes for width/spacing (e.g., `"col-sm-2"`, `"col-sm-6"`) | | `css_classes` | string | no | Bootstrap CSS classes for width/spacing (e.g., `"col-sm-2"`, `"col-sm-6"`) |
@@ -64,7 +64,7 @@ Plain text display (read-only).
```json ```json
{ {
"column": "Watched_Value1", "column": "watchedValue1",
"show": true, "show": true,
"type": "label", "type": "label",
"localized": ["name"], "localized": ["name"],
@@ -99,7 +99,7 @@ Resolves an IP address to a MAC address and creates a device link.
```json ```json
{ {
"column": "Object_SecondaryID", "column": "objectSecondaryId",
"show": true, "show": true,
"type": "device_ip", "type": "device_ip",
"localized": ["name"], "localized": ["name"],
@@ -117,7 +117,7 @@ Creates a device link with the target device's name as the link label.
```json ```json
{ {
"column": "Object_PrimaryID", "column": "objectPrimaryId",
"show": true, "show": true,
"type": "device_name_mac", "type": "device_name_mac",
"localized": ["name"], "localized": ["name"],
@@ -135,7 +135,7 @@ Renders as a clickable HTTP/HTTPS link.
```json ```json
{ {
"column": "Watched_Value1", "column": "watchedValue1",
"show": true, "show": true,
"type": "url", "type": "url",
"localized": ["name"], "localized": ["name"],
@@ -153,7 +153,7 @@ Creates two links (HTTP and HTTPS) as lock icons for the given IP/hostname.
```json ```json
{ {
"column": "Object_SecondaryID", "column": "objectSecondaryId",
"show": true, "show": true,
"type": "url_http_https", "type": "url_http_https",
"localized": ["name"], "localized": ["name"],
@@ -207,7 +207,7 @@ Color-codes values based on ranges. Useful for status codes, latency, capacity p
```json ```json
{ {
"column": "Watched_Value1", "column": "watchedValue1",
"show": true, "show": true,
"type": "threshold", "type": "threshold",
"options": [ "options": [
@@ -252,7 +252,7 @@ Replaces specific values with display strings or HTML.
```json ```json
{ {
"column": "Watched_Value2", "column": "watchedValue2",
"show": true, "show": true,
"type": "replace", "type": "replace",
"options": [ "options": [
@@ -286,7 +286,7 @@ Applies a regular expression to extract/transform values.
```json ```json
{ {
"column": "Watched_Value1", "column": "watchedValue1",
"show": true, "show": true,
"type": "regex", "type": "regex",
"options": [ "options": [
@@ -310,7 +310,7 @@ Evaluates JavaScript code with access to the column value (use `${value}` or `{v
```json ```json
{ {
"column": "Watched_Value1", "column": "watchedValue1",
"show": true, "show": true,
"type": "eval", "type": "eval",
"default_value": "", "default_value": "",
@@ -322,7 +322,7 @@ Evaluates JavaScript code with access to the column value (use `${value}` or `{v
**Example with custom formatting:** **Example with custom formatting:**
```json ```json
{ {
"column": "Watched_Value1", "column": "watchedValue1",
"show": true, "show": true,
"type": "eval", "type": "eval",
"options": [ "options": [
@@ -347,7 +347,7 @@ You can chain multiple transformations with dot notation:
```json ```json
{ {
"column": "Watched_Value3", "column": "watchedValue3",
"show": true, "show": true,
"type": "regex.url_http_https", "type": "regex.url_http_https",
"options": [ "options": [
@@ -376,7 +376,7 @@ Use SQL query results to populate dropdown options:
```json ```json
{ {
"column": "Watched_Value2", "column": "watchedValue2",
"show": true, "show": true,
"type": "select", "type": "select",
"options": ["{value}"], "options": ["{value}"],
@@ -405,7 +405,7 @@ Use plugin settings to populate options:
```json ```json
{ {
"column": "Watched_Value1", "column": "watchedValue1",
"show": true, "show": true,
"type": "select", "type": "select",
"options": ["{value}"], "options": ["{value}"],
@@ -439,7 +439,7 @@ To import plugin data into the device scan pipeline (for notifications, heuristi
"mapped_to_table": "CurrentScan", "mapped_to_table": "CurrentScan",
"database_column_definitions": [ "database_column_definitions": [
{ {
"column": "Object_PrimaryID", "column": "objectPrimaryId",
"mapped_to_column": "scanMac", "mapped_to_column": "scanMac",
"show": true, "show": true,
"type": "device_mac", "type": "device_mac",
@@ -447,7 +447,7 @@ To import plugin data into the device scan pipeline (for notifications, heuristi
"name": [{"language_code": "en_us", "string": "MAC Address"}] "name": [{"language_code": "en_us", "string": "MAC Address"}]
}, },
{ {
"column": "Object_SecondaryID", "column": "objectSecondaryId",
"mapped_to_column": "scanLastIP", "mapped_to_column": "scanLastIP",
"show": true, "show": true,
"type": "device_ip", "type": "device_ip",
@@ -501,7 +501,7 @@ Control which rows are displayed based on filter conditions. Filters are applied
{ {
"data_filters": [ "data_filters": [
{ {
"compare_column": "Object_PrimaryID", "compare_column": "objectPrimaryId",
"compare_operator": "==", "compare_operator": "==",
"compare_field_id": "txtMacFilter", "compare_field_id": "txtMacFilter",
"compare_js_template": "'{value}'.toString()", "compare_js_template": "'{value}'.toString()",
@@ -545,7 +545,7 @@ When viewing a device detail page, the `txtMacFilter` field is populated with th
{ {
"database_column_definitions": [ "database_column_definitions": [
{ {
"column": "Object_PrimaryID", "column": "objectPrimaryId",
"mapped_to_column": "scanMac", "mapped_to_column": "scanMac",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",
"show": true, "show": true,
@@ -555,7 +555,7 @@ When viewing a device detail page, the `txtMacFilter` field is populated with th
"name": [{"language_code": "en_us", "string": "MAC Address"}] "name": [{"language_code": "en_us", "string": "MAC Address"}]
}, },
{ {
"column": "Object_SecondaryID", "column": "objectSecondaryId",
"mapped_to_column": "scanLastIP", "mapped_to_column": "scanLastIP",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",
"show": true, "show": true,
@@ -574,7 +574,7 @@ When viewing a device detail page, the `txtMacFilter` field is populated with th
"name": [{"language_code": "en_us", "string": "Last Seen"}] "name": [{"language_code": "en_us", "string": "Last Seen"}]
}, },
{ {
"column": "Watched_Value1", "column": "watchedValue1",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",
"show": true, "show": true,
"type": "threshold", "type": "threshold",
@@ -589,7 +589,7 @@ When viewing a device detail page, the `txtMacFilter` field is populated with th
"name": [{"language_code": "en_us", "string": "HTTP Status"}] "name": [{"language_code": "en_us", "string": "HTTP Status"}]
}, },
{ {
"column": "Watched_Value2", "column": "watchedValue2",
"css_classes": "col-sm-1", "css_classes": "col-sm-1",
"show": true, "show": true,
"type": "label", "type": "label",

View File

@@ -63,7 +63,7 @@ There is also an in-app Help / FAQ section that should be answering frequently a
#### ♻ Misc #### ♻ Misc
- [Reverse proxy (Nginx, Apache, SWAG)](./REVERSE_PROXY.md) - [Reverse Proxy](./REVERSE_PROXY.md)
- [Installing Updates](./UPDATES.md) - [Installing Updates](./UPDATES.md)
- [Setting up Authelia](./AUTHELIA.md) (DRAFT) - [Setting up Authelia](./AUTHELIA.md) (DRAFT)
@@ -137,7 +137,7 @@ Some additional context:
Before submitting a new issue please spend a couple of minutes on research: Before submitting a new issue please spend a couple of minutes on research:
* Check [🛑 Common issues](./DEBUG_TIPS.md#common-issues) * Check [🛑 Common issues](./DEBUG_TIPS.md#common-issues)
* Check [💡 Closed issues](https://github.com/jokob-sk/NetAlertX/issues?q=is%3Aissue+is%3Aclosed) if a similar issue was solved in the past. * Check [💡 Closed issues](https://github.com/netalertx/NetAlertX/issues?q=is%3Aissue+is%3Aclosed) if a similar issue was solved in the past.
* When submitting an issue ❗[enable debug](./DEBUG_TIPS.md)❗ * When submitting an issue ❗[enable debug](./DEBUG_TIPS.md)❗
⚠ Please follow the pre-defined issue template to resolve your issue faster. ⚠ Please follow the pre-defined issue template to resolve your issue faster.

View File

@@ -43,18 +43,18 @@ You can use supplementary plugins that employ alternate methods. Protocols used
## Multiple NetAlertX Instances ## Multiple NetAlertX Instances
If you have servers in different networks, you can set up separate NetAlertX instances on those subnets and synchronize the results into one instance using the [`SYNC` plugin](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/sync). If you have servers in different networks, you can set up separate NetAlertX instances on those subnets and synchronize the results into one instance using the [`SYNC` plugin](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/sync).
## Manual Entry ## Manual Entry
If you don't need to discover new devices and only need to report on their status (`online`, `offline`, `down`), you can manually enter devices and check their status using the [`ICMP` plugin](https://github.com/jokob-sk/NetAlertX/blob/main/front/plugins/icmp_scan/), which uses the `ping` command internally. If you don't need to discover new devices and only need to report on their status (`online`, `offline`, `down`), you can manually enter devices and check their status using the [`ICMP` plugin](https://github.com/netalertx/NetAlertX/blob/main/front/plugins/icmp_scan/), which uses the `ping` command internally.
For more information on how to add devices manually (or dummy devices), refer to the [Device Management](./DEVICE_MANAGEMENT.md) documentation. For more information on how to add devices manually (or dummy devices), refer to the [Device Management](./DEVICE_MANAGEMENT.md) documentation.
To create truly dummy devices, you can use a loopback IP address (e.g., `0.0.0.0` or `127.0.0.1`) so they appear online. To create truly dummy devices, you can use a loopback IP address (e.g., `0.0.0.0` or `127.0.0.1`) or the `Force Status` field so they appear online.
## NMAP and Fake MAC Addresses ## NMAP and Fake MAC Addresses
Scanning remote networks with NMAP is possible (via the `NMAPDEV` plugin), but since it cannot retrieve the MAC address, you need to enable the `NMAPDEV_FAKE_MAC` setting. This will generate a fake MAC address based on the IP address, allowing you to track devices. However, this can lead to inconsistencies, especially if the IP address changes or a previously logged device is rediscovered. If this setting is disabled, only the IP address will be discovered, and devices with missing MAC addresses will be skipped. Scanning remote networks with NMAP is possible (via the `NMAPDEV` plugin), but since it cannot retrieve the MAC address, you need to enable the `NMAPDEV_FAKE_MAC` setting. This will generate a fake MAC address based on the IP address, allowing you to track devices. However, this can lead to inconsistencies, especially if the IP address changes or a previously logged device is rediscovered. If this setting is disabled, only the IP address will be discovered, and devices with missing MAC addresses will be skipped.
Check the [NMAPDEV plugin](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/nmap_dev_scan) for details Check the [NMAPDEV plugin](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/nmap_dev_scan) for details

View File

@@ -39,7 +39,7 @@ You can specify the DNS server in the docker-compose to improve name resolution
services: services:
netalertx: netalertx:
container_name: netalertx container_name: netalertx
image: "ghcr.io/jokob-sk/netalertx:latest" image: "ghcr.io/netalertx/netalertx:latest"
... ...
dns: # specifying the DNS servers used for the container dns: # specifying the DNS servers used for the container
- 10.8.0.1 - 10.8.0.1

577
docs/REVERSE_PROXY.md Executable file → Normal file
View File

@@ -1,526 +1,135 @@
# Reverse Proxy Configuration # Reverse Proxy Configuration
> [!NOTE] A reverse proxy is a server that sits between users and your NetAlertX instance. It allows you to:
> This is community-contributed. Due to environment, setup, or networking differences, results may vary. Please open a PR to improve it instead of creating an issue, as the maintainer is not actively maintaining it. - Access NetAlertX via a domain name (e.g., `https://netalertx.example.com`).
- Add HTTPS/SSL encryption.
- Enforce authentication (like SSO).
> [!NOTE] ```mermaid
> NetAlertX requires access to both the **web UI** (default `20211`) and the **GraphQL backend `GRAPHQL_PORT`** (default `20212`) ports. flowchart LR
> Ensure your reverse proxy allows traffic to both for proper functionality. Browser --HTTPS--> Proxy[Reverse Proxy] --HTTP--> Container[NetAlertX Container]
> [!IMPORTANT]
> You will need to specify 2 entries in your reverse proxy, one for the front end, one for the backend URL. The custom backend URL, including the `GRAPHQL_PORT`, needs to be aslo specified in the `BACKEND_API_URL` setting.This is the URL that points to the backend API server.
>
> ![BACKEND_API_URL setting](./img/REVERSE_PROXY/BACKEND_API_URL.png)
>
> ![NPM set up](./img/REVERSE_PROXY/nginx_proxy_manager_npm.png)
See also:
- [CADDY + AUTHENTIK](./REVERSE_PROXY_CADDY.md)
- [TRAEFIK](./REVERSE_PROXY_TRAEFIK.md)
## NGINX HTTP Configuration (Direct Path)
> Submitted by amazing [cvc90](https://github.com/cvc90) 🙏
> [!NOTE]
> There are various NGINX config files for NetAlertX, some for the bare-metal install, currently Debian 12 and Ubuntu 24 (`netalertx.conf`), and one for the docker container (`netalertx.template.conf`).
>
> The first one you can find in the respective bare metal installer folder `/app/install/\<system\>/netalertx.conf`.
> The docker one can be found in the [install](https://github.com/jokob-sk/NetAlertX/tree/main/install) folder. Map, or use, the one appropriate for your setup.
<br/>
1. On your NGINX server, create a new file called /etc/nginx/sites-available/netalertx
2. In this file, paste the following code:
```
server {
listen 80;
server_name netalertx;
proxy_preserve_host on;
proxy_pass http://localhost:20211/;
proxy_pass_reverse http://localhost:20211/;
}
``` ```
3. Activate the new website by running the following command: ## NetAlertX Ports
`nginx -s reload` or `systemctl restart nginx` NetAlertX exposes two ports that serve different purposes. Your reverse proxy can target one or both, depending on your needs.
4. Check your config with `nginx -t`. If there are any issues, it will tell you. | Port | Service | Purpose |
|------|---------|---------|
| **20211** | Nginx (Web UI) | The main interface. |
| **20212** | Backend API | Direct access to the API and GraphQL. Includes API docs you can view with a browser. |
5. Once NGINX restarts, you should be able to access the proxy website at http://netalertx/ > [!WARNING]
> **Do not document or use `/server` as an external API endpoint.** It is an internal route used by the Nginx frontend to communicate with the backend.
<br/> ## Connection Patterns
## NGINX HTTP Configuration (Sub Path) ### 1. Default (No Proxy)
For local testing or LAN access. The browser accesses the UI on port 20211. Code and API docs are accessible on 20212.
1. On your NGINX server, create a new file called /etc/nginx/sites-available/netalertx ```mermaid
flowchart LR
2. In this file, paste the following code: B[Browser]
subgraph NAC[NetAlertX Container]
``` N[Nginx listening on port 20211]
server { A[Service on port 20212]
listen 80; N -->|Proxy /server to localhost:20212| A
server_name netalertx; end
proxy_preserve_host on; B -->|port 20211| NAC
location ^~ /netalertx/ { B -->|port 20212| NAC
proxy_pass http://localhost:20211/;
proxy_pass_reverse http://localhost:20211/;
proxy_redirect ~^/(.*)$ /netalertx/$1;
rewrite ^/netalertx/?(.*)$ /$1 break;
}
}
``` ```
3. Check your config with `nginx -t`. If there are any issues, it will tell you. ### 2. Direct API Consumer (Not Recommended)
Connecting directly to the backend API port (20212).
4. Activate the new website by running the following command: > [!CAUTION]
> This exposes the API directly to the network without additional protection. Avoid this on untrusted networks.
`nginx -s reload` or `systemctl restart nginx` ```mermaid
flowchart LR
5. Once NGINX restarts, you should be able to access the proxy website at http://netalertx/netalertx/ B[Browser] -->|HTTPS| S[Any API Consumer app]
subgraph NAC[NetAlertX Container]
<br/> N[Nginx listening on port 20211]
N -->|Proxy /server to localhost:20212| A[Service on port 20212]
## NGINX HTTP Configuration (Sub Path) with module ngx_http_sub_module end
S -->|Port 20212| NAC
1. On your NGINX server, create a new file called /etc/nginx/sites-available/netalertx
2. In this file, paste the following code:
```
server {
listen 80;
server_name netalertx;
proxy_preserve_host on;
location ^~ /netalertx/ {
proxy_pass http://localhost:20211/;
proxy_pass_reverse http://localhost:20211/;
proxy_redirect ~^/(.*)$ /netalertx/$1;
rewrite ^/netalertx/?(.*)$ /$1 break;
sub_filter_once off;
sub_filter_types *;
sub_filter 'href="/' 'href="/netalertx/';
sub_filter '(?>$host)/css' '/netalertx/css';
sub_filter '(?>$host)/js' '/netalertx/js';
sub_filter '/img' '/netalertx/img';
sub_filter '/lib' '/netalertx/lib';
sub_filter '/php' '/netalertx/php';
}
}
``` ```
3. Check your config with `nginx -t`. If there are any issues, it will tell you. ### 3. Recommended: Reverse Proxy to Web UI
Using a reverse proxy (Nginx, Traefik, Caddy, etc.) to handle HTTPS and Auth in front of the main UI.
4. Activate the new website by running the following command: ```mermaid
flowchart LR
`nginx -s reload` or `systemctl restart nginx` B[Browser] -->|HTTPS| S[Any Auth/SSL proxy]
subgraph NAC[NetAlertX Container]
5. Once NGINX restarts, you should be able to access the proxy website at http://netalertx/netalertx/ N[Nginx listening on port 20211]
N -->|Proxy /server to localhost:20212| A[Service on port 20212]
<br/> end
S -->|port 20211| NAC
**NGINX HTTPS Configuration (Direct Path)**
1. On your NGINX server, create a new file called /etc/nginx/sites-available/netalertx
2. In this file, paste the following code:
```
server {
listen 443;
server_name netalertx;
SSLEngine On;
SSLCertificateFile /etc/ssl/certs/netalertx.pem;
SSLCertificateKeyFile /etc/ssl/private/netalertx.key;
proxy_preserve_host on;
proxy_pass http://localhost:20211/;
proxy_pass_reverse http://localhost:20211/;
}
``` ```
3. Check your config with `nginx -t`. If there are any issues, it will tell you. ### 4. Recommended: Proxied API Consumer
Using a proxy to secure API access with TLS or IP limiting.
4. Activate the new website by running the following command: **Why is this important?**
The backend API (`:20212`) is powerful—more so than the Web UI, which is a safer, password-protectable interface. By using a reverse proxy to **limit sources** (e.g., allowing only your Home Assistant server's IP), you ensure that only trusted devices can talk to your backend.
`nginx -s reload` or `systemctl restart nginx` ```mermaid
flowchart LR
5. Once NGINX restarts, you should be able to access the proxy website at https://netalertx/ B[Browser] -->|HTTPS| S[Any API Consumer app]
C[HTTPS/source-limiting Proxy]
<br/> subgraph NAC[NetAlertX Container]
N[Nginx listening on port 20211]
**NGINX HTTPS Configuration (Sub Path)** N -->|Proxy /server to localhost:20212| A[Service on port 20212]
end
1. On your NGINX server, create a new file called /etc/nginx/sites-available/netalertx S -->|HTTPS| C
C -->|Port 20212| NAC
2. In this file, paste the following code:
```
server {
listen 443;
server_name netalertx;
SSLEngine On;
SSLCertificateFile /etc/ssl/certs/netalertx.pem;
SSLCertificateKeyFile /etc/ssl/private/netalertx.key;
location ^~ /netalertx/ {
proxy_pass http://localhost:20211/;
proxy_pass_reverse http://localhost:20211/;
proxy_redirect ~^/(.*)$ /netalertx/$1;
rewrite ^/netalertx/?(.*)$ /$1 break;
}
}
``` ```
3. Check your config with `nginx -t`. If there are any issues, it will tell you. ## Getting Started: Nginx Proxy Manager
4. Activate the new website by running the following command: For beginners, we recommend **[Nginx Proxy Manager](https://nginxproxymanager.com/)**. It provides a user-friendly interface to manage proxy hosts and free SSL certificates via Let's Encrypt.
`nginx -s reload` or `systemctl restart nginx` 1. Install Nginx Proxy Manager alongside NetAlertX.
2. Create a **Proxy Host** pointing to your NetAlertX IP and Port `20211` for the Web UI.
3. (Optional) Create a second host for the API on Port `20212`.
5. Once NGINX restarts, you should be able to access the proxy website at https://netalertx/netalertx/ ![NPM Setup](./img/REVERSE_PROXY/nginx_proxy_manager_npm.png)
<br/> ### Configuration Settings
## NGINX HTTPS Configuration (Sub Path) with module ngx_http_sub_module When using a reverse proxy, you should verify two settings in **Settings > Core > General**:
1. On your NGINX server, create a new file called /etc/nginx/sites-available/netalertx 1. **BACKEND_API_URL**: This should be set to `/server`.
* *Reason:* The frontend should communicate with the backend via the internal Nginx proxy rather than routing out to the internet and back.
2. In this file, paste the following code: 2. **REPORT_DASHBOARD_URL**: Set this to your external proxy URL (e.g., `https://netalertx.example.com`).
* *Reason:* This URL is used to generate proper clickable links in emails and HTML reports.
``` ![Configuration Settings](./img/REVERSE_PROXY/BACKEND_API_URL.png)
server {
listen 443;
server_name netalertx;
SSLEngine On;
SSLCertificateFile /etc/ssl/certs/netalertx.pem;
SSLCertificateKeyFile /etc/ssl/private/netalertx.key;
location ^~ /netalertx/ {
proxy_pass http://localhost:20211/;
proxy_pass_reverse http://localhost:20211/;
proxy_redirect ~^/(.*)$ /netalertx/$1;
rewrite ^/netalertx/?(.*)$ /$1 break;
sub_filter_once off;
sub_filter_types *;
sub_filter 'href="/' 'href="/netalertx/';
sub_filter '(?>$host)/css' '/netalertx/css';
sub_filter '(?>$host)/js' '/netalertx/js';
sub_filter '/img' '/netalertx/img';
sub_filter '/lib' '/netalertx/lib';
sub_filter '/php' '/netalertx/php';
}
}
```
3. Check your config with `nginx -t`. If there are any issues, it will tell you. ## Other Reverse Proxies
4. Activate the new website by running the following command: NetAlertX uses standard HTTP. Any reverse proxy will work. Simply forward traffic to the appropriate port (`20211` or `20212`).
`nginx -s reload` or `systemctl restart nginx` For configuration details, consult the documentation for your preferred proxy:
5. Once NGINX restarts, you should be able to access the proxy website at https://netalertx/netalertx/ * **[NGINX](https://nginx.org/en/docs/http/ngx_http_proxy_module.html)**
* **[Apache (mod_proxy)](https://httpd.apache.org/docs/current/mod/mod_proxy.html)**
* **[Caddy](https://caddyserver.com/docs/caddyfile/directives/reverse_proxy)**
* **[Traefik](https://doc.traefik.io/traefik/routing/services/)**
<br/> ## Authentication
## Apache HTTP Configuration (Direct Path) If you wish to add Single Sign-On (SSO) or other authentication in front of NetAlertX, refer to the documentation for your identity provider:
1. On your Apache server, create a new file called /etc/apache2/sites-available/netalertx.conf. * **[Authentik](https://docs.goauthentik.io/)**
* **[Authelia](https://www.authelia.com/docs/)**
2. In this file, paste the following code: ## Further Reading
```
<VirtualHost *:80>
ServerName netalertx
ProxyPreserveHost On
ProxyPass / http://localhost:20211/
ProxyPassReverse / http://localhost:20211/
</VirtualHost>
```
3. Check your config with `httpd -t` (or `apache2ctl -t` on Debian/Ubuntu). If there are any issues, it will tell you.
4. Activate the new website by running the following command:
`a2ensite netalertx` or `service apache2 reload`
5. Once Apache restarts, you should be able to access the proxy website at http://netalertx/
<br/>
## Apache HTTP Configuration (Sub Path)
1. On your Apache server, create a new file called /etc/apache2/sites-available/netalertx.conf.
2. In this file, paste the following code:
```
<VirtualHost *:80>
ServerName netalertx
location ^~ /netalertx/ {
ProxyPreserveHost On
ProxyPass / http://localhost:20211/
ProxyPassReverse / http://localhost:20211/
}
</VirtualHost>
```
3. Check your config with `httpd -t` (or `apache2ctl -t` on Debian/Ubuntu). If there are any issues, it will tell you.
4. Activate the new website by running the following command:
`a2ensite netalertx` or `service apache2 reload`
5. Once Apache restarts, you should be able to access the proxy website at http://netalertx/
<br/>
## Apache HTTPS Configuration (Direct Path)
1. On your Apache server, create a new file called /etc/apache2/sites-available/netalertx.conf.
2. In this file, paste the following code:
```
<VirtualHost *:443>
ServerName netalertx
SSLEngine On
SSLCertificateFile /etc/ssl/certs/netalertx.pem
SSLCertificateKeyFile /etc/ssl/private/netalertx.key
ProxyPreserveHost On
ProxyPass / http://localhost:20211/
ProxyPassReverse / http://localhost:20211/
</VirtualHost>
```
3. Check your config with `httpd -t` (or `apache2ctl -t` on Debian/Ubuntu). If there are any issues, it will tell you.
4. Activate the new website by running the following command:
`a2ensite netalertx` or `service apache2 reload`
5. Once Apache restarts, you should be able to access the proxy website at https://netalertx/
<br/>
## Apache HTTPS Configuration (Sub Path)
1. On your Apache server, create a new file called /etc/apache2/sites-available/netalertx.conf.
2. In this file, paste the following code:
```
<VirtualHost *:443>
ServerName netalertx
SSLEngine On
SSLCertificateFile /etc/ssl/certs/netalertx.pem
SSLCertificateKeyFile /etc/ssl/private/netalertx.key
location ^~ /netalertx/ {
ProxyPreserveHost On
ProxyPass / http://localhost:20211/
ProxyPassReverse / http://localhost:20211/
}
</VirtualHost>
```
3. Check your config with `httpd -t` (or `apache2ctl -t` on Debian/Ubuntu). If there are any issues, it will tell you.
4. Activate the new website by running the following command:
`a2ensite netalertx` or `service apache2 reload`
5. Once Apache restarts, you should be able to access the proxy website at https://netalertx/netalertx/
<br/>
## Reverse proxy example by using LinuxServer's SWAG container.
> Submitted by [s33d1ing](https://github.com/s33d1ing). 🙏
## [linuxserver/swag](https://github.com/linuxserver/docker-swag)
In the SWAG container create `/config/nginx/proxy-confs/netalertx.subfolder.conf` with the following contents:
``` nginx
## Version 2023/02/05
# make sure that your netalertx container is named netalertx
# netalertx does not require a base url setting
# Since NetAlertX uses a Host network, you may need to use the IP address of the system running NetAlertX for $upstream_app.
location /netalertx {
return 301 $scheme://$host/netalertx/;
}
location ^~ /netalertx/ {
# enable the next two lines for http auth
#auth_basic "Restricted";
#auth_basic_user_file /config/nginx/.htpasswd;
# enable for ldap auth (requires ldap-server.conf in the server block)
#include /config/nginx/ldap-location.conf;
# enable for Authelia (requires authelia-server.conf in the server block)
#include /config/nginx/authelia-location.conf;
# enable for Authentik (requires authentik-server.conf in the server block)
#include /config/nginx/authentik-location.conf;
include /config/nginx/proxy.conf;
include /config/nginx/resolver.conf;
set $upstream_app netalertx;
set $upstream_port 20211;
set $upstream_proto http;
proxy_pass $upstream_proto://$upstream_app:$upstream_port;
proxy_set_header Accept-Encoding "";
proxy_redirect ~^/(.*)$ /netalertx/$1;
rewrite ^/netalertx/?(.*)$ /$1 break;
sub_filter_once off;
sub_filter_types *;
sub_filter 'href="/' 'href="/netalertx/';
sub_filter '(?>$host)/css' '/netalertx/css';
sub_filter '(?>$host)/js' '/netalertx/js';
sub_filter '/img' '/netalertx/img';
sub_filter '/lib' '/netalertx/lib';
sub_filter '/php' '/netalertx/php';
}
```
<br/>
## Traefik
> Submitted by [Isegrimm](https://github.com/Isegrimm) 🙏 (based on this [discussion](https://github.com/jokob-sk/NetAlertX/discussions/449#discussioncomment-7281442))
Assuming the user already has a working Traefik setup, this is what's needed to make NetAlertX work at a URL like www.domain.com/netalertx/.
Note: Everything in these configs assumes '**www.domain.com**' as your domainname and '**section31**' as an arbitrary name for your certificate setup. You will have to substitute these with your own.
Also, I use the prefix '**netalertx**'. If you want to use another prefix, change it in these files: dynamic.toml and default.
Content of my yaml-file (this is the generic Traefik config, which defines which ports to listen on, redirect http to https and sets up the certificate process).
It also contains Authelia, which I use for authentication.
This part contains nothing specific to NetAlertX.
```yaml
version: '3.8'
services:
traefik:
image: traefik
container_name: traefik
command:
- "--api=true"
- "--api.insecure=true"
- "--api.dashboard=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
- "--entrypoints.websecure.address=:443"
- "--providers.file.filename=/traefik-config/dynamic.toml"
- "--providers.file.watch=true"
- "--log.level=ERROR"
- "--certificatesresolvers.section31.acme.email=postmaster@domain.com"
- "--certificatesresolvers.section31.acme.storage=/traefik-config/acme.json"
- "--certificatesresolvers.section31.acme.httpchallenge=true"
- "--certificatesresolvers.section31.acme.httpchallenge.entrypoint=web"
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- /appl/docker/traefik/config:/traefik-config
depends_on:
- authelia
restart: unless-stopped
authelia:
container_name: authelia
image: authelia/authelia:latest
ports:
- "9091:9091"
volumes:
- /appl/docker/authelia:/config
restart: u
nless-stopped
```
Snippet of the dynamic.toml file (referenced in the yml-file above) that defines the config for NetAlertX:
The following are self-defined keywords, everything else is traefik keywords:
- netalertx-router
- netalertx-service
- auth
- netalertx-stripprefix
```toml
[http.routers]
[http.routers.netalertx-router]
entryPoints = ["websecure"]
rule = "Host(`www.domain.com`) && PathPrefix(`/netalertx`)"
service = "netalertx-service"
middlewares = "auth,netalertx-stripprefix"
[http.routers.netalertx-router.tls]
certResolver = "section31"
[[http.routers.netalertx-router.tls.domains]]
main = "www.domain.com"
[http.services]
[http.services.netalertx-service]
[[http.services.netalertx-service.loadBalancer.servers]]
url = "http://internal-ip-address:20211/"
[http.middlewares]
[http.middlewares.auth.forwardAuth]
address = "http://authelia:9091/api/verify?rd=https://www.domain.com/authelia/"
trustForwardHeader = true
authResponseHeaders = ["Remote-User", "Remote-Groups", "Remote-Name", "Remote-Email"]
[http.middlewares.netalertx-stripprefix.stripprefix]
prefixes = "/netalertx"
forceSlash = false
```
To make NetAlertX work with this setup I modified the default file at `/etc/nginx/sites-available/default` in the docker container by copying it to my local filesystem, adding the changes as specified by [cvc90](https://github.com/cvc90) and mounting the new file into the docker container, overwriting the original one. By mapping the file instead of changing the file in-place, the changes persist if an updated dockerimage is pulled. This is also a downside when the default file is updated, so I only use this as a temporary solution, until the dockerimage is updated with this change.
Default-file:
```
server {
listen 80 default_server;
root /var/www/html;
index index.php;
#rewrite /netalertx/(.*) / permanent;
add_header X-Forwarded-Prefix "/netalertx" always;
proxy_set_header X-Forwarded-Prefix "/netalertx";
location ~* \.php$ {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_connect_timeout 75;
fastcgi_send_timeout 600;
fastcgi_read_timeout 600;
}
}
```
Mapping the updated file (on the local filesystem at `/appl/docker/netalertx/default`) into the docker container:
```yaml
...
volumes:
- /appl/docker/netalertx/default:/etc/nginx/sites-available/default
...
```
If you want to understand more about reverse proxies and networking concepts:
* [What is a Reverse Proxy? (Cloudflare)](https://www.cloudflare.com/learning/cdn/glossary/reverse-proxy/)
* [Proxy vs Reverse Proxy (StrongDM)](https://www.strongdm.com/blog/difference-between-proxy-and-reverse-proxy)
* [Nginx Reverse Proxy Glossary](https://www.nginx.com/resources/glossary/reverse-proxy-server/)

View File

@@ -1,892 +0,0 @@
## Caddy + Authentik Outpost Proxy SSO
> Submitted by [luckylinux](https://github.com/luckylinux) 🙏.
> [!NOTE]
> This is community-contributed. Due to environment, setup, or networking differences, results may vary. Please open a PR to improve it instead of creating an issue, as the maintainer is not actively maintaining it.
> [!NOTE]
> NetAlertX requires access to both the **web UI** (default `20211`) and the **GraphQL backend `GRAPHQL_PORT`** (default `20212`) ports.
> Ensure your reverse proxy allows traffic to both for proper functionality.
### Introduction
This Setup assumes:
1. Authentik Installation running on a separate Host at `https://authentik.MYDOMAIN.TLD`
2. Container Management is done on Baremetal OR in a Virtual Machine (KVM/Xen/ESXi/..., no LXC Containers !):
i. Docker and Docker Compose configured locally running as Root (needed for `network_mode: host`) OR
ii. Podman (optionally `podman-compose`) configured locally running as Root (needed for `network_mode: host`)
3. TLS Certificates are already pre-obtained and located at `/var/lib/containers/certificates/letsencrypt/MYDOMAIN.TLD`.
I use the `certbot/dns-cloudflare` Podman Container on a separate Host to obtain the Certificates which I then distribute internally.
This Container uses the Wildcard Top-Level Domain Certificate which is valid for `MYDOMAIN.TLD` and `*.MYDOMAIN.TLD`.
4. Proxied Access
i. NetAlertX Web Interface is accessible via Caddy Reverse Proxy at `https://netalertx.MYDOMAIN.TLD` (default HTTPS Port 443: `https://netalertx.MYDOMAIN.TLD:443`) with `REPORT_DASHBOARD_URL=https://netalertx.MYDOMAIN.TLD`
ii. NetAlertX GraphQL Interface is accessible via Caddy Reverse Proxy at `https://netalertx.MYDOMAIN.TLD:20212` with `BACKEND_API_URL=https://netalertx.MYDOMAIN.TLD:20212`
iii. Authentik Proxy Outpost is accessible via Caddy Reverse Proxy at `https://netalertx.MYDOMAIN.TLD:9443`
5. Internal Ports
i. NGINX Web Server is set to listen on internal Port 20211 set via `PORT=20211`
ii. Python Web Server is set to listen on internal Port `GRAPHQL_PORT=20219`
iii. Authentik Proxy Outpost is listening on internal Port `AUTHENTIK_LISTEN__HTTP=[::1]:6000` (unencrypted) and Port `AUTHENTIK_LISTEN__HTTPS=[::1]:6443` (encrypted)
8. Some further Configuration for Caddy is performed in Terms of Logging, SSL Certificates, etc
It's also possible to [let Caddy automatically request & keep TLS Certificates up-to-date](https://caddyserver.com/docs/automatic-https), although please keep in mind that:
1. You risk enumerating your LAN. Every Domain/Subdomain for which Caddy requests a TLS Certificate for you will result in that Host to be listed on [List of Letsencrypt Certificates issued](https://crt.sh/).
2. You need to either:
i. Open Port 80 for external Access ([HTTP challenge](https://caddyserver.com/docs/automatic-https#http-challenge)) in order for Letsencrypt to verify the Ownership of the Domain/Subdomain
ii. Open Port 443 for external Access ([TLS-ALPN challenge](https://caddyserver.com/docs/automatic-https#tls-alpn-challenge)) in order for Letsencrypt to verify the Ownership of the Domain/Subdomain
iii. Give Caddy the Credentials to update the DNS Records at your DNS Provider ([DNS challenge](https://caddyserver.com/docs/automatic-https#dns-challenge))
You can also decide to deploy your own Certificates & Certification Authority, either manually with OpenSSL, or by using something like [mkcert](https://github.com/FiloSottile/mkcert).
In Terms of IP Stack Used:
- External: Caddy listens on both IPv4 and IPv6.
- Internal:
- Authentik Outpost Proxy listens on IPv6 `[::1]`
- NetAlertX listens on IPv4 `0.0.0.0`
### Flow
The Traffic Flow will therefore be as follows:
- Web GUI:
i. Client accesses `http://authentik.MYDOMAIN.TLD:80`: default (built-in Caddy) Redirect to `https://authentik.MYDOMAIN.TLD:443`
ii. Client accesses `https://authentik.MYDOMAIN.TLD:443` -> reverse Proxy to internal Port 20211 (NetAlertX Web GUI / NGINX - unencrypted)
- GraphQL: Client accesses `https://authentik.MYDOMAIN.TLD:20212` -> reverse Proxy to internal Port 20219 (NetAlertX GraphQL - unencrypted)
- Authentik Outpost: Client accesses `https://authentik.MYDOMAIN.TLD:9443` -> reverse Proxy to internal Port 6000 (Authentik Outpost Proxy - unencrypted)
An Overview of the Flow is provided in the Picture below:
![Reverse Proxy Traffic Flow with Authentik SSSO](./img/REVERSE_PROXY/reverse_proxy_flow.svg)
### Security Considerations
#### Caddy should be run rootless
> [!WARNING]
> By default Caddy runs as `root` which is a Security Risk.
> In order to solve this, it's recommended to create an unprivileged User `caddy` and Group `caddy` on the Host:
> ```
> groupadd --gid 980 caddy
> useradd --shell /usr/sbin/nologin --gid 980 --uid 980 -c "Caddy web server" --base-dir /var/lib/caddy
> ```
At least using Quadlets with Usernames (NOT required with UID/GID), but possibly using Compose in certain Cases as well, a custom `/etc/passwd` and `/etc/group` might need to be bind-mounted inside the Container.
`passwd`:
```
root:x:0:0:root:/root:/bin/sh
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/mail:/sbin/nologin
news:x:9:13:news:/usr/lib/news:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin
cron:x:16:16:cron:/var/spool/cron:/sbin/nologin
ftp:x:21:21::/var/lib/ftp:/sbin/nologin
sshd:x:22:22:sshd:/dev/null:/sbin/nologin
games:x:35:35:games:/usr/games:/sbin/nologin
ntp:x:123:123:NTP:/var/empty:/sbin/nologin
guest:x:405:100:guest:/dev/null:/sbin/nologin
nobody:x:65534:65534:nobody:/:/sbin/nologin
caddy:x:980:980:caddy:/var/lib/caddy:/bin/sh
```
`group`:
```
root:x:0:root
bin:x:1:root,bin,daemon
daemon:x:2:root,bin,daemon
sys:x:3:root,bin
adm:x:4:root,daemon
tty:x:5:
disk:x:6:root
lp:x:7:lp
kmem:x:9:
wheel:x:10:root
floppy:x:11:root
mail:x:12:mail
news:x:13:news
uucp:x:14:uucp
cron:x:16:cron
audio:x:18:
cdrom:x:19:
dialout:x:20:root
ftp:x:21:
sshd:x:22:
input:x:23:
tape:x:26:root
video:x:27:root
netdev:x:28:
kvm:x:34:kvm
games:x:35:
shadow:x:42:
www-data:x:82:
users:x:100:games
ntp:x:123:
abuild:x:300:
utmp:x:406:
ping:x:999:
nogroup:x:65533:
nobody:x:65534:
caddy:x:980:
```
#### Authentication of GraphQL Endpoint
> [!WARNING]
> Currently the GraphQL Endpoint is NOT authenticated !
### Environment Files
Depending on the Preference of the User (Environment Variables defined in Compose/Quadlet or in external `.env` File[s]), it might be prefereable to place at least some Environment Variables in external `.env` and `.env.<application>` Files.
The following is proposed:
- `.env`: common Settings (empty by Default)
- `.env.caddy`: Caddy Settings
- `.env.server`: NetAlertX Server/Application Settings
- `.env.outpost.proxy`: Authentik Proxy Outpost Settings
The following Contents is assumed.
`.env.caddy`:
```
# Define Application Hostname
APPLICATION_HOSTNAME=netalertx.MYDOMAIN.TLD
# Define Certificate Domain
# In this case: use Wildcard Certificate
APPLICATION_CERTIFICATE_DOMAIN=MYDOMAIN.TLD
APPLICATION_CERTIFICATE_CERT_FILE=fullchain.pem
APPLICATION_CERTIFICATE_KEY_FILE=privkey.pem
# Define Outpost Hostname
OUTPOST_HOSTNAME=netalertx.MYDOMAIN.TLD
# Define Outpost External Port (TLS)
OUTPOST_EXTERNAL_PORT=9443
```
`.env.server`:
```
PORT=20211
PORT_SSL=443
NETALERTX_NETWORK_MODE=host
LISTEN_ADDR=0.0.0.0
GRAPHQL_PORT=20219
NETALERTX_DEBUG=1
BACKEND_API_URL=https://netalertx.MYDOMAIN.TLD:20212
```
`.env.outpost.proxy`:
```
AUTHENTIK_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
AUTHENTIK_LISTEN__HTTP=[::1]:6000
AUTHENTIK_LISTEN__HTTPS=[::1]:6443
```
### Compose Setup
```
version: "3.8"
services:
netalertx-caddy:
container_name: netalertx-caddy
network_mode: host
image: docker.io/library/caddy:latest
pull: missing
env_file:
- .env
- .env.caddy
environment:
CADDY_DOCKER_CADDYFILE_PATH: "/etc/caddy/Caddyfile"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro,z
- /var/lib/containers/data/netalertx/caddy:/data/caddy:rw,z
- /var/lib/containers/log/netalertx/caddy:/var/log:rw,z
- /var/lib/containers/config/netalertx/caddy:/config/caddy:rw,z
- /var/lib/containers/certificates/letsencrypt:/certificates:ro,z
# Set User
user: "caddy:caddy"
# Automatically restart Container
restart: unless-stopped
netalertx-server:
container_name: netalertx-server # The name when you docker contiainer ls
network_mode: host # Use host networking for ARP scanning and other services
depends_on:
netalertx-caddy:
condition: service_started
restart: true
netalertx-outpost-proxy:
condition: service_started
restart: true
# Local built Image including latest Changes
image: localhost/netalertx-dev:dev-20260109-232454
read_only: true # Make the container filesystem read-only
# It is most secure to start with user 20211, but then we lose provisioning capabilities.
# user: "${NETALERTX_UID:-20211}:${NETALERTX_GID:-20211}"
cap_drop: # Drop all capabilities for enhanced security
- ALL
cap_add: # Add only the necessary capabilities
- NET_ADMIN # Required for scanning with arp-scan, nmap, nbtscan, traceroute, and zero-conf
- NET_RAW # Required for raw socket operations with arp-scan, nmap, nbtscan, traceroute and zero-conf
- NET_BIND_SERVICE # Required to bind to privileged ports with nbtscan
- CHOWN # Required for root-entrypoint to chown /data + /tmp before dropping privileges
- SETUID # Required for root-entrypoint to switch to non-root user
- SETGID # Required for root-entrypoint to switch to non-root group
volumes:
# Override NGINX Configuration Template
- type: bind
source: /var/lib/containers/config/netalertx/server/nginx/netalertx.conf.template
target: /services/config/nginx/netalertx.conf.template
read_only: true
bind:
selinux: Z
# Letsencrypt Certificates
- type: bind
source: /var/lib/containers/certificates/letsencrypt/MYDOMAIN.TLD
target: /certificates
read_only: true
bind:
selinux: Z
# Data Storage for NetAlertX
- type: bind # Persistent Docker-managed Named Volume for storage
source: /var/lib/containers/data/netalertx/server
target: /data # consolidated configuration and database storage
read_only: false # writable volume
bind:
selinux: Z
# Set the Timezone
- type: bind # Bind mount for timezone consistency
source: /etc/localtime
target: /etc/localtime
read_only: true
bind:
selinux: Z
# tmpfs mounts for writable directories in a read-only container and improve system performance
# All writes now live under /tmp/* subdirectories which are created dynamically by entrypoint.d scripts
# mode=1700 gives rwx------ permissions; ownership is set by /root-entrypoint.sh
- type: tmpfs
target: /tmp
tmpfs-mode: 1700
uid: 0
gid: 0
rw: true
noexec: true
nosuid: true
nodev: true
async: true
noatime: true
nodiratime: true
bind:
selinux: Z
env_file:
- .env
- .env.server
environment:
PUID: ${NETALERTX_UID:-20211} # Runtime UID after priming (Synology/no-copy-up safe)
PGID: ${NETALERTX_GID:-20211} # Runtime GID after priming (Synology/no-copy-up safe)
LISTEN_ADDR: ${LISTEN_ADDR:-0.0.0.0} # Listen for connections on all interfaces
PORT: ${PORT:-20211} # Application port
PORT_SSL: ${PORT_SSL:-443}
GRAPHQL_PORT: ${GRAPHQL_PORT:-20212} # GraphQL API port
ALWAYS_FRESH_INSTALL: ${ALWAYS_FRESH_INSTALL:-false} # Set to true to reset your config and database on each container start
NETALERTX_DEBUG: ${NETALERTX_DEBUG:-0} # 0=kill all services and restart if any dies. 1 keeps running dead services.
BACKEND_API_URL: ${BACKEND_API_URL-"https://netalertx.MYDOMAIN.TLD:20212"}
# Resource limits to prevent resource exhaustion
mem_limit: 4096m # Maximum memory usage
mem_reservation: 2048m # Soft memory limit
cpu_shares: 512 # Relative CPU weight for CPU contention scenarios
pids_limit: 512 # Limit the number of processes/threads to prevent fork bombs
logging:
driver: "json-file" # Use JSON file logging driver
options:
max-size: "10m" # Rotate log files after they reach 10MB
max-file: "3" # Keep a maximum of 3 log files
# Always restart the container unless explicitly stopped
restart: unless-stopped
# To sign Out, you need to visit
# {$OUTPOST_HOSTNAME}:{$OUTPOST_EXTERNAL_PORT}/outpost.goauthentik.io/sign_out
netalertx-outpost-proxy:
container_name: netalertx-outpost-proxy
network_mode: host
depends_on:
netalertx-caddy:
condition: service_started
restart: true
restart: unless-stopped
image: ghcr.io/goauthentik/proxy:2025.10
pull: missing
env_file:
- .env
- .env.outpost.proxy
environment:
AUTHENTIK_HOST: "https://authentik.MYDOMAIN.TLD"
AUTHENTIK_INSECURE: false
AUTHENTIK_LISTEN__HTTP: "[::1]:6000"
AUTHENTIK_LISTEN__HTTPS: "[::1]:6443"
```
### Quadlet Setup
`netalertx.pod`:
```
[Pod]
# Name of the Pod
PodName=netalertx
# Network Mode Host is required for ARP to work
Network=host
# Automatically start Pod at Boot Time
[Install]
WantedBy=default.target
```
`netalertx-caddy.container`:
```
[Unit]
Description=NetAlertX Caddy Container
[Service]
Restart=always
[Container]
ContainerName=netalertx-caddy
Pod=netalertx.pod
StartWithPod=true
# Generic Environment Configuration
EnvironmentFile=.env
# Caddy Specific Environment Configuration
EnvironmentFile=.env.caddy
Environment=CADDY_DOCKER_CADDYFILE_PATH=/etc/caddy/Caddyfile
Image=docker.io/library/caddy:latest
Pull=missing
# Run as rootless
# Specifying User & Group by Name requires to mount a custom passwd & group File inside the Container
# Otherwise an Error like the following will result: netalertx-caddy[593191]: Error: unable to find user caddy: no matching entries in passwd file
# User=caddy
# Group=caddy
# Volume=/var/lib/containers/config/netalertx/caddy-rootless/passwd:/etc/passwd:ro,z
# Volume=/var/lib/containers/config/netalertx/caddy-rootless/group:/etc/group:ro,z
# Run as rootless
# Specifying User & Group by UID/GID will NOT require a custom passwd / group File to be bind-mounted inside the Container
User=980
Group=980
Volume=./Caddyfile:/etc/caddy/Caddyfile:ro,z
Volume=/var/lib/containers/data/netalertx/caddy:/data/caddy:z
Volume=/var/lib/containers/log/netalertx/caddy:/var/log:z
Volume=/var/lib/containers/config/netalertx/caddy:/config/caddy:z
Volume=/var/lib/containers/certificates/letsencrypt:/certificates:ro,z
```
`netalertx-server.container`:
```
[Unit]
Description=NetAlertX Server Container
Requires=netalertx-caddy.service netalertx-outpost-proxy.service
After=netalertx-caddy.service netalertx-outpost-proxy.service
[Service]
Restart=always
[Container]
ContainerName=netalertx-server
Pod=netalertx.pod
StartWithPod=true
# Local built Image including latest Changes
Image=localhost/netalertx-dev:dev-20260109-232454
Pull=missing
# Make the container filesystem read-only
ReadOnly=true
# Drop all capabilities for enhanced security
DropCapability=ALL
# It is most secure to start with user 20211, but then we lose provisioning capabilities.
# User=20211:20211
# Required for scanning with arp-scan, nmap, nbtscan, traceroute, and zero-conf
AddCapability=NET_ADMIN
# Required for raw socket operations with arp-scan, nmap, nbtscan, traceroute and zero-conf
AddCapability=NET_RAW
# Required to bind to privileged ports with nbtscan
AddCapability=NET_BIND_SERVICE
# Required for root-entrypoint to chown /data + /tmp before dropping privileges
AddCapability=CHOWN
# Required for root-entrypoint to switch to non-root user
AddCapability=SETUID
# Required for root-entrypoint to switch to non-root group
AddCapability=SETGID
# Override the Configuration Template
Volume=/var/lib/containers/config/netalertx/server/nginx/netalertx.conf.template:/services/config/nginx/netalertx.conf.template:ro,Z
# Letsencrypt Certificates
Volume=/var/lib/containers/certificates/letsencrypt/MYDOMAIN.TLD:/certificates:ro,Z
# Data Storage for NetAlertX
Volume=/var/lib/containers/data/netalertx/server:/data:rw,Z
# Set the Timezone
Volume=/etc/localtime:/etc/localtime:ro,Z
# tmpfs mounts for writable directories in a read-only container and improve system performance
# All writes now live under /tmp/* subdirectories which are created dynamically by entrypoint.d scripts
# mode=1700 gives rwx------ permissions; ownership is set by /root-entrypoint.sh
# Mount=type=tmpfs,destination=/tmp,tmpfs-mode=1700,uid=0,gid=0,rw=true,noexec=true,nosuid=true,nodev=true,async=true,noatime=true,nodiratime=true,relabel=private
Mount=type=tmpfs,destination=/tmp,tmpfs-mode=1700,rw=true,noexec=true,nosuid=true,nodev=true
# Environment Configuration
EnvironmentFile=.env
EnvironmentFile=.env.server
# Runtime UID after priming (Synology/no-copy-up safe)
Environment=PUID=20211
# Runtime GID after priming (Synology/no-copy-up safe)
Environment=PGID=20211
# Listen for connections on all interfaces (IPv4)
Environment=LISTEN_ADDR=0.0.0.0
# Application port
Environment=PORT=20211
# SSL Port
Environment=PORT_SSL=443
# GraphQL API port
Environment=GRAPHQL_PORT=20212
# Set to true to reset your config and database on each container start
Environment=ALWAYS_FRESH_INSTALL=false
# 0=kill all services and restart if any dies. 1 keeps running dead services.
Environment=NETALERTX_DEBUG=0
# Set the GraphQL URL for external Access (via Caddy Reverse Proxy)
Environment=BACKEND_API_URL=https://netalertx-fedora.MYDOMAIN.TLD:20212
# Resource limits to prevent resource exhaustion
# Maximum memory usage
Memory=4g
# Limit the number of processes/threads to prevent fork bombs
PidsLimit=512
# Relative CPU weight for CPU contention scenarios
PodmanArgs=--cpus=2
PodmanArgs=--cpu-shares=512
# Soft memory limit
PodmanArgs=--memory-reservation=2g
# !! The following Keys are unfortunately not [yet] supported !!
# Relative CPU weight for CPU contention scenarios
#CpuShares=512
# Soft memory limit
#MemoryReservation=2g
```
`netalertx-outpost-proxy.container`:
```
[Unit]
Description=NetAlertX Authentik Proxy Outpost Container
Requires=netalertx-caddy.service
After=netalertx-caddy.service
[Service]
Restart=always
[Container]
ContainerName=netalertx-outpost-proxy
Pod=netalertx.pod
StartWithPod=true
# General Configuration
EnvironmentFile=.env
# Authentik Outpost Proxy Specific Configuration
EnvironmentFile=.env.outpost.proxy
Environment=AUTHENTIK_HOST=https://authentik.MYDOMAIN.TLD
Environment=AUTHENTIK_INSECURE=false
# Overrides Value from .env.outpost.rac
# Environment=AUTHENTIK_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# Optional setting to be used when `authentik_host` for internal communication doesn't match the public URL
# Environment=AUTHENTIK_HOST_BROWSER=https://authentik.MYDOMAIN.TLD
# Container Image
Image=ghcr.io/goauthentik/proxy:2025.10
Pull=missing
# Network Configuration
Network=container:supermicro-ikvm-pve031-caddy
# Security Configuration
NoNewPrivileges=true
```
### Firewall Setup
Depending on which GNU/Linux Distribution you are running, it might be required to open up some Firewall Ports in order to be able to access the Endpoints from outside the Host itself.
This is for instance the Case for Fedora Linux, where I had to open:
- Port 20212 for external GraphQL Access (both TCP & UDP are open, unsure if UDP is required)
- Port 9443 for external Authentik Outpost Proxy Access (both TCP & UDP are open, unsure if UDP is required)
![Fedora Firewall Configuration](./img/REVERSE_PROXY/fedora-firewall.png)
### Authentik Setup
In order to enable Single Sign On (SSO) with Authentik, you will need to create a Provider, an Application and an Outpost.
![Authentik Left Sidebar](./img/REVERSE_PROXY/authentik-sidebar.png)
First of all, using the Left Sidebar, navigate to `Applications` &#8594; `Providers`, click on `Create` (Blue Button at the Top of the Screen), select `Proxy Provider`, then click `Next`:
![Authentik Provider Setup (Part 1)](./img/REVERSE_PROXY/authentik-provider-setup-01.png)
Fill in the required Fields:
- Name: choose a Name for the Provider (e.g. `netalertx`)
- Authorization Flow: choose the Authorization Flow. I typically use `default-provider-authorization-implicit-consent (Authorize Application)`. If you select the `default-provider-authorization-explicit-consent (Authorize Application)` you will need to authorize Authentik every Time you want to log in NetAlertX, which can make the Experience less User-friendly
- Type: Click on `Forward Auth (single application)`
- External Host: set to `https://netalertx.MYDOMAIN.TLD`
Click `Finish`.
![Authentik Provider Setup (Part 2)](./img/REVERSE_PROXY/authentik-provider-setup-02.png)
Now, using the Left Sidebar, navigate to `Applications` &#8594; `Applications`, click on `Create` (Blue Button at the Top of the Screen) and fill in the required Fields:
- Name: choose a Name for the Application (e.g. `netalertx`)
- Slug: choose a Slug for the Application (e.g. `netalertx`)
- Group: optionally you can assign this Application to a Group of Applications of your Choosing (for grouping Purposes within Authentik User Interface)
- Provider: select the Provider you created the the `Providers` Section previosly (e.g. `netalertx`)
Then click `Create`.
![Authentik Application Setup (Part 1)](./img/REVERSE_PROXY/authentik-application-setup-01.png)
Now, using the Left Sidebar, navigate to `Applications` &#8594; `Outposts`, click on `Create` (Blue Button at the Top of the Screen) and fill in the required Fields:
- Name: choose a Name for the Outpost (e.g. `netalertx`)
- Type: `Proxy`
- Integration: open the Dropdown and click on `---------`. Make sure it is NOT set to `Local Docker connection` !
In the `Available Applications` Section, select the Application you created in the Previous Step, then click the right Arrow (approx. located in the Center of the Screen), so that it gets copied in the `Selected Applications` Section.
Then click `Create`.
![Authentik Outpost Setup (Part 1)](./img/REVERSE_PROXY/authentik-outpost-setup-01.png)
Wait a few Seconds for the Outpost to be created. Once it appears in the List, click on `Deployment Info` on the Right Side of the relevant Line.
![Authentik Outpost Setup (Part 2)](./img/REVERSE_PROXY/authentik-outpost-setup-02.png)
Take note of that Token. You will need it for the Authentik Outpost Proxy Container, which will read it as the `AUTHENTIK_TOKEN` Environment Variable.
### NGINX Configuration inside NetAlertX Container
> [!NOTE]
> This is something that was implemented based on the previous Content of this Reverse Proxy Document.
> Due to some Buffer Warnings/Errors in the Logs as well as some other Issues I was experiencing, I increased a lot the client_body_buffer_size and large_client_header_buffers Parameters, although these might not be required anymore.
> Further Testing might be required.
```
# Set number of worker processes automatically based on number of CPU cores.
worker_processes auto;
# Enables the use of JIT for regular expressions to speed-up their processing.
pcre_jit on;
# Configures default error logger.
error_log /tmp/log/nginx-error.log warn;
pid /tmp/run/nginx.pid;
events {
# The maximum number of simultaneous connections that can be opened by
# a worker process.
worker_connections 1024;
}
http {
# Mapping of temp paths for various nginx modules.
client_body_temp_path /tmp/nginx/client_body;
proxy_temp_path /tmp/nginx/proxy;
fastcgi_temp_path /tmp/nginx/fastcgi;
uwsgi_temp_path /tmp/nginx/uwsgi;
scgi_temp_path /tmp/nginx/scgi;
# Includes mapping of file name extensions to MIME types of responses
# and defines the default type.
include /services/config/nginx/mime.types;
default_type application/octet-stream;
# Name servers used to resolve names of upstream servers into addresses.
# It's also needed when using tcpsocket and udpsocket in Lua modules.
#resolver 1.1.1.1 1.0.0.1 [2606:4700:4700::1111] [2606:4700:4700::1001];
# Don't tell nginx version to the clients. Default is 'on'.
server_tokens off;
# Specifies the maximum accepted body size of a client request, as
# indicated by the request header Content-Length. If the stated content
# length is greater than this size, then the client receives the HTTP
# error code 413. Set to 0 to disable. Default is '1m'.
client_max_body_size 1m;
# Sendfile copies data between one FD and other from within the kernel,
# which is more efficient than read() + write(). Default is off.
sendfile on;
# Causes nginx to attempt to send its HTTP response head in one packet,
# instead of using partial frames. Default is 'off'.
tcp_nopush on;
# Enables the specified protocols. Default is TLSv1 TLSv1.1 TLSv1.2.
# TIP: If you're not obligated to support ancient clients, remove TLSv1.1.
ssl_protocols TLSv1.2 TLSv1.3;
# Path of the file with Diffie-Hellman parameters for EDH ciphers.
# TIP: Generate with: `openssl dhparam -out /etc/ssl/nginx/dh2048.pem 2048`
#ssl_dhparam /etc/ssl/nginx/dh2048.pem;
# Specifies that our cipher suits should be preferred over client ciphers.
# Default is 'off'.
ssl_prefer_server_ciphers on;
# Enables a shared SSL cache with size that can hold around 8000 sessions.
# Default is 'none'.
ssl_session_cache shared:SSL:2m;
# Specifies a time during which a client may reuse the session parameters.
# Default is '5m'.
ssl_session_timeout 1h;
# Disable TLS session tickets (they are insecure). Default is 'on'.
ssl_session_tickets off;
# Enable gzipping of responses.
gzip on;
# Set the Vary HTTP header as defined in the RFC 2616. Default is 'off'.
gzip_vary on;
# Specifies the main log format.
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# Sets the path, format, and configuration for a buffered log write.
access_log /tmp/log/nginx-access.log main;
# Virtual host config (unencrypted)
server {
listen ${LISTEN_ADDR}:${PORT} default_server;
root /app/front;
index index.php;
add_header X-Forwarded-Prefix "/app" always;
server_name netalertx-server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
client_body_buffer_size 512k;
large_client_header_buffers 64 128k;
location ~* \.php$ {
# Set Cache-Control header to prevent caching on the first load
add_header Cache-Control "no-store";
fastcgi_pass unix:/tmp/run/php.sock;
include /services/config/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_connect_timeout 75;
fastcgi_send_timeout 600;
fastcgi_read_timeout 600;
}
}
}
```
### Caddyfile
```
# Example and Guide
# https://caddyserver.com/docs/caddyfile/options
# General Options
{
# (Optional) Debug Mode
# debug
# (Optional ) Enable / Disable Admin API
admin off
# TLS Options
# (Optional) Disable Certificates Management (only if SSL/TLS Certificates are managed by certbot or other external Tools)
auto_https disable_certs
}
# (Optional Enable Admin API)
# localhost {
# reverse_proxy /api/* localhost:9001
# }
# NetAlertX Web GUI (HTTPS Port 443)
# (Optional) Only if SSL/TLS Certificates are managed by certbot or other external Tools and Custom Logging is required
{$APPLICATION_HOSTNAME}:443 {
tls /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_CERT_FILE:fullchain.pem} /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_KEY_FILE:privkey.pem}
log {
output file /var/log/{$APPLICATION_HOSTNAME}/access_web.json {
roll_size 100MiB
roll_keep 5000
roll_keep_for 720h
roll_uncompressed
}
format json
}
route {
# Always forward outpost path to actual outpost
reverse_proxy /outpost.goauthentik.io/* https://{$OUTPOST_HOSTNAME}:{$OUTPOST_EXTERNAL_PORT} {
header_up Host {http.reverse_proxy.upstream.hostport}
}
# Forward authentication to outpost
forward_auth https://{$OUTPOST_HOSTNAME}:{$OUTPOST_EXTERNAL_PORT} {
uri /outpost.goauthentik.io/auth/caddy
# Capitalization of the headers is important, otherwise they will be empty
copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Email X-Authentik-Name X-Authentik-Uid X-Authentik-Jwt X-Authentik-Meta-Jwks X-Authentik-Meta-Outpost X-Authentik-Meta-Provider X-Authentik-Meta-App X-Authentik-Meta-Version
# (Optional)
# If not set, trust all private ranges, but for Security Reasons, this should be set to the outposts IP
trusted_proxies private_ranges
}
}
# IPv4 Reverse Proxy to NetAlertX Web GUI (internal unencrypted Host)
reverse_proxy http://0.0.0.0:20211
# IPv6 Reverse Proxy to NetAlertX Web GUI (internal unencrypted Host)
# reverse_proxy http://[::1]:20211
}
# NetAlertX GraphQL Endpoint (HTTPS Port 20212)
# (Optional) Only if SSL/TLS Certificates are managed by certbot or other external Tools and Custom Logging is required
{$APPLICATION_HOSTNAME}:20212 {
tls /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_CERT_FILE:fullchain.pem} /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_KEY_FILE:privkey.pem}
log {
output file /var/log/{$APPLICATION_HOSTNAME}/access_graphql.json {
roll_size 100MiB
roll_keep 5000
roll_keep_for 720h
roll_uncompressed
}
format json
}
# IPv4 Reverse Proxy to NetAlertX GraphQL Endpoint (internal unencrypted Host)
reverse_proxy http://0.0.0.0:20219
# IPv6 Reverse Proxy to NetAlertX GraphQL Endpoint (internal unencrypted Host)
# reverse_proxy http://[::1]:6000
}
# Authentik Outpost
# (Optional) Only if SSL/TLS Certificates are managed by certbot or other external Tools and Custom Logging is required
{$OUTPOST_HOSTNAME}:{$OUTPOST_EXTERNAL_PORT} {
tls /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_CERT_FILE:fullchain.pem} /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_KEY_FILE:privkey.pem}
log {
output file /var/log/outpost/{$OUTPOST_HOSTNAME}/access.json {
roll_size 100MiB
roll_keep 5000
roll_keep_for 720h
roll_uncompressed
}
format json
}
# IPv4 Reverse Proxy to internal unencrypted Host
# reverse_proxy http://0.0.0.0:6000
# IPv6 Reverse Proxy to internal unencrypted Host
reverse_proxy http://[::1]:6000
}
```
### Login
Now try to login by visiting `https://netalertx.MYDOMAIN.TLD`.
You should be greeted with a Login Screen by Authentik.
If you are already logged in Authentik, log out first. You can do that by visiting `https://netalertx.MYDOMAIN.TLD/outpost.goauthentik.io/sign_out`, then click on `Log out of authentik` (2nd Button). Or you can just sign out from your Authentik Admin Panel at `https://authentik.MYDOMAIN.TLD`.
If everything works as expected, then you can now set `SETPWD_enable_password=false` to disable double Authentication.
![Authentik Login Screen](./img/REVERSE_PROXY/authentik-login.png)

View File

@@ -1,86 +0,0 @@
# Guide: Routing NetAlertX API via Traefik v3
> [!NOTE]
> NetAlertX requires access to both the **web UI** (default `20211`) and the **GraphQL backend `GRAPHQL_PORT`** (default `20212`) ports.
> Ensure your reverse proxy allows traffic to both for proper functionality.
> [!NOTE]
> This is community-contributed. Due to environment, setup, or networking differences, results may vary. Please open a PR to improve it instead of creating an issue, as the maintainer is not actively maintaining it.
Traefik v3 requires the following setup to route traffic properly. This guide shows a working configuration using a dedicated `PathPrefix`.
---
## 1. Configure NetAlertX Backend URL
1. Open the NetAlertX UI: **Settings → Core → General**.
2. Set the `BACKEND_API_URL` to include a custom path prefix, for example:
```
https://netalertx.yourdomain.com/netalertx-api
```
This tells the frontend where to reach the backend API.
---
## 2. Create a Traefik Router for the API
Define a router specifically for the API with a higher priority and a `PathPrefix` rule:
```yaml
netalertx-api:
rule: "Host(`netalertx.yourdomain.com`) && PathPrefix(`/netalertx-api`)"
service: netalertx-api-service
middlewares:
- netalertx-stripprefix
priority: 100
```
**Notes:**
* `Host(...)` ensures requests are only routed for your domain.
* `PathPrefix(...)` routes anything under `/netalertx-api` to the backend.
* Priority `100` ensures this router takes precedence over other routes.
---
## 3. Add a Middleware to Strip the Prefix
NetAlertX expects requests at the root (`/`). Use Traefiks `StripPrefix` middleware:
```yaml
middlewares:
netalertx-stripprefix:
stripPrefix:
prefixes:
- "/netalertx-api"
```
This removes `/netalertx-api` before forwarding the request to the backend container.
---
## 4. Map the API Service to the Backend Container
Point the service to the internal GraphQL/Backend port (20212):
```yaml
netalertx-api-service:
loadBalancer:
servers:
- url: "http://<INTERNAL_IP>:20212"
```
Replace `<INTERNAL_IP>` with your NetAlertX containers internal address.
---
✅ With this setup:
* `https://netalertx.yourdomain.com` → Web interface (port 20211)
* `https://netalertx.yourdomain.com/netalertx-api` → API/GraphQL backend (port 20212)
This cleanly separates API requests from frontend requests while keeping everything under the same domain.

View File

@@ -73,7 +73,7 @@ The adapter will probably be `eth0` or `eth1`. (Check `System Info` > `Network H
#### VLANs on a Hyper-V Setup #### 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). > Community-sourced content by [mscreations](https://github.com/mscreations) from this [discussion](https://github.com/netalertx/NetAlertX/discussions/404).
**Tested Setup:** Bare Metal → Hyper-V on Win Server 2019 → Ubuntu 22.04 VM → Docker → NetAlertX. **Tested Setup:** Bare Metal → Hyper-V on Win Server 2019 → Ubuntu 22.04 VM → Docker → NetAlertX.

View File

@@ -37,8 +37,8 @@ services:
netalertx: netalertx:
container_name: netalertx container_name: netalertx
# use the below line if you want to test the latest dev image # use the below line if you want to test the latest dev image
# image: "ghcr.io/jokob-sk/netalertx-dev:latest" # image: "ghcr.io/netalertx/netalertx-dev:latest"
image: "ghcr.io/jokob-sk/netalertx:latest" image: "ghcr.io/netalertx/netalertx:latest"
network_mode: "host" network_mode: "host"
restart: unless-stopped restart: unless-stopped
cap_drop: # Drop all capabilities for enhanced security cap_drop: # Drop all capabilities for enhanced security

View File

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

View File

@@ -8,7 +8,7 @@ N8N can be used for more advanced conditional notification use cases. For exampl
![n8n workflow](./img/WEBHOOK_N8N/n8n_workflow.png) ![n8n workflow](./img/WEBHOOK_N8N/n8n_workflow.png)
### Specify your email template ### Specify your email template
See [sample JSON](https://github.com/jokob-sk/NetAlertX/blob/main/front/report_templates/webhook_json_sample.json) if you want to see the JSON paths used in the email template below See [sample JSON](https://github.com/netalertx/NetAlertX/blob/main/front/report_templates/webhook_json_sample.json) if you want to see the JSON paths used in the email template below
![Email template](./img/WEBHOOK_N8N/n8n_send_email_settings.png) ![Email template](./img/WEBHOOK_N8N/n8n_send_email_settings.png)
``` ```

View File

@@ -67,4 +67,4 @@ You can find a couple of configuration examples in [Workflow Examples](WORKFLOW_
> [!TIP] > [!TIP]
> Share your workflows in [Discord](https://discord.com/invite/NczTUTWyRr) or [GitHub Discussions](https://github.com/jokob-sk/NetAlertX/discussions). > Share your workflows in [Discord](https://discord.com/invite/NczTUTWyRr) or [GitHub Discussions](https://github.com/netalertx/NetAlertX/discussions).

View File

@@ -0,0 +1,71 @@
# ARP Flux Sysctls Not Set
## Issue Description
NetAlertX detected that ARP flux protection sysctls are not set as expected:
- `net.ipv4.conf.all.arp_ignore=1`
- `net.ipv4.conf.all.arp_announce=2`
## Security Ramifications
This is not a direct container breakout risk, but detection quality can degrade:
- Incorrect IP/MAC associations
- Device state flapping
- Unreliable topology or presence data
## Why You're Seeing This Issue
The running environment does not provide the expected kernel sysctl values. This is common in Docker setups where sysctls were not explicitly configured.
## How to Correct the Issue
### Option A: Via Docker (Standard Bridge Networking or `network_mode: host` with `NET_ADMIN`)
If you are using standard bridged networking, or `network_mode: host` and the container is granted the `NET_ADMIN` capability (as is the default recommendation), set these sysctls at container runtime.
- In `docker-compose.yml` (preferred):
```yaml
services:
netalertx:
sysctls:
net.ipv4.conf.all.arp_ignore: 1
net.ipv4.conf.all.arp_announce: 2
```
- For `docker run`:
```bash
docker run \
--sysctl net.ipv4.conf.all.arp_ignore=1 \
--sysctl net.ipv4.conf.all.arp_announce=2 \
ghcr.io/netalertx/netalertx:latest
```
> **Note:** Setting `net.ipv4.conf.all.arp_ignore` and `net.ipv4.conf.all.arp_announce` may fail with "operation not permitted" unless the container is run with elevated privileges. To resolve this, you can:
> - Use `--privileged` with `docker run`.
> - Use the more restrictive `--cap-add=NET_ADMIN` (or `cap_add: [NET_ADMIN]` in `docker-compose` service definitions) to allow the sysctls to be applied at runtime.
### Option B: Via Host OS (Fallback for `network_mode: host`)
If you are running the container with `network_mode: host` and cannot grant the `NET_ADMIN` capability, or if your container runtime environment explicitly blocks sysctl overrides, applying these settings via the container configuration will fail. Attempting to do so without sufficient privileges typically results in an OCI runtime error: `sysctl "net.ipv4.conf.all.arp_announce" not allowed in host network namespace`.
In this scenario, you must apply the settings directly on your host operating system:
1. **Remove** the `sysctls` section from your `docker-compose.yml`.
2. **Apply** on the host immediately:
```bash
sudo sysctl -w net.ipv4.conf.all.arp_ignore=1
sudo sysctl -w net.ipv4.conf.all.arp_announce=2
```
3. **Make persistent** by adding the following lines to `/etc/sysctl.conf` on the host:
```text
net.ipv4.conf.all.arp_ignore=1
net.ipv4.conf.all.arp_announce=2
```
## Additional Resources
For broader Docker Compose guidance, see:
- [DOCKER_COMPOSE.md](https://docs.netalertx.com/DOCKER_COMPOSE)

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

View File

@@ -1,202 +0,0 @@
<mxfile host="Electron" modified="2026-01-15T05:36:26.645Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.1.0 Chrome/120.0.6099.109 Electron/28.1.0 Safari/537.36" etag="OpSjRPjeNeyudFLZJ2fD" version="24.1.0" type="device">
<diagram name="Page-1" id="mulIpG3YQAhf4Klf7Njm">
<mxGraphModel dx="6733" dy="1168" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="4681" pageHeight="3300" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-1" value="" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="850" y="160" width="920" height="810" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-2" value="NetAlertX Pod" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=32;" vertex="1" parent="1">
<mxGeometry x="850" y="130" width="670" height="30" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-3" value="" style="image;html=1;image=img/lib/clip_art/computers/Laptop_128x128.png" vertex="1" parent="1">
<mxGeometry x="-50" y="395" width="140" height="140" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-4" value="" style="image;html=1;image=img/lib/clip_art/networking/Firewall_02_128x128.png" vertex="1" parent="1">
<mxGeometry x="488" y="344" width="80" height="80" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-5" value="" style="image;html=1;image=img/lib/clip_art/networking/Firewall_02_128x128.png" vertex="1" parent="1">
<mxGeometry x="488" y="555" width="80" height="80" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-8" value="Web UI&lt;br&gt;(NGINX + PHP)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;" vertex="1" parent="1">
<mxGeometry x="230" y="320" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-9" value="API GraphQL&lt;br&gt;(Python)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;" vertex="1" parent="1">
<mxGeometry x="230" y="555" width="200" height="30" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-10" value="" style="endArrow=classic;html=1;rounded=0;dashed=1;dashPattern=8 8;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="240" y="390" as="sourcePoint" />
<mxPoint x="240" y="600" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-12" value="&lt;div&gt;443&lt;/div&gt;" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;fontColor=#FF0000;" vertex="1" parent="1">
<mxGeometry x="581" y="335" width="100" height="60" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-13" value="20212" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;fontColor=#FF0000;" vertex="1" parent="1">
<mxGeometry x="581" y="554" width="100" height="60" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-14" value="" style="image;html=1;image=img/lib/clip_art/networking/Firewall_02_128x128.png" vertex="1" parent="1">
<mxGeometry x="488" y="813" width="80" height="80" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-16" value="Authentik SSO for Web UI" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;" vertex="1" parent="1">
<mxGeometry x="230" y="793" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-17" value="9443" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;fontColor=#FF0000;" vertex="1" parent="1">
<mxGeometry x="580" y="803" width="100" height="60" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-18" value="" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="1470" y="250" width="288" height="440" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-19" value="NetAlertX" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;" vertex="1" parent="1">
<mxGeometry x="1470" y="210" width="288" height="40" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-21" value="" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="1260" y="751" width="500" height="199" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-22" value="Authentik Outpost Proxy" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;" vertex="1" parent="1">
<mxGeometry x="1280" y="711" width="480" height="40" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-23" value="" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="860" y="250" width="380" height="700" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-24" value="Caddy" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;" vertex="1" parent="1">
<mxGeometry x="860" y="210" width="390" height="40" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-25" value="" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="1498" y="319" width="220" height="130" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-26" value="" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="1498" y="530" width="220" height="150" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-27" value="Web UI&lt;div&gt;(NGINX + PHP)&lt;/div&gt;" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;" vertex="1" parent="1">
<mxGeometry x="1498" y="264" width="220" height="50" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-28" value="API GraphQL&lt;div&gt;(Python)&lt;/div&gt;" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;" vertex="1" parent="1">
<mxGeometry x="1498" y="475" width="220" height="50" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-6" value="" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="wwqsnaxs0Bt7SYwqQu8i-53" target="wwqsnaxs0Bt7SYwqQu8i-58">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="130" y="390" as="sourcePoint" />
<mxPoint x="1129" y="389.9999999999998" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-30" value="" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="wwqsnaxs0Bt7SYwqQu8i-59" target="wwqsnaxs0Bt7SYwqQu8i-31">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1214" y="483" as="sourcePoint" />
<mxPoint x="1209" y="823" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-31" value="Authenticated &amp;amp; Authorized ?" style="rhombus;whiteSpace=wrap;html=1;fontSize=18;" vertex="1" parent="1">
<mxGeometry x="1294" y="773.5" width="170" height="160" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-35" value="20211" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;fontColor=#FF0000;" vertex="1" parent="1">
<mxGeometry x="1488" y="335" width="100" height="60" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-36" value="" style="endArrow=classic;html=1;rounded=0;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1688" y="369" as="sourcePoint" />
<mxPoint x="1688" y="649" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-37" value="20219" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;fontColor=#FF0000;" vertex="1" parent="1">
<mxGeometry x="1498" y="535" width="100" height="60" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-38" value="HTTPS" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;fontColor=#66CC00;" vertex="1" parent="1">
<mxGeometry x="730" y="340" width="100" height="60" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-39" value="HTTPS" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;fontColor=#66CC00;" vertex="1" parent="1">
<mxGeometry x="730" y="803" width="100" height="60" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-40" value="HTTPS" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;fontColor=#66CC00;" vertex="1" parent="1">
<mxGeometry x="730" y="554" width="100" height="60" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-42" value="" style="endArrow=none;html=1;rounded=0;endFill=0;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1381" y="1071" as="sourcePoint" />
<mxPoint x="130" y="1071" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-43" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="130.5" y="1070" as="sourcePoint" />
<mxPoint x="130" y="860" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-44" value="NO" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;" vertex="1" parent="1">
<mxGeometry x="1364" y="1000" width="100" height="60" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-45" value="YES" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;" vertex="1" parent="1">
<mxGeometry x="1294" y="680" width="100" height="60" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-47" value="" style="endArrow=classic;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1156.5" y="450" as="sourcePoint" />
<mxPoint x="1157" y="1070" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-48" value="" style="endArrow=classic;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="wwqsnaxs0Bt7SYwqQu8i-56" target="wwqsnaxs0Bt7SYwqQu8i-26">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1299" y="600" as="sourcePoint" />
<mxPoint x="1499" y="600" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-49" value="HTTP" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;fontColor=#FF0000;" vertex="1" parent="1">
<mxGeometry x="1379" y="340" width="100" height="60" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-50" value="HTTP" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;fontColor=#FF0000;" vertex="1" parent="1">
<mxGeometry x="1379" y="554" width="100" height="60" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-54" value="" style="endArrow=classic;html=1;rounded=0;" edge="1" parent="1" target="wwqsnaxs0Bt7SYwqQu8i-53">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="130" y="390" as="sourcePoint" />
<mxPoint x="1129" y="390" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-53" value="TLS Termination" style="whiteSpace=wrap;html=1;aspect=fixed;fontSize=18;" vertex="1" parent="1">
<mxGeometry x="905" y="340" width="100" height="100" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-56" value="TLS Termination" style="whiteSpace=wrap;html=1;aspect=fixed;fontSize=18;" vertex="1" parent="1">
<mxGeometry x="902" y="554" width="100" height="100" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-7" value="" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" target="wwqsnaxs0Bt7SYwqQu8i-56">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="130" y="601" as="sourcePoint" />
<mxPoint x="850" y="601" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-58" value="Check Authentication" style="whiteSpace=wrap;html=1;aspect=fixed;fontSize=18;" vertex="1" parent="1">
<mxGeometry x="1097" y="330" width="120" height="120" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-59" value="TLS Termination" style="whiteSpace=wrap;html=1;aspect=fixed;fontSize=18;" vertex="1" parent="1">
<mxGeometry x="899" y="803" width="100" height="100" as="geometry" />
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-15" value="" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" target="wwqsnaxs0Bt7SYwqQu8i-59">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="30" y="853" as="sourcePoint" />
<mxPoint x="850" y="853" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-60" value="" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1379" y="390" as="sourcePoint" />
<mxPoint x="1500" y="389.58" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-61" value="" style="endArrow=none;html=1;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;endFill=0;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1379" y="773" as="sourcePoint" />
<mxPoint x="1379" y="390" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="wwqsnaxs0Bt7SYwqQu8i-62" value="" style="endArrow=classic;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="1380" y="933.5" as="sourcePoint" />
<mxPoint x="1379" y="1069" as="targetPoint" />
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 KiB

After

Width:  |  Height:  |  Size: 201 KiB

65
front/403_internal.html Normal file
View File

@@ -0,0 +1,65 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Access Restricted - NetAlertX</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
background-color: #f8f9fa;
color: #212529;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
margin: 0;
}
.container {
text-align: center;
padding: 2rem;
background: white;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
max-width: 600px;
}
h1 {
color: #dc3545;
font-size: 2rem;
margin-bottom: 1rem;
}
p {
margin-bottom: 1rem;
line-height: 1.5;
}
.code-snippet {
background-color: #e9ecef;
padding: 0.2rem 0.4rem;
border-radius: 4px;
font-family: monospace;
font-weight: bold;
}
.footer {
margin-top: 2rem;
font-size: 0.9rem;
color: #6c757d;
border-top: 1px solid #dee2e6;
padding-top: 1rem;
}
</style>
</head>
<body>
<div class="container">
<h1>403 Forbidden</h1>
<p>
The <span class="code-snippet">/server</span> endpoint is for <strong>internal use only</strong> and cannot be accessed from external browsers or applications.
</p>
<p>
This security measure protects the backend API. You will need to contact your system administrator in order to gain access to the API port (default: 20212), or use the application through the standard web interface.
</p>
<div class="footer">
NetAlertX Security &bull; Trust Level: Untrusted Origin
</div>
</div>
</body>
</html>

View File

@@ -61,16 +61,16 @@ $(document).ready(function () {
appEvents(options: $options) { appEvents(options: $options) {
count count
appEvents { appEvents {
DateTimeCreated dateTimeCreated
AppEventProcessed appEventProcessed
AppEventType appEventType
ObjectType objectType
ObjectPrimaryID objectPrimaryId
ObjectSecondaryID objectSecondaryId
ObjectStatus objectStatus
ObjectPlugin objectPlugin
ObjectGUID objectGuid
GUID guid
} }
} }
} }
@@ -128,16 +128,16 @@ $(document).ready(function () {
}, },
columns: [ columns: [
{ data: 'DateTimeCreated', title: getString('AppEvents_DateTimeCreated') }, { data: 'dateTimeCreated', title: getString('AppEvents_DateTimeCreated') },
{ data: 'AppEventProcessed', title: getString('AppEvents_AppEventProcessed') }, { data: 'appEventProcessed', title: getString('AppEvents_AppEventProcessed') },
{ data: 'AppEventType', title: getString('AppEvents_Type') }, { data: 'appEventType', title: getString('AppEvents_Type') },
{ data: 'ObjectType', title: getString('AppEvents_ObjectType') }, { data: 'objectType', title: getString('AppEvents_ObjectType') },
{ data: 'ObjectPrimaryID', title: getString('AppEvents_ObjectPrimaryID') }, { data: 'objectPrimaryId', title: getString('AppEvents_ObjectPrimaryID') },
{ data: 'ObjectSecondaryID', title: getString('AppEvents_ObjectSecondaryID') }, { data: 'objectSecondaryId', title: getString('AppEvents_ObjectSecondaryID') },
{ data: 'ObjectStatus', title: getString('AppEvents_ObjectStatus') }, { data: 'objectStatus', title: getString('AppEvents_ObjectStatus') },
{ data: 'ObjectPlugin', title: getString('AppEvents_Plugin') }, { data: 'objectPlugin', title: getString('AppEvents_Plugin') },
{ data: 'ObjectGUID', title: 'Object GUID' }, { data: 'objectGuid', title: 'Object GUID' },
{ data: 'GUID', title: 'Event GUID' } { data: 'guid', title: 'Event GUID' }
], ],
columnDefs: [ columnDefs: [

View File

@@ -538,6 +538,7 @@ body
font-size: larger; font-size: larger;
float: right; float: right;
text-align: center; text-align: center;
z-index: 1;
} }
hr hr
@@ -929,6 +930,14 @@ height: 50px;
.nav-tabs-custom .tab-content { .nav-tabs-custom .tab-content {
overflow: scroll; overflow: scroll;
} }
.infobox_label
{
display: none;
}
.small-box .icon
{
display: block !important;
}
} }
.top_small_box_gray_text { .top_small_box_gray_text {

View File

@@ -42,14 +42,7 @@ h4 {
.content-header > .breadcrumb > li > a { .content-header > .breadcrumb > li > a {
color: #bec5cb; color: #bec5cb;
} }
.table > thead > tr > th,
.table > tbody > tr > th,
.table > tfoot > tr > th,
.table > thead > tr > td,
.table > tbody > tr > td,
.table > tfoot > tr > td {
border-top: 0;
}
.table > thead > tr.odd, .table > thead > tr.odd,
.table > tbody > tr.odd, .table > tbody > tr.odd,
.table > tfoot > tr.odd { .table > tfoot > tr.odd {
@@ -73,7 +66,6 @@ h4 {
border: 1px solid #353c42; border: 1px solid #353c42;
} }
.dataTables_wrapper input[type="search"] { .dataTables_wrapper input[type="search"] {
border-radius: 4px;
background-color: #353c42; background-color: #353c42;
border: 0; border: 0;
color: #bec5cb; color: #bec5cb;
@@ -126,7 +118,6 @@ h4 {
border-color: #3c8dbc; border-color: #3c8dbc;
} }
.sidebar-menu > li > .treeview-menu { .sidebar-menu > li > .treeview-menu {
margin: 0 1px;
background-color: #32393e; background-color: #32393e;
} }
.sidebar a { .sidebar a {
@@ -144,16 +135,13 @@ h4 {
color: #fff; color: #fff;
} }
.sidebar-form { .sidebar-form {
border-radius: 3px;
border: 1px solid #3e464c; border: 1px solid #3e464c;
margin: 10px;
} }
.sidebar-form input[type="text"], .sidebar-form input[type="text"],
.sidebar-form .btn { .sidebar-form .btn {
box-shadow: none; box-shadow: none;
background-color: #3e464c; background-color: #3e464c;
border: 1px solid transparent; border: 1px solid transparent;
height: 35px;
} }
.sidebar-form input[type="text"] { .sidebar-form input[type="text"] {
color: #666; color: #666;
@@ -207,20 +195,13 @@ h4 {
.box > .box-header .btn { .box > .box-header .btn {
color: #bec5cb; color: #bec5cb;
} }
.box.box-info,
.box.box-primary,
.box.box-success,
.box.box-warning,
.box.box-danger {
border-top-width: 3px;
}
.main-header .navbar { .main-header .navbar {
background-color: #272c30; background-color: #272c30;
} }
.main-header .navbar .nav > li > a, .main-header .navbar .nav > li > a,
.main-header .navbar .nav > li > .navbar-text { .main-header .navbar .nav > li > .navbar-text {
color: #bec5cb; color: #bec5cb;
max-height: 50px;
} }
.main-header .navbar .nav > li > a:hover, .main-header .navbar .nav > li > a:hover,
.main-header .navbar .nav > li > a:active, .main-header .navbar .nav > li > a:active,
@@ -277,7 +258,6 @@ h4 {
background: rgba(64, 72, 80, 0.666); background: rgba(64, 72, 80, 0.666);
} }
.nav-tabs-custom > .nav-tabs > li { .nav-tabs-custom > .nav-tabs > li {
margin-right: 1px;
color: #bec5cb; color: #bec5cb;
} }
.nav-tabs-custom > .nav-tabs > li.active > a, .nav-tabs-custom > .nav-tabs > li.active > a,
@@ -386,11 +366,8 @@ h4 {
code, code,
pre { pre {
padding: 2px 4px;
font-size: 90%;
color: #bec5cb; color: #bec5cb;
background-color: #353c42; background-color: #353c42;
border-radius: 4px;
} }
/* Used in the Query Log table */ /* Used in the Query Log table */
@@ -456,7 +433,7 @@ td.highlight {
/* Used by the long-term pages */ /* Used by the long-term pages */
.daterangepicker { .daterangepicker {
background-color: #3e464c; background-color: #3e464c;
border-radius: 4px;
border: 1px solid #353c42; border: 1px solid #353c42;
} }
.daterangepicker .ranges li:hover { .daterangepicker .ranges li:hover {
@@ -467,7 +444,7 @@ td.highlight {
} }
.daterangepicker .calendar-table { .daterangepicker .calendar-table {
background-color: #3e464c; background-color: #3e464c;
border-radius: 4px;
border: 1px solid #353c42; border: 1px solid #353c42;
} }
.daterangepicker td.off, .daterangepicker td.off,
@@ -535,7 +512,7 @@ textarea[readonly],
.panel-body, .panel-body,
.panel-default > .panel-heading { .panel-default > .panel-heading {
background-color: #3e464c; background-color: #3e464c;
border-radius: 4px;
border: 1px solid #353c42; border: 1px solid #353c42;
color: #bec5cb; color: #bec5cb;
} }
@@ -568,23 +545,10 @@ input[type="password"]::-webkit-caps-lock-indicator {
background-image: linear-gradient(to right, #114100 0%, #525200 100%); background-image: linear-gradient(to right, #114100 0%, #525200 100%);
} }
.icheckbox_polaris,
.icheckbox_futurico,
.icheckbox_minimal-blue {
margin-right: 10px;
}
.iradio_polaris,
.iradio_futurico,
.iradio_minimal-blue {
margin-right: 8px;
}
/* Overlay box with spinners as shown during data collection for graphs */ /* Overlay box with spinners as shown during data collection for graphs */
.box .overlay, .box .overlay,
.overlay-wrapper .overlay { .overlay-wrapper .overlay {
z-index: 50;
background-color: rgba(53, 60, 66, 0.733); background-color: rgba(53, 60, 66, 0.733);
border-radius: 3px;
} }
.box .overlay > .fa, .box .overlay > .fa,
.overlay-wrapper .overlay > .fa, .overlay-wrapper .overlay > .fa,
@@ -594,7 +558,6 @@ input[type="password"]::-webkit-caps-lock-indicator {
.navbar-nav > .user-menu > .dropdown-menu > .user-footer { .navbar-nav > .user-menu > .dropdown-menu > .user-footer {
background-color: #353c42bb; background-color: #353c42bb;
padding: 10px;
} }
.modal-content { .modal-content {
@@ -626,29 +589,29 @@ input[type="password"]::-webkit-caps-lock-indicator {
/*** Additional fixes For UI ***/ /*** Additional fixes For UI ***/
.pa-small-box-aqua .inner { .pa-small-box-aqua .inner {
background-color: rgb(45,108,133); background-color: rgb(45,108,133);
border-top-left-radius: 10px;
border-top-right-radius: 10px;
} }
.pa-small-box-green .inner { .pa-small-box-green .inner {
background-color: rgb(31,76,46); background-color: rgb(31,76,46);
border-top-left-radius: 10px;
border-top-right-radius: 10px;
} }
.pa-small-box-yellow .inner { .pa-small-box-yellow .inner {
background-color: rgb(151,104,37); background-color: rgb(151,104,37);
border-top-left-radius: 10px;
border-top-right-radius: 10px;
} }
.pa-small-box-red .inner { .pa-small-box-red .inner {
background-color: rgb(120,50,38); background-color: rgb(120,50,38);
border-top-left-radius: 10px;
border-top-right-radius: 10px;
} }
.pa-small-box-gray .inner { .pa-small-box-gray .inner {
background-color: #777; background-color: #777;
/* color: rgba(20,20,20,30%); */ /* color: rgba(20,20,20,30%); */
border-top-left-radius: 10px;
border-top-right-radius: 10px;
} }
.pa-small-box-gray .inner h3 { .pa-small-box-gray .inner h3 {
color: #bbb; color: #bbb;
@@ -687,15 +650,6 @@ table.dataTable tbody tr.selected, table.dataTable tbody tr .selected
.db_tools_table_cell_b:nth-child(1) {background: #272c30} .db_tools_table_cell_b:nth-child(1) {background: #272c30}
.db_tools_table_cell_b:nth-child(2) {background: #272c30} .db_tools_table_cell_b:nth-child(2) {background: #272c30}
.db_info_table {
display: table;
border-spacing: 0em;
font-weight: 400;
font-size: 15px;
width: 100%;
margin: auto;
}
.nav-tabs-custom > .nav-tabs > li:hover > a, .nav-tabs-custom > .nav-tabs > li.active:hover > a { .nav-tabs-custom > .nav-tabs > li:hover > a, .nav-tabs-custom > .nav-tabs > li.active:hover > a {
background-color: #272c30; background-color: #272c30;
color: #bec5cb; color: #bec5cb;
@@ -738,23 +692,7 @@ table.dataTable tbody tr.selected, table.dataTable tbody tr .selected
color: #bec5cb; color: #bec5cb;
background-color: #272c30; background-color: #272c30;
} }
/* Add border radius to bottom of the status boxes*/
.pa-small-box-footer {
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
}
.small-box > .inner h3, .small-box > .inner p {
margin-bottom: 0px;
margin-left: 0px;
}
.small-box:hover .icon {
font-size: 3em;
}
.small-box .icon {
top: 0.01em;
font-size: 3.25em;
}
.nax_semitransparent-panel{ .nax_semitransparent-panel{
background-color: #000 !important; background-color: #000 !important;
} }

View File

@@ -37,7 +37,7 @@
body, .bg-yellow, .callout.callout-warning, .alert-warning, .label-warning, .modal-warning .modal-body { body, .bg-yellow, .callout.callout-warning, .alert-warning, .label-warning, .modal-warning .modal-body {
background-color: #353c42 !important; background-color: #353c42 !important;
color: #bec5cb !important; color: #ffffff !important;
} }
h4 { h4 {
color: #44def1; color: #44def1;
@@ -76,9 +76,7 @@
border: 1px solid #353c42; border: 1px solid #353c42;
} }
.dataTables_wrapper input[type="search"] { .dataTables_wrapper input[type="search"] {
border-radius: 4px;
background-color: #353c42; background-color: #353c42;
border: 0;
color: #bec5cb; color: #bec5cb;
} }
.dataTables_paginate .pagination li > a { .dataTables_paginate .pagination li > a {
@@ -129,7 +127,6 @@
border-color: #3c8dbc; border-color: #3c8dbc;
} }
.sidebar-menu > li > .treeview-menu { .sidebar-menu > li > .treeview-menu {
margin: 0 1px;
background-color: #32393e; background-color: #32393e;
} }
.sidebar a { .sidebar a {
@@ -147,23 +144,16 @@
color: #fff; color: #fff;
} }
.sidebar-form { .sidebar-form {
border-radius: 3px;
border: 1px solid #3e464c; border: 1px solid #3e464c;
margin: 10px;
} }
.sidebar-form input[type="text"], .sidebar-form input[type="text"],
.sidebar-form .btn { .sidebar-form .btn {
box-shadow: none; box-shadow: none;
background-color: #3e464c; background-color: #3e464c;
border: 1px solid transparent; border: 1px solid transparent;
height: 35px;
} }
.sidebar-form input[type="text"] { .sidebar-form input[type="text"] {
color: #666; color: #666;
border-top-left-radius: 2px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-bottom-left-radius: 2px;
} }
.sidebar-form input[type="text"]:focus, .sidebar-form input[type="text"]:focus,
.sidebar-form input[type="text"]:focus + .input-group-btn .btn { .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
@@ -175,10 +165,6 @@
} }
.sidebar-form .btn { .sidebar-form .btn {
color: #999; color: #999;
border-top-left-radius: 0;
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
border-bottom-left-radius: 0;
} }
.box, .box,
.box-footer, .box-footer,
@@ -210,20 +196,12 @@
.box > .box-header .btn { .box > .box-header .btn {
color: #bec5cb; color: #bec5cb;
} }
.box.box-info,
.box.box-primary,
.box.box-success,
.box.box-warning,
.box.box-danger {
border-top-width: 3px;
}
.main-header .navbar { .main-header .navbar {
background-color: #272c30; background-color: #272c30;
} }
.main-header .navbar .nav > li > a, .main-header .navbar .nav > li > a,
.main-header .navbar .nav > li > .navbar-text { .main-header .navbar .nav > li > .navbar-text {
color: #bec5cb; color: #bec5cb;
max-height: 50px;
} }
.main-header .navbar .nav > li > a:hover, .main-header .navbar .nav > li > a:hover,
.main-header .navbar .nav > li > a:active, .main-header .navbar .nav > li > a:active,
@@ -280,7 +258,6 @@
background: rgba(64, 72, 80, 0.666); background: rgba(64, 72, 80, 0.666);
} }
.nav-tabs-custom > .nav-tabs > li { .nav-tabs-custom > .nav-tabs > li {
margin-right: 1px;
color: #bec5cb; color: #bec5cb;
} }
.nav-tabs-custom > .nav-tabs > li.active > a, .nav-tabs-custom > .nav-tabs > li.active > a,
@@ -389,11 +366,8 @@
code, code,
pre { pre {
padding: 2px 4px;
font-size: 90%;
color: #bec5cb; color: #bec5cb;
background-color: #353c42; background-color: #353c42;
border-radius: 4px;
} }
/* Used in the Query Log table */ /* Used in the Query Log table */
@@ -459,7 +433,6 @@
/* Used by the long-term pages */ /* Used by the long-term pages */
.daterangepicker { .daterangepicker {
background-color: #3e464c; background-color: #3e464c;
border-radius: 4px;
border: 1px solid #353c42; border: 1px solid #353c42;
} }
.daterangepicker .ranges li:hover { .daterangepicker .ranges li:hover {
@@ -470,7 +443,6 @@
} }
.daterangepicker .calendar-table { .daterangepicker .calendar-table {
background-color: #3e464c; background-color: #3e464c;
border-radius: 4px;
border: 1px solid #353c42; border: 1px solid #353c42;
} }
.daterangepicker td.off, .daterangepicker td.off,
@@ -537,7 +509,6 @@
.panel-body, .panel-body,
.panel-default > .panel-heading { .panel-default > .panel-heading {
background-color: #3e464c; background-color: #3e464c;
border-radius: 4px;
border: 1px solid #353c42; border: 1px solid #353c42;
color: #bec5cb; color: #bec5cb;
} }
@@ -570,23 +541,10 @@
background-image: linear-gradient(to right, #114100 0%, #525200 100%); background-image: linear-gradient(to right, #114100 0%, #525200 100%);
} }
.icheckbox_polaris,
.icheckbox_futurico,
.icheckbox_minimal-blue {
margin-right: 10px;
}
.iradio_polaris,
.iradio_futurico,
.iradio_minimal-blue {
margin-right: 8px;
}
/* Overlay box with spinners as shown during data collection for graphs */ /* Overlay box with spinners as shown during data collection for graphs */
.box .overlay, .box .overlay,
.overlay-wrapper .overlay { .overlay-wrapper .overlay {
z-index: 50;
background-color: rgba(53, 60, 66, 0.733); background-color: rgba(53, 60, 66, 0.733);
border-radius: 3px;
} }
.box .overlay > .fa, .box .overlay > .fa,
.overlay-wrapper .overlay > .fa, .overlay-wrapper .overlay > .fa,
@@ -596,7 +554,6 @@
.navbar-nav > .user-menu > .dropdown-menu > .user-footer { .navbar-nav > .user-menu > .dropdown-menu > .user-footer {
background-color: #353c42bb; background-color: #353c42bb;
padding: 10px;
} }
.modal-content { .modal-content {
@@ -625,36 +582,21 @@
border-color: rgb(120, 127, 133); border-color: rgb(120, 127, 133);
} }
/*** Additional fixes For Pi.Alert UI ***/
.small-box {
border-radius: 10px;
border-top: 0px;
}
.pa-small-box-aqua .inner { .pa-small-box-aqua .inner {
background-color: rgb(45,108,133); background-color: rgb(45,108,133);
border-top-left-radius: 10px;
border-top-right-radius: 10px;
} }
.pa-small-box-green .inner { .pa-small-box-green .inner {
background-color: rgb(31,76,46); background-color: rgb(31,76,46);
border-top-left-radius: 10px;
border-top-right-radius: 10px;
} }
.pa-small-box-yellow .inner { .pa-small-box-yellow .inner {
background-color: rgb(151,104,37); background-color: rgb(151,104,37);
border-top-left-radius: 10px;
border-top-right-radius: 10px;
} }
.pa-small-box-red .inner { .pa-small-box-red .inner {
background-color: rgb(120,50,38); background-color: rgb(120,50,38);
border-top-left-radius: 10px;
border-top-right-radius: 10px;
} }
.pa-small-box-gray .inner { .pa-small-box-gray .inner {
background-color: #777; background-color: #777;
/* color: rgba(20,20,20,30%); */ /* color: rgba(20,20,20,30%); */
border-top-left-radius: 10px;
border-top-right-radius: 10px;
} }
.pa-small-box-gray .inner h3 { .pa-small-box-gray .inner h3 {
color: #bbb; color: #bbb;
@@ -693,15 +635,6 @@
.db_tools_table_cell_b:nth-child(1) {background: #272c30} .db_tools_table_cell_b:nth-child(1) {background: #272c30}
.db_tools_table_cell_b:nth-child(2) {background: #272c30} .db_tools_table_cell_b:nth-child(2) {background: #272c30}
.db_info_table {
display: table;
border-spacing: 0em;
font-weight: 400;
font-size: 15px;
width: 100%;
margin: auto;
}
.nav-tabs-custom > .nav-tabs > li:hover > a, .nav-tabs-custom > .nav-tabs > li.active:hover > a { .nav-tabs-custom > .nav-tabs > li:hover > a, .nav-tabs-custom > .nav-tabs > li.active:hover > a {
background-color: #272c30; background-color: #272c30;
color: #bec5cb; color: #bec5cb;
@@ -723,15 +656,6 @@
color: white !important; color: white !important;
} }
/* remove white border that appears on mobile screen sizes */
.box-body {
border: 0px;
}
/* remove white border that appears on mobile screen sizes */
.table-responsive {
border: 0px;
}
.login-page { .login-page {
background-color: transparent; background-color: transparent;
} }
@@ -744,23 +668,6 @@
color: #bec5cb; color: #bec5cb;
background-color: #272c30; background-color: #272c30;
} }
/* Add border radius to bottom of the status boxes*/
.pa-small-box-footer {
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
}
.small-box > .inner h3, .small-box > .inner p {
margin-bottom: 0px;
margin-left: 0px;
}
.small-box:hover .icon {
font-size: 3em;
}
.small-box .icon {
top: 0.01em;
font-size: 3.25em;
}
.nax_semitransparent-panel{ .nax_semitransparent-panel{
background-color: #000 !important; background-color: #000 !important;
} }

View File

@@ -299,7 +299,7 @@ function updateChevrons(currentMac) {
showSpinner(); showSpinner();
cacheDevices().then(() => { cacheDevices(true).then(() => {
hideSpinner(); hideSpinner();
// Retry after re-caching // Retry after re-caching
@@ -384,25 +384,9 @@ $(document).on('input', 'input:text', function() {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
function initializeTabs () { function initializeTabs () {
initializeTabsShared({
key ="activeDevicesTab" cacheKey: 'activeDevicesTab',
defaultTab: 'tabDetails'
// Activate panel
if(!emptyArr.includes(getCache(key)))
{
selectedTab = getCache(key);
}
$('.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'))
});
// events on tab change
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
var target = $(e.target).attr("href") // activated tab
}); });
} }
@@ -419,7 +403,12 @@ async function renderSmallBoxes() {
const apiToken = getSetting("API_TOKEN"); const apiToken = getSetting("API_TOKEN");
const apiBaseUrl = getApiBase(); const apiBaseUrl = getApiBase();
const url = `${apiBaseUrl}/device/${getMac()}?period=${encodeURIComponent(period)}`; // Ensure period is a string, not an element
let periodValue = period;
if (typeof period === 'object' && period !== null && 'value' in period) {
periodValue = period.value;
}
const url = `${apiBaseUrl}/device/${getMac()}?period=${encodeURIComponent(periodValue)}`;
const response = await fetch(url, { const response = await fetch(url, {
method: "GET", method: "GET",
@@ -436,17 +425,22 @@ async function renderSmallBoxes() {
const deviceData = await response.json(); const deviceData = await response.json();
// Derive status card appearance from shared getStatusBadgeParts —
// ensures icon, color, label and lang key are always in sync with the rest of the UI.
const statusBadge = badgeFromDevice(deviceData);
const statusText = statusBadge.label;
// Prepare custom data // Prepare custom data
const customData = [ const customData = [
{ {
"onclickEvent": "$('#tabDetails').trigger('click')", "onclickEvent": "$('#tabDetails').trigger('click')",
"color": "bg-aqua", "color": statusBadge.cssClass,
"headerId": "deviceStatus", "headerId": "deviceStatus",
"headerStyle": "margin-left: 0em", "headerStyle": "margin-left: 0em",
"labelLang": "DevDetail_Shortcut_CurrentStatus", "labelLang": "DevDetail_Shortcut_CurrentStatus",
"iconId": "deviceStatusIcon", "iconId": "deviceStatusIcon",
"iconClass": deviceData.devPresentLastScan == 1 ? "fa fa-check text-green" : "fa fa-xmark text-red", "iconHtml": statusBadge.iconHtml,
"dataValue": deviceData.devPresentLastScan == 1 ? getString("Gen_Online") : getString("Gen_Offline") "dataValue": statusText
}, },
{ {
"onclickEvent": "$('#tabSessions').trigger('click');", "onclickEvent": "$('#tabSessions').trigger('click');",
@@ -513,7 +507,7 @@ function updateDevicePageName(mac) {
if (mac != 'new' && (name === null|| owner === null)) { if (mac != 'new' && (name === null|| owner === null)) {
console.warn("Device not found in cache, retrying after re-cache:", mac); console.warn("Device not found in cache, retrying after re-cache:", mac);
showSpinner(); showSpinner();
cacheDevices().then(() => { cacheDevices(true).then(() => {
hideSpinner(); hideSpinner();
// Retry after successful cache // Retry after successful cache
updateDevicePageName(mac); updateDevicePageName(mac);
@@ -553,20 +547,24 @@ function updateDevicePageName(mac) {
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
// Call renderSmallBoxes, then main
(async () => {
window.onload = function() {
// Always trigger app-init bootstrap
if (typeof executeOnce === 'function') {
executeOnce();
}
mac = getMac();
// Wait for app initialization (cache populated) before using cached data
callAfterAppInitialized(async () => {
updateDevicePageName(mac);
updateChevrons(mac);
await renderSmallBoxes(); await renderSmallBoxes();
main(); main();
})(); });
window.onload = function async()
{
mac = getMac()
// initializeTabs();
updateChevrons(mac);
updateDevicePageName(mac);
} }
</script> </script>

View File

@@ -17,7 +17,7 @@ require_once $_SERVER["DOCUMENT_ROOT"] . "/php/templates/security.php"; ?>
class="btn btn-default pa-btn pa-btn-delete" class="btn btn-default pa-btn pa-btn-delete"
style="margin-left:0px;" style="margin-left:0px;"
id="btnDelete" id="btnDelete"
onclick="askDeleteDevice()"> onclick="askDeleteDeviceByMac()">
<i class="fas fa-trash-alt"></i> <i class="fas fa-trash-alt"></i>
<?= lang("DevDetail_button_Delete") ?> <?= lang("DevDetail_button_Delete") ?>
</button> </button>
@@ -138,7 +138,7 @@ function getDeviceData() {
}, },
// Group for event and alert settings // Group for event and alert settings
DevDetail_EveandAl_Title: { DevDetail_EveandAl_Title: {
data: ["devAlertEvents", "devAlertDown", "devSkipRepeated", "devReqNicsOnline", "devChildrenNicsDynamic", "devForceStatus"], data: ["devAlertEvents", "devAlertDown", "devCanSleep", "devSkipRepeated", "devReqNicsOnline", "devChildrenNicsDynamic", "devForceStatus"],
docs: "https://docs.netalertx.com/NOTIFICATIONS", docs: "https://docs.netalertx.com/NOTIFICATIONS",
iconClass: "fa fa-bell", iconClass: "fa fa-bell",
inputGroupClasses: "field-group alert-group col-lg-4 col-sm-6 col-xs-12", inputGroupClasses: "field-group alert-group col-lg-4 col-sm-6 col-xs-12",
@@ -363,7 +363,7 @@ function getDeviceData() {
generateSimpleForm(relevantSettings); generateSimpleForm(relevantSettings);
toggleNetworkConfiguration(mac == 'Internet') toggleNetworkConfiguration(mac.toLowerCase() == 'internet')
initSelect2(); initSelect2();
initHoverNodeInfo(); initHoverNodeInfo();
@@ -423,7 +423,7 @@ function setDeviceData(direction = '', refreshCallback = '') {
// Build payload // Build payload
const payload = { const payload = {
devName: $('#NEWDEV_devName').val().replace(/'/g, ""), devName: $('#NEWDEV_devName').val(),
devOwner: $('#NEWDEV_devOwner').val().replace(/'/g, ""), devOwner: $('#NEWDEV_devOwner').val().replace(/'/g, ""),
devType: $('#NEWDEV_devType').val().replace(/'/g, ""), devType: $('#NEWDEV_devType').val().replace(/'/g, ""),
devVendor: $('#NEWDEV_devVendor').val().replace(/'/g, ""), devVendor: $('#NEWDEV_devVendor').val().replace(/'/g, ""),
@@ -432,7 +432,7 @@ function setDeviceData(direction = '', refreshCallback = '') {
devFavorite: ($('#NEWDEV_devFavorite')[0].checked * 1), devFavorite: ($('#NEWDEV_devFavorite')[0].checked * 1),
devGroup: $('#NEWDEV_devGroup').val().replace(/'/g, ""), devGroup: $('#NEWDEV_devGroup').val().replace(/'/g, ""),
devLocation: $('#NEWDEV_devLocation').val().replace(/'/g, ""), devLocation: $('#NEWDEV_devLocation').val().replace(/'/g, ""),
devComments: encodeSpecialChars($('#NEWDEV_devComments').val()), devComments: ($('#NEWDEV_devComments').val()),
devParentMAC: $('#NEWDEV_devParentMAC').val(), devParentMAC: $('#NEWDEV_devParentMAC').val(),
devParentPort: $('#NEWDEV_devParentPort').val(), devParentPort: $('#NEWDEV_devParentPort').val(),
@@ -447,6 +447,7 @@ function setDeviceData(direction = '', refreshCallback = '') {
devAlertEvents: ($('#NEWDEV_devAlertEvents')[0].checked * 1), devAlertEvents: ($('#NEWDEV_devAlertEvents')[0].checked * 1),
devAlertDown: ($('#NEWDEV_devAlertDown')[0].checked * 1), devAlertDown: ($('#NEWDEV_devAlertDown')[0].checked * 1),
devCanSleep: ($('#NEWDEV_devCanSleep')[0].checked * 1),
devSkipRepeated: $('#NEWDEV_devSkipRepeated').val().split(' ')[0], devSkipRepeated: $('#NEWDEV_devSkipRepeated').val().split(' ')[0],
devForceStatus: $('#NEWDEV_devForceStatus').val().replace(/'/g, ""), devForceStatus: $('#NEWDEV_devForceStatus').val().replace(/'/g, ""),
@@ -479,7 +480,12 @@ function setDeviceData(direction = '', refreshCallback = '') {
if (resp && resp.success) { if (resp && resp.success) {
showMessage(getString("Device_Saved_Success")); showMessage(getString("Device_Saved_Success"));
} else { } else {
showMessage(getString("Device_Saved_Unexpected"));
console.log(resp);
errorMessage = resp?.error;
showMessage(`${getString("Device_Saved_Unexpected")}: ${errorMessage}`, 5000, "modal_red");
} }
// Remove navigation prompt // Remove navigation prompt

View File

@@ -32,49 +32,62 @@
function loadEventsData() { function loadEventsData() {
const hideConnections = $('#chkHideConnectionEvents')[0].checked; const hideConnections = $('#chkHideConnectionEvents')[0].checked;
const hideConnectionsStr = hideConnections ? 'true' : 'false';
let period = $("#period").val(); let period = $("#period").val();
let { start, end } = getPeriodStartEnd(period); let { start, end } = getPeriodStartEnd(period);
const rawSql = ` const apiToken = getSetting("API_TOKEN");
SELECT eve_DateTime, eve_EventType, eve_IP, eve_AdditionalInfo const apiBase = getApiBase();
FROM Events const graphqlUrl = `${apiBase}/graphql`;
WHERE eve_MAC = "${mac}"
AND eve_DateTime BETWEEN "${start}" AND "${end}" const query = `
AND ( query Events($options: EventQueryOptionsInput) {
(eve_EventType NOT IN ("Connected", "Disconnected", "VOIDED - Connected", "VOIDED - Disconnected")) events(options: $options) {
OR "${hideConnectionsStr}" = "false" count
) entries {
eveDateTime
eveEventType
eveIp
eveAdditionalInfo
}
}
}
`; `;
const apiToken = getSetting("API_TOKEN");
const apiBaseUrl = getApiBase();
const url = `${apiBaseUrl}/dbquery/read`;
$.ajax({ $.ajax({
url: url, url: graphqlUrl,
method: "POST", method: "POST",
contentType: "application/json", contentType: "application/json",
headers: { headers: {
"Authorization": `Bearer ${apiToken}` "Authorization": `Bearer ${apiToken}`
}, },
data: JSON.stringify({ data: JSON.stringify({
rawSql: btoa(rawSql) query,
variables: {
options: {
eveMac: mac,
dateFrom: start,
dateTo: end,
limit: 500,
sort: [{ field: "eveDateTime", order: "desc" }]
}
}
}), }),
success: function (data) { success: function (data) {
// assuming read_query returns rows directly const CONNECTION_TYPES = ["Connected", "Disconnected", "VOIDED - Connected", "VOIDED - Disconnected"];
const rows = data["results"].map(row => {
const rawDate = row.eve_DateTime; const rows = data.data.events.entries
.filter(row => !hideConnections || !CONNECTION_TYPES.includes(row.eveEventType))
.map(row => {
const rawDate = row.eveDateTime;
const formattedDate = rawDate ? localizeTimestamp(rawDate) : '-'; const formattedDate = rawDate ? localizeTimestamp(rawDate) : '-';
return [ return [
formattedDate, formattedDate,
row.eve_DateTime, row.eveDateTime,
row.eve_EventType, row.eveEventType,
row.eve_IP, row.eveIp,
row.eve_AdditionalInfo row.eveAdditionalInfo
]; ];
}); });
@@ -116,7 +129,7 @@ function initializeEventsDatatable (eventsRows) {
{ {
targets: [0], targets: [0],
'createdCell': function (td, cellData, rowData, row, col) { 'createdCell': function (td, cellData, rowData, row, col) {
$(td).html(translateHTMLcodes(localizeTimestamp(cellData))); $(td).html(translateHTMLcodes((cellData)));
} }
} }
], ],

View File

@@ -121,12 +121,12 @@ function loadSessionsData() {
if (data.success && data.sessions.length) { if (data.success && data.sessions.length) {
data.sessions.forEach(session => { data.sessions.forEach(session => {
table.row.add([ table.row.add([
session.ses_DateTimeOrder, session.sesDateTimeOrder,
session.ses_Connection, session.sesConnection,
session.ses_Disconnection, session.sesDisconnection,
session.ses_Duration, session.sesDuration,
session.ses_IP, session.sesIp,
session.ses_Info session.sesInfo
]); ]);
}); });
} }

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