Skip to content

Commit 42752c1

Browse files
fix(ble): enumerate undiscovered peripherals and refuse unbonded before any BLE link
list_fido_devices filtered on Peripheral::services(), which per btleplug docs is empty until discover_services() is called, so unconnected peripherals were dropped even when their advertised UUIDs included the FIDO service. Filter on PeripheralProperties::services (advertised UUIDs) instead, and run a brief scan first so adapter.peripherals() returns currently-advertising authenticators. supported_fido_revisions performed a GATT read without first calling Peripheral::connect() / discover_services(), so the characteristic lookup found nothing on a peripheral whose services had not been discovered in the current process. Enforce bonding here too (it's only a bluez D-Bus lookup) so unbonded peripherals are refused before any BLE link is opened. Both bugs predate PR #202 and only surface when the peripheral is not already an actively-connected, services-discovered device in the current btleplug session.
1 parent d8142f1 commit 42752c1

1 file changed

Lines changed: 24 additions & 5 deletions

File tree

libwebauthn/src/transport/ble/btleplug/manager.rs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -151,19 +151,29 @@ async fn discover_properties(
151151
Ok(result)
152152
}
153153

154+
/// Brief scan window so btleplug's adapter.peripherals() observes
155+
/// currently-advertising FIDO authenticators before we enumerate.
156+
const SCAN_DURATION: std::time::Duration = std::time::Duration::from_secs(3);
157+
154158
#[instrument(level = Level::DEBUG, skip_all)]
155159
pub async fn list_fido_devices() -> Result<Vec<FidoDevice>, Error> {
156160
let adapter = get_adapter().await?;
161+
adapter
162+
.start_scan(ScanFilter {
163+
services: vec![FIDO_PROFILE_UUID],
164+
})
165+
.await
166+
.or(Err(Error::ConnectionFailed))?;
167+
tokio::time::sleep(SCAN_DURATION).await;
168+
let _ = adapter.stop_scan().await;
157169
let peripherals: Vec<Peripheral> = adapter
158170
.peripherals()
159171
.await
160-
.or(Err(Error::ConnectionFailed))?
161-
.into_iter()
162-
.filter(|p| p.services().iter().any(|s| s.uuid == FIDO_PROFILE_UUID))
163-
.collect();
164-
let with_properties = discover_properties(peripherals)
172+
.or(Err(Error::ConnectionFailed))?;
173+
let with_properties: Vec<FidoDevice> = discover_properties(peripherals)
165174
.await?
166175
.into_iter()
176+
.filter(|(_, props)| props.services.contains(&FIDO_PROFILE_UUID))
167177
.map(|(peripheral, properties)| FidoDevice {
168178
peripheral,
169179
properties,
@@ -191,6 +201,15 @@ pub async fn get_device(peripheral: Peripheral) -> Result<Option<FidoDevice>, Er
191201
pub async fn supported_fido_revisions(
192202
peripheral: &Peripheral,
193203
) -> Result<SupportedRevisions, Error> {
204+
enforce_bonded(peripheral).await?;
205+
peripheral
206+
.connect()
207+
.await
208+
.or(Err(Error::ConnectionFailed))?;
209+
peripheral
210+
.discover_services()
211+
.await
212+
.or(Err(Error::ConnectionFailed))?;
194213
let services = discover_services(peripheral).await?;
195214
let revision = peripheral
196215
.read(&services.service_revision_bitfield)

0 commit comments

Comments
 (0)