910e62b5创建于 1月15日历史提交
// Copyright 2015 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/bluetooth_allowed_devices.h"

#include "base/strings/string_util.h"
#include "content/browser/bluetooth/bluetooth_allowed_devices_map.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/bluetooth/web_bluetooth_device_id.h"
#include "url/gurl.h"

using device::BluetoothUUID;

namespace content {
namespace {
const std::string kDeviceAddress1 = "00:00:00";
const std::string kDeviceAddress2 = "11:11:11";

const std::string kDeviceName = "TestName";

const char kGlucoseUUIDString[] = "00001808-0000-1000-8000-00805f9b34fb";
const char kHeartRateUUIDString[] = "0000180d-0000-1000-8000-00805f9b34fb";
const char kBatteryServiceUUIDString[] = "0000180f-0000-1000-8000-00805f9b34fb";
const char kBloodPressureUUIDString[] = "00001813-0000-1000-8000-00805f9b34fb";
const char kCyclingPowerUUIDString[] = "00001818-0000-1000-8000-00805f9b34fb";
const BluetoothUUID kGlucoseUUID(kGlucoseUUIDString);
const BluetoothUUID kHeartRateUUID(kHeartRateUUIDString);
const BluetoothUUID kBatteryServiceUUID(kBatteryServiceUUIDString);
const BluetoothUUID kBloodPressureUUID(kBloodPressureUUIDString);
const BluetoothUUID kCyclingPowerUUID(kCyclingPowerUUIDString);

class BluetoothAllowedDevicesTest : public testing::Test {
 protected:
  BluetoothAllowedDevicesTest() {
    empty_options_ = blink::mojom::WebBluetoothRequestDeviceOptions::New();
  }

  ~BluetoothAllowedDevicesTest() override {}

  blink::mojom::WebBluetoothRequestDeviceOptionsPtr empty_options_;
};

}  // namespace

TEST_F(BluetoothAllowedDevicesTest, UniqueOriginNotSupported) {
  auto allowed_devices_map = std::make_unique<BluetoothAllowedDevicesMap>();
  EXPECT_DEATH_IF_SUPPORTED(
      allowed_devices_map->GetOrCreateAllowedDevices(url::Origin()), "");
}

TEST_F(BluetoothAllowedDevicesTest, AddDevice) {
  BluetoothAllowedDevices allowed_devices;

  const blink::WebBluetoothDeviceId& device_id =
      allowed_devices.AddDevice(kDeviceAddress1, empty_options_);

  // Test that we can retrieve the device address/id.
  EXPECT_EQ(device_id, *allowed_devices.GetDeviceId(kDeviceAddress1));
  EXPECT_EQ(kDeviceAddress1, allowed_devices.GetDeviceAddress(device_id));
}

TEST_F(BluetoothAllowedDevicesTest, AddDeviceTwice) {
  BluetoothAllowedDevices allowed_devices;
  const blink::WebBluetoothDeviceId& device_id1 =
      allowed_devices.AddDevice(kDeviceAddress1, empty_options_);
  const blink::WebBluetoothDeviceId& device_id2 =
      allowed_devices.AddDevice(kDeviceAddress1, empty_options_);

  EXPECT_EQ(device_id1, device_id2);

  // Test that we can retrieve the device address/id.
  EXPECT_EQ(device_id1, *allowed_devices.GetDeviceId(kDeviceAddress1));
  EXPECT_EQ(kDeviceAddress1, allowed_devices.GetDeviceAddress(device_id1));
}

TEST_F(BluetoothAllowedDevicesTest, AddTwoDevices) {
  BluetoothAllowedDevices allowed_devices;
  const blink::WebBluetoothDeviceId& device_id1 =
      allowed_devices.AddDevice(kDeviceAddress1, empty_options_);
  const blink::WebBluetoothDeviceId& device_id2 =
      allowed_devices.AddDevice(kDeviceAddress2, empty_options_);

  EXPECT_NE(device_id1, device_id2);

  // Test that we can retrieve the device address/id.
  EXPECT_EQ(device_id1, *allowed_devices.GetDeviceId(kDeviceAddress1));
  EXPECT_EQ(device_id2, *allowed_devices.GetDeviceId(kDeviceAddress2));

  EXPECT_EQ(kDeviceAddress1, allowed_devices.GetDeviceAddress(device_id1));
  EXPECT_EQ(kDeviceAddress2, allowed_devices.GetDeviceAddress(device_id2));
}

TEST_F(BluetoothAllowedDevicesTest, AddTwoDevicesFromTwoOriginsToMap) {
  auto allowed_devices_map = std::make_unique<BluetoothAllowedDevicesMap>();
  content::BluetoothAllowedDevices& allowed_devices1 =
      allowed_devices_map->GetOrCreateAllowedDevices(
          url::Origin::Create(GURL("https://www.example1.com")));
  content::BluetoothAllowedDevices& allowed_devices2 =
      allowed_devices_map->GetOrCreateAllowedDevices(
          url::Origin::Create(GURL("https://www.example2.com")));

  const blink::WebBluetoothDeviceId& device_id1 =
      allowed_devices1.AddDevice(kDeviceAddress1, empty_options_);
  const blink::WebBluetoothDeviceId& device_id2 =
      allowed_devices2.AddDevice(kDeviceAddress2, empty_options_);

  EXPECT_NE(device_id1, device_id2);

  // Test that the wrong origin doesn't have access to the device.
  EXPECT_EQ(nullptr, allowed_devices1.GetDeviceId(kDeviceAddress2));
  EXPECT_EQ(nullptr, allowed_devices2.GetDeviceId(kDeviceAddress1));

  EXPECT_EQ(std::string(), allowed_devices1.GetDeviceAddress(device_id2));
  EXPECT_EQ(std::string(), allowed_devices2.GetDeviceAddress(device_id1));

  // Test that we can retrieve the device address/id.
  EXPECT_EQ(device_id1, *(allowed_devices1.GetDeviceId(kDeviceAddress1)));
  EXPECT_EQ(device_id2, *(allowed_devices2.GetDeviceId(kDeviceAddress2)));

  EXPECT_EQ(kDeviceAddress1, allowed_devices1.GetDeviceAddress(device_id1));
  EXPECT_EQ(kDeviceAddress2, allowed_devices2.GetDeviceAddress(device_id2));
}

TEST_F(BluetoothAllowedDevicesTest, AddDeviceFromTwoOriginsToMap) {
  auto allowed_devices_map = std::make_unique<BluetoothAllowedDevicesMap>();
  content::BluetoothAllowedDevices& allowed_devices1 =
      allowed_devices_map->GetOrCreateAllowedDevices(
          url::Origin::Create(GURL("https://www.example1.com")));
  content::BluetoothAllowedDevices& allowed_devices2 =
      allowed_devices_map->GetOrCreateAllowedDevices(
          url::Origin::Create(GURL("https://www.example2.com")));

  const blink::WebBluetoothDeviceId& device_id1 =
      allowed_devices1.AddDevice(kDeviceAddress1, empty_options_);
  const blink::WebBluetoothDeviceId& device_id2 =
      allowed_devices2.AddDevice(kDeviceAddress1, empty_options_);

  EXPECT_NE(device_id1, device_id2);

  // Test that the wrong origin doesn't have access to the device.
  EXPECT_EQ(std::string(), allowed_devices1.GetDeviceAddress(device_id2));
  EXPECT_EQ(std::string(), allowed_devices2.GetDeviceAddress(device_id1));
}

TEST_F(BluetoothAllowedDevicesTest, AddRemoveAddDevice) {
  BluetoothAllowedDevices allowed_devices;
  const blink::WebBluetoothDeviceId device_id_first_time =
      allowed_devices.AddDevice(kDeviceAddress1, empty_options_);

  allowed_devices.RemoveDevice(kDeviceAddress1);

  const blink::WebBluetoothDeviceId device_id_second_time =
      allowed_devices.AddDevice(kDeviceAddress1, empty_options_);

  EXPECT_NE(device_id_first_time, device_id_second_time);
}

TEST_F(BluetoothAllowedDevicesTest, RemoveDevice) {
  BluetoothAllowedDevices allowed_devices;

  const blink::WebBluetoothDeviceId device_id =
      allowed_devices.AddDevice(kDeviceAddress1, empty_options_);

  allowed_devices.RemoveDevice(kDeviceAddress1);

  EXPECT_EQ(nullptr, allowed_devices.GetDeviceId(kDeviceAddress1));
  EXPECT_EQ(std::string(), allowed_devices.GetDeviceAddress(device_id));
}

TEST_F(BluetoothAllowedDevicesTest, NoPermissionForAnyService) {
  BluetoothAllowedDevices allowed_devices;

  // Setup device.
  blink::mojom::WebBluetoothRequestDeviceOptionsPtr options =
      blink::mojom::WebBluetoothRequestDeviceOptions::New();
  blink::mojom::WebBluetoothLeScanFilterPtr scan_filter =
      blink::mojom::WebBluetoothLeScanFilter::New();

  scan_filter->name = kDeviceName;
  options->filters.emplace();
  options->filters->push_back({scan_filter.Clone()});

  // Add to map.
  const blink::WebBluetoothDeviceId device_id =
      allowed_devices.AddDevice(kDeviceAddress1, options);

  // Try to access at least one service.
  EXPECT_FALSE(allowed_devices.IsAllowedToAccessAtLeastOneService(device_id));
  EXPECT_FALSE(
      allowed_devices.IsAllowedToAccessService(device_id, kGlucoseUUID));
}

TEST_F(BluetoothAllowedDevicesTest, AllowedServices_OneDevice) {
  BluetoothAllowedDevices allowed_devices;

  // Setup device.
  blink::mojom::WebBluetoothRequestDeviceOptionsPtr options =
      blink::mojom::WebBluetoothRequestDeviceOptions::New();
  blink::mojom::WebBluetoothLeScanFilterPtr scan_filter1 =
      blink::mojom::WebBluetoothLeScanFilter::New();
  blink::mojom::WebBluetoothLeScanFilterPtr scan_filter2 =
      blink::mojom::WebBluetoothLeScanFilter::New();

  scan_filter1->services.emplace();
  scan_filter1->services->push_back(kGlucoseUUID);
  options->filters.emplace();
  options->filters->push_back(scan_filter1.Clone());

  scan_filter2->services.emplace();
  scan_filter2->services->push_back(kHeartRateUUID);
  options->filters->push_back(scan_filter2.Clone());

  options->optional_services.push_back(kBatteryServiceUUID);
  options->optional_services.push_back(kHeartRateUUID);

  // Add to map.
  const blink::WebBluetoothDeviceId device_id1 =
      allowed_devices.AddDevice(kDeviceAddress1, options);

  // Access allowed services.
  EXPECT_TRUE(allowed_devices.IsAllowedToAccessAtLeastOneService(device_id1));
  EXPECT_TRUE(
      allowed_devices.IsAllowedToAccessService(device_id1, kGlucoseUUID));
  EXPECT_TRUE(
      allowed_devices.IsAllowedToAccessService(device_id1, kHeartRateUUID));
  EXPECT_TRUE(allowed_devices.IsAllowedToAccessService(device_id1,
                                                       kBatteryServiceUUID));

  // Try to access a non-allowed service.
  EXPECT_FALSE(
      allowed_devices.IsAllowedToAccessService(device_id1, kBloodPressureUUID));

  // Try to access allowed services after removing device.
  allowed_devices.RemoveDevice(kDeviceAddress1);

  EXPECT_FALSE(allowed_devices.IsAllowedToAccessAtLeastOneService(device_id1));
  EXPECT_FALSE(
      allowed_devices.IsAllowedToAccessService(device_id1, kGlucoseUUID));
  EXPECT_FALSE(
      allowed_devices.IsAllowedToAccessService(device_id1, kHeartRateUUID));
  EXPECT_FALSE(allowed_devices.IsAllowedToAccessService(device_id1,
                                                        kBatteryServiceUUID));

  // Add device back.
  blink::mojom::WebBluetoothRequestDeviceOptionsPtr options2 =
      blink::mojom::WebBluetoothRequestDeviceOptions::New();

  options2->filters.emplace();
  options2->filters->push_back(scan_filter1.Clone());
  options2->filters->push_back(scan_filter2.Clone());

  const blink::WebBluetoothDeviceId device_id2 =
      allowed_devices.AddDevice(kDeviceAddress1, options2);

  // Access allowed services.
  EXPECT_TRUE(allowed_devices.IsAllowedToAccessAtLeastOneService(device_id2));
  EXPECT_TRUE(
      allowed_devices.IsAllowedToAccessService(device_id2, kGlucoseUUID));
  EXPECT_TRUE(
      allowed_devices.IsAllowedToAccessService(device_id2, kHeartRateUUID));

  // Try to access a non-allowed service.
  EXPECT_FALSE(allowed_devices.IsAllowedToAccessService(device_id2,
                                                        kBatteryServiceUUID));

  // Try to access services from old device.
  EXPECT_FALSE(
      allowed_devices.IsAllowedToAccessService(device_id1, kGlucoseUUID));
  EXPECT_FALSE(
      allowed_devices.IsAllowedToAccessService(device_id1, kHeartRateUUID));
  EXPECT_FALSE(allowed_devices.IsAllowedToAccessService(device_id1,
                                                        kBatteryServiceUUID));
}

TEST_F(BluetoothAllowedDevicesTest, AllowedServices_TwoDevices) {
  BluetoothAllowedDevices allowed_devices;

  // Setup request for device #1.
  blink::mojom::WebBluetoothRequestDeviceOptionsPtr options1 =
      blink::mojom::WebBluetoothRequestDeviceOptions::New();
  blink::mojom::WebBluetoothLeScanFilterPtr scan_filter1 =
      blink::mojom::WebBluetoothLeScanFilter::New();

  scan_filter1->services.emplace();
  scan_filter1->services->push_back(kGlucoseUUID);
  options1->filters.emplace();
  options1->filters->push_back(std::move(scan_filter1));

  options1->optional_services.push_back(kHeartRateUUID);

  // Setup request for device #2.
  blink::mojom::WebBluetoothRequestDeviceOptionsPtr options2 =
      blink::mojom::WebBluetoothRequestDeviceOptions::New();
  blink::mojom::WebBluetoothLeScanFilterPtr scan_filter2 =
      blink::mojom::WebBluetoothLeScanFilter::New();

  scan_filter2->services.emplace();
  scan_filter2->services->push_back(kBatteryServiceUUID);
  options2->filters.emplace();
  options2->filters->push_back(std::move(scan_filter2));

  options2->optional_services.push_back(kBloodPressureUUID);

  // Add devices to map.
  const blink::WebBluetoothDeviceId& device_id1 =
      allowed_devices.AddDevice(kDeviceAddress1, options1);
  const blink::WebBluetoothDeviceId& device_id2 =
      allowed_devices.AddDevice(kDeviceAddress2, options2);

  // Access allowed services.
  EXPECT_TRUE(allowed_devices.IsAllowedToAccessAtLeastOneService(device_id1));
  EXPECT_TRUE(
      allowed_devices.IsAllowedToAccessService(device_id1, kGlucoseUUID));
  EXPECT_TRUE(
      allowed_devices.IsAllowedToAccessService(device_id1, kHeartRateUUID));

  EXPECT_TRUE(allowed_devices.IsAllowedToAccessAtLeastOneService(device_id2));
  EXPECT_TRUE(allowed_devices.IsAllowedToAccessService(device_id2,
                                                       kBatteryServiceUUID));
  EXPECT_TRUE(
      allowed_devices.IsAllowedToAccessService(device_id2, kBloodPressureUUID));

  // Try to access non-allowed services.
  EXPECT_FALSE(allowed_devices.IsAllowedToAccessService(device_id1,
                                                        kBatteryServiceUUID));
  EXPECT_FALSE(
      allowed_devices.IsAllowedToAccessService(device_id1, kBloodPressureUUID));
  EXPECT_FALSE(
      allowed_devices.IsAllowedToAccessService(device_id1, kCyclingPowerUUID));

  EXPECT_FALSE(
      allowed_devices.IsAllowedToAccessService(device_id2, kGlucoseUUID));
  EXPECT_FALSE(
      allowed_devices.IsAllowedToAccessService(device_id2, kHeartRateUUID));
  EXPECT_FALSE(
      allowed_devices.IsAllowedToAccessService(device_id2, kCyclingPowerUUID));
}

TEST_F(BluetoothAllowedDevicesTest, AllowedServices_TwoOriginsOneDevice) {
  auto allowed_devices_map = std::make_unique<BluetoothAllowedDevicesMap>();
  content::BluetoothAllowedDevices& allowed_devices1 =
      allowed_devices_map->GetOrCreateAllowedDevices(
          url::Origin::Create(GURL("https://www.example1.com")));
  content::BluetoothAllowedDevices& allowed_devices2 =
      allowed_devices_map->GetOrCreateAllowedDevices(
          url::Origin::Create(GURL("https://www.example2.com")));
  // Setup request #1 for device.
  blink::mojom::WebBluetoothRequestDeviceOptionsPtr options1 =
      blink::mojom::WebBluetoothRequestDeviceOptions::New();
  blink::mojom::WebBluetoothLeScanFilterPtr scan_filter1 =
      blink::mojom::WebBluetoothLeScanFilter::New();

  scan_filter1->services.emplace();
  scan_filter1->services->push_back(kGlucoseUUID);
  options1->filters.emplace();
  options1->filters->push_back(std::move(scan_filter1));

  options1->optional_services.push_back(kHeartRateUUID);

  // Setup request #2 for device.
  blink::mojom::WebBluetoothRequestDeviceOptionsPtr options2 =
      blink::mojom::WebBluetoothRequestDeviceOptions::New();
  blink::mojom::WebBluetoothLeScanFilterPtr scan_filter2 =
      blink::mojom::WebBluetoothLeScanFilter::New();

  scan_filter2->services.emplace();
  scan_filter2->services->push_back(kBatteryServiceUUID);
  options2->filters.emplace();
  options2->filters->push_back(std::move(scan_filter2));

  options2->optional_services.push_back(kBloodPressureUUID);

  // Add devices to map.
  const blink::WebBluetoothDeviceId& device_id1 =
      allowed_devices1.AddDevice(kDeviceAddress1, options1);
  const blink::WebBluetoothDeviceId& device_id2 =
      allowed_devices2.AddDevice(kDeviceAddress1, options2);

  // Access allowed services.
  EXPECT_TRUE(allowed_devices1.IsAllowedToAccessAtLeastOneService(device_id1));
  EXPECT_TRUE(
      allowed_devices1.IsAllowedToAccessService(device_id1, kGlucoseUUID));
  EXPECT_TRUE(
      allowed_devices1.IsAllowedToAccessService(device_id1, kHeartRateUUID));

  EXPECT_TRUE(allowed_devices2.IsAllowedToAccessAtLeastOneService(device_id2));
  EXPECT_TRUE(allowed_devices2.IsAllowedToAccessService(device_id2,
                                                        kBatteryServiceUUID));
  EXPECT_TRUE(allowed_devices2.IsAllowedToAccessService(device_id2,
                                                        kBloodPressureUUID));

  // Try to access non-allowed services.
  EXPECT_FALSE(allowed_devices1.IsAllowedToAccessService(device_id1,
                                                         kBatteryServiceUUID));
  EXPECT_FALSE(allowed_devices1.IsAllowedToAccessService(device_id1,
                                                         kBloodPressureUUID));

  EXPECT_FALSE(allowed_devices1.IsAllowedToAccessAtLeastOneService(device_id2));
  EXPECT_FALSE(
      allowed_devices1.IsAllowedToAccessService(device_id2, kGlucoseUUID));
  EXPECT_FALSE(
      allowed_devices1.IsAllowedToAccessService(device_id2, kHeartRateUUID));
  EXPECT_FALSE(allowed_devices1.IsAllowedToAccessService(device_id2,
                                                         kBatteryServiceUUID));
  EXPECT_FALSE(allowed_devices1.IsAllowedToAccessService(device_id2,
                                                         kBloodPressureUUID));

  EXPECT_FALSE(
      allowed_devices2.IsAllowedToAccessService(device_id2, kGlucoseUUID));
  EXPECT_FALSE(
      allowed_devices2.IsAllowedToAccessService(device_id2, kHeartRateUUID));

  EXPECT_FALSE(allowed_devices2.IsAllowedToAccessAtLeastOneService(device_id1));
  EXPECT_FALSE(
      allowed_devices2.IsAllowedToAccessService(device_id1, kGlucoseUUID));
  EXPECT_FALSE(
      allowed_devices2.IsAllowedToAccessService(device_id1, kHeartRateUUID));
  EXPECT_FALSE(allowed_devices2.IsAllowedToAccessService(device_id1,
                                                         kBatteryServiceUUID));
  EXPECT_FALSE(allowed_devices2.IsAllowedToAccessService(device_id1,
                                                         kBloodPressureUUID));
}

TEST_F(BluetoothAllowedDevicesTest, MergeServices) {
  BluetoothAllowedDevices allowed_devices;

  // Setup first request.
  blink::mojom::WebBluetoothRequestDeviceOptionsPtr options1 =
      blink::mojom::WebBluetoothRequestDeviceOptions::New();
  blink::mojom::WebBluetoothLeScanFilterPtr scan_filter1 =
      blink::mojom::WebBluetoothLeScanFilter::New();

  scan_filter1->services.emplace();
  scan_filter1->services->push_back(kGlucoseUUID);
  options1->filters.emplace();
  options1->filters->push_back(std::move(scan_filter1));

  options1->optional_services.push_back(kBatteryServiceUUID);

  // Add to map.
  const blink::WebBluetoothDeviceId device_id1 =
      allowed_devices.AddDevice(kDeviceAddress1, options1);

  // Setup second request.
  blink::mojom::WebBluetoothRequestDeviceOptionsPtr options2 =
      blink::mojom::WebBluetoothRequestDeviceOptions::New();
  blink::mojom::WebBluetoothLeScanFilterPtr scan_filter2 =
      blink::mojom::WebBluetoothLeScanFilter::New();

  scan_filter2->services.emplace();
  scan_filter2->services->push_back(kHeartRateUUID);
  options2->filters.emplace();
  options2->filters->push_back(std::move(scan_filter2));

  options2->optional_services.push_back(kBloodPressureUUID);

  // Add to map again.
  const blink::WebBluetoothDeviceId device_id2 =
      allowed_devices.AddDevice(kDeviceAddress1, options2);

  EXPECT_EQ(device_id1, device_id2);

  EXPECT_TRUE(allowed_devices.IsAllowedToAccessAtLeastOneService(device_id1));
  EXPECT_TRUE(
      allowed_devices.IsAllowedToAccessService(device_id1, kGlucoseUUID));
  EXPECT_TRUE(allowed_devices.IsAllowedToAccessService(device_id1,
                                                       kBatteryServiceUUID));
  EXPECT_TRUE(
      allowed_devices.IsAllowedToAccessService(device_id1, kHeartRateUUID));
  EXPECT_TRUE(
      allowed_devices.IsAllowedToAccessService(device_id1, kBloodPressureUUID));
}

TEST_F(BluetoothAllowedDevicesTest, CorrectIdFormat) {
  BluetoothAllowedDevices allowed_devices;

  const blink::WebBluetoothDeviceId& device_id =
      allowed_devices.AddDevice(kDeviceAddress1, empty_options_);

  EXPECT_TRUE(blink::WebBluetoothDeviceId::IsValid(device_id.str()));
}

TEST_F(BluetoothAllowedDevicesTest, NoFilterServices) {
  BluetoothAllowedDevices allowed_devices;

  // Setup request.
  blink::mojom::WebBluetoothRequestDeviceOptionsPtr options =
      blink::mojom::WebBluetoothRequestDeviceOptions::New();
  blink::mojom::WebBluetoothLeScanFilterPtr scan_filter =
      blink::mojom::WebBluetoothLeScanFilter::New();

  options->filters.emplace();
  options->filters->push_back(std::move(scan_filter));

  // Add to map.
  const blink::WebBluetoothDeviceId device_id =
      allowed_devices.AddDevice(kDeviceAddress1, options);

  EXPECT_FALSE(allowed_devices.IsAllowedToAccessAtLeastOneService(device_id));
}

}  // namespace content