diff --git a/.coverage b/.coverage new file mode 100644 index 0000000..946a518 Binary files /dev/null and b/.coverage differ diff --git a/server/utils.py b/server/utils.py index f6126df..3646d06 100644 --- a/server/utils.py +++ b/server/utils.py @@ -91,10 +91,10 @@ def get_client_ip(request) -> str: return request.remote_addr or "" -def get_mac_from_arp(ip: str) -> Optional[str]: - """Attempt to resolve a MAC address from /proc/net/arp for the given IP.""" +def get_mac_from_arp(ip: str, arp_path: str = "/proc/net/arp") -> Optional[str]: + """Attempt to resolve a MAC address from the ARP table for the given IP.""" try: - with open("/proc/net/arp") as f: + with open(arp_path) as f: for line in f: parts = line.split() if len(parts) >= 4 and parts[0] == ip: diff --git a/tests/test_saip.py b/tests/test_saip.py index cca17e6..95badd1 100644 --- a/tests/test_saip.py +++ b/tests/test_saip.py @@ -41,6 +41,22 @@ class TestSaipEncoding: saip.create_saip_profile("302720000000001", generate_ki(), b"\x00" * 16, generate_iccid()) + def test_decode_unavailable_raises(self, monkeypatch): + monkeypatch.setattr(saip, "_compiler", lambda: None) + with pytest.raises(RuntimeError, match="unavailable"): + saip.decode_saip_profile(b"\x00") + + def test_find_asn_honours_env_override(self, tmp_path, monkeypatch): + fake = tmp_path / "schema.asn" + fake.write_text("-- placeholder\n") + monkeypatch.setenv("SAIP_ASN_PATH", str(fake)) + assert saip.find_saip_asn() == str(fake) + + def test_find_asn_ignores_missing_override(self, monkeypatch): + monkeypatch.setenv("SAIP_ASN_PATH", "/no/such/schema.asn") + # Falls through to the pySim lookup (or None); never returns the bad path. + assert saip.find_saip_asn() != "/no/such/schema.asn" + @saip_required def test_produces_der_bytes(self): ki = generate_ki() diff --git a/tests/test_utils.py b/tests/test_utils.py index 31b3caa..22c4bd6 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -2,6 +2,8 @@ import pytest from server.utils import ( ensure_parent_dir, + get_client_ip, + get_mac_from_arp, load_config, normalize_mac, validate_imsi, @@ -10,6 +12,41 @@ from server.utils import ( ) +class _FakeRequest: + def __init__(self, headers=None, remote_addr=None): + self.headers = headers or {} + self.remote_addr = remote_addr + + +class TestClientResolution: + def test_client_ip_prefers_forwarded(self): + req = _FakeRequest(headers={"X-Forwarded-For": "203.0.113.7, 10.0.0.1"}, + remote_addr="10.0.0.1") + assert get_client_ip(req) == "203.0.113.7" + + def test_client_ip_falls_back_to_remote_addr(self): + assert get_client_ip(_FakeRequest(remote_addr="192.168.4.10")) == "192.168.4.10" + + def test_client_ip_empty_when_unknown(self): + assert get_client_ip(_FakeRequest()) == "" + + def test_mac_from_arp_match(self, tmp_path): + arp = tmp_path / "arp" + arp.write_text( + "IP address HW type Flags HW address Mask Device\n" + "192.168.4.10 0x1 0x2 AA:BB:CC:DD:EE:FF * wlan0\n" + ) + assert get_mac_from_arp("192.168.4.10", str(arp)) == "aa:bb:cc:dd:ee:ff" + + def test_mac_from_arp_no_match(self, tmp_path): + arp = tmp_path / "arp" + arp.write_text("IP address ...\n192.168.4.99 0x1 0x2 11:22:33:44:55:66 * wlan0\n") + assert get_mac_from_arp("192.168.4.10", str(arp)) is None + + def test_mac_from_arp_missing_file(self): + assert get_mac_from_arp("192.168.4.10", "/no/such/arp") is None + + class TestEnsureParentDir: def test_bare_filename_does_not_crash(self): # No directory component -> must be a no-op, not FileNotFoundError.