#include "chrome/browser/usb/usb_chooser_context.h"
#include <vector>
#include "base/containers/flat_map.h"
#include "base/functional/callback_helpers.h"
#include "base/no_destructor.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "base/test/test_future.h"
#include "base/test/values_test_util.h"
#include "base/values.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/usb/usb_chooser_context_factory.h"
#include "chrome/browser/usb/usb_chooser_context_mock_device_observer.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/test/base/testing_profile.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/permissions/test/object_permission_context_base_mock_permission_observer.h"
#include "components/prefs/pref_service.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/test/browser_task_environment.h"
#include "services/device/public/cpp/test/fake_usb_device_manager.h"
#include "services/device/public/mojom/usb_device.mojom.h"
#include "services/device/public/mojom/usb_manager.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h"
#include "chrome/browser/ash/settings/stub_cros_settings_provider.h"
#include "chromeos/ash/components/settings/cros_settings_names.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chromeos/crosapi/mojom/crosapi.mojom.h"
#include "chromeos/crosapi/mojom/device_settings_service.mojom.h"
#include "chromeos/startup/browser_init_params.h"
#endif
TestFuture;
SettingSource;
UsbDeviceInfoPtr;
_;
AnyNumber;
NiceMock;
namespace {
constexpr char kDeviceNameKey[] = …;
constexpr char kGuidKey[] = …;
constexpr char kProductIdKey[] = …;
constexpr char kSerialNumberKey[] = …;
constexpr char kVendorIdKey[] = …;
constexpr int kDeviceIdWildcard = …;
class UsbChooserContextTest : public testing::Test { … };
}
TEST_F(UsbChooserContextTest, CheckGrantAndRevokePermission) { … }
TEST_F(UsbChooserContextTest, CheckGrantAndRevokeEphemeralPermission) { … }
TEST_F(UsbChooserContextTest, DisconnectDeviceWithPermission) { … }
TEST_F(UsbChooserContextTest, DisconnectDeviceWithEphemeralPermission) { … }
TEST_F(UsbChooserContextTest, GrantPermissionInIncognito) { … }
TEST_F(UsbChooserContextTest, UsbGuardPermission) { … }
TEST_F(UsbChooserContextTest, GetObjectDisplayNameForNamelessDevice) { … }
TEST_F(UsbChooserContextTest, PolicyGuardPermission) { … }
TEST_F(UsbChooserContextTest, PolicyAskForUrls) { … }
TEST_F(UsbChooserContextTest, PolicyBlockedForUrls) { … }
namespace {
constexpr char kPolicySetting[] = …;
constexpr char kAnyDeviceUrl[] = …;
constexpr char kVendorUrl[] = …;
constexpr char kProductVendorUrl[] = …;
constexpr char kGadgetUrl[] = …;
constexpr char kCoolUrl[] = …;
const std::vector<GURL>& PolicyOrigins() { … }
void ExpectNoPermissions(UsbChooserContext* store,
const device::mojom::UsbDeviceInfo& device_info) { … }
void ExpectCorrectPermissions(UsbChooserContext* store,
const std::vector<GURL>& kValidOrigins,
const std::vector<GURL>& kInvalidOrigins,
const device::mojom::UsbDeviceInfo& device_info) { … }
}
TEST_F(UsbChooserContextTest,
UsbAllowDevicesForUrlsPermissionForSpecificDevice) { … }
TEST_F(UsbChooserContextTest,
UsbAllowDevicesForUrlsPermissionForVendorRelatedDevice) { … }
TEST_F(UsbChooserContextTest,
UsbAllowDevicesForUrlsPermissionForUnrelatedDevice) { … }
TEST_F(UsbChooserContextTest,
UsbAllowDevicesForUrlsPermissionOverrulesUsbGuardPermission) { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
class DeviceLoginScreenWebUsbChooserContextTest : public UsbChooserContextTest {
public:
DeviceLoginScreenWebUsbChooserContextTest() {
TestingProfile::Builder builder;
builder.SetPath(base::FilePath(FILE_PATH_LITERAL(chrome::kInitialProfile)));
signin_profile_ = builder.Build();
}
~DeviceLoginScreenWebUsbChooserContextTest() override = default;
protected:
Profile* GetSigninProfile() { return signin_profile_.get(); }
private:
std::unique_ptr<Profile> signin_profile_;
};
TEST_F(DeviceLoginScreenWebUsbChooserContextTest,
UserUsbChooserContextOnlyUsesUserPolicy) {
const std::vector<GURL> kValidOrigins = {
GURL(kProductVendorUrl), GURL(kVendorUrl), GURL(kAnyDeviceUrl)};
const std::vector<GURL> kInvalidOrigins = {GURL(kGadgetUrl), GURL(kCoolUrl)};
UsbDeviceInfoPtr specific_device_info = device_manager_.CreateAndAddDevice(
6353, 5678, "Google", "Gizmo", "ABC123");
Profile* user_profile = profile();
Profile* signin_profile = GetSigninProfile();
auto* user_store = GetChooserContext(user_profile);
auto* signin_store = GetChooserContext(signin_profile);
ExpectNoPermissions(user_store, *specific_device_info);
ExpectNoPermissions(signin_store, *specific_device_info);
user_profile->GetPrefs()->SetList(prefs::kManagedWebUsbAllowDevicesForUrls,
base::test::ParseJsonList(kPolicySetting));
ExpectCorrectPermissions(user_store, kValidOrigins, kInvalidOrigins,
*specific_device_info);
ExpectNoPermissions(signin_store, *specific_device_info);
}
TEST_F(DeviceLoginScreenWebUsbChooserContextTest,
SigninUsbChooserContextOnlyUsesDevicePolicy) {
const std::vector<GURL> kValidOrigins = {
GURL(kProductVendorUrl), GURL(kVendorUrl), GURL(kAnyDeviceUrl)};
const std::vector<GURL> kInvalidOrigins = {GURL(kGadgetUrl), GURL(kCoolUrl)};
UsbDeviceInfoPtr specific_device_info = device_manager_.CreateAndAddDevice(
6353, 5678, "Google", "Gizmo", "ABC123");
Profile* user_profile = profile();
Profile* signin_profile = GetSigninProfile();
auto* user_store = GetChooserContext(user_profile);
auto* signin_store = GetChooserContext(signin_profile);
ExpectNoPermissions(user_store, *specific_device_info);
ExpectNoPermissions(signin_store, *specific_device_info);
signin_profile->GetPrefs()->SetList(
prefs::kManagedWebUsbAllowDevicesForUrls,
base::test::ParseJsonList(kPolicySetting));
ExpectNoPermissions(user_store, *specific_device_info);
ExpectCorrectPermissions(signin_store, kValidOrigins, kInvalidOrigins,
*specific_device_info);
}
#endif
namespace {
void ExpectDeviceObjectInfo(const base::Value::Dict& actual,
int vendor_id,
int product_id,
const std::string& name) { … }
void ExpectChooserObjectInfo(const UsbChooserContext::Object* actual,
const GURL& origin,
SettingSource source,
bool incognito,
int vendor_id,
int product_id,
const std::string& name) { … }
}
TEST_F(UsbChooserContextTest, GetGrantedObjectsWithOnlyPolicyAllowedDevices) { … }
TEST_F(UsbChooserContextTest,
GetGrantedObjectsWithUserAndPolicyAllowedDevices) { … }
TEST_F(UsbChooserContextTest,
GetGrantedObjectsWithUserGrantedDeviceAllowedBySpecificDevicePolicy) { … }
TEST_F(UsbChooserContextTest,
GetGrantedObjectsWithUserGrantedDeviceAllowedByVendorDevicePolicy) { … }
TEST_F(UsbChooserContextTest,
GetGrantedObjectsWithUserGrantedDeviceAllowedByAnyVendorDevicePolicy) { … }
TEST_F(UsbChooserContextTest,
GetAllGrantedObjectsWithOnlyPolicyAllowedDevices) { … }
TEST_F(UsbChooserContextTest,
GetAllGrantedObjectsWithUserAndPolicyAllowedDevices) { … }
TEST_F(UsbChooserContextTest,
GetAllGrantedObjectsWithSpecificPolicyAndUserGrantedDevice) { … }
TEST_F(UsbChooserContextTest,
GetAllGrantedObjectsWithVendorPolicyAndUserGrantedDevice) { … }
TEST_F(UsbChooserContextTest,
GetAllGrantedObjectsWithAnyPolicyAndUserGrantedDevice) { … }
TEST_F(UsbChooserContextTest, MassStorageHidden) { … }
#if BUILDFLAG(IS_CHROMEOS)
TEST_F(UsbChooserContextTest, MassStorageShownWhenDetachable) {
#if BUILDFLAG(IS_CHROMEOS_ASH)
base::Value::List allowlist;
base::Value::Dict ids;
ids.Set(ash::kUsbDetachableAllowlistKeyVid, 1234);
ids.Set(ash::kUsbDetachableAllowlistKeyPid, 1);
allowlist.Append(std::move(ids));
profile()->ScopedCrosSettingsTestHelper()->GetStubbedProvider()->Set(
ash::kUsbDetachableAllowlist, base::Value(std::move(allowlist)));
#endif
#if BUILDFLAG(IS_CHROMEOS_LACROS)
auto allowlist = crosapi::mojom::UsbDetachableAllowlist::New();
auto device_id = crosapi::mojom::UsbDeviceId::New();
device_id->has_vendor_id = true;
device_id->vendor_id = 1234;
device_id->has_product_id = true;
device_id->product_id = 1;
allowlist->usb_device_ids.push_back(std::move(device_id));
auto params = crosapi::mojom::BrowserInitParams::New();
params->device_settings = crosapi::mojom::DeviceSettings::New();
params->device_settings->usb_detachable_allow_list = std::move(allowlist);
chromeos::BrowserInitParams::SetInitParamsForTests(std::move(params));
#endif
GURL kUrl("https://www.google.com");
const auto origin = url::Origin::Create(kUrl);
std::vector<device::mojom::UsbConfigurationInfoPtr> storage_configs;
storage_configs.push_back(
device::FakeUsbDeviceInfo::CreateConfiguration(0x08, 0x06, 0x50));
UsbDeviceInfoPtr detachable_storage_device_info =
device_manager_.CreateAndAddDevice(1234, 1, "vendor1",
"detachable storage", "123ABC",
std::move(storage_configs));
storage_configs.clear();
storage_configs.push_back(
device::FakeUsbDeviceInfo::CreateConfiguration(0x08, 0x06, 0x50));
UsbDeviceInfoPtr storage_device_info = device_manager_.CreateAndAddDevice(
1234, 2, "vendor1", "storage", "456DEF", std::move(storage_configs));
UsbChooserContext* chooser_context = GetChooserContext(profile());
base::RunLoop loop;
chooser_context->GetDevices(
base::BindLambdaForTesting([&](std::vector<UsbDeviceInfoPtr> devices) {
EXPECT_EQ(1u, devices.size());
EXPECT_EQ(detachable_storage_device_info->product_name,
devices[0]->product_name);
loop.Quit();
}));
loop.Run();
}
#endif
TEST_F(UsbChooserContextTest, DeviceWithNoInterfaceVisible) { … }