@@ -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/).** | |||
**👉🏼 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. | |||
@@ -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 | |||
------------------ | ------------ | -------------------------- | ----- | |||
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) | |||
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) | |||
@@ -3,6 +3,7 @@ | |||
<html lang="en"> | |||
<head> | |||
<meta charset="UTF-8"> | |||
<meta name="viewport" content="width=device-width, initial-scale=1"> | |||
<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 rel="stylesheet" type="text/css" href="./swagger-ui.css" > | |||
@@ -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":""} |
@@ -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":""} |
@@ -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, | |||
@@ -1,6 +1,6 @@ | |||
{ | |||
"name": "swagger-ui", | |||
"version": "3.3.1", | |||
"version": "3.3.2", | |||
"main": "dist/swagger-ui.js", | |||
"repository": "git@github.com:swagger-api/swagger-ui.git", | |||
"contributors": [ | |||
@@ -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", | |||
@@ -78,7 +78,7 @@ | |||
"scroll-to-element": "^2.0.0", | |||
"serialize-error": "2.0.0", | |||
"shallowequal": "0.2.2", | |||
"swagger-client": "^3.2.0", | |||
"swagger-client": "^3.2.2", | |||
"url-parse": "^1.1.8", | |||
"whatwg-fetch": "0.11.1", | |||
"worker-loader": "^0.7.1", | |||
@@ -115,7 +115,7 @@ export default class ParameterRow extends Component { | |||
required={ required } | |||
description={param.get("description") ? `${param.get("name")} - ${param.get("description")}` : `${param.get("name")}`} | |||
onChange={ this.onChangeWrapper } | |||
schema={ param }/> | |||
schema={ isOAS3 && isOAS3() ? param.get("schema") : param }/> | |||
} | |||
@@ -29,7 +29,11 @@ Markdown.propTypes = { | |||
export default Markdown | |||
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) { | |||
return text.replace(/"/g, "\"") | |||
} | |||
@@ -83,8 +83,12 @@ export default class ResponseBody extends React.Component { | |||
// Anything else (CORS) | |||
} else if (typeof content === "string") { | |||
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> | |||
} else { | |||
// We don't know the contentType and there was no content returned | |||
bodyEl = null | |||
} | |||
return ( !bodyEl ? null : <div> | |||
@@ -7,13 +7,16 @@ export default function downloadUrlPlugin (toolbox) { | |||
let { fn } = toolbox | |||
const actions = { | |||
download: (url)=> ({ errActions, specSelectors, specActions }) => { | |||
download: (url)=> ({ errActions, specSelectors, specActions, getConfigs }) => { | |||
let { fetch } = fn | |||
const config = getConfigs() | |||
url = url || specSelectors.url() | |||
specActions.updateLoadingStatus("loading") | |||
fetch({ | |||
url, | |||
loadSpec: true, | |||
requestInterceptor: config.requestInterceptor || (a => a), | |||
responseInterceptor: config.responseInterceptor || (a => a), | |||
credentials: "same-origin", | |||
headers: { | |||
"Accept": "application/json,*/*" | |||
@@ -8,7 +8,7 @@ import { isOAS3 as isOAS3Helper } from "../helpers" | |||
const state = state => state | |||
function onlyOAS3(selector) { | |||
return (ori, system) => (...args) => { | |||
return (ori, system) => (state, ...args) => { | |||
const spec = system.getSystem().specSelectors.specJson() | |||
if(isOAS3Helper(spec)) { | |||
return selector(system, ...args) | |||
@@ -57,4 +57,4 @@ export const definitionsToAuthorize = onlyOAS3(createSelector( | |||
return list | |||
} | |||
)) | |||
)) |
@@ -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 | |||
}) | |||
} | |||
Markdown.propTypes = { | |||
source: PropTypes.string | |||
} | |||
export default OAS3ComponentWrapFactory(Markdown) |
@@ -137,10 +137,13 @@ export function changeParam( path, paramName, paramIn, value, isXml ){ | |||
} | |||
} | |||
export function validateParams( payload ){ | |||
export const validateParams = ( payload, isOAS3 ) =>{ | |||
return { | |||
type: VALIDATE_PARAMS, | |||
payload:{ pathMethod: payload } | |||
payload:{ | |||
pathMethod: payload, | |||
isOAS3 | |||
} | |||
} | |||
} | |||
@@ -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 isXml = /xml/i.test(operation.get("consumes_value")) | |||
return state.updateIn( [ "resolved", "paths", ...pathMethod, "parameters" ], fromJS([]), parameters => { | |||
return parameters.withMutations( parameters => { | |||
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)) | |||
} | |||
}) | |||
@@ -13,3 +13,7 @@ export const executeRequest = (ori, { specActions }) => (req) => { | |||
specActions.logRequest(req) | |||
return ori(req) | |||
} | |||
export const validateParams = (ori, { specSelectors }) => (req) => { | |||
return ori(req, specSelectors.isOAS3()) | |||
} |
@@ -537,16 +537,18 @@ export const validateMinLength = (val, min) => { | |||
} | |||
// validation of parameters before execute | |||
export const validateParam = (param, isXml) => { | |||
export const validateParam = (param, isXml, isOAS3 = false) => { | |||
let errors = [] | |||
let value = isXml && param.get("in") === "body" ? param.get("value_xml") : param.get("value") | |||
let required = param.get("required") | |||
let maximum = param.get("maximum") | |||
let minimum = param.get("minimum") | |||
let type = param.get("type") | |||
let format = param.get("format") | |||
let maxLength = param.get("maxLength") | |||
let minLength = param.get("minLength") | |||
let paramDetails = isOAS3 ? param.get("schema") : param | |||
let maximum = paramDetails.get("maximum") | |||
let minimum = paramDetails.get("minimum") | |||
let type = paramDetails.get("type") | |||
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) | |||
@@ -616,7 +618,7 @@ export const validateParam = (param, isXml) => { | |||
if ( !value.count() ) { return errors } | |||
itemType = param.getIn(["items", "type"]) | |||
itemType = paramDetails.getIn(["items", "type"]) | |||
value.forEach((item, index) => { | |||
let err | |||
@@ -30,6 +30,10 @@ select | |||
.opblock-body select | |||
{ | |||
min-width: 230px; | |||
@media (max-width: 768px) | |||
{ | |||
min-width: 180px; | |||
} | |||
} | |||
label | |||
@@ -56,6 +60,10 @@ input[type=file] | |||
border: 1px solid #d9d9d9; | |||
border-radius: 4px; | |||
background: #fff; | |||
@media (max-width: 768px) { | |||
max-width: 175px; | |||
} | |||
&.invalid | |||
{ | |||
@@ -250,6 +250,10 @@ | |||
.opblock-summary-path__deprecated | |||
{ | |||
font-size: 16px; | |||
@media (max-width: 768px) { | |||
font-size: 12px; | |||
} | |||
display: flex; | |||
flex: 0 3 auto; | |||
@@ -543,14 +547,14 @@ | |||
.response-col_description__inner | |||
{ | |||
span | |||
div.markdown, div.renderedMarkdown | |||
{ | |||
font-size: 12px; | |||
font-style: italic; | |||
display: block; | |||
margin: 10px 0; | |||
margin: 0; | |||
padding: 10px; | |||
border-radius: 4px; | |||
@@ -768,14 +772,6 @@ | |||
} | |||
} | |||
.renderedMarkdown { | |||
p { | |||
@include text_body(); | |||
margin-top: 0px; | |||
margin-bottom: 0px; | |||
} | |||
} | |||
.response-content-type { | |||
padding-top: 1em; | |||
@@ -1,6 +1,6 @@ | |||
.topbar | |||
{ | |||
padding: 8px 30px; | |||
padding: 8px 0; | |||
background-color: #89bf04; | |||
.topbar-wrapper | |||
@@ -39,7 +39,6 @@ | |||
input[type=text] | |||
{ | |||
width: 100%; | |||
min-width: 350px; | |||
margin: 0; | |||
border: 2px solid #547f00; | |||
@@ -84,7 +83,7 @@ | |||
font-size: 16px; | |||
font-weight: bold; | |||
padding: 4px 40px; | |||
padding: 4px 30px; | |||
border: none; | |||
border-radius: 0 4px 4px 0; | |||
@@ -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>`) | |||
}) | |||
}) | |||
}) |
@@ -277,461 +277,438 @@ describe("utils", function() { | |||
let param = null | |||
let result = null | |||
it("skips validation when `type` is not specified", function() { | |||
// invalid type | |||
const assertValidateParam = (param, expectedError) => { | |||
// 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({ | |||
required: false, | |||
type: undefined, | |||
value: "" | |||
value: "", | |||
required: true, | |||
schema: { | |||
notTheTypeProperty: "string" | |||
} | |||
}) | |||
result = validateParam( param, false ) | |||
result = validateParam( param, false, true ) | |||
expect( result ).toEqual( [] ) | |||
}) | |||
it("validates required strings", function() { | |||
// invalid string | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "string", | |||
value: "" | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( ["Required field is not provided"] ) | |||
} | |||
assertValidateParam(param, ["Required field is not provided"]) | |||
// valid string | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "string", | |||
value: "test string" | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
// valid string with min and max length | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "string", | |||
value: "test string", | |||
maxLength: 50, | |||
minLength: 1 | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
}) | |||
it("validates required strings with min and max length", function() { | |||
// invalid string with max length | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "string", | |||
value: "test string", | |||
maxLength: 5 | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( ["Value must be less than MaxLength"] ) | |||
} | |||
assertValidateParam(param, ["Value must be less than MaxLength"]) | |||
// invalid string with max length 0 | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "string", | |||
value: "test string", | |||
maxLength: 0 | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( ["Value must be less than MaxLength"] ) | |||
} | |||
assertValidateParam(param, ["Value must be less than MaxLength"]) | |||
// invalid string with min length | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "string", | |||
value: "test string", | |||
minLength: 50 | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( ["Value must be greater than MinLength"] ) | |||
} | |||
assertValidateParam(param, ["Value must be greater than MinLength"]) | |||
}) | |||
it("validates optional strings", function() { | |||
// valid (empty) string | |||
param = fromJS({ | |||
param = { | |||
required: false, | |||
type: "string", | |||
value: "" | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
// valid string | |||
param = fromJS({ | |||
param = { | |||
required: false, | |||
type: "string", | |||
value: "test" | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
}) | |||
it("validates required files", function() { | |||
// invalid file | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "file", | |||
value: undefined | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( ["Required field is not provided"] ) | |||
} | |||
assertValidateParam(param, ["Required field is not provided"]) | |||
// valid file | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "file", | |||
value: new win.File() | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
}) | |||
it("validates optional files", function() { | |||
// invalid file | |||
param = fromJS({ | |||
param = { | |||
required: false, | |||
type: "file", | |||
value: "not a file" | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( ["Value must be a file"] ) | |||
} | |||
assertValidateParam(param, ["Value must be a file"]) | |||
// valid (empty) file | |||
param = fromJS({ | |||
param = { | |||
required: false, | |||
type: "file", | |||
value: undefined | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
// valid file | |||
param = fromJS({ | |||
param = { | |||
required: false, | |||
type: "file", | |||
value: new win.File() | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
}) | |||
it("validates required arrays", function() { | |||
// invalid (empty) array | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "array", | |||
value: [] | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( ["Required field is not provided"] ) | |||
} | |||
assertValidateParam(param, ["Required field is not provided"]) | |||
// invalid (not an array) | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "array", | |||
value: undefined | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( ["Required field is not provided"] ) | |||
} | |||
assertValidateParam(param, ["Required field is not provided"]) | |||
// invalid array, items do not match correct type | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "array", | |||
value: [1], | |||
items: { | |||
type: "string" | |||
} | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [{index: 0, error: "Value must be a string"}] ) | |||
} | |||
assertValidateParam(param, [{index: 0, error: "Value must be a string"}]) | |||
// valid array, with no 'type' for items | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "array", | |||
value: ["1"] | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
// valid array, items match type | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "array", | |||
value: ["1"], | |||
items: { | |||
type: "string" | |||
} | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
}) | |||
it("validates optional arrays", function() { | |||
// valid, empty array | |||
param = fromJS({ | |||
param = { | |||
required: false, | |||
type: "array", | |||
value: [] | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
// invalid, items do not match correct type | |||
param = fromJS({ | |||
param = { | |||
required: false, | |||
type: "array", | |||
value: ["number"], | |||
items: { | |||
type: "number" | |||
} | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [{index: 0, error: "Value must be a number"}] ) | |||
} | |||
assertValidateParam(param, [{index: 0, error: "Value must be a number"}]) | |||
// valid | |||
param = fromJS({ | |||
param = { | |||
required: false, | |||
type: "array", | |||
value: ["test"], | |||
items: { | |||
type: "string" | |||
} | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
}) | |||
it("validates required booleans", function() { | |||
// invalid boolean value | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "boolean", | |||
value: undefined | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( ["Required field is not provided"] ) | |||
} | |||
assertValidateParam(param, ["Required field is not provided"]) | |||
// invalid boolean value (not a boolean) | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "boolean", | |||
value: "test string" | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( ["Required field is not provided"] ) | |||
} | |||
assertValidateParam(param, ["Required field is not provided"]) | |||
// valid boolean value | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "boolean", | |||
value: "true" | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
// valid boolean value | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "boolean", | |||
value: false | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
}) | |||
it("validates optional booleans", function() { | |||
// valid (empty) boolean value | |||
param = fromJS({ | |||
param = { | |||
required: false, | |||
type: "boolean", | |||
value: undefined | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
// invalid boolean value (not a boolean) | |||
param = fromJS({ | |||
param = { | |||
required: false, | |||
type: "boolean", | |||
value: "test string" | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( ["Value must be a boolean"] ) | |||
} | |||
assertValidateParam(param, ["Value must be a boolean"]) | |||
// valid boolean value | |||
param = fromJS({ | |||
param = { | |||
required: false, | |||
type: "boolean", | |||
value: "true" | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
// valid boolean value | |||
param = fromJS({ | |||
param = { | |||
required: false, | |||
type: "boolean", | |||
value: false | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
}) | |||
it("validates required numbers", function() { | |||
// invalid number, string instead of a number | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "number", | |||
value: "test" | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( ["Required field is not provided"] ) | |||
} | |||
assertValidateParam(param, ["Required field is not provided"]) | |||
// invalid number, undefined value | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "number", | |||
value: undefined | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( ["Required field is not provided"] ) | |||
} | |||
assertValidateParam(param, ["Required field is not provided"]) | |||
// valid number with min and max | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "number", | |||
value: 10, | |||
minimum: 5, | |||
maximum: 99 | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
// valid negative number with min and max | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "number", | |||
value: -10, | |||
minimum: -50, | |||
maximum: -5 | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
// invalid number with maximum:0 | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "number", | |||
value: 1, | |||
maximum: 0 | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( ["Value must be less than Maximum"] ) | |||
} | |||
assertValidateParam(param, ["Value must be less than Maximum"]) | |||
// invalid number with minimum:0 | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "number", | |||
value: -10, | |||
minimum: 0 | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( ["Value must be greater than Minimum"] ) | |||
} | |||
assertValidateParam(param, ["Value must be greater than Minimum"]) | |||
}) | |||
it("validates optional numbers", function() { | |||
// invalid number, string instead of a number | |||
param = fromJS({ | |||
param = { | |||
required: false, | |||
type: "number", | |||
value: "test" | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( ["Value must be a number"] ) | |||
} | |||
assertValidateParam(param, ["Value must be a number"]) | |||
// valid (empty) number | |||
param = fromJS({ | |||
param = { | |||
required: false, | |||
type: "number", | |||
value: undefined | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
// valid number | |||
param = fromJS({ | |||
param = { | |||
required: false, | |||
type: "number", | |||
value: 10 | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
}) | |||
it("validates required integers", function() { | |||
// invalid integer, string instead of an integer | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "integer", | |||
value: "test" | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( ["Required field is not provided"] ) | |||
} | |||
assertValidateParam(param, ["Required field is not provided"]) | |||
// invalid integer, undefined value | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "integer", | |||
value: undefined | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( ["Required field is not provided"] ) | |||
} | |||
assertValidateParam(param, ["Required field is not provided"]) | |||
// valid integer | |||
param = fromJS({ | |||
param = { | |||
required: true, | |||
type: "integer", | |||
value: 10 | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
}) | |||
it("validates optional integers", function() { | |||
// invalid integer, string instead of an integer | |||
param = fromJS({ | |||
param = { | |||
required: false, | |||
type: "integer", | |||
value: "test" | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( ["Value must be an integer"] ) | |||
} | |||
assertValidateParam(param, ["Value must be an integer"]) | |||
// valid (empty) integer | |||
param = fromJS({ | |||
param = { | |||
required: false, | |||
type: "integer", | |||
value: undefined | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
// integers | |||
param = fromJS({ | |||
param = { | |||
required: false, | |||
type: "integer", | |||
value: 10 | |||
}) | |||
result = validateParam( param, false ) | |||
expect( result ).toEqual( [] ) | |||
} | |||
assertValidateParam(param, []) | |||
}) | |||
}) | |||
@@ -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>") | |||
}) | |||
}) |
@@ -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>`) | |||
}) | |||
}) | |||
}) |
@@ -11,7 +11,7 @@ let rules = [ | |||
name: "[name].js" | |||
} | |||
}, | |||
{ loader: "babel-loader" } | |||
{ loader: "babel-loader?retainLines=true" } | |||
] | |||
} | |||
] | |||
@@ -11,7 +11,7 @@ let rules = [ | |||
name: "[name].js" | |||
} | |||
}, | |||
{ loader: "babel-loader" } | |||
{ loader: "babel-loader?retainLines=true" } | |||
] | |||
} | |||
] | |||
@@ -13,7 +13,7 @@ let rules = [ | |||
name: "[name].js" | |||
} | |||
}, | |||
{ loader: "babel-loader" } | |||
{ loader: "babel-loader?retainLines=true" } | |||
] | |||
} | |||
] | |||
@@ -9,13 +9,7 @@ const rules = [ | |||
inline: true | |||
} | |||
}, | |||
{ loader: "babel-loader" } | |||
] | |||
}, | |||
{ test: /\.(jsx)(\?.*)?$/, | |||
use: [ | |||
{ loader: "react-hot-loader" }, | |||
{ loader: "babel-loader" } | |||
{ loader: "babel-loader?retainLines=true" } | |||
] | |||
}, | |||
{ test: /\.(css)(\?.*)?$/, | |||
@@ -48,7 +42,7 @@ module.exports = require("./make-webpack-config")(rules, { | |||
_special: { | |||
separateStylesheets: false, | |||
}, | |||
devtool: "eval", | |||
devtool: "eval-source-map", | |||
entry: { | |||
"swagger-ui-bundle": [ | |||
"./src/polyfills", | |||