From 71039ed6601f2512d04fd729910b52542b015189 Mon Sep 17 00:00:00 2001 From: zwang <30325083+deadlywang@users.noreply.github.com> Date: Fri, 19 Jun 2026 13:28:12 -0500 Subject: [PATCH 1/4] escaped string to network manager bytes --- networking/generate_network_config.py | 28 +++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/networking/generate_network_config.py b/networking/generate_network_config.py index f4dbbfb..f42db05 100644 --- a/networking/generate_network_config.py +++ b/networking/generate_network_config.py @@ -6,9 +6,35 @@ import os import stat import ipaddress +import re + +HEX_ESCAPE_RE = re.compile(r'\\x([0-9A-Fa-f]{2})') SYS_CON_DIR = "/etc/NetworkManager/system-connections" +def is_escaped_essid(essid: str) -> bool: + """True if the ESSID contains at least one \\xHH hex escape sequence.""" + return HEX_ESCAPE_RE.search(essid) is not None + +def bytes_to_nm_ssid_value(raw: bytes) -> str: + return ";".join(str(b) for b in raw) + ";" + +def unescape_regex(essid: str) -> bytes: + """ + Only touch \\xHH sequences with a targeted regex substitution, leave + every other character exactly as-is, then encode the result as Latin-1 + (a 1:1 char -> byte mapping) to recover the raw bytes. + """ + unescaped_chars = HEX_ESCAPE_RE.sub(lambda m: chr(int(m.group(1), 16)), essid) + return unescaped_chars.encode("latin-1") + +def build_ssid_value(raw_essid_from_iwlist: str) -> str: + """Return the exact text to put after 'ssid=' in the .nmconnection file.""" + if is_escaped_essid(raw_essid_from_iwlist): + raw_bytes = unescape_regex(raw_essid_from_iwlist) + return bytes_to_nm_ssid_value(raw_bytes) + return raw_essid_from_iwlist + def calculate_brd_by_hand(address: str, netmask: str) -> str: return format(ipaddress.IPv4Network(f"{address}/{netmask}", strict=False).broadcast_address) @@ -122,6 +148,8 @@ def get_wireless_conn_file(config: ConfigGroup): ssid = escape_backslashes_for_network_manager(ssid) psk = escape_backslashes_for_network_manager(psk) + ssid = build_ssid_value(ssid) + file = [ "[connection]", "id=wireless", From 3fc86be19936d4d6c43eac77d5b2ba276000efae Mon Sep 17 00:00:00 2001 From: zwang <30325083+deadlywang@users.noreply.github.com> Date: Fri, 19 Jun 2026 13:52:31 -0500 Subject: [PATCH 2/4] adjust ssid processing sequence so no extra "92;" in the bytes sequence. --- networking/generate_network_config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/networking/generate_network_config.py b/networking/generate_network_config.py index f42db05..126a3e5 100644 --- a/networking/generate_network_config.py +++ b/networking/generate_network_config.py @@ -145,11 +145,11 @@ def get_wireless_conn_file(config: ConfigGroup): psk = config.get("wireless-password") connect = "true" if config.get("wireless-network") else "false" + ssid = build_ssid_value(ssid) + ssid = escape_backslashes_for_network_manager(ssid) psk = escape_backslashes_for_network_manager(psk) - ssid = build_ssid_value(ssid) - file = [ "[connection]", "id=wireless", From 83533b48aa71e29e3a2558568b707938d59c0504 Mon Sep 17 00:00:00 2001 From: zwang <30325083+deadlywang@users.noreply.github.com> Date: Wed, 24 Jun 2026 10:50:54 -0500 Subject: [PATCH 3/4] change the function name for easier understanding --- networking/generate_network_config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/networking/generate_network_config.py b/networking/generate_network_config.py index 126a3e5..9201f9a 100644 --- a/networking/generate_network_config.py +++ b/networking/generate_network_config.py @@ -28,7 +28,7 @@ def unescape_regex(essid: str) -> bytes: unescaped_chars = HEX_ESCAPE_RE.sub(lambda m: chr(int(m.group(1), 16)), essid) return unescaped_chars.encode("latin-1") -def build_ssid_value(raw_essid_from_iwlist: str) -> str: +def escaped_hex_to_bytes_string(raw_essid_from_iwlist: str) -> str: """Return the exact text to put after 'ssid=' in the .nmconnection file.""" if is_escaped_essid(raw_essid_from_iwlist): raw_bytes = unescape_regex(raw_essid_from_iwlist) @@ -145,7 +145,7 @@ def get_wireless_conn_file(config: ConfigGroup): psk = config.get("wireless-password") connect = "true" if config.get("wireless-network") else "false" - ssid = build_ssid_value(ssid) + ssid = escaped_hex_to_bytes_string(ssid) ssid = escape_backslashes_for_network_manager(ssid) psk = escape_backslashes_for_network_manager(psk) From 57c9a61958eaf9d49c0a34cdddc354e95e606d02 Mon Sep 17 00:00:00 2001 From: zwang <30325083+deadlywang@users.noreply.github.com> Date: Wed, 24 Jun 2026 16:07:41 -0500 Subject: [PATCH 4/4] added various ssid test cases to test_generate_network_config --- networking/test_generate_network_config.py | 66 +++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/networking/test_generate_network_config.py b/networking/test_generate_network_config.py index b2164dd..c8a8463 100644 --- a/networking/test_generate_network_config.py +++ b/networking/test_generate_network_config.py @@ -226,7 +226,71 @@ def get(k): c.get = Mock(side_effect=get) template = get_wireless_conn_file(c) assert template == wireless_template.format("method=auto") - + + @mock.patch("generate_network_config.configure_static_network", side_effect=mock_csn) + def test_get_wireless_conn_file_ascii_ssid(self, csn_mock): + """Test ASCII-only SSID like 'MyNetwork' from iwlist.""" + c = Mock() + + def get(k): + if k == "wireless-type": + return "dhcp" + elif k == "wireless-ssid": + return "MyNetwork" # ASCII SSID + elif k == "wireless-password": + return "password123" + else: + return None + c.get = Mock(side_effect=get) + + template = get_wireless_conn_file(c) + # Verify ssid=MyNetwork appears in output (ASCII SSIDs pass through unchanged) + assert "ssid=MyNetwork" in template + assert "psk=password123" in template + assert "method=auto" in template + + @mock.patch("generate_network_config.configure_static_network", side_effect=mock_csn) + def test_get_wireless_conn_file_mixed_ssid(self, csn_mock): + """Test mixed ASCII and non-ASCII SSID.""" + c = Mock() + + def get(k): + if k == "wireless-type": + return "dhcp" + elif k == "wireless-ssid": + # München in UTF-8 hex escapes (as iwlist would output) + return r"M\xC3\xBCnchen" + elif k == "wireless-password": + return "password123" + else: + return None + c.get = Mock(side_effect=get) + + template = get_wireless_conn_file(c) + # Verify ssid=77;195;188;110;99;104;101;110; (byte values for München) + assert "ssid=77;195;188;110;99;104;101;110;" in template + + @mock.patch("generate_network_config.configure_static_network", side_effect=mock_csn) + def test_get_wireless_conn_file_non_ascii_ssid(self, csn_mock): + """Test non-ASCII SSID from iwlist hex-escaped output.""" + c = Mock() + + def get(k): + if k == "wireless-type": + return "dhcp" + elif k == "wireless-ssid": + # "😂" -(non-ASCII) + return r"\xF0\x9F\x98\x82" + elif k == "wireless-password": + return "password123" + else: + return None + c.get = Mock(side_effect=get) + + template = get_wireless_conn_file(c) + # Verify correct byte conversion for mixed SSID + assert "ssid=240;159;152;130;" in template + def test_calculate_brd_by_hand(self): brd = calculate_brd_by_hand("192.168.1.24", 8) assert brd == "192.255.255.255"