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

WebView: Support CSP Fix #12070

Merged
merged 1 commit into from
Jan 16, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
223 changes: 112 additions & 111 deletions packages/plugin-ext/src/main/browser/webview/pre/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,117 +67,117 @@
};

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]
* @return {string}
*/
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;
`;
}

/**
Expand Down Expand Up @@ -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
Expand Down