diff --git a/src/Tracy/Bar/assets/bar.js b/src/Tracy/Bar/assets/bar.js index f7f1dc546..d64c677cd 100644 --- a/src/Tracy/Bar/assets/bar.js +++ b/src/Tracy/Bar/assets/bar.js @@ -41,7 +41,8 @@ class Panel { let elem = this.elem; this.init = function () {}; - elem.innerHTML = elem.tracyContent = elem.dataset.tracyContent; + elem.tracyContent = elem.dataset.tracyContent; + elem.innerHTML = Tracy.trusted.html(elem.tracyContent); delete elem.dataset.tracyContent; Tracy.Dumper.init(Debug.shadow); evalScripts(elem); @@ -164,7 +165,7 @@ class Panel { doc.body.id = 'tracy-debug'; let script = doc.createElement('script'); - script.src = baseUrl + '_tracy_bar=js&XDEBUG_SESSION_STOP=1'; + script.src = Tracy.trusted.scriptURL(baseUrl + '_tracy_bar=js&XDEBUG_SESSION_STOP=1'); script.async = true; script.addEventListener('load', () => { win.Tracy.adoptStyleSheets(doc, ['shared', 'bar']); @@ -173,10 +174,10 @@ class Panel { doc.head.appendChild(script); let meta = this.elem.parentElement.lastElementChild; - doc.body.innerHTML = '
' + doc.body.innerHTML = Tracy.trusted.html('
' + '
' + this.elem.tracyContent + '
' + meta.outerHTML - + '
'; + + '
'); evalScripts(doc.body); if (this.elem.querySelector('h1')) { doc.title = this.elem.querySelector('h1').textContent; @@ -417,7 +418,7 @@ class Debug { // #tracy-debug wrapper is kept for backward compatibility of third-party panel CSS Debug.layer = document.createElement('tracy-div'); Debug.layer.setAttribute('id', 'tracy-debug'); - Debug.layer.innerHTML = content; + Debug.layer.innerHTML = Tracy.trusted.html(content); shadow.appendChild(Debug.layer); (document.body || document.documentElement).appendChild(host); @@ -467,9 +468,9 @@ class Debug { }); } - Debug.layer.insertAdjacentHTML('beforeend', content.panels); + Debug.layer.insertAdjacentHTML('beforeend', Tracy.trusted.html(content.panels)); evalScripts(Debug.layer); - Debug.bar.elem.insertAdjacentHTML('beforeend', content.bar); + Debug.bar.elem.insertAdjacentHTML('beforeend', Tracy.trusted.html(content.bar)); let ajaxBar = Debug.bar.elem.querySelector('.tracy-row:last-child'); Debug.shadow.querySelectorAll('.tracy-panel').forEach((panel) => { @@ -556,7 +557,7 @@ class Debug { Debug.scriptElem.remove(); } Debug.scriptElem = document.createElement('script'); - Debug.scriptElem.src = url; + Debug.scriptElem.src = Tracy.trusted.scriptURL(url); (document.body || document.documentElement).appendChild(Debug.scriptElem); } } @@ -567,7 +568,7 @@ function evalScripts(elem) { if ((!script.hasAttribute('type') || script.type === 'text/javascript' || script.type === 'application/javascript') && !script.tracyEvaluated) { let document = script.ownerDocument; let dolly = document.createElement('script'); - dolly.textContent = script.textContent; + dolly.textContent = Tracy.trusted.script(script.textContent); (document.body || document.documentElement).appendChild(dolly); dolly.remove(); script.tracyEvaluated = true; diff --git a/src/Tracy/BlueScreen/assets/bluescreen.js b/src/Tracy/BlueScreen/assets/bluescreen.js index 7249b0dd3..ec2a302ca 100644 --- a/src/Tracy/BlueScreen/assets/bluescreen.js +++ b/src/Tracy/BlueScreen/assets/bluescreen.js @@ -105,7 +105,7 @@ class BlueScreen { if (host) { host.remove(); } - document.body.insertAdjacentHTML('beforeend', content); + document.body.insertAdjacentHTML('beforeend', Tracy.trusted.html(content)); BlueScreen.init(true); } } diff --git a/src/Tracy/Dumper/assets/dumper.js b/src/Tracy/Dumper/assets/dumper.js index e6e792f3c..2e0fabdc1 100644 --- a/src/Tracy/Dumper/assets/dumper.js +++ b/src/Tracy/Dumper/assets/dumper.js @@ -341,7 +341,7 @@ function createEl(el, attrs, content) { } if (content && content.html !== undefined) { - el.innerHTML = content.html; + el.innerHTML = Tracy.trusted.html(content.html); return el; } diff --git a/src/Tracy/assets/helpers.js b/src/Tracy/assets/helpers.js index fdb161f2e..3aa715ae4 100644 --- a/src/Tracy/assets/helpers.js +++ b/src/Tracy/assets/helpers.js @@ -18,6 +18,26 @@ let Tracy = window.Tracy = window.Tracy || {}; // returns the real event target even when the event crossed a shadow DOM boundary Tracy.retarget = (e) => e.composedPath()[0] ?? e.target; +// passes Tracy's own markup and scripts to sinks that a page enforcing Trusted Types +// (require-trusted-types-for 'script') refuses plain strings at +Tracy.trusted = Tracy.trusted || (() => { + let policy; + try { + policy = window.trustedTypes?.createPolicy('tracy', { + createHTML: (s) => s, + createScript: (s) => s, + createScriptURL: (s) => s, + }); + } catch { + // the page's trusted-types directive doesn't allow the name + } + return { + html: (s) => policy ? policy.createHTML(s) : s, + script: (s) => policy ? policy.createScript(s) : s, + scriptURL: (s) => policy ? policy.createScriptURL(s) : s, + }; +})(); + // registry of CSS sources filled by the loader (DeferredContent, Dumper::renderAssets) Tracy.css = Tracy.css || {};