mirror of
https://github.com/Microsoft/vscode
synced 2024-09-13 13:46:13 +00:00
Fix anchors and data images in extension pages
Fixes #144897 Refactors to have a single `hookDomPurifyHrefAndSrcSanitizer` function that handles sanitizing the href and src attributes. Also updates this function to allow fragment links `#` and data images
This commit is contained in:
parent
92bf104b52
commit
c521f36041
|
@ -1417,6 +1417,49 @@ export function detectFullscreen(): IDetectedFullscreen | null {
|
|||
|
||||
// -- sanitize and trusted html
|
||||
|
||||
/**
|
||||
* Hooks dompurify using `afterSanitizeAttributes` to check that all `href` and `src`
|
||||
* attributes are valid.
|
||||
*/
|
||||
export function hookDomPurifyHrefAndSrcSanitizer(allowedProtocols: readonly string[], allowDataImages = false): IDisposable {
|
||||
// https://github.com/cure53/DOMPurify/blob/main/demos/hooks-scheme-allowlist.html
|
||||
|
||||
// build an anchor to map URLs to
|
||||
const anchor = document.createElement('a');
|
||||
|
||||
dompurify.addHook('afterSanitizeAttributes', (node) => {
|
||||
// check all href/src attributes for validity
|
||||
for (const attr of ['href', 'src']) {
|
||||
if (node.hasAttribute(attr)) {
|
||||
const attrValue = node.getAttribute(attr) as string;
|
||||
if (attr === 'href' && attrValue.startsWith('#')) {
|
||||
// Allow fragment links
|
||||
continue;
|
||||
}
|
||||
|
||||
anchor.href = attrValue;
|
||||
if (!allowedProtocols.includes(anchor.protocol.replace(/:$/, ''))) {
|
||||
if (allowDataImages && attr === 'src' && anchor.href.startsWith('data:')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
node.removeAttribute(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return toDisposable(() => {
|
||||
dompurify.removeHook('afterSanitizeAttributes');
|
||||
});
|
||||
}
|
||||
|
||||
const defaultSafeProtocols = [
|
||||
Schemas.http,
|
||||
Schemas.https,
|
||||
Schemas.command,
|
||||
];
|
||||
|
||||
/**
|
||||
* Sanitizes the given `value` and reset the given `node` with it.
|
||||
*/
|
||||
|
@ -1428,29 +1471,12 @@ export function safeInnerHtml(node: HTMLElement, value: string): void {
|
|||
RETURN_DOM_FRAGMENT: false,
|
||||
};
|
||||
|
||||
const allowedProtocols = [Schemas.http, Schemas.https, Schemas.command];
|
||||
|
||||
// https://github.com/cure53/DOMPurify/blob/main/demos/hooks-scheme-allowlist.html
|
||||
dompurify.addHook('afterSanitizeAttributes', (node) => {
|
||||
// build an anchor to map URLs to
|
||||
const anchor = document.createElement('a');
|
||||
|
||||
// check all href/src attributes for validity
|
||||
for (const attr in ['href', 'src']) {
|
||||
if (node.hasAttribute(attr)) {
|
||||
anchor.href = node.getAttribute(attr) as string;
|
||||
if (!allowedProtocols.includes(anchor.protocol)) {
|
||||
node.removeAttribute(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const hook = hookDomPurifyHrefAndSrcSanitizer(defaultSafeProtocols);
|
||||
try {
|
||||
const html = dompurify.sanitize(value, { ...options, RETURN_TRUSTED_TYPE: true });
|
||||
node.innerHTML = html as unknown as string;
|
||||
} finally {
|
||||
dompurify.removeHook('afterSanitizeAttributes');
|
||||
hook.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -326,27 +326,13 @@ function sanitizeRenderedMarkdown(
|
|||
}
|
||||
});
|
||||
|
||||
// build an anchor to map URLs to
|
||||
const anchor = document.createElement('a');
|
||||
|
||||
// https://github.com/cure53/DOMPurify/blob/main/demos/hooks-scheme-allowlist.html
|
||||
dompurify.addHook('afterSanitizeAttributes', (node) => {
|
||||
// check all href/src attributes for validity
|
||||
for (const attr of ['href', 'src']) {
|
||||
if (node.hasAttribute(attr)) {
|
||||
anchor.href = node.getAttribute(attr) as string;
|
||||
if (!allowedSchemes.includes(anchor.protocol.replace(/:$/, ''))) {
|
||||
node.removeAttribute(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
const hook = DOM.hookDomPurifyHrefAndSrcSanitizer(allowedSchemes);
|
||||
|
||||
try {
|
||||
return dompurify.sanitize(renderedMarkdown, { ...config, RETURN_TRUSTED_TYPE: true });
|
||||
} finally {
|
||||
dompurify.removeHook('uponSanitizeAttribute');
|
||||
dompurify.removeHook('afterSanitizeAttributes');
|
||||
hook.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { hookDomPurifyHrefAndSrcSanitizer } from 'vs/base/browser/dom';
|
||||
import * as dompurify from 'vs/base/browser/dompurify/dompurify';
|
||||
import { marked } from 'vs/base/common/marked/marked';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { tokenizeToString } from 'vs/editor/common/languages/textToHtmlTokenizer';
|
||||
import { ILanguageService } from 'vs/editor/common/languages/language';
|
||||
import { tokenizeToString } from 'vs/editor/common/languages/textToHtmlTokenizer';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
||||
export const DEFAULT_MARKDOWN_STYLES = `
|
||||
|
@ -152,21 +153,7 @@ code > div {
|
|||
const allowedProtocols = [Schemas.http, Schemas.https, Schemas.command];
|
||||
function sanitize(documentContent: string, allowUnknownProtocols: boolean): string {
|
||||
|
||||
// https://github.com/cure53/DOMPurify/blob/main/demos/hooks-scheme-allowlist.html
|
||||
dompurify.addHook('afterSanitizeAttributes', (node) => {
|
||||
// build an anchor to map URLs to
|
||||
const anchor = document.createElement('a');
|
||||
|
||||
// check all href/src attributes for validity
|
||||
for (const attr of ['href', 'src']) {
|
||||
if (node.hasAttribute(attr)) {
|
||||
anchor.href = node.getAttribute(attr) as string;
|
||||
if (!allowedProtocols.includes(anchor.protocol.replace(/:$/, ''))) {
|
||||
node.removeAttribute(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
const hook = hookDomPurifyHrefAndSrcSanitizer(allowedProtocols, true);
|
||||
|
||||
try {
|
||||
return dompurify.sanitize(documentContent, {
|
||||
|
@ -186,7 +173,7 @@ function sanitize(documentContent: string, allowUnknownProtocols: boolean): stri
|
|||
...(allowUnknownProtocols ? { ALLOW_UNKNOWN_PROTOCOLS: true } : {}),
|
||||
});
|
||||
} finally {
|
||||
dompurify.removeHook('afterSanitizeAttributes');
|
||||
hook.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue