/** * @license * Copyright Google Inc. All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ import {browserDetection} from '@angular/platform-browser/testing/src/browser_util'; import {getDOM} from '../../src/dom/dom_adapter'; import {sanitizeHtml} from '../../src/security/html_sanitizer'; { describe('HTML sanitizer', () => { let defaultDoc: any; let originalLog: (msg: any) => any = null !; let logMsgs: string[]; beforeEach(() => { defaultDoc = getDOM().supportsDOMEvents() ? document : getDOM().createHtmlDocument(); logMsgs = []; originalLog = getDOM().log; // Monkey patch DOM.log. getDOM().log = (msg) => logMsgs.push(msg); }); afterEach(() => { getDOM().log = originalLog; }); it('serializes nested structures', () => { expect(sanitizeHtml(defaultDoc, '
a
bcdea
bcdeHello
World
Hello
World
Hellö Wörld
')) .toEqual('Hellö Wörld
'); expect(logMsgs).toEqual([]); }); it('escapes entities', () => { expect(sanitizeHtml(defaultDoc, 'Hello < World
')) .toEqual('Hello < World
'); expect(sanitizeHtml(defaultDoc, 'Hello < World
')).toEqual('Hello < World
'); expect(sanitizeHtml(defaultDoc, 'Hello
')) .toEqual('Hello
'); // NB: quote encoded as ASCII ". }); describe('should strip dangerous elements', () => { const dangerousTags = [ 'frameset', 'form', 'param', 'object', 'embed', 'textarea', 'input', 'button', 'option', 'select', 'script', 'style', 'link', 'base', 'basefont' ]; for (const tag of dangerousTags) { it(`${tag}`, () => { expect(sanitizeHtml(defaultDoc, `<${tag}>evil!${tag}>`)).toEqual('evil!'); }); } it(`swallows frame entirely`, () => { expect(sanitizeHtml(defaultDoc, `evil!`)).not.toContain(''); }); }); describe('should strip dangerous attributes', () => { const dangerousAttrs = ['id', 'name', 'style']; for (const attr of dangerousAttrs) { it(`${attr}`, () => { expect(sanitizeHtml(defaultDoc, `evil!`)).toEqual('evil!'); }); } }); it('should not enter an infinite loop on clobbered elements', () => { // Some browsers are vulnerable to clobbered elements and will throw an expected exception // IE and EDGE does not seems to be affected by those cases // Anyway what we want to test is that browsers do not enter an infinite loop which would // result in a timeout error for the test. try { sanitizeHtml(defaultDoc, ''); } catch (e) { // depending on the browser, we might ge an exception } try { sanitizeHtml(defaultDoc, ''); } catch (e) { // depending on the browser, we might ge an exception } try { sanitizeHtml(defaultDoc, ''); } catch (e) { // depending on the browser, we might ge an exception } }); // See // https://github.com/cure53/DOMPurify/blob/a992d3a75031cb8bb032e5ea8399ba972bdf9a65/src/purify.js#L439-L449 it('should not allow JavaScript execution when creating inert document', () => { const output = sanitizeHtml(defaultDoc, ''); const window = defaultDoc.defaultView; if (window) { expect(window.xxx).toBe(undefined); window.xxx = undefined; } expect(output).toEqual(''); }); // See https://github.com/cure53/DOMPurify/releases/tag/0.6.7 it('should not allow JavaScript hidden in badly formed HTML to get through sanitization (Firefox bug)', () => { expect(sanitizeHtml( defaultDoc, '