Skip to content

Commit 6575255

Browse files
authored
Merge pull request microsoft#256082 from mjbvz/certain-halibut
Refactor dom sanitizer usage
2 parents 6c6ff57 + 4219c84 commit 6575255

File tree

13 files changed

+587
-393
lines changed

13 files changed

+587
-393
lines changed

src/vs/base/browser/dom.ts

Lines changed: 1 addition & 219 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@ import { IMouseEvent, StandardMouseEvent } from './mouseEvent.js';
1010
import { AbstractIdleValue, IntervalTimer, TimeoutTimer, _runWhenIdle, IdleDeadline } from '../common/async.js';
1111
import { BugIndicatingError, onUnexpectedError } from '../common/errors.js';
1212
import * as event from '../common/event.js';
13-
import dompurify from './dompurify/dompurify.js';
1413
import { KeyCode } from '../common/keyCodes.js';
1514
import { Disposable, DisposableStore, IDisposable, toDisposable } from '../common/lifecycle.js';
16-
import { RemoteAuthorities, Schemas } from '../common/network.js';
15+
import { RemoteAuthorities } from '../common/network.js';
1716
import * as platform from '../common/platform.js';
1817
import { URI } from '../common/uri.js';
1918
import { hash } from '../common/hash.js';
@@ -1681,223 +1680,6 @@ export function detectFullscreen(targetWindow: Window): IDetectedFullscreen | nu
16811680
return null;
16821681
}
16831682

1684-
// -- sanitize and trusted html
1685-
1686-
/**
1687-
* Hooks dompurify using `afterSanitizeAttributes` to check that all `href` and `src`
1688-
* attributes are valid.
1689-
*/
1690-
export function hookDomPurifyHrefAndSrcSanitizer(allowedProtocols: readonly string[], allowDataImages = false): IDisposable {
1691-
// https://github.com/cure53/DOMPurify/blob/main/demos/hooks-scheme-allowlist.html
1692-
1693-
// build an anchor to map URLs to
1694-
const anchor = document.createElement('a');
1695-
1696-
dompurify.addHook('afterSanitizeAttributes', (node) => {
1697-
// check all href/src attributes for validity
1698-
for (const attr of ['href', 'src']) {
1699-
if (node.hasAttribute(attr)) {
1700-
const attrValue = node.getAttribute(attr) as string;
1701-
if (attr === 'href' && attrValue.startsWith('#')) {
1702-
// Allow fragment links
1703-
continue;
1704-
}
1705-
1706-
anchor.href = attrValue;
1707-
if (!allowedProtocols.includes(anchor.protocol.replace(/:$/, ''))) {
1708-
if (allowDataImages && attr === 'src' && anchor.href.startsWith('data:')) {
1709-
continue;
1710-
}
1711-
1712-
node.removeAttribute(attr);
1713-
}
1714-
}
1715-
}
1716-
});
1717-
1718-
return toDisposable(() => {
1719-
dompurify.removeHook('afterSanitizeAttributes');
1720-
});
1721-
}
1722-
1723-
const defaultSafeProtocols = [
1724-
Schemas.http,
1725-
Schemas.https,
1726-
Schemas.command,
1727-
];
1728-
1729-
/**
1730-
* List of safe, non-input html tags.
1731-
*/
1732-
export const basicMarkupHtmlTags = Object.freeze([
1733-
'a',
1734-
'abbr',
1735-
'b',
1736-
'bdo',
1737-
'blockquote',
1738-
'br',
1739-
'caption',
1740-
'cite',
1741-
'code',
1742-
'col',
1743-
'colgroup',
1744-
'dd',
1745-
'del',
1746-
'details',
1747-
'dfn',
1748-
'div',
1749-
'dl',
1750-
'dt',
1751-
'em',
1752-
'figcaption',
1753-
'figure',
1754-
'h1',
1755-
'h2',
1756-
'h3',
1757-
'h4',
1758-
'h5',
1759-
'h6',
1760-
'hr',
1761-
'i',
1762-
'img',
1763-
'input',
1764-
'ins',
1765-
'kbd',
1766-
'label',
1767-
'li',
1768-
'mark',
1769-
'ol',
1770-
'p',
1771-
'pre',
1772-
'q',
1773-
'rp',
1774-
'rt',
1775-
'ruby',
1776-
'samp',
1777-
'small',
1778-
'small',
1779-
'source',
1780-
'span',
1781-
'strike',
1782-
'strong',
1783-
'sub',
1784-
'summary',
1785-
'sup',
1786-
'table',
1787-
'tbody',
1788-
'td',
1789-
'tfoot',
1790-
'th',
1791-
'thead',
1792-
'time',
1793-
'tr',
1794-
'tt',
1795-
'u',
1796-
'ul',
1797-
'var',
1798-
'video',
1799-
'wbr',
1800-
]);
1801-
1802-
export const trustedMathMlTags = Object.freeze([
1803-
'semantics',
1804-
'annotation',
1805-
'math',
1806-
'menclose',
1807-
'merror',
1808-
'mfenced',
1809-
'mfrac',
1810-
'mglyph',
1811-
'mi',
1812-
'mlabeledtr',
1813-
'mmultiscripts',
1814-
'mn',
1815-
'mo',
1816-
'mover',
1817-
'mpadded',
1818-
'mphantom',
1819-
'mroot',
1820-
'mrow',
1821-
'ms',
1822-
'mspace',
1823-
'msqrt',
1824-
'mstyle',
1825-
'msub',
1826-
'msup',
1827-
'msubsup',
1828-
'mtable',
1829-
'mtd',
1830-
'mtext',
1831-
'mtr',
1832-
'munder',
1833-
'munderover',
1834-
'mprescripts',
1835-
1836-
// svg tags
1837-
'svg',
1838-
'altglyph',
1839-
'altglyphdef',
1840-
'altglyphitem',
1841-
'circle',
1842-
'clippath',
1843-
'defs',
1844-
'desc',
1845-
'ellipse',
1846-
'filter',
1847-
'font',
1848-
'g',
1849-
'glyph',
1850-
'glyphref',
1851-
'hkern',
1852-
'line',
1853-
'lineargradient',
1854-
'marker',
1855-
'mask',
1856-
'metadata',
1857-
'mpath',
1858-
'path',
1859-
'pattern',
1860-
'polygon',
1861-
'polyline',
1862-
'radialgradient',
1863-
'rect',
1864-
'stop',
1865-
'style',
1866-
'switch',
1867-
'symbol',
1868-
'text',
1869-
'textpath',
1870-
'title',
1871-
'tref',
1872-
'tspan',
1873-
'view',
1874-
'vkern',
1875-
]);
1876-
1877-
1878-
export const defaultAllowedAttrs = Object.freeze(['href', 'data-href', 'data-command', 'target', 'title', 'name', 'src', 'alt', 'class', 'id', 'role', 'tabindex', 'style', 'data-code', 'width', 'height', 'align', 'x-dispatch', 'required', 'checked', 'placeholder', 'type', 'start']);
1879-
1880-
const defaultDomPurifyConfig = Object.freeze<dompurify.Config & { RETURN_TRUSTED_TYPE: true }>({
1881-
ALLOWED_TAGS: ['a', 'button', 'blockquote', 'code', 'div', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'input', 'label', 'li', 'p', 'pre', 'select', 'small', 'span', 'strong', 'textarea', 'ul', 'ol'],
1882-
ALLOWED_ATTR: [...defaultAllowedAttrs],
1883-
RETURN_DOM: false,
1884-
RETURN_DOM_FRAGMENT: false,
1885-
RETURN_TRUSTED_TYPE: true
1886-
});
1887-
1888-
/**
1889-
* Sanitizes the given `value` and reset the given `node` with it.
1890-
*/
1891-
export function safeInnerHtml(node: HTMLElement, value: string, extraDomPurifyConfig?: dompurify.Config): void {
1892-
const hook = hookDomPurifyHrefAndSrcSanitizer(defaultSafeProtocols);
1893-
try {
1894-
const html = dompurify.sanitize(value, { ...defaultDomPurifyConfig, ...extraDomPurifyConfig });
1895-
node.innerHTML = html as unknown as string;
1896-
} finally {
1897-
hook.dispose();
1898-
}
1899-
}
1900-
19011683
type ModifierKey = 'alt' | 'ctrl' | 'shift' | 'meta';
19021684

19031685
export interface IModifierKeyStatus {

0 commit comments

Comments
 (0)