Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Define WebUSB in Shared Workers #73

Open
reillyeon opened this issue Jan 8, 2017 · 10 comments
Open

Define WebUSB in Shared Workers #73

reillyeon opened this issue Jan 8, 2017 · 10 comments

Comments

@reillyeon
Copy link
Collaborator

Driving a USB device from a worker allows processing to be moved off of the main event loop. Moving device access to a Shared Worker also allows multiple tabs of the same application to coordinate access to a single device as unique ownership of an interface is enforced by both the WebUSB API and underlying operating systems.

Unlike defining WebUSB in Service Workers there are likely no additional security and privacy considerations here.

@karelbilek
Copy link

I was trying to make some inter-tab sharing of information about connecting/disconnecting with BroadcastChannel and it's really hard to do it correctly.

webusb in shared worker would be great.

@odejesush
Copy link
Collaborator

Hi @karel-3d, could you elaborate on what kind of application you were trying to build that required this sharing of information from the USB device? There is currently on going discussion on whether WebUSB should be implemented on shared workers, since shared workers could be deprecated. If you like, you could follow the discussion on the blink-dev Google group (https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/MReOVYgRpKk). Learning about the use cases for this feature could help in figuring out how to approach this problem. Thank you!

@karelbilek
Copy link

I will reply here and post link to the group.

We are makers of this cryptographic device - https://trezor.io/ - which is used mostly for safely storing cryptocurrencies.

Explained simply - the device keeps private keys, can give the PC public keys on request and can sign messages on request, which the user has to confirm on the device. Private keys don't leave the device.

On the PC side, we have a web app (web wallet) that connects directly to Trezor, from the browser, via a variety of transports:

  • we have a small daemon that user has to install, or
  • a small helper chrome app (that will soon be gone due to Google cutting Chrome apps), or
  • WebUSB, for the new models (and soon-ish the old models with new FW).

Our webapp has a following "flow":

  • user opens a website
  • user plugs in the device
  • website automatically starts communicating with the device, asking about its name, asking for the public keys, and starts working with them in some way, sometimes asking about more keys. The web app can detect connections and disconnections and react to them.

We also want two things that seem to go against each other:

  • We want the action in the web app to be immediate - immediately after connecting the device, show the user some info
  • We also want the web app to work in multiple tabs in browser

We have a concept of "session" and somehow cooperative multitasking - since the actions are usually rather short, we tell to the transport layer (the desktop daemon or the chrome app) "I am working with the device now - ok now it's free" and the web app works with that, so more tabs can work with a device that is otherwise exclusive.

We are doing that with webusb, too, with sharedworker. Once user selects a device in the Chrome GUI box, the permission is remembered and next time does not require the box, in all tabs on the domain. We use SharedWorked for cooperation between tabs for the "multitasking".

In the end we did not need to use webusb in the sharedworked directly, but we send messages to the worker and the worker "orchestrates" who can and cannot read to/from the device, even when in the end the web pages read the device directly. I originally wanted the access to happen only in the sharedworker and the messages would be the data read from the device, but we worked around that.

For example. We send messages like "acquire intent" from page to the worker, then after worker "allows" that, we send message "acquire done" or "acquire failed" - acquire meaning both open + claim interface. After that, only the one tab can communicate, until the tab sends "release" back to the worker, etc.

You can look at the code here

https://github.com/trezor/trezor-link/blob/master/src/lowlevel/withSharedConnections.js#L48

https://github.com/trezor/trezor-link/blob/master/src/lowlevel/sharedConnectionWorker.js
https://github.com/trezor/trezor-link/blob/master/src/lowlevel/webusb.js

If shared worker will indeed be deprecated (which is news to me :(( ), we can work around that with perhaps localStorage APIs somehow, but that feels a little hacky,

@inexorabletash
Copy link
Member

Thanks, @karel-3d !

It sounds like you could use my proposed Web Locks API (https://github.com/inexorabletash/web-locks) to achieve this coordination. Can you take a look at that proposal and see if it would satisfy your use cases for coordinating? The Locks API is implemented in Chrome and available as an Origin Trial (read more about the trial and sign up here)

@karelbilek
Copy link

Hello.

That looks interesting, first time I see that.

What I like about shared worker is that it also stores information. WebLocks API seems interesting, but it cannot share information directly, only with some additional mechanisms.

I guess we could use weblocks + localstorage for the same use as we currently use shared worker.

@odejesush
Copy link
Collaborator

Yes, thank you @karel-3d !

I would also like to add that I have a section in my design document for WebUSB on Workers with an example of how WebUSB, Web Locks, Dedicated Workers, and BroadcastChannel could potentially be used together to achieve similar functionality to WebUSB on Shared Workers.

@karelbilek
Copy link

Thanks. Yes that could be used; however, the sharedworker is currently written and tested and I don't want to touch that for a while :)

(we are still solving windows issues with webusb and drivers; the WDI thread here helped a lot but there are still little issues, mostly with Window 7. But that is beyond the scope of this thread)

@odejesush
Copy link
Collaborator

No need to worry about modifying anything yet; we're still figuring out how to best facilitate the use of USB devices across pages. Thank you for providing us with your specific use case because it gives us a developer's perspective on the issue that we can use a reference in figuring this out.

@gregjhogan
Copy link

I am trying to write an application that flashes firmware on a non-usb device via an off-the-shelf USB device

Here is what the setup looks like:

Web Browser (sends firmware) <---> USB device (translates to a serial protocol) <---> non-USB device (receives firmware)

I have two problems:

  • Once a programming session is established with the non-USB device I have to periodically send a message to maintain the programming session
  • Flashing of firmware should not get interrupted from start to finish

I started out using a dedicated web worker, and while this works if I keep the tab focused during the entire process, switching tabs in the middle of the process seems to suspend the dedicated web worker and causes the above two problems.

I believe that if shared workers had been implemented I would have an easy solution to my problems. I tried enabling chrome experimental flags and using a shared worker and it didn't work because navigator.usb === null.

Am I missing some other clean way to handle this? Is there some other feature (other than shared workers) that I should be looking at?

@odejesush
Copy link
Collaborator

Hi gregjhogan,

Unfortunately, WebUSB on shared workers in Chrome is not going to be implemented anytime soon because the future of shared workers is uncertain. See whatwg/html#315 for some context.

There is an intent to implement and ship the throttling of background dedicated workers, which will throttle dedicated workers by default. However, there is a proposal to allow users to opt-out of the throttling (see the design doc). This could potentially solve your problem with the process becoming suspended when switching tabs.

Please file a bug at https://crbug.com with the Blink>USB component so that we can track the issue.

@reillyeon reillyeon changed the title Define WebUSB in (Shared) Workers Define WebUSB in Shared Workers Mar 15, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants