test_auth.py (2192B)
1 """Tests for the current FF81 authentication payload.""" 2 3 import unittest 4 5 from pyhunterbtt.auth import encode_authentication, encode_passcode_change 6 from pyhunterbtt.protocol import ProtocolError 7 8 SYNTHETIC_CLIENT_IDENTIFIER = bytes.fromhex("01 23 45 67 89 ab") 9 SYNTHETIC_NONCE = b"K7m" 10 11 12 class AuthenticationTests(unittest.TestCase): 13 """Verify the app-compatible encoder without captured credentials.""" 14 15 def test_synthetic_known_vector(self) -> None: 16 payload = encode_authentication( 17 "2468", 18 SYNTHETIC_CLIENT_IDENTIFIER, 19 nonce=SYNTHETIC_NONCE, 20 ) 21 self.assertEqual( 22 payload, 23 bytes.fromhex("8a 86 82 9e 8c c8 04 40 9d d9 00 4b 37 6d"), 24 ) 25 26 def test_passcode_change_sets_operation_byte(self) -> None: 27 payload = encode_passcode_change( 28 "2468", 29 SYNTHETIC_CLIENT_IDENTIFIER, 30 nonce=SYNTHETIC_NONCE, 31 ) 32 self.assertEqual(payload[10], 1) 33 self.assertEqual(payload[11:], SYNTHETIC_NONCE) 34 35 def test_generated_nonce_has_app_compatible_shape(self) -> None: 36 payload = encode_authentication("2468", SYNTHETIC_CLIENT_IDENTIFIER) 37 self.assertEqual(len(payload), 14) 38 self.assertEqual(payload[10], 0) 39 self.assertEqual(len(payload[11:]), 3) 40 self.assertTrue(payload[11:].isalnum()) 41 42 def test_rejects_non_digit_passcode(self) -> None: 43 for passcode in ("123", "12345", "12x4", "1234"): 44 with self.subTest(passcode=passcode), self.assertRaises(ProtocolError): 45 encode_authentication( 46 passcode, 47 SYNTHETIC_CLIENT_IDENTIFIER, 48 nonce=SYNTHETIC_NONCE, 49 ) 50 51 def test_rejects_wrong_identifier_or_nonce_size(self) -> None: 52 with self.assertRaises(ProtocolError): 53 encode_authentication("2468", b"short", nonce=SYNTHETIC_NONCE) 54 with self.assertRaises(ProtocolError): 55 encode_authentication( 56 "2468", 57 SYNTHETIC_CLIENT_IDENTIFIER, 58 nonce=b"no", 59 ) 60 61 62 if __name__ == "__main__": 63 unittest.main()