fix(DomSchemaRegistry): detect invalid elements

This commit is contained in:
Victor Berchet
2016-08-23 10:52:40 -07:00
parent 2b20db6c5a
commit 1df69cb4d2
22 changed files with 638 additions and 395 deletions

View File

@ -27,8 +27,10 @@ export interface ModuleWithProviders {
export interface SchemaMetadata { name: string; }
/**
* Defines a schema that will allow any property on elements with a `-` in their name,
* which is the common rule for custom elements.
* Defines a schema that will allow:
* - any non-angular elements with a `-` in their name,
* - any properties on elements with a `-` in their name which is the common rule for custom
* elements.
*
* @stable
*/
@ -161,6 +163,18 @@ export class NgModuleMetadata extends InjectableMetadata implements NgModuleMeta
*/
bootstrap: Array<Type<any>|any[]>;
/**
* Elements and properties that are not angular Components nor Directives have to be declared in
* the schema.
*
* Available schemas:
* - `NO_ERRORS_SCHEMA`: any elements and properties are allowed,
* - `CUSTOM_ELEMENTS_SCHEMA`: any custom elements (tag name has "-") with any properties are
* allowed.
*
* @security When using one of `NO_ERRORS_SCHEMA` or `CUSTOM_ELEMENTS_SCHEMA` we're trusting that
* allowed elements (and its properties) securely escape inputs.
*/
schemas: Array<SchemaMetadata|any[]>;
constructor(options: NgModuleMetadataType = {}) {

View File

@ -7,7 +7,7 @@
*/
import {NgFor, NgIf} from '@angular/common';
import {Injectable} from '@angular/core';
import {Injectable, NO_ERRORS_SCHEMA} from '@angular/core';
import {Component, Directive, Input} from '@angular/core/src/metadata';
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
import {By} from '@angular/platform-browser/src/dom/debug/by';
@ -185,9 +185,8 @@ export function main() {
TestApp,
UsingFor,
],
providers: [
Logger,
]
providers: [Logger],
schemas: [NO_ERRORS_SCHEMA],
});
}));

View File

@ -7,7 +7,7 @@
*/
import {CommonModule} from '@angular/common';
import {Component, ContentChildren, Directive, Inject, NgModule, QueryList, asNativeElements, forwardRef} from '@angular/core';
import {Component, ContentChildren, Directive, Inject, NO_ERRORS_SCHEMA, NgModule, QueryList, asNativeElements, forwardRef} from '@angular/core';
import {TestBed} from '@angular/core/testing';
import {expect} from '@angular/platform-browser/testing/matchers';
@ -16,7 +16,7 @@ export function main() {
beforeEach(() => { TestBed.configureTestingModule({imports: [Module], declarations: [App]}); });
it('should instantiate components which are declared using forwardRef', () => {
const a = TestBed.createComponent(App);
const a = TestBed.configureTestingModule({schemas: [NO_ERRORS_SCHEMA]}).createComponent(App);
a.detectChanges();
expect(asNativeElements(a.debugElement.children)).toHaveText('frame(lock)');
expect(TestBed.get(ModuleFrame)).toBeDefined();

View File

@ -7,7 +7,7 @@
*/
import {CommonModule} from '@angular/common';
import {ComponentFactory, Host, Inject, Injectable, Injector, NgModule, OnDestroy, OpaqueToken, ReflectiveInjector, SkipSelf, SkipSelfMetadata, forwardRef} from '@angular/core';
import {ComponentFactory, Host, Inject, Injectable, Injector, NO_ERRORS_SCHEMA, NgModule, OnDestroy, OpaqueToken, ReflectiveInjector, SkipSelf, SkipSelfMetadata} from '@angular/core';
import {ChangeDetectionStrategy, ChangeDetectorRef, PipeTransform} from '@angular/core/src/change_detection/change_detection';
import {ComponentFactoryResolver} from '@angular/core/src/linker/component_factory_resolver';
import {ElementRef} from '@angular/core/src/linker/element_ref';
@ -304,7 +304,7 @@ function declareTests({useJit}: {useJit: boolean}) {
it('should support template directives via `<template>` elements.', () => {
TestBed.configureTestingModule({declarations: [MyComp, SomeViewport]});
const template =
'<template some-viewport let-greeting="someTmpl"><copy-me>{{greeting}}</copy-me></template>';
'<template some-viewport let-greeting="someTmpl"><span>{{greeting}}</span></template>';
TestBed.overrideComponent(MyComp, {set: {template}});
const fixture = TestBed.createComponent(MyComp);
@ -364,7 +364,7 @@ function declareTests({useJit}: {useJit: boolean}) {
it('should support template directives via `template` attribute.', () => {
TestBed.configureTestingModule({declarations: [MyComp, SomeViewport]});
const template =
'<copy-me template="some-viewport: let greeting=someTmpl">{{greeting}}</copy-me>';
'<span template="some-viewport: let greeting=someTmpl">{{greeting}}</span>';
TestBed.overrideComponent(MyComp, {set: {template}});
const fixture = TestBed.createComponent(MyComp);
@ -382,7 +382,8 @@ function declareTests({useJit}: {useJit: boolean}) {
declarations: [
MyComp, SomeDirective, CompWithHost, ToolbarComponent, ToolbarViewContainer, ToolbarPart
],
imports: [CommonModule]
imports: [CommonModule],
schemas: [NO_ERRORS_SCHEMA],
});
const template =
'<some-directive><toolbar><template toolbarpart let-toolbarProp="toolbarProp">{{ctxProp}},{{toolbarProp}},<cmp-with-host></cmp-with-host></template></toolbar></some-directive>';
@ -640,7 +641,10 @@ function declareTests({useJit}: {useJit: boolean}) {
});
it('should create a component that injects an @Host', () => {
TestBed.configureTestingModule({declarations: [MyComp, SomeDirective, CompWithHost]});
TestBed.configureTestingModule({
declarations: [MyComp, SomeDirective, CompWithHost],
schemas: [NO_ERRORS_SCHEMA],
});
const template = `
<some-directive>
<p>
@ -656,7 +660,10 @@ function declareTests({useJit}: {useJit: boolean}) {
});
it('should create a component that injects an @Host through viewcontainer directive', () => {
TestBed.configureTestingModule({declarations: [MyComp, SomeDirective, CompWithHost]});
TestBed.configureTestingModule({
declarations: [MyComp, SomeDirective, CompWithHost],
schemas: [NO_ERRORS_SCHEMA],
});
const template = `
<some-directive>
<p *ngIf="true">
@ -879,25 +886,24 @@ function declareTests({useJit}: {useJit: boolean}) {
describe('dynamic ViewContainers', () => {
beforeEach(() => {
// we need a module to declarate ChildCompUsingService as an entryComponent otherwise the
// factory doesn't get created
@NgModule({
declarations: [MyComp, DynamicViewport, ChildCompUsingService],
entryComponents: [ChildCompUsingService]
entryComponents: [ChildCompUsingService],
schemas: [NO_ERRORS_SCHEMA],
})
class MyModule {
}
TestBed.configureTestingModule({imports: [MyModule]});
TestBed.overrideComponent(
MyComp, {add: {template: '<div><dynamic-vp #dynamic></dynamic-vp></div>'}});
});
it('should allow to create a ViewContainerRef at any bound location', async(() => {
var fixture = TestBed.createComponent(MyComp);
var fixture = TestBed.configureTestingModule({schemas: [NO_ERRORS_SCHEMA]})
.createComponent(MyComp);
var tc = fixture.debugElement.children[0].children[0];
var dynamicVp: DynamicViewport = tc.injector.get(DynamicViewport);
dynamicVp.done.then((_) => {
@ -945,8 +951,10 @@ function declareTests({useJit}: {useJit: boolean}) {
describe('dependency injection', () => {
it('should support bindings', () => {
TestBed.configureTestingModule(
{declarations: [MyComp, DirectiveProvidingInjectable, DirectiveConsumingInjectable]});
TestBed.configureTestingModule({
declarations: [MyComp, DirectiveProvidingInjectable, DirectiveConsumingInjectable],
schemas: [NO_ERRORS_SCHEMA],
});
const template = `
<directive-providing-injectable >
<directive-consuming-injectable #consuming>
@ -962,8 +970,8 @@ function declareTests({useJit}: {useJit: boolean}) {
it('should support viewProviders', () => {
TestBed.configureTestingModule({
declarations:
[MyComp, DirectiveProvidingInjectableInView, DirectiveConsumingInjectable]
declarations: [MyComp, DirectiveProvidingInjectableInView, DirectiveConsumingInjectable],
schemas: [NO_ERRORS_SCHEMA],
});
const template = `
<directive-consuming-injectable #consuming>
@ -981,7 +989,8 @@ function declareTests({useJit}: {useJit: boolean}) {
declarations: [
MyComp, DirectiveProvidingInjectable, DirectiveContainingDirectiveConsumingAnInjectable,
DirectiveConsumingInjectableUnbounded
]
],
schemas: [NO_ERRORS_SCHEMA],
});
const template = `
<directive-providing-injectable>
@ -1007,7 +1016,8 @@ function declareTests({useJit}: {useJit: boolean}) {
TestBed.configureTestingModule({
declarations: [
MyComp, GrandParentProvidingEventBus, ParentProvidingEventBus, ChildConsumingEventBus
]
],
schemas: [NO_ERRORS_SCHEMA],
});
const template = `
<grand-parent-providing-event-bus>
@ -1036,8 +1046,8 @@ function declareTests({useJit}: {useJit: boolean}) {
it('should instantiate bindings lazily', () => {
TestBed.configureTestingModule({
declarations:
[MyComp, DirectiveConsumingInjectable, ComponentProvidingLoggingInjectable]
declarations: [MyComp, DirectiveConsumingInjectable, ComponentProvidingLoggingInjectable],
schemas: [NO_ERRORS_SCHEMA],
});
const template = `
<component-providing-logging-injectable #providing>
@ -1138,7 +1148,10 @@ function declareTests({useJit}: {useJit: boolean}) {
});
it('should provide an error context when an error happens in DI', () => {
TestBed.configureTestingModule({declarations: [MyComp, DirectiveThrowingAnError]});
TestBed.configureTestingModule({
declarations: [MyComp, DirectiveThrowingAnError],
schemas: [NO_ERRORS_SCHEMA],
});
const template = `<directive-throwing-error></directive-throwing-error>`;
TestBed.overrideComponent(MyComp, {set: {template}});
@ -1190,8 +1203,10 @@ function declareTests({useJit}: {useJit: boolean}) {
if (getDOM().supportsDOMEvents()) { // this is required to use fakeAsync
it('should provide an error context when an error happens in an event handler',
fakeAsync(() => {
TestBed.configureTestingModule(
{declarations: [MyComp, DirectiveEmittingEvent, DirectiveListeningEvent]});
TestBed.configureTestingModule({
declarations: [MyComp, DirectiveEmittingEvent, DirectiveListeningEvent],
schemas: [NO_ERRORS_SCHEMA],
});
const template = `<span emitter listener (event)="throwError()" #local></span>`;
TestBed.overrideComponent(MyComp, {set: {template}});
const fixture = TestBed.createComponent(MyComp);
@ -1366,7 +1381,10 @@ function declareTests({useJit}: {useJit: boolean}) {
describe('property decorators', () => {
it('should support property decorators', () => {
TestBed.configureTestingModule({declarations: [MyComp, DirectiveWithPropDecorators]});
TestBed.configureTestingModule({
declarations: [MyComp, DirectiveWithPropDecorators],
schemas: [NO_ERRORS_SCHEMA],
});
const template = '<with-prop-decorators elProp="aaa"></with-prop-decorators>';
TestBed.overrideComponent(MyComp, {set: {template}});
const fixture = TestBed.createComponent(MyComp);
@ -1377,7 +1395,10 @@ function declareTests({useJit}: {useJit: boolean}) {
});
it('should support host binding decorators', () => {
TestBed.configureTestingModule({declarations: [MyComp, DirectiveWithPropDecorators]});
TestBed.configureTestingModule({
declarations: [MyComp, DirectiveWithPropDecorators],
schemas: [NO_ERRORS_SCHEMA],
});
const template = '<with-prop-decorators></with-prop-decorators>';
TestBed.overrideComponent(MyComp, {set: {template}});
const fixture = TestBed.createComponent(MyComp);
@ -1393,7 +1414,10 @@ function declareTests({useJit}: {useJit: boolean}) {
if (getDOM().supportsDOMEvents()) {
it('should support event decorators', fakeAsync(() => {
TestBed.configureTestingModule({declarations: [MyComp, DirectiveWithPropDecorators]});
TestBed.configureTestingModule({
declarations: [MyComp, DirectiveWithPropDecorators],
schemas: [NO_ERRORS_SCHEMA],
});
const template = `<with-prop-decorators (elEvent)="ctxProp='called'">`;
TestBed.overrideComponent(MyComp, {set: {template}});
const fixture = TestBed.createComponent(MyComp);
@ -1411,7 +1435,10 @@ function declareTests({useJit}: {useJit: boolean}) {
it('should support host listener decorators', () => {
TestBed.configureTestingModule({declarations: [MyComp, DirectiveWithPropDecorators]});
TestBed.configureTestingModule({
declarations: [MyComp, DirectiveWithPropDecorators],
schemas: [NO_ERRORS_SCHEMA],
});
const template = '<with-prop-decorators></with-prop-decorators>';
TestBed.overrideComponent(MyComp, {set: {template}});
const fixture = TestBed.createComponent(MyComp);
@ -1426,8 +1453,11 @@ function declareTests({useJit}: {useJit: boolean}) {
}
it('should support defining views in the component decorator', () => {
TestBed.configureTestingModule(
{declarations: [MyComp, ComponentWithTemplate], imports: [CommonModule]});
TestBed.configureTestingModule({
declarations: [MyComp, ComponentWithTemplate],
imports: [CommonModule],
schemas: [NO_ERRORS_SCHEMA],
});
const template = '<component-with-template></component-with-template>';
TestBed.overrideComponent(MyComp, {set: {template}});
const fixture = TestBed.createComponent(MyComp);

View File

@ -6,10 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Component, Directive, ElementRef, TemplateRef, ViewContainerRef, ViewEncapsulation, forwardRef} from '@angular/core';
import {Component, Directive, ElementRef, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
import {getAllDebugNodes} from '@angular/core/src/debug/debug_node';
import {ViewMetadata} from '@angular/core/src/metadata/view';
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
import {TestBed} from '@angular/core/testing';
import {beforeEach, beforeEachProviders, ddescribe, describe, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
import {By} from '@angular/platform-browser/src/dom/debug/by';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
@ -457,8 +456,8 @@ export function main() {
main.detectChanges();
expect(getDOM().getInnerHTML(main.debugElement.nativeElement))
.toEqual(
'<cmp-a><cmp-b><cmp-d><d>cmp-d</d></cmp-d></cmp-b>' +
'<cmp-c><c>cmp-c</c></cmp-c></cmp-a>');
'<cmp-a><cmp-b><cmp-d><i>cmp-d</i></cmp-d></cmp-b>' +
'<cmp-c><b>cmp-c</b></cmp-c></cmp-a>');
});
it('should create nested components in the right order', () => {
@ -652,7 +651,7 @@ class Tree {
}
@Component({selector: 'cmp-d', template: `<d>{{tagName}}</d>`})
@Component({selector: 'cmp-d', template: `<i>{{tagName}}</i>`})
class CmpD {
tagName: string;
constructor(elementRef: ElementRef) {
@ -661,7 +660,7 @@ class CmpD {
}
@Component({selector: 'cmp-c', template: `<c>{{tagName}}</c>`})
@Component({selector: 'cmp-c', template: `<b>{{tagName}}</b>`})
class CmpC {
tagName: string;
constructor(elementRef: ElementRef) {

View File

@ -6,14 +6,15 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Component, Directive, ElementRef, Input, QueryList, ViewChild, ViewChildren} from '@angular/core';
import {Component, Directive, ElementRef, Input, NO_ERRORS_SCHEMA, QueryList, ViewChild, ViewChildren} from '@angular/core';
import {TestBed} from '@angular/core/testing';
export function main() {
describe('ViewChild', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ViewChildTypeSelectorComponent, ViewChildStringSelectorComponent, Simple]
declarations: [ViewChildTypeSelectorComponent, ViewChildStringSelectorComponent, Simple],
schemas: [NO_ERRORS_SCHEMA],
});
});
@ -42,7 +43,8 @@ export function main() {
beforeEach(() => {
TestBed.configureTestingModule({
declarations:
[ViewChildrenTypeSelectorComponent, ViewChildrenStringSelectorComponent, Simple]
[ViewChildrenTypeSelectorComponent, ViewChildrenStringSelectorComponent, Simple],
schemas: [NO_ERRORS_SCHEMA],
});
});
@ -61,7 +63,8 @@ export function main() {
TestBed.overrideComponent(
ViewChildrenStringSelectorComponent,
{set: {template: `<simple #child1></simple><simple #child2></simple>`}});
const view = TestBed.createComponent(ViewChildrenStringSelectorComponent);
const view = TestBed.configureTestingModule({schemas: [NO_ERRORS_SCHEMA]})
.createComponent(ViewChildrenStringSelectorComponent);
view.detectChanges();
expect(view.componentInstance.children).toBeDefined();
expect(view.componentInstance.children.length).toBe(2);