fix(rawcli): writes take (location, data); multi-frame + CRC
- A write needs both a location and data. NTAG WRITE (0xA2) already did; the two-phase 0xA0 writes (Type 2 COMPAT_WRITE, MIFARE Classic WRITE) only took the page/block. They now take (page/block, data) and build a frame *list* — the command frame plus the 16-byte data frame. - Catalog build() may now return a list of frames; _handle_call sends each in sequence and traces every exchange (so both phases of a write show). - 14a catalog commands now append the ISO14443-A CRC (ISO14A_APPEND_CRC), which real tags require — manual raw hex is still sent verbatim. 3 new/updated tests (two-phase build + send, CRC flag on reads). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -270,6 +270,8 @@ class TestCatalog:
|
||||
assert TYPE2.get("GET_VERSION").build() == b"\x60"
|
||||
assert TYPE2.get("WRITE").build("4", "01020304") == b"\xA2\x04\x01\x02\x03\x04"
|
||||
assert TYPE2.get("PWD_AUTH").build("FFFFFFFF") == b"\x1B\xFF\xFF\xFF\xFF"
|
||||
# two-phase write builds a frame list: command frame + 16-byte data frame
|
||||
assert TYPE2.get("COMPAT_WRITE").build("4", "0102") == [b"\xA0\x04", b"\x01\x02" + b"\x00" * 14]
|
||||
|
||||
def test_iso15_builds(self):
|
||||
assert ISO15.get("READ_BLOCK").build("4") == b"\x02\x20\x04"
|
||||
@@ -294,12 +296,23 @@ class TestFunctionCalls:
|
||||
def test_call_read_sends_correct_bytes(self, capsys):
|
||||
s = self._id()
|
||||
dispatch(s, "identify")
|
||||
s.device.hf.iso14a.raw.return_value = {"data": b"\xAA\xBB\xCC\xDD"}
|
||||
s.device.hf.iso14a.raw.return_value = {"raw": b"\xAA\xBB\xCC\xDD"}
|
||||
capsys.readouterr()
|
||||
dispatch(s, "READ(4)")
|
||||
out = _plain(capsys.readouterr().out)
|
||||
assert "30 04" in out # the built command hit the trace
|
||||
s.device.hf.iso14a.raw.assert_called_with(b"\x30\x04")
|
||||
s.device.hf.iso14a.raw.assert_called_with(b"\x30\x04", flags=0x20) # CRC appended
|
||||
|
||||
def test_two_phase_write_sends_both_frames(self, capsys):
|
||||
s = self._id() # SAK 0 -> Type 2 catalog
|
||||
dispatch(s, "identify")
|
||||
s.device.hf.iso14a.raw.return_value = {"raw": b"\x0A"} # ACK
|
||||
s.device.hf.iso14a.raw.reset_mock()
|
||||
dispatch(s, "COMPAT_WRITE(4, 01020304)")
|
||||
calls = s.device.hf.iso14a.raw.call_args_list
|
||||
assert len(calls) == 2 # command frame + data frame
|
||||
assert calls[0].args[0] == b"\xA0\x04"
|
||||
assert calls[1].args[0] == b"\x01\x02\x03\x04" + b"\x00" * 12
|
||||
|
||||
def test_call_without_identify(self, capsys):
|
||||
dispatch(RawSession(), "READ(4)")
|
||||
|
||||
Reference in New Issue
Block a user