blob: f7c87e60057a87346e5acbf36dc7943d5008db9e [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/usb/usb_policy_allowed_devices.h"
#include "base/values.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/prefs/pref_service.h"
#include "device/usb/public/mojom/device_manager.mojom.h"
#include "url/gurl.h"
namespace {
constexpr char kPrefDevicesKey[] = "devices";
constexpr char kPrefUrlPatternsKey[] = "url_patterns";
constexpr char kPrefVendorIdKey[] = "vendor_id";
constexpr char kPrefProductIdKey[] = "product_id";
// Find the URL match by checking if the pattern matches the given GURL types
// using ContentSettingsPattern::Matches().
bool FindMatchInSet(const std::set<content_settings::PatternPair>& pattern_set,
const GURL& requesting_origin,
const GURL& embedding_origin) {
for (const auto& pattern : pattern_set) {
if (pattern.first.Matches(requesting_origin) &&
pattern.second.Matches(embedding_origin)) {
return true;
}
}
return false;
}
} // namespace
UsbPolicyAllowedDevices::UsbPolicyAllowedDevices(PrefService* pref_service) {
pref_change_registrar_.Init(pref_service);
// Add an observer for |kManagedWebUsbAllowDevicesForUrls| to call
// CreateOrUpdateMap when the value is changed. The lifetime of
// |pref_change_registrar_| is managed by this class, therefore it is safe to
// use base::Unretained here.
pref_change_registrar_.Add(
prefs::kManagedWebUsbAllowDevicesForUrls,
base::BindRepeating(&UsbPolicyAllowedDevices::CreateOrUpdateMap,
base::Unretained(this)));
CreateOrUpdateMap();
}
UsbPolicyAllowedDevices::~UsbPolicyAllowedDevices() {}
bool UsbPolicyAllowedDevices::IsDeviceAllowed(
const GURL& requesting_origin,
const GURL& embedding_origin,
const device::mojom::UsbDeviceInfo& device_info) {
// Search through each set of URL patterns that match the given device. The
// keys correspond to the following URL pattern sets:
// * (vendor_id, product_id): A set corresponding to the exact device.
// * (vendor_id, -1): A set corresponding to any device with |vendor_id|.
// * (-1, -1): A set corresponding to any device.
const std::pair<int, int> set_keys[] = {
std::make_pair(device_info.vendor_id, device_info.product_id),
std::make_pair(device_info.vendor_id, -1), std::make_pair(-1, -1)};
for (const auto& key : set_keys) {
const auto patterns = usb_device_ids_to_url_patterns_.find(key);
if (patterns == usb_device_ids_to_url_patterns_.cend())
continue;
if (FindMatchInSet(patterns->second, requesting_origin, embedding_origin))
return true;
}
return false;
}
void UsbPolicyAllowedDevices::CreateOrUpdateMap() {
const base::Value* pref_value = pref_change_registrar_.prefs()->Get(
prefs::kManagedWebUsbAllowDevicesForUrls);
usb_device_ids_to_url_patterns_.clear();
// A policy has not been assigned.
if (!pref_value) {
return;
}
// The pref value has already been validated by the policy handler, so it is
// safe to assume that |pref_value| follows the policy template.
for (const auto& item : pref_value->GetList()) {
const base::Value* url_patterns = item.FindKey(kPrefUrlPatternsKey);
std::set<content_settings::PatternPair> parsed_url_set;
// Parse each URL pattern into a PatternPair and store it in
// |parsed_url_set|.
for (const auto& url_pattern : url_patterns->GetList()) {
content_settings::PatternPair pattern_pair =
content_settings::ParsePatternString(url_pattern.GetString());
// Ignore invalid patterns.
if (!pattern_pair.first.IsValid())
continue;
parsed_url_set.insert(std::move(pattern_pair));
}
// Ignore items with empty parsed URLs.
if (parsed_url_set.empty())
continue;
// For each device entry in the map, create or update its respective URL
// pattern set.
const base::Value* devices = item.FindKey(kPrefDevicesKey);
for (const auto& device : devices->GetList()) {
// A missing ID signifies a wildcard for that ID, so a sentinel value of
// -1 is assigned.
const base::Value* vendor_id_value = device.FindKey(kPrefVendorIdKey);
const base::Value* product_id_value = device.FindKey(kPrefProductIdKey);
int vendor_id = vendor_id_value ? vendor_id_value->GetInt() : -1;
int product_id = product_id_value ? product_id_value->GetInt() : -1;
DCHECK(vendor_id != -1 || product_id == -1);
auto key = std::make_pair(vendor_id, product_id);
usb_device_ids_to_url_patterns_[key].insert(parsed_url_set.begin(),
parsed_url_set.end());
}
}
}