mirror of
https://github.com/Redocly/redoc.git
synced 2024-11-29 03:53:43 +03:00
fix: prevent possible xss using untrusted-spec
option
This commit is contained in:
parent
7a5d315e09
commit
c0698bb215
|
@ -131,6 +131,7 @@ ReDoc makes use of the following [vendor extensions](http://swagger.io/specifica
|
||||||
|
|
||||||
### `<redoc>` tag attributes
|
### `<redoc>` tag attributes
|
||||||
* `spec-url` - relative or absolute url to your spec file;
|
* `spec-url` - relative or absolute url to your spec file;
|
||||||
|
* `untrusted-spec` - if set, the spec is considered untrusted and all HTML/markdown is sanitized to prevent XSS. **Disabled by default** for performance reasons. **Enable this option if you work with untrusted user data!**
|
||||||
* `scroll-y-offset` - If set, specifies a vertical scroll-offset. This is often useful when there are fixed positioned elements at the top of the page, such as navbars, headers etc;
|
* `scroll-y-offset` - If set, specifies a vertical scroll-offset. This is often useful when there are fixed positioned elements at the top of the page, such as navbars, headers etc;
|
||||||
`scroll-y-offset` can be specified in various ways:
|
`scroll-y-offset` can be specified in various ways:
|
||||||
* **number**: A fixed number of pixels to be used as offset;
|
* **number**: A fixed number of pixels to be used as offset;
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
frameborder="0" scrolling="0" width="130px" height="30px"></iframe>
|
frameborder="0" scrolling="0" width="130px" height="30px"></iframe>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<redoc scroll-y-offset="body > nav" spec-url='swagger.yaml' lazy-rendering></redoc>
|
<redoc scroll-y-offset="body > nav" spec-url='swagger.yaml' lazy-rendering untrusted-spec></redoc>
|
||||||
|
|
||||||
<script src="main.js"> </script>
|
<script src="main.js"> </script>
|
||||||
<script src="./dist/redoc.min.js"> </script>
|
<script src="./dist/redoc.min.js"> </script>
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
frameborder="0" scrolling="0" width="130px" height="30px"></iframe>
|
frameborder="0" scrolling="0" width="130px" height="30px"></iframe>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<redoc scroll-y-offset="body > nav" spec-url='swagger.yaml' lazy-rendering></redoc>
|
<redoc scroll-y-offset="body > nav" spec-url='swagger.yaml' lazy-rendering untrusted-spec></redoc>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
window.__REDOC_DEV__ = true;
|
window.__REDOC_DEV__ = true;
|
||||||
|
|
|
@ -19,6 +19,7 @@ const OPTION_NAMES = new Set([
|
||||||
'requiredPropsFirst',
|
'requiredPropsFirst',
|
||||||
'noAutoAuth',
|
'noAutoAuth',
|
||||||
'pathInMiddlePanel',
|
'pathInMiddlePanel',
|
||||||
|
'untrustedSpec'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export interface Options {
|
export interface Options {
|
||||||
|
@ -33,6 +34,7 @@ export interface Options {
|
||||||
requiredPropsFirst?: boolean;
|
requiredPropsFirst?: boolean;
|
||||||
noAutoAuth?: boolean;
|
noAutoAuth?: boolean;
|
||||||
pathInMiddlePanel?: boolean;
|
pathInMiddlePanel?: boolean;
|
||||||
|
untrustedSpec?: boolean;
|
||||||
spec?: any;
|
spec?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +103,7 @@ export class OptionsService {
|
||||||
if (isString(this._options.requiredPropsFirst)) this._options.requiredPropsFirst = true;
|
if (isString(this._options.requiredPropsFirst)) this._options.requiredPropsFirst = true;
|
||||||
if (isString(this._options.noAutoAuth)) this._options.noAutoAuth = true;
|
if (isString(this._options.noAutoAuth)) this._options.noAutoAuth = true;
|
||||||
if (isString(this._options.pathInMiddlePanel)) this._options.pathInMiddlePanel = true;
|
if (isString(this._options.pathInMiddlePanel)) this._options.pathInMiddlePanel = true;
|
||||||
|
if (isString(this._options.untrustedSpec)) this._options.untrustedSpec = true;
|
||||||
if (isString(this._options.expandResponses)) {
|
if (isString(this._options.expandResponses)) {
|
||||||
let str = this._options.expandResponses as string;
|
let str = this._options.expandResponses as string;
|
||||||
if (str === 'all') return;
|
if (str === 'all') return;
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { isString, stringify, isBlank } from './helpers';
|
||||||
import JsonPointer from './JsonPointer';
|
import JsonPointer from './JsonPointer';
|
||||||
import { MdRenderer } from './';
|
import { MdRenderer } from './';
|
||||||
import { JsonFormatter } from './JsonFormatterPipe';
|
import { JsonFormatter } from './JsonFormatterPipe';
|
||||||
|
import { OptionsService } from '../services/options.service';
|
||||||
|
|
||||||
declare var Prism: any;
|
declare var Prism: any;
|
||||||
|
|
||||||
|
@ -48,18 +49,19 @@ export class JsonPointerEscapePipe implements PipeTransform {
|
||||||
@Pipe({ name: 'marked' })
|
@Pipe({ name: 'marked' })
|
||||||
export class MarkedPipe implements PipeTransform {
|
export class MarkedPipe implements PipeTransform {
|
||||||
renderer: MdRenderer;
|
renderer: MdRenderer;
|
||||||
constructor(private sanitizer: DomSanitizer) {
|
unstrustedSpec: boolean;
|
||||||
|
|
||||||
|
constructor(private sanitizer: DomSanitizer, optionsService: OptionsService) {
|
||||||
this.renderer = new MdRenderer(true);
|
this.renderer = new MdRenderer(true);
|
||||||
|
this.unstrustedSpec = !!optionsService.options.untrustedSpec;
|
||||||
}
|
}
|
||||||
transform(value:string) {
|
transform(value:string) {
|
||||||
if (isBlank(value)) return value;
|
if (isBlank(value)) return value;
|
||||||
if (!isString(value)) {
|
if (!isString(value)) {
|
||||||
throw new InvalidPipeArgumentException(JsonPointerEscapePipe, value);
|
throw new InvalidPipeArgumentException(JsonPointerEscapePipe, value);
|
||||||
}
|
}
|
||||||
|
let res = `<span class="redoc-markdown-block">${this.renderer.renderMd(value)}</span>`;
|
||||||
return this.sanitizer.bypassSecurityTrustHtml(
|
return this.unstrustedSpec ? res : this.sanitizer.bypassSecurityTrustHtml(res);
|
||||||
`<span class="redoc-markdown-block">${this.renderer.renderMd(value)}</span>`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user