diff --git a/front/js/network-tabs.js b/front/js/network-tabs.js index 708af683..c7e6db02 100644 --- a/front/js/network-tabs.js +++ b/front/js/network-tabs.js @@ -13,7 +13,7 @@ function renderNetworkTabs(nodes) { (node.devAlertDown == 1 ? "text-red" : "text-gray50")); const portLabel = node.node_ports_count ? ` (${node.node_ports_count})` : ''; - const icon = atob(node.devIcon); + const icon = safeAtob(node.devIcon); const id = node.devMac.replace(/:/g, '_'); html += ` diff --git a/front/js/ui_components.js b/front/js/ui_components.js index 34c2cb3e..4fcf96fe 100755 --- a/front/js/ui_components.js +++ b/front/js/ui_components.js @@ -971,6 +971,9 @@ function renderDeviceLink(data, container, useName = false) { // Build and return badge parts const badge = badgeFromDevice(device); + // Decode once (with a safe fallback) and reuse for both the chip and hover preview + const decodedIcon = safeAtob(device.devIcon); + // badge class and hover-info class to container $(container) .addClass(`${badge.cssClass} hover-node-info`) @@ -990,13 +993,13 @@ function renderDeviceLink(data, container, useName = false) { 'data-sleeping': device.devIsSleeping || 0, 'data-archived': device.devIsArchived || 0, 'data-isnew': device.devIsNew || 0, - 'data-icon': device.devIcon + 'data-icon': decodedIcon }); return ` - ${device.devIcon ? atob(device.devIcon) : ''} + ${decodedIcon} ${useName ? encodeSpecialChars(device.devName) : data.text} (${badge.iconHtml}) @@ -1006,6 +1009,17 @@ function renderDeviceLink(data, container, useName = false) { `; } +// ------------------------------------------ +// Base64-decode a devIcon value, tolerating missing/empty/malformed input +function safeAtob(value) { + if (!value) return ''; + try { + return atob(value); + } catch (e) { + return ''; + } +} + // ------------------------------------------ // Display device info on hover (attach only once) function initHoverNodeInfo() { @@ -1063,7 +1077,7 @@ function initHoverNodeInfo() { const html = `
-
${atob(icon)}
${encodeSpecialChars(name)}
+
${icon || ''}
${encodeSpecialChars(name)}

diff --git a/server/database.py b/server/database.py index bffdde9a..4e63ad43 100755 --- a/server/database.py +++ b/server/database.py @@ -228,7 +228,6 @@ class DB: ensure_mac_lowercase_triggers(self.sql) # Prevent/repair dangling devParentMAC references left by deleted devices - ensure_dangling_parentmac_cleanup_trigger(self.sql) cleanup_existing_dangling_parentmac(self.sql) # Device history table + audit triggers @@ -246,9 +245,10 @@ class DB: AppEvent_obj(self) # AppEvent_obj.drop_all_triggers() wipes every trigger in the DB - # (including trg_devhist_*) as part of its clean-start routine. - # Re-create the device history audit triggers here so they survive. + # (including trg_devhist_* and trg_clear_dangling_parentmac_on_delete) + # as part of its clean-start routine. Re-create them here so they survive. ensure_deviceshistory_triggers(self.sql) + ensure_dangling_parentmac_cleanup_trigger(self.sql) self.commitDB() def get_table_as_json(self, sqlQuery, parameters=None): diff --git a/server/scan/device_handling.py b/server/scan/device_handling.py index a604e28b..59e5149c 100755 --- a/server/scan/device_handling.py +++ b/server/scan/device_handling.py @@ -10,6 +10,7 @@ from models.device_instance import DeviceInstance from scan.name_resolution import NameResolver from scan.device_heuristics import guess_icon, guess_type from db.db_helper import sanitize_SQL_input, list_to_where, safe_int +from db.db_upgrade import PARENT_MAC_SENTINELS from db.authoritative_handler import ( get_overwrite_sql_clause, can_overwrite_field, @@ -734,7 +735,7 @@ def create_new_devices(db): # to a MAC that no longer exists (e.g. that device was since deleted) - # falling back to unset rather than seeding new devices with a dangling reference. default_parent_mac_setting = get_setting_value("NEWDEV_devParentMAC") - if default_parent_mac_setting: + if default_parent_mac_setting and default_parent_mac_setting.lower() not in PARENT_MAC_SENTINELS: existing_device_macs = { str(row[0]).lower() for row in sql.execute("SELECT devMac FROM Devices").fetchall() if row[0] }