Skip to content

Commit

Permalink
backends/winrt/client: handle arbitrary access denied
Browse files Browse the repository at this point in the history
We had a hard-coded list of services know to return an access denied
error when attempting to enumerate characteristics. However, since
we don't know Windows internals, the list was not exhaustive and it
could also change in the future.

Instead, we can just check for the access denied error and skip any
service that returns that error which should also handle additional
services we don't know about yet.

Fixes: #1291
  • Loading branch information
dlech committed Apr 29, 2023
1 parent 3216f20 commit 44b27ce
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 27 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ Changed
-------
- Improved error messages when failing to get services in WinRT backend.

Fixed
-----
- Fix handling all access denied errors when enumerating characteristics on Windows. Fixes #1291.

`0.20.2`_ (2023-04-19)
======================

Expand Down
42 changes: 15 additions & 27 deletions bleak/backends/winrt/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,6 @@

logger = logging.getLogger(__name__)

_ACCESS_DENIED_SERVICES = list(
uuid.UUID(u)
for u in ("00001812-0000-1000-8000-00805f9b34fb",) # Human Interface Device Service
)

# TODO: we can use this when minimum Python is 3.8
# class _Result(typing.Protocol):
# status: GattCommunicationStatus
Expand Down Expand Up @@ -652,8 +647,6 @@ async def get_services(
if cache_mode is not None:
args.append(cache_mode)

logger.debug("calling get_gatt_services_async")

def dispose_on_cancel(future):
if future._cancel_requested and future._result is not None:
logger.debug("disposing services object because of cancel")
Expand Down Expand Up @@ -688,44 +681,39 @@ def dispose_on_cancel(future):
)
)

logger.debug("returned from get_gatt_services_async")

try:
for service in services:
# Windows returns an ACCESS_DENIED error when trying to enumerate
# characteristics of services used by the OS, like the HID service
# so we have to exclude those services.
if service.uuid in _ACCESS_DENIED_SERVICES:
continue

new_services.add_service(BleakGATTServiceWinRT(service))
result = await FutureLike(service.get_characteristics_async(*args))

logger.debug("calling get_characteristics_async")
if result.status == GattCommunicationStatus.ACCESS_DENIED:
# Windows does not allow access to services "owned" by the
# OS. This includes services like HID and Bond Manager.
logger.debug(
"skipping service %s due to access denied", service.uuid
)
continue

characteristics: Sequence[GattCharacteristic] = _ensure_success(
await FutureLike(service.get_characteristics_async(*args)),
result,
"characteristics",
f"Could not get GATT characteristics for service {service.uuid} ({service.attribute_handle})",
)

logger.debug("returned from get_characteristics_async")
new_services.add_service(BleakGATTServiceWinRT(service))

for characteristic in characteristics:
new_services.add_characteristic(
BleakGATTCharacteristicWinRT(
characteristic, self._session.max_pdu_size - 3
)
)

logger.debug("calling get_descriptors_async")

descriptors: Sequence[GattDescriptor] = _ensure_success(
await FutureLike(characteristic.get_descriptors_async(*args)),
"descriptors",
f"Could not get GATT descriptors for characteristic {characteristic.uuid} ({characteristic.attribute_handle})",
)

logger.debug("returned from get_descriptors_async")
new_services.add_characteristic(
BleakGATTCharacteristicWinRT(
characteristic, self._session.max_pdu_size - 3
)
)

for descriptor in descriptors:
new_services.add_descriptor(
Expand Down

0 comments on commit 44b27ce

Please sign in to comment.