feat(pm3py): soft firmware compatibility check on connect (ping + version probe)

This commit is contained in:
michael
2026-03-15 22:25:37 -07:00
parent fec04acc23
commit d9ec661d06
2 changed files with 103 additions and 1 deletions

View File

@@ -3,6 +3,7 @@ import struct
import asyncio
from unittest.mock import AsyncMock, MagicMock
from pm3py import Proxmark3, Cmd
from pm3py.client import FirmwareInfo
def test_full_api_surface():
@@ -18,6 +19,8 @@ def test_full_api_surface():
assert hasattr(pm3.hf, "mf")
assert hasattr(pm3, "send_ng")
assert hasattr(pm3, "send_mix")
assert hasattr(pm3, "firmware")
assert isinstance(pm3.firmware, FirmwareInfo)
def test_hw_ping_roundtrip():
@@ -47,3 +50,52 @@ def test_mf_rdbl_returns_hex():
pm3.hf.mf.rdbl(block=4, key="FFFFFFFFFFFF"))
assert result["data"] == "000102030405060708090a0b0c0d0e0f"
assert result["raw"] == block
def test_firmware_probe_compatible():
"""Verify firmware probe populates FirmwareInfo on successful connect."""
pm3 = Proxmark3("/dev/null")
mock_transport = AsyncMock()
pm3._transport = mock_transport
pm3.hw._t = mock_transport
from pm3py.transport import PM3Response
ping_data = bytes(range(32))
vstr = b"Proxmark3 RDV4.0 FW v4.18000\x00"
version_payload = struct.pack("<III", 0x270B0A40, 512*1024, len(vstr)) + vstr
# send_ng called twice: once for ping, once for version
mock_transport.send_ng.side_effect = [
PM3Response(cmd=Cmd.PING, status=0, reason=0, ng=True, data=ping_data),
PM3Response(cmd=Cmd.VERSION, status=0, reason=0, ng=True, data=version_payload),
]
asyncio.get_event_loop().run_until_complete(pm3._probe_firmware())
assert pm3.firmware.compatible is True
assert pm3.firmware.ng_protocol is True
assert "Proxmark3 RDV4.0" in pm3.firmware.version_string
assert pm3.firmware.warnings == []
def test_firmware_probe_ping_fails():
"""Verify firmware probe marks incompatible when ping fails."""
pm3 = Proxmark3("/dev/null")
mock_transport = AsyncMock()
pm3._transport = mock_transport
pm3.hw._t = mock_transport
from pm3py.transport import PM3Response, PM3Error
vstr = b"Proxmark3 OLD\x00"
version_payload = struct.pack("<III", 0x270B0A40, 256*1024, len(vstr)) + vstr
mock_transport.send_ng.side_effect = [
PM3Error("Ping failed"),
PM3Response(cmd=Cmd.VERSION, status=0, reason=0, ng=True, data=version_payload),
]
asyncio.get_event_loop().run_until_complete(pm3._probe_firmware())
assert pm3.firmware.compatible is False
assert pm3.firmware.ng_protocol is False
assert len(pm3.firmware.warnings) > 0