/** * @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 * as t from '@angular/core/testing/testing_internal'; import {browserDetection} from '@angular/platform-browser/testing/browser_util'; import {getDOM} from '../../src/dom/dom_adapter'; import {sanitizeHtml} from '../../src/security/html_sanitizer'; export function main() { t.describe('HTML sanitizer', () => { let originalLog: (msg: any) => any = null; let logMsgs: string[]; t.beforeEach(() => { logMsgs = []; originalLog = getDOM().log; // Monkey patch DOM.log. getDOM().log = (msg) => logMsgs.push(msg); }); t.afterEach(() => { getDOM().log = originalLog; }); t.it('serializes nested structures', () => { t.expect(sanitizeHtml('

a

bcde
')) .toEqual('

a

bcde
'); t.expect(logMsgs).toEqual([]); }); t.it('serializes self closing elements', () => { t.expect(sanitizeHtml('

Hello
World

')).toEqual('

Hello
World

'); }); t.it('supports namespaced elements', () => { t.expect(sanitizeHtml('abc')).toEqual('abc'); }); t.it('supports namespaced attributes', () => { t.expect(sanitizeHtml('t')) .toEqual('t'); t.expect(sanitizeHtml('t')).toEqual('t'); t.expect(sanitizeHtml('t')) .toEqual('t'); }); t.it('supports HTML5 elements', () => { t.expect(sanitizeHtml('
Works
')) .toEqual('
Works
'); }); t.it('sanitizes srcset attributes', () => { t.expect(sanitizeHtml('')) .toEqual(''); }); t.it('supports sanitizing plain text', () => { t.expect(sanitizeHtml('Hello, World')).toEqual('Hello, World'); }); t.it('ignores non-element, non-attribute nodes', () => { t.expect(sanitizeHtml('no.')).toEqual('no.'); t.expect(sanitizeHtml('no.')).toEqual('no.'); t.expect(logMsgs.join('\n')).toMatch(/sanitizing HTML stripped some content/); }); t.it('supports sanitizing escaped entities', () => { t.expect(sanitizeHtml('🚀')).toEqual('🚀'); t.expect(logMsgs).toEqual([]); }); t.it('does not warn when just re-encoding text', () => { t.expect(sanitizeHtml('

Hellö Wörld

')).toEqual('

Hellö Wörld

'); t.expect(logMsgs).toEqual([]); }); t.it('escapes entities', () => { t.expect(sanitizeHtml('

Hello < World

')).toEqual('

Hello < World

'); t.expect(sanitizeHtml('

Hello < World

')).toEqual('

Hello < World

'); t.expect(sanitizeHtml('

Hello

')) .toEqual('

Hello

'); // NB: quote encoded as ASCII ". }); t.describe('should strip dangerous elements', () => { let dangerousTags = [ 'frameset', 'form', 'param', 'object', 'embed', 'textarea', 'input', 'button', 'option', 'select', 'script', 'style', 'link', 'base', 'basefont' ]; for (let tag of dangerousTags) { t.it( `${tag}`, () => { t.expect(sanitizeHtml(`<${tag}>evil!`)).toEqual('evil!'); }); } t.it(`swallows frame entirely`, () => { t.expect(sanitizeHtml(`evil!`)).not.toContain(''); }); }); t.describe('should strip dangerous attributes', () => { let dangerousAttrs = ['id', 'name', 'style']; for (let attr of dangerousAttrs) { t.it(`${attr}`, () => { t.expect(sanitizeHtml(`evil!`)).toEqual('evil!'); }); } }); if (browserDetection.isWebkit) { t.it('should prevent mXSS attacks', function() { t.expect(sanitizeHtml('CLICKME')) .toEqual('CLICKME'); }); } }); }