bumble 0.0.159__py3-none-any.whl → 0.0.161__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
bumble/smp.py CHANGED
@@ -25,6 +25,7 @@
25
25
  from __future__ import annotations
26
26
  import logging
27
27
  import asyncio
28
+ import enum
28
29
  import secrets
29
30
  from typing import (
30
31
  TYPE_CHECKING,
@@ -553,20 +554,16 @@ class AddressResolver:
553
554
 
554
555
 
555
556
  # -----------------------------------------------------------------------------
556
- class Session:
557
- # Pairing methods
557
+ class PairingMethod(enum.IntEnum):
558
558
  JUST_WORKS = 0
559
559
  NUMERIC_COMPARISON = 1
560
560
  PASSKEY = 2
561
561
  OOB = 3
562
+ CTKD_OVER_CLASSIC = 4
562
563
 
563
- PAIRING_METHOD_NAMES = {
564
- JUST_WORKS: 'JUST_WORKS',
565
- NUMERIC_COMPARISON: 'NUMERIC_COMPARISON',
566
- PASSKEY: 'PASSKEY',
567
- OOB: 'OOB',
568
- }
569
564
 
565
+ # -----------------------------------------------------------------------------
566
+ class Session:
570
567
  # I/O Capability to pairing method decision matrix
571
568
  #
572
569
  # See Bluetooth spec @ Vol 3, part H - Table 2.8: Mapping of IO Capabilities to Key
@@ -581,47 +578,50 @@ class Session:
581
578
  # (False).
582
579
  PAIRING_METHODS = {
583
580
  SMP_DISPLAY_ONLY_IO_CAPABILITY: {
584
- SMP_DISPLAY_ONLY_IO_CAPABILITY: JUST_WORKS,
585
- SMP_DISPLAY_YES_NO_IO_CAPABILITY: JUST_WORKS,
586
- SMP_KEYBOARD_ONLY_IO_CAPABILITY: (PASSKEY, True, False),
587
- SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: JUST_WORKS,
588
- SMP_KEYBOARD_DISPLAY_IO_CAPABILITY: (PASSKEY, True, False),
581
+ SMP_DISPLAY_ONLY_IO_CAPABILITY: PairingMethod.JUST_WORKS,
582
+ SMP_DISPLAY_YES_NO_IO_CAPABILITY: PairingMethod.JUST_WORKS,
583
+ SMP_KEYBOARD_ONLY_IO_CAPABILITY: (PairingMethod.PASSKEY, True, False),
584
+ SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: PairingMethod.JUST_WORKS,
585
+ SMP_KEYBOARD_DISPLAY_IO_CAPABILITY: (PairingMethod.PASSKEY, True, False),
589
586
  },
590
587
  SMP_DISPLAY_YES_NO_IO_CAPABILITY: {
591
- SMP_DISPLAY_ONLY_IO_CAPABILITY: JUST_WORKS,
592
- SMP_DISPLAY_YES_NO_IO_CAPABILITY: (JUST_WORKS, NUMERIC_COMPARISON),
593
- SMP_KEYBOARD_ONLY_IO_CAPABILITY: (PASSKEY, True, False),
594
- SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: JUST_WORKS,
588
+ SMP_DISPLAY_ONLY_IO_CAPABILITY: PairingMethod.JUST_WORKS,
589
+ SMP_DISPLAY_YES_NO_IO_CAPABILITY: (
590
+ PairingMethod.JUST_WORKS,
591
+ PairingMethod.NUMERIC_COMPARISON,
592
+ ),
593
+ SMP_KEYBOARD_ONLY_IO_CAPABILITY: (PairingMethod.PASSKEY, True, False),
594
+ SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: PairingMethod.JUST_WORKS,
595
595
  SMP_KEYBOARD_DISPLAY_IO_CAPABILITY: (
596
- (PASSKEY, True, False),
597
- NUMERIC_COMPARISON,
596
+ (PairingMethod.PASSKEY, True, False),
597
+ PairingMethod.NUMERIC_COMPARISON,
598
598
  ),
599
599
  },
600
600
  SMP_KEYBOARD_ONLY_IO_CAPABILITY: {
601
- SMP_DISPLAY_ONLY_IO_CAPABILITY: (PASSKEY, False, True),
602
- SMP_DISPLAY_YES_NO_IO_CAPABILITY: (PASSKEY, False, True),
603
- SMP_KEYBOARD_ONLY_IO_CAPABILITY: (PASSKEY, False, False),
604
- SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: JUST_WORKS,
605
- SMP_KEYBOARD_DISPLAY_IO_CAPABILITY: (PASSKEY, False, True),
601
+ SMP_DISPLAY_ONLY_IO_CAPABILITY: (PairingMethod.PASSKEY, False, True),
602
+ SMP_DISPLAY_YES_NO_IO_CAPABILITY: (PairingMethod.PASSKEY, False, True),
603
+ SMP_KEYBOARD_ONLY_IO_CAPABILITY: (PairingMethod.PASSKEY, False, False),
604
+ SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: PairingMethod.JUST_WORKS,
605
+ SMP_KEYBOARD_DISPLAY_IO_CAPABILITY: (PairingMethod.PASSKEY, False, True),
606
606
  },
607
607
  SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: {
608
- SMP_DISPLAY_ONLY_IO_CAPABILITY: JUST_WORKS,
609
- SMP_DISPLAY_YES_NO_IO_CAPABILITY: JUST_WORKS,
610
- SMP_KEYBOARD_ONLY_IO_CAPABILITY: JUST_WORKS,
611
- SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: JUST_WORKS,
612
- SMP_KEYBOARD_DISPLAY_IO_CAPABILITY: JUST_WORKS,
608
+ SMP_DISPLAY_ONLY_IO_CAPABILITY: PairingMethod.JUST_WORKS,
609
+ SMP_DISPLAY_YES_NO_IO_CAPABILITY: PairingMethod.JUST_WORKS,
610
+ SMP_KEYBOARD_ONLY_IO_CAPABILITY: PairingMethod.JUST_WORKS,
611
+ SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: PairingMethod.JUST_WORKS,
612
+ SMP_KEYBOARD_DISPLAY_IO_CAPABILITY: PairingMethod.JUST_WORKS,
613
613
  },
614
614
  SMP_KEYBOARD_DISPLAY_IO_CAPABILITY: {
615
- SMP_DISPLAY_ONLY_IO_CAPABILITY: (PASSKEY, False, True),
615
+ SMP_DISPLAY_ONLY_IO_CAPABILITY: (PairingMethod.PASSKEY, False, True),
616
616
  SMP_DISPLAY_YES_NO_IO_CAPABILITY: (
617
- (PASSKEY, False, True),
618
- NUMERIC_COMPARISON,
617
+ (PairingMethod.PASSKEY, False, True),
618
+ PairingMethod.NUMERIC_COMPARISON,
619
619
  ),
620
- SMP_KEYBOARD_ONLY_IO_CAPABILITY: (PASSKEY, True, False),
621
- SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: JUST_WORKS,
620
+ SMP_KEYBOARD_ONLY_IO_CAPABILITY: (PairingMethod.PASSKEY, True, False),
621
+ SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: PairingMethod.JUST_WORKS,
622
622
  SMP_KEYBOARD_DISPLAY_IO_CAPABILITY: (
623
- (PASSKEY, True, False),
624
- NUMERIC_COMPARISON,
623
+ (PairingMethod.PASSKEY, True, False),
624
+ PairingMethod.NUMERIC_COMPARISON,
625
625
  ),
626
626
  },
627
627
  }
@@ -664,7 +664,7 @@ class Session:
664
664
  self.passkey_ready = asyncio.Event()
665
665
  self.passkey_step = 0
666
666
  self.passkey_display = False
667
- self.pairing_method = 0
667
+ self.pairing_method: PairingMethod = PairingMethod.JUST_WORKS
668
668
  self.pairing_config = pairing_config
669
669
  self.wait_before_continuing: Optional[asyncio.Future[None]] = None
670
670
  self.completed = False
@@ -769,19 +769,23 @@ class Session:
769
769
  def decide_pairing_method(
770
770
  self, auth_req: int, initiator_io_capability: int, responder_io_capability: int
771
771
  ) -> None:
772
+ if self.connection.transport == BT_BR_EDR_TRANSPORT:
773
+ self.pairing_method = PairingMethod.CTKD_OVER_CLASSIC
774
+ return
772
775
  if (not self.mitm) and (auth_req & SMP_MITM_AUTHREQ == 0):
773
- self.pairing_method = self.JUST_WORKS
776
+ self.pairing_method = PairingMethod.JUST_WORKS
774
777
  return
775
778
 
776
779
  details = self.PAIRING_METHODS[initiator_io_capability][responder_io_capability] # type: ignore[index]
777
780
  if isinstance(details, tuple) and len(details) == 2:
778
781
  # One entry for legacy pairing and one for secure connections
779
782
  details = details[1 if self.sc else 0]
780
- if isinstance(details, int):
783
+ if isinstance(details, PairingMethod):
781
784
  # Just a method ID
782
785
  self.pairing_method = details
783
786
  else:
784
787
  # PASSKEY method, with a method ID and display/input flags
788
+ assert isinstance(details[0], PairingMethod)
785
789
  self.pairing_method = details[0]
786
790
  self.passkey_display = details[1 if self.is_initiator else 2]
787
791
 
@@ -858,10 +862,13 @@ class Session:
858
862
  self.tk = self.passkey.to_bytes(16, byteorder='little')
859
863
  logger.debug(f'TK from passkey = {self.tk.hex()}')
860
864
 
861
- self.connection.abort_on(
862
- 'disconnection',
863
- self.pairing_config.delegate.display_number(self.passkey, digits=6),
864
- )
865
+ try:
866
+ self.connection.abort_on(
867
+ 'disconnection',
868
+ self.pairing_config.delegate.display_number(self.passkey, digits=6),
869
+ )
870
+ except Exception as error:
871
+ logger.warning(f'exception while displaying number: {error}')
865
872
 
866
873
  def input_passkey(self, next_steps: Optional[Callable[[], None]] = None) -> None:
867
874
  # Prompt the user for the passkey displayed on the peer
@@ -929,9 +936,12 @@ class Session:
929
936
  if self.sc:
930
937
 
931
938
  async def next_steps() -> None:
932
- if self.pairing_method in (self.JUST_WORKS, self.NUMERIC_COMPARISON):
939
+ if self.pairing_method in (
940
+ PairingMethod.JUST_WORKS,
941
+ PairingMethod.NUMERIC_COMPARISON,
942
+ ):
933
943
  z = 0
934
- elif self.pairing_method == self.PASSKEY:
944
+ elif self.pairing_method == PairingMethod.PASSKEY:
935
945
  # We need a passkey
936
946
  await self.passkey_ready.wait()
937
947
  assert self.passkey
@@ -1224,7 +1234,7 @@ class Session:
1224
1234
  # Create an object to hold the keys
1225
1235
  keys = PairingKeys()
1226
1236
  keys.address_type = peer_address.address_type
1227
- authenticated = self.pairing_method != self.JUST_WORKS
1237
+ authenticated = self.pairing_method != PairingMethod.JUST_WORKS
1228
1238
  if self.sc or self.connection.transport == BT_BR_EDR_TRANSPORT:
1229
1239
  keys.ltk = PairingKeys.Key(value=self.ltk, authenticated=authenticated)
1230
1240
  else:
@@ -1300,7 +1310,11 @@ class Session:
1300
1310
  self, command: SMP_Pairing_Request_Command
1301
1311
  ) -> None:
1302
1312
  # Check if the request should proceed
1303
- accepted = await self.pairing_config.delegate.accept()
1313
+ try:
1314
+ accepted = await self.pairing_config.delegate.accept()
1315
+ except Exception as error:
1316
+ logger.warning(f'exception while accepting: {error}')
1317
+ accepted = False
1304
1318
  if not accepted:
1305
1319
  logger.debug('pairing rejected by delegate')
1306
1320
  self.send_pairing_failed(SMP_PAIRING_NOT_SUPPORTED_ERROR)
@@ -1323,9 +1337,7 @@ class Session:
1323
1337
  self.decide_pairing_method(
1324
1338
  command.auth_req, command.io_capability, self.io_capability
1325
1339
  )
1326
- logger.debug(
1327
- f'pairing method: {self.PAIRING_METHOD_NAMES[self.pairing_method]}'
1328
- )
1340
+ logger.debug(f'pairing method: {self.pairing_method.name}')
1329
1341
 
1330
1342
  # Key distribution
1331
1343
  (
@@ -1341,7 +1353,7 @@ class Session:
1341
1353
 
1342
1354
  # Display a passkey if we need to
1343
1355
  if not self.sc:
1344
- if self.pairing_method == self.PASSKEY and self.passkey_display:
1356
+ if self.pairing_method == PairingMethod.PASSKEY and self.passkey_display:
1345
1357
  self.display_passkey()
1346
1358
 
1347
1359
  # Respond
@@ -1382,9 +1394,7 @@ class Session:
1382
1394
  self.decide_pairing_method(
1383
1395
  command.auth_req, self.io_capability, command.io_capability
1384
1396
  )
1385
- logger.debug(
1386
- f'pairing method: {self.PAIRING_METHOD_NAMES[self.pairing_method]}'
1387
- )
1397
+ logger.debug(f'pairing method: {self.pairing_method.name}')
1388
1398
 
1389
1399
  # Key distribution
1390
1400
  if (
@@ -1400,13 +1410,16 @@ class Session:
1400
1410
  self.compute_peer_expected_distributions(self.responder_key_distribution)
1401
1411
 
1402
1412
  # Start phase 2
1403
- if self.sc:
1404
- if self.pairing_method == self.PASSKEY:
1413
+ if self.pairing_method == PairingMethod.CTKD_OVER_CLASSIC:
1414
+ # Authentication is already done in SMP, so remote shall start keys distribution immediately
1415
+ return
1416
+ elif self.sc:
1417
+ if self.pairing_method == PairingMethod.PASSKEY:
1405
1418
  self.display_or_input_passkey()
1406
1419
 
1407
1420
  self.send_public_key_command()
1408
1421
  else:
1409
- if self.pairing_method == self.PASSKEY:
1422
+ if self.pairing_method == PairingMethod.PASSKEY:
1410
1423
  self.display_or_input_passkey(self.send_pairing_confirm_command)
1411
1424
  else:
1412
1425
  self.send_pairing_confirm_command()
@@ -1418,7 +1431,10 @@ class Session:
1418
1431
  self.send_pairing_random_command()
1419
1432
  else:
1420
1433
  # If the method is PASSKEY, now is the time to input the code
1421
- if self.pairing_method == self.PASSKEY and not self.passkey_display:
1434
+ if (
1435
+ self.pairing_method == PairingMethod.PASSKEY
1436
+ and not self.passkey_display
1437
+ ):
1422
1438
  self.input_passkey(self.send_pairing_confirm_command)
1423
1439
  else:
1424
1440
  self.send_pairing_confirm_command()
@@ -1426,11 +1442,14 @@ class Session:
1426
1442
  def on_smp_pairing_confirm_command_secure_connections(
1427
1443
  self, _: SMP_Pairing_Confirm_Command
1428
1444
  ) -> None:
1429
- if self.pairing_method in (self.JUST_WORKS, self.NUMERIC_COMPARISON):
1445
+ if self.pairing_method in (
1446
+ PairingMethod.JUST_WORKS,
1447
+ PairingMethod.NUMERIC_COMPARISON,
1448
+ ):
1430
1449
  if self.is_initiator:
1431
1450
  self.r = crypto.r()
1432
1451
  self.send_pairing_random_command()
1433
- elif self.pairing_method == self.PASSKEY:
1452
+ elif self.pairing_method == PairingMethod.PASSKEY:
1434
1453
  if self.is_initiator:
1435
1454
  self.send_pairing_random_command()
1436
1455
  else:
@@ -1486,13 +1505,16 @@ class Session:
1486
1505
  def on_smp_pairing_random_command_secure_connections(
1487
1506
  self, command: SMP_Pairing_Random_Command
1488
1507
  ) -> None:
1489
- if self.pairing_method == self.PASSKEY and self.passkey is None:
1508
+ if self.pairing_method == PairingMethod.PASSKEY and self.passkey is None:
1490
1509
  logger.warning('no passkey entered, ignoring command')
1491
1510
  return
1492
1511
 
1493
1512
  # pylint: disable=too-many-return-statements
1494
1513
  if self.is_initiator:
1495
- if self.pairing_method in (self.JUST_WORKS, self.NUMERIC_COMPARISON):
1514
+ if self.pairing_method in (
1515
+ PairingMethod.JUST_WORKS,
1516
+ PairingMethod.NUMERIC_COMPARISON,
1517
+ ):
1496
1518
  assert self.confirm_value
1497
1519
  # Check that the random value matches what was committed to earlier
1498
1520
  confirm_verifier = crypto.f4(
@@ -1502,7 +1524,7 @@ class Session:
1502
1524
  self.confirm_value, confirm_verifier, SMP_CONFIRM_VALUE_FAILED_ERROR
1503
1525
  ):
1504
1526
  return
1505
- elif self.pairing_method == self.PASSKEY:
1527
+ elif self.pairing_method == PairingMethod.PASSKEY:
1506
1528
  assert self.passkey and self.confirm_value
1507
1529
  # Check that the random value matches what was committed to earlier
1508
1530
  confirm_verifier = crypto.f4(
@@ -1525,9 +1547,12 @@ class Session:
1525
1547
  else:
1526
1548
  return
1527
1549
  else:
1528
- if self.pairing_method in (self.JUST_WORKS, self.NUMERIC_COMPARISON):
1550
+ if self.pairing_method in (
1551
+ PairingMethod.JUST_WORKS,
1552
+ PairingMethod.NUMERIC_COMPARISON,
1553
+ ):
1529
1554
  self.send_pairing_random_command()
1530
- elif self.pairing_method == self.PASSKEY:
1555
+ elif self.pairing_method == PairingMethod.PASSKEY:
1531
1556
  assert self.passkey and self.confirm_value
1532
1557
  # Check that the random value matches what was committed to earlier
1533
1558
  confirm_verifier = crypto.f4(
@@ -1558,10 +1583,13 @@ class Session:
1558
1583
  (mac_key, self.ltk) = crypto.f5(self.dh_key, self.na, self.nb, a, b)
1559
1584
 
1560
1585
  # Compute the DH Key checks
1561
- if self.pairing_method in (self.JUST_WORKS, self.NUMERIC_COMPARISON):
1586
+ if self.pairing_method in (
1587
+ PairingMethod.JUST_WORKS,
1588
+ PairingMethod.NUMERIC_COMPARISON,
1589
+ ):
1562
1590
  ra = bytes(16)
1563
1591
  rb = ra
1564
- elif self.pairing_method == self.PASSKEY:
1592
+ elif self.pairing_method == PairingMethod.PASSKEY:
1565
1593
  assert self.passkey
1566
1594
  ra = self.passkey.to_bytes(16, byteorder='little')
1567
1595
  rb = ra
@@ -1585,13 +1613,16 @@ class Session:
1585
1613
  self.wait_before_continuing.set_result(None)
1586
1614
 
1587
1615
  # Prompt the user for confirmation if needed
1588
- if self.pairing_method in (self.JUST_WORKS, self.NUMERIC_COMPARISON):
1616
+ if self.pairing_method in (
1617
+ PairingMethod.JUST_WORKS,
1618
+ PairingMethod.NUMERIC_COMPARISON,
1619
+ ):
1589
1620
  # Compute the 6-digit code
1590
1621
  code = crypto.g2(self.pka, self.pkb, self.na, self.nb) % 1000000
1591
1622
 
1592
1623
  # Ask for user confirmation
1593
1624
  self.wait_before_continuing = asyncio.get_running_loop().create_future()
1594
- if self.pairing_method == self.JUST_WORKS:
1625
+ if self.pairing_method == PairingMethod.JUST_WORKS:
1595
1626
  self.prompt_user_for_confirmation(next_steps)
1596
1627
  else:
1597
1628
  self.prompt_user_for_numeric_comparison(code, next_steps)
@@ -1628,13 +1659,16 @@ class Session:
1628
1659
  if self.is_initiator:
1629
1660
  self.send_pairing_confirm_command()
1630
1661
  else:
1631
- if self.pairing_method == self.PASSKEY:
1662
+ if self.pairing_method == PairingMethod.PASSKEY:
1632
1663
  self.display_or_input_passkey()
1633
1664
 
1634
1665
  # Send our public key back to the initiator
1635
1666
  self.send_public_key_command()
1636
1667
 
1637
- if self.pairing_method in (self.JUST_WORKS, self.NUMERIC_COMPARISON):
1668
+ if self.pairing_method in (
1669
+ PairingMethod.JUST_WORKS,
1670
+ PairingMethod.NUMERIC_COMPARISON,
1671
+ ):
1638
1672
  # We can now send the confirmation value
1639
1673
  self.send_pairing_confirm_command()
1640
1674
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bumble
3
- Version: 0.0.159
3
+ Version: 0.0.161
4
4
  Summary: Bluetooth Stack for Apps, Emulation, Test and Experimentation
5
5
  Home-page: https://github.com/google/bumble
6
6
  Author: Google
@@ -1,5 +1,5 @@
1
1
  bumble/__init__.py,sha256=Q8jkz6rgl95IMAeInQVt_2GLoJl3DcEP2cxtrQ-ho5c,110
2
- bumble/_version.py,sha256=WSj7NUFDKYQiyZrpP7OjHIDQxwUeoeILsRj77qiYXrs,164
2
+ bumble/_version.py,sha256=z2uj4v0zOw20JF0drVkUjMouxtJipeDu3RBasPE26ks,164
3
3
  bumble/a2dp.py,sha256=vwnKknvSKPR7IdTz8JHHNvHGObjepVy1kFRWm0kNWEI,21923
4
4
  bumble/att.py,sha256=qXwC5gtC-4Bwjqul0sCm_bWA_BbK4NVf5xNlOCRE7LI,30231
5
5
  bumble/avdtp.py,sha256=sT0mFeFvp9jTEP-dOp4_ibdtKX3mtw1Gyi-72tHfkiE,72268
@@ -7,13 +7,13 @@ bumble/bridge.py,sha256=T6es5oS1dy8QgkxQ8iOD-YcZ0SWOv8jaqC7TGxqodk4,3003
7
7
  bumble/codecs.py,sha256=Vc7FOo6d-6VCgDI0ibnLmX8vCZ4-jtX_-0vEUM-yOrI,15343
8
8
  bumble/colors.py,sha256=9H-qzGgMr-YoWdIFpcGPaiRvTvkCzz7FPIkpwqKyKug,3033
9
9
  bumble/company_ids.py,sha256=mHmG9mk_0lkjiRm-IMggDnuXzY2QlZzH9jugy_ijhDc,95931
10
- bumble/controller.py,sha256=YwOVfcsPD8BvzXqfswY-wUECym2BX7_8zEBjIjUnhWw,44266
11
- bumble/core.py,sha256=_BnrlhR4OcS0RJE3510CshdD5iQ1zQeoMrdCD0oDebQ,48167
10
+ bumble/controller.py,sha256=AaRNjz8-1UYH3HgSIVdBvLLwHOLNbxj5J9ScG518PE0,44940
11
+ bumble/core.py,sha256=5gvUyF8aJKg2T_8QPVGiv6wtP-zsWJZ6w89UTGKQHrQ,52293
12
12
  bumble/crypto.py,sha256=JX3wg6kd-aFMxkxJz2FYFvyXHOukD-z0QcGH9jpEYvk,8679
13
13
  bumble/decoder.py,sha256=N9nMvuVhuwpnfw7EDVuNe9uYY6B6c3RY2dh8RhRPC1U,9608
14
- bumble/device.py,sha256=VmLZ9V_XQWjYQBO9KMURMye8UcYJLUgUkv0HJO-K5ag,122190
14
+ bumble/device.py,sha256=UPusLfD-sb3wpeDXTHMVS-MqoFRF39tKtCWLLfHfFOc,122493
15
15
  bumble/gap.py,sha256=axlOZIv99357Ehq2vMokeioU85z81qdQvplGn0pF70Q,2137
16
- bumble/gatt.py,sha256=bq6-oR0qx2Vp05IxnAiDZEGv3WsWCiNtdjYHpi0A6Fg,28150
16
+ bumble/gatt.py,sha256=HwjxuFjuH0LvRyP4HUfslPd-qZ0P17e5Xx8E9usehz0,28295
17
17
  bumble/gatt_client.py,sha256=0NrwW7Y3oy1HUWisIyBLwnBpYNnuI9jtbcNkS6CD__U,40297
18
18
  bumble/gatt_server.py,sha256=vi_-sofp5NjPWDYX5K_hldsAaoFuNlt8GFA-eVzFkb8,35277
19
19
  bumble/hci.py,sha256=7WleGG4Mp80qFGPGoRxUDP2qs6mpRRAWywkgTHJkPHM,217086
@@ -21,13 +21,13 @@ bumble/helpers.py,sha256=AgtOigAqQzzTEMMwHQJ2EO7dOTp77qhnyfHQ2LCDd-k,8896
21
21
  bumble/hfp.py,sha256=BQEuh7A9WkP2V-YuuveuI5W-k1-O1Ovq2DvRao_2psk,3434
22
22
  bumble/host.py,sha256=BzxDA4crNZrj0u0Gm_hW-uanXn6mFwjRVWKdfd4jrvw,34574
23
23
  bumble/keys.py,sha256=_ibaJ4CxM5zyxnTp7wnihIQSsEAEkCiPxx9qHsGA04Q,12601
24
- bumble/l2cap.py,sha256=Md_1af1jEP0dXlXpVkaXINnnmElq423o5m9OJFBaiYk,72106
24
+ bumble/l2cap.py,sha256=lk8hNofT04uTiPZ169zgipHWxnq48bz3VcGs3t4CfWE,75417
25
25
  bumble/link.py,sha256=dvb3fdmV8689A4rLhFVHHKMR3u4wQbUapFi-GeheK0M,20220
26
26
  bumble/pairing.py,sha256=smMCrWdgtdLXKJ_Ix9e5x1SuvSs_49mKtwzJS94ygd4,7002
27
27
  bumble/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
28
  bumble/rfcomm.py,sha256=LgcHvRelcToJy3PiPedqkrj4CRZjCg2zFVba-hTkZCY,31632
29
29
  bumble/sdp.py,sha256=h0DyXOYpQ5OLzwVZsE4b5YZq_jxxu7m_QSbFkaPy9mQ,42464
30
- bumble/smp.py,sha256=NxbAlbijmTy3V1Yc8bqn0MlK3qnyNqFomgO0R_Wedsc,68767
30
+ bumble/smp.py,sha256=kh8CA9wnyNT4kqz4Rt9_K6xqFeWDd7POdp4karCKsdU,70430
31
31
  bumble/snoop.py,sha256=_QfF36eylBW6Snd-_KYOwKaGiM8i_Ed-B5XoFIPt3Dg,5631
32
32
  bumble/utils.py,sha256=x7AKW6QD35Dl1OkROLJ6TX4dNN6ajwFjW8w_BZGGcA4,10195
33
33
  bumble/apps/README.md,sha256=XTwjRAY-EJWDXpl1V8K3Mw8B7kIqzUIUizRjVBVhoIE,1769
@@ -119,9 +119,9 @@ bumble/transport/grpc_protobuf/packet_streamer_pb2_grpc.py,sha256=k4RDFvE5Y4QgGL
119
119
  bumble/transport/grpc_protobuf/startup_pb2.py,sha256=viPPlvFuRE1HoM3zg3Ayy5wfNnuSSAX80MNqtKVqv-o,1854
120
120
  bumble/transport/grpc_protobuf/startup_pb2.pyi,sha256=8bDHVKJ_PIZuPvXRVK7tJCPOY8E8ZKW-5xzqbRLEJcw,2140
121
121
  bumble/transport/grpc_protobuf/startup_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
122
- bumble-0.0.159.dist-info/LICENSE,sha256=FvaYh4NRWIGgS_OwoBs5gFgkCmAghZ-DYnIGBZPuw-s,12142
123
- bumble-0.0.159.dist-info/METADATA,sha256=IOACdkt4OfTSKuKWMnYIMsyC9sI_dRTaAh6eQ3iFL9U,5221
124
- bumble-0.0.159.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
125
- bumble-0.0.159.dist-info/entry_points.txt,sha256=AjCwgm9SvZDOhV7T6jWwAhWdE728pd759LQCscMLjnM,765
126
- bumble-0.0.159.dist-info/top_level.txt,sha256=tV6JJKaHPYMFiJYiBYFW24PCcfLxTJZdlu6BmH3Cb00,7
127
- bumble-0.0.159.dist-info/RECORD,,
122
+ bumble-0.0.161.dist-info/LICENSE,sha256=FvaYh4NRWIGgS_OwoBs5gFgkCmAghZ-DYnIGBZPuw-s,12142
123
+ bumble-0.0.161.dist-info/METADATA,sha256=Xy3VY03sptPDb03hJdGpFK6WqP476EPk6J63eAhvU0c,5221
124
+ bumble-0.0.161.dist-info/WHEEL,sha256=AtBG6SXL3KF_v0NxLf0ehyVOh0cold-JbJYXNGorC6Q,92
125
+ bumble-0.0.161.dist-info/entry_points.txt,sha256=AjCwgm9SvZDOhV7T6jWwAhWdE728pd759LQCscMLjnM,765
126
+ bumble-0.0.161.dist-info/top_level.txt,sha256=tV6JJKaHPYMFiJYiBYFW24PCcfLxTJZdlu6BmH3Cb00,7
127
+ bumble-0.0.161.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.40.0)
2
+ Generator: bdist_wheel (0.41.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5