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; 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 = { USBPermissionPrompt.prototype = {
__proto__: PermissionPromptForRequestPrototype, __proto__: PermissionPromptForRequestPrototype,
get permissionKey() {
return "usb";
},
get notificationID() { get notificationID() {
return "web-usb"; return "web-usb";
}, },
@ -509,17 +524,21 @@ USBPermissionPrompt.prototype = {
}, },
get promptActions() { get promptActions() {
return [{ let actions = [];
label: getUSBString("webUSB.allow", "Allow USB Devices"), for (let choice of getUSBDeviceChoices(this.request)) {
accessKey: getUSBString("webUSB.allow.accesskey", "A"), actions.push({
action: Ci.nsIPermissionManager.ALLOW_ACTION, label: choice,
expireType: Ci.nsIPermissionManager.EXPIRE_SESSION, accessKey: "",
}, { callback: () => this.request.allow({usb: choice}),
});
}
actions.push({
label: getUSBString("webUSB.block", "Block USB Devices"), label: getUSBString("webUSB.block", "Block USB Devices"),
accessKey: getUSBString("webUSB.block.accesskey", "B"), accessKey: getUSBString("webUSB.block.accesskey", "B"),
action: Ci.nsIPermissionManager.DENY_ACTION, callback: () => this.cancel(),
expireType: Ci.nsIPermissionManager.EXPIRE_SESSION, });
}]; return actions;
}, },
}; };

View file

@ -5,7 +5,10 @@
#include "mozilla/dom/USBBinding.h" #include "mozilla/dom/USBBinding.h"
#include "mozilla/dom/Promise.h" #include "mozilla/dom/Promise.h"
#include "mozilla/dom/USBDevice.h" #include "mozilla/dom/USBDevice.h"
#include "mozilla/dom/ScriptSettings.h"
#include "jsapi.h"
#include "nsContentPermissionHelper.h" #include "nsContentPermissionHelper.h"
#include "nsContentUtils.h"
#include "nsIDocument.h" #include "nsIDocument.h"
#include "nsError.h" #include "nsError.h"
#include "nsPIDOMWindow.h" #include "nsPIDOMWindow.h"
@ -177,15 +180,46 @@ USBPermissionRequest::Cancel()
NS_IMETHODIMP NS_IMETHODIMP
USBPermissionRequest::Allow(JS::HandleValue aChoices) USBPermissionRequest::Allow(JS::HandleValue aChoices)
{ {
(void)aChoices;
if (mCandidates.IsEmpty()) { if (mCandidates.IsEmpty()) {
mPromise->MaybeReject(NS_ERROR_DOM_NOT_FOUND_ERR); mPromise->MaybeReject(NS_ERROR_DOM_NOT_FOUND_ERR);
return NS_OK; 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); mUSB->AddAuthorizedDevice(device);
mPromise->MaybeResolve(device); mPromise->MaybeResolve(device.get());
return NS_OK; return NS_OK;
} }