feat(all): add ability to eject from Ionic sanitizer (#20457)

resolves #18277
This commit is contained in:
Liam DeBeasi
2020-04-27 16:03:39 -04:00
committed by GitHub
parent 578ab93d29
commit fa9ddc91bc
21 changed files with 90 additions and 38 deletions

View File

@@ -175,6 +175,11 @@ export interface IonicConfig {
*/
experimentalTransitionShadow?: boolean;
/**
* If `true`, Ionic will enable a basic DOM sanitizer on component properties that accept custom HTML.
*/
sanitizerEnabled?: boolean;
// PRIVATE configs
keyboardHeight?: number;
inputShims?: boolean;

View File

@@ -3,9 +3,10 @@
* in an untrusted string
*/
export const sanitizeDOMString = (untrustedString: string | undefined): string | undefined => {
export const sanitizeDOMString = (untrustedString: IonicSafeString | string | undefined): string | undefined => {
try {
if (typeof untrustedString !== 'string' || untrustedString === '') { return untrustedString; }
if (untrustedString instanceof IonicSafeString) { return untrustedString.value; }
if (!isSanitizerEnabled() || typeof untrustedString !== 'string' || untrustedString === '') { return untrustedString; }
/**
* Create a document fragment
@@ -122,5 +123,22 @@ const getElementChildren = (el: any) => {
return (el.children != null) ? el.children : el.childNodes;
};
const isSanitizerEnabled = (): boolean => {
const win = window as any;
const config = win && win.Ionic && win.Ionic.config;
if (config) {
if (config.get) {
return config.get('sanitizerEnabled', true);
} else {
return config.sanitizerEnabled === true || config.sanitizerEnabled === undefined;
}
}
return true;
};
const allowedAttributes = ['class', 'id', 'href', 'src', 'name', 'slot'];
const blockedTags = ['script', 'style', 'iframe', 'meta', 'link', 'object', 'embed'];
export class IonicSafeString {
constructor(public value: string) {}
}

View File

@@ -1,6 +1,16 @@
import { sanitizeDOMString } from "..";
import { IonicSafeString, sanitizeDOMString } from "..";
describe('sanitizeDOMString', () => {
it('disable sanitizer', () => {
enableSanitizer(false);
expect(sanitizeDOMString('<img src="x" onerror="alert(document.cookie);">'))
.toEqual('<img src="x" onerror="alert(document.cookie);">');
})
it('bypass sanitizer', () => {
expect(sanitizeDOMString(new IonicSafeString('<img src="x" onerror="alert(document.cookie);">')))
.toEqual('<img src="x" onerror="alert(document.cookie);">');
});
it('filter onerror', () => {
expect(sanitizeDOMString('<img src="x" onerror="alert(document.cookie);">'))
@@ -41,4 +51,10 @@ describe('sanitizeDOMString', () => {
expect(sanitizeDOMString('<ion-item><ion-label>Hello!</ion-label><ion-button onclick="alert(document.cookie);">Click me</ion-button>'))
.toEqual('<ion-item><ion-label>Hello!</ion-label><ion-button>Click me</ion-button></ion-item>');
});
});
});
const enableSanitizer = (enable: boolean = true) => {
window.Ionic = {};
window.Ionic.config = {};
window.Ionic.config.sanitizerEnabled = enable;
}