Commit 722c9273 authored by Ovidio Henriquez's avatar Ovidio Henriquez Committed by Commit Bot

Add validation to the requestDevice filters

This change adds validation checks to the USBDeviceFilter parameters
passed into navigator.usb.requestDevice.

Bug: 854703
Change-Id: I921a7f30a9e2ec5d46d3a74801de594565ab8a6f
Reviewed-on: https://chromium-review.googlesource.com/1196034Reviewed-by: default avatarReilly Grant <reillyg@chromium.org>
Commit-Queue: Ovidio Henriquez <odejesush@chromium.org>
Cr-Commit-Position: refs/heads/master@{#588140}
parent bc61acb9
......@@ -78,7 +78,7 @@ usb_test(() => {
return callWithTrustedClick(() => {
return navigator.usb.requestDevice({ filters: expectedFilters })
.then(device => {
assert_unreachable(
assert_unreached(
'requestDevice should reject because no device selected');
})
.catch(error => {
......@@ -87,6 +87,26 @@ usb_test(() => {
});
}, 'filters are sent correctly');
usb_test(async () => {
const badFilters = [
{ productId: 1234 }, // productId requires vendorId
{ subclassCode: 5678 }, // subclassCode requires classCode
{ protocolCode: 9012 }, // protocolCode requires subclassCode
];
for (const filter of badFilters) {
await callWithTrustedClick(async () => {
try {
await navigator.usb.requestDevice({ filters: [filter] });
assert_unreached(
'requestDevice should reject because of invalid filters');
} catch (error) {
assert_equals(error.name, 'TypeError');
}
});
}
}, 'requestDevice rejects on invalid filters');
usb_test(() => {
return getFakeDevice().then(({ device, fakeDevice }) => {
navigator.usb.test.onrequestdevice = event => {
......
......@@ -34,23 +34,53 @@ const char kFeaturePolicyBlocked[] =
"Access to the feature \"usb\" is disallowed by feature policy.";
const char kNoDeviceSelected[] = "No device selected.";
UsbDeviceFilterPtr ConvertDeviceFilter(const USBDeviceFilter& filter) {
void RejectWithTypeError(const String& error_details,
ScriptPromiseResolver* resolver) {
ScriptState::Scope scope(resolver->GetScriptState());
v8::Isolate* isolate = resolver->GetScriptState()->GetIsolate();
resolver->Reject(V8ThrowException::CreateTypeError(isolate, error_details));
}
UsbDeviceFilterPtr ConvertDeviceFilter(const USBDeviceFilter& filter,
ScriptPromiseResolver* resolver) {
auto mojo_filter = device::mojom::blink::UsbDeviceFilter::New();
mojo_filter->has_vendor_id = filter.hasVendorId();
if (mojo_filter->has_vendor_id)
mojo_filter->vendor_id = filter.vendorId();
mojo_filter->has_product_id = filter.hasProductId();
if (mojo_filter->has_product_id)
if (mojo_filter->has_product_id) {
if (!mojo_filter->has_vendor_id) {
RejectWithTypeError(
"A filter containing a productId must also contain a vendorId.",
resolver);
return nullptr;
}
mojo_filter->product_id = filter.productId();
}
mojo_filter->has_class_code = filter.hasClassCode();
if (mojo_filter->has_class_code)
mojo_filter->class_code = filter.classCode();
mojo_filter->has_subclass_code = filter.hasSubclassCode();
if (mojo_filter->has_subclass_code)
if (mojo_filter->has_subclass_code) {
if (!mojo_filter->has_class_code) {
RejectWithTypeError(
"A filter containing a subclassCode must also contain a classCode.",
resolver);
return nullptr;
}
mojo_filter->subclass_code = filter.subclassCode();
}
mojo_filter->has_protocol_code = filter.hasProtocolCode();
if (mojo_filter->has_protocol_code)
if (mojo_filter->has_protocol_code) {
if (!mojo_filter->has_subclass_code) {
RejectWithTypeError(
"A filter containing a protocolCode must also contain a "
"subclassCode.",
resolver);
return nullptr;
}
mojo_filter->protocol_code = filter.protocolCode();
}
if (filter.hasSerialNumber())
mojo_filter->serial_number = filter.serialNumber();
return mojo_filter;
......@@ -126,19 +156,26 @@ ScriptPromise USB::requestDevice(ScriptState* script_state,
"Must be handling a user gesture to show a permission request."));
}
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise promise = resolver->Promise();
Vector<UsbDeviceFilterPtr> filters;
if (options.hasFilters()) {
filters.ReserveCapacity(options.filters().size());
for (const auto& filter : options.filters())
filters.push_back(ConvertDeviceFilter(filter));
for (const auto& filter : options.filters()) {
UsbDeviceFilterPtr converted_filter =
ConvertDeviceFilter(filter, resolver);
if (!converted_filter)
return promise;
filters.push_back(std::move(converted_filter));
}
}
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
DCHECK(options.filters().size() == filters.size());
get_permission_requests_.insert(resolver);
service_->GetPermission(std::move(filters),
WTF::Bind(&USB::OnGetPermission, WrapPersistent(this),
WrapPersistent(resolver)));
return resolver->Promise();
return promise;
}
ExecutionContext* USB::GetExecutionContext() const {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment