blob: 9b7c986f723bb9330b419a7ab586551571065577 [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/policy/webusb_allow_devices_for_urls_policy_handler.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "chrome/common/pref_names.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/policy/core/browser/policy_error_map.h"
#include "components/policy/core/common/policy_map.h"
#include "components/policy/policy_constants.h"
#include "components/prefs/pref_value_map.h"
#include "url/gurl.h"
namespace policy {
namespace {
constexpr char kDevicesKey[] = "devices";
constexpr char kVendorIdKey[] = "vendor_id";
constexpr char kProductIdKey[] = "product_id";
constexpr char kUrlsKey[] = "urls";
constexpr char kErrorPathTemplate[] = "items[%d].%s.items[%d]";
constexpr char kInvalidUnsignedShortIntErrorTemplate[] =
"The %s must be an unsigned short integer";
constexpr char kMissingVendorIdError[] = "A vendor_id must also be specified";
constexpr char kInvalidNumberOfUrlsError[] =
"Each urls string entry must contain between 1 to 2 URLs";
constexpr char kInvalidUrlError[] = "The urls item must contain valid URLs";
} // namespace
WebUsbAllowDevicesForUrlsPolicyHandler::WebUsbAllowDevicesForUrlsPolicyHandler(
Schema schema)
: SchemaValidatingPolicyHandler(
key::kWebUsbAllowDevicesForUrls,
schema.GetKnownProperty(key::kWebUsbAllowDevicesForUrls),
SchemaOnErrorStrategy::SCHEMA_STRICT) {}
WebUsbAllowDevicesForUrlsPolicyHandler::
~WebUsbAllowDevicesForUrlsPolicyHandler() {}
bool WebUsbAllowDevicesForUrlsPolicyHandler::CheckPolicySettings(
const PolicyMap& policies,
PolicyErrorMap* errors) {
const base::Value* value = policies.GetValue(policy_name());
if (!value)
return true;
bool result =
SchemaValidatingPolicyHandler::CheckPolicySettings(policies, errors);
std::string error_path;
std::string error;
if (!result)
return result;
int item_index = 0;
for (const auto& item : value->GetList()) {
// The vendor and product ID descriptors of a USB devices should be
// unsigned short integers.
int device_index = 0;
auto* devices_list =
item.FindKeyOfType(kDevicesKey, base::Value::Type::LIST);
DCHECK(devices_list);
for (const auto& device : devices_list->GetList()) {
auto* vendor_id_value =
device.FindKeyOfType(kVendorIdKey, base::Value::Type::INTEGER);
if (vendor_id_value) {
const int vendor_id = vendor_id_value->GetInt();
if (vendor_id > 0xFFFF || vendor_id < 0) {
error_path = base::StringPrintf(kErrorPathTemplate, item_index,
kDevicesKey, device_index);
error = base::StringPrintf(kInvalidUnsignedShortIntErrorTemplate,
kVendorIdKey);
result = false;
break;
}
}
auto* product_id_value =
device.FindKeyOfType(kProductIdKey, base::Value::Type::INTEGER);
if (product_id_value) {
// If a |product_id| is specified, then a |vendor_id| must also be
// specified. Otherwise, the device policy is invalid.
if (vendor_id_value) {
const int product_id = product_id_value->GetInt();
if (product_id > 0xFFFF || product_id < 0) {
error_path = base::StringPrintf(kErrorPathTemplate, item_index,
kDevicesKey, device_index);
error = base::StringPrintf(kInvalidUnsignedShortIntErrorTemplate,
kProductIdKey);
result = false;
break;
}
} else {
error_path = base::StringPrintf(kErrorPathTemplate, item_index,
kDevicesKey, device_index);
error = kMissingVendorIdError;
result = false;
break;
}
}
++device_index;
}
// The whitelisted URLs should be valid.
int url_index = 0;
auto* urls_list = item.FindKeyOfType(kUrlsKey, base::Value::Type::LIST);
DCHECK(urls_list);
for (const auto& url_value : urls_list->GetList()) {
const std::string url_error_path = base::StringPrintf(
kErrorPathTemplate, item_index, kUrlsKey, url_index);
DCHECK(url_value.is_string());
const std::vector<std::string> urls =
base::SplitString(url_value.GetString(), ",", base::TRIM_WHITESPACE,
base::SPLIT_WANT_ALL);
if (urls.size() > 2 || urls.empty()) {
error_path = url_error_path;
error = kInvalidNumberOfUrlsError;
result = false;
break;
}
GURL requesting_url(urls[0]);
if (!requesting_url.is_valid()) {
error_path = url_error_path;
error = kInvalidUrlError;
result = false;
break;
}
if (urls.size() == 2) {
bool embedding_url_is_wildcard = urls[1].empty();
GURL embedding_url(urls[1]);
// Invalid URLs do not get stored in the GURL, so the string value is
// checked to see if it is empty to signify a wildcard.
if (!embedding_url_is_wildcard && !embedding_url.is_valid()) {
error_path = url_error_path;
error = kInvalidUrlError;
result = false;
break;
}
}
++url_index;
}
if (!error_path.empty() || !error.empty())
break;
++item_index;
}
if (errors && !error.empty()) {
if (error_path.empty())
error_path = "(ROOT)";
errors->AddError(policy_name(), error_path, error);
}
return result;
}
void WebUsbAllowDevicesForUrlsPolicyHandler::ApplyPolicySettings(
const PolicyMap& policies,
PrefValueMap* prefs) {
std::unique_ptr<base::Value> value;
if (!CheckAndGetValue(policies, nullptr, &value))
return;
if (!value || !value->is_list())
return;
prefs->SetValue(prefs::kManagedWebUsbAllowDevicesForUrls, std::move(value));
}
} // namespace policy