Skip to content

Commit

Permalink
feat: add support for HIDDevice.forget()
Browse files Browse the repository at this point in the history
  • Loading branch information
jkleinsc committed May 13, 2022
1 parent a810369 commit 583a5e9
Show file tree
Hide file tree
Showing 15 changed files with 352 additions and 106 deletions.
13 changes: 13 additions & 0 deletions docs/api/session.md
Expand Up @@ -274,6 +274,19 @@ from `select-hid-device` is called. This event is intended for use when using
a UI to ask users to pick a device so that the UI can be updated to remove the
specified device.
#### Event: 'hid-device-revoked'
Returns:
* `event` Event
* `details` Object
* `device` [HIDDevice[]](structures/hid-device.md)
* `frame` [WebFrameMain](web-frame-main.md)
Emitted after `HIDDevice.forget()` has been called. This event can be used
to help maintain persistent storage of permissions when
`setDevicePermissionHandler` is used.
#### Event: 'select-serial-port'
Returns:
Expand Down
1 change: 1 addition & 0 deletions filenames.gni
Expand Up @@ -566,6 +566,7 @@ filenames = {
"shell/common/gin_converters/gfx_converter.h",
"shell/common/gin_converters/guid_converter.h",
"shell/common/gin_converters/gurl_converter.h",
"shell/common/gin_converters/hid_device_info_converter.h",
"shell/common/gin_converters/image_converter.cc",
"shell/common/gin_converters/image_converter.h",
"shell/common/gin_converters/message_box_converter.cc",
Expand Down
106 changes: 94 additions & 12 deletions shell/browser/api/electron_api_web_contents.cc
Expand Up @@ -48,6 +48,7 @@
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/permission_type.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
Expand Down Expand Up @@ -3450,37 +3451,118 @@ v8::Local<v8::Promise> WebContents::TakeHeapSnapshot(
void WebContents::GrantDevicePermission(
const url::Origin& origin,
const base::Value* device,
content::PermissionType permissionType,
content::PermissionType permission_type,
content::RenderFrameHost* render_frame_host) {
granted_devices_[render_frame_host->GetFrameTreeNodeId()][permissionType]
granted_devices_[render_frame_host->GetFrameTreeNodeId()][permission_type]
[origin]
.push_back(
std::make_unique<base::Value>(device->Clone()));
}

std::vector<base::Value> WebContents::GetGrantedDevices(
void WebContents::RevokeDevicePermission(
const url::Origin& origin,
content::PermissionType permissionType,
const base::Value* device,
content::PermissionType permission_type,
content::RenderFrameHost* render_frame_host) {
const auto& devices_for_frame_host_it =
granted_devices_.find(render_frame_host->GetFrameTreeNodeId());
if (devices_for_frame_host_it == granted_devices_.end())
return;

const auto& current_devices_it =
devices_for_frame_host_it->second.find(permission_type);
if (current_devices_it == devices_for_frame_host_it->second.end())
return;

const auto& origin_devices_it = current_devices_it->second.find(origin);
if (origin_devices_it == current_devices_it->second.end())
return;

for (auto it = origin_devices_it->second.begin();
it != origin_devices_it->second.end();) {
if (DoesDeviceMatch(device, it->get(), permission_type)) {
it = origin_devices_it->second.erase(it);
} else {
++it;
}
}
}

bool WebContents::DoesDeviceMatch(const base::Value* device,
const base::Value* device_to_compare,
content::PermissionType permission_type) {
if (permission_type ==
static_cast<content::PermissionType>(
WebContentsPermissionHelper::PermissionType::HID)) {
if (device->GetDict().FindInt(kHidVendorIdKey) !=
device_to_compare->GetDict().FindInt(kHidVendorIdKey) ||
device->GetDict().FindInt(kHidProductIdKey) !=
device_to_compare->GetDict().FindInt(kHidProductIdKey)) {
return false;
}

const auto* serial_number =
device_to_compare->GetDict().FindString(kHidSerialNumberKey);
const auto* device_serial_number =
device->GetDict().FindString(kHidSerialNumberKey);

if (serial_number && device_serial_number &&
*device_serial_number == *serial_number)
return true;
} else if (permission_type ==
static_cast<content::PermissionType>(
WebContentsPermissionHelper::PermissionType::SERIAL)) {
#if BUILDFLAG(IS_WIN)
if (device->GetDict().FindString(kDeviceInstanceIdKey) ==
device_to_compare->GetDict().FindString(kDeviceInstanceIdKey))
return true;
#else
if (device->GetDict().FindInt(kVendorIdKey) !=
device_to_compare->GetDict().FindInt(kVendorIdKey) ||
device->GetDict().FindInt(kProductIdKey) !=
device_to_compare->GetDict().FindInt(kProductIdKey) ||
*device->GetDict().FindString(kSerialNumberKey) !=
*device_to_compare->GetDict().FindString(kSerialNumberKey)) {
return false;
}

#if BUILDFLAG(IS_MAC)
if (*device->GetDict().FindString(kUsbDriverKey) !=
*device_to_compare->GetDict().FindString(kUsbDriverKey)) {
return false;
}
#endif // BUILDFLAG(IS_MAC)
return true;
#endif // BUILDFLAG(IS_WIN)
}
return false;
}

bool WebContents::CheckDevicePermission(
const url::Origin& origin,
const base::Value* device,
content::PermissionType permission_type,
content::RenderFrameHost* render_frame_host) {
const auto& devices_for_frame_host_it =
granted_devices_.find(render_frame_host->GetFrameTreeNodeId());
if (devices_for_frame_host_it == granted_devices_.end())
return {};
return false;

const auto& current_devices_it =
devices_for_frame_host_it->second.find(permissionType);
devices_for_frame_host_it->second.find(permission_type);
if (current_devices_it == devices_for_frame_host_it->second.end())
return {};
return false;

const auto& origin_devices_it = current_devices_it->second.find(origin);
if (origin_devices_it == current_devices_it->second.end())
return {};
return false;

std::vector<base::Value> results;
for (const auto& object : origin_devices_it->second)
results.push_back(object->Clone());
for (const auto& device_to_compare : origin_devices_it->second) {
if (DoesDeviceMatch(device, device_to_compare.get(), permission_type))
return true;
}

return results;
return false;
}

void WebContents::UpdatePreferredSize(content::WebContents* web_contents,
Expand Down
21 changes: 16 additions & 5 deletions shell/browser/api/electron_api_web_contents.h
Expand Up @@ -439,16 +439,23 @@ class WebContents : public ExclusiveAccessContext,
// To be used in place of ObjectPermissionContextBase::GrantObjectPermission.
void GrantDevicePermission(const url::Origin& origin,
const base::Value* device,
content::PermissionType permissionType,
content::PermissionType permission_type,
content::RenderFrameHost* render_frame_host);

// Revokes |origin| access to |device|.
// To be used in place of ObjectPermissionContextBase::RevokeObjectPermission.
void RevokeDevicePermission(const url::Origin& origin,
const base::Value* device,
content::PermissionType permission_type,
content::RenderFrameHost* render_frame_host);

// Returns the list of devices that |origin| has been granted permission to
// access. To be used in place of
// ObjectPermissionContextBase::GetGrantedObjects.
std::vector<base::Value> GetGrantedDevices(
const url::Origin& origin,
content::PermissionType permissionType,
content::RenderFrameHost* render_frame_host);
bool CheckDevicePermission(const url::Origin& origin,
const base::Value* device,
content::PermissionType permission_type,
content::RenderFrameHost* render_frame_host);

// disable copy
WebContents(const WebContents&) = delete;
Expand Down Expand Up @@ -745,6 +752,10 @@ class WebContents : public ExclusiveAccessContext,
// Update the html fullscreen flag in both browser and renderer.
void UpdateHtmlApiFullscreen(bool fullscreen);

bool DoesDeviceMatch(const base::Value* device,
const base::Value* device_to_compare,
content::PermissionType permission_type);

v8::Global<v8::Value> session_;
v8::Global<v8::Value> devtools_web_contents_;
v8::Global<v8::Value> debugger_;
Expand Down
67 changes: 15 additions & 52 deletions shell/browser/electron_permission_manager.cc
Expand Up @@ -22,8 +22,6 @@
#include "shell/browser/api/electron_api_web_contents.h"
#include "shell/browser/electron_browser_client.h"
#include "shell/browser/electron_browser_main_parts.h"
#include "shell/browser/hid/hid_chooser_context.h"
#include "shell/browser/serial/serial_chooser_context.h"
#include "shell/browser/web_contents_permission_helper.h"
#include "shell/browser/web_contents_preferences.h"
#include "shell/common/gin_converters/content_converter.h"
Expand Down Expand Up @@ -308,56 +306,8 @@ bool ElectronPermissionManager::CheckDevicePermission(
api::WebContents* api_web_contents = api::WebContents::From(web_contents);
if (device_permission_handler_.is_null()) {
if (api_web_contents) {
std::vector<base::Value> granted_devices =
api_web_contents->GetGrantedDevices(origin, permission,
render_frame_host);

for (const auto& granted_device : granted_devices) {
if (permission ==
static_cast<content::PermissionType>(
WebContentsPermissionHelper::PermissionType::HID)) {
if (device->FindIntKey(kHidVendorIdKey) !=
granted_device.FindIntKey(kHidVendorIdKey) ||
device->FindIntKey(kHidProductIdKey) !=
granted_device.FindIntKey(kHidProductIdKey)) {
continue;
}

const auto* serial_number =
granted_device.FindStringKey(kHidSerialNumberKey);
const auto* device_serial_number =
device->FindStringKey(kHidSerialNumberKey);

if (serial_number && device_serial_number &&
*device_serial_number == *serial_number)
return true;
} else if (permission ==
static_cast<content::PermissionType>(
WebContentsPermissionHelper::PermissionType::SERIAL)) {
#if BUILDFLAG(IS_WIN)
if (device->FindStringKey(kDeviceInstanceIdKey) ==
granted_device.FindStringKey(kDeviceInstanceIdKey))
return true;
#else
if (device->FindIntKey(kVendorIdKey) !=
granted_device.FindIntKey(kVendorIdKey) ||
device->FindIntKey(kProductIdKey) !=
granted_device.FindIntKey(kProductIdKey) ||
*device->FindStringKey(kSerialNumberKey) !=
*granted_device.FindStringKey(kSerialNumberKey)) {
continue;
}

#if BUILDFLAG(IS_MAC)
if (*device->FindStringKey(kUsbDriverKey) !=
*granted_device.FindStringKey(kUsbDriverKey)) {
continue;
}
#endif // BUILDFLAG(IS_MAC)
return true;
#endif // BUILDFLAG(IS_WIN)
}
}
return api_web_contents->CheckDevicePermission(origin, device, permission,
render_frame_host);
}
return false;
} else {
Expand Down Expand Up @@ -388,6 +338,19 @@ void ElectronPermissionManager::GrantDevicePermission(
}
}

void ElectronPermissionManager::RevokeDevicePermission(
content::PermissionType permission,
const url::Origin& origin,
const base::Value* device,
content::RenderFrameHost* render_frame_host) const {
auto* web_contents =
content::WebContents::FromRenderFrameHost(render_frame_host);
api::WebContents* api_web_contents = api::WebContents::From(web_contents);
if (api_web_contents)
api_web_contents->RevokeDevicePermission(origin, device, permission,
render_frame_host);
}

blink::mojom::PermissionStatus
ElectronPermissionManager::GetPermissionStatusForFrame(
content::PermissionType permission,
Expand Down
6 changes: 6 additions & 0 deletions shell/browser/electron_permission_manager.h
Expand Up @@ -104,6 +104,12 @@ class ElectronPermissionManager : public content::PermissionControllerDelegate {
const base::Value* object,
content::RenderFrameHost* render_frame_host) const;

void RevokeDevicePermission(
content::PermissionType permission,
const url::Origin& origin,
const base::Value* object,
content::RenderFrameHost* render_frame_host) const;

protected:
void OnPermissionResponse(int request_id,
int permission_id,
Expand Down
7 changes: 5 additions & 2 deletions shell/browser/hid/electron_hid_delegate.cc
Expand Up @@ -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(
Expand Down

0 comments on commit 583a5e9

Please sign in to comment.