chore: Show FIDO devices in the chooser if allowed (#40216)
* chore: Show FIDO devices in the chooser if allowed * chore: tweak HidChooserContext::IsFidoAllowedForOrigin * chore: feedback from review --------- Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
This commit is contained in:
parent
32a721fa2b
commit
025af3500c
5 changed files with 110 additions and 37 deletions
|
@ -29,6 +29,8 @@ namespace {
|
||||||
|
|
||||||
electron::HidChooserContext* GetChooserContext(
|
electron::HidChooserContext* GetChooserContext(
|
||||||
content::BrowserContext* browser_context) {
|
content::BrowserContext* browser_context) {
|
||||||
|
if (!browser_context)
|
||||||
|
return nullptr;
|
||||||
return electron::HidChooserContextFactory::GetForBrowserContext(
|
return electron::HidChooserContextFactory::GetForBrowserContext(
|
||||||
browser_context);
|
browser_context);
|
||||||
}
|
}
|
||||||
|
@ -110,6 +112,7 @@ std::unique_ptr<content::HidChooser> ElectronHidDelegate::RunChooser(
|
||||||
std::vector<blink::mojom::HidDeviceFilterPtr> filters,
|
std::vector<blink::mojom::HidDeviceFilterPtr> filters,
|
||||||
std::vector<blink::mojom::HidDeviceFilterPtr> exclusion_filters,
|
std::vector<blink::mojom::HidDeviceFilterPtr> exclusion_filters,
|
||||||
content::HidChooser::Callback callback) {
|
content::HidChooser::Callback callback) {
|
||||||
|
DCHECK(render_frame_host);
|
||||||
auto* browser_context = render_frame_host->GetBrowserContext();
|
auto* browser_context = render_frame_host->GetBrowserContext();
|
||||||
|
|
||||||
// Start observing HidChooserContext for permission and device events.
|
// Start observing HidChooserContext for permission and device events.
|
||||||
|
@ -133,6 +136,9 @@ std::unique_ptr<content::HidChooser> ElectronHidDelegate::RunChooser(
|
||||||
bool ElectronHidDelegate::CanRequestDevicePermission(
|
bool ElectronHidDelegate::CanRequestDevicePermission(
|
||||||
content::BrowserContext* browser_context,
|
content::BrowserContext* browser_context,
|
||||||
const url::Origin& origin) {
|
const url::Origin& origin) {
|
||||||
|
if (!browser_context)
|
||||||
|
return false;
|
||||||
|
|
||||||
base::Value::Dict details;
|
base::Value::Dict details;
|
||||||
details.Set("securityOrigin", origin.GetURL().spec());
|
details.Set("securityOrigin", origin.GetURL().spec());
|
||||||
auto* permission_manager = static_cast<ElectronPermissionManager*>(
|
auto* permission_manager = static_cast<ElectronPermissionManager*>(
|
||||||
|
@ -147,31 +153,38 @@ bool ElectronHidDelegate::HasDevicePermission(
|
||||||
content::BrowserContext* browser_context,
|
content::BrowserContext* browser_context,
|
||||||
const url::Origin& origin,
|
const url::Origin& origin,
|
||||||
const device::mojom::HidDeviceInfo& device) {
|
const device::mojom::HidDeviceInfo& device) {
|
||||||
return GetChooserContext(browser_context)
|
return browser_context && GetChooserContext(browser_context)
|
||||||
->HasDevicePermission(origin, device);
|
->HasDevicePermission(origin, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ElectronHidDelegate::RevokeDevicePermission(
|
void ElectronHidDelegate::RevokeDevicePermission(
|
||||||
content::BrowserContext* browser_context,
|
content::BrowserContext* browser_context,
|
||||||
const url::Origin& origin,
|
const url::Origin& origin,
|
||||||
const device::mojom::HidDeviceInfo& device) {
|
const device::mojom::HidDeviceInfo& device) {
|
||||||
return GetChooserContext(browser_context)
|
if (browser_context) {
|
||||||
->RevokeDevicePermission(origin, device);
|
GetChooserContext(browser_context)->RevokeDevicePermission(origin, device);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
device::mojom::HidManager* ElectronHidDelegate::GetHidManager(
|
device::mojom::HidManager* ElectronHidDelegate::GetHidManager(
|
||||||
content::BrowserContext* browser_context) {
|
content::BrowserContext* browser_context) {
|
||||||
|
if (!browser_context)
|
||||||
|
return nullptr;
|
||||||
return GetChooserContext(browser_context)->GetHidManager();
|
return GetChooserContext(browser_context)->GetHidManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ElectronHidDelegate::AddObserver(content::BrowserContext* browser_context,
|
void ElectronHidDelegate::AddObserver(content::BrowserContext* browser_context,
|
||||||
Observer* observer) {
|
Observer* observer) {
|
||||||
|
if (!browser_context)
|
||||||
|
return;
|
||||||
GetContextObserver(browser_context)->AddObserver(observer);
|
GetContextObserver(browser_context)->AddObserver(observer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ElectronHidDelegate::RemoveObserver(
|
void ElectronHidDelegate::RemoveObserver(
|
||||||
content::BrowserContext* browser_context,
|
content::BrowserContext* browser_context,
|
||||||
content::HidDelegate::Observer* observer) {
|
content::HidDelegate::Observer* observer) {
|
||||||
|
if (!browser_context)
|
||||||
|
return;
|
||||||
DCHECK(base::Contains(observations_, browser_context));
|
DCHECK(base::Contains(observations_, browser_context));
|
||||||
GetContextObserver(browser_context)->RemoveObserver(observer);
|
GetContextObserver(browser_context)->RemoveObserver(observer);
|
||||||
}
|
}
|
||||||
|
@ -180,14 +193,16 @@ const device::mojom::HidDeviceInfo* ElectronHidDelegate::GetDeviceInfo(
|
||||||
content::BrowserContext* browser_context,
|
content::BrowserContext* browser_context,
|
||||||
const std::string& guid) {
|
const std::string& guid) {
|
||||||
auto* chooser_context = GetChooserContext(browser_context);
|
auto* chooser_context = GetChooserContext(browser_context);
|
||||||
|
if (!chooser_context)
|
||||||
|
return nullptr;
|
||||||
return chooser_context->GetDeviceInfo(guid);
|
return chooser_context->GetDeviceInfo(guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ElectronHidDelegate::IsFidoAllowedForOrigin(
|
bool ElectronHidDelegate::IsFidoAllowedForOrigin(
|
||||||
content::BrowserContext* browser_context,
|
content::BrowserContext* browser_context,
|
||||||
const url::Origin& origin) {
|
const url::Origin& origin) {
|
||||||
return base::CommandLine::ForCurrentProcess()->HasSwitch(
|
auto* chooser_context = GetChooserContext(browser_context);
|
||||||
switches::kDisableHidBlocklist);
|
return chooser_context && chooser_context->IsFidoAllowedForOrigin(origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ElectronHidDelegate::IsServiceWorkerAllowedForOrigin(
|
bool ElectronHidDelegate::IsServiceWorkerAllowedForOrigin(
|
||||||
|
|
|
@ -29,9 +29,14 @@
|
||||||
#include "shell/common/gin_converters/value_converter.h"
|
#include "shell/common/gin_converters/value_converter.h"
|
||||||
#include "shell/common/gin_helper/dictionary.h"
|
#include "shell/common/gin_helper/dictionary.h"
|
||||||
#include "third_party/blink/public/common/permissions/permission_utils.h"
|
#include "third_party/blink/public/common/permissions/permission_utils.h"
|
||||||
|
|
||||||
#include "ui/base/l10n/l10n_util.h"
|
#include "ui/base/l10n/l10n_util.h"
|
||||||
|
|
||||||
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||||
|
#include "base/containers/fixed_flat_set.h"
|
||||||
|
#include "base/strings/string_piece.h"
|
||||||
|
#include "extensions/common/constants.h"
|
||||||
|
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||||
|
|
||||||
namespace electron {
|
namespace electron {
|
||||||
|
|
||||||
const char kHidDeviceNameKey[] = "name";
|
const char kHidDeviceNameKey[] = "name";
|
||||||
|
@ -181,6 +186,26 @@ bool HidChooserContext::HasDevicePermission(
|
||||||
origin, DeviceInfoToValue(device), browser_context_);
|
origin, DeviceInfoToValue(device), browser_context_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HidChooserContext::IsFidoAllowedForOrigin(const url::Origin& origin) {
|
||||||
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||||
|
static constexpr auto kPrivilegedExtensionIds =
|
||||||
|
base::MakeFixedFlatSet<base::StringPiece>({
|
||||||
|
"ckcendljdlmgnhghiaomidhiiclmapok", // gnubbyd-v3 dev
|
||||||
|
"lfboplenmmjcmpbkeemecobbadnmpfhi", // gnubbyd-v3 prod
|
||||||
|
});
|
||||||
|
|
||||||
|
if (origin.scheme() == extensions::kExtensionScheme &&
|
||||||
|
base::Contains(kPrivilegedExtensionIds, origin.host())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||||
|
|
||||||
|
// This differs from upstream - we want to allow users greater
|
||||||
|
// ability to communicate with FIDO devices in Electron.
|
||||||
|
return base::CommandLine::ForCurrentProcess()->HasSwitch(
|
||||||
|
switches::kDisableHidBlocklist);
|
||||||
|
}
|
||||||
|
|
||||||
void HidChooserContext::AddDeviceObserver(DeviceObserver* observer) {
|
void HidChooserContext::AddDeviceObserver(DeviceObserver* observer) {
|
||||||
EnsureHidManagerConnection();
|
EnsureHidManagerConnection();
|
||||||
device_observer_list_.AddObserver(observer);
|
device_observer_list_.AddObserver(observer);
|
||||||
|
|
|
@ -78,6 +78,9 @@ class HidChooserContext : public KeyedService,
|
||||||
bool HasDevicePermission(const url::Origin& origin,
|
bool HasDevicePermission(const url::Origin& origin,
|
||||||
const device::mojom::HidDeviceInfo& device);
|
const device::mojom::HidDeviceInfo& device);
|
||||||
|
|
||||||
|
// Returns true if `origin` is allowed to access FIDO reports.
|
||||||
|
bool IsFidoAllowedForOrigin(const url::Origin& origin);
|
||||||
|
|
||||||
// For ScopedObserver.
|
// For ScopedObserver.
|
||||||
void AddDeviceObserver(DeviceObserver* observer);
|
void AddDeviceObserver(DeviceObserver* observer);
|
||||||
void RemoveDeviceObserver(DeviceObserver* observer);
|
void RemoveDeviceObserver(DeviceObserver* observer);
|
||||||
|
|
|
@ -85,12 +85,16 @@ HidChooserController::HidChooserController(
|
||||||
filters_(std::move(filters)),
|
filters_(std::move(filters)),
|
||||||
exclusion_filters_(std::move(exclusion_filters)),
|
exclusion_filters_(std::move(exclusion_filters)),
|
||||||
callback_(std::move(callback)),
|
callback_(std::move(callback)),
|
||||||
|
initiator_document_(render_frame_host->GetWeakDocumentPtr()),
|
||||||
origin_(content::WebContents::FromRenderFrameHost(render_frame_host)
|
origin_(content::WebContents::FromRenderFrameHost(render_frame_host)
|
||||||
->GetPrimaryMainFrame()
|
->GetPrimaryMainFrame()
|
||||||
->GetLastCommittedOrigin()),
|
->GetLastCommittedOrigin()),
|
||||||
frame_tree_node_id_(render_frame_host->GetFrameTreeNodeId()),
|
|
||||||
hid_delegate_(hid_delegate),
|
hid_delegate_(hid_delegate),
|
||||||
render_frame_host_id_(render_frame_host->GetGlobalId()) {
|
render_frame_host_id_(render_frame_host->GetGlobalId()) {
|
||||||
|
// The use above of GetMainFrame is safe as content::HidService instances are
|
||||||
|
// not created for fenced frames.
|
||||||
|
DCHECK(!render_frame_host->IsNestedWithinFencedFrame());
|
||||||
|
|
||||||
chooser_context_ = HidChooserContextFactory::GetForBrowserContext(
|
chooser_context_ = HidChooserContextFactory::GetForBrowserContext(
|
||||||
web_contents->GetBrowserContext())
|
web_contents->GetBrowserContext())
|
||||||
->AsWeakPtr();
|
->AsWeakPtr();
|
||||||
|
@ -129,6 +133,7 @@ void HidChooserController::OnDeviceAdded(
|
||||||
const device::mojom::HidDeviceInfo& device) {
|
const device::mojom::HidDeviceInfo& device) {
|
||||||
if (!DisplayDevice(device))
|
if (!DisplayDevice(device))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (AddDeviceInfo(device)) {
|
if (AddDeviceInfo(device)) {
|
||||||
api::Session* session = GetSession();
|
api::Session* session = GetSession();
|
||||||
if (session) {
|
if (session) {
|
||||||
|
@ -142,8 +147,6 @@ void HidChooserController::OnDeviceAdded(
|
||||||
session->Emit("hid-device-added", details);
|
session->Emit("hid-device-added", details);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HidChooserController::OnDeviceRemoved(
|
void HidChooserController::OnDeviceRemoved(
|
||||||
|
@ -151,7 +154,8 @@ void HidChooserController::OnDeviceRemoved(
|
||||||
if (!base::Contains(items_, PhysicalDeviceIdFromDeviceInfo(device)))
|
if (!base::Contains(items_, PhysicalDeviceIdFromDeviceInfo(device)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (api::Session* session = GetSession(); session != nullptr) {
|
api::Session* session = GetSession();
|
||||||
|
if (session) {
|
||||||
auto* rfh = content::RenderFrameHost::FromID(render_frame_host_id_);
|
auto* rfh = content::RenderFrameHost::FromID(render_frame_host_id_);
|
||||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||||
v8::HandleScope scope(isolate);
|
v8::HandleScope scope(isolate);
|
||||||
|
@ -223,9 +227,8 @@ void HidChooserController::OnGotDevices(
|
||||||
|
|
||||||
for (auto& device : devices) {
|
for (auto& device : devices) {
|
||||||
if (DisplayDevice(*device)) {
|
if (DisplayDevice(*device)) {
|
||||||
if (AddDeviceInfo(*device)) {
|
if (AddDeviceInfo(*device))
|
||||||
devicesToDisplay.push_back(device->Clone());
|
devicesToDisplay.push_back(device->Clone());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,6 +236,7 @@ void HidChooserController::OnGotDevices(
|
||||||
// enumeration.
|
// enumeration.
|
||||||
if (chooser_context_)
|
if (chooser_context_)
|
||||||
observation_.Observe(chooser_context_.get());
|
observation_.Observe(chooser_context_.get());
|
||||||
|
|
||||||
bool prevent_default = false;
|
bool prevent_default = false;
|
||||||
api::Session* session = GetSession();
|
api::Session* session = GetSession();
|
||||||
if (session) {
|
if (session) {
|
||||||
|
@ -255,26 +259,41 @@ void HidChooserController::OnGotDevices(
|
||||||
|
|
||||||
bool HidChooserController::DisplayDevice(
|
bool HidChooserController::DisplayDevice(
|
||||||
const device::mojom::HidDeviceInfo& device) const {
|
const device::mojom::HidDeviceInfo& device) const {
|
||||||
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
|
// Check if `device` has a top-level collection with a FIDO usage. FIDO
|
||||||
switches::kDisableHidBlocklist)) {
|
// devices may be displayed if the origin is privileged or the blocklist is
|
||||||
// Do not pass the device to the chooser if it is excluded by the blocklist.
|
// disabled.
|
||||||
if (device.is_excluded_by_blocklist)
|
const bool has_fido_collection =
|
||||||
return false;
|
base::Contains(device.collections, device::mojom::kPageFido,
|
||||||
|
[](const auto& c) { return c->usage->usage_page; });
|
||||||
|
|
||||||
// Do not pass the device to the chooser if it has a top-level collection
|
if (has_fido_collection) {
|
||||||
// with the FIDO usage page.
|
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
|
||||||
//
|
switches::kDisableHidBlocklist) ||
|
||||||
// Note: The HID blocklist also blocks top-level collections with the FIDO
|
(chooser_context_ &&
|
||||||
// usage page, but will not block the device if it has other (non-FIDO)
|
chooser_context_->IsFidoAllowedForOrigin(origin_))) {
|
||||||
// collections. The check below will exclude the device from the chooser
|
return FilterMatchesAny(device) && !IsExcluded(device);
|
||||||
// if it has any top-level FIDO collection.
|
}
|
||||||
auto find_it =
|
|
||||||
std::find_if(device.collections.begin(), device.collections.end(),
|
AddMessageToConsole(
|
||||||
[](const device::mojom::HidCollectionInfoPtr& c) {
|
blink::mojom::ConsoleMessageLevel::kInfo,
|
||||||
return c->usage->usage_page == device::mojom::kPageFido;
|
base::StringPrintf(
|
||||||
});
|
"Chooser dialog is not displaying a FIDO HID device: vendorId=%d, "
|
||||||
if (find_it != device.collections.end())
|
"productId=%d, name='%s', serial='%s'",
|
||||||
return false;
|
device.vendor_id, device.product_id, device.product_name.c_str(),
|
||||||
|
device.serial_number.c_str()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device.is_excluded_by_blocklist) {
|
||||||
|
AddMessageToConsole(
|
||||||
|
blink::mojom::ConsoleMessageLevel::kInfo,
|
||||||
|
base::StringPrintf(
|
||||||
|
"Chooser dialog is not displaying a device excluded by "
|
||||||
|
"the HID blocklist: vendorId=%d, "
|
||||||
|
"productId=%d, name='%s', serial='%s'",
|
||||||
|
device.vendor_id, device.product_id, device.product_name.c_str(),
|
||||||
|
device.serial_number.c_str()));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FilterMatchesAny(device) && !IsExcluded(device);
|
return FilterMatchesAny(device) && !IsExcluded(device);
|
||||||
|
@ -303,6 +322,15 @@ bool HidChooserController::IsExcluded(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HidChooserController::AddMessageToConsole(
|
||||||
|
blink::mojom::ConsoleMessageLevel level,
|
||||||
|
const std::string& message) const {
|
||||||
|
if (content::RenderFrameHost* rfh =
|
||||||
|
initiator_document_.AsRenderFrameHostIfValid()) {
|
||||||
|
rfh->AddMessageToConsole(level, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool HidChooserController::AddDeviceInfo(
|
bool HidChooserController::AddDeviceInfo(
|
||||||
const device::mojom::HidDeviceInfo& device) {
|
const device::mojom::HidDeviceInfo& device) {
|
||||||
const auto& id = PhysicalDeviceIdFromDeviceInfo(device);
|
const auto& id = PhysicalDeviceIdFromDeviceInfo(device);
|
||||||
|
@ -340,10 +368,8 @@ void HidChooserController::UpdateDeviceInfo(
|
||||||
auto physical_device_it = device_map_.find(id);
|
auto physical_device_it = device_map_.find(id);
|
||||||
DCHECK(physical_device_it != device_map_.end());
|
DCHECK(physical_device_it != device_map_.end());
|
||||||
auto& device_infos = physical_device_it->second;
|
auto& device_infos = physical_device_it->second;
|
||||||
auto device_it = base::ranges::find_if(
|
auto device_it = base::ranges::find(device_infos, device.guid,
|
||||||
device_infos, [&device](const device::mojom::HidDeviceInfoPtr& d) {
|
&device::mojom::HidDeviceInfo::guid);
|
||||||
return d->guid == device.guid;
|
|
||||||
});
|
|
||||||
DCHECK(device_it != device_infos.end());
|
DCHECK(device_it != device_infos.end());
|
||||||
*device_it = device.Clone();
|
*device_it = device.Clone();
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "base/scoped_observation.h"
|
#include "base/scoped_observation.h"
|
||||||
#include "content/public/browser/global_routing_id.h"
|
#include "content/public/browser/global_routing_id.h"
|
||||||
#include "content/public/browser/hid_chooser.h"
|
#include "content/public/browser/hid_chooser.h"
|
||||||
|
#include "content/public/browser/weak_document_ptr.h"
|
||||||
#include "content/public/browser/web_contents.h"
|
#include "content/public/browser/web_contents.h"
|
||||||
#include "content/public/browser/web_contents_observer.h"
|
#include "content/public/browser/web_contents_observer.h"
|
||||||
#include "services/device/public/mojom/hid.mojom-forward.h"
|
#include "services/device/public/mojom/hid.mojom-forward.h"
|
||||||
|
@ -20,6 +21,7 @@
|
||||||
#include "shell/browser/hid/electron_hid_delegate.h"
|
#include "shell/browser/hid/electron_hid_delegate.h"
|
||||||
#include "shell/browser/hid/hid_chooser_context.h"
|
#include "shell/browser/hid/hid_chooser_context.h"
|
||||||
#include "shell/common/gin_converters/frame_converter.h"
|
#include "shell/common/gin_converters/frame_converter.h"
|
||||||
|
#include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
|
||||||
#include "third_party/blink/public/mojom/hid/hid.mojom.h"
|
#include "third_party/blink/public/mojom/hid/hid.mojom.h"
|
||||||
|
|
||||||
namespace content {
|
namespace content {
|
||||||
|
@ -76,6 +78,8 @@ class HidChooserController
|
||||||
bool DisplayDevice(const device::mojom::HidDeviceInfo& device) const;
|
bool DisplayDevice(const device::mojom::HidDeviceInfo& device) const;
|
||||||
bool FilterMatchesAny(const device::mojom::HidDeviceInfo& device) const;
|
bool FilterMatchesAny(const device::mojom::HidDeviceInfo& device) const;
|
||||||
bool IsExcluded(const device::mojom::HidDeviceInfo& device) const;
|
bool IsExcluded(const device::mojom::HidDeviceInfo& device) const;
|
||||||
|
void AddMessageToConsole(blink::mojom::ConsoleMessageLevel level,
|
||||||
|
const std::string& message) const;
|
||||||
|
|
||||||
// Add |device_info| to |device_map_|. The device is added to the chooser item
|
// Add |device_info| to |device_map_|. The device is added to the chooser item
|
||||||
// representing the physical device. If the chooser item does not yet exist, a
|
// representing the physical device. If the chooser item does not yet exist, a
|
||||||
|
@ -98,8 +102,8 @@ class HidChooserController
|
||||||
std::vector<blink::mojom::HidDeviceFilterPtr> filters_;
|
std::vector<blink::mojom::HidDeviceFilterPtr> filters_;
|
||||||
std::vector<blink::mojom::HidDeviceFilterPtr> exclusion_filters_;
|
std::vector<blink::mojom::HidDeviceFilterPtr> exclusion_filters_;
|
||||||
content::HidChooser::Callback callback_;
|
content::HidChooser::Callback callback_;
|
||||||
|
content::WeakDocumentPtr initiator_document_;
|
||||||
const url::Origin origin_;
|
const url::Origin origin_;
|
||||||
const int frame_tree_node_id_;
|
|
||||||
|
|
||||||
// The lifetime of the chooser context is tied to the browser context used to
|
// The lifetime of the chooser context is tied to the browser context used to
|
||||||
// create it, and may be destroyed while the chooser is still active.
|
// create it, and may be destroyed while the chooser is still active.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue