Allow more elements and attributes from the HTML5 spec which were stripped by the htmlSanitizer. fixes #9438 feat(security): allow audio data URLs in urlSanitizer test(security) : add test for valid audio data URL feat(security): allow and sanitize srcset attributes test(security): test for srcset sanitization
		
			
				
	
	
		
			119 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			119 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| /**
 | |
|  * @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 {getDOM} from '../../src/dom/dom_adapter';
 | |
| import {sanitizeSrcset, sanitizeUrl} from '../../src/security/url_sanitizer';
 | |
| 
 | |
| export function main() {
 | |
|   t.describe('URL sanitizer', () => {
 | |
|     let logMsgs: string[];
 | |
|     let originalLog: (msg: any) => any;
 | |
| 
 | |
|     t.beforeEach(() => {
 | |
|       logMsgs = [];
 | |
|       originalLog = getDOM().log;  // Monkey patch DOM.log.
 | |
|       getDOM().log = (msg) => logMsgs.push(msg);
 | |
|     });
 | |
|     t.afterEach(() => { getDOM().log = originalLog; });
 | |
| 
 | |
|     t.it('reports unsafe URLs', () => {
 | |
|       t.expect(sanitizeUrl('javascript:evil()')).toBe('unsafe:javascript:evil()');
 | |
|       t.expect(logMsgs.join('\n')).toMatch(/sanitizing unsafe URL value/);
 | |
|     });
 | |
| 
 | |
|     t.describe('valid URLs', () => {
 | |
|       const validUrls = [
 | |
|         '',
 | |
|         'http://abc',
 | |
|         'HTTP://abc',
 | |
|         'https://abc',
 | |
|         'HTTPS://abc',
 | |
|         'ftp://abc',
 | |
|         'FTP://abc',
 | |
|         'mailto:me@example.com',
 | |
|         'MAILTO:me@example.com',
 | |
|         'tel:123-123-1234',
 | |
|         'TEL:123-123-1234',
 | |
|         '#anchor',
 | |
|         '/page1.md',
 | |
|         'http://JavaScript/my.js',
 | |
|         'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/',  // Truncated.
 | |
|         'data:video/webm;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/',
 | |
|         'data:audio/opus;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/',
 | |
|       ];
 | |
|       for (let url of validUrls) {
 | |
|         t.it(`valid ${url}`, () => t.expect(sanitizeUrl(url)).toEqual(url));
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     t.describe('invalid URLs', () => {
 | |
|       const invalidUrls = [
 | |
|         'javascript:evil()',
 | |
|         'JavaScript:abc',
 | |
|         'evilNewProtocol:abc',
 | |
|         ' \n Java\n Script:abc',
 | |
|         'javascript:',
 | |
|         'javascript:',
 | |
|         'j avascript:',
 | |
|         'javascript:',
 | |
|         'javascript:',
 | |
|         'jav	ascript:alert();',
 | |
|         'jav\u0000ascript:alert();',
 | |
|         'data:;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/',
 | |
|         'data:,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/',
 | |
|         'data:iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/',
 | |
|         'data:text/javascript;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/',
 | |
|         'data:application/x-msdownload;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/',
 | |
|       ];
 | |
|       for (let url of invalidUrls) {
 | |
|         t.it(`valid ${url}`, () => t.expect(sanitizeUrl(url)).toMatch(/^unsafe:/));
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     t.describe('valid srcsets', () => {
 | |
|       const validSrcsets = [
 | |
|         '',
 | |
|         'http://angular.io/images/test.png',
 | |
|         'http://angular.io/images/test.png, http://angular.io/images/test.png',
 | |
|         'http://angular.io/images/test.png, http://angular.io/images/test.png, http://angular.io/images/test.png',
 | |
|         'http://angular.io/images/test.png 2x',
 | |
|         'http://angular.io/images/test.png 2x, http://angular.io/images/test.png 3x',
 | |
|         'http://angular.io/images/test.png 1.5x',
 | |
|         'http://angular.io/images/test.png 1.25x',
 | |
|         'http://angular.io/images/test.png 200w, http://angular.io/images/test.png 300w',
 | |
|         'https://angular.io/images/test.png, http://angular.io/images/test.png',
 | |
|         'http://angular.io:80/images/test.png, http://angular.io:8080/images/test.png',
 | |
|         'http://www.angular.io:80/images/test.png, http://www.angular.io:8080/images/test.png',
 | |
|         'https://angular.io/images/test.png, https://angular.io/images/test.png',
 | |
|         '//angular.io/images/test.png, //angular.io/images/test.png',
 | |
|         '/images/test.png, /images/test.png',
 | |
|         'images/test.png, images/test.png',
 | |
|         'http://angular.io/images/test.png?12345, http://angular.io/images/test.png?12345',
 | |
|         'http://angular.io/images/test.png?maxage, http://angular.io/images/test.png?maxage',
 | |
|         'http://angular.io/images/test.png?maxage=234, http://angular.io/images/test.png?maxage=234',
 | |
|       ];
 | |
|       for (let srcset of validSrcsets) {
 | |
|         t.it(`valid ${srcset}`, () => t.expect(sanitizeSrcset(srcset)).toEqual(srcset));
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     t.describe('invalid srcsets', () => {
 | |
|       const invalidSrcsets = [
 | |
|         'ht:tp://angular.io/images/test.png',
 | |
|         'http://angular.io/images/test.png, ht:tp://angular.io/images/test.png',
 | |
|       ];
 | |
|       for (let srcset of invalidSrcsets) {
 | |
|         t.it(`valid ${srcset}`, () => t.expect(sanitizeSrcset(srcset)).toMatch(/unsafe:/));
 | |
|       }
 | |
|     });
 | |
| 
 | |
|   });
 | |
| }
 |