mirror of
https://github.com/Redocly/redoc.git
synced 2025-02-18 10:50:32 +03:00
Implement sanitization (aka untrustedSpec option)
This commit is contained in:
parent
ce1f014f62
commit
07eef93820
|
@ -28,6 +28,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/chai": "^4.0.5",
|
"@types/chai": "^4.0.5",
|
||||||
"@types/cypress": "^0.1.2",
|
"@types/cypress": "^0.1.2",
|
||||||
|
"@types/dompurify": "^0.0.31",
|
||||||
"@types/enzyme": "^2.8.10",
|
"@types/enzyme": "^2.8.10",
|
||||||
"@types/enzyme-to-json": "^1.5.0",
|
"@types/enzyme-to-json": "^1.5.0",
|
||||||
"@types/jest": "^20.0.8",
|
"@types/jest": "^20.0.8",
|
||||||
|
@ -72,6 +73,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/prop-types": "^15.5.2",
|
"@types/prop-types": "^15.5.2",
|
||||||
"decko": "^1.2.0",
|
"decko": "^1.2.0",
|
||||||
|
"dompurify": "^1.0.2",
|
||||||
"eventemitter3": "^2.0.3",
|
"eventemitter3": "^2.0.3",
|
||||||
"json-pointer": "^0.6.0",
|
"json-pointer": "^0.6.0",
|
||||||
"json-schema-ref-parser": "^3.3.1",
|
"json-schema-ref-parser": "^3.3.1",
|
||||||
|
|
|
@ -2,6 +2,8 @@ import * as React from 'react';
|
||||||
import styled from '../../styled-components';
|
import styled from '../../styled-components';
|
||||||
|
|
||||||
import { MarkdownRenderer } from '../../services';
|
import { MarkdownRenderer } from '../../services';
|
||||||
|
import { ComponentWithOptions } from '../OptionsProvider';
|
||||||
|
import * as DOMPurify from 'dompurify';
|
||||||
|
|
||||||
import { markdownCss } from './styles';
|
import { markdownCss } from './styles';
|
||||||
|
|
||||||
|
@ -12,9 +14,10 @@ interface MarkdownProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
raw?: boolean;
|
raw?: boolean;
|
||||||
components?: { [name: string]: React.ComponentClass };
|
components?: { [name: string]: React.ComponentClass };
|
||||||
|
sanitize?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
class InternalMarkdown extends React.PureComponent<MarkdownProps> {
|
class InternalMarkdown extends ComponentWithOptions<MarkdownProps> {
|
||||||
constructor(props: MarkdownProps) {
|
constructor(props: MarkdownProps) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
|
@ -24,6 +27,14 @@ class InternalMarkdown extends React.PureComponent<MarkdownProps> {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
let sanitize: (string) => string;
|
||||||
|
|
||||||
|
if (this.props.sanitize || this.options.untrustedSpec) {
|
||||||
|
sanitize = html => DOMPurify.sanitize(html);
|
||||||
|
} else {
|
||||||
|
sanitize = html => html;
|
||||||
|
}
|
||||||
|
|
||||||
const renderer = new MarkdownRenderer();
|
const renderer = new MarkdownRenderer();
|
||||||
const { source, raw, className, components, inline, dense } = this.props;
|
const { source, raw, className, components, inline, dense } = this.props;
|
||||||
const parts = components
|
const parts = components
|
||||||
|
@ -40,7 +51,7 @@ class InternalMarkdown extends React.PureComponent<MarkdownProps> {
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
className={className + appendClass}
|
className={className + appendClass}
|
||||||
dangerouslySetInnerHTML={{ __html: parts[0] as string }}
|
dangerouslySetInnerHTML={{ __html: sanitize(parts[0] as string) }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -50,7 +61,7 @@ class InternalMarkdown extends React.PureComponent<MarkdownProps> {
|
||||||
{parts.map(
|
{parts.map(
|
||||||
(part, idx) =>
|
(part, idx) =>
|
||||||
typeof part === 'string' ? (
|
typeof part === 'string' ? (
|
||||||
<div key={idx} dangerouslySetInnerHTML={{ __html: part }} />
|
<div key={idx} dangerouslySetInnerHTML={{ __html: sanitize(part) }} />
|
||||||
) : (
|
) : (
|
||||||
<part.component key={idx} {...part.attrs} />
|
<part.component key={idx} {...part.attrs} />
|
||||||
),
|
),
|
||||||
|
|
|
@ -11,6 +11,7 @@ export interface RedocRawOptions {
|
||||||
noAutoAuth?: boolean | string;
|
noAutoAuth?: boolean | string;
|
||||||
nativeScrollbars?: boolean | string;
|
nativeScrollbars?: boolean | string;
|
||||||
pathInMiddlePanel?: boolean | string;
|
pathInMiddlePanel?: boolean | string;
|
||||||
|
untrustedSpec?: boolean | string;
|
||||||
hideLoading?: boolean | string;
|
hideLoading?: boolean | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +30,7 @@ export class RedocNormalizedOptions {
|
||||||
noAutoAuth: boolean;
|
noAutoAuth: boolean;
|
||||||
nativeScrollbars: boolean;
|
nativeScrollbars: boolean;
|
||||||
pathInMiddlePanel: boolean;
|
pathInMiddlePanel: boolean;
|
||||||
|
untrustedSpec: boolean;
|
||||||
|
|
||||||
constructor(raw: RedocRawOptions) {
|
constructor(raw: RedocRawOptions) {
|
||||||
this.theme = { ...(raw.theme || {}), ...defaultTheme }; // todo: merge deep
|
this.theme = { ...(raw.theme || {}), ...defaultTheme }; // todo: merge deep
|
||||||
|
@ -39,6 +41,7 @@ export class RedocNormalizedOptions {
|
||||||
this.noAutoAuth = argValueToBoolean(raw.noAutoAuth);
|
this.noAutoAuth = argValueToBoolean(raw.noAutoAuth);
|
||||||
this.nativeScrollbars = argValueToBoolean(raw.nativeScrollbars);
|
this.nativeScrollbars = argValueToBoolean(raw.nativeScrollbars);
|
||||||
this.pathInMiddlePanel = argValueToBoolean(raw.pathInMiddlePanel);
|
this.pathInMiddlePanel = argValueToBoolean(raw.pathInMiddlePanel);
|
||||||
|
this.untrustedSpec = argValueToBoolean(raw.untrustedSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
static normalizeExpandResponses(value: RedocRawOptions['expandResponses']) {
|
static normalizeExpandResponses(value: RedocRawOptions['expandResponses']) {
|
||||||
|
|
|
@ -27,6 +27,10 @@
|
||||||
version "0.1.3"
|
version "0.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/@types/cypress/-/cypress-0.1.3.tgz#1783db79f0d1a44b85aae6a473104e2d7987e022"
|
resolved "https://registry.yarnpkg.com/@types/cypress/-/cypress-0.1.3.tgz#1783db79f0d1a44b85aae6a473104e2d7987e022"
|
||||||
|
|
||||||
|
"@types/dompurify@^0.0.31":
|
||||||
|
version "0.0.31"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-0.0.31.tgz#f152d5a81f2b5625e29f11eb016cd9b301d0d4b4"
|
||||||
|
|
||||||
"@types/enzyme-to-json@^1.5.0":
|
"@types/enzyme-to-json@^1.5.0":
|
||||||
version "1.5.0"
|
version "1.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/enzyme-to-json/-/enzyme-to-json-1.5.0.tgz#0b53c4c8479050e76a38ad298fb2672a7241fad3"
|
resolved "https://registry.yarnpkg.com/@types/enzyme-to-json/-/enzyme-to-json-1.5.0.tgz#0b53c4c8479050e76a38ad298fb2672a7241fad3"
|
||||||
|
@ -1774,6 +1778,10 @@ domhandler@^2.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
domelementtype "1"
|
domelementtype "1"
|
||||||
|
|
||||||
|
dompurify@^1.0.2:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-1.0.2.tgz#7cf47d57614324a9723a1ba69143eeb7d3c617ac"
|
||||||
|
|
||||||
domutils@1.1:
|
domutils@1.1:
|
||||||
version "1.1.6"
|
version "1.1.6"
|
||||||
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.1.6.tgz#bddc3de099b9a2efacc51c623f28f416ecc57485"
|
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.1.6.tgz#bddc3de099b9a2efacc51c623f28f416ecc57485"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user