The previous implementation derived the guest WiFi device MAC using a
custom MD5 hash of the Fritz!Box hardware MAC, producing a
locally-administered address with a 02: prefix. This was inconsistent
with the project-wide convention of using string_to_fake_mac() from
crypto_utils, which produces a fa:ce: prefixed address and is used by
all other plugins (nmap_dev_scan, adguard_import, pihole_api_scan, etc.).
A naive switch to string_to_fake_mac(host) would have introduced a
stability problem: if the user reconfigures FRITZBOX_HOST from an IP
address (e.g. 192.168.178.1) to a hostname (e.g. fritz.box), the fake
MAC would change and the guest device would re-appear as a new unknown
device in NetAlertX. The Fritz!Box hardware MAC is a stable identifier
that does not change with the configured host string.
Requested by reviewer jokob-sk in PR #1592.
Changes:
- Remove import hashlib (fritzbox.py:3) — no longer needed
- Add import string_to_fake_mac from utils.crypto_utils (fritzbox.py:15)
- Replace custom MD5-based MAC derivation in create_guest_wifi_device()
with string_to_fake_mac(normalize_mac(fritzbox_mac)) (fritzbox.py:178)
The Fritz!Box hardware MAC is fetched via TR-064 as before, but is now
passed to the shared project utility instead of a custom hash.
- Add host parameter to create_guest_wifi_device(fc, host) (fritzbox.py:169)
Used as fallback input to string_to_fake_mac() if the hardware MAC
cannot be retrieved.
- Update call site in main() to pass host (fritzbox.py:224)
The guest WiFi device MAC is now stable across host configuration changes
and consistent with the fa:ce: prefix convention used across the project.
Requested by reviewer jokob-sk in PR #1592.
Changes:
- Replace generic author "NetAlertX Community" with @sebingel
(README.md:204)
- Update release date from January 2026 to April 2026
(README.md:205)
- Remove license field from version section (README.md:206)
Project license is defined at repository level and does not need
to be repeated in individual plugin READMEs.
- Update repository link from jokob-sk/NetAlertX to netalertx/NetAlertX
(README.md:211)
The project was transferred to the netalertx organisation; the
canonical URL is now github.com/netalertx/NetAlertX.
The fritzconnection imports were originally placed inside the function
bodies as a defensive pattern: by catching ImportError locally,
get_fritzbox_connection() and get_connected_devices() could each return
None or an empty list with a user-friendly log message instead of
crashing at import time. This kept the plugin runnable even when the
dependency was missing.
Requested by reviewer jokob-sk in PR #1592: move all imports to the top
of the module, treating fritzconnection as a required dependency that is
assumed to be installed via requirements.txt.
Changes:
- Add top-level imports for FritzConnection and FritzHosts
(fritzbox.py:16-17)
- Remove inline import and ImportError handler from
get_fritzbox_connection() (fritzbox.py:48, 64-67)
- Remove inline import and ImportError handler from
get_connected_devices() (fritzbox.py:79, 133-134)
Functional behavior of the plugin is unchanged.
The device information table in README.md incorrectly stated that the
Connection Status field ("Active"/"Inactive") maps to devVendor in the
devices table. In reality, watchedValue2 has no mapped_to_column entry
in config.json, meaning the value is stored only in the plugin's own
Plugins_FRITZBOX table and never promoted to the Devices table. A user
following the documentation to filter or display Connection Status via
devVendor would find no data there.
Changes:
- Correct the "Mapped To" column for Connection Status (README.md:86)
Changed from "`devVendor` (shown as vendor field)" to "Plugin table
only (not mapped to device fields)" to accurately reflect config.json
behavior.
Users now have a correct expectation: Connection Status is visible in
the Fritz!Box plugin view but not in standard device columns. No
functional code was changed.
Two independent reliability problems were identified during PR readiness
review. First, FritzConnection had no explicit timeout, meaning an
unreachable or slow Fritz!Box would block the plugin process indefinitely
until the OS TCP timeout fired (typically 2+ minutes), making the 60s
RUN_TIMEOUT in config.json ineffective. Second, hashlib.md5() called
without usedforsecurity=False raises ValueError on FIPS-enforced systems
(common in enterprise Docker hosts), silently breaking the guest WiFi
synthetic device feature for those users.
Changes:
- Add timeout=10 to FritzConnection(...) call (fritzbox.py:57)
The fritzconnection library accepts a timeout parameter directly in
__init__; it applies per individual HTTP request to the Fritz!Box,
bounding each TR-064 call including the initial connection handshake.
- Add usedforsecurity=False to hashlib.md5() call (fritzbox.py:191)
The MD5 hash is used only for deterministic MAC derivation (not for
any security purpose), so the flag is semantically correct and lifts
the FIPS restriction without changing the computed value.
- Update test assertion to include timeout=10 (test_fritzbox.py:307)
assert_called_once_with checks the exact call signature; the test
expectation must match the updated production code.
The plugin now fails fast on unreachable Fritz!Box (within 10s per
request) and works correctly on FIPS-enabled hosts. Default behavior
for standard deployments is unchanged.
The Fritz!Box plugin config.json only contained English (en_us) strings
for all translatable fields. NetAlertX supports 21 languages and shows
the plugin description and all setting labels in the user's chosen
language. Without translations, every non-English user sees raw English
text for the plugin card description, setting names, and setting
explanations regardless of their language preference.
Changes:
- front/plugins/fritzbox/config.json: added 20 translations for the
top-level plugin `description` field (all 21 supported languages)
- front/plugins/fritzbox/config.json: added translations for `name` and
`description` fields in all 14 settings (RUN, RUN_SCHD, HOST, PORT,
USER, PASS, USE_TLS, REPORT_GUEST, GUEST_SERVICE, ACTIVE_ONLY, CMD,
RUN_TIMEOUT, SET_ALWAYS, SET_EMPTY)
Selectively translated by field type:
- 12 settings: 21 languages for both name and description
- HOST (name "Fritz!Box Host") and PORT (name "TR-064 Port"): name
kept as en_us only — these are language-neutral proper names and
standard identifiers; description translated in all 21 languages
Technical terms left untranslated in all languages: Fritz!Box, TR-064,
HTTPS, HTTP, WLANConfiguration, and all code identifiers referenced
in descriptions (schedule, NEWDEV, Source = USER, Source = LOCKED)
Total: 544 localized strings added across 21 languages (ar_ar, ca_ca,
cs_cz, de_de, es_es, fa_fa, fr_fr, id_id, it_it, ja_jp, nb_no, pl_pl,
pt_br, pt_pt, ru_ru, sv_sv, tr_tr, uk_ua, vi_vn, zh_cn).
Users in all supported languages now see the plugin description card and
every setting label in their own language. The existing en_us fallback
mechanism ensures forward compatibility with any future languages added
to the project.
NetAlertX had no native support for discovering devices connected to
Fritz!Box routers. Users relying on Fritz!Box as their primary home
router had to use generic network scanning (ARP/ICMP), missing
Fritz!Box-specific details like interface type (WiFi/LAN) and
connection status per device.
Changes:
- Add plugin implementation (front/plugins/fritzbox/fritzbox.py)
Queries all hosts via FritzHosts TR-064 service, normalizes MACs,
maps interface types (802.11→WiFi, Ethernet→LAN), and writes results
to CurrentScan via Plugin_Objects. Supports filtering to active-only
devices and optional guest WiFi monitoring via a synthetic AP device
with a deterministic locally-administered MAC (02:xx derived from
Fritz!Box MAC via MD5).
- Add plugin configuration (front/plugins/fritzbox/config.json)
Defines plugin_type "device_scanner" with settings for host, port,
credentials, guest WiFi reporting, and active-only filtering.
Maps scan columns to CurrentScan fields (scanMac, scanLastIP, scanName,
scanType). Default schedule: every 5 minutes.
- Add plugin documentation (front/plugins/fritzbox/README.md)
Covers TR-064 protocol basics, quick setup guide, all settings with
defaults, troubleshooting for common issues (connection refused, auth
failures, no devices found), and technical details.
- Add fritzconnection>=1.15.1 dependency (requirements.txt)
Required Python library for TR-064 communication with Fritz!Box.
- Add test suite (test/plugins/test_fritzbox.py:1-298)
298 lines covering get_connected_devices (active filtering, MAC
normalization, interface mapping, error resilience), check_guest_wifi_status
(service detection, SSID-based guest detection, fallback behavior), and
create_guest_wifi_device (deterministic MAC generation, locally-administered
bit, fallback MAC, regression anchor with precomputed hash).
Users can now scan Fritz!Box-connected devices natively, seeing per-device
connection status and interface type directly in NetAlertX. Guest WiFi
monitoring provides visibility into guest network state. The plugin
defaults to HTTPS on port 49443 with active-only filtering enabled.
The rename of the elementOptions key from "ordeable" to "orderable" (part of
#1584) updated handleElementOptions() in settings_utils.js to return the
property as isOrderable. However, multiEditCore.php still destructured the
old name isOrdeable from that return value (line 139). Because JavaScript
object destructuring resolves properties by name, isOrdeable would silently
evaluate to undefined — no runtime error, just a broken binding.
The bug was masked because isOrdeable is not referenced after destructuring
in the current code of multiEditCore.php. The incorrect binding would become
a functional regression as soon as that code path is extended to actually
consume the orderable flag (e.g. to conditionally apply select2 sorting in
the multi-edit form).
Changes:
- front/multiEditCore.php:139 — isOrdeable → isOrderable
Aligns the destructured property name with the renamed return key of
handleElementOptions() so the binding resolves to the correct boolean
value instead of undefined.
All 35 previously updated files already use the correct spelling; this was
the single remaining inconsistency. After this commit, grep for "isOrdeable"
and "ordeable" across front/ and server/ returns zero results.
The key 'ordeable' in elementOptions was a long-standing typo for the
correct English word 'orderable'. Since the JS check in settings_utils.js
used the same misspelled key, the feature appeared to work — but it was
relying on the consistent propagation of a typo across the entire codebase.
Two pre-existing entries in front/plugins/ui_settings/config.json already
used the correct spelling 'orderable', but these had no effect because the
JavaScript check (option.ordeable === 'true') never matched them. As a
result, orderable behavior was silently disabled for those two settings.
Changes:
- front/js/settings_utils.js: renamed option.ordeable → option.orderable
and isOrdeable → isOrderable (6 occurrences, lines 792/823/824/880/1079/
1192/1228). The JS key check is the authoritative definition of the
elementOptions property name, so this must change atomically with all
config files.
- server/initialise.py:245: renamed "ordeable" → "orderable" in the
hardcoded JSON string for LOADED_PLUGINS setting. This string is the
source-of-truth for that setting's elementOptions and is not auto-
generated from the plugin config files.
- front/plugins/*/config.json (33 files, 90 occurrences): renamed all
"ordeable": "true" entries to "orderable": "true" via sed. All plugins
used the typo consistently; they must be updated in the same commit to
avoid a broken intermediate state.
The two formerly broken 'orderable' entries in ui_settings/config.json
are now matched by the corrected JS check and work as intended.
Fixesnetalertx/NetAlertX#1584
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 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.
- 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.