Merge branch 'master' into bug/auth-display-regression
This commit is contained in:
@@ -32,7 +32,7 @@
|
|||||||
"test": "npm run lint-errors && npm run just-test-in-node",
|
"test": "npm run lint-errors && npm run just-test-in-node",
|
||||||
"test-in-node": "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": "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",
|
"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",
|
"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",
|
"mock-api": "json-server --watch test/e2e/db.json --port 3204",
|
||||||
|
|||||||
@@ -29,7 +29,10 @@ Markdown.propTypes = {
|
|||||||
export default Markdown
|
export default Markdown
|
||||||
|
|
||||||
const sanitizeOptions = {
|
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) {
|
textFilter: function(text) {
|
||||||
return text.replace(/"/g, "\"")
|
return text.replace(/"/g, "\"")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,8 +83,12 @@ export default class ResponseBody extends React.Component {
|
|||||||
// Anything else (CORS)
|
// Anything else (CORS)
|
||||||
} else if (typeof content === "string") {
|
} else if (typeof content === "string") {
|
||||||
bodyEl = <HighlightCode value={ content } />
|
bodyEl = <HighlightCode value={ content } />
|
||||||
} else {
|
} else if ( content.size > 0 ) {
|
||||||
|
// We don't know the contentType, but there was some content returned
|
||||||
bodyEl = <div>Unknown response type</div>
|
bodyEl = <div>Unknown response type</div>
|
||||||
|
} else {
|
||||||
|
// We don't know the contentType and there was no content returned
|
||||||
|
bodyEl = null
|
||||||
}
|
}
|
||||||
|
|
||||||
return ( !bodyEl ? null : <div>
|
return ( !bodyEl ? null : <div>
|
||||||
|
|||||||
@@ -7,13 +7,16 @@ export default function downloadUrlPlugin (toolbox) {
|
|||||||
let { fn } = toolbox
|
let { fn } = toolbox
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
download: (url)=> ({ errActions, specSelectors, specActions }) => {
|
download: (url)=> ({ errActions, specSelectors, specActions, getConfigs }) => {
|
||||||
let { fetch } = fn
|
let { fetch } = fn
|
||||||
|
const config = getConfigs()
|
||||||
url = url || specSelectors.url()
|
url = url || specSelectors.url()
|
||||||
specActions.updateLoadingStatus("loading")
|
specActions.updateLoadingStatus("loading")
|
||||||
fetch({
|
fetch({
|
||||||
url,
|
url,
|
||||||
loadSpec: true,
|
loadSpec: true,
|
||||||
|
requestInterceptor: config.requestInterceptor || (a => a),
|
||||||
|
responseInterceptor: config.responseInterceptor || (a => a),
|
||||||
credentials: "same-origin",
|
credentials: "same-origin",
|
||||||
headers: {
|
headers: {
|
||||||
"Accept": "application/json,*/*"
|
"Accept": "application/json,*/*"
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
import ReactMarkdown from "react-markdown"
|
import ReactMarkdown from "react-markdown"
|
||||||
import { Parser, HtmlRenderer } from "commonmark"
|
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 }) => {
|
export const Markdown = ({ source }) => {
|
||||||
if ( source ) {
|
if ( source ) {
|
||||||
const parser = new Parser()
|
const parser = new Parser()
|
||||||
const writer = new HtmlRenderer()
|
const writer = new HtmlRenderer()
|
||||||
@@ -23,4 +24,9 @@ export default OAS3ComponentWrapFactory(({ source }) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
})
|
}
|
||||||
|
Markdown.propTypes = {
|
||||||
|
source: PropTypes.string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OAS3ComponentWrapFactory(Markdown)
|
||||||
@@ -543,14 +543,14 @@
|
|||||||
|
|
||||||
.response-col_description__inner
|
.response-col_description__inner
|
||||||
{
|
{
|
||||||
span
|
div.markdown, div.renderedMarkdown
|
||||||
{
|
{
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
|
||||||
display: block;
|
display: block;
|
||||||
|
|
||||||
margin: 10px 0;
|
margin: 0;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|||||||
48
test/components/markdown.js
Normal file
48
test/components/markdown.js
Normal file
@@ -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 = ``
|
||||||
|
const el = render(<Markdown source={str} />)
|
||||||
|
expect(el.html()).toEqual(`<div class="markdown"><p><img src="http://image.source" title="Image title"></p>\n</div>`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("allows heading elements", function() {
|
||||||
|
const str = `
|
||||||
|
# h1
|
||||||
|
## h2
|
||||||
|
### h3
|
||||||
|
#### h4
|
||||||
|
##### h5
|
||||||
|
###### h6`
|
||||||
|
const el = render(<Markdown source={str} />)
|
||||||
|
expect(el.html()).toEqual(`<div class="markdown"><h1>h1</h1>\n<h2>h2</h2>\n<h3>h3</h3>\n<h4>h4</h4>\n<h5>h5</h5>\n<h6>h6</h6>\n</div>`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("OAS 3", function() {
|
||||||
|
it("allows image elements", function() {
|
||||||
|
const str = ``
|
||||||
|
const el = render(<OAS3Markdown source={str} />)
|
||||||
|
expect(el.html()).toEqual(`<div class="renderedMarkdown"><div><p><img src="http://image.source" title="Image title"></p></div></div>`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("allows heading elements", function() {
|
||||||
|
const str = `
|
||||||
|
# h1
|
||||||
|
## h2
|
||||||
|
### h3
|
||||||
|
#### h4
|
||||||
|
##### h5
|
||||||
|
###### h6`
|
||||||
|
const el = render(<OAS3Markdown source={str} />)
|
||||||
|
expect(el.html()).toEqual(`<div class="renderedMarkdown"><div><h1>h1</h1>\n<h2>h2</h2>\n<h3>h3</h3>\n<h4>h4</h4>\n<h5>h5</h5>\n<h6>h6</h6></div></div>`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
33
test/xss/info-sanitization.js
Normal file
33
test/xss/info-sanitization.js
Normal file
@@ -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("<Info/> Sanitization", function(){
|
||||||
|
const dummyComponent = () => null
|
||||||
|
const components = {
|
||||||
|
Markdown
|
||||||
|
}
|
||||||
|
const props = {
|
||||||
|
getComponent: c => components[c] || dummyComponent,
|
||||||
|
info: fromJS({
|
||||||
|
title: "Test Title **strong** <script>alert(1)</script>",
|
||||||
|
description: "Description *with* <script>Markdown</script>"
|
||||||
|
}),
|
||||||
|
host: "example.test",
|
||||||
|
basePath: "/api"
|
||||||
|
}
|
||||||
|
|
||||||
|
it("renders sanitized .title content", function(){
|
||||||
|
let wrapper = render(<Info {...props}/>)
|
||||||
|
expect(wrapper.find(".title").html()).toEqual("Test Title **strong** <script>alert(1)</script>")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("renders sanitized .description content", function() {
|
||||||
|
let wrapper = render(<Info {...props}/>)
|
||||||
|
expect(wrapper.find(".description").html()).toEqual("<div class=\"markdown\"><p>Description <em>with</em> </p>\n</div>")
|
||||||
|
})
|
||||||
|
})
|
||||||
36
test/xss/markdown-script-sanitization.js
Normal file
36
test/xss/markdown-script-sanitization.js
Normal file
@@ -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 <script> elements", function() {
|
||||||
|
const str = `script <script>alert(1)</script>`
|
||||||
|
const el = render(<Markdown source={str} />)
|
||||||
|
expect(el.html()).toEqual(`<div class="markdown"><p>script </p>\n</div>`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("sanitizes <img> elements", function() {
|
||||||
|
const str = `<img src=x onerror="alert('img-in-description')">`
|
||||||
|
const el = render(<Markdown source={str} />)
|
||||||
|
expect(el.html()).toEqual(`<div class="markdown"><p><img src="x"></p>\n</div>`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("OAS 3", function() {
|
||||||
|
it("sanitizes <script> elements", function() {
|
||||||
|
const str = `script <script>alert(1)</script>`
|
||||||
|
const el = render(<OAS3Markdown source={str} />)
|
||||||
|
expect(el.html()).toEqual(`<div class="renderedMarkdown"><div><p>script </p></div></div>`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("sanitizes <img> elements", function() {
|
||||||
|
const str = `<img src=x onerror="alert('img-in-description')">`
|
||||||
|
const el = render(<OAS3Markdown source={str} />)
|
||||||
|
expect(el.html()).toEqual(`<div class="renderedMarkdown"><div><img src="x"></div></div>`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user