2016-06-23 12:47:54 -04:00
|
|
|
/**
|
|
|
|
* @license
|
2020-05-19 15:08:49 -04:00
|
|
|
* Copyright Google LLC All Rights Reserved.
|
2016-06-23 12:47:54 -04:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
import {DomElementSchemaRegistry} from '@angular/compiler/src/schema/dom_element_schema_registry';
|
2016-08-19 19:05:34 -04:00
|
|
|
import {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA, SecurityContext} from '@angular/core';
|
2017-03-02 15:12:46 -05:00
|
|
|
import {browserDetection} from '@angular/platform-browser/testing/src/browser_util';
|
2016-05-10 20:47:17 -04:00
|
|
|
|
2016-08-01 15:19:09 -04:00
|
|
|
import {Element} from '../../src/ml_parser/ast';
|
|
|
|
import {HtmlParser} from '../../src/ml_parser/html_parser';
|
2016-07-21 14:41:25 -04:00
|
|
|
|
2016-04-28 20:50:03 -04:00
|
|
|
import {extractSchema} from './schema_extractor';
|
2015-07-29 08:01:18 -04:00
|
|
|
|
2017-12-16 17:42:55 -05:00
|
|
|
{
|
2015-07-29 08:01:18 -04:00
|
|
|
describe('DOMElementSchema', () => {
|
feat: security implementation in Angular 2.
Summary:
This adds basic security hooks to Angular 2.
* `SecurityContext` is a private API between core, compiler, and
platform-browser. `SecurityContext` communicates what context a value is used
in across template parser, compiler, and sanitization at runtime.
* `SanitizationService` is the bare bones interface to sanitize values for a
particular context.
* `SchemaElementRegistry.securityContext(tagName, attributeOrPropertyName)`
determines the security context for an attribute or property (it turns out
attributes and properties match for the purposes of sanitization).
Based on these hooks:
* `DomSchemaElementRegistry` decides what sanitization applies in a particular
context.
* `DomSanitizationService` implements `SanitizationService` and adds *Safe
Value*s, i.e. the ability to mark a value as safe and not requiring further
sanitization.
* `url_sanitizer` and `style_sanitizer` sanitize URLs and Styles, respectively
(surprise!).
`DomSanitizationService` is the default implementation bound for browser
applications, in the three contexts (browser rendering, web worker rendering,
server side rendering).
BREAKING CHANGES:
*** SECURITY WARNING ***
Angular 2 Release Candidates do not implement proper contextual escaping yet.
Make sure to correctly escape all values that go into the DOM.
*** SECURITY WARNING ***
Reviewers: IgorMinar
Differential Revision: https://reviews.angular.io/D103
2016-04-29 19:04:08 -04:00
|
|
|
let registry: DomElementSchemaRegistry;
|
2020-04-08 13:14:18 -04:00
|
|
|
beforeEach(() => {
|
|
|
|
registry = new DomElementSchemaRegistry();
|
|
|
|
});
|
2015-07-29 08:01:18 -04:00
|
|
|
|
2016-08-23 13:52:40 -04:00
|
|
|
it('should detect elements', () => {
|
|
|
|
expect(registry.hasElement('div', [])).toBeTruthy();
|
|
|
|
expect(registry.hasElement('b', [])).toBeTruthy();
|
|
|
|
expect(registry.hasElement('ng-container', [])).toBeTruthy();
|
|
|
|
expect(registry.hasElement('ng-content', [])).toBeTruthy();
|
|
|
|
|
|
|
|
expect(registry.hasElement('my-cmp', [])).toBeFalsy();
|
|
|
|
expect(registry.hasElement('abc', [])).toBeFalsy();
|
|
|
|
});
|
|
|
|
|
2016-09-01 22:37:09 -04:00
|
|
|
// https://github.com/angular/angular/issues/11219
|
|
|
|
it('should detect elements missing from chrome', () => {
|
|
|
|
expect(registry.hasElement('data', [])).toBeTruthy();
|
|
|
|
expect(registry.hasElement('menuitem', [])).toBeTruthy();
|
|
|
|
expect(registry.hasElement('summary', [])).toBeTruthy();
|
|
|
|
expect(registry.hasElement('time', [])).toBeTruthy();
|
|
|
|
});
|
|
|
|
|
2015-07-29 08:01:18 -04:00
|
|
|
it('should detect properties on regular elements', () => {
|
2016-07-25 06:02:57 -04:00
|
|
|
expect(registry.hasProperty('div', 'id', [])).toBeTruthy();
|
|
|
|
expect(registry.hasProperty('div', 'title', [])).toBeTruthy();
|
|
|
|
expect(registry.hasProperty('h1', 'align', [])).toBeTruthy();
|
|
|
|
expect(registry.hasProperty('h2', 'align', [])).toBeTruthy();
|
|
|
|
expect(registry.hasProperty('h3', 'align', [])).toBeTruthy();
|
|
|
|
expect(registry.hasProperty('h4', 'align', [])).toBeTruthy();
|
|
|
|
expect(registry.hasProperty('h5', 'align', [])).toBeTruthy();
|
|
|
|
expect(registry.hasProperty('h6', 'align', [])).toBeTruthy();
|
|
|
|
expect(registry.hasProperty('h7', 'align', [])).toBeFalsy();
|
|
|
|
expect(registry.hasProperty('textarea', 'disabled', [])).toBeTruthy();
|
|
|
|
expect(registry.hasProperty('input', 'disabled', [])).toBeTruthy();
|
|
|
|
expect(registry.hasProperty('div', 'unknown', [])).toBeFalsy();
|
2015-07-29 08:01:18 -04:00
|
|
|
});
|
|
|
|
|
2016-09-01 22:37:09 -04:00
|
|
|
// https://github.com/angular/angular/issues/11219
|
|
|
|
it('should detect properties on elements missing from Chrome', () => {
|
|
|
|
expect(registry.hasProperty('data', 'value', [])).toBeTruthy();
|
|
|
|
|
|
|
|
expect(registry.hasProperty('menuitem', 'type', [])).toBeTruthy();
|
|
|
|
expect(registry.hasProperty('menuitem', 'default', [])).toBeTruthy();
|
|
|
|
|
|
|
|
expect(registry.hasProperty('time', 'dateTime', [])).toBeTruthy();
|
|
|
|
});
|
|
|
|
|
feat: security implementation in Angular 2.
Summary:
This adds basic security hooks to Angular 2.
* `SecurityContext` is a private API between core, compiler, and
platform-browser. `SecurityContext` communicates what context a value is used
in across template parser, compiler, and sanitization at runtime.
* `SanitizationService` is the bare bones interface to sanitize values for a
particular context.
* `SchemaElementRegistry.securityContext(tagName, attributeOrPropertyName)`
determines the security context for an attribute or property (it turns out
attributes and properties match for the purposes of sanitization).
Based on these hooks:
* `DomSchemaElementRegistry` decides what sanitization applies in a particular
context.
* `DomSanitizationService` implements `SanitizationService` and adds *Safe
Value*s, i.e. the ability to mark a value as safe and not requiring further
sanitization.
* `url_sanitizer` and `style_sanitizer` sanitize URLs and Styles, respectively
(surprise!).
`DomSanitizationService` is the default implementation bound for browser
applications, in the three contexts (browser rendering, web worker rendering,
server side rendering).
BREAKING CHANGES:
*** SECURITY WARNING ***
Angular 2 Release Candidates do not implement proper contextual escaping yet.
Make sure to correctly escape all values that go into the DOM.
*** SECURITY WARNING ***
Reviewers: IgorMinar
Differential Revision: https://reviews.angular.io/D103
2016-04-29 19:04:08 -04:00
|
|
|
it('should detect different kinds of types', () => {
|
2016-09-01 20:32:47 -04:00
|
|
|
// inheritance: video => media => [HTMLElement] => [Element]
|
|
|
|
expect(registry.hasProperty('video', 'className', [])).toBeTruthy(); // from [Element]
|
2016-07-25 06:02:57 -04:00
|
|
|
expect(registry.hasProperty('video', 'id', [])).toBeTruthy(); // string
|
|
|
|
expect(registry.hasProperty('video', 'scrollLeft', [])).toBeTruthy(); // number
|
|
|
|
expect(registry.hasProperty('video', 'height', [])).toBeTruthy(); // number
|
|
|
|
expect(registry.hasProperty('video', 'autoplay', [])).toBeTruthy(); // boolean
|
|
|
|
expect(registry.hasProperty('video', 'classList', [])).toBeTruthy(); // object
|
feat: security implementation in Angular 2.
Summary:
This adds basic security hooks to Angular 2.
* `SecurityContext` is a private API between core, compiler, and
platform-browser. `SecurityContext` communicates what context a value is used
in across template parser, compiler, and sanitization at runtime.
* `SanitizationService` is the bare bones interface to sanitize values for a
particular context.
* `SchemaElementRegistry.securityContext(tagName, attributeOrPropertyName)`
determines the security context for an attribute or property (it turns out
attributes and properties match for the purposes of sanitization).
Based on these hooks:
* `DomSchemaElementRegistry` decides what sanitization applies in a particular
context.
* `DomSanitizationService` implements `SanitizationService` and adds *Safe
Value*s, i.e. the ability to mark a value as safe and not requiring further
sanitization.
* `url_sanitizer` and `style_sanitizer` sanitize URLs and Styles, respectively
(surprise!).
`DomSanitizationService` is the default implementation bound for browser
applications, in the three contexts (browser rendering, web worker rendering,
server side rendering).
BREAKING CHANGES:
*** SECURITY WARNING ***
Angular 2 Release Candidates do not implement proper contextual escaping yet.
Make sure to correctly escape all values that go into the DOM.
*** SECURITY WARNING ***
Reviewers: IgorMinar
Differential Revision: https://reviews.angular.io/D103
2016-04-29 19:04:08 -04:00
|
|
|
// from *; but events are not properties
|
2016-07-25 06:02:57 -04:00
|
|
|
expect(registry.hasProperty('video', 'click', [])).toBeFalsy();
|
feat: security implementation in Angular 2.
Summary:
This adds basic security hooks to Angular 2.
* `SecurityContext` is a private API between core, compiler, and
platform-browser. `SecurityContext` communicates what context a value is used
in across template parser, compiler, and sanitization at runtime.
* `SanitizationService` is the bare bones interface to sanitize values for a
particular context.
* `SchemaElementRegistry.securityContext(tagName, attributeOrPropertyName)`
determines the security context for an attribute or property (it turns out
attributes and properties match for the purposes of sanitization).
Based on these hooks:
* `DomSchemaElementRegistry` decides what sanitization applies in a particular
context.
* `DomSanitizationService` implements `SanitizationService` and adds *Safe
Value*s, i.e. the ability to mark a value as safe and not requiring further
sanitization.
* `url_sanitizer` and `style_sanitizer` sanitize URLs and Styles, respectively
(surprise!).
`DomSanitizationService` is the default implementation bound for browser
applications, in the three contexts (browser rendering, web worker rendering,
server side rendering).
BREAKING CHANGES:
*** SECURITY WARNING ***
Angular 2 Release Candidates do not implement proper contextual escaping yet.
Make sure to correctly escape all values that go into the DOM.
*** SECURITY WARNING ***
Reviewers: IgorMinar
Differential Revision: https://reviews.angular.io/D103
2016-04-29 19:04:08 -04:00
|
|
|
});
|
2016-04-28 20:50:03 -04:00
|
|
|
|
2016-07-26 14:25:38 -04:00
|
|
|
it('should treat custom elements as an unknown element by default', () => {
|
|
|
|
expect(registry.hasProperty('custom-like', 'unknown', [])).toBe(false);
|
|
|
|
expect(registry.hasProperty('custom-like', 'className', [])).toBeTruthy();
|
|
|
|
expect(registry.hasProperty('custom-like', 'style', [])).toBeTruthy();
|
|
|
|
expect(registry.hasProperty('custom-like', 'id', [])).toBeTruthy();
|
|
|
|
});
|
2016-07-25 06:02:57 -04:00
|
|
|
|
|
|
|
it('should return true for custom-like elements if the CUSTOM_ELEMENTS_SCHEMA was used', () => {
|
|
|
|
expect(registry.hasProperty('custom-like', 'unknown', [CUSTOM_ELEMENTS_SCHEMA])).toBeTruthy();
|
2016-08-23 13:52:40 -04:00
|
|
|
|
|
|
|
expect(registry.hasElement('custom-like', [CUSTOM_ELEMENTS_SCHEMA])).toBeTruthy();
|
2016-07-25 06:02:57 -04:00
|
|
|
});
|
2015-07-29 08:01:18 -04:00
|
|
|
|
2016-08-19 19:05:34 -04:00
|
|
|
it('should return true for all elements if the NO_ERRORS_SCHEMA was used', () => {
|
|
|
|
expect(registry.hasProperty('custom-like', 'unknown', [NO_ERRORS_SCHEMA])).toBeTruthy();
|
|
|
|
expect(registry.hasProperty('a', 'unknown', [NO_ERRORS_SCHEMA])).toBeTruthy();
|
2016-08-23 13:52:40 -04:00
|
|
|
|
|
|
|
expect(registry.hasElement('custom-like', [NO_ERRORS_SCHEMA])).toBeTruthy();
|
|
|
|
expect(registry.hasElement('unknown', [NO_ERRORS_SCHEMA])).toBeTruthy();
|
2016-08-19 19:05:34 -04:00
|
|
|
});
|
|
|
|
|
2020-04-08 13:14:18 -04:00
|
|
|
it('should re-map property names that are specified in DOM facade', () => {
|
|
|
|
expect(registry.getMappedPropName('readonly')).toEqual('readOnly');
|
|
|
|
});
|
2015-07-29 08:01:18 -04:00
|
|
|
|
|
|
|
it('should not re-map property names that are not specified in DOM facade', () => {
|
|
|
|
expect(registry.getMappedPropName('title')).toEqual('title');
|
|
|
|
expect(registry.getMappedPropName('exotic-unknown')).toEqual('exotic-unknown');
|
|
|
|
});
|
2015-12-06 07:21:34 -05:00
|
|
|
|
2016-09-27 20:10:02 -04:00
|
|
|
it('should return an error message when asserting event properties', () => {
|
|
|
|
let report = registry.validateProperty('onClick');
|
|
|
|
expect(report.error).toBeTruthy();
|
|
|
|
expect(report.msg)
|
|
|
|
.toEqual(
|
|
|
|
`Binding to event property 'onClick' is disallowed for security reasons, please use (Click)=...
|
|
|
|
If 'onClick' is a directive input, make sure the directive is imported by the current module.`);
|
|
|
|
|
|
|
|
report = registry.validateProperty('onAnything');
|
|
|
|
expect(report.error).toBeTruthy();
|
|
|
|
expect(report.msg)
|
|
|
|
.toEqual(
|
|
|
|
`Binding to event property 'onAnything' is disallowed for security reasons, please use (Anything)=...
|
|
|
|
If 'onAnything' is a directive input, make sure the directive is imported by the current module.`);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should return an error message when asserting event attributes', () => {
|
|
|
|
let report = registry.validateAttribute('onClick');
|
|
|
|
expect(report.error).toBeTruthy();
|
|
|
|
expect(report.msg)
|
|
|
|
.toEqual(
|
|
|
|
`Binding to event attribute 'onClick' is disallowed for security reasons, please use (Click)=...`);
|
|
|
|
|
|
|
|
report = registry.validateAttribute('onAnything');
|
|
|
|
expect(report.error).toBeTruthy();
|
|
|
|
expect(report.msg)
|
|
|
|
.toEqual(
|
|
|
|
`Binding to event attribute 'onAnything' is disallowed for security reasons, please use (Anything)=...`);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should not return an error message when asserting non-event properties or attributes',
|
|
|
|
() => {
|
|
|
|
let report = registry.validateProperty('title');
|
|
|
|
expect(report.error).toBeFalsy();
|
|
|
|
expect(report.msg).not.toBeDefined();
|
|
|
|
|
|
|
|
report = registry.validateProperty('exotic-unknown');
|
|
|
|
expect(report.error).toBeFalsy();
|
|
|
|
expect(report.msg).not.toBeDefined();
|
|
|
|
});
|
|
|
|
|
2016-05-04 13:26:17 -04:00
|
|
|
it('should return security contexts for elements', () => {
|
2016-10-24 12:58:52 -04:00
|
|
|
expect(registry.securityContext('iframe', 'srcdoc', false)).toBe(SecurityContext.HTML);
|
|
|
|
expect(registry.securityContext('p', 'innerHTML', false)).toBe(SecurityContext.HTML);
|
|
|
|
expect(registry.securityContext('a', 'href', false)).toBe(SecurityContext.URL);
|
|
|
|
expect(registry.securityContext('a', 'style', false)).toBe(SecurityContext.STYLE);
|
|
|
|
expect(registry.securityContext('ins', 'cite', false)).toBe(SecurityContext.URL);
|
|
|
|
expect(registry.securityContext('base', 'href', false)).toBe(SecurityContext.RESOURCE_URL);
|
2016-05-04 13:26:17 -04:00
|
|
|
});
|
feat: security implementation in Angular 2.
Summary:
This adds basic security hooks to Angular 2.
* `SecurityContext` is a private API between core, compiler, and
platform-browser. `SecurityContext` communicates what context a value is used
in across template parser, compiler, and sanitization at runtime.
* `SanitizationService` is the bare bones interface to sanitize values for a
particular context.
* `SchemaElementRegistry.securityContext(tagName, attributeOrPropertyName)`
determines the security context for an attribute or property (it turns out
attributes and properties match for the purposes of sanitization).
Based on these hooks:
* `DomSchemaElementRegistry` decides what sanitization applies in a particular
context.
* `DomSanitizationService` implements `SanitizationService` and adds *Safe
Value*s, i.e. the ability to mark a value as safe and not requiring further
sanitization.
* `url_sanitizer` and `style_sanitizer` sanitize URLs and Styles, respectively
(surprise!).
`DomSanitizationService` is the default implementation bound for browser
applications, in the three contexts (browser rendering, web worker rendering,
server side rendering).
BREAKING CHANGES:
*** SECURITY WARNING ***
Angular 2 Release Candidates do not implement proper contextual escaping yet.
Make sure to correctly escape all values that go into the DOM.
*** SECURITY WARNING ***
Reviewers: IgorMinar
Differential Revision: https://reviews.angular.io/D103
2016-04-29 19:04:08 -04:00
|
|
|
|
2016-05-26 19:17:35 -04:00
|
|
|
it('should detect properties on namespaced elements', () => {
|
2016-06-24 17:31:35 -04:00
|
|
|
const htmlAst = new HtmlParser().parse('<svg:style>', 'TestComp');
|
2016-07-21 16:56:58 -04:00
|
|
|
const nodeName = (<Element>htmlAst.rootNodes[0]).name;
|
2016-07-25 06:02:57 -04:00
|
|
|
expect(registry.hasProperty(nodeName, 'type', [])).toBeTruthy();
|
2016-05-26 19:17:35 -04:00
|
|
|
});
|
2016-04-28 20:50:03 -04:00
|
|
|
|
2016-05-26 17:35:27 -04:00
|
|
|
it('should check security contexts case insensitive', () => {
|
2016-10-24 12:58:52 -04:00
|
|
|
expect(registry.securityContext('p', 'iNnErHtMl', false)).toBe(SecurityContext.HTML);
|
|
|
|
expect(registry.securityContext('p', 'formaction', false)).toBe(SecurityContext.URL);
|
|
|
|
expect(registry.securityContext('p', 'formAction', false)).toBe(SecurityContext.URL);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should check security contexts for attributes', () => {
|
|
|
|
expect(registry.securityContext('p', 'innerHtml', true)).toBe(SecurityContext.HTML);
|
|
|
|
expect(registry.securityContext('p', 'formaction', true)).toBe(SecurityContext.URL);
|
2016-05-26 17:35:27 -04:00
|
|
|
});
|
|
|
|
|
2016-06-15 12:57:58 -04:00
|
|
|
describe('Angular custom elements', () => {
|
2020-04-08 13:14:18 -04:00
|
|
|
it('should support <ng-container>', () => {
|
|
|
|
expect(registry.hasProperty('ng-container', 'id', [])).toBeFalsy();
|
|
|
|
});
|
2016-06-15 12:57:58 -04:00
|
|
|
|
|
|
|
it('should support <ng-content>', () => {
|
2016-07-25 06:02:57 -04:00
|
|
|
expect(registry.hasProperty('ng-content', 'id', [])).toBeFalsy();
|
|
|
|
expect(registry.hasProperty('ng-content', 'select', [])).toBeFalsy();
|
2016-06-15 12:57:58 -04:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-05-10 20:47:17 -04:00
|
|
|
if (browserDetection.isChromeDesktop) {
|
|
|
|
it('generate a new schema', () => {
|
2016-06-02 13:27:33 -04:00
|
|
|
let schema = '\n';
|
2020-04-08 13:14:18 -04:00
|
|
|
extractSchema()!.forEach((props, name) => {
|
|
|
|
schema += `'${name}|${props.join(',')}',\n`;
|
|
|
|
});
|
2016-06-02 13:27:33 -04:00
|
|
|
// Uncomment this line to see:
|
|
|
|
// the generated schema which can then be pasted to the DomElementSchemaRegistry
|
2016-06-08 19:38:52 -04:00
|
|
|
// console.log(schema);
|
2016-05-10 20:47:17 -04:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-11-08 18:45:30 -05:00
|
|
|
describe('normalizeAnimationStyleProperty', () => {
|
|
|
|
it('should normalize the given CSS property to camelCase', () => {
|
|
|
|
expect(registry.normalizeAnimationStyleProperty('border-radius')).toBe('borderRadius');
|
|
|
|
expect(registry.normalizeAnimationStyleProperty('zIndex')).toBe('zIndex');
|
|
|
|
expect(registry.normalizeAnimationStyleProperty('-webkit-animation'))
|
|
|
|
.toBe('WebkitAnimation');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('normalizeAnimationStyleValue', () => {
|
|
|
|
it('should normalize the given dimensional CSS style value to contain a PX value when numeric',
|
|
|
|
() => {
|
|
|
|
expect(
|
|
|
|
registry.normalizeAnimationStyleValue('borderRadius', 'border-radius', 10)['value'])
|
|
|
|
.toBe('10px');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should not normalize any values that are of zero', () => {
|
|
|
|
expect(registry.normalizeAnimationStyleValue('opacity', 'opacity', 0)['value']).toBe('0');
|
|
|
|
expect(registry.normalizeAnimationStyleValue('width', 'width', 0)['value']).toBe('0');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should retain the given dimensional CSS style value\'s unit if it already exists', () => {
|
|
|
|
expect(
|
|
|
|
registry.normalizeAnimationStyleValue('borderRadius', 'border-radius', '10em')['value'])
|
|
|
|
.toBe('10em');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should trim the provided CSS style value', () => {
|
|
|
|
expect(registry.normalizeAnimationStyleValue('color', 'color', ' red ')['value'])
|
|
|
|
.toBe('red');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should stringify all non dimensional numeric style values', () => {
|
|
|
|
expect(registry.normalizeAnimationStyleValue('zIndex', 'zIndex', 10)['value']).toBe('10');
|
|
|
|
expect(registry.normalizeAnimationStyleValue('opacity', 'opacity', 0.5)['value'])
|
|
|
|
.toBe('0.5');
|
|
|
|
});
|
|
|
|
});
|
2015-07-29 08:01:18 -04:00
|
|
|
});
|
|
|
|
}
|