import os import struct import pytest from fido2.ctap import CtapError from fido2.hid import CAPABILITY, CTAPHID def test_init_assigns_channel(device): assert device._channel_id not in (0, 0xFFFFFFFF) assert device.capabilities & CAPABILITY.CBOR assert device.capabilities & CAPABILITY.WINK def test_ping_single_packet(device): assert device.ping(b"hello") == b"hello" def test_ping_multi_packet(device): # 57 bytes in the first packet, then 59 per continuation packet. payload = os.urandom(3000) assert device.ping(payload) == payload def test_ping_largest_message(device): payload = os.urandom(57 + 128 * 59) assert device.ping(payload) == payload def test_wink(device): device.wink() def test_unknown_command(device): with pytest.raises(CtapError) as e: device.call(0x40) assert e.value.code == CtapError.ERR.INVALID_COMMAND def test_out_of_order_continuation(device): conn = device._connection cid = device._channel_id conn.write_packet(struct.pack(">IBH", cid, 0x80 | CTAPHID.PING, 100).ljust(64, b"\0")) conn.write_packet(struct.pack(">IB", cid, 1).ljust(64, b"\0")) # expected seq 0 response = conn.read_packet() assert response[:7] == struct.pack(">IBH", cid, 0x80 | CTAPHID.ERROR, 1) assert response[7] == CtapError.ERR.INVALID_SEQ assert device.ping(b"still alive") == b"still alive" def test_other_channel_busy_while_receiving(device): conn = device._connection cid = device._channel_id conn.write_packet(struct.pack(">IBH", cid, 0x80 | CTAPHID.PING, 100).ljust(64, b"\0")) conn.write_packet(struct.pack(">IBH", cid + 1, 0x80 | CTAPHID.PING, 1).ljust(64, b"\0")) response = conn.read_packet() assert response[:8] == struct.pack(">IBHB", cid + 1, 0x80 | CTAPHID.ERROR, 1, CtapError.ERR.CHANNEL_BUSY) # Finish the original message. conn.write_packet(struct.pack(">IB", cid, 0).ljust(64, b"\0")) response = conn.read_packet() assert response[:7] == struct.pack(">IBH", cid, 0x80 | CTAPHID.PING, 100) conn.read_packet() # continuation packet with the rest of the echo