Skip to content
8 changes: 7 additions & 1 deletion pyoverkiz/obfuscate.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def obfuscate_email(email: str | None) -> str:

def obfuscate_string(value: str) -> str:
"""Mask string."""
return re.sub(r"[a-zA-Z0-9_.-]*", "*", str(value))
return re.sub(r"[\w.-]+", "*", str(value), flags=re.UNICODE)


def _obfuscate_value(key: str, value: Any, mask_next_value: bool) -> tuple[Any, bool]:
Expand Down Expand Up @@ -49,6 +49,12 @@ def _obfuscate_value(key: str, value: Any, mask_next_value: bool) -> tuple[Any,
"homekit:SetupPayload",
"core:SSIDState",
"core:NetworkMacState",
"internal:CurrentInfraConfigState",
"core:LocalIPv4AddressState",
"core:IPAddress",
"core:MacAddress",
"core:SerialNumber",
"core:DeviceSerialNumberState",
):
mask_next_value = True

Expand Down
69 changes: 68 additions & 1 deletion tests/test_obfuscate.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

import pytest

from pyoverkiz.obfuscate import obfuscate_email, obfuscate_sensitive_data
from pyoverkiz.obfuscate import (
obfuscate_email,
obfuscate_sensitive_data,
obfuscate_string,
)

LOCAL_HOST = "gateway-1234-5678-1243.local:8443"
LOCAL_HOST_BY_IP = "192.168.1.105:8443"
Expand All @@ -23,6 +27,28 @@ def test_email_obfuscate(self, email: str, obfuscated: str):
assert obfuscate_email(email) == obfuscated


class TestObfuscateString:
"""Tests for obfuscate_string with various character sets."""

@pytest.mark.parametrize(
("value", "expected"),
[
("My Room", "* *"),
("Séjour", "*"),
("Étage", "*"),
("Entrée", "*"),
("Volet Fenêtre", "* *"),
("Ré-de-chaussée", "*"),
("Büro", "*"),
("abc123", "*"),
("", ""),
],
)
def test_obfuscate_string(self, value: str, expected: str):
"""Verify string obfuscation handles Unicode characters."""
assert obfuscate_string(value) == expected


class TestObfucscateSensitive:
"""Tests around obfuscating sensitive structures while preserving non-sensitive content."""

Expand Down Expand Up @@ -71,3 +97,44 @@ def test_obfuscate_list_of_dicts(self):
assert result[0]["oid"] == "abc-123" # oid is not a sensitive key
assert result[1]["label"] != "Night Mode"
assert result[1]["deviceURL"] != "io://1234-5678-1234/12345678"

def test_obfuscate_infra_config_state(self):
"""Ensure internal:CurrentInfraConfigState value is redacted."""
data = {
"name": "internal:CurrentInfraConfigState",
"type": 3,
"value": "wifi_ssid:MyNetwork;password:secret123",
}
result = obfuscate_sensitive_data(data)
assert result["name"] == "internal:CurrentInfraConfigState"
assert result["value"] != "wifi_ssid:MyNetwork;password:secret123"

@pytest.mark.parametrize(
"state_name",
[
"core:NameState",
"homekit:SetupCode",
"homekit:SetupPayload",
"core:SSIDState",
"core:NetworkMacState",
"internal:CurrentInfraConfigState",
"core:LocalIPv4AddressState",
"core:IPAddress",
"core:MacAddress",
"core:SerialNumber",
"core:DeviceSerialNumberState",
],
)
def test_obfuscate_sensitive_states(self, state_name: str):
"""Ensure all sensitive state names trigger value redaction."""
data = {"name": state_name, "type": 3, "value": "sensitive_data"}
result = obfuscate_sensitive_data(data)
assert result["name"] == state_name
assert result["value"] != "sensitive_data"

def test_obfuscate_unicode_label(self):
"""Ensure labels with Unicode characters are fully redacted."""
data = {"label": "Volet Séjour"}
result = obfuscate_sensitive_data(data)
assert "Séjour" not in result["label"]
assert "é" not in result["label"]
Loading