Merge branch 'master' into ft/oas3-authorization

This commit is contained in:
kyle
2017-10-20 19:07:38 -07:00
committed by GitHub
30 changed files with 379 additions and 255 deletions

View File

@@ -6,7 +6,7 @@
**This is the new version of swagger-ui, 3.x. Want to learn more? Check out our [FAQ](http://swagger.io/new-ui-faq/).** **This is the new version of swagger-ui, 3.x. Want to learn more? Check out our [FAQ](http://swagger.io/new-ui-faq/).**
**👉🏼 Want to score an easy open-source contribution?** Check out our [Good first contribution](https://github.com/swagger-api/swagger-ui/issues?q=is%3Aissue+is%3Aopen+label%3A%22Good+first+contribution%22) label. **👉🏼 Want to score an easy open-source contribution?** Check out our [Good first issue](https://github.com/swagger-api/swagger-ui/issues?q=is%3Aissue+is%3Aopen+label%3A%22Good+first+issue%22) label.
As a brand new version, written from the ground up, there are some known issues and unimplemented features. Check out the [Known Issues](#known-issues) section for more details. As a brand new version, written from the ground up, there are some known issues and unimplemented features. Check out the [Known Issues](#known-issues) section for more details.
@@ -22,7 +22,7 @@ The OpenAPI Specification has undergone 5 revisions since initial creation in 20
Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes
------------------ | ------------ | -------------------------- | ----- ------------------ | ------------ | -------------------------- | -----
3.3.1 | 2017-10-02 | 2.0, 3.0 | [tag v3.3.1](https://github.com/swagger-api/swagger-ui/tree/v3.3.1) 3.3.2 | 2017-10-13 | 2.0, 3.0 | [tag v3.3.2](https://github.com/swagger-api/swagger-ui/tree/v3.3.2)
3.0.21 | 2017-07-26 | 2.0 | [tag v3.0.21](https://github.com/swagger-api/swagger-ui/tree/v3.0.21) 3.0.21 | 2017-07-26 | 2.0 | [tag v3.0.21](https://github.com/swagger-api/swagger-ui/tree/v3.0.21)
2.2.10 | 2017-01-04 | 1.1, 1.2, 2.0 | [tag v2.2.10](https://github.com/swagger-api/swagger-ui/tree/v2.2.10) 2.2.10 | 2017-01-04 | 1.1, 1.2, 2.0 | [tag v2.2.10](https://github.com/swagger-api/swagger-ui/tree/v2.2.10)
2.1.5 | 2016-07-20 | 1.1, 1.2, 2.0 | [tag v2.1.5](https://github.com/swagger-api/swagger-ui/tree/v2.1.5) 2.1.5 | 2016-07-20 | 1.1, 1.2, 2.0 | [tag v2.1.5](https://github.com/swagger-api/swagger-ui/tree/v2.1.5)

View File

@@ -3,6 +3,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Swagger UI</title> <title>Swagger UI</title>
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700" rel="stylesheet"> <link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" > <link rel="stylesheet" type="text/css" href="./swagger-ui.css" >

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"version":3,"file":"swagger-ui-bundle.js","sources":["webpack:///swagger-ui-bundle.js"],"mappings":"AAAA;;;;;AAonMA;;;;;;AAm5DA;;;;;;;;;;;;;;;;;;;;;;;;;;AAukUA;;;;;;;;;;;;;;AAq4JA;AA4+iBA;;;;;;;;;AA8oIA;;;;;AA87QA;;;;;AAynBA;AAo0CA;;;;;;AA6gZA;;;;;;AAkzZA;AAixYA","sourceRoot":""} {"version":3,"file":"swagger-ui-bundle.js","sources":["webpack:///swagger-ui-bundle.js"],"mappings":"AAAA;;;;;AAsnMA;;;;;;AAm5DA;;;;;;;;;;;;;;;;;;;;;;;;;;AA0kUA;;;;;;;;;;;;;;AAq4JA;AA4/iBA;;;;;;;;;AA+vIA;;;;;AAk8QA;;;;;AAynBA;AAo0CA;;;;;;AAuqxBA;AAixYA;;;;;;AA6gbA","sourceRoot":""}

2
dist/swagger-ui.css vendored

File diff suppressed because one or more lines are too long

2
dist/swagger-ui.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"version":3,"file":"swagger-ui.js","sources":["webpack:///swagger-ui.js"],"mappings":"AAAA;;;;;;AA67eA","sourceRoot":""} {"version":3,"file":"swagger-ui.js","sources":["webpack:///swagger-ui.js"],"mappings":"AAAA;;;;;;AAs9eA","sourceRoot":""}

View File

@@ -137,7 +137,7 @@ module.exports = function(rules, options) {
} }
}, },
devtool: specialOptions.sourcemaps ? "cheap-module-source-map" : null, devtool: specialOptions.sourcemaps ? "nosource-source-map" : null,
plugins, plugins,

View File

@@ -1,6 +1,6 @@
{ {
"name": "swagger-ui", "name": "swagger-ui",
"version": "3.3.1", "version": "3.3.2",
"main": "dist/swagger-ui.js", "main": "dist/swagger-ui.js",
"repository": "git@github.com:swagger-api/swagger-ui.git", "repository": "git@github.com:swagger-api/swagger-ui.git",
"contributors": [ "contributors": [
@@ -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",
@@ -78,7 +78,7 @@
"scroll-to-element": "^2.0.0", "scroll-to-element": "^2.0.0",
"serialize-error": "2.0.0", "serialize-error": "2.0.0",
"shallowequal": "0.2.2", "shallowequal": "0.2.2",
"swagger-client": "^3.2.0", "swagger-client": "^3.2.2",
"url-parse": "^1.1.8", "url-parse": "^1.1.8",
"whatwg-fetch": "0.11.1", "whatwg-fetch": "0.11.1",
"worker-loader": "^0.7.1", "worker-loader": "^0.7.1",

View File

@@ -115,7 +115,7 @@ export default class ParameterRow extends Component {
required={ required } required={ required }
description={param.get("description") ? `${param.get("name")} - ${param.get("description")}` : `${param.get("name")}`} description={param.get("description") ? `${param.get("name")} - ${param.get("description")}` : `${param.get("name")}`}
onChange={ this.onChangeWrapper } onChange={ this.onChangeWrapper }
schema={ param }/> schema={ isOAS3 && isOAS3() ? param.get("schema") : param }/>
} }

View File

@@ -29,7 +29,11 @@ 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: {
...sanitize.defaults.allowedAttributes,
"img": sanitize.defaults.allowedAttributes.img.concat(["title"])
},
textFilter: function(text) { textFilter: function(text) {
return text.replace(/&quot;/g, "\"") return text.replace(/&quot;/g, "\"")
} }

View File

@@ -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>

View File

@@ -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,*/*"

View File

@@ -8,7 +8,7 @@ import { isOAS3 as isOAS3Helper } from "../helpers"
const state = state => state const state = state => state
function onlyOAS3(selector) { function onlyOAS3(selector) {
return (ori, system) => (...args) => { return (ori, system) => (state, ...args) => {
const spec = system.getSystem().specSelectors.specJson() const spec = system.getSystem().specSelectors.specJson()
if(isOAS3Helper(spec)) { if(isOAS3Helper(spec)) {
return selector(system, ...args) return selector(system, ...args)
@@ -57,4 +57,4 @@ export const definitionsToAuthorize = onlyOAS3(createSelector(
return list return list
} }
)) ))

View File

@@ -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)

View File

@@ -137,10 +137,13 @@ export function changeParam( path, paramName, paramIn, value, isXml ){
} }
} }
export function validateParams( payload ){ export const validateParams = ( payload, isOAS3 ) =>{
return { return {
type: VALIDATE_PARAMS, type: VALIDATE_PARAMS,
payload:{ pathMethod: payload } payload:{
pathMethod: payload,
isOAS3
}
} }
} }

View File

@@ -51,14 +51,14 @@ export default {
}) })
}, },
[VALIDATE_PARAMS]: ( state, { payload: { pathMethod } } ) => { [VALIDATE_PARAMS]: ( state, { payload: { pathMethod, isOAS3 } } ) => {
let operation = state.getIn( [ "resolved", "paths", ...pathMethod ] ) let operation = state.getIn( [ "resolved", "paths", ...pathMethod ] )
let isXml = /xml/i.test(operation.get("consumes_value")) let isXml = /xml/i.test(operation.get("consumes_value"))
return state.updateIn( [ "resolved", "paths", ...pathMethod, "parameters" ], fromJS([]), parameters => { return state.updateIn( [ "resolved", "paths", ...pathMethod, "parameters" ], fromJS([]), parameters => {
return parameters.withMutations( parameters => { return parameters.withMutations( parameters => {
for ( let i = 0, len = parameters.count(); i < len; i++ ) { for ( let i = 0, len = parameters.count(); i < len; i++ ) {
let errors = validateParam(parameters.get(i), isXml) let errors = validateParam(parameters.get(i), isXml, isOAS3)
parameters.setIn([i, "errors"], fromJS(errors)) parameters.setIn([i, "errors"], fromJS(errors))
} }
}) })

View File

@@ -13,3 +13,7 @@ export const executeRequest = (ori, { specActions }) => (req) => {
specActions.logRequest(req) specActions.logRequest(req)
return ori(req) return ori(req)
} }
export const validateParams = (ori, { specSelectors }) => (req) => {
return ori(req, specSelectors.isOAS3())
}

View File

@@ -537,16 +537,18 @@ export const validateMinLength = (val, min) => {
} }
// validation of parameters before execute // validation of parameters before execute
export const validateParam = (param, isXml) => { export const validateParam = (param, isXml, isOAS3 = false) => {
let errors = [] let errors = []
let value = isXml && param.get("in") === "body" ? param.get("value_xml") : param.get("value") let value = isXml && param.get("in") === "body" ? param.get("value_xml") : param.get("value")
let required = param.get("required") let required = param.get("required")
let maximum = param.get("maximum")
let minimum = param.get("minimum") let paramDetails = isOAS3 ? param.get("schema") : param
let type = param.get("type") let maximum = paramDetails.get("maximum")
let format = param.get("format") let minimum = paramDetails.get("minimum")
let maxLength = param.get("maxLength") let type = paramDetails.get("type")
let minLength = param.get("minLength") let format = paramDetails.get("format")
let maxLength = paramDetails.get("maxLength")
let minLength = paramDetails.get("minLength")
/* /*
If the parameter is required OR the parameter has a value (meaning optional, but filled in) If the parameter is required OR the parameter has a value (meaning optional, but filled in)
@@ -616,7 +618,7 @@ export const validateParam = (param, isXml) => {
if ( !value.count() ) { return errors } if ( !value.count() ) { return errors }
itemType = param.getIn(["items", "type"]) itemType = paramDetails.getIn(["items", "type"])
value.forEach((item, index) => { value.forEach((item, index) => {
let err let err

View File

@@ -30,6 +30,10 @@ select
.opblock-body select .opblock-body select
{ {
min-width: 230px; min-width: 230px;
@media (max-width: 768px)
{
min-width: 180px;
}
} }
label label
@@ -56,6 +60,10 @@ input[type=file]
border: 1px solid #d9d9d9; border: 1px solid #d9d9d9;
border-radius: 4px; border-radius: 4px;
background: #fff; background: #fff;
@media (max-width: 768px) {
max-width: 175px;
}
&.invalid &.invalid
{ {

View File

@@ -250,6 +250,10 @@
.opblock-summary-path__deprecated .opblock-summary-path__deprecated
{ {
font-size: 16px; font-size: 16px;
@media (max-width: 768px) {
font-size: 12px;
}
display: flex; display: flex;
flex: 0 3 auto; flex: 0 3 auto;
@@ -543,14 +547,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;
@@ -768,14 +772,6 @@
} }
} }
.renderedMarkdown {
p {
@include text_body();
margin-top: 0px;
margin-bottom: 0px;
}
}
.response-content-type { .response-content-type {
padding-top: 1em; padding-top: 1em;

View File

@@ -1,6 +1,6 @@
.topbar .topbar
{ {
padding: 8px 30px; padding: 8px 0;
background-color: #89bf04; background-color: #89bf04;
.topbar-wrapper .topbar-wrapper
@@ -39,7 +39,6 @@
input[type=text] input[type=text]
{ {
width: 100%; width: 100%;
min-width: 350px;
margin: 0; margin: 0;
border: 2px solid #547f00; border: 2px solid #547f00;
@@ -84,7 +83,7 @@
font-size: 16px; font-size: 16px;
font-weight: bold; font-weight: bold;
padding: 4px 40px; padding: 4px 30px;
border: none; border: none;
border-radius: 0 4px 4px 0; border-radius: 0 4px 4px 0;

View File

@@ -0,0 +1,54 @@
/* 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(<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>`)
})
it("allows links", function() {
const str = `[Link](https://example.com/)`
const el = render(<Markdown source={str} />)
expect(el.html()).toEqual(`<div class="markdown"><p><a href="https://example.com/" target="_blank">Link</a></p>\n</div>`)
})
})
describe("OAS 3", function() {
it("allows image elements", function() {
const str = `![Image alt text](http://image.source "Image title")`
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>`)
})
})
})

View File

@@ -277,461 +277,438 @@ describe("utils", function() {
let param = null let param = null
let result = null let result = null
it("skips validation when `type` is not specified", function() { const assertValidateParam = (param, expectedError) => {
// invalid type // Swagger 2.0 version
result = validateParam( fromJS(param), false )
expect( result ).toEqual( expectedError )
// OAS3 version, using `schema` sub-object
let oas3Param = {
value: param.value,
required: param.required,
schema: {
...param,
value: undefined,
required: undefined
}
}
result = validateParam( fromJS(oas3Param), false, true )
expect( result ).toEqual( expectedError )
}
it("should check the isOAS3 flag when validating parameters", function() {
// This should "skip" validation because there is no `schema.type` property
// and we are telling `validateParam` this is an OAS3 spec
param = fromJS({ param = fromJS({
required: false, value: "",
type: undefined, required: true,
value: "" schema: {
notTheTypeProperty: "string"
}
}) })
result = validateParam( param, false ) result = validateParam( param, false, true )
expect( result ).toEqual( [] ) expect( result ).toEqual( [] )
}) })
it("validates required strings", function() { it("validates required strings", function() {
// invalid string // invalid string
param = fromJS({ param = {
required: true, required: true,
type: "string", type: "string",
value: "" value: ""
}) }
result = validateParam( param, false ) assertValidateParam(param, ["Required field is not provided"])
expect( result ).toEqual( ["Required field is not provided"] )
// valid string // valid string
param = fromJS({ param = {
required: true, required: true,
type: "string", type: "string",
value: "test string" value: "test string"
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
// valid string with min and max length // valid string with min and max length
param = fromJS({ param = {
required: true, required: true,
type: "string", type: "string",
value: "test string", value: "test string",
maxLength: 50, maxLength: 50,
minLength: 1 minLength: 1
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
}) })
it("validates required strings with min and max length", function() { it("validates required strings with min and max length", function() {
// invalid string with max length // invalid string with max length
param = fromJS({ param = {
required: true, required: true,
type: "string", type: "string",
value: "test string", value: "test string",
maxLength: 5 maxLength: 5
}) }
result = validateParam( param, false ) assertValidateParam(param, ["Value must be less than MaxLength"])
expect( result ).toEqual( ["Value must be less than MaxLength"] )
// invalid string with max length 0 // invalid string with max length 0
param = fromJS({ param = {
required: true, required: true,
type: "string", type: "string",
value: "test string", value: "test string",
maxLength: 0 maxLength: 0
}) }
result = validateParam( param, false ) assertValidateParam(param, ["Value must be less than MaxLength"])
expect( result ).toEqual( ["Value must be less than MaxLength"] )
// invalid string with min length // invalid string with min length
param = fromJS({ param = {
required: true, required: true,
type: "string", type: "string",
value: "test string", value: "test string",
minLength: 50 minLength: 50
}) }
result = validateParam( param, false ) assertValidateParam(param, ["Value must be greater than MinLength"])
expect( result ).toEqual( ["Value must be greater than MinLength"] )
}) })
it("validates optional strings", function() { it("validates optional strings", function() {
// valid (empty) string // valid (empty) string
param = fromJS({ param = {
required: false, required: false,
type: "string", type: "string",
value: "" value: ""
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
// valid string // valid string
param = fromJS({ param = {
required: false, required: false,
type: "string", type: "string",
value: "test" value: "test"
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
}) })
it("validates required files", function() { it("validates required files", function() {
// invalid file // invalid file
param = fromJS({ param = {
required: true, required: true,
type: "file", type: "file",
value: undefined value: undefined
}) }
result = validateParam( param, false ) assertValidateParam(param, ["Required field is not provided"])
expect( result ).toEqual( ["Required field is not provided"] )
// valid file // valid file
param = fromJS({ param = {
required: true, required: true,
type: "file", type: "file",
value: new win.File() value: new win.File()
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
}) })
it("validates optional files", function() { it("validates optional files", function() {
// invalid file // invalid file
param = fromJS({ param = {
required: false, required: false,
type: "file", type: "file",
value: "not a file" value: "not a file"
}) }
result = validateParam( param, false ) assertValidateParam(param, ["Value must be a file"])
expect( result ).toEqual( ["Value must be a file"] )
// valid (empty) file // valid (empty) file
param = fromJS({ param = {
required: false, required: false,
type: "file", type: "file",
value: undefined value: undefined
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
// valid file // valid file
param = fromJS({ param = {
required: false, required: false,
type: "file", type: "file",
value: new win.File() value: new win.File()
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
}) })
it("validates required arrays", function() { it("validates required arrays", function() {
// invalid (empty) array // invalid (empty) array
param = fromJS({ param = {
required: true, required: true,
type: "array", type: "array",
value: [] value: []
}) }
result = validateParam( param, false ) assertValidateParam(param, ["Required field is not provided"])
expect( result ).toEqual( ["Required field is not provided"] )
// invalid (not an array) // invalid (not an array)
param = fromJS({ param = {
required: true, required: true,
type: "array", type: "array",
value: undefined value: undefined
}) }
result = validateParam( param, false ) assertValidateParam(param, ["Required field is not provided"])
expect( result ).toEqual( ["Required field is not provided"] )
// invalid array, items do not match correct type // invalid array, items do not match correct type
param = fromJS({ param = {
required: true, required: true,
type: "array", type: "array",
value: [1], value: [1],
items: { items: {
type: "string" type: "string"
} }
}) }
result = validateParam( param, false ) assertValidateParam(param, [{index: 0, error: "Value must be a string"}])
expect( result ).toEqual( [{index: 0, error: "Value must be a string"}] )
// valid array, with no 'type' for items // valid array, with no 'type' for items
param = fromJS({ param = {
required: true, required: true,
type: "array", type: "array",
value: ["1"] value: ["1"]
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
// valid array, items match type // valid array, items match type
param = fromJS({ param = {
required: true, required: true,
type: "array", type: "array",
value: ["1"], value: ["1"],
items: { items: {
type: "string" type: "string"
} }
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
}) })
it("validates optional arrays", function() { it("validates optional arrays", function() {
// valid, empty array // valid, empty array
param = fromJS({ param = {
required: false, required: false,
type: "array", type: "array",
value: [] value: []
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
// invalid, items do not match correct type // invalid, items do not match correct type
param = fromJS({ param = {
required: false, required: false,
type: "array", type: "array",
value: ["number"], value: ["number"],
items: { items: {
type: "number" type: "number"
} }
}) }
result = validateParam( param, false ) assertValidateParam(param, [{index: 0, error: "Value must be a number"}])
expect( result ).toEqual( [{index: 0, error: "Value must be a number"}] )
// valid // valid
param = fromJS({ param = {
required: false, required: false,
type: "array", type: "array",
value: ["test"], value: ["test"],
items: { items: {
type: "string" type: "string"
} }
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
}) })
it("validates required booleans", function() { it("validates required booleans", function() {
// invalid boolean value // invalid boolean value
param = fromJS({ param = {
required: true, required: true,
type: "boolean", type: "boolean",
value: undefined value: undefined
}) }
result = validateParam( param, false ) assertValidateParam(param, ["Required field is not provided"])
expect( result ).toEqual( ["Required field is not provided"] )
// invalid boolean value (not a boolean) // invalid boolean value (not a boolean)
param = fromJS({ param = {
required: true, required: true,
type: "boolean", type: "boolean",
value: "test string" value: "test string"
}) }
result = validateParam( param, false ) assertValidateParam(param, ["Required field is not provided"])
expect( result ).toEqual( ["Required field is not provided"] )
// valid boolean value // valid boolean value
param = fromJS({ param = {
required: true, required: true,
type: "boolean", type: "boolean",
value: "true" value: "true"
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
// valid boolean value // valid boolean value
param = fromJS({ param = {
required: true, required: true,
type: "boolean", type: "boolean",
value: false value: false
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
}) })
it("validates optional booleans", function() { it("validates optional booleans", function() {
// valid (empty) boolean value // valid (empty) boolean value
param = fromJS({ param = {
required: false, required: false,
type: "boolean", type: "boolean",
value: undefined value: undefined
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
// invalid boolean value (not a boolean) // invalid boolean value (not a boolean)
param = fromJS({ param = {
required: false, required: false,
type: "boolean", type: "boolean",
value: "test string" value: "test string"
}) }
result = validateParam( param, false ) assertValidateParam(param, ["Value must be a boolean"])
expect( result ).toEqual( ["Value must be a boolean"] )
// valid boolean value // valid boolean value
param = fromJS({ param = {
required: false, required: false,
type: "boolean", type: "boolean",
value: "true" value: "true"
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
// valid boolean value // valid boolean value
param = fromJS({ param = {
required: false, required: false,
type: "boolean", type: "boolean",
value: false value: false
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
}) })
it("validates required numbers", function() { it("validates required numbers", function() {
// invalid number, string instead of a number // invalid number, string instead of a number
param = fromJS({ param = {
required: true, required: true,
type: "number", type: "number",
value: "test" value: "test"
}) }
result = validateParam( param, false ) assertValidateParam(param, ["Required field is not provided"])
expect( result ).toEqual( ["Required field is not provided"] )
// invalid number, undefined value // invalid number, undefined value
param = fromJS({ param = {
required: true, required: true,
type: "number", type: "number",
value: undefined value: undefined
}) }
result = validateParam( param, false ) assertValidateParam(param, ["Required field is not provided"])
expect( result ).toEqual( ["Required field is not provided"] )
// valid number with min and max // valid number with min and max
param = fromJS({ param = {
required: true, required: true,
type: "number", type: "number",
value: 10, value: 10,
minimum: 5, minimum: 5,
maximum: 99 maximum: 99
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
// valid negative number with min and max // valid negative number with min and max
param = fromJS({ param = {
required: true, required: true,
type: "number", type: "number",
value: -10, value: -10,
minimum: -50, minimum: -50,
maximum: -5 maximum: -5
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
// invalid number with maximum:0 // invalid number with maximum:0
param = fromJS({ param = {
required: true, required: true,
type: "number", type: "number",
value: 1, value: 1,
maximum: 0 maximum: 0
}) }
result = validateParam( param, false ) assertValidateParam(param, ["Value must be less than Maximum"])
expect( result ).toEqual( ["Value must be less than Maximum"] )
// invalid number with minimum:0 // invalid number with minimum:0
param = fromJS({ param = {
required: true, required: true,
type: "number", type: "number",
value: -10, value: -10,
minimum: 0 minimum: 0
}) }
result = validateParam( param, false ) assertValidateParam(param, ["Value must be greater than Minimum"])
expect( result ).toEqual( ["Value must be greater than Minimum"] )
}) })
it("validates optional numbers", function() { it("validates optional numbers", function() {
// invalid number, string instead of a number // invalid number, string instead of a number
param = fromJS({ param = {
required: false, required: false,
type: "number", type: "number",
value: "test" value: "test"
}) }
result = validateParam( param, false ) assertValidateParam(param, ["Value must be a number"])
expect( result ).toEqual( ["Value must be a number"] )
// valid (empty) number // valid (empty) number
param = fromJS({ param = {
required: false, required: false,
type: "number", type: "number",
value: undefined value: undefined
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
// valid number // valid number
param = fromJS({ param = {
required: false, required: false,
type: "number", type: "number",
value: 10 value: 10
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
}) })
it("validates required integers", function() { it("validates required integers", function() {
// invalid integer, string instead of an integer // invalid integer, string instead of an integer
param = fromJS({ param = {
required: true, required: true,
type: "integer", type: "integer",
value: "test" value: "test"
}) }
result = validateParam( param, false ) assertValidateParam(param, ["Required field is not provided"])
expect( result ).toEqual( ["Required field is not provided"] )
// invalid integer, undefined value // invalid integer, undefined value
param = fromJS({ param = {
required: true, required: true,
type: "integer", type: "integer",
value: undefined value: undefined
}) }
result = validateParam( param, false ) assertValidateParam(param, ["Required field is not provided"])
expect( result ).toEqual( ["Required field is not provided"] )
// valid integer // valid integer
param = fromJS({ param = {
required: true, required: true,
type: "integer", type: "integer",
value: 10 value: 10
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
}) })
it("validates optional integers", function() { it("validates optional integers", function() {
// invalid integer, string instead of an integer // invalid integer, string instead of an integer
param = fromJS({ param = {
required: false, required: false,
type: "integer", type: "integer",
value: "test" value: "test"
}) }
result = validateParam( param, false ) assertValidateParam(param, ["Value must be an integer"])
expect( result ).toEqual( ["Value must be an integer"] )
// valid (empty) integer // valid (empty) integer
param = fromJS({ param = {
required: false, required: false,
type: "integer", type: "integer",
value: undefined value: undefined
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
// integers // integers
param = fromJS({ param = {
required: false, required: false,
type: "integer", type: "integer",
value: 10 value: 10
}) }
result = validateParam( param, false ) assertValidateParam(param, [])
expect( result ).toEqual( [] )
}) })
}) })

View 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** &lt;script&gt;alert(1)&lt;/script&gt;")
})
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>")
})
})

View 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>`)
})
})
})

View File

@@ -11,7 +11,7 @@ let rules = [
name: "[name].js" name: "[name].js"
} }
}, },
{ loader: "babel-loader" } { loader: "babel-loader?retainLines=true" }
] ]
} }
] ]

View File

@@ -11,7 +11,7 @@ let rules = [
name: "[name].js" name: "[name].js"
} }
}, },
{ loader: "babel-loader" } { loader: "babel-loader?retainLines=true" }
] ]
} }
] ]

View File

@@ -13,7 +13,7 @@ let rules = [
name: "[name].js" name: "[name].js"
} }
}, },
{ loader: "babel-loader" } { loader: "babel-loader?retainLines=true" }
] ]
} }
] ]

View File

@@ -9,13 +9,7 @@ const rules = [
inline: true inline: true
} }
}, },
{ loader: "babel-loader" } { loader: "babel-loader?retainLines=true" }
]
},
{ test: /\.(jsx)(\?.*)?$/,
use: [
{ loader: "react-hot-loader" },
{ loader: "babel-loader" }
] ]
}, },
{ test: /\.(css)(\?.*)?$/, { test: /\.(css)(\?.*)?$/,
@@ -48,7 +42,7 @@ module.exports = require("./make-webpack-config")(rules, {
_special: { _special: {
separateStylesheets: false, separateStylesheets: false,
}, },
devtool: "eval", devtool: "eval-source-map",
entry: { entry: {
"swagger-ui-bundle": [ "swagger-ui-bundle": [
"./src/polyfills", "./src/polyfills",