910e62b5创建于 1月15日历史提交
// 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