blob: d7c9e5051bb99109a52e6d2f10787e9c15f84cdb [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/bluetooth/web_bluetooth_pairing_manager_impl.h"
#include <utility>
#include "base/functional/callback_helpers.h"
#include "base/notimplemented.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "content/browser/bluetooth/web_bluetooth_pairing_manager_delegate.h"
#include "content/browser/bluetooth/web_bluetooth_service_impl.h"
#include "content/public/browser/bluetooth_delegate.h"
namespace content {
namespace {
using ::blink::mojom::WebBluetoothService;
using ::device::BluetoothDevice;
void OnPairForReadCharacteristicCallback(
std::string characteristic_instance_id,
WebBluetoothPairingManagerDelegate* pairing_manager_delegate,
WebBluetoothService::RemoteCharacteristicReadValueCallback callback,
std::optional<BluetoothDevice::ConnectErrorCode> error_code) {
if (error_code) {
std::move(callback).Run(
WebBluetoothServiceImpl::TranslateConnectErrorAndRecord(*error_code),
/*value=*/{});
return;
}
pairing_manager_delegate->RemoteCharacteristicReadValue(
characteristic_instance_id, std::move(callback));
}
void OnPairForWriteCharacteristicCallback(
std::string characteristic_instance_id,
WebBluetoothPairingManagerDelegate* pairing_manager_delegate,
std::vector<uint8_t> value,
blink::mojom::WebBluetoothWriteType write_type,
WebBluetoothService::RemoteCharacteristicWriteValueCallback callback,
std::optional<BluetoothDevice::ConnectErrorCode> error_code) {
if (error_code) {
std::move(callback).Run(
WebBluetoothServiceImpl::TranslateConnectErrorAndRecord(*error_code));
return;
}
pairing_manager_delegate->RemoteCharacteristicWriteValue(
characteristic_instance_id, value, write_type, std::move(callback));
}
void OnPairForReadDescriptorCallback(
const std::string& descriptor_instance_id,
WebBluetoothPairingManagerDelegate* pairing_manager_delegate,
WebBluetoothService::RemoteDescriptorReadValueCallback callback,
std::optional<BluetoothDevice::ConnectErrorCode> error_code) {
if (error_code) {
std::move(callback).Run(
WebBluetoothServiceImpl::TranslateConnectErrorAndRecord(*error_code),
/*value=*/{});
return;
}
pairing_manager_delegate->RemoteDescriptorReadValue(descriptor_instance_id,
std::move(callback));
}
void OnPairForWriteDescriptorCallback(
const std::string& descriptor_instance_id,
WebBluetoothPairingManagerDelegate* pairing_manager_delegate,
std::vector<uint8_t> value,
WebBluetoothService::RemoteDescriptorWriteValueCallback callback,
std::optional<BluetoothDevice::ConnectErrorCode> error_code) {
if (error_code) {
std::move(callback).Run(
WebBluetoothServiceImpl::TranslateConnectErrorAndRecord(*error_code));
return;
}
pairing_manager_delegate->RemoteDescriptorWriteValue(
descriptor_instance_id, value, std::move(callback));
}
void OnPairCharacteristicStartNotifications(
const std::string& characteristic_instance_id,
mojo::AssociatedRemote<blink::mojom::WebBluetoothCharacteristicClient>
client,
WebBluetoothPairingManagerDelegate* pairing_manager_delegate,
WebBluetoothService::RemoteCharacteristicStartNotificationsCallback
callback,
std::optional<BluetoothDevice::ConnectErrorCode> error_code) {
if (error_code) {
std::move(callback).Run(
WebBluetoothServiceImpl::TranslateConnectErrorAndRecord(*error_code));
return;
}
pairing_manager_delegate->RemoteCharacteristicStartNotificationsInternal(
characteristic_instance_id, std::move(client), std::move(callback));
}
} // namespace
constexpr int WebBluetoothPairingManagerImpl::kMaxPairAttempts;
// TODO(crbug.com/40626253): Ensure this delegate outlives any in-progress
// pairing operation for which it is used. Additionally review use of
// WebBluetoothDeviceId vs. BluetoothDevice as well as how to deal with
// simultaneous pairing requests for the same device.
WebBluetoothPairingManagerImpl::WebBluetoothPairingManagerImpl(
WebBluetoothPairingManagerDelegate* pairing_manager_delegate)
: pairing_manager_delegate_(pairing_manager_delegate) {
DCHECK(pairing_manager_delegate_);
}
WebBluetoothPairingManagerImpl::~WebBluetoothPairingManagerImpl() {
auto pending_pair_device_ids = std::move(pending_pair_device_ids_);
for (const auto& device_id : pending_pair_device_ids) {
pairing_manager_delegate_->CancelPairing(device_id);
}
}
void WebBluetoothPairingManagerImpl::PairForCharacteristicReadValue(
const std::string& characteristic_instance_id,
WebBluetoothService::RemoteCharacteristicReadValueCallback read_callback) {
blink::WebBluetoothDeviceId device_id =
pairing_manager_delegate_->GetCharacteristicDeviceID(
characteristic_instance_id);
if (!device_id.IsValid()) {
std::move(read_callback)
.Run(WebBluetoothServiceImpl::TranslateConnectErrorAndRecord(
BluetoothDevice::ConnectErrorCode::ERROR_UNKNOWN),
/*value=*/{});
return;
}
PairDevice(
device_id, /*num_pair_attempts=*/0,
base::BindOnce(&OnPairForReadCharacteristicCallback,
characteristic_instance_id, pairing_manager_delegate_,
std::move(read_callback)));
}
void WebBluetoothPairingManagerImpl::PairForCharacteristicWriteValue(
const std::string& characteristic_instance_id,
const std::vector<uint8_t>& value,
blink::mojom::WebBluetoothWriteType write_type,
WebBluetoothService::RemoteCharacteristicWriteValueCallback callback) {
blink::WebBluetoothDeviceId device_id =
pairing_manager_delegate_->GetCharacteristicDeviceID(
characteristic_instance_id);
if (!device_id.IsValid()) {
std::move(callback).Run(
WebBluetoothServiceImpl::TranslateConnectErrorAndRecord(
BluetoothDevice::ConnectErrorCode::ERROR_UNKNOWN));
return;
}
PairDevice(
device_id, /*num_pair_attempts=*/0,
base::BindOnce(&OnPairForWriteCharacteristicCallback,
characteristic_instance_id, pairing_manager_delegate_,
value, write_type, std::move(callback)));
}
void WebBluetoothPairingManagerImpl::PairForDescriptorReadValue(
const std::string& descriptor_instance_id,
WebBluetoothService::RemoteDescriptorReadValueCallback read_callback) {
blink::WebBluetoothDeviceId device_id =
pairing_manager_delegate_->GetDescriptorDeviceId(descriptor_instance_id);
if (!device_id.IsValid()) {
std::move(read_callback)
.Run(WebBluetoothServiceImpl::TranslateConnectErrorAndRecord(
BluetoothDevice::ConnectErrorCode::ERROR_UNKNOWN),
/*value=*/{});
return;
}
PairDevice(
device_id, /*num_pair_attempts=*/0,
base::BindOnce(&OnPairForReadDescriptorCallback, descriptor_instance_id,
pairing_manager_delegate_, std::move(read_callback)));
}
void WebBluetoothPairingManagerImpl::PairForDescriptorWriteValue(
const std::string& descriptor_instance_id,
const std::vector<uint8_t>& value,
WebBluetoothService::RemoteDescriptorWriteValueCallback callback) {
blink::WebBluetoothDeviceId device_id =
pairing_manager_delegate_->GetDescriptorDeviceId(descriptor_instance_id);
if (!device_id.IsValid()) {
std::move(callback).Run(
WebBluetoothServiceImpl::TranslateConnectErrorAndRecord(
BluetoothDevice::ConnectErrorCode::ERROR_UNKNOWN));
return;
}
PairDevice(device_id, /*num_pair_attempts=*/0,
base::BindOnce(&OnPairForWriteDescriptorCallback,
descriptor_instance_id, pairing_manager_delegate_,
std::move(value), std::move(callback)));
}
void WebBluetoothPairingManagerImpl::PairForCharacteristicStartNotifications(
const std::string& characteristic_instance_id,
mojo::AssociatedRemote<blink::mojom::WebBluetoothCharacteristicClient>
client,
blink::mojom::WebBluetoothService::
RemoteCharacteristicStartNotificationsCallback callback) {
blink::WebBluetoothDeviceId device_id =
pairing_manager_delegate_->GetCharacteristicDeviceID(
characteristic_instance_id);
if (!device_id.IsValid()) {
std::move(callback).Run(
WebBluetoothServiceImpl::TranslateConnectErrorAndRecord(
BluetoothDevice::ConnectErrorCode::ERROR_UNKNOWN));
return;
}
PairDevice(device_id, /*num_pair_attempts=*/0,
base::BindOnce(&OnPairCharacteristicStartNotifications,
characteristic_instance_id, std::move(client),
pairing_manager_delegate_, std::move(callback)));
}
void WebBluetoothPairingManagerImpl::PairDevice(
blink::WebBluetoothDeviceId device_id,
int num_pair_attempts,
device::BluetoothDevice::ConnectCallback callback) {
DCHECK(device_id.IsValid());
if (pending_pair_device_ids_.contains(device_id)) {
std::move(callback).Run(
BluetoothDevice::ConnectErrorCode::ERROR_AUTH_CANCELED);
return;
}
pending_pair_device_ids_.insert(device_id);
pairing_manager_delegate_->PairDevice(
device_id, /*pairing_delegate=*/this,
base::BindOnce(&WebBluetoothPairingManagerImpl::OnPairDevice,
weak_ptr_factory_.GetWeakPtr(), device_id,
num_pair_attempts + 1, std::move(callback)));
}
void WebBluetoothPairingManagerImpl::OnPairDevice(
blink::WebBluetoothDeviceId device_id,
int num_pair_attempts,
BluetoothDevice::ConnectCallback callback,
std::optional<BluetoothDevice::ConnectErrorCode> error_code) {
pending_pair_device_ids_.erase(device_id);
if (!error_code) {
std::move(callback).Run(/*error_code=*/std::nullopt);
return;
}
if (*error_code == BluetoothDevice::ConnectErrorCode::ERROR_AUTH_REJECTED &&
num_pair_attempts < kMaxPairAttempts) {
PairDevice(device_id, num_pair_attempts, std::move(callback));
return;
}
std::move(callback).Run(error_code);
}
void WebBluetoothPairingManagerImpl::RequestPinCode(BluetoothDevice* device) {
blink::WebBluetoothDeviceId device_id =
pairing_manager_delegate_->GetWebBluetoothDeviceId(device->GetAddress());
pairing_manager_delegate_->PromptForBluetoothPairing(
device->GetNameForDisplay(),
base::BindOnce(&WebBluetoothPairingManagerImpl::OnPinCodeResult,
weak_ptr_factory_.GetWeakPtr(), device_id),
BluetoothDelegate::PairingKind::kProvidePin, std::nullopt);
}
void WebBluetoothPairingManagerImpl::OnPinCodeResult(
blink::WebBluetoothDeviceId device_id,
const BluetoothDelegate::PairPromptResult& result) {
switch (result.result_code) {
case BluetoothDelegate::PairPromptStatus::kCancelled:
pairing_manager_delegate_->CancelPairing(device_id);
break;
case BluetoothDelegate::PairPromptStatus::kSuccess:
pairing_manager_delegate_->SetPinCode(device_id, result.pin);
break;
}
}
void WebBluetoothPairingManagerImpl::OnPairConfirmResult(
blink::WebBluetoothDeviceId device_id,
const BluetoothDelegate::PairPromptResult& result) {
switch (result.result_code) {
case BluetoothDelegate::PairPromptStatus::kCancelled:
pairing_manager_delegate_->CancelPairing(device_id);
break;
case BluetoothDelegate::PairPromptStatus::kSuccess:
pairing_manager_delegate_->PairConfirmed(device_id);
break;
}
}
void WebBluetoothPairingManagerImpl::RequestPasskey(BluetoothDevice* device) {
device->CancelPairing();
NOTIMPLEMENTED() << "Passkey pairing not supported.";
}
void WebBluetoothPairingManagerImpl::DisplayPinCode(
BluetoothDevice* device,
const std::string& pincode) {
device->CancelPairing();
NOTIMPLEMENTED();
}
void WebBluetoothPairingManagerImpl::DisplayPasskey(BluetoothDevice* device,
uint32_t passkey) {
device->CancelPairing();
NOTIMPLEMENTED();
}
void WebBluetoothPairingManagerImpl::KeysEntered(BluetoothDevice* device,
uint32_t entered) {
device->CancelPairing();
NOTIMPLEMENTED();
}
void WebBluetoothPairingManagerImpl::ConfirmPasskey(BluetoothDevice* device,
uint32_t passkey) {
blink::WebBluetoothDeviceId device_id =
pairing_manager_delegate_->GetWebBluetoothDeviceId(device->GetAddress());
// In HstringToUint32() we have validated original uint32_t passkey range from
// 0 to 999999 before conversion. So here we can safely always assume
// pin.size() == 6 after conversion
std::u16string pin = base::ASCIIToUTF16(base::StringPrintf("%06u", passkey));
pairing_manager_delegate_->PromptForBluetoothPairing(
device->GetNameForDisplay(),
base::BindOnce(&WebBluetoothPairingManagerImpl::OnPairConfirmResult,
weak_ptr_factory_.GetWeakPtr(), device_id),
BluetoothDelegate::PairingKind::kConfirmPinMatch, pin);
}
void WebBluetoothPairingManagerImpl::AuthorizePairing(BluetoothDevice* device) {
blink::WebBluetoothDeviceId device_id =
pairing_manager_delegate_->GetWebBluetoothDeviceId(device->GetAddress());
pairing_manager_delegate_->PromptForBluetoothPairing(
device->GetNameForDisplay(),
base::BindOnce(&WebBluetoothPairingManagerImpl::OnPairConfirmResult,
weak_ptr_factory_.GetWeakPtr(), device_id),
BluetoothDelegate::PairingKind::kConfirmOnly, std::nullopt);
}
} // namespace content