mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
[cr] whitelist flexbox styles in text panel editor (#43222)
* [cr] whitelist flexbox styles in text panel editor * [cr] separate sanitize function for text panel only * [cr] separate markdown function for text panel * [cr] common markdown options
This commit is contained in:
parent
6abced840d
commit
119f756c0e
@ -1,11 +1,12 @@
|
||||
export * from './string';
|
||||
export * from './markdown';
|
||||
export * from './text';
|
||||
import { escapeHtml, hasAnsiCodes, sanitize, sanitizeUrl } from './sanitize';
|
||||
import { escapeHtml, hasAnsiCodes, sanitize, sanitizeUrl, sanitizeTextPanelContent } from './sanitize';
|
||||
|
||||
export const textUtil = {
|
||||
escapeHtml,
|
||||
hasAnsiCodes,
|
||||
sanitize,
|
||||
sanitizeTextPanelContent,
|
||||
sanitizeUrl,
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { renderMarkdown } from './markdown';
|
||||
import { sanitizeTextPanelContent } from './sanitize';
|
||||
|
||||
describe('Markdown wrapper', () => {
|
||||
it('should be able to handle undefined value', () => {
|
||||
@ -10,4 +11,13 @@ describe('Markdown wrapper', () => {
|
||||
const str = renderMarkdown('<script>alert()</script>');
|
||||
expect(str).toBe('<script>alert()</script>');
|
||||
});
|
||||
|
||||
it('should allow whitelisted styles in text panel', () => {
|
||||
const html =
|
||||
'<div style="display:flex; flex-direction: column; flex-wrap: wrap; justify-content: start; gap: 2px;"><div style="flex-basis: 50%"></div></div>';
|
||||
const str = sanitizeTextPanelContent(html);
|
||||
expect(str).toBe(
|
||||
'<div style="display:flex; flex-direction:column; flex-wrap:wrap; justify-content:start; gap:2px;"><div style="flex-basis:50%;"></div></div>'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { marked } from 'marked';
|
||||
import { sanitize } from './sanitize';
|
||||
import { sanitize, sanitizeTextPanelContent } from './sanitize';
|
||||
|
||||
let hasInitialized = false;
|
||||
|
||||
@ -7,15 +7,17 @@ export interface RenderMarkdownOptions {
|
||||
noSanitize?: boolean;
|
||||
}
|
||||
|
||||
const markdownOptions = {
|
||||
pedantic: false,
|
||||
gfm: true,
|
||||
smartLists: true,
|
||||
smartypants: false,
|
||||
xhtml: false,
|
||||
};
|
||||
|
||||
export function renderMarkdown(str?: string, options?: RenderMarkdownOptions): string {
|
||||
if (!hasInitialized) {
|
||||
marked.setOptions({
|
||||
pedantic: false,
|
||||
gfm: true,
|
||||
smartLists: true,
|
||||
smartypants: false,
|
||||
xhtml: false,
|
||||
});
|
||||
marked.setOptions({ ...markdownOptions });
|
||||
hasInitialized = true;
|
||||
}
|
||||
|
||||
@ -26,3 +28,17 @@ export function renderMarkdown(str?: string, options?: RenderMarkdownOptions): s
|
||||
|
||||
return sanitize(html);
|
||||
}
|
||||
|
||||
export function renderTextPanelMarkdown(str?: string, options?: RenderMarkdownOptions): string {
|
||||
if (!hasInitialized) {
|
||||
marked.setOptions({ ...markdownOptions });
|
||||
hasInitialized = true;
|
||||
}
|
||||
|
||||
const html = marked(str || '');
|
||||
if (options?.noSanitize) {
|
||||
return html;
|
||||
}
|
||||
|
||||
return sanitizeTextPanelContent(html);
|
||||
}
|
||||
|
@ -10,6 +10,29 @@ const sanitizeXSS = new FilterXSS({
|
||||
whiteList: XSSWL,
|
||||
});
|
||||
|
||||
const sanitizeTextPanelWhitelist = new xss.FilterXSS({
|
||||
whiteList: XSSWL,
|
||||
css: {
|
||||
whiteList: {
|
||||
...xss.getDefaultCSSWhiteList(),
|
||||
'flex-direction': true,
|
||||
'flex-wrap': true,
|
||||
'flex-basis': true,
|
||||
'flex-grow': true,
|
||||
'flex-shrink': true,
|
||||
'flex-flow': true,
|
||||
gap: true,
|
||||
order: true,
|
||||
'justify-content': true,
|
||||
'justify-items': true,
|
||||
'justify-self': true,
|
||||
'align-items': true,
|
||||
'align-content': true,
|
||||
'align-self': true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns string safe from XSS attacks.
|
||||
*
|
||||
@ -26,6 +49,15 @@ export function sanitize(unsanitizedString: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
export function sanitizeTextPanelContent(unsanitizedString: string): string {
|
||||
try {
|
||||
return sanitizeTextPanelWhitelist.process(unsanitizedString);
|
||||
} catch (error) {
|
||||
console.error('String could not be sanitized', unsanitizedString);
|
||||
return 'Text string could not be sanitized';
|
||||
}
|
||||
}
|
||||
|
||||
export function sanitizeUrl(url: string): string {
|
||||
return braintreeSanitizeUrl(url);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Libraries
|
||||
import React, { PureComponent } from 'react';
|
||||
import { debounce } from 'lodash';
|
||||
import { PanelProps, renderMarkdown, textUtil } from '@grafana/data';
|
||||
import { PanelProps, renderTextPanelMarkdown, textUtil } from '@grafana/data';
|
||||
// Utils
|
||||
import config from 'app/core/config';
|
||||
// Types
|
||||
@ -44,7 +44,9 @@ export class TextPanel extends PureComponent<Props, State> {
|
||||
|
||||
prepareMarkdown(content: string): string {
|
||||
// Sanitize is disabled here as we handle that after variable interpolation
|
||||
return renderMarkdown(this.interpolateAndSanitizeString(content), { noSanitize: config.disableSanitizeHtml });
|
||||
return renderTextPanelMarkdown(this.interpolateAndSanitizeString(content), {
|
||||
noSanitize: config.disableSanitizeHtml,
|
||||
});
|
||||
}
|
||||
|
||||
interpolateAndSanitizeString(content: string): string {
|
||||
@ -52,7 +54,7 @@ export class TextPanel extends PureComponent<Props, State> {
|
||||
|
||||
content = replaceVariables(content, {}, 'html');
|
||||
|
||||
return config.disableSanitizeHtml ? content : textUtil.sanitize(content);
|
||||
return config.disableSanitizeHtml ? content : textUtil.sanitizeTextPanelContent(content);
|
||||
}
|
||||
|
||||
processContent(options: PanelOptions): string {
|
||||
|
@ -40,7 +40,7 @@ export const TextPanelEditor: FC<StandardEditorProps<string, any, PanelOptions>>
|
||||
width={width}
|
||||
showMiniMap={false}
|
||||
showLineNumbers={false}
|
||||
height="200px"
|
||||
height="500px"
|
||||
getSuggestions={getSuggestions}
|
||||
/>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user