-
Notifications
You must be signed in to change notification settings - Fork 778
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
Detect WebCrypto API in web workers via self
#586
Detect WebCrypto API in web workers via self
#586
Conversation
Is there an easy way to test this? Maybe some sort of modification to the legacy keygen interactive test? |
This will allow for separate, karma-only test suites in the future.
@davidlehn I wasn't very comfortable adding something to a "legacy" setup so I took the liberty of tweaking karma setup a bit. It now allows karma-only tests. This allowed me to setup a web worker without compromising the mocha tests (that only run in Node.js). This does not reliably test the performance improvement but hopefully serves as a starting point to ensure, i.e., compatibility with web workers (or even other browser-only APIs). I'm aware that this might have been too big of a leap forward, so be sure that I'm appreciating whatever feedback is incoming . :) |
I just realized, browserify is available as a bundler option. |
I like that approach of having karma specific tests. I'll take a look at that test when I get some time. I'm not sure how many people use browserify. It wasn't much effort to keep it working so we just kept it in the test setup. I imagine a future forge is going to go all-in on ES2017+ which is when I figured all the babel transpiling and polyfills would make browserify path more difficult. If it's possible to keep the tests working now, that would be nice. Not quite sure what that involves here. Maybe easier to just disable difficult things in browserify. |
Hey @davidlehn My proposal would be to drop support for running tests based on browserify. As far as I can tell there is no immediate benefit of running tests with both bundlers and webpack seems to have taken the lead in the community. If you agree, I'd be up to adapt this PR. |
Love the idea of supporting service workers. For what it's worth, I suspect the following may be cleaner and reduce the overhead of a function call: util.getGlobalScope = this.global // node
|| this.window // browser
|| this.self // service worker |
lib/rsa.js
Outdated
typeof window.crypto === 'object' && | ||
typeof window.crypto.subtle === 'object' && | ||
typeof window.crypto.subtle[fn] === 'function'); | ||
return (typeof util.getGlobalScope() !== 'undefined' && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Micro optimization would be to do lift out var globalScope = util.getGlobalScope()
above to avoid repeated calls.
lib/rsa.js
Outdated
typeof window.msCrypto === 'object' && | ||
typeof window.msCrypto.subtle === 'object' && | ||
typeof window.msCrypto.subtle[fn] === 'function'); | ||
return (typeof util.getGlobalScope() !== 'undefined' && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, could use a globalScope var.
lib/util.js
Outdated
return global; | ||
} | ||
|
||
return typeof self === "undefined" ? window : self; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: use single quotes.
tests/karma/index.js
Outdated
require('../unit'); | ||
|
||
// ...plus some tests that can only run in the browser (e.g. web worker compatibility) | ||
require('./rsa'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: add newline
tests/karma/rsa.js
Outdated
describe('rsa', function() { | ||
it('should generate key pairs when running forge in a web worker', function(done) { | ||
// Make test worker call rsa.generateKeyPair() on its own side | ||
testWorker.postMessage({method:'rsa.generateKeyPair'}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: space after the colon.
tests/karma/testWorker.js
Outdated
// We define a light-weight protocol to simplify testing | ||
self.addEventListener('message', function (event) { | ||
|
||
// Test scripts call worker.postMessage(data)` – we can access the payload via event.data |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: 2 space indents and add end of file newline.
@leoselig sorry this sat for so long. added some code comments. |
These were mentioned in the PR review here: digitalbazaar#586 (comment)
This motivated by the discussion here: digitalbazaar#586 (comment) Essentially, using the `worker-loader` for webpack for the first time disclosed the challenges of supporting two bundlers at the same time. Since there is no dominant development use case for having two bundlers, removing browserify should reduce the maintenance overhead.
The evaluation function stays the same but is wrapped as an IEFE and executed once on module initialization. This should avoid unnecessary recomputations in the relying code.
These were mentioned in the PR review here: digitalbazaar#586 (comment)
This motivated by the discussion here: digitalbazaar#586 (comment) Essentially, using the `worker-loader` for webpack for the first time disclosed the challenges of supporting two bundlers at the same time. Since there is no dominant development use case for having two bundlers, removing browserify should reduce the maintenance overhead.
1803b04
to
f470145
Compare
@davidlehn No worries, it's OSS – I won't expect anyone to be ultra responsive :D I changed the code as you asked for. I also, as I suggested, removed the browserify bundler option entirely. I believe this to be a good idea to reduce the overhead of maintaining both and didn't see any use case for it. (It also has the pleasant side effect of making my build green) |
…r-generation-in-web-workers
@davidlehn Sorry to ping you once again. We just merged the upstream back into my fork. Tests are still passing, apps work as expected. |
These were mentioned in the PR review here: #586 (comment)
This motivated by the discussion here: #586 (comment) Essentially, using the `worker-loader` for webpack for the first time disclosed the challenges of supporting two bundlers at the same time. Since there is no dominant development use case for having two bundlers, removing browserify should reduce the maintenance overhead.
@leoselig I updated #645 to keep browserify support. I dropped your commit and my revert commits of it. The reason to keep support is that people may be using browserify with forge. Hard to know. It still works so until we decide to specifically stop supporting browserify, we should keep testing it. The web worker test is trickier to deal with so I just omitted it while doing browserify tests. Can call that good enough for now. |
These were mentioned in the PR review here: #586 (comment)
Merged via #645. Thanks! |
@davidlehn Fair enough. Just to clarify though, I was not suggesting to break node-forge for browserify users. I only wanted to remove it from the test execution since it seemed effectively irrelevant what bundler is used for the tests. Thanks for merging this and for all the work on this package! :) |
Problem
The following code has been used to detect the Web Crypto API:
While this works fine in the browser main thread, it fails to detect the crypto API in Web Workers.
Solution
A typical solution to write code that works in Web Workers as well as the main thread is to use the
self
keyword that resolves towindow
in the main thread and the instance ofWorkerGlobalScope
in the web worker.Since this is not supported yet in
< IE 11
, I'm introducing agetGlobalScope()
-helper in theutil
-namespace.As we are using
node-forge
in a web worker to avoid blocking the main thread for other operations, this sped up RSA key pair generation from ~1min in average to less than 3 seconds.Feel free to tell me what should change to make this happen. :)