feat: add support for HIDDevice.forget() (#34210)

* feat: add support for HIDDevice.forget()

* chore: remove whitespace

* chore: use `SetGetter` to serialize the render_frame_host

Co-authored-by: Samuel Maddock <samuel.maddock@gmail.com>

* fixup chore: use `SetGetter` to serialize the render_frame_host

* fixup after rebase

* fixup for crash on navigator.serial.getPorts()

* fixup for lint

Co-authored-by: Samuel Maddock <samuel.maddock@gmail.com>
This commit is contained in:
John Kleinschmidt 2022-05-23 15:13:18 -04:00 committed by GitHub
parent df9383cb3c
commit ba573f5583
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 359 additions and 114 deletions

View file

@ -80,8 +80,11 @@ bool ElectronHidDelegate::HasDevicePermission(
void ElectronHidDelegate::RevokeDevicePermission(
content::RenderFrameHost* render_frame_host,
const device::mojom::HidDeviceInfo& device) {
// TODO(jkleinsc) implement this for
// https://chromium-review.googlesource.com/c/chromium/src/+/3297868
auto* chooser_context = GetChooserContext(render_frame_host);
const auto& origin =
render_frame_host->GetMainFrame()->GetLastCommittedOrigin();
return chooser_context->RevokeDevicePermission(origin, device,
render_frame_host);
}
device::mojom::HidManager* ElectronHidDelegate::GetHidManager(

View file

@ -19,7 +19,13 @@
#include "content/public/browser/device_service.h"
#include "services/device/public/cpp/hid/hid_blocklist.h"
#include "services/device/public/cpp/hid/hid_switches.h"
#include "shell/browser/api/electron_api_session.h"
#include "shell/browser/web_contents_permission_helper.h"
#include "shell/common/gin_converters/content_converter.h"
#include "shell/common/gin_converters/frame_converter.h"
#include "shell/common/gin_converters/hid_device_info_converter.h"
#include "shell/common/gin_converters/value_converter.h"
#include "shell/common/gin_helper/dictionary.h"
#include "ui/base/l10n/l10n_util.h"
namespace electron {
@ -99,6 +105,66 @@ void HidChooserContext::GrantDevicePermission(
}
}
void HidChooserContext::RevokeDevicePermission(
const url::Origin& origin,
const device::mojom::HidDeviceInfo& device,
content::RenderFrameHost* render_frame_host) {
DCHECK(base::Contains(devices_, device.guid));
if (CanStorePersistentEntry(device)) {
RevokePersistentDevicePermission(origin, device, render_frame_host);
} else {
RevokeEphemeralDevicePermission(origin, device);
}
auto* web_contents =
content::WebContents::FromRenderFrameHost(render_frame_host);
api::Session* session =
api::Session::FromBrowserContext(web_contents->GetBrowserContext());
if (session) {
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::HandleScope scope(isolate);
gin_helper::Dictionary details =
gin_helper::Dictionary::CreateEmpty(isolate);
details.Set("device", device.Clone());
details.SetGetter("frame", render_frame_host);
session->Emit("hid-device-revoked", details);
}
}
void HidChooserContext::RevokePersistentDevicePermission(
const url::Origin& origin,
const device::mojom::HidDeviceInfo& device,
content::RenderFrameHost* render_frame_host) {
auto* web_contents =
content::WebContents::FromRenderFrameHost(render_frame_host);
auto* permission_helper =
WebContentsPermissionHelper::FromWebContents(web_contents);
permission_helper->RevokeHIDDevicePermission(
origin, DeviceInfoToValue(device), render_frame_host);
RevokeEphemeralDevicePermission(origin, device);
}
void HidChooserContext::RevokeEphemeralDevicePermission(
const url::Origin& origin,
const device::mojom::HidDeviceInfo& device) {
auto it = ephemeral_devices_.find(origin);
if (it != ephemeral_devices_.end()) {
std::set<std::string>& devices = it->second;
for (auto guid = devices.begin(); guid != devices.end();) {
DCHECK(base::Contains(devices_, *guid));
if (devices_[*guid]->physical_device_id != device.physical_device_id) {
++guid;
continue;
}
guid = devices.erase(guid);
if (devices.empty())
ephemeral_devices_.erase(it);
}
}
}
bool HidChooserContext::HasDevicePermission(
const url::Origin& origin,
const device::mojom::HidDeviceInfo& device,

View file

@ -76,6 +76,9 @@ class HidChooserContext : public KeyedService,
void GrantDevicePermission(const url::Origin& origin,
const device::mojom::HidDeviceInfo& device,
content::RenderFrameHost* render_frame_host);
void RevokeDevicePermission(const url::Origin& origin,
const device::mojom::HidDeviceInfo& device,
content::RenderFrameHost* render_frame_host);
bool HasDevicePermission(const url::Origin& origin,
const device::mojom::HidDeviceInfo& device,
content::RenderFrameHost* render_frame_host);
@ -111,6 +114,15 @@ class HidChooserContext : public KeyedService,
std::vector<device::mojom::HidDeviceInfoPtr> devices);
void OnHidManagerConnectionError();
// HID-specific interface for revoking device permissions.
void RevokePersistentDevicePermission(
const url::Origin& origin,
const device::mojom::HidDeviceInfo& device,
content::RenderFrameHost* render_frame_host);
void RevokeEphemeralDevicePermission(
const url::Origin& origin,
const device::mojom::HidDeviceInfo& device);
ElectronBrowserContext* browser_context_;
bool is_initialized_ = false;

View file

@ -20,6 +20,7 @@
#include "shell/browser/javascript_environment.h"
#include "shell/common/gin_converters/callback_converter.h"
#include "shell/common/gin_converters/content_converter.h"
#include "shell/common/gin_converters/hid_device_info_converter.h"
#include "shell/common/gin_converters/value_converter.h"
#include "shell/common/gin_helper/dictionary.h"
#include "shell/common/node_includes.h"
@ -28,18 +29,6 @@
namespace {
std::string PhysicalDeviceIdFromDeviceInfo(
const device::mojom::HidDeviceInfo& device) {
// A single physical device may expose multiple HID interfaces, each
// represented by a HidDeviceInfo object. When a device exposes multiple
// HID interfaces, the HidDeviceInfo objects will share a common
// |physical_device_id|. Group these devices so that a single chooser item
// is shown for each physical device. If a device's physical device ID is
// empty, use its GUID instead.
return device.physical_device_id.empty() ? device.guid
: device.physical_device_id;
}
bool FilterMatch(const blink::mojom::HidDeviceFilterPtr& filter,
const device::mojom::HidDeviceInfo& device) {
if (filter->device_ids) {
@ -83,21 +72,6 @@ bool FilterMatch(const blink::mojom::HidDeviceFilterPtr& filter,
} // namespace
namespace gin {
template <>
struct Converter<device::mojom::HidDeviceInfoPtr> {
static v8::Local<v8::Value> ToV8(
v8::Isolate* isolate,
const device::mojom::HidDeviceInfoPtr& device) {
base::Value value = electron::HidChooserContext::DeviceInfoToValue(*device);
value.SetStringKey("deviceId", PhysicalDeviceIdFromDeviceInfo(*device));
return gin::ConvertToV8(isolate, value);
}
};
} // namespace gin
namespace electron {
HidChooserController::HidChooserController(
@ -131,6 +105,19 @@ HidChooserController::~HidChooserController() {
std::move(callback_).Run(std::vector<device::mojom::HidDeviceInfoPtr>());
}
// static
std::string HidChooserController::PhysicalDeviceIdFromDeviceInfo(
const device::mojom::HidDeviceInfo& device) {
// A single physical device may expose multiple HID interfaces, each
// represented by a HidDeviceInfo object. When a device exposes multiple
// HID interfaces, the HidDeviceInfo objects will share a common
// |physical_device_id|. Group these devices so that a single chooser item
// is shown for each physical device. If a device's physical device ID is
// empty, use its GUID instead.
return device.physical_device_id.empty() ? device.guid
: device.physical_device_id;
}
api::Session* HidChooserController::GetSession() {
if (!web_contents()) {
return nullptr;

View file

@ -53,6 +53,10 @@ class HidChooserController
HidChooserController& operator=(HidChooserController&) = delete;
~HidChooserController() override;
// static
static std::string PhysicalDeviceIdFromDeviceInfo(
const device::mojom::HidDeviceInfo& device);
// HidChooserContext::DeviceObserver:
void OnDeviceAdded(const device::mojom::HidDeviceInfo& device_info) override;
void OnDeviceRemoved(