mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-19 07:19:41 +02:00
Merge branch 'advisory-fix-1' of https://github.com/mermaid-js/mermaid-ghsa-7rqq-prvp-x9jh into advisory-fix-1
* 'advisory-fix-1' of https://github.com/mermaid-js/mermaid-ghsa-7rqq-prvp-x9jh: fix: Sanitize Katex
This commit is contained in:
@@ -311,9 +311,8 @@ export const hasKatex = (text: string): boolean => (text.match(katexRegex)?.leng
|
|||||||
* @returns Object containing \{width, height\}
|
* @returns Object containing \{width, height\}
|
||||||
*/
|
*/
|
||||||
export const calculateMathMLDimensions = async (text: string, config: MermaidConfig) => {
|
export const calculateMathMLDimensions = async (text: string, config: MermaidConfig) => {
|
||||||
text = await renderKatex(text, config);
|
|
||||||
const divElem = document.createElement('div');
|
const divElem = document.createElement('div');
|
||||||
divElem.innerHTML = text;
|
divElem.innerHTML = await renderKatexSanitized(text, config);
|
||||||
divElem.id = 'katex-temp';
|
divElem.id = 'katex-temp';
|
||||||
divElem.style.visibility = 'hidden';
|
divElem.style.visibility = 'hidden';
|
||||||
divElem.style.position = 'absolute';
|
divElem.style.position = 'absolute';
|
||||||
@@ -325,14 +324,7 @@ export const calculateMathMLDimensions = async (text: string, config: MermaidCon
|
|||||||
return dim;
|
return dim;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
const renderKatexUnsanitized = async (text: string, config: MermaidConfig): Promise<string> => {
|
||||||
* Attempts to render and return the KaTeX portion of a string with MathML
|
|
||||||
*
|
|
||||||
* @param text - The text to test
|
|
||||||
* @param config - Configuration for Mermaid
|
|
||||||
* @returns String containing MathML if KaTeX is supported, or an error message if it is not and stylesheets aren't present
|
|
||||||
*/
|
|
||||||
export const renderKatex = async (text: string, config: MermaidConfig): Promise<string> => {
|
|
||||||
if (!hasKatex(text)) {
|
if (!hasKatex(text)) {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
@@ -373,6 +365,20 @@ export const renderKatex = async (text: string, config: MermaidConfig): Promise<
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to render and return the KaTeX portion of a string with MathML
|
||||||
|
*
|
||||||
|
* @param text - The text to test
|
||||||
|
* @param config - Configuration for Mermaid
|
||||||
|
* @returns String containing MathML if KaTeX is supported, or an error message if it is not and stylesheets aren't present
|
||||||
|
*/
|
||||||
|
export const renderKatexSanitized = async (
|
||||||
|
text: string,
|
||||||
|
config: MermaidConfig
|
||||||
|
): Promise<string> => {
|
||||||
|
return sanitizeText(await renderKatexUnsanitized(text, config), config);
|
||||||
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
getRows,
|
getRows,
|
||||||
sanitizeText,
|
sanitizeText,
|
||||||
|
@@ -1,8 +1,12 @@
|
|||||||
import common, { calculateMathMLDimensions, hasKatex, renderKatex } from '../common/common.js';
|
|
||||||
import * as svgDrawCommon from '../common/svgDrawCommon.js';
|
|
||||||
import { ZERO_WIDTH_SPACE, parseFontSize } from '../../utils.js';
|
|
||||||
import { sanitizeUrl } from '@braintree/sanitize-url';
|
import { sanitizeUrl } from '@braintree/sanitize-url';
|
||||||
import * as configApi from '../../config.js';
|
import * as configApi from '../../config.js';
|
||||||
|
import { ZERO_WIDTH_SPACE, parseFontSize } from '../../utils.js';
|
||||||
|
import common, {
|
||||||
|
calculateMathMLDimensions,
|
||||||
|
hasKatex,
|
||||||
|
renderKatexSanitized,
|
||||||
|
} from '../common/common.js';
|
||||||
|
import * as svgDrawCommon from '../common/svgDrawCommon.js';
|
||||||
|
|
||||||
export const ACTOR_TYPE_WIDTH = 18 * 2;
|
export const ACTOR_TYPE_WIDTH = 18 * 2;
|
||||||
const TOP_ACTOR_CLASS = 'actor-top';
|
const TOP_ACTOR_CLASS = 'actor-top';
|
||||||
@@ -87,13 +91,13 @@ const popupMenuToggle = function (popId) {
|
|||||||
|
|
||||||
export const drawKatex = async function (elem, textData, msgModel = null) {
|
export const drawKatex = async function (elem, textData, msgModel = null) {
|
||||||
let textElem = elem.append('foreignObject');
|
let textElem = elem.append('foreignObject');
|
||||||
const lines = await renderKatex(textData.text, configApi.getConfig());
|
const linesSanitized = await renderKatexSanitized(textData.text, configApi.getConfig());
|
||||||
|
|
||||||
const divElem = textElem
|
const divElem = textElem
|
||||||
.append('xhtml:div')
|
.append('xhtml:div')
|
||||||
.attr('style', 'width: fit-content;')
|
.attr('style', 'width: fit-content;')
|
||||||
.attr('xmlns', 'http://www.w3.org/1999/xhtml')
|
.attr('xmlns', 'http://www.w3.org/1999/xhtml')
|
||||||
.html(lines);
|
.html(linesSanitized);
|
||||||
const dim = divElem.node().getBoundingClientRect();
|
const dim = divElem.node().getBoundingClientRect();
|
||||||
|
|
||||||
textElem.attr('height', Math.round(dim.height)).attr('width', Math.round(dim.width));
|
textElem.attr('height', Math.round(dim.height)).attr('width', Math.round(dim.width));
|
||||||
@@ -965,7 +969,7 @@ const _drawTextCandidateFunc = (function () {
|
|||||||
.append('div')
|
.append('div')
|
||||||
.style('text-align', 'center')
|
.style('text-align', 'center')
|
||||||
.style('vertical-align', 'middle')
|
.style('vertical-align', 'middle')
|
||||||
.html(await renderKatex(content, configApi.getConfig()));
|
.html(await renderKatexSanitized(content, configApi.getConfig()));
|
||||||
|
|
||||||
byTspan(content, s, x, y, width, height, textAttrs, conf);
|
byTspan(content, s, x, y, width, height, textAttrs, conf);
|
||||||
_setTextAttrs(text, textAttrs);
|
_setTextAttrs(text, textAttrs);
|
||||||
|
@@ -4,7 +4,7 @@ import { select } from 'd3';
|
|||||||
import type { MermaidConfig } from '../config.type.js';
|
import type { MermaidConfig } from '../config.type.js';
|
||||||
import { getConfig, sanitizeText } from '../diagram-api/diagramAPI.js';
|
import { getConfig, sanitizeText } from '../diagram-api/diagramAPI.js';
|
||||||
import type { SVGGroup } from '../diagram-api/types.js';
|
import type { SVGGroup } from '../diagram-api/types.js';
|
||||||
import common, { hasKatex, renderKatex } from '../diagrams/common/common.js';
|
import common, { hasKatex, renderKatexSanitized } from '../diagrams/common/common.js';
|
||||||
import type { D3TSpanElement, D3TextElement } from '../diagrams/common/commonTypes.js';
|
import type { D3TSpanElement, D3TextElement } from '../diagrams/common/commonTypes.js';
|
||||||
import { log } from '../logger.js';
|
import { log } from '../logger.js';
|
||||||
import { markdownToHTML, markdownToLines } from '../rendering-util/handle-markdown-text.js';
|
import { markdownToHTML, markdownToLines } from '../rendering-util/handle-markdown-text.js';
|
||||||
@@ -29,7 +29,10 @@ async function addHtmlSpan(element, node, width, classes, addBackground = false)
|
|||||||
const div = fo.append('xhtml:div');
|
const div = fo.append('xhtml:div');
|
||||||
let label = node.label;
|
let label = node.label;
|
||||||
if (node.label && hasKatex(node.label)) {
|
if (node.label && hasKatex(node.label)) {
|
||||||
label = await renderKatex(node.label.replace(common.lineBreakRegex, '\n'), getConfig());
|
label = await renderKatexSanitized(
|
||||||
|
node.label.replace(common.lineBreakRegex, '\n'),
|
||||||
|
getConfig()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
const labelClass = node.isNode ? 'nodeLabel' : 'edgeLabel';
|
const labelClass = node.isNode ? 'nodeLabel' : 'edgeLabel';
|
||||||
const span = div.append('span');
|
const span = div.append('span');
|
||||||
|
@@ -1,7 +1,12 @@
|
|||||||
import { select } from 'd3';
|
import { select } from 'd3';
|
||||||
import { log } from '../../logger.js';
|
|
||||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||||
import common, { evaluate, renderKatex, hasKatex } from '../../diagrams/common/common.js';
|
import common, {
|
||||||
|
evaluate,
|
||||||
|
hasKatex,
|
||||||
|
renderKatexSanitized,
|
||||||
|
sanitizeText,
|
||||||
|
} from '../../diagrams/common/common.js';
|
||||||
|
import { log } from '../../logger.js';
|
||||||
import { decodeEntities } from '../../utils.js';
|
import { decodeEntities } from '../../utils.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -22,20 +27,21 @@ async function addHtmlLabel(node) {
|
|||||||
const fo = select(document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject'));
|
const fo = select(document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject'));
|
||||||
const div = fo.append('xhtml:div');
|
const div = fo.append('xhtml:div');
|
||||||
|
|
||||||
|
const config = getConfig();
|
||||||
let label = node.label;
|
let label = node.label;
|
||||||
if (node.label && hasKatex(node.label)) {
|
if (node.label && hasKatex(node.label)) {
|
||||||
label = await renderKatex(node.label.replace(common.lineBreakRegex, '\n'), getConfig());
|
label = await renderKatexSanitized(node.label.replace(common.lineBreakRegex, '\n'), config);
|
||||||
}
|
}
|
||||||
const labelClass = node.isNode ? 'nodeLabel' : 'edgeLabel';
|
const labelClass = node.isNode ? 'nodeLabel' : 'edgeLabel';
|
||||||
div.html(
|
const labelSpan =
|
||||||
'<span class="' +
|
'<span class="' +
|
||||||
labelClass +
|
labelClass +
|
||||||
'" ' +
|
'" ' +
|
||||||
(node.labelStyle ? 'style="' + node.labelStyle + '"' : '') + // codeql [js/html-constructed-from-input] : false positive
|
(node.labelStyle ? 'style="' + node.labelStyle + '"' : '') + // codeql [js/html-constructed-from-input] : false positive
|
||||||
'>' +
|
'>' +
|
||||||
label +
|
label +
|
||||||
'</span>'
|
'</span>';
|
||||||
);
|
div.html(sanitizeText(labelSpan, config));
|
||||||
|
|
||||||
applyStyle(div, node.labelStyle);
|
applyStyle(div, node.labelStyle);
|
||||||
div.style('display', 'inline-block');
|
div.style('display', 'inline-block');
|
||||||
|
Reference in New Issue
Block a user