USBPermissionRequest (WebUSB pt.5)

This commit is contained in:
wuggy 2026-09-19 14:45:05 -07:00
commit 3ab65a542d
2 changed files with 69 additions and 16 deletions

View file

@ -488,13 +488,28 @@ function USBPermissionPrompt(request) {
this.request = request;
}
function getUSBDeviceChoices(request) {
let choices = [];
let types = request.types.QueryInterface(Ci.nsIArray);
if (!types.length) {
return choices;
}
let type = types.queryElementAt(0, Ci.nsIContentPermissionType);
let options = type.options;
if (!options) {
return choices;
}
for (let i = 0; i < options.length; ++i) {
choices.push(options.queryElementAt(i, Ci.nsISupportsString).data);
}
return choices;
}
USBPermissionPrompt.prototype = {
__proto__: PermissionPromptForRequestPrototype,
get permissionKey() {
return "usb";
},
get notificationID() {
return "web-usb";
},
@ -509,17 +524,21 @@ USBPermissionPrompt.prototype = {
},
get promptActions() {
return [{
label: getUSBString("webUSB.allow", "Allow USB Devices"),
accessKey: getUSBString("webUSB.allow.accesskey", "A"),
action: Ci.nsIPermissionManager.ALLOW_ACTION,
expireType: Ci.nsIPermissionManager.EXPIRE_SESSION,
}, {
let actions = [];
for (let choice of getUSBDeviceChoices(this.request)) {
actions.push({
label: choice,
accessKey: "",
callback: () => this.request.allow({usb: choice}),
});
}
actions.push({
label: getUSBString("webUSB.block", "Block USB Devices"),
accessKey: getUSBString("webUSB.block.accesskey", "B"),
action: Ci.nsIPermissionManager.DENY_ACTION,
expireType: Ci.nsIPermissionManager.EXPIRE_SESSION,
}];
callback: () => this.cancel(),
});
return actions;
},
};

View file

@ -5,7 +5,10 @@
#include "mozilla/dom/USBBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/USBDevice.h"
#include "mozilla/dom/ScriptSettings.h"
#include "jsapi.h"
#include "nsContentPermissionHelper.h"
#include "nsContentUtils.h"
#include "nsIDocument.h"
#include "nsError.h"
#include "nsPIDOMWindow.h"
@ -177,15 +180,46 @@ USBPermissionRequest::Cancel()
NS_IMETHODIMP
USBPermissionRequest::Allow(JS::HandleValue aChoices)
{
(void)aChoices;
if (mCandidates.IsEmpty()) {
mPromise->MaybeReject(NS_ERROR_DOM_NOT_FOUND_ERR);
return NS_OK;
}
RefPtr<USBDevice> device = mCandidates[0];
uint32_t selected = 0;
if (aChoices.isObject()) {
JSContext* cx = nsContentUtils::GetCurrentJSContext();
if (cx) {
JS::RootedObject object(cx, &aChoices.toObject());
JSAutoCompartment ac(cx, object);
JS::RootedValue value(cx);
if (JS_GetProperty(cx, object, "usb", &value) && value.isString()) {
nsAutoJSString choice;
if (choice.init(cx, value)) {
for (uint32_t i = 0; i < mCandidates.Length(); ++i) {
DOMString label;
mCandidates[i]->GetProductName(label);
nsAutoString labelString;
label.ToString(labelString);
if ((label.IsNull() || labelString.IsEmpty()) &&
choice.EqualsLiteral("USB device")) {
selected = i;
break;
}
if (!label.IsNull() && labelString.Equals(choice)) {
selected = i;
break;
}
}
}
} else {
JS_ClearPendingException(cx);
}
}
}
RefPtr<USBDevice> device = mCandidates[selected];
mUSB->AddAuthorizedDevice(device);
mPromise->MaybeResolve(device);
mPromise->MaybeResolve(device.get());
return NS_OK;
}