diff --git a/bumble/device.py b/bumble/device.py index 4b3fa431..55ac3b08 100644 --- a/bumble/device.py +++ b/bumble/device.py @@ -2067,13 +2067,13 @@ class Device(CompositeEventEmitter): # Ask what the pairing config should be for this connection pairing_config = self.pairing_config_factory(connection) - can_confirm = pairing_config.delegate.io_capability not in { + can_compare = pairing_config.delegate.io_capability not in { smp.SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY, smp.SMP_DISPLAY_ONLY_IO_CAPABILITY } # Respond - if can_confirm and pairing_config.delegate: + if can_compare: async def compare_numbers(): numbers_match = await pairing_config.delegate.compare_numbers(code, digits=6) if numbers_match: @@ -2087,9 +2087,18 @@ class Device(CompositeEventEmitter): asyncio.create_task(compare_numbers()) else: - self.host.send_command_sync( - HCI_User_Confirmation_Request_Reply_Command(bd_addr=connection.peer_address) - ) + async def confirm(): + confirm = await pairing_config.delegate.confirm() + if confirm: + self.host.send_command_sync( + HCI_User_Confirmation_Request_Reply_Command(bd_addr=connection.peer_address) + ) + else: + self.host.send_command_sync( + HCI_User_Confirmation_Request_Negative_Reply_Command(bd_addr=connection.peer_address) + ) + + asyncio.create_task(confirm()) # [Classic only] @host_event_handler @@ -2104,7 +2113,7 @@ class Device(CompositeEventEmitter): } # Respond - if can_input and pairing_config.delegate: + if can_input: async def get_number(): number = await pairing_config.delegate.get_number() if number is not None: diff --git a/bumble/smp.py b/bumble/smp.py index c544a821..d7591131 100644 --- a/bumble/smp.py +++ b/bumble/smp.py @@ -477,6 +477,9 @@ class PairingDelegate: async def accept(self): return True + async def confirm(self): + return True + async def compare_numbers(self, number, digits=6): return True @@ -715,6 +718,21 @@ class Session: return False return True + def prompt_user_for_confirmation(self, next_steps): + async def prompt(): + logger.debug('ask for confirmation') + try: + response = await self.pairing_config.delegate.confirm() + if response: + next_steps() + return + except Exception as error: + logger.warn(f'exception while confirm: {error}') + + self.send_pairing_failed(SMP_CONFIRM_VALUE_FAILED_ERROR) + + asyncio.create_task(prompt()) + def prompt_user_for_numeric_comparison(self, code, next_steps): async def prompt(): logger.debug(f'verification code: {code}') @@ -1387,12 +1405,12 @@ class Session: # Compute the 6-digit code code = crypto.g2(self.pka, self.pkb, self.na, self.nb) % 1000000 - if self.pairing_method == self.NUMERIC_COMPARISON: - # Ask for user confirmation - self.wait_before_continuing = asyncio.get_running_loop().create_future() - self.prompt_user_for_numeric_comparison(code, next_steps) + # Ask for user confirmation + self.wait_before_continuing = asyncio.get_running_loop().create_future() + if self.pairing_method == self.JUST_WORKS: + self.prompt_user_for_confirmation(next_steps) else: - next_steps() + self.prompt_user_for_numeric_comparison(code, next_steps) else: next_steps()