FIX: lowercase MAC normalization across project v0.1

Signed-off-by: jokob-sk <jokob.sk@gmail.com>
This commit is contained in:
jokob-sk
2026-02-07 13:44:50 +11:00
parent 3734c43284
commit 946ad00253
22 changed files with 164 additions and 257 deletions

View File

@@ -64,9 +64,9 @@ ALLOWED_EVENT_TYPES = Literal[
def validate_mac(value: str) -> str:
"""Validate and normalize MAC address format."""
# Allow "Internet" as a special case for the gateway/WAN device
# Allow "internet" as a special case for the gateway/WAN device
if value.lower() == "internet":
return "Internet"
return "internet"
if not is_mac(value):
raise ValueError(f"Invalid MAC address format: {value}")
@@ -439,7 +439,7 @@ class DeviceUpdateRequest(BaseModel):
def sanitize_text_fields(cls, v: Optional[str]) -> Optional[str]:
if v is None:
return v
return sanitize_string(v)
return v
class DeleteDevicesRequest(BaseModel):

View File

@@ -16,6 +16,7 @@ from db.db_upgrade import (
ensure_Parameters,
ensure_Settings,
ensure_Indexes,
ensure_mac_lowercase_triggers,
)
@@ -198,6 +199,9 @@ class DB:
# Indexes
ensure_Indexes(self.sql)
# Normalization triggers
ensure_mac_lowercase_triggers(self.sql)
# commit changes
self.commitDB()
except Exception as e:

View File

@@ -105,6 +105,50 @@ def ensure_column(sql, table: str, column_name: str, column_type: str) -> bool:
return False
def ensure_mac_lowercase_triggers(sql):
"""
Ensures the triggers for lowercasing MAC addresses exist on the Devices table.
"""
try:
# 1. Handle INSERT Trigger
sql.execute("SELECT name FROM sqlite_master WHERE type='trigger' AND name='trg_lowercase_mac_insert'")
if not sql.fetchone():
mylog("verbose", ["[db_upgrade] Creating trigger 'trg_lowercase_mac_insert'"])
sql.execute("""
CREATE TRIGGER trg_lowercase_mac_insert
AFTER INSERT ON Devices
BEGIN
UPDATE Devices
SET devMac = LOWER(NEW.devMac),
devParentMAC = LOWER(NEW.devParentMAC)
WHERE rowid = NEW.rowid;
END;
""")
# 2. Handle UPDATE Trigger
sql.execute("SELECT name FROM sqlite_master WHERE type='trigger' AND name='trg_lowercase_mac_update'")
if not sql.fetchone():
mylog("verbose", ["[db_upgrade] Creating trigger 'trg_lowercase_mac_update'"])
# Note: Using 'WHEN' to prevent unnecessary updates and recursion
sql.execute("""
CREATE TRIGGER trg_lowercase_mac_update
AFTER UPDATE OF devMac, devParentMAC ON Devices
WHEN (NEW.devMac GLOB '*[A-Z]*') OR (NEW.devParentMAC GLOB '*[A-Z]*')
BEGIN
UPDATE Devices
SET devMac = LOWER(NEW.devMac),
devParentMAC = LOWER(NEW.devParentMAC)
WHERE rowid = NEW.rowid;
END;
""")
return True
except Exception as e:
mylog("none", [f"[db_upgrade] ERROR while ensuring MAC triggers: {e}"])
return False
def ensure_views(sql) -> bool:
"""
Ensures required views exist.

View File

@@ -358,7 +358,7 @@ def importConfigs(pm, db, all_plugins):
"Router",
"USB LAN Adapter",
"USB WIFI Adapter",
"Internet",
"internet",
],
c_d,
"Network device types",

View File

@@ -495,7 +495,7 @@ class DeviceInstance:
# Fetch children
cur.execute(
"SELECT * FROM Devices WHERE devParentMAC = ? ORDER BY devPresentLastScan DESC",
"SELECT * FROM Devices WHERE LOWER(devParentMAC) = LOWER(?) ORDER BY devPresentLastScan DESC",
(device_data["devMac"],),
)
children_rows = cur.fetchall()

View File

@@ -728,10 +728,10 @@ def create_new_devices(db):
scanParentMAC = raw_parent_mac
scanParentMAC = (
scanParentMAC
if scanParentMAC and scanMac != "Internet"
if scanParentMAC and scanMac.lower() != "internet"
else (
get_setting_value("NEWDEV_devParentMAC")
if scanMac != "Internet"
if scanMac.lower() != "internet"
else "null"
)
)
@@ -1243,7 +1243,7 @@ def update_devPresentLastScan_based_on_force_status(db):
# -------------------------------------------------------------------------------
# Check if the variable contains a valid MAC address or "Internet"
# Check if the variable contains a valid MAC address or "internet"
def check_mac_or_internet(input_str):
# Regular expression pattern for matching a MAC address
mac_pattern = r"([0-9A-Fa-f]{2}[:-][0-9A-Fa-f]{2}[:-][0-9A-Fa-f]{2}[:-][0-9A-Fa-f]{2}[:-][0-9A-Fa-f]{2}[:-][0-9A-Fa-f]{2})"

View File

@@ -179,7 +179,7 @@ def guess_device_attributes(
# # Internet shortcut
# if mac == "INTERNET":
# return ICONS.get("globe", default_icon), DEVICE_TYPES.get("Internet", default_type)
# return ICONS.get("globe", default_icon), DEVICE_TYPES.get("internet", default_type)
type_ = None
icon = None