From d25f5d7018082e7a9be7b3abdafaceeea95a761b Mon Sep 17 00:00:00 2001 From: FernandoAscencio Date: Fri, 13 Jan 2023 11:14:13 -0500 Subject: [PATCH] WebView: Support CSP Fix Implementation of the proposed fix for the CORS issue that did not allow images to be displayed in previews. Sugned-off-by: FernandoAscencio --- .../src/main/browser/webview/pre/main.js | 223 +++++++++--------- 1 file changed, 112 insertions(+), 111 deletions(-) diff --git a/packages/plugin-ext/src/main/browser/webview/pre/main.js b/packages/plugin-ext/src/main/browser/webview/pre/main.js index fe86c550d8540..f9e694a019e77 100644 --- a/packages/plugin-ext/src/main/browser/webview/pre/main.js +++ b/packages/plugin-ext/src/main/browser/webview/pre/main.js @@ -67,78 +67,78 @@ }; const defaultCssRules = ` - body { - background-color: var(--vscode-editor-background); - color: var(--vscode-editor-foreground); - font-family: var(--vscode-font-family); - font-weight: var(--vscode-font-weight); - font-size: var(--vscode-font-size); - margin: 0; - padding: 0 20px; - } - - img { - max-width: 100%; - max-height: 100%; - } - - a { - color: var(--vscode-textLink-foreground); - } - - a:hover { - color: var(--vscode-textLink-activeForeground); - } - - a:focus, - input:focus, - select:focus, - textarea:focus { - outline: 1px solid -webkit-focus-ring-color; - outline-offset: -1px; - } - - code { - color: var(--vscode-textPreformat-foreground); - } - - blockquote { - background: var(--vscode-textBlockQuote-background); - border-color: var(--vscode-textBlockQuote-border); - } - - kbd { - color: var(--vscode-editor-foreground); - border-radius: 3px; - vertical-align: middle; - padding: 1px 3px; - - background-color: hsla(0,0%,50%,.17); - border: 1px solid rgba(71,71,71,.4); - border-bottom-color: rgba(88,88,88,.4); - box-shadow: inset 0 -1px 0 rgba(88,88,88,.4); - } - .vscode-light kbd { - background-color: hsla(0,0%,87%,.5); - border: 1px solid hsla(0,0%,80%,.7); - border-bottom-color: hsla(0,0%,73%,.7); - box-shadow: inset 0 -1px 0 hsla(0,0%,73%,.7); - } - - ::-webkit-scrollbar { - width: 10px; - height: 10px; - } - - ::-webkit-scrollbar-thumb { - background-color: var(--vscode-scrollbarSlider-background); - } - ::-webkit-scrollbar-thumb:hover { - background-color: var(--vscode-scrollbarSlider-hoverBackground); - } - ::-webkit-scrollbar-thumb:active { - background-color: var(--vscode-scrollbarSlider-activeBackground); - }`; + body { + background-color: var(--vscode-editor-background); + color: var(--vscode-editor-foreground); + font-family: var(--vscode-font-family); + font-weight: var(--vscode-font-weight); + font-size: var(--vscode-font-size); + margin: 0; + padding: 0 20px; + } + + img { + max-width: 100%; + max-height: 100%; + } + + a { + color: var(--vscode-textLink-foreground); + } + + a:hover { + color: var(--vscode-textLink-activeForeground); + } + + a:focus, + input:focus, + select:focus, + textarea:focus { + outline: 1px solid -webkit-focus-ring-color; + outline-offset: -1px; + } + + code { + color: var(--vscode-textPreformat-foreground); + } + + blockquote { + background: var(--vscode-textBlockQuote-background); + border-color: var(--vscode-textBlockQuote-border); + } + + kbd { + color: var(--vscode-editor-foreground); + border-radius: 3px; + vertical-align: middle; + padding: 1px 3px; + + background-color: hsla(0,0%,50%,.17); + border: 1px solid rgba(71,71,71,.4); + border-bottom-color: rgba(88,88,88,.4); + box-shadow: inset 0 -1px 0 rgba(88,88,88,.4); + } + .vscode-light kbd { + background-color: hsla(0,0%,87%,.5); + border: 1px solid hsla(0,0%,80%,.7); + border-bottom-color: hsla(0,0%,73%,.7); + box-shadow: inset 0 -1px 0 hsla(0,0%,73%,.7); + } + + ::-webkit-scrollbar { + width: 10px; + height: 10px; + } + + ::-webkit-scrollbar-thumb { + background-color: var(--vscode-scrollbarSlider-background); + } + ::-webkit-scrollbar-thumb:hover { + background-color: var(--vscode-scrollbarSlider-hoverBackground); + } + ::-webkit-scrollbar-thumb:active { + background-color: var(--vscode-scrollbarSlider-activeBackground); + }`; /** * @param {*} [state] @@ -146,38 +146,38 @@ */ function getVsCodeApiScript(state) { return ` - const acquireVsCodeApi = (function() { - const originalPostMessage = window.parent.postMessage.bind(window.parent); - const targetOrigin = '*'; - let acquired = false; - - let state = ${state ? `JSON.parse(${JSON.stringify(state)})` : undefined}; - - return () => { - if (acquired) { - throw new Error('An instance of the VS Code API has already been acquired'); - } - acquired = true; - return Object.freeze({ - postMessage: function(msg) { - return originalPostMessage({ command: 'onmessage', data: msg }, targetOrigin); - }, - setState: function(newState) { - state = newState; - originalPostMessage({ command: 'do-update-state', data: JSON.stringify(newState) }, targetOrigin); - return newState; - }, - getState: function() { - return state; - } - }); - }; - })(); - const acquireTheiaApi = acquireVsCodeApi; - delete window.parent; - delete window.top; - delete window.frameElement; - `; + const acquireVsCodeApi = (function() { + const originalPostMessage = window.parent.postMessage.bind(window.parent); + const targetOrigin = '*'; + let acquired = false; + + let state = ${state ? `JSON.parse(${JSON.stringify(state)})` : undefined}; + + return () => { + if (acquired) { + throw new Error('An instance of the VS Code API has already been acquired'); + } + acquired = true; + return Object.freeze({ + postMessage: function(msg) { + return originalPostMessage({ command: 'onmessage', data: msg }, targetOrigin); + }, + setState: function(newState) { + state = newState; + originalPostMessage({ command: 'do-update-state', data: JSON.stringify(newState) }, targetOrigin); + return newState; + }, + getState: function() { + return state; + } + }); + }; + })(); + const acquireTheiaApi = acquireVsCodeApi; + delete window.parent; + delete window.top; + delete window.frameElement; + `; } /** @@ -381,20 +381,21 @@ applyStyles(newDocument, newDocument.body); + const sameOrigin = '\'self\''; // see: https://content-security-policy.com/self/ // Check for CSP const csp = newDocument.querySelector('meta[http-equiv="Content-Security-Policy"]'); - if (!csp) { - host.postMessage('no-csp-found'); - } else { - // Rewrite vscode-resource in csp - if (data.endpoint) { + if (csp !== null) { + const cspContent = csp.getAttribute('content'); + if (cspContent !== null) { + // Rewrite vscode-resource in csp try { - const endpointUrl = new URL(data.endpoint); - csp.setAttribute('content', csp.getAttribute('content').replace(/(?:vscode|theia)-resource:(?=(\s|;|$))/g, endpointUrl.origin)); + csp.setAttribute('content', cspContent.replace(/(vscode-webview-resource|vscode-resource):(?=(\s|;|$))/g, sameOrigin)); } catch (e) { console.error('Could not rewrite csp'); } } + } else { + host.postMessage('no-csp-found'); } // set DOCTYPE for newDocument explicitly as DOMParser.parseFromString strips it off