Open ChrisMiami opened 1 year ago
Note: this is only a bug in a page with a Content-Security-Policy as described in the Chrome error message. It works fine in a wide-open test page. Not so much in a business environment.
As I look deeper into this (illegally, as nobody but me thinks audio feedback is of any importance), I realize that the code mentioned is written so that Tone.js is entirely self-contained and deliverable via CDN. If I just excise the JS inside the blob and put it into a co-resident file, and serve the lib from my servers, then heck, I bet it could actually work! Maybe...
So, I extracted the template literal into its own file (TickWorker.js) and am creating the blob using 'TickWorker.js' as its argument. Ironically, I find that the worker is entirely optional but the error it causes doesn't raise an exception that would cause Tone to use the setTimeout fallback in Ticker._createClock(). If the side-by-side file doesn't work to create the blob, I'll probably just comment out the whole thing and go with setTimeout.
It should work if you add 'blob:'
as a script-src
. It's not the safest thing to do but given that the page already allows any URL as well as inlined and eval-ed JavaScript I would argue it doesn't further increase the potential risk of an attack.
I don't have access to either the server or the source of the page - the content I create is hosted inside an iFrame that's contained in a commercial solution. I tried everything to get the Worker created with "known" source code, but it just wasn't possible. I ended up just throwing so setTimeout would be used. The hosting app does offer a worker that performs a setTimeout but I had to move on before being able to figure out how to match up the different APIs (between their worker timer and Tone's ticker worker).
Okay, I see. I took another look at the source code you referenced above and it actually catches the error and handles it correctly.
Running console.log(Tone.context.clockSource);
should log 'timeout'
in your case.
I believe this is Chrome's strange behavior of logging network errors even though they are handled programmatically. As far as I know there is no way to avoid this despite not triggering the error in the first place. You could do this by changing the code linked above to not create a worker when asked to do so.
private _createClock(): void {
if (this._type === "worker") {
// workers not supported, fallback to timeout
this._type = "timeout";
this._createClock();
} else if (this._type === "timeout") {
this._createTimeout();
}
}
By the way the ScriptProcessorNode
deprecation warning in the console is also unavoidable in Chrome.
Describe the bug
In Chrome Version 117.0.5938.149 (Official Build) (arm64), I got the following error when Tone.js.min was loaded:
Refused to create a worker from 'blob:<my-server/guid>' because it violates the following Content Security Policy directive: "script-src 'unsafe-inline' 'unsafe-eval'". Note that 'worker-src' was not explicitly set, so 'script-src' is used as a fallback. Note that '' matches only URLs with network schemes ('http', 'https', 'ws', 'wss'), or URLs whose scheme matches
self
's scheme. The scheme 'blob:' must be added explicitly.also
[Deprecation] The ScriptProcessorNode is deprecated. Use AudioWorkletNode instead. (https://bit.ly/audio-worklet)
To Reproduce
Add tone.js.min to a web page (yes, you have to rename to tone.js.min.js) and then look at the DevTools. The error is self-replicating.
The code that causes this problem is in Ticker.ts:
For some reason, the best solution here is to attempt to inject code into the page and then evaluate it. Super bad idea for pages where security is even a minor concern! Is there no other way to accomplish this feature?
Expected behavior Not having an error.
What I've tried Learning TypeScript, learning why this code is here, asking ChatGPT to figure out a better way to do it, trying to figure out how this project is built. Too much to do within my little deadline.
Additional context There MUST be some way to do this that doesn't involve hacking the page. I know setTimeout() might be inferior, but maybe it'd be better than having to not use the entire project.