bumble 0.0.160__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
 
@@ -932,9 +936,12 @@ class Session:
932
936
  if self.sc:
933
937
 
934
938
  async def next_steps() -> None:
935
- 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
+ ):
936
943
  z = 0
937
- elif self.pairing_method == self.PASSKEY:
944
+ elif self.pairing_method == PairingMethod.PASSKEY:
938
945
  # We need a passkey
939
946
  await self.passkey_ready.wait()
940
947
  assert self.passkey
@@ -1227,7 +1234,7 @@ class Session:
1227
1234
  # Create an object to hold the keys
1228
1235
  keys = PairingKeys()
1229
1236
  keys.address_type = peer_address.address_type
1230
- authenticated = self.pairing_method != self.JUST_WORKS
1237
+ authenticated = self.pairing_method != PairingMethod.JUST_WORKS
1231
1238
  if self.sc or self.connection.transport == BT_BR_EDR_TRANSPORT:
1232
1239
  keys.ltk = PairingKeys.Key(value=self.ltk, authenticated=authenticated)
1233
1240
  else:
@@ -1330,9 +1337,7 @@ class Session:
1330
1337
  self.decide_pairing_method(
1331
1338
  command.auth_req, command.io_capability, self.io_capability
1332
1339
  )
1333
- logger.debug(
1334
- f'pairing method: {self.PAIRING_METHOD_NAMES[self.pairing_method]}'
1335
- )
1340
+ logger.debug(f'pairing method: {self.pairing_method.name}')
1336
1341
 
1337
1342
  # Key distribution
1338
1343
  (
@@ -1348,7 +1353,7 @@ class Session:
1348
1353
 
1349
1354
  # Display a passkey if we need to
1350
1355
  if not self.sc:
1351
- if self.pairing_method == self.PASSKEY and self.passkey_display:
1356
+ if self.pairing_method == PairingMethod.PASSKEY and self.passkey_display:
1352
1357
  self.display_passkey()
1353
1358
 
1354
1359
  # Respond
@@ -1389,9 +1394,7 @@ class Session:
1389
1394
  self.decide_pairing_method(
1390
1395
  command.auth_req, self.io_capability, command.io_capability
1391
1396
  )
1392
- logger.debug(
1393
- f'pairing method: {self.PAIRING_METHOD_NAMES[self.pairing_method]}'
1394
- )
1397
+ logger.debug(f'pairing method: {self.pairing_method.name}')
1395
1398
 
1396
1399
  # Key distribution
1397
1400
  if (
@@ -1407,13 +1410,16 @@ class Session:
1407
1410
  self.compute_peer_expected_distributions(self.responder_key_distribution)
1408
1411
 
1409
1412
  # Start phase 2
1410
- if self.sc:
1411
- 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:
1412
1418
  self.display_or_input_passkey()
1413
1419
 
1414
1420
  self.send_public_key_command()
1415
1421
  else:
1416
- if self.pairing_method == self.PASSKEY:
1422
+ if self.pairing_method == PairingMethod.PASSKEY:
1417
1423
  self.display_or_input_passkey(self.send_pairing_confirm_command)
1418
1424
  else:
1419
1425
  self.send_pairing_confirm_command()
@@ -1425,7 +1431,10 @@ class Session:
1425
1431
  self.send_pairing_random_command()
1426
1432
  else:
1427
1433
  # If the method is PASSKEY, now is the time to input the code
1428
- 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
+ ):
1429
1438
  self.input_passkey(self.send_pairing_confirm_command)
1430
1439
  else:
1431
1440
  self.send_pairing_confirm_command()
@@ -1433,11 +1442,14 @@ class Session:
1433
1442
  def on_smp_pairing_confirm_command_secure_connections(
1434
1443
  self, _: SMP_Pairing_Confirm_Command
1435
1444
  ) -> None:
1436
- 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
+ ):
1437
1449
  if self.is_initiator:
1438
1450
  self.r = crypto.r()
1439
1451
  self.send_pairing_random_command()
1440
- elif self.pairing_method == self.PASSKEY:
1452
+ elif self.pairing_method == PairingMethod.PASSKEY:
1441
1453
  if self.is_initiator:
1442
1454
  self.send_pairing_random_command()
1443
1455
  else:
@@ -1493,13 +1505,16 @@ class Session:
1493
1505
  def on_smp_pairing_random_command_secure_connections(
1494
1506
  self, command: SMP_Pairing_Random_Command
1495
1507
  ) -> None:
1496
- if self.pairing_method == self.PASSKEY and self.passkey is None:
1508
+ if self.pairing_method == PairingMethod.PASSKEY and self.passkey is None:
1497
1509
  logger.warning('no passkey entered, ignoring command')
1498
1510
  return
1499
1511
 
1500
1512
  # pylint: disable=too-many-return-statements
1501
1513
  if self.is_initiator:
1502
- 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
+ ):
1503
1518
  assert self.confirm_value
1504
1519
  # Check that the random value matches what was committed to earlier
1505
1520
  confirm_verifier = crypto.f4(
@@ -1509,7 +1524,7 @@ class Session:
1509
1524
  self.confirm_value, confirm_verifier, SMP_CONFIRM_VALUE_FAILED_ERROR
1510
1525
  ):
1511
1526
  return
1512
- elif self.pairing_method == self.PASSKEY:
1527
+ elif self.pairing_method == PairingMethod.PASSKEY:
1513
1528
  assert self.passkey and self.confirm_value
1514
1529
  # Check that the random value matches what was committed to earlier
1515
1530
  confirm_verifier = crypto.f4(
@@ -1532,9 +1547,12 @@ class Session:
1532
1547
  else:
1533
1548
  return
1534
1549
  else:
1535
- 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
+ ):
1536
1554
  self.send_pairing_random_command()
1537
- elif self.pairing_method == self.PASSKEY:
1555
+ elif self.pairing_method == PairingMethod.PASSKEY:
1538
1556
  assert self.passkey and self.confirm_value
1539
1557
  # Check that the random value matches what was committed to earlier
1540
1558
  confirm_verifier = crypto.f4(
@@ -1565,10 +1583,13 @@ class Session:
1565
1583
  (mac_key, self.ltk) = crypto.f5(self.dh_key, self.na, self.nb, a, b)
1566
1584
 
1567
1585
  # Compute the DH Key checks
1568
- 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
+ ):
1569
1590
  ra = bytes(16)
1570
1591
  rb = ra
1571
- elif self.pairing_method == self.PASSKEY:
1592
+ elif self.pairing_method == PairingMethod.PASSKEY:
1572
1593
  assert self.passkey
1573
1594
  ra = self.passkey.to_bytes(16, byteorder='little')
1574
1595
  rb = ra
@@ -1592,13 +1613,16 @@ class Session:
1592
1613
  self.wait_before_continuing.set_result(None)
1593
1614
 
1594
1615
  # Prompt the user for confirmation if needed
1595
- 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
+ ):
1596
1620
  # Compute the 6-digit code
1597
1621
  code = crypto.g2(self.pka, self.pkb, self.na, self.nb) % 1000000
1598
1622
 
1599
1623
  # Ask for user confirmation
1600
1624
  self.wait_before_continuing = asyncio.get_running_loop().create_future()
1601
- if self.pairing_method == self.JUST_WORKS:
1625
+ if self.pairing_method == PairingMethod.JUST_WORKS:
1602
1626
  self.prompt_user_for_confirmation(next_steps)
1603
1627
  else:
1604
1628
  self.prompt_user_for_numeric_comparison(code, next_steps)
@@ -1635,13 +1659,16 @@ class Session:
1635
1659
  if self.is_initiator:
1636
1660
  self.send_pairing_confirm_command()
1637
1661
  else:
1638
- if self.pairing_method == self.PASSKEY:
1662
+ if self.pairing_method == PairingMethod.PASSKEY:
1639
1663
  self.display_or_input_passkey()
1640
1664
 
1641
1665
  # Send our public key back to the initiator
1642
1666
  self.send_public_key_command()
1643
1667
 
1644
- 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
+ ):
1645
1672
  # We can now send the confirmation value
1646
1673
  self.send_pairing_confirm_command()
1647
1674
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bumble
3
- Version: 0.0.160
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=8QQ6AIqjIlq1RtkPH3mWqZT4r6Ws-quKv8xtZR3mY0Y,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
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=83zWhDSI9yXc4ZGXrw29EeOC5v8W-JZzdZM7UUDS7Fs,69052
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.160.dist-info/LICENSE,sha256=FvaYh4NRWIGgS_OwoBs5gFgkCmAghZ-DYnIGBZPuw-s,12142
123
- bumble-0.0.160.dist-info/METADATA,sha256=-in8X3mK1x1XxDBvqt8C4LnuEd-JCi5XFsuYcT2mTjA,5221
124
- bumble-0.0.160.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
125
- bumble-0.0.160.dist-info/entry_points.txt,sha256=AjCwgm9SvZDOhV7T6jWwAhWdE728pd759LQCscMLjnM,765
126
- bumble-0.0.160.dist-info/top_level.txt,sha256=tV6JJKaHPYMFiJYiBYFW24PCcfLxTJZdlu6BmH3Cb00,7
127
- bumble-0.0.160.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