diff --git a/package.json b/package.json index 14456728..18229513 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "test": "npm run lint-errors && npm run just-test-in-node", "test-in-node": "npm run lint-errors && npm run just-test-in-node", "just-test": "karma start --config karma.conf.js", - "just-test-in-node": "mocha --recursive --compilers js:babel-core/register test/core test/components test/bugs test/swagger-ui-dist-package", + "just-test-in-node": "mocha --recursive --compilers js:babel-core/register test/core test/components test/bugs test/swagger-ui-dist-package test/xss", "test-e2e": "sleep 3 && nightwatch test/e2e/scenarios/ --config test/e2e/nightwatch.json", "e2e-initial-render": "nightwatch test/e2e/scenarios/ --config test/e2e/nightwatch.json --group initial-render", "mock-api": "json-server --watch test/e2e/db.json --port 3204", diff --git a/src/core/components/providers/markdown.jsx b/src/core/components/providers/markdown.jsx index 2b21c10b..2ef8b6a6 100644 --- a/src/core/components/providers/markdown.jsx +++ b/src/core/components/providers/markdown.jsx @@ -29,7 +29,10 @@ Markdown.propTypes = { export default Markdown const sanitizeOptions = { - allowedTags: sanitize.defaults.allowedTags.concat([ "img" ]), + allowedTags: sanitize.defaults.allowedTags.concat([ "h1", "h2", "img" ]), + allowedAttributes: { + "img": sanitize.defaults.allowedAttributes.img.concat(["title"]) + }, textFilter: function(text) { return text.replace(/"/g, "\"") } diff --git a/src/core/plugins/oas3/wrap-components/markdown.js b/src/core/plugins/oas3/wrap-components/markdown.js index 103a2801..2d7f27e7 100644 --- a/src/core/plugins/oas3/wrap-components/markdown.js +++ b/src/core/plugins/oas3/wrap-components/markdown.js @@ -1,10 +1,11 @@ import React from "react" +import PropTypes from "prop-types" import ReactMarkdown from "react-markdown" import { Parser, HtmlRenderer } from "commonmark" import { OAS3ComponentWrapFactory } from "../helpers" import { sanitizer } from "core/components/providers/markdown" -export default OAS3ComponentWrapFactory(({ source }) => { +export const Markdown = ({ source }) => { if ( source ) { const parser = new Parser() const writer = new HtmlRenderer() @@ -23,4 +24,9 @@ export default OAS3ComponentWrapFactory(({ source }) => { ) } return null -}) \ No newline at end of file +} +Markdown.propTypes = { + source: PropTypes.string +} + +export default OAS3ComponentWrapFactory(Markdown) \ No newline at end of file diff --git a/test/components/markdown.js b/test/components/markdown.js new file mode 100644 index 00000000..01a55e1c --- /dev/null +++ b/test/components/markdown.js @@ -0,0 +1,48 @@ +/* eslint-env mocha */ +import React from "react" +import expect from "expect" +import { render } from "enzyme" +import Markdown from "components/providers/markdown" +import { Markdown as OAS3Markdown } from "corePlugins/oas3/wrap-components/markdown.js" + +describe("Markdown component", function() { + describe("Swagger 2.0", function() { + it("allows image elements", function() { + const str = `![Image alt text](http://image.source "Image title")` + const el = render() + expect(el.html()).toEqual(`

\n
`) + }) + + it("allows heading elements", function() { + const str = ` +# h1 +## h2 +### h3 +#### h4 +##### h5 +###### h6` + const el = render() + expect(el.html()).toEqual(`

h1

\n

h2

\n

h3

\n

h4

\n
h5
\n
h6
\n
`) + }) + }) + + describe("OAS 3", function() { + it("allows image elements", function() { + const str = `![Image alt text](http://image.source "Image title")` + const el = render() + expect(el.html()).toEqual(`

`) + }) + + it("allows heading elements", function() { + const str = ` +# h1 +## h2 +### h3 +#### h4 +##### h5 +###### h6` + const el = render() + expect(el.html()).toEqual(`

h1

\n

h2

\n

h3

\n

h4

\n
h5
\n
h6
`) + }) + }) +}) diff --git a/test/xss/info-sanitization.js b/test/xss/info-sanitization.js new file mode 100644 index 00000000..e868fe9f --- /dev/null +++ b/test/xss/info-sanitization.js @@ -0,0 +1,33 @@ +/* eslint-env mocha */ +import React from "react" +import expect from "expect" +import { render } from "enzyme" +import { fromJS } from "immutable" +import Info from "components/info" +import Markdown from "components/providers/markdown" + +describe(" Sanitization", function(){ + const dummyComponent = () => null + const components = { + Markdown + } + const props = { + getComponent: c => components[c] || dummyComponent, + info: fromJS({ + title: "Test Title **strong** ", + description: "Description *with* " + }), + host: "example.test", + basePath: "/api" + } + + it("renders sanitized .title content", function(){ + let wrapper = render() + expect(wrapper.find(".title").html()).toEqual("Test Title **strong** <script>alert(1)</script>") + }) + + it("renders sanitized .description content", function() { + let wrapper = render() + expect(wrapper.find(".description").html()).toEqual("

Description with

\n
") + }) +}) diff --git a/test/xss/markdown-script-sanitization.js b/test/xss/markdown-script-sanitization.js new file mode 100644 index 00000000..9d6624c7 --- /dev/null +++ b/test/xss/markdown-script-sanitization.js @@ -0,0 +1,36 @@ +/* eslint-env mocha */ +import React from "react" +import expect from "expect" +import { render } from "enzyme" +import Markdown from "components/providers/markdown" +import { Markdown as OAS3Markdown } from "corePlugins/oas3/wrap-components/markdown.js" + +describe("Markdown Script Sanitization", function() { + describe("Swagger 2.0", function() { + it("sanitizes ` + const el = render() + expect(el.html()).toEqual(`

script

\n
`) + }) + + it("sanitizes elements", function() { + const str = `` + const el = render() + expect(el.html()).toEqual(`

\n
`) + }) + }) + + describe("OAS 3", function() { + it("sanitizes ` + const el = render() + expect(el.html()).toEqual(`

script

`) + }) + + it("sanitizes elements", function() { + const str = `` + const el = render() + expect(el.html()).toEqual(`
`) + }) + }) +})