fix: WebUSB should not crash when using in-memory partitions (#42364)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com> Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
This commit is contained in:
parent
e645ea88e0
commit
4c96ced00a
3 changed files with 68 additions and 14 deletions
|
@ -174,6 +174,9 @@ std::unique_ptr<content::UsbChooser> ElectronUsbDelegate::RunChooser(
|
||||||
bool ElectronUsbDelegate::CanRequestDevicePermission(
|
bool ElectronUsbDelegate::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*>(
|
||||||
|
@ -188,32 +191,46 @@ void ElectronUsbDelegate::RevokeDevicePermissionWebInitiated(
|
||||||
content::BrowserContext* browser_context,
|
content::BrowserContext* browser_context,
|
||||||
const url::Origin& origin,
|
const url::Origin& origin,
|
||||||
const device::mojom::UsbDeviceInfo& device) {
|
const device::mojom::UsbDeviceInfo& device) {
|
||||||
GetChooserContext(browser_context)
|
auto* chooser_context = GetChooserContext(browser_context);
|
||||||
->RevokeDevicePermissionWebInitiated(origin, device);
|
if (chooser_context) {
|
||||||
|
chooser_context->RevokeDevicePermissionWebInitiated(origin, device);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const device::mojom::UsbDeviceInfo* ElectronUsbDelegate::GetDeviceInfo(
|
const device::mojom::UsbDeviceInfo* ElectronUsbDelegate::GetDeviceInfo(
|
||||||
content::BrowserContext* browser_context,
|
content::BrowserContext* browser_context,
|
||||||
const std::string& guid) {
|
const std::string& guid) {
|
||||||
return GetChooserContext(browser_context)->GetDeviceInfo(guid);
|
auto* chooser_context = GetChooserContext(browser_context);
|
||||||
|
if (!chooser_context)
|
||||||
|
return nullptr;
|
||||||
|
return chooser_context->GetDeviceInfo(guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ElectronUsbDelegate::HasDevicePermission(
|
bool ElectronUsbDelegate::HasDevicePermission(
|
||||||
content::BrowserContext* browser_context,
|
content::BrowserContext* browser_context,
|
||||||
content::RenderFrameHost* frame,
|
content::RenderFrameHost* frame,
|
||||||
const url::Origin& origin,
|
const url::Origin& origin,
|
||||||
const device::mojom::UsbDeviceInfo& device) {
|
const device::mojom::UsbDeviceInfo& device_info) {
|
||||||
if (IsDevicePermissionAutoGranted(origin, device))
|
if (IsDevicePermissionAutoGranted(origin, device_info))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
auto* chooser_context = GetChooserContext(browser_context);
|
||||||
|
if (!chooser_context)
|
||||||
|
return false;
|
||||||
|
|
||||||
return GetChooserContext(browser_context)
|
return GetChooserContext(browser_context)
|
||||||
->HasDevicePermission(origin, device);
|
->HasDevicePermission(origin, device_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ElectronUsbDelegate::GetDevices(
|
void ElectronUsbDelegate::GetDevices(
|
||||||
content::BrowserContext* browser_context,
|
content::BrowserContext* browser_context,
|
||||||
blink::mojom::WebUsbService::GetDevicesCallback callback) {
|
blink::mojom::WebUsbService::GetDevicesCallback callback) {
|
||||||
GetChooserContext(browser_context)->GetDevices(std::move(callback));
|
auto* chooser_context = GetChooserContext(browser_context);
|
||||||
|
if (!chooser_context) {
|
||||||
|
std::move(callback).Run(std::vector<device::mojom::UsbDeviceInfoPtr>());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
chooser_context->GetDevices(std::move(callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ElectronUsbDelegate::GetDevice(
|
void ElectronUsbDelegate::GetDevice(
|
||||||
|
@ -222,25 +239,35 @@ void ElectronUsbDelegate::GetDevice(
|
||||||
base::span<const uint8_t> blocked_interface_classes,
|
base::span<const uint8_t> blocked_interface_classes,
|
||||||
mojo::PendingReceiver<device::mojom::UsbDevice> device_receiver,
|
mojo::PendingReceiver<device::mojom::UsbDevice> device_receiver,
|
||||||
mojo::PendingRemote<device::mojom::UsbDeviceClient> device_client) {
|
mojo::PendingRemote<device::mojom::UsbDeviceClient> device_client) {
|
||||||
GetChooserContext(browser_context)
|
auto* chooser_context = GetChooserContext(browser_context);
|
||||||
->GetDevice(guid, blocked_interface_classes, std::move(device_receiver),
|
if (chooser_context) {
|
||||||
|
chooser_context->GetDevice(guid, blocked_interface_classes,
|
||||||
|
std::move(device_receiver),
|
||||||
std::move(device_client));
|
std::move(device_client));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ElectronUsbDelegate::AddObserver(content::BrowserContext* browser_context,
|
void ElectronUsbDelegate::AddObserver(content::BrowserContext* browser_context,
|
||||||
Observer* observer) {
|
Observer* observer) {
|
||||||
|
if (!browser_context)
|
||||||
|
return;
|
||||||
|
|
||||||
GetContextObserver(browser_context)->AddObserver(observer);
|
GetContextObserver(browser_context)->AddObserver(observer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ElectronUsbDelegate::RemoveObserver(
|
void ElectronUsbDelegate::RemoveObserver(
|
||||||
content::BrowserContext* browser_context,
|
content::BrowserContext* browser_context,
|
||||||
Observer* observer) {
|
Observer* observer) {
|
||||||
|
if (!browser_context)
|
||||||
|
return;
|
||||||
|
|
||||||
GetContextObserver(browser_context)->RemoveObserver(observer);
|
GetContextObserver(browser_context)->RemoveObserver(observer);
|
||||||
}
|
}
|
||||||
|
|
||||||
ElectronUsbDelegate::ContextObservation*
|
ElectronUsbDelegate::ContextObservation*
|
||||||
ElectronUsbDelegate::GetContextObserver(
|
ElectronUsbDelegate::GetContextObserver(
|
||||||
content::BrowserContext* browser_context) {
|
content::BrowserContext* browser_context) {
|
||||||
|
CHECK(browser_context);
|
||||||
if (!base::Contains(observations_, browser_context)) {
|
if (!base::Contains(observations_, browser_context)) {
|
||||||
observations_.emplace(browser_context, std::make_unique<ContextObservation>(
|
observations_.emplace(browser_context, std::make_unique<ContextObservation>(
|
||||||
this, browser_context));
|
this, browser_context));
|
||||||
|
|
|
@ -56,10 +56,11 @@ class ElectronUsbDelegate : public content::UsbDelegate {
|
||||||
const device::mojom::UsbDeviceInfo* GetDeviceInfo(
|
const device::mojom::UsbDeviceInfo* GetDeviceInfo(
|
||||||
content::BrowserContext* browser_context,
|
content::BrowserContext* browser_context,
|
||||||
const std::string& guid) override;
|
const std::string& guid) override;
|
||||||
bool HasDevicePermission(content::BrowserContext* browser_context,
|
bool HasDevicePermission(
|
||||||
|
content::BrowserContext* browser_context,
|
||||||
content::RenderFrameHost* frame,
|
content::RenderFrameHost* frame,
|
||||||
const url::Origin& origin,
|
const url::Origin& origin,
|
||||||
const device::mojom::UsbDeviceInfo& device) override;
|
const device::mojom::UsbDeviceInfo& device_info) override;
|
||||||
void GetDevices(
|
void GetDevices(
|
||||||
content::BrowserContext* browser_context,
|
content::BrowserContext* browser_context,
|
||||||
blink::mojom::WebUsbService::GetDevicesCallback callback) override;
|
blink::mojom::WebUsbService::GetDevicesCallback callback) override;
|
||||||
|
|
|
@ -3678,18 +3678,44 @@ describe('navigator.usb', () => {
|
||||||
`, true);
|
`, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getDevices: any = () => {
|
||||||
|
return w.webContents.executeJavaScript(`
|
||||||
|
navigator.usb.getDevices().then(devices => devices.map(device => device.toString())).catch(err => err.toString());
|
||||||
|
`, true);
|
||||||
|
};
|
||||||
|
|
||||||
const notFoundError = 'NotFoundError: Failed to execute \'requestDevice\' on \'USB\': No device selected.';
|
const notFoundError = 'NotFoundError: Failed to execute \'requestDevice\' on \'USB\': No device selected.';
|
||||||
|
|
||||||
after(() => {
|
after(() => {
|
||||||
server.close();
|
server.close();
|
||||||
closeAllWindows();
|
closeAllWindows();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
session.defaultSession.setPermissionCheckHandler(null);
|
session.defaultSession.setPermissionCheckHandler(null);
|
||||||
session.defaultSession.setDevicePermissionHandler(null);
|
session.defaultSession.setDevicePermissionHandler(null);
|
||||||
session.defaultSession.removeAllListeners('select-usb-device');
|
session.defaultSession.removeAllListeners('select-usb-device');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('does not crash when using in-memory partitions', async () => {
|
||||||
|
const sesWin = new BrowserWindow({
|
||||||
|
webPreferences: {
|
||||||
|
partition: 'test-partition'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await sesWin.loadFile(path.join(fixturesPath, 'pages', 'blank.html'));
|
||||||
|
server = http.createServer((req, res) => {
|
||||||
|
res.setHeader('Content-Type', 'text/html');
|
||||||
|
res.end('<body>');
|
||||||
|
});
|
||||||
|
|
||||||
|
serverUrl = (await listen(server)).url;
|
||||||
|
|
||||||
|
const devices = await getDevices();
|
||||||
|
expect(devices).to.be.an('array').that.is.empty();
|
||||||
|
});
|
||||||
|
|
||||||
it('does not return a device if select-usb-device event is not defined', async () => {
|
it('does not return a device if select-usb-device event is not defined', async () => {
|
||||||
w.loadFile(path.join(fixturesPath, 'pages', 'blank.html'));
|
w.loadFile(path.join(fixturesPath, 'pages', 'blank.html'));
|
||||||
const device = await requestDevices();
|
const device = await requestDevices();
|
||||||
|
|
Loading…
Reference in a new issue