Merge branch 'master' into ft/react_15_6_2

This commit is contained in:
kyle
2017-11-02 09:37:42 -07:00
committed by GitHub
24 changed files with 172 additions and 50 deletions

View File

@@ -1,6 +1,9 @@
<!--- <!---
Thanks for filing an issue 😄 ! Before you submit, please read the following: Thanks for filing an issue 😄 ! Before you submit, please read the following:
If you're here to report a security issue, please STOP writing an issue and contact us
at security@swagger.io instead!
Search open/closed issues before submitting since someone might have asked the same thing before! Search open/closed issues before submitting since someone might have asked the same thing before!
Issues on GitHub are only related to problems of Swagger-UI itself. We'll try to offer support Issues on GitHub are only related to problems of Swagger-UI itself. We'll try to offer support

42
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,42 @@
<!--- Provide a general summary of your changes in the Title above -->
### Description
<!--- Describe your changes in detail -->
### Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->
<!--- Use the magic "Fixes #1234" format, so the issues are -->
<!--- automatically closed when this PR is merged. -->
### How Has This Been Tested?
<!--- Please describe in detail how you manually tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->
### Screenshots (if appropriate):
### Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] No code changes (changes to documentation, CI, metadata, etc)
- [ ] Dependency changes (any modification to dependencies in `package.json`)
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
### Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [ ] I have added tests to cover my changes.
- [ ] All new and existing tests passed.

View File

@@ -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.4.0 | 2017-10-20 | 2.0, 3.0 | [tag v3.4.0](https://github.com/swagger-api/swagger-ui/tree/v3.4.0) 3.4.2 | 2017-10-30 | 2.0, 3.0 | [tag v3.4.2](https://github.com/swagger-api/swagger-ui/tree/v3.4.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)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
dist/swagger-ui.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -32,7 +32,7 @@ fi
if [[ -f $SWAGGER_JSON ]]; then if [[ -f $SWAGGER_JSON ]]; then
cp $SWAGGER_JSON $NGINX_ROOT cp $SWAGGER_JSON $NGINX_ROOT
REL_PATH="/$(basename $SWAGGER_JSON)" REL_PATH="./$(basename $SWAGGER_JSON)"
sed -i "s|http://petstore.swagger.io/v2/swagger.json|$REL_PATH|g" $INDEX_FILE sed -i "s|http://petstore.swagger.io/v2/swagger.json|$REL_PATH|g" $INDEX_FILE
sed -i "s|http://example.com/api|$REL_PATH|g" $INDEX_FILE sed -i "s|http://example.com/api|$REL_PATH|g" $INDEX_FILE
else else

View File

@@ -20,8 +20,8 @@ Some distinct identifiers to Swagger-UI 3.X:
If you've determined this is the version you have, to find the exact version: If you've determined this is the version you have, to find the exact version:
- Open your browser's web console (changes between browsers) - Open your browser's web console (changes between browsers)
- Type `versions` in the console and execute the call. - Type `JSON.stringify(versions)` in the console and execute the call.
- You might need to expand the result, until you get a string similar to `swaggerUi : Object { version: "3.1.6", gitRevision: "g786cd47", gitDirty: true, … }`. - The result should look similar to `swaggerUi : Object { version: "3.1.6", gitRevision: "g786cd47", gitDirty: true, … }`.
- The version taken from that example would be `3.1.6`. - The version taken from that example would be `3.1.6`.
Note: This functionality was added in 3.0.8. If you're unable to execute it, you're likely to use an older version, and in that case the first step would be to upgrade. Note: This functionality was added in 3.0.8. If you're unable to execute it, you're likely to use an older version, and in that case the first step would be to upgrade.
@@ -51,4 +51,4 @@ If you've determined this is the version you have, to find the exact version:
* @link http://swagger.io * @link http://swagger.io
* @license Apache-2.0 * @license Apache-2.0
*/ */
``` ```

View File

@@ -1,6 +1,6 @@
{ {
"name": "swagger-ui", "name": "swagger-ui",
"version": "3.4.0", "version": "3.4.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": [
@@ -39,6 +39,7 @@
"e2e": "npm-run-all --parallel -r hot-server mock-api test-e2e" "e2e": "npm-run-all --parallel -r hot-server mock-api test-e2e"
}, },
"dependencies": { "dependencies": {
"@braintree/sanitize-url": "^2.0.2",
"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",
@@ -78,7 +79,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.3.0", "swagger-client": "^3.3.1",
"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

@@ -2,6 +2,7 @@ import React from "react"
import PropTypes from "prop-types" import PropTypes from "prop-types"
import { fromJS } from "immutable" import { fromJS } from "immutable"
import ImPropTypes from "react-immutable-proptypes" import ImPropTypes from "react-immutable-proptypes"
import { sanitizeUrl } from "core/utils"
class Path extends React.Component { class Path extends React.Component {
@@ -35,9 +36,9 @@ class Contact extends React.Component {
return ( return (
<div> <div>
{ url && <div><a href={ url } target="_blank">{ name } - Website</a></div> } { url && <div><a href={ sanitizeUrl(url) } target="_blank">{ name } - Website</a></div> }
{ email && { email &&
<a href={`mailto:${email}`}> <a href={sanitizeUrl(`mailto:${email}`)}>
{ url ? `Send email to ${name}` : `Contact ${name}`} { url ? `Send email to ${name}` : `Contact ${name}`}
</a> </a>
} }
@@ -59,7 +60,7 @@ class License extends React.Component {
return ( return (
<div> <div>
{ {
url ? <a target="_blank" href={ url }>{ name }</a> url ? <a target="_blank" href={ sanitizeUrl(url) }>{ name }</a>
: <span>{ name }</span> : <span>{ name }</span>
} }
</div> </div>
@@ -97,7 +98,7 @@ export default class Info extends React.Component {
{ version && <VersionStamp version={version}></VersionStamp> } { version && <VersionStamp version={version}></VersionStamp> }
</h2> </h2>
{ host || basePath ? <Path host={ host } basePath={ basePath } /> : null } { host || basePath ? <Path host={ host } basePath={ basePath } /> : null }
{ url && <a target="_blank" href={ url }><span className="url"> { url } </span></a> } { url && <a target="_blank" href={ sanitizeUrl(url) }><span className="url"> { url } </span></a> }
</hgroup> </hgroup>
<div className="description"> <div className="description">
@@ -106,14 +107,14 @@ export default class Info extends React.Component {
{ {
termsOfService && <div> termsOfService && <div>
<a target="_blank" href={ termsOfService }>Terms of service</a> <a target="_blank" href={ sanitizeUrl(termsOfService) }>Terms of service</a>
</div> </div>
} }
{ contact && contact.size ? <Contact data={ contact } /> : null } { contact && contact.size ? <Contact data={ contact } /> : null }
{ license && license.size ? <License license={ license } /> : null } { license && license.size ? <License license={ license } /> : null }
{ externalDocsUrl ? { externalDocsUrl ?
<a target="_blank" href={externalDocsUrl}>{externalDocsDescription || externalDocsUrl}</a> <a target="_blank" href={sanitizeUrl(externalDocsUrl)}>{externalDocsDescription || externalDocsUrl}</a>
: null } : null }
</div> </div>

View File

@@ -1,5 +1,6 @@
import React from "react" import React from "react"
import PropTypes from "prop-types" import PropTypes from "prop-types"
import { sanitizeUrl } from "core/utils"
export default class OnlineValidatorBadge extends React.Component { export default class OnlineValidatorBadge extends React.Component {
static propTypes = { static propTypes = {
@@ -32,6 +33,8 @@ export default class OnlineValidatorBadge extends React.Component {
let { getConfigs } = this.props let { getConfigs } = this.props
let { spec } = getConfigs() let { spec } = getConfigs()
let sanitizedValidatorUrl = sanitizeUrl(this.state.validatorUrl)
if ( typeof spec === "object" && Object.keys(spec).length) return null if ( typeof spec === "object" && Object.keys(spec).length) return null
if (!this.state.url || !this.state.validatorUrl || this.state.url.indexOf("localhost") >= 0 if (!this.state.url || !this.state.validatorUrl || this.state.url.indexOf("localhost") >= 0
@@ -40,8 +43,8 @@ export default class OnlineValidatorBadge extends React.Component {
} }
return (<span style={{ float: "right"}}> return (<span style={{ float: "right"}}>
<a target="_blank" href={`${ this.state.validatorUrl }/debug?url=${ this.state.url }`}> <a target="_blank" href={`${ sanitizedValidatorUrl }/debug?url=${ this.state.url }`}>
<ValidatorImage src={`${ this.state.validatorUrl }?url=${ this.state.url }`} alt="Online validator badge"/> <ValidatorImage src={`${ sanitizedValidatorUrl }?url=${ this.state.url }`} alt="Online validator badge"/>
</a> </a>
</span>) </span>)
} }

View File

@@ -2,6 +2,7 @@ import React, { PureComponent } from "react"
import PropTypes from "prop-types" import PropTypes from "prop-types"
import { getList } from "core/utils" import { getList } from "core/utils"
import * as CustomPropTypes from "core/proptypes" import * as CustomPropTypes from "core/proptypes"
import { sanitizeUrl } from "core/utils"
//import "less/opblock" //import "less/opblock"
@@ -206,7 +207,7 @@ export default class Operation extends PureComponent {
<span className="opblock-external-docs__description"> <span className="opblock-external-docs__description">
<Markdown source={ externalDocs.get("description") } /> <Markdown source={ externalDocs.get("description") } />
</span> </span>
<a className="opblock-external-docs__link" href={ externalDocs.get("url") }>{ externalDocs.get("url") }</a> <a className="opblock-external-docs__link" href={ sanitizeUrl(externalDocs.get("url")) }>{ externalDocs.get("url") }</a>
</div> </div>
</div> : null </div> : null
} }

View File

@@ -1,7 +1,7 @@
import React from "react" import React from "react"
import PropTypes from "prop-types" import PropTypes from "prop-types"
import { helpers } from "swagger-client" import { helpers } from "swagger-client"
import { createDeepLinkPath } from "core/utils" import { createDeepLinkPath, sanitizeUrl } from "core/utils"
const { opId } = helpers const { opId } = helpers
export default class Operations extends React.Component { export default class Operations extends React.Component {
@@ -101,7 +101,7 @@ export default class Operations extends React.Component {
{ tagExternalDocsUrl ? ": " : null } { tagExternalDocsUrl ? ": " : null }
{ tagExternalDocsUrl ? { tagExternalDocsUrl ?
<a <a
href={tagExternalDocsUrl} href={sanitizeUrl(tagExternalDocsUrl)}
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
target={"_blank"} target={"_blank"}
>{tagExternalDocsUrl}</a> : null >{tagExternalDocsUrl}</a> : null

View File

@@ -1,4 +1,5 @@
import React, { Component } from "react" import React, { Component } from "react"
import { Map } from "immutable"
import PropTypes from "prop-types" import PropTypes from "prop-types"
import win from "core/window" import win from "core/window"
@@ -29,11 +30,21 @@ export default class ParameterRow extends Component {
componentWillReceiveProps(props) { componentWillReceiveProps(props) {
let { specSelectors, pathMethod, param } = props let { specSelectors, pathMethod, param } = props
let { isOAS3 } = specSelectors
let example = param.get("example") let example = param.get("example")
let defaultValue = param.get("default") let defaultValue = param.get("default")
let parameter = specSelectors.getParameter(pathMethod, param.get("name"), param.get("in")) let parameter = specSelectors.getParameter(pathMethod, param.get("name"), param.get("in"))
let enumValue
if(isOAS3()) {
let schema = param.get("schema") || Map()
enumValue = schema.get("enum")
} else {
enumValue = parameter ? parameter.get("enum") : undefined
}
let paramValue = parameter ? parameter.get("value") : undefined let paramValue = parameter ? parameter.get("value") : undefined
let enumValue = parameter ? parameter.get("enum") : undefined
let value let value
if ( paramValue !== undefined ) { if ( paramValue !== undefined ) {

View File

@@ -20,10 +20,10 @@ function onlyOAS3(selector) {
export const definitionsToAuthorize = onlyOAS3(createSelector( export const definitionsToAuthorize = onlyOAS3(createSelector(
state, state,
({ specSelectors }) => { ({specSelectors}) => specSelectors.securityDefinitions(),
(system, definitions) => {
// Coerce our OpenAPI 3.0 definitions into monoflow definitions // Coerce our OpenAPI 3.0 definitions into monoflow definitions
// that look like Swagger2 definitions. // that look like Swagger2 definitions.
let definitions = specSelectors.securityDefinitions()
let list = List() let list = List()
definitions.entrySeq().forEach( ([ defName, definition ]) => { definitions.entrySeq().forEach( ([ defName, definition ]) => {
@@ -57,4 +57,4 @@ export const definitionsToAuthorize = onlyOAS3(createSelector(
return list return list
} }
)) ))

View File

@@ -50,7 +50,7 @@ export const definitions = onlyOAS3(createSelector(
export const securityDefinitions = onlyOAS3(createSelector( export const securityDefinitions = onlyOAS3(createSelector(
spec, spec,
spec => spec.getIn(["components", "securitySchemes"]) || Map() spec => spec.getIn(["components", "securitySchemes"]) || null
)) ))
export const host = OAS3NullSelector export const host = OAS3NullSelector

View File

@@ -80,7 +80,12 @@ export const parseToJson = (str) => ({specActions, specSelectors, errActions}) =
} }
export const resolveSpec = (json, url) => ({specActions, specSelectors, errActions, fn: { fetch, resolve, AST }, getConfigs}) => { export const resolveSpec = (json, url) => ({specActions, specSelectors, errActions, fn: { fetch, resolve, AST }, getConfigs}) => {
const { modelPropertyMacro, parameterMacro } = getConfigs() const {
modelPropertyMacro,
parameterMacro,
requestInterceptor,
responseInterceptor
} = getConfigs()
if(typeof(json) === "undefined") { if(typeof(json) === "undefined") {
json = specSelectors.specJson() json = specSelectors.specJson()
@@ -93,8 +98,15 @@ export const resolveSpec = (json, url) => ({specActions, specSelectors, errActio
let specStr = specSelectors.specStr() let specStr = specSelectors.specStr()
return resolve({fetch, spec: json, baseDoc: url, modelPropertyMacro, parameterMacro }) return resolve({
.then( ({spec, errors}) => { fetch,
spec: json,
baseDoc: url,
modelPropertyMacro,
parameterMacro,
requestInterceptor,
responseInterceptor
}).then( ({spec, errors}) => {
errActions.clear({ errActions.clear({
type: "thrown" type: "thrown"
}) })
@@ -140,7 +152,7 @@ export function changeParam( path, paramName, paramIn, value, isXml ){
export const validateParams = ( payload, isOAS3 ) =>{ export const validateParams = ( payload, isOAS3 ) =>{
return { return {
type: VALIDATE_PARAMS, type: VALIDATE_PARAMS,
payload:{ payload:{
pathMethod: payload, pathMethod: payload,
isOAS3 isOAS3
} }

View File

@@ -1,5 +1,5 @@
import Im from "immutable" import Im from "immutable"
import { sanitizeUrl as braintreeSanitizeUrl } from "@braintree/sanitize-url"
import camelCase from "lodash/camelCase" import camelCase from "lodash/camelCase"
import upperFirst from "lodash/upperFirst" import upperFirst from "lodash/upperFirst"
import _memoize from "lodash/memoize" import _memoize from "lodash/memoize"
@@ -722,6 +722,14 @@ export const shallowEqualKeys = (a,b, keys) => {
}) })
} }
export function sanitizeUrl(url) {
if(typeof url !== "string" || url === "") {
return ""
}
return braintreeSanitizeUrl(url)
}
export function getAcceptControllingResponse(responses) { export function getAcceptControllingResponse(responses) {
if(!Im.OrderedMap.isOrderedMap(responses)) { if(!Im.OrderedMap.isOrderedMap(responses)) {
// wrong type! // wrong type!

View File

@@ -1,6 +1,6 @@
# Add a plugin # Add a plugin
### Swagger-UX relies on plugins for all the good stuff. ### Swagger-UI relies on plugins for all the good stuff.
Plugins allow you to add Plugins allow you to add
- `statePlugins` - `statePlugins`

View File

@@ -129,7 +129,7 @@ export default class Topbar extends React.Component {
<div className="topbar"> <div className="topbar">
<div className="wrapper"> <div className="wrapper">
<div className="topbar-wrapper"> <div className="topbar-wrapper">
<Link href="#" title="Swagger UX"> <Link href="#">
<img height="30" width="30" src={ Logo } alt="Swagger UI"/> <img height="30" width="30" src={ Logo } alt="Swagger UI"/>
<span>swagger</span> <span>swagger</span>
</Link> </Link>

View File

@@ -16,7 +16,8 @@ import {
fromJSOrdered, fromJSOrdered,
getAcceptControllingResponse, getAcceptControllingResponse,
createDeepLinkPath, createDeepLinkPath,
escapeDeepLinkPath escapeDeepLinkPath,
sanitizeUrl
} from "core/utils" } from "core/utils"
import win from "core/window" import win from "core/window"
@@ -885,4 +886,43 @@ describe("utils", function() {
expect(result).toEqual("hello\\#world") expect(result).toEqual("hello\\#world")
}) })
}) })
describe("sanitizeUrl", function() {
it("should sanitize a `javascript:` url", function() {
const res = sanitizeUrl("javascript:alert('bam!')")
expect(res).toEqual("about:blank")
})
it("should sanitize a `data:` url", function() {
const res = sanitizeUrl(`data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGV
sbG8iKTs8L3NjcmlwdD4=`)
expect(res).toEqual("about:blank")
})
it("should not modify a `http:` url", function() {
const res = sanitizeUrl(`http://swagger.io/`)
expect(res).toEqual("http://swagger.io/")
})
it("should not modify a `https:` url", function() {
const res = sanitizeUrl(`https://swagger.io/`)
expect(res).toEqual("https://swagger.io/")
})
it("should gracefully handle empty strings", function() {
expect(sanitizeUrl("")).toEqual("")
})
it("should gracefully handle non-string values", function() {
expect(sanitizeUrl(123)).toEqual("")
expect(sanitizeUrl(null)).toEqual("")
expect(sanitizeUrl(undefined)).toEqual("")
expect(sanitizeUrl([])).toEqual("")
expect(sanitizeUrl({})).toEqual("")
})
})
}) })