'use strict'; describe('HTML', function(){ function expectHTML(html) { return expect(new HTML(html).get()); } describe('htmlParser', function(){ var handler, start, text; beforeEach(function(){ handler = { start: function(tag, attrs, unary){ start = { tag: tag, attrs: attrs, unary: unary }; // Since different browsers handle newlines differenttly we trim // so that it is easier to write tests. forEach(attrs, function(value, key){ attrs[key] = trim(value); }); }, chars: function(text_){ text = text_; }, end:function(tag) { expect(tag).toEqual(start.tag); } }; }); it('should parse basic format', function(){ htmlParser('text', handler); expect(start).toEqual({tag:'tag', attrs:{attr:'value'}, unary:false}); expect(text).toEqual('text'); }); it('should parse newlines in tags', function(){ htmlParser('<\ntag\n attr="value"\n>text<\n/\ntag\n>', handler); expect(start).toEqual({tag:'tag', attrs:{attr:'value'}, unary:false}); expect(text).toEqual('text'); }); it('should parse newlines in attributes', function(){ htmlParser('text', handler); expect(start).toEqual({tag:'tag', attrs:{attr:'value'}, unary:false}); expect(text).toEqual('text'); }); it('should parse namespace', function(){ htmlParser('text', handler); expect(start).toEqual({tag:'ns:t-a-g', attrs:{'ns:a-t-t-r':'value'}, unary:false}); expect(text).toEqual('text'); }); it('should parse empty value attribute of node', function(){ htmlParser('', handler); expect(start).toEqual({tag:'option', attrs:{selected:'', value:''}, unary:false}); expect(text).toEqual('abc'); }); }); it('should echo html', function(){ expectHTML('helloworld.'). toEqual('helloworld.'); }); it('should remove script', function(){ expectHTML('ac.').toEqual('ac.'); }); it('should remove double nested script', function(){ expectHTML('ailc.').toEqual('ac.'); }); it('should remove unknown names', function(){ expectHTML('abc').toEqual('abc'); }); it('should remove unsafe value', function(){ expectHTML('').toEqual(''); }); it('should handle self closed elements', function(){ expectHTML('a
c').toEqual('a
c'); }); it('should handle namespace', function(){ expectHTML('abc').toEqual('abc'); }); it('should handle entities', function(){ var everything = '
' + '!@#$%^&*()_+-={}[]:";\'<>?,./`~ ħ
'; expectHTML(everything).toEqual(everything); }); it('should handle improper html', function(){ expectHTML('< div rel="" alt=abc dir=\'"\' >text< /div>'). toEqual('
text
'); }); it('should handle improper html2', function(){ expectHTML('< div rel="" / >'). toEqual('
'); }); it('should ignore back slash as escape', function(){ expectHTML('xxx\\'). toEqual('xxx\\'); }); it('should ignore object attributes', function(){ expectHTML(':)'). toEqual(':)'); expectHTML(':)'). toEqual(''); }); describe('htmlSanitizerWriter', function(){ var writer, html; beforeEach(function(){ html = ''; writer = htmlSanitizeWriter({push:function(text){html+=text;}}); }); it('should write basic HTML', function(){ writer.chars('before'); writer.start('div', {rel:'123'}, false); writer.chars('in'); writer.end('div'); writer.chars('after'); expect(html).toEqual('before
in
after'); }); it('should escape text nodes', function(){ writer.chars('a
&
c'); expect(html).toEqual('a<div>&</div>c'); }); it('should escape IE script', function(){ writer.chars('&<>{}'); expect(html).toEqual('&<>{}'); }); it('should escape attributes', function(){ writer.start('div', {rel:'!@#$%^&*()_+-={}[]:";\'<>?,./`~ \n\0\r\u0127'}); expect(html).toEqual('
'); }); it('should ignore missformed elements', function(){ writer.start('d>i&v', {}); expect(html).toEqual(''); }); it('should ignore unknown attributes', function(){ writer.start('div', {unknown:""}); expect(html).toEqual('
'); }); describe('explicitly dissallow', function(){ it('should not allow attributes', function(){ writer.start('div', {id:'a', name:'a', style:'a'}); expect(html).toEqual('
'); }); it('should not allow tags', function(){ function tag(name) { writer.start(name, {}); writer.end(name); } tag('frameset'); tag('frame'); tag('form'); tag('param'); tag('object'); tag('embed'); tag('textarea'); tag('input'); tag('button'); tag('option'); tag('select'); tag('script'); tag('style'); tag('link'); tag('base'); tag('basefont'); expect(html).toEqual(''); }); }); describe('isUri', function(){ function isUri(value) { return value.match(URI_REGEXP); } it('should be URI', function(){ expect(isUri('http://abc')).toBeTruthy(); expect(isUri('https://abc')).toBeTruthy(); expect(isUri('ftp://abc')).toBeTruthy(); expect(isUri('mailto:me@example.com')).toBeTruthy(); expect(isUri('#anchor')).toBeTruthy(); }); it('should not be UIR', function(){ expect(isUri('')).toBeFalsy(); expect(isUri('javascript:alert')).toBeFalsy(); }); }); describe('javascript URL attribute', function(){ beforeEach(function(){ this.addMatchers({ toBeValidUrl: function(){ return URI_REGEXP.exec(this.actual); } }); }); it('should ignore javascript:', function(){ expect('JavaScript:abc').not.toBeValidUrl(); expect(' \n Java\n Script:abc').not.toBeValidUrl(); expect('http://JavaScript/my.js').toBeValidUrl(); }); it('should ignore dec encoded javascript:', function(){ expect('javascript:').not.toBeValidUrl(); expect('javascript:').not.toBeValidUrl(); expect('j avascript:').not.toBeValidUrl(); }); it('should ignore decimal with leading 0 encodede javascript:', function(){ expect('javascript:').not.toBeValidUrl(); expect('j avascript:').not.toBeValidUrl(); expect('j avascript:').not.toBeValidUrl(); }); it('should ignore hex encoded javascript:', function(){ expect('javascript:').not.toBeValidUrl(); expect('javascript:').not.toBeValidUrl(); expect('j avascript:').not.toBeValidUrl(); }); it('should ignore hex encoded whitespace javascript:', function(){ expect('jav ascript:alert("A");').not.toBeValidUrl(); expect('jav ascript:alert("B");').not.toBeValidUrl(); expect('jav ascript:alert("C");').not.toBeValidUrl(); expect('jav\u0000ascript:alert("D");').not.toBeValidUrl(); expect('java\u0000\u0000script:alert("D");').not.toBeValidUrl(); expect('  java\u0000\u0000script:alert("D");').not.toBeValidUrl(); }); }); }); });