2018-03-01 20:14:01 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @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
|
|
|
|
*/
|
|
|
|
|
2019-01-03 13:04:06 -05:00
|
|
|
import {SECURITY_SCHEMA} from '@angular/compiler/src/schema/dom_security_schema';
|
2019-01-28 17:45:31 -05:00
|
|
|
import {HEADER_OFFSET, LView} from '@angular/core/src/render3/interfaces/view';
|
2018-11-22 00:14:06 -05:00
|
|
|
import {setTNodeAndViewData} from '@angular/core/src/render3/state';
|
|
|
|
|
2018-07-11 13:58:18 -04:00
|
|
|
import {bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript, bypassSanitizationTrustStyle, bypassSanitizationTrustUrl} from '../../src/sanitization/bypass';
|
2019-05-17 21:49:21 -04:00
|
|
|
import {getUrlSanitizer, ɵɵsanitizeHtml, ɵɵsanitizeResourceUrl, ɵɵsanitizeScript, ɵɵsanitizeStyle, ɵɵsanitizeUrl, ɵɵsanitizeUrlOrResourceUrl} from '../../src/sanitization/sanitization';
|
2019-01-03 13:04:06 -05:00
|
|
|
import {SecurityContext} from '../../src/sanitization/security';
|
2018-03-01 20:14:01 -05:00
|
|
|
|
2019-01-28 17:45:31 -05:00
|
|
|
function fakeLView(): LView {
|
2019-02-23 14:14:35 -05:00
|
|
|
return [null, {}] as LView;
|
2019-01-28 17:45:31 -05:00
|
|
|
}
|
|
|
|
|
2018-03-01 20:14:01 -05:00
|
|
|
describe('sanitization', () => {
|
2019-01-28 17:45:31 -05:00
|
|
|
beforeEach(() => setTNodeAndViewData(null !, fakeLView()));
|
2018-11-22 00:14:06 -05:00
|
|
|
afterEach(() => setTNodeAndViewData(null !, null !));
|
2018-03-01 20:14:01 -05:00
|
|
|
class Wrap {
|
|
|
|
constructor(private value: string) {}
|
|
|
|
toString() { return this.value; }
|
|
|
|
}
|
|
|
|
it('should sanitize html', () => {
|
2019-05-17 21:49:21 -04:00
|
|
|
expect(ɵɵsanitizeHtml('<div></div>')).toEqual('<div></div>');
|
|
|
|
expect(ɵɵsanitizeHtml(new Wrap('<div></div>'))).toEqual('<div></div>');
|
|
|
|
expect(ɵɵsanitizeHtml('<img src="javascript:true">'))
|
2018-03-01 20:14:01 -05:00
|
|
|
.toEqual('<img src="unsafe:javascript:true">');
|
2019-05-17 21:49:21 -04:00
|
|
|
expect(ɵɵsanitizeHtml(new Wrap('<img src="javascript:true">')))
|
2018-03-01 20:14:01 -05:00
|
|
|
.toEqual('<img src="unsafe:javascript:true">');
|
2019-07-31 16:15:50 -04:00
|
|
|
expect(() => ɵɵsanitizeHtml(bypassSanitizationTrustUrl('<img src="javascript:true">')))
|
|
|
|
.toThrowError(/Required a safe HTML, got a URL/);
|
2019-05-17 21:49:21 -04:00
|
|
|
expect(ɵɵsanitizeHtml(bypassSanitizationTrustHtml('<img src="javascript:true">')))
|
2018-03-01 20:14:01 -05:00
|
|
|
.toEqual('<img src="javascript:true">');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should sanitize url', () => {
|
2019-05-17 21:49:21 -04:00
|
|
|
expect(ɵɵsanitizeUrl('http://server')).toEqual('http://server');
|
|
|
|
expect(ɵɵsanitizeUrl(new Wrap('http://server'))).toEqual('http://server');
|
|
|
|
expect(ɵɵsanitizeUrl('javascript:true')).toEqual('unsafe:javascript:true');
|
|
|
|
expect(ɵɵsanitizeUrl(new Wrap('javascript:true'))).toEqual('unsafe:javascript:true');
|
2019-07-31 16:15:50 -04:00
|
|
|
expect(() => ɵɵsanitizeUrl(bypassSanitizationTrustHtml('javascript:true')))
|
|
|
|
.toThrowError(/Required a safe URL, got a HTML/);
|
2019-05-17 21:49:21 -04:00
|
|
|
expect(ɵɵsanitizeUrl(bypassSanitizationTrustUrl('javascript:true'))).toEqual('javascript:true');
|
2018-03-01 20:14:01 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should sanitize resourceUrl', () => {
|
|
|
|
const ERROR = 'unsafe value used in a resource URL context (see http://g.co/ng/security#xss)';
|
2019-05-17 21:49:21 -04:00
|
|
|
expect(() => ɵɵsanitizeResourceUrl('http://server')).toThrowError(ERROR);
|
|
|
|
expect(() => ɵɵsanitizeResourceUrl('javascript:true')).toThrowError(ERROR);
|
|
|
|
expect(() => ɵɵsanitizeResourceUrl(bypassSanitizationTrustHtml('javascript:true')))
|
2019-07-31 16:15:50 -04:00
|
|
|
.toThrowError(/Required a safe ResourceURL, got a HTML/);
|
2019-05-17 21:49:21 -04:00
|
|
|
expect(ɵɵsanitizeResourceUrl(bypassSanitizationTrustResourceUrl('javascript:true')))
|
2018-03-01 20:14:01 -05:00
|
|
|
.toEqual('javascript:true');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should sanitize style', () => {
|
2019-05-17 21:49:21 -04:00
|
|
|
expect(ɵɵsanitizeStyle('red')).toEqual('red');
|
|
|
|
expect(ɵɵsanitizeStyle(new Wrap('red'))).toEqual('red');
|
|
|
|
expect(ɵɵsanitizeStyle('url("http://server")')).toEqual('unsafe');
|
|
|
|
expect(ɵɵsanitizeStyle(new Wrap('url("http://server")'))).toEqual('unsafe');
|
2019-07-31 16:15:50 -04:00
|
|
|
expect(() => ɵɵsanitizeStyle(bypassSanitizationTrustHtml('url("http://server")')))
|
|
|
|
.toThrowError(/Required a safe Style, got a HTML/);
|
2019-05-17 21:49:21 -04:00
|
|
|
expect(ɵɵsanitizeStyle(bypassSanitizationTrustStyle('url("http://server")')))
|
2018-03-01 20:14:01 -05:00
|
|
|
.toEqual('url("http://server")');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should sanitize script', () => {
|
|
|
|
const ERROR = 'unsafe value used in a script context';
|
2019-05-17 21:49:21 -04:00
|
|
|
expect(() => ɵɵsanitizeScript('true')).toThrowError(ERROR);
|
|
|
|
expect(() => ɵɵsanitizeScript('true')).toThrowError(ERROR);
|
2019-07-31 16:15:50 -04:00
|
|
|
expect(() => ɵɵsanitizeScript(bypassSanitizationTrustHtml('true')))
|
|
|
|
.toThrowError(/Required a safe Script, got a HTML/);
|
2019-05-17 21:49:21 -04:00
|
|
|
expect(ɵɵsanitizeScript(bypassSanitizationTrustScript('true'))).toEqual('true');
|
2018-03-01 20:14:01 -05:00
|
|
|
});
|
2019-01-03 13:04:06 -05:00
|
|
|
|
|
|
|
it('should select correct sanitizer for URL props', () => {
|
|
|
|
// making sure security schema we have on compiler side is in sync with the `getUrlSanitizer`
|
|
|
|
// runtime function definition
|
|
|
|
const schema = SECURITY_SCHEMA();
|
|
|
|
const contextsByProp: Map<string, Set<number>> = new Map();
|
2019-04-04 14:41:52 -04:00
|
|
|
const sanitizerNameByContext: Map<number, Function> = new Map([
|
2019-05-17 21:49:21 -04:00
|
|
|
[SecurityContext.URL, ɵɵsanitizeUrl], [SecurityContext.RESOURCE_URL, ɵɵsanitizeResourceUrl]
|
2019-01-03 13:04:06 -05:00
|
|
|
]);
|
|
|
|
Object.keys(schema).forEach(key => {
|
|
|
|
const context = schema[key];
|
|
|
|
if (context === SecurityContext.URL || SecurityContext.RESOURCE_URL) {
|
|
|
|
const [tag, prop] = key.split('|');
|
|
|
|
const contexts = contextsByProp.get(prop) || new Set<number>();
|
|
|
|
contexts.add(context);
|
|
|
|
contextsByProp.set(prop, contexts);
|
|
|
|
// check only in case a prop can be a part of both URL contexts
|
|
|
|
if (contexts.size === 2) {
|
2019-04-04 14:41:52 -04:00
|
|
|
expect(getUrlSanitizer(tag, prop)).toEqual(sanitizerNameByContext.get(context) !);
|
2019-01-03 13:04:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should sanitize resourceUrls via sanitizeUrlOrResourceUrl', () => {
|
|
|
|
const ERROR = 'unsafe value used in a resource URL context (see http://g.co/ng/security#xss)';
|
2019-05-17 21:49:21 -04:00
|
|
|
expect(() => ɵɵsanitizeUrlOrResourceUrl('http://server', 'iframe', 'src')).toThrowError(ERROR);
|
|
|
|
expect(() => ɵɵsanitizeUrlOrResourceUrl('javascript:true', 'iframe', 'src'))
|
|
|
|
.toThrowError(ERROR);
|
2019-01-03 13:04:06 -05:00
|
|
|
expect(
|
2019-05-17 21:49:21 -04:00
|
|
|
() => ɵɵsanitizeUrlOrResourceUrl(
|
2019-01-03 13:04:06 -05:00
|
|
|
bypassSanitizationTrustHtml('javascript:true'), 'iframe', 'src'))
|
2019-07-31 16:15:50 -04:00
|
|
|
.toThrowError(/Required a safe ResourceURL, got a HTML/);
|
2019-05-17 21:49:21 -04:00
|
|
|
expect(ɵɵsanitizeUrlOrResourceUrl(
|
2019-01-03 13:04:06 -05:00
|
|
|
bypassSanitizationTrustResourceUrl('javascript:true'), 'iframe', 'src'))
|
|
|
|
.toEqual('javascript:true');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should sanitize urls via sanitizeUrlOrResourceUrl', () => {
|
2019-05-17 21:49:21 -04:00
|
|
|
expect(ɵɵsanitizeUrlOrResourceUrl('http://server', 'a', 'href')).toEqual('http://server');
|
|
|
|
expect(ɵɵsanitizeUrlOrResourceUrl(new Wrap('http://server'), 'a', 'href'))
|
2019-01-03 13:04:06 -05:00
|
|
|
.toEqual('http://server');
|
2019-05-17 21:49:21 -04:00
|
|
|
expect(ɵɵsanitizeUrlOrResourceUrl('javascript:true', 'a', 'href'))
|
2019-01-03 13:04:06 -05:00
|
|
|
.toEqual('unsafe:javascript:true');
|
2019-05-17 21:49:21 -04:00
|
|
|
expect(ɵɵsanitizeUrlOrResourceUrl(new Wrap('javascript:true'), 'a', 'href'))
|
2019-01-03 13:04:06 -05:00
|
|
|
.toEqual('unsafe:javascript:true');
|
2019-07-31 16:15:50 -04:00
|
|
|
expect(
|
|
|
|
() =>
|
|
|
|
ɵɵsanitizeUrlOrResourceUrl(bypassSanitizationTrustHtml('javascript:true'), 'a', 'href'))
|
|
|
|
.toThrowError(/Required a safe URL, got a HTML/);
|
2019-05-17 21:49:21 -04:00
|
|
|
expect(ɵɵsanitizeUrlOrResourceUrl(bypassSanitizationTrustUrl('javascript:true'), 'a', 'href'))
|
2019-01-03 13:04:06 -05:00
|
|
|
.toEqual('javascript:true');
|
|
|
|
});
|
2018-07-11 13:58:18 -04:00
|
|
|
});
|