chore: refactor persisting permission granted to serial ports (#31181)
This commit is contained in:
parent
21c6b33ebe
commit
d6de243837
13 changed files with 155 additions and 131 deletions
|
@ -297,6 +297,35 @@ app.whenReady().then(() => {
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600
|
height: 600
|
||||||
})
|
})
|
||||||
|
|
||||||
|
win.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => {
|
||||||
|
if (permission === 'serial') {
|
||||||
|
// Add logic here to determine if permission should be given to allow serial selection
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
// Optionally, retrieve previously persisted devices from a persistent store
|
||||||
|
const grantedDevices = fetchGrantedDevices()
|
||||||
|
|
||||||
|
win.webContents.session.setDevicePermissionHandler((details) => {
|
||||||
|
if (new URL(details.origin).hostname === 'some-host' && details.deviceType === 'serial') {
|
||||||
|
if (details.device.vendorId === 123 && details.device.productId === 345) {
|
||||||
|
// Always allow this type of device (this allows skipping the call to `navigator.serial.requestPort` first)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search through the list of devices that have previously been granted permission
|
||||||
|
return grantedDevices.some((grantedDevice) => {
|
||||||
|
return grantedDevice.vendorId === details.device.vendorId &&
|
||||||
|
grantedDevice.productId === details.device.productId &&
|
||||||
|
grantedDevice.serialNumber && grantedDevice.serialNumber === details.device.serialNumber
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
win.webContents.session.on('select-serial-port', (event, portList, webContents, callback) => {
|
win.webContents.session.on('select-serial-port', (event, portList, webContents, callback) => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
const selectedPort = portList.find((device) => {
|
const selectedPort = portList.find((device) => {
|
||||||
|
@ -647,9 +676,9 @@ session.fromPartition('some-partition').setPermissionCheckHandler((webContents,
|
||||||
|
|
||||||
* `handler` Function\<Boolean> | null
|
* `handler` Function\<Boolean> | null
|
||||||
* `details` Object
|
* `details` Object
|
||||||
* `deviceType` String - The type of device that permission is being requested on, can be `hid`.
|
* `deviceType` String - The type of device that permission is being requested on, can be `hid` or `serial`.
|
||||||
* `origin` String - The origin URL of the device permission check.
|
* `origin` String - The origin URL of the device permission check.
|
||||||
* `device` [HIDDevice](structures/hid-device.md) - the device that permission is being requested for.
|
* `device` [HIDDevice](structures/hid-device.md) | [SerialPort](structures/serial-port.md)- the device that permission is being requested for.
|
||||||
* `frame` [WebFrameMain](web-frame-main.md) - WebFrameMain checking the device permission.
|
* `frame` [WebFrameMain](web-frame-main.md) - WebFrameMain checking the device permission.
|
||||||
|
|
||||||
Sets the handler which can be used to respond to device permission checks for the `session`.
|
Sets the handler which can be used to respond to device permission checks for the `session`.
|
||||||
|
@ -674,6 +703,8 @@ app.whenReady().then(() => {
|
||||||
if (permission === 'hid') {
|
if (permission === 'hid') {
|
||||||
// Add logic here to determine if permission should be given to allow HID selection
|
// Add logic here to determine if permission should be given to allow HID selection
|
||||||
return true
|
return true
|
||||||
|
} else if (permission === 'serial') {
|
||||||
|
// Add logic here to determine if permission should be given to allow serial port selection
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
@ -694,6 +725,11 @@ app.whenReady().then(() => {
|
||||||
grantedDevice.productId === details.device.productId &&
|
grantedDevice.productId === details.device.productId &&
|
||||||
grantedDevice.serialNumber && grantedDevice.serialNumber === details.device.serialNumber
|
grantedDevice.serialNumber && grantedDevice.serialNumber === details.device.serialNumber
|
||||||
})
|
})
|
||||||
|
} else if (details.deviceType === 'serial') {
|
||||||
|
if (details.device.vendorId === 123 && details.device.productId === 345) {
|
||||||
|
// Always allow this type of device (this allows skipping the call to `navigator.hid.requestDevice` first)
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
|
@ -84,13 +84,22 @@ There are several additional APIs for working with the Web Serial API:
|
||||||
and [`serial-port-removed`](../api/session.md#event-serial-port-removed) events
|
and [`serial-port-removed`](../api/session.md#event-serial-port-removed) events
|
||||||
on the Session can be used to handle devices being plugged in or unplugged during the
|
on the Session can be used to handle devices being plugged in or unplugged during the
|
||||||
`navigator.serial.requestPort` process.
|
`navigator.serial.requestPort` process.
|
||||||
|
* [`ses.setDevicePermissionHandler(handler)`](../api/session.md#sessetdevicepermissionhandlerhandler)
|
||||||
|
can be used to provide default permissioning to devices without first calling
|
||||||
|
for permission to devices via `navigator.serial.requestPort`. Additionally,
|
||||||
|
the default behavior of Electron is to store granted device permision through
|
||||||
|
the lifetime of the corresponding WebContents. If longer term storage is
|
||||||
|
needed, a developer can store granted device permissions (eg when handling
|
||||||
|
the `select-serial-port` event) and then read from that storage with
|
||||||
|
`setDevicePermissionHandler`.
|
||||||
* [`ses.setPermissionCheckHandler(handler)`](../api/session.md#sessetpermissioncheckhandlerhandler)
|
* [`ses.setPermissionCheckHandler(handler)`](../api/session.md#sessetpermissioncheckhandlerhandler)
|
||||||
can be used to disable serial access for specific origins.
|
can be used to disable serial access for specific origins.
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
This example demonstrates an Electron application that automatically selects
|
This example demonstrates an Electron application that automatically selects
|
||||||
the first available Arduino Uno serial device (if connected) through
|
serial devices through [`ses.setDevicePermissionHandler(handler)`](../api/session.md#sessetdevicepermissionhandlerhandler)
|
||||||
|
as well as demonstrating selecting the first available Arduino Uno serial device (if connected) through
|
||||||
[`select-serial-port` event on the Session](../api/session.md#event-select-serial-port)
|
[`select-serial-port` event on the Session](../api/session.md#event-select-serial-port)
|
||||||
when the `Test Web Serial` button is clicked.
|
when the `Test Web Serial` button is clicked.
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "base/barrier_closure.h"
|
#include "base/barrier_closure.h"
|
||||||
#include "base/base_paths.h"
|
#include "base/base_paths.h"
|
||||||
#include "base/command_line.h"
|
#include "base/command_line.h"
|
||||||
|
@ -95,9 +93,6 @@ std::string MakePartitionName(const std::string& input) {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
const char kSerialGrantedDevicesPref[] =
|
|
||||||
"profile.content_settings.exceptions.serial-chooser-data";
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
ElectronBrowserContext::BrowserContextMap&
|
ElectronBrowserContext::BrowserContextMap&
|
||||||
ElectronBrowserContext::browser_context_map() {
|
ElectronBrowserContext::browser_context_map() {
|
||||||
|
@ -194,7 +189,6 @@ void ElectronBrowserContext::InitPrefs() {
|
||||||
registry->RegisterFilePathPref(prefs::kDownloadDefaultDirectory,
|
registry->RegisterFilePathPref(prefs::kDownloadDefaultDirectory,
|
||||||
download_dir);
|
download_dir);
|
||||||
registry->RegisterDictionaryPref(prefs::kDevToolsFileSystemPaths);
|
registry->RegisterDictionaryPref(prefs::kDevToolsFileSystemPaths);
|
||||||
registry->RegisterDictionaryPref(kSerialGrantedDevicesPref);
|
|
||||||
InspectableWebContents::RegisterPrefs(registry.get());
|
InspectableWebContents::RegisterPrefs(registry.get());
|
||||||
MediaDeviceIDSalt::RegisterPrefs(registry.get());
|
MediaDeviceIDSalt::RegisterPrefs(registry.get());
|
||||||
ZoomLevelDelegate::RegisterPrefs(registry.get());
|
ZoomLevelDelegate::RegisterPrefs(registry.get());
|
||||||
|
@ -420,54 +414,6 @@ void ElectronBrowserContext::SetSSLConfigClient(
|
||||||
ssl_config_client_ = std::move(client);
|
ssl_config_client_ = std::move(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ElectronBrowserContext::GrantObjectPermission(
|
|
||||||
const url::Origin& origin,
|
|
||||||
base::Value object,
|
|
||||||
const std::string& pref_key) {
|
|
||||||
std::string origin_string = origin.Serialize();
|
|
||||||
DictionaryPrefUpdate update(prefs(), pref_key);
|
|
||||||
base::Value* const current_objects = update.Get();
|
|
||||||
if (!current_objects || !current_objects->is_dict()) {
|
|
||||||
base::ListValue objects_for_origin;
|
|
||||||
objects_for_origin.Append(std::move(object));
|
|
||||||
base::DictionaryValue objects_by_origin;
|
|
||||||
objects_by_origin.SetPath(origin_string, std::move(objects_for_origin));
|
|
||||||
prefs()->Set(pref_key, std::move(objects_by_origin));
|
|
||||||
} else {
|
|
||||||
base::Value* const objects_mutable =
|
|
||||||
current_objects->FindListKey(origin_string);
|
|
||||||
if (objects_mutable) {
|
|
||||||
base::Value::ListStorage objects = std::move(*objects_mutable).TakeList();
|
|
||||||
objects.push_back(std::move(object));
|
|
||||||
*objects_mutable = base::Value(std::move(objects));
|
|
||||||
} else {
|
|
||||||
base::Value new_objects(base::Value::Type::LIST);
|
|
||||||
new_objects.Append(std::move(object));
|
|
||||||
current_objects->SetKey(origin_string, std::move(new_objects));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<base::Value>>
|
|
||||||
ElectronBrowserContext::GetGrantedObjects(const url::Origin& origin,
|
|
||||||
const std::string& pref_key) {
|
|
||||||
auto* current_objects = prefs()->Get(pref_key);
|
|
||||||
if (!current_objects || !current_objects->is_dict()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const base::Value* objects_for_origin =
|
|
||||||
current_objects->FindPath(origin.Serialize());
|
|
||||||
if (!objects_for_origin)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<base::Value>> results;
|
|
||||||
for (const auto& object : objects_for_origin->GetList())
|
|
||||||
results.push_back(std::make_unique<base::Value>(object.Clone()));
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
ElectronBrowserContext* ElectronBrowserContext::From(
|
ElectronBrowserContext* ElectronBrowserContext::From(
|
||||||
const std::string& partition,
|
const std::string& partition,
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "base/memory/weak_ptr.h"
|
#include "base/memory/weak_ptr.h"
|
||||||
#include "chrome/browser/predictors/preconnect_manager.h"
|
#include "chrome/browser/predictors/preconnect_manager.h"
|
||||||
|
@ -47,9 +46,6 @@ class ResolveProxyHelper;
|
||||||
class WebViewManager;
|
class WebViewManager;
|
||||||
class ProtocolRegistry;
|
class ProtocolRegistry;
|
||||||
|
|
||||||
// Preference keys for device apis
|
|
||||||
extern const char kSerialGrantedDevicesPref[];
|
|
||||||
|
|
||||||
class ElectronBrowserContext : public content::BrowserContext {
|
class ElectronBrowserContext : public content::BrowserContext {
|
||||||
public:
|
public:
|
||||||
// partition_id => browser_context
|
// partition_id => browser_context
|
||||||
|
@ -146,19 +142,6 @@ class ElectronBrowserContext : public content::BrowserContext {
|
||||||
network::mojom::SSLConfigPtr GetSSLConfig();
|
network::mojom::SSLConfigPtr GetSSLConfig();
|
||||||
void SetSSLConfigClient(mojo::Remote<network::mojom::SSLConfigClient> client);
|
void SetSSLConfigClient(mojo::Remote<network::mojom::SSLConfigClient> client);
|
||||||
|
|
||||||
// Grants |origin| access to |object| by writing it into the browser context.
|
|
||||||
// To be used in place of ObjectPermissionContextBase::GrantObjectPermission.
|
|
||||||
void GrantObjectPermission(const url::Origin& origin,
|
|
||||||
base::Value object,
|
|
||||||
const std::string& pref_key);
|
|
||||||
|
|
||||||
// Returns the list of objects that |origin| has been granted permission to
|
|
||||||
// access. To be used in place of
|
|
||||||
// ObjectPermissionContextBase::GetGrantedObjects.
|
|
||||||
std::vector<std::unique_ptr<base::Value>> GetGrantedObjects(
|
|
||||||
const url::Origin& origin,
|
|
||||||
const std::string& pref_key);
|
|
||||||
|
|
||||||
~ElectronBrowserContext() override;
|
~ElectronBrowserContext() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "shell/browser/electron_browser_client.h"
|
#include "shell/browser/electron_browser_client.h"
|
||||||
#include "shell/browser/electron_browser_main_parts.h"
|
#include "shell/browser/electron_browser_main_parts.h"
|
||||||
#include "shell/browser/hid/hid_chooser_context.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_permission_helper.h"
|
||||||
#include "shell/browser/web_contents_preferences.h"
|
#include "shell/browser/web_contents_preferences.h"
|
||||||
#include "shell/common/gin_converters/content_converter.h"
|
#include "shell/common/gin_converters/content_converter.h"
|
||||||
|
@ -328,6 +329,31 @@ bool ElectronPermissionManager::CheckDevicePermission(
|
||||||
if (serial_number && device_serial_number &&
|
if (serial_number && device_serial_number &&
|
||||||
*device_serial_number == *serial_number)
|
*device_serial_number == *serial_number)
|
||||||
return true;
|
return true;
|
||||||
|
} else if (permission ==
|
||||||
|
static_cast<content::PermissionType>(
|
||||||
|
WebContentsPermissionHelper::PermissionType::SERIAL)) {
|
||||||
|
#if defined(OS_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 defined(OS_MAC)
|
||||||
|
if (*device->FindStringKey(kUsbDriverKey) !=
|
||||||
|
*granted_device.FindStringKey(kUsbDriverKey)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif // defined(OS_MAC)
|
||||||
|
return true;
|
||||||
|
#endif // defined(OS_WIN)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ bool ElectronSerialDelegate::HasPortPermission(
|
||||||
auto* chooser_context =
|
auto* chooser_context =
|
||||||
SerialChooserContextFactory::GetForBrowserContext(browser_context);
|
SerialChooserContextFactory::GetForBrowserContext(browser_context);
|
||||||
return chooser_context->HasPortPermission(
|
return chooser_context->HasPortPermission(
|
||||||
web_contents->GetMainFrame()->GetLastCommittedOrigin(), port);
|
web_contents->GetMainFrame()->GetLastCommittedOrigin(), port, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
device::mojom::SerialPortManager* ElectronSerialDelegate::GetPortManager(
|
device::mojom::SerialPortManager* ElectronSerialDelegate::GetPortManager(
|
||||||
|
|
|
@ -13,22 +13,25 @@
|
||||||
#include "base/strings/utf_string_conversions.h"
|
#include "base/strings/utf_string_conversions.h"
|
||||||
#include "base/values.h"
|
#include "base/values.h"
|
||||||
#include "content/public/browser/device_service.h"
|
#include "content/public/browser/device_service.h"
|
||||||
|
#include "content/public/browser/web_contents.h"
|
||||||
#include "mojo/public/cpp/bindings/pending_remote.h"
|
#include "mojo/public/cpp/bindings/pending_remote.h"
|
||||||
|
#include "shell/browser/web_contents_permission_helper.h"
|
||||||
|
|
||||||
namespace electron {
|
namespace electron {
|
||||||
|
|
||||||
constexpr char kPortNameKey[] = "name";
|
constexpr char kPortNameKey[] = "name";
|
||||||
constexpr char kTokenKey[] = "token";
|
constexpr char kTokenKey[] = "token";
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
constexpr char kDeviceInstanceIdKey[] = "device_instance_id";
|
const char kDeviceInstanceIdKey[] = "device_instance_id";
|
||||||
#else
|
#else
|
||||||
constexpr char kVendorIdKey[] = "vendor_id";
|
const char kVendorIdKey[] = "vendor_id";
|
||||||
constexpr char kProductIdKey[] = "product_id";
|
const char kProductIdKey[] = "product_id";
|
||||||
constexpr char kSerialNumberKey[] = "serial_number";
|
const char kSerialNumberKey[] = "serial_number";
|
||||||
#if defined(OS_MAC)
|
#if defined(OS_MAC)
|
||||||
constexpr char kUsbDriverKey[] = "usb_driver";
|
const char kUsbDriverKey[] = "usb_driver";
|
||||||
#endif // defined(OS_MAC)
|
#endif // defined(OS_MAC)
|
||||||
#endif // defined(OS_WIN)
|
#endif // defined(OS_WIN
|
||||||
|
|
||||||
std::string EncodeToken(const base::UnguessableToken& token) {
|
std::string EncodeToken(const base::UnguessableToken& token) {
|
||||||
const uint64_t data[2] = {token.GetHighForSerialization(),
|
const uint64_t data[2] = {token.GetHighForSerialization(),
|
||||||
|
@ -83,21 +86,24 @@ base::Value PortInfoToValue(const device::mojom::SerialPortInfo& port) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
SerialChooserContext::SerialChooserContext(
|
SerialChooserContext::SerialChooserContext() = default;
|
||||||
ElectronBrowserContext* browser_context)
|
|
||||||
: browser_context_(browser_context) {}
|
|
||||||
|
|
||||||
SerialChooserContext::~SerialChooserContext() = default;
|
SerialChooserContext::~SerialChooserContext() = default;
|
||||||
|
|
||||||
void SerialChooserContext::GrantPortPermission(
|
void SerialChooserContext::GrantPortPermission(
|
||||||
const url::Origin& origin,
|
const url::Origin& origin,
|
||||||
const device::mojom::SerialPortInfo& port) {
|
const device::mojom::SerialPortInfo& port,
|
||||||
|
content::RenderFrameHost* render_frame_host) {
|
||||||
base::Value value = PortInfoToValue(port);
|
base::Value value = PortInfoToValue(port);
|
||||||
port_info_.insert({port.token, value.Clone()});
|
port_info_.insert({port.token, value.Clone()});
|
||||||
|
|
||||||
if (CanStorePersistentEntry(port)) {
|
if (CanStorePersistentEntry(port)) {
|
||||||
browser_context_->GrantObjectPermission(origin, std::move(value),
|
auto* web_contents =
|
||||||
kSerialGrantedDevicesPref);
|
content::WebContents::FromRenderFrameHost(render_frame_host);
|
||||||
|
auto* permission_helper =
|
||||||
|
WebContentsPermissionHelper::FromWebContents(web_contents);
|
||||||
|
permission_helper->GrantSerialPortPermission(origin, std::move(value),
|
||||||
|
render_frame_host);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +112,8 @@ void SerialChooserContext::GrantPortPermission(
|
||||||
|
|
||||||
bool SerialChooserContext::HasPortPermission(
|
bool SerialChooserContext::HasPortPermission(
|
||||||
const url::Origin& origin,
|
const url::Origin& origin,
|
||||||
const device::mojom::SerialPortInfo& port) {
|
const device::mojom::SerialPortInfo& port,
|
||||||
|
content::RenderFrameHost* render_frame_host) {
|
||||||
auto it = ephemeral_ports_.find(origin);
|
auto it = ephemeral_ports_.find(origin);
|
||||||
if (it != ephemeral_ports_.end()) {
|
if (it != ephemeral_ports_.end()) {
|
||||||
const std::set<base::UnguessableToken> ports = it->second;
|
const std::set<base::UnguessableToken> ports = it->second;
|
||||||
|
@ -118,39 +125,13 @@ bool SerialChooserContext::HasPortPermission(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::unique_ptr<base::Value>> object_list =
|
auto* web_contents =
|
||||||
browser_context_->GetGrantedObjects(origin, kSerialGrantedDevicesPref);
|
content::WebContents::FromRenderFrameHost(render_frame_host);
|
||||||
for (const auto& device : object_list) {
|
auto* permission_helper =
|
||||||
#if defined(OS_WIN)
|
WebContentsPermissionHelper::FromWebContents(web_contents);
|
||||||
const std::string& device_instance_id =
|
base::Value value = PortInfoToValue(port);
|
||||||
*device->FindStringKey(kDeviceInstanceIdKey);
|
return permission_helper->CheckSerialPortPermission(origin, std::move(value),
|
||||||
if (port.device_instance_id == device_instance_id)
|
render_frame_host);
|
||||||
return true;
|
|
||||||
#else
|
|
||||||
const int vendor_id = *device->FindIntKey(kVendorIdKey);
|
|
||||||
const int product_id = *device->FindIntKey(kProductIdKey);
|
|
||||||
const std::string& serial_number = *device->FindStringKey(kSerialNumberKey);
|
|
||||||
|
|
||||||
// Guaranteed by the CanStorePersistentEntry) check above.
|
|
||||||
DCHECK(port.has_vendor_id);
|
|
||||||
DCHECK(port.has_product_id);
|
|
||||||
DCHECK(port.serial_number && !port.serial_number->empty());
|
|
||||||
if (port.vendor_id != vendor_id || port.product_id != product_id ||
|
|
||||||
port.serial_number != serial_number) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(OS_MAC)
|
|
||||||
const std::string& usb_driver_name = *device->FindStringKey(kUsbDriverKey);
|
|
||||||
if (port.usb_driver_name != usb_driver_name) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#endif // defined(OS_MAC)
|
|
||||||
|
|
||||||
return true;
|
|
||||||
#endif // defined(OS_WIN)
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
|
|
@ -29,19 +29,35 @@ class Value;
|
||||||
|
|
||||||
namespace electron {
|
namespace electron {
|
||||||
|
|
||||||
|
extern const char kHidVendorIdKey[];
|
||||||
|
extern const char kHidProductIdKey[];
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
extern const char kDeviceInstanceIdKey[];
|
||||||
|
#else
|
||||||
|
extern const char kVendorIdKey[];
|
||||||
|
extern const char kProductIdKey[];
|
||||||
|
extern const char kSerialNumberKey[];
|
||||||
|
#if defined(OS_MAC)
|
||||||
|
extern const char kUsbDriverKey[];
|
||||||
|
#endif // defined(OS_MAC)
|
||||||
|
#endif // defined(OS_WIN)
|
||||||
|
|
||||||
class SerialChooserContext : public KeyedService,
|
class SerialChooserContext : public KeyedService,
|
||||||
public device::mojom::SerialPortManagerClient {
|
public device::mojom::SerialPortManagerClient {
|
||||||
public:
|
public:
|
||||||
using PortObserver = content::SerialDelegate::Observer;
|
using PortObserver = content::SerialDelegate::Observer;
|
||||||
|
|
||||||
explicit SerialChooserContext(ElectronBrowserContext* browser_context);
|
SerialChooserContext();
|
||||||
~SerialChooserContext() override;
|
~SerialChooserContext() override;
|
||||||
|
|
||||||
// Serial-specific interface for granting and checking permissions.
|
// Serial-specific interface for granting and checking permissions.
|
||||||
void GrantPortPermission(const url::Origin& origin,
|
void GrantPortPermission(const url::Origin& origin,
|
||||||
const device::mojom::SerialPortInfo& port);
|
const device::mojom::SerialPortInfo& port,
|
||||||
|
content::RenderFrameHost* render_frame_host);
|
||||||
bool HasPortPermission(const url::Origin& origin,
|
bool HasPortPermission(const url::Origin& origin,
|
||||||
const device::mojom::SerialPortInfo& port);
|
const device::mojom::SerialPortInfo& port,
|
||||||
|
content::RenderFrameHost* render_frame_host);
|
||||||
static bool CanStorePersistentEntry(
|
static bool CanStorePersistentEntry(
|
||||||
const device::mojom::SerialPortInfo& port);
|
const device::mojom::SerialPortInfo& port);
|
||||||
|
|
||||||
|
@ -62,8 +78,6 @@ class SerialChooserContext : public KeyedService,
|
||||||
mojo::PendingRemote<device::mojom::SerialPortManager> manager);
|
mojo::PendingRemote<device::mojom::SerialPortManager> manager);
|
||||||
void OnPortManagerConnectionError();
|
void OnPortManagerConnectionError();
|
||||||
|
|
||||||
ElectronBrowserContext* browser_context_;
|
|
||||||
|
|
||||||
// Tracks the set of ports to which an origin has access to.
|
// Tracks the set of ports to which an origin has access to.
|
||||||
std::map<url::Origin, std::set<base::UnguessableToken>> ephemeral_ports_;
|
std::map<url::Origin, std::set<base::UnguessableToken>> ephemeral_ports_;
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,7 @@ SerialChooserContextFactory::~SerialChooserContextFactory() = default;
|
||||||
|
|
||||||
KeyedService* SerialChooserContextFactory::BuildServiceInstanceFor(
|
KeyedService* SerialChooserContextFactory::BuildServiceInstanceFor(
|
||||||
content::BrowserContext* context) const {
|
content::BrowserContext* context) const {
|
||||||
auto* browser_context =
|
return new SerialChooserContext();
|
||||||
static_cast<electron::ElectronBrowserContext*>(context);
|
|
||||||
return new SerialChooserContext(browser_context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
|
|
@ -67,7 +67,8 @@ SerialChooserController::SerialChooserController(
|
||||||
: WebContentsObserver(web_contents),
|
: WebContentsObserver(web_contents),
|
||||||
filters_(std::move(filters)),
|
filters_(std::move(filters)),
|
||||||
callback_(std::move(callback)),
|
callback_(std::move(callback)),
|
||||||
serial_delegate_(serial_delegate) {
|
serial_delegate_(serial_delegate),
|
||||||
|
render_frame_host_id_(render_frame_host->GetGlobalId()) {
|
||||||
origin_ = web_contents->GetMainFrame()->GetLastCommittedOrigin();
|
origin_ = web_contents->GetMainFrame()->GetLastCommittedOrigin();
|
||||||
|
|
||||||
chooser_context_ = SerialChooserContextFactory::GetForBrowserContext(
|
chooser_context_ = SerialChooserContextFactory::GetForBrowserContext(
|
||||||
|
@ -124,7 +125,8 @@ void SerialChooserController::OnDeviceChosen(const std::string& port_id) {
|
||||||
return ptr->token.ToString() == port_id;
|
return ptr->token.ToString() == port_id;
|
||||||
});
|
});
|
||||||
if (it != ports_.end()) {
|
if (it != ports_.end()) {
|
||||||
chooser_context_->GrantPortPermission(origin_, *it->get());
|
auto* rfh = content::RenderFrameHost::FromID(render_frame_host_id_);
|
||||||
|
chooser_context_->GrantPortPermission(origin_, *it->get(), rfh);
|
||||||
RunCallback(it->Clone());
|
RunCallback(it->Clone());
|
||||||
} else {
|
} else {
|
||||||
RunCallback(/*port=*/nullptr);
|
RunCallback(/*port=*/nullptr);
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#include "base/macros.h"
|
#include "base/macros.h"
|
||||||
#include "base/memory/weak_ptr.h"
|
#include "base/memory/weak_ptr.h"
|
||||||
|
#include "content/public/browser/global_routing_id.h"
|
||||||
#include "content/public/browser/serial_chooser.h"
|
#include "content/public/browser/serial_chooser.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"
|
||||||
|
@ -61,6 +62,8 @@ class SerialChooserController final : public SerialChooserContext::PortObserver,
|
||||||
|
|
||||||
base::WeakPtr<ElectronSerialDelegate> serial_delegate_;
|
base::WeakPtr<ElectronSerialDelegate> serial_delegate_;
|
||||||
|
|
||||||
|
content::GlobalRenderFrameHostId render_frame_host_id_;
|
||||||
|
|
||||||
base::WeakPtrFactory<SerialChooserController> weak_factory_{this};
|
base::WeakPtrFactory<SerialChooserController> weak_factory_{this};
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(SerialChooserController);
|
DISALLOW_COPY_AND_ASSIGN(SerialChooserController);
|
||||||
|
|
|
@ -190,6 +190,24 @@ bool WebContentsPermissionHelper::CheckSerialAccessPermission(
|
||||||
static_cast<content::PermissionType>(PermissionType::SERIAL), &details);
|
static_cast<content::PermissionType>(PermissionType::SERIAL), &details);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WebContentsPermissionHelper::CheckSerialPortPermission(
|
||||||
|
const url::Origin& origin,
|
||||||
|
base::Value device,
|
||||||
|
content::RenderFrameHost* render_frame_host) const {
|
||||||
|
return CheckDevicePermission(
|
||||||
|
static_cast<content::PermissionType>(PermissionType::SERIAL), origin,
|
||||||
|
&device, render_frame_host);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebContentsPermissionHelper::GrantSerialPortPermission(
|
||||||
|
const url::Origin& origin,
|
||||||
|
base::Value device,
|
||||||
|
content::RenderFrameHost* render_frame_host) const {
|
||||||
|
return GrantDevicePermission(
|
||||||
|
static_cast<content::PermissionType>(PermissionType::SERIAL), origin,
|
||||||
|
&device, render_frame_host);
|
||||||
|
}
|
||||||
|
|
||||||
bool WebContentsPermissionHelper::CheckHIDAccessPermission(
|
bool WebContentsPermissionHelper::CheckHIDAccessPermission(
|
||||||
const url::Origin& embedding_origin) const {
|
const url::Origin& embedding_origin) const {
|
||||||
base::DictionaryValue details;
|
base::DictionaryValue details;
|
||||||
|
|
|
@ -42,6 +42,14 @@ class WebContentsPermissionHelper
|
||||||
bool CheckMediaAccessPermission(const GURL& security_origin,
|
bool CheckMediaAccessPermission(const GURL& security_origin,
|
||||||
blink::mojom::MediaStreamType type) const;
|
blink::mojom::MediaStreamType type) const;
|
||||||
bool CheckSerialAccessPermission(const url::Origin& embedding_origin) const;
|
bool CheckSerialAccessPermission(const url::Origin& embedding_origin) const;
|
||||||
|
bool CheckSerialPortPermission(
|
||||||
|
const url::Origin& origin,
|
||||||
|
base::Value device,
|
||||||
|
content::RenderFrameHost* render_frame_host) const;
|
||||||
|
void GrantSerialPortPermission(
|
||||||
|
const url::Origin& origin,
|
||||||
|
base::Value device,
|
||||||
|
content::RenderFrameHost* render_frame_host) const;
|
||||||
bool CheckHIDAccessPermission(const url::Origin& embedding_origin) const;
|
bool CheckHIDAccessPermission(const url::Origin& embedding_origin) const;
|
||||||
bool CheckHIDDevicePermission(
|
bool CheckHIDDevicePermission(
|
||||||
const url::Origin& origin,
|
const url::Origin& origin,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue