Merge branch 'master' into bearer-dialog-fix
This commit is contained in:
3
.github/issue_template.md
vendored
3
.github/issue_template.md
vendored
@@ -1,6 +1,9 @@
|
||||
<!---
|
||||
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!
|
||||
|
||||
Issues on GitHub are only related to problems of Swagger-UI itself. We'll try to offer support
|
||||
|
||||
@@ -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.4.1 | 2017-10-20 | 2.0, 3.0 | [tag v3.4.1](https://github.com/swagger-api/swagger-ui/tree/v3.4.1)
|
||||
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)
|
||||
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)
|
||||
|
||||
98
dist/swagger-ui-bundle.js
vendored
98
dist/swagger-ui-bundle.js
vendored
File diff suppressed because one or more lines are too long
2
dist/swagger-ui-bundle.js.map
vendored
2
dist/swagger-ui-bundle.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/swagger-ui.js
vendored
4
dist/swagger-ui.js
vendored
File diff suppressed because one or more lines are too long
2
dist/swagger-ui.js.map
vendored
2
dist/swagger-ui.js.map
vendored
File diff suppressed because one or more lines are too long
@@ -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:
|
||||
- Open your browser's web console (changes between browsers)
|
||||
- Type `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, … }`.
|
||||
- Type `JSON.stringify(versions)` in the console and execute the call.
|
||||
- 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`.
|
||||
|
||||
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
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
```
|
||||
```
|
||||
|
||||
10
package.json
10
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "swagger-ui",
|
||||
"version": "3.4.1",
|
||||
"version": "3.4.2",
|
||||
"main": "dist/swagger-ui.js",
|
||||
"repository": "git@github.com:swagger-api/swagger-ui.git",
|
||||
"contributors": [
|
||||
@@ -39,6 +39,7 @@
|
||||
"e2e": "npm-run-all --parallel -r hot-server mock-api test-e2e"
|
||||
},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^2.0.2",
|
||||
"base64-js": "^1.2.0",
|
||||
"brace": "0.7.0",
|
||||
"classnames": "^2.2.5",
|
||||
@@ -55,12 +56,12 @@
|
||||
"memoizee": "0.4.1",
|
||||
"promise-worker": "^1.1.1",
|
||||
"prop-types": "^15.5.10",
|
||||
"react": "^15.4.0",
|
||||
"react": "^15.6.2",
|
||||
"react-addons-perf": "^15.4.0",
|
||||
"react-addons-shallow-compare": "0.14.8",
|
||||
"react-addons-test-utils": "^15.4.0",
|
||||
"react-addons-test-utils": "^15.6.2",
|
||||
"react-collapse": "2.3.1",
|
||||
"react-dom": "^15.4.0",
|
||||
"react-dom": "^15.6.2",
|
||||
"react-height": "^2.0.0",
|
||||
"react-hot-loader": "1.3.1",
|
||||
"react-immutable-proptypes": "2.1.0",
|
||||
@@ -83,6 +84,7 @@
|
||||
"whatwg-fetch": "0.11.1",
|
||||
"worker-loader": "^0.7.1",
|
||||
"xml": "1.0.1",
|
||||
"xml-but-prettier": "^1.0.1",
|
||||
"yaml-js": "0.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import { fromJS } from "immutable"
|
||||
import ImPropTypes from "react-immutable-proptypes"
|
||||
import { sanitizeUrl } from "core/utils"
|
||||
|
||||
|
||||
class Path extends React.Component {
|
||||
@@ -35,9 +36,9 @@ class Contact extends React.Component {
|
||||
|
||||
return (
|
||||
<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 &&
|
||||
<a href={`mailto:${email}`}>
|
||||
<a href={sanitizeUrl(`mailto:${email}`)}>
|
||||
{ url ? `Send email to ${name}` : `Contact ${name}`}
|
||||
</a>
|
||||
}
|
||||
@@ -59,7 +60,7 @@ class License extends React.Component {
|
||||
return (
|
||||
<div>
|
||||
{
|
||||
url ? <a target="_blank" href={ url }>{ name }</a>
|
||||
url ? <a target="_blank" href={ sanitizeUrl(url) }>{ name }</a>
|
||||
: <span>{ name }</span>
|
||||
}
|
||||
</div>
|
||||
@@ -97,7 +98,7 @@ export default class Info extends React.Component {
|
||||
{ version && <VersionStamp version={version}></VersionStamp> }
|
||||
</h2>
|
||||
{ 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>
|
||||
|
||||
<div className="description">
|
||||
@@ -106,14 +107,14 @@ export default class Info extends React.Component {
|
||||
|
||||
{
|
||||
termsOfService && <div>
|
||||
<a target="_blank" href={ termsOfService }>Terms of service</a>
|
||||
<a target="_blank" href={ sanitizeUrl(termsOfService) }>Terms of service</a>
|
||||
</div>
|
||||
}
|
||||
|
||||
{ contact && contact.size ? <Contact data={ contact } /> : null }
|
||||
{ license && license.size ? <License license={ license } /> : null }
|
||||
{ externalDocsUrl ?
|
||||
<a target="_blank" href={externalDocsUrl}>{externalDocsDescription || externalDocsUrl}</a>
|
||||
<a target="_blank" href={sanitizeUrl(externalDocsUrl)}>{externalDocsDescription || externalDocsUrl}</a>
|
||||
: null }
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import { sanitizeUrl } from "core/utils"
|
||||
|
||||
export default class OnlineValidatorBadge extends React.Component {
|
||||
static propTypes = {
|
||||
@@ -32,6 +33,8 @@ export default class OnlineValidatorBadge extends React.Component {
|
||||
let { getConfigs } = this.props
|
||||
let { spec } = getConfigs()
|
||||
|
||||
let sanitizedValidatorUrl = sanitizeUrl(this.state.validatorUrl)
|
||||
|
||||
if ( typeof spec === "object" && Object.keys(spec).length) return null
|
||||
|
||||
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"}}>
|
||||
<a target="_blank" href={`${ this.state.validatorUrl }/debug?url=${ this.state.url }`}>
|
||||
<ValidatorImage src={`${ this.state.validatorUrl }?url=${ this.state.url }`} alt="Online validator badge"/>
|
||||
<a target="_blank" href={`${ sanitizedValidatorUrl }/debug?url=${ this.state.url }`}>
|
||||
<ValidatorImage src={`${ sanitizedValidatorUrl }?url=${ this.state.url }`} alt="Online validator badge"/>
|
||||
</a>
|
||||
</span>)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { PureComponent } from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import { getList } from "core/utils"
|
||||
import * as CustomPropTypes from "core/proptypes"
|
||||
import { sanitizeUrl } from "core/utils"
|
||||
|
||||
//import "less/opblock"
|
||||
|
||||
@@ -206,7 +207,7 @@ export default class Operation extends PureComponent {
|
||||
<span className="opblock-external-docs__description">
|
||||
<Markdown source={ externalDocs.get("description") } />
|
||||
</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> : null
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import { helpers } from "swagger-client"
|
||||
import { createDeepLinkPath } from "core/utils"
|
||||
import { createDeepLinkPath, sanitizeUrl } from "core/utils"
|
||||
const { opId } = helpers
|
||||
|
||||
export default class Operations extends React.Component {
|
||||
@@ -101,7 +101,7 @@ export default class Operations extends React.Component {
|
||||
{ tagExternalDocsUrl ? ": " : null }
|
||||
{ tagExternalDocsUrl ?
|
||||
<a
|
||||
href={tagExternalDocsUrl}
|
||||
href={sanitizeUrl(tagExternalDocsUrl)}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
target={"_blank"}
|
||||
>{tagExternalDocsUrl}</a> : null
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import { formatXml } from "core/utils"
|
||||
import formatXml from "xml-but-prettier"
|
||||
import lowerCase from "lodash/lowerCase"
|
||||
|
||||
export default class ResponseBody extends React.Component {
|
||||
@@ -31,7 +31,9 @@ export default class ResponseBody extends React.Component {
|
||||
|
||||
// XML
|
||||
} else if (/xml/i.test(contentType)) {
|
||||
body = formatXml(content)
|
||||
body = formatXml(content, {
|
||||
textNodesOnSameLine: true
|
||||
})
|
||||
bodyEl = <HighlightCode value={ body } />
|
||||
|
||||
// HTML or Plain Text
|
||||
|
||||
@@ -58,13 +58,12 @@ module.exports = function SwaggerUI(opts) {
|
||||
plugins: [
|
||||
],
|
||||
|
||||
// Initial state
|
||||
initialState: { },
|
||||
|
||||
// Inline Plugin
|
||||
fn: { },
|
||||
components: { },
|
||||
state: { },
|
||||
|
||||
// Override some core configs... at your own risk
|
||||
store: { },
|
||||
}
|
||||
|
||||
let queryConfig = parseSearch()
|
||||
@@ -74,12 +73,12 @@ module.exports = function SwaggerUI(opts) {
|
||||
|
||||
const constructorConfig = deepExtend({}, defaults, opts, queryConfig)
|
||||
|
||||
const storeConfigs = deepExtend({}, constructorConfig.store, {
|
||||
const storeConfigs = {
|
||||
system: {
|
||||
configs: constructorConfig.configs
|
||||
},
|
||||
plugins: constructorConfig.presets,
|
||||
state: {
|
||||
state: deepExtend({
|
||||
layout: {
|
||||
layout: constructorConfig.layout,
|
||||
filter: constructorConfig.filter
|
||||
@@ -88,8 +87,8 @@ module.exports = function SwaggerUI(opts) {
|
||||
spec: "",
|
||||
url: constructorConfig.url
|
||||
}
|
||||
}
|
||||
})
|
||||
}, constructorConfig.initialState)
|
||||
}
|
||||
|
||||
let inlinePlugin = ()=> {
|
||||
return {
|
||||
|
||||
@@ -10,6 +10,7 @@ import auth from "core/plugins/auth"
|
||||
import util from "core/plugins/util"
|
||||
import SplitPaneModePlugin from "core/plugins/split-pane-mode"
|
||||
import downloadUrlPlugin from "core/plugins/download-url"
|
||||
import configsPlugin from "plugins/configs"
|
||||
import deepLinkingPlugin from "core/plugins/deep-linking"
|
||||
|
||||
import App from "core/components/app"
|
||||
@@ -122,6 +123,7 @@ export default function() {
|
||||
}
|
||||
|
||||
return [
|
||||
configsPlugin,
|
||||
util,
|
||||
logs,
|
||||
view,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Im from "immutable"
|
||||
|
||||
import { sanitizeUrl as braintreeSanitizeUrl } from "@braintree/sanitize-url"
|
||||
import camelCase from "lodash/camelCase"
|
||||
import upperFirst from "lodash/upperFirst"
|
||||
import _memoize from "lodash/memoize"
|
||||
@@ -155,83 +155,6 @@ export function getList(iterable, keys) {
|
||||
return Im.List.isList(val) ? val : Im.List()
|
||||
}
|
||||
|
||||
// Adapted from http://stackoverflow.com/a/2893259/454004
|
||||
// Note: directly ported from CoffeeScript
|
||||
export function formatXml (xml) {
|
||||
var contexp, fn, formatted, indent, l, lastType, len, lines, ln, reg, transitions, wsexp
|
||||
reg = /(>)(<)(\/*)/g
|
||||
wsexp = /[ ]*(.*)[ ]+\n/g
|
||||
contexp = /(<.+>)(.+\n)/g
|
||||
xml = xml.replace(/\r\n/g, "\n").replace(reg, "$1\n$2$3").replace(wsexp, "$1\n").replace(contexp, "$1\n$2")
|
||||
formatted = ""
|
||||
lines = xml.split("\n")
|
||||
indent = 0
|
||||
lastType = "other"
|
||||
transitions = {
|
||||
"single->single": 0,
|
||||
"single->closing": -1,
|
||||
"single->opening": 0,
|
||||
"single->other": 0,
|
||||
"closing->single": 0,
|
||||
"closing->closing": -1,
|
||||
"closing->opening": 0,
|
||||
"closing->other": 0,
|
||||
"opening->single": 1,
|
||||
"opening->closing": 0,
|
||||
"opening->opening": 1,
|
||||
"opening->other": 1,
|
||||
"other->single": 0,
|
||||
"other->closing": -1,
|
||||
"other->opening": 0,
|
||||
"other->other": 0
|
||||
}
|
||||
fn = function(ln) {
|
||||
var fromTo, key, padding, type, types, value
|
||||
types = {
|
||||
single: Boolean(ln.match(/<.+\/>/)),
|
||||
closing: Boolean(ln.match(/<\/.+>/)),
|
||||
opening: Boolean(ln.match(/<[^!?].*>/))
|
||||
}
|
||||
type = ((function() {
|
||||
var results
|
||||
results = []
|
||||
for (key in types) {
|
||||
value = types[key]
|
||||
if (value) {
|
||||
results.push(key)
|
||||
}
|
||||
}
|
||||
return results
|
||||
})())[0]
|
||||
type = type === void 0 ? "other" : type
|
||||
fromTo = lastType + "->" + type
|
||||
lastType = type
|
||||
padding = ""
|
||||
indent += transitions[fromTo]
|
||||
padding = ((function() {
|
||||
/* eslint-disable no-unused-vars */
|
||||
var m, ref1, results, j
|
||||
results = []
|
||||
for (j = m = 0, ref1 = indent; 0 <= ref1 ? m < ref1 : m > ref1; j = 0 <= ref1 ? ++m : --m) {
|
||||
results.push(" ")
|
||||
}
|
||||
/* eslint-enable no-unused-vars */
|
||||
return results
|
||||
})()).join("")
|
||||
if (fromTo === "opening->closing") {
|
||||
formatted = formatted.substr(0, formatted.length - 1) + ln + "\n"
|
||||
} else {
|
||||
formatted += padding + ln + "\n"
|
||||
}
|
||||
}
|
||||
for (l = 0, len = lines.length; l < len; l++) {
|
||||
ln = lines[l]
|
||||
fn(ln)
|
||||
}
|
||||
return formatted
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adapted from http://github.com/asvd/microlight
|
||||
* @copyright 2016 asvd <heliosframework@gmail.com>
|
||||
@@ -722,6 +645,14 @@ export const shallowEqualKeys = (a,b, keys) => {
|
||||
})
|
||||
}
|
||||
|
||||
export function sanitizeUrl(url) {
|
||||
if(typeof url !== "string" || url === "") {
|
||||
return ""
|
||||
}
|
||||
|
||||
return braintreeSanitizeUrl(url)
|
||||
}
|
||||
|
||||
export function getAcceptControllingResponse(responses) {
|
||||
if(!Im.OrderedMap.isOrderedMap(responses)) {
|
||||
// wrong type!
|
||||
|
||||
20
src/plugins/configs/actions.js
Normal file
20
src/plugins/configs/actions.js
Normal file
@@ -0,0 +1,20 @@
|
||||
export const UPDATE_CONFIGS = "configs_update"
|
||||
export const TOGGLE_CONFIGS = "configs_toggle"
|
||||
|
||||
// Update the configs, with a merge ( not deep )
|
||||
export function update(configName, configValue) {
|
||||
return {
|
||||
type: UPDATE_CONFIGS,
|
||||
payload: {
|
||||
[configName]: configValue
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle's the config, by name
|
||||
export function toggle(configName) {
|
||||
return {
|
||||
type: TOGGLE_CONFIGS,
|
||||
payload: configName,
|
||||
}
|
||||
}
|
||||
@@ -1,56 +1,66 @@
|
||||
import YAML from "js-yaml"
|
||||
import yamlConfig from "../../../swagger-config.yaml"
|
||||
import * as actions from "./actions"
|
||||
import * as selectors from "./selectors"
|
||||
import reducers from "./reducers"
|
||||
|
||||
const parseYamlConfig = (yaml, system) => {
|
||||
try {
|
||||
return YAML.safeLoad(yaml)
|
||||
} catch(e) {
|
||||
if (system) {
|
||||
system.errActions.newThrownErr( new Error(e) )
|
||||
}
|
||||
return {}
|
||||
try {
|
||||
return YAML.safeLoad(yaml)
|
||||
} catch(e) {
|
||||
if (system) {
|
||||
system.errActions.newThrownErr( new Error(e) )
|
||||
}
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default function configPlugin (toolbox) {
|
||||
let { fn } = toolbox
|
||||
|
||||
const actions = {
|
||||
downloadConfig: (url) => () => {
|
||||
let {fetch} = fn
|
||||
return fetch(url)
|
||||
},
|
||||
|
||||
getConfigByUrl: (configUrl, cb)=> ({ specActions }) => {
|
||||
if (configUrl) {
|
||||
return specActions.downloadConfig(configUrl).then(next, next)
|
||||
}
|
||||
|
||||
function next(res) {
|
||||
if (res instanceof Error || res.status >= 400) {
|
||||
specActions.updateLoadingStatus("failedConfig")
|
||||
specActions.updateLoadingStatus("failedConfig")
|
||||
specActions.updateUrl("")
|
||||
console.error(res.statusText + " " + configUrl)
|
||||
cb(null)
|
||||
} else {
|
||||
cb(parseYamlConfig(res.text))
|
||||
}
|
||||
}
|
||||
}
|
||||
const specActions = {
|
||||
downloadConfig: (url) => ({fn}) => {
|
||||
let {fetch} = fn
|
||||
return fetch(url)
|
||||
},
|
||||
|
||||
getConfigByUrl: (configUrl, cb)=> ({ specActions }) => {
|
||||
if (configUrl) {
|
||||
return specActions.downloadConfig(configUrl).then(next, next)
|
||||
}
|
||||
|
||||
const selectors = {
|
||||
getLocalConfig: () => {
|
||||
return parseYamlConfig(yamlConfig)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
statePlugins: {
|
||||
spec: { actions, selectors }
|
||||
}
|
||||
function next(res) {
|
||||
if (res instanceof Error || res.status >= 400) {
|
||||
specActions.updateLoadingStatus("failedConfig")
|
||||
specActions.updateLoadingStatus("failedConfig")
|
||||
specActions.updateUrl("")
|
||||
console.error(res.statusText + " " + configUrl)
|
||||
cb(null)
|
||||
} else {
|
||||
cb(parseYamlConfig(res.text))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const specSelectors = {
|
||||
getLocalConfig: () => {
|
||||
return parseYamlConfig(yamlConfig)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default function configsPlugin() {
|
||||
|
||||
return {
|
||||
statePlugins: {
|
||||
spec: {
|
||||
actions: specActions,
|
||||
selectors: specSelectors,
|
||||
},
|
||||
configs: {
|
||||
reducers,
|
||||
actions,
|
||||
selectors,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
20
src/plugins/configs/reducers.js
Normal file
20
src/plugins/configs/reducers.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import { fromJS } from "immutable"
|
||||
|
||||
import {
|
||||
UPDATE_CONFIGS,
|
||||
TOGGLE_CONFIGS,
|
||||
} from "./actions"
|
||||
|
||||
export default {
|
||||
|
||||
[UPDATE_CONFIGS]: (state, action) => {
|
||||
return state.merge(fromJS(action.payload))
|
||||
},
|
||||
|
||||
[TOGGLE_CONFIGS]: (state, action) => {
|
||||
const configName = action.payload
|
||||
const oriVal = state.get(configName)
|
||||
return state.set(configName, !oriVal)
|
||||
},
|
||||
|
||||
}
|
||||
4
src/plugins/configs/selectors.js
Normal file
4
src/plugins/configs/selectors.js
Normal file
@@ -0,0 +1,4 @@
|
||||
// Just get the config value ( it can possibly be an immutable object)
|
||||
export const get = (state, path) => {
|
||||
return state.getIn(Array.isArray(path) ? path : [path])
|
||||
}
|
||||
@@ -16,7 +16,8 @@ import {
|
||||
fromJSOrdered,
|
||||
getAcceptControllingResponse,
|
||||
createDeepLinkPath,
|
||||
escapeDeepLinkPath
|
||||
escapeDeepLinkPath,
|
||||
sanitizeUrl
|
||||
} from "core/utils"
|
||||
import win from "core/window"
|
||||
|
||||
@@ -885,4 +886,44 @@ describe("utils", function() {
|
||||
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("")
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user