Fixes swagger-editor/#1502.

Change logic for markdown rendering to:

1. Convert source markdown to HTML
2. Sanitize HTML
3. Send sanitized HTML to markdown renderer
This commit is contained in:
Owen Conti
2017-09-27 18:05:12 -06:00
parent 774a06606d
commit 590819ad9b
4 changed files with 45 additions and 25 deletions

View File

@@ -42,6 +42,7 @@
"base64-js": "^1.2.0", "base64-js": "^1.2.0",
"brace": "0.7.0", "brace": "0.7.0",
"classnames": "^2.2.5", "classnames": "^2.2.5",
"commonmark": "^0.28.1",
"css.escape": "1.5.1", "css.escape": "1.5.1",
"deep-extend": "0.4.1", "deep-extend": "0.4.1",
"expect": "1.20.2", "expect": "1.20.2",
@@ -72,6 +73,7 @@
"redux": "^3.x.x", "redux": "^3.x.x",
"redux-immutable": "3.0.8", "redux-immutable": "3.0.8",
"redux-logger": "*", "redux-logger": "*",
"remarkable": "^1.7.1",
"reselect": "2.5.3", "reselect": "2.5.3",
"sanitize-html": "^1.14.1", "sanitize-html": "^1.14.1",
"scroll-to-element": "^2.0.0", "scroll-to-element": "^2.0.0",

View File

@@ -1,22 +1,25 @@
import React from "react" import React from "react"
import PropTypes from "prop-types" import PropTypes from "prop-types"
import Remarkable from "react-remarkable" import Remarkable from "remarkable"
import sanitize from "sanitize-html" import sanitize from "sanitize-html"
function Markdown({ source }) { function Markdown({ source }) {
const sanitized = sanitizer(source) const html = new Remarkable({
html: true,
typographer: true,
breaks: true,
linkify: true,
linkTarget: "_blank"
}).render(source)
const sanitized = sanitizer(html)
// sometimes the sanitizer returns "undefined" as a string if ( !source || !html || !sanitized ) {
if(!source || !sanitized || sanitized === "undefined") {
return null return null
} }
return <div className="markdown"> return (
<Remarkable <div className="markdown" dangerouslySetInnerHTML={{ __html: sanitized }}></div>
options={{html: true, typographer: true, breaks: true, linkify: true, linkTarget: "_blank"}} )
source={sanitized}
></Remarkable>
</div>
} }
Markdown.propTypes = { Markdown.propTypes = {
@@ -26,9 +29,9 @@ Markdown.propTypes = {
export default Markdown export default Markdown
const sanitizeOptions = { const sanitizeOptions = {
allowedTags: sanitize.defaults.allowedTags.concat([ "img" ]),
textFilter: function(text) { textFilter: function(text) {
return text return text.replace(/&quot;/g, "\"")
.replace(/&quot;/g, "\"")
} }
} }

View File

@@ -111,7 +111,7 @@ export default class Response extends React.Component {
if(examples) { if(examples) {
examples = examples.map(example => { examples = examples.map(example => {
// Remove unwanted properties from examples // Remove unwanted properties from examples
return example.set("$$ref", undefined) return example.set ? example.set("$$ref", undefined) : example
}) })
} }

View File

@@ -1,11 +1,26 @@
import React from "react" import React from "react"
import ReactMarkdown from "react-markdown" import ReactMarkdown from "react-markdown"
import { Parser, HtmlRenderer } from "commonmark"
import { OAS3ComponentWrapFactory } from "../helpers" import { OAS3ComponentWrapFactory } from "../helpers"
import { sanitizer } from "core/components/providers/markdown" import { sanitizer } from "core/components/providers/markdown"
export default OAS3ComponentWrapFactory(({ source }) => { return source ? ( export default OAS3ComponentWrapFactory(({ source }) => {
if ( source ) {
const parser = new Parser()
const writer = new HtmlRenderer()
const html = writer.render(parser.parse(source || ""))
const sanitized = sanitizer(html)
if ( !source || !html || !sanitized ) {
return null
}
return (
<ReactMarkdown <ReactMarkdown
source={sanitizer(source)} source={sanitized}
className={"renderedMarkdown"} className={"renderedMarkdown"}
/> />
) : null}) )
}
return null
})