fix(compiler): move detection of unsafe properties for binding to ElementSchemaRegistry (#11378)
This commit is contained in:
parent
3a5b4882bc
commit
61129fa12d
|
@ -344,4 +344,26 @@ export class DomElementSchemaRegistry extends ElementSchemaRegistry {
|
|||
getMappedPropName(propName: string): string { return _ATTR_TO_PROP[propName] || propName; }
|
||||
|
||||
getDefaultComponentElementName(): string { return 'ng-component'; }
|
||||
|
||||
validateProperty(name: string): {error: boolean, msg?: string} {
|
||||
if (name.toLowerCase().startsWith('on')) {
|
||||
const msg = `Binding to event property '${name}' is disallowed for security reasons, ` +
|
||||
`please use (${name.slice(2)})=...` +
|
||||
`\nIf '${name}' is a directive input, make sure the directive is imported by the` +
|
||||
` current module.`;
|
||||
return {error: true, msg: msg};
|
||||
} else {
|
||||
return {error: false};
|
||||
}
|
||||
}
|
||||
|
||||
validateAttribute(name: string): {error: boolean, msg?: string} {
|
||||
if (name.toLowerCase().startsWith('on')) {
|
||||
const msg = `Binding to event attribute '${name}' is disallowed for security reasons, ` +
|
||||
`please use (${name.slice(2)})=...`;
|
||||
return {error: true, msg: msg};
|
||||
} else {
|
||||
return {error: false};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,4 +14,6 @@ export abstract class ElementSchemaRegistry {
|
|||
abstract securityContext(tagName: string, propName: string): any;
|
||||
abstract getMappedPropName(propName: string): string;
|
||||
abstract getDefaultComponentElementName(): string;
|
||||
abstract validateProperty(name: string): {error: boolean, msg?: string};
|
||||
abstract validateAttribute(name: string): {error: boolean, msg?: string};
|
||||
}
|
||||
|
|
|
@ -927,7 +927,7 @@ class TemplateParseVisitor implements html.Visitor {
|
|||
boundPropertyName = this._schemaRegistry.getMappedPropName(partValue);
|
||||
securityContext = this._schemaRegistry.securityContext(elementName, boundPropertyName);
|
||||
bindingType = PropertyBindingType.Property;
|
||||
this._assertNoEventBinding(boundPropertyName, sourceSpan, false);
|
||||
this._validatePropertyOrAttributeName(boundPropertyName, sourceSpan, false);
|
||||
if (!this._schemaRegistry.hasProperty(elementName, boundPropertyName, this._schemas)) {
|
||||
let errorMsg =
|
||||
`Can't bind to '${boundPropertyName}' since it isn't a known property of '${elementName}'.`;
|
||||
|
@ -942,7 +942,7 @@ class TemplateParseVisitor implements html.Visitor {
|
|||
} else {
|
||||
if (parts[0] == ATTRIBUTE_PREFIX) {
|
||||
boundPropertyName = parts[1];
|
||||
this._assertNoEventBinding(boundPropertyName, sourceSpan, true);
|
||||
this._validatePropertyOrAttributeName(boundPropertyName, sourceSpan, true);
|
||||
// NB: For security purposes, use the mapped property name, not the attribute name.
|
||||
const mapPropName = this._schemaRegistry.getMappedPropName(boundPropertyName);
|
||||
securityContext = this._schemaRegistry.securityContext(elementName, mapPropName);
|
||||
|
@ -975,23 +975,19 @@ class TemplateParseVisitor implements html.Visitor {
|
|||
boundPropertyName, bindingType, securityContext, ast, unit, sourceSpan);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param propName the name of the property / attribute
|
||||
* @param sourceSpan
|
||||
* @param isAttr true when binding to an attribute
|
||||
* @private
|
||||
*/
|
||||
private _assertNoEventBinding(propName: string, sourceSpan: ParseSourceSpan, isAttr: boolean):
|
||||
void {
|
||||
if (propName.toLowerCase().startsWith('on')) {
|
||||
let msg = `Binding to event attribute '${propName}' is disallowed for security reasons, ` +
|
||||
`please use (${propName.slice(2)})=...`;
|
||||
if (!isAttr) {
|
||||
msg +=
|
||||
`\nIf '${propName}' is a directive input, make sure the directive is imported by the` +
|
||||
` current module.`;
|
||||
}
|
||||
this._reportError(msg, sourceSpan, ParseErrorLevel.FATAL);
|
||||
private _validatePropertyOrAttributeName(
|
||||
propName: string, sourceSpan: ParseSourceSpan, isAttr: boolean): void {
|
||||
const report = isAttr ? this._schemaRegistry.validateAttribute(propName) :
|
||||
this._schemaRegistry.validateProperty(propName);
|
||||
if (report.error) {
|
||||
this._reportError(report.msg, sourceSpan, ParseErrorLevel.FATAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -105,6 +105,47 @@ export function main() {
|
|||
expect(registry.getMappedPropName('exotic-unknown')).toEqual('exotic-unknown');
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
it('should return security contexts for elements', () => {
|
||||
expect(registry.securityContext('iframe', 'srcdoc')).toBe(SecurityContext.HTML);
|
||||
expect(registry.securityContext('p', 'innerHTML')).toBe(SecurityContext.HTML);
|
||||
|
|
|
@ -26,7 +26,8 @@ const someModuleUrl = 'package:someModule';
|
|||
const MOCK_SCHEMA_REGISTRY = [{
|
||||
provide: ElementSchemaRegistry,
|
||||
useValue: new MockSchemaRegistry(
|
||||
{'invalidProp': false}, {'mappedAttr': 'mappedProp'}, {'unknown': false, 'un-known': false}),
|
||||
{'invalidProp': false}, {'mappedAttr': 'mappedProp'}, {'unknown': false, 'un-known': false},
|
||||
['onEvent'], ['onEvent']),
|
||||
}];
|
||||
|
||||
export function main() {
|
||||
|
@ -141,7 +142,8 @@ export function main() {
|
|||
});
|
||||
});
|
||||
|
||||
describe('TemplateParser', () => {
|
||||
describe(
|
||||
'TemplateParser', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureCompiler({providers: [TEST_COMPILER_PROVIDERS, MOCK_SCHEMA_REGISTRY]});
|
||||
});
|
||||
|
@ -276,12 +278,26 @@ Can't bind to 'invalidProp' since it isn't a known property of 'my-component'.
|
|||
2. If 'unknown' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. ("[ERROR ->]<unknown></unknown>"): TestComp@0:0`);
|
||||
});
|
||||
|
||||
it('should throw error when binding to an unknown custom element w/o bindings', () => {
|
||||
expect(() => parse('<un-known></un-known>', [])).toThrowError(`Template parse errors:
|
||||
it('should throw error when binding to an unknown custom element w/o bindings',
|
||||
() => {
|
||||
expect(() => parse('<un-known></un-known>', []))
|
||||
.toThrowError(`Template parse errors:
|
||||
'un-known' is not a known element:
|
||||
1. If 'un-known' is an Angular component, then verify that it is part of this module.
|
||||
2. If 'un-known' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. ("[ERROR ->]<un-known></un-known>"): TestComp@0:0`);
|
||||
});
|
||||
|
||||
it('should throw error when binding to an invalid property', () => {
|
||||
expect(() => parse('<my-component [onEvent]="bar"></my-component>', []))
|
||||
.toThrowError(`Template parse errors:
|
||||
Binding to property 'onEvent' is disallowed for security reasons ("<my-component [ERROR ->][onEvent]="bar"></my-component>"): TestComp@0:14`);
|
||||
});
|
||||
|
||||
it('should throw error when binding to an invalid attribute', () => {
|
||||
expect(() => parse('<my-component [attr.onEvent]="bar"></my-component>', []))
|
||||
.toThrowError(`Template parse errors:
|
||||
Binding to attribute 'onEvent' is disallowed for security reasons ("<my-component [ERROR ->][attr.onEvent]="bar"></my-component>"): TestComp@0:14`);
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse bound properties via [...] and not report them as attributes', () => {
|
||||
|
@ -298,16 +314,20 @@ Can't bind to 'invalidProp' since it isn't a known property of 'my-component'.
|
|||
]);
|
||||
});
|
||||
|
||||
it('should parse bound properties via {{...}} and not report them as attributes', () => {
|
||||
it('should parse bound properties via {{...}} and not report them as attributes',
|
||||
() => {
|
||||
expect(humanizeTplAst(parse('<div prop="{{v}}">', []))).toEqual([
|
||||
[ElementAst, 'div'],
|
||||
[BoundElementPropertyAst, PropertyBindingType.Property, 'prop', '{{ v }}', null]
|
||||
[
|
||||
BoundElementPropertyAst, PropertyBindingType.Property, 'prop', '{{ v }}', null
|
||||
]
|
||||
]);
|
||||
});
|
||||
|
||||
it('should parse bound properties via bind-animate- and not report them as attributes',
|
||||
() => {
|
||||
expect(humanizeTplAst(parse('<div bind-animate-someAnimation="value2">', [], [], [])))
|
||||
expect(
|
||||
humanizeTplAst(parse('<div bind-animate-someAnimation="value2">', [], [], [])))
|
||||
.toEqual([
|
||||
[ElementAst, 'div'],
|
||||
[
|
||||
|
@ -473,8 +493,8 @@ Can't bind to 'invalidProp' since it isn't a known property of 'my-component'.
|
|||
});
|
||||
expect(humanizeTplAst(parse('<div a c b a b>', [dirA, dirB, dirC]))).toEqual([
|
||||
[ElementAst, 'div'], [AttrAst, 'a', ''], [AttrAst, 'c', ''], [AttrAst, 'b', ''],
|
||||
[AttrAst, 'a', ''], [AttrAst, 'b', ''], [DirectiveAst, dirA], [DirectiveAst, dirB],
|
||||
[DirectiveAst, dirC]
|
||||
[AttrAst, 'a', ''], [AttrAst, 'b', ''], [DirectiveAst, dirA],
|
||||
[DirectiveAst, dirB], [DirectiveAst, dirC]
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -554,7 +574,8 @@ Can't bind to 'invalidProp' since it isn't a known property of 'my-component'.
|
|||
inputs: ['b:a']
|
||||
});
|
||||
expect(humanizeTplAst(parse('<div [a]="expr"></div>', [dirA]))).toEqual([
|
||||
[ElementAst, 'div'], [DirectiveAst, dirA], [BoundDirectivePropertyAst, 'b', 'expr']
|
||||
[ElementAst, 'div'], [DirectiveAst, dirA],
|
||||
[BoundDirectivePropertyAst, 'b', 'expr']
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -632,8 +653,12 @@ Can't bind to 'invalidProp' since it isn't a known property of 'my-component'.
|
|||
isHost = true;
|
||||
value = value.substring(5);
|
||||
}
|
||||
return new CompileDiDependencyMetadata(
|
||||
{token: createToken(value), isOptional: isOptional, isSelf: isSelf, isHost: isHost});
|
||||
return new CompileDiDependencyMetadata({
|
||||
token: createToken(value),
|
||||
isOptional: isOptional,
|
||||
isSelf: isSelf,
|
||||
isHost: isHost
|
||||
});
|
||||
}
|
||||
|
||||
function createProvider(
|
||||
|
@ -649,7 +674,8 @@ Can't bind to 'invalidProp' since it isn't a known property of 'my-component'.
|
|||
}
|
||||
|
||||
function createDir(
|
||||
selector: string, {providers = null, viewProviders = null, deps = [], queries = []}: {
|
||||
selector: string,
|
||||
{providers = null, viewProviders = null, deps = [], queries = []}: {
|
||||
providers?: CompileProviderMetadata[],
|
||||
viewProviders?: CompileProviderMetadata[],
|
||||
deps?: string[],
|
||||
|
@ -802,7 +828,8 @@ Can't bind to 'invalidProp' since it isn't a known property of 'my-component'.
|
|||
it('should mark directives and dependencies of directives as eager', () => {
|
||||
var provider0 = createProvider('service0');
|
||||
var provider1 = createProvider('service1');
|
||||
var dirA = createDir('[dirA]', {providers: [provider0, provider1], deps: ['service0']});
|
||||
var dirA =
|
||||
createDir('[dirA]', {providers: [provider0, provider1], deps: ['service0']});
|
||||
var elAst: ElementAst = <ElementAst>parse('<div dirA>', [dirA])[0];
|
||||
expect(elAst.providers.length).toBe(3);
|
||||
expect(elAst.providers[0].providers).toEqual([provider0]);
|
||||
|
@ -1072,8 +1099,9 @@ Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>
|
|||
{moduleUrl: someModuleUrl, name: 'DirB', reference: {} as Type<any>})
|
||||
});
|
||||
expect(humanizeTplAst(parse('<div template="a b" b>', [dirA, dirB]))).toEqual([
|
||||
[EmbeddedTemplateAst], [DirectiveAst, dirA], [BoundDirectivePropertyAst, 'a', 'b'],
|
||||
[ElementAst, 'div'], [AttrAst, 'b', ''], [DirectiveAst, dirB]
|
||||
[EmbeddedTemplateAst], [DirectiveAst, dirA],
|
||||
[BoundDirectivePropertyAst, 'a', 'b'], [ElementAst, 'div'], [AttrAst, 'b', ''],
|
||||
[DirectiveAst, dirB]
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -1148,8 +1176,9 @@ Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>
|
|||
|
||||
describe('project text nodes', () => {
|
||||
it('should project text nodes with wildcard selector', () => {
|
||||
expect(humanizeContentProjection(parse('<div>hello</div>', [createComp('div', ['*'])])))
|
||||
.toEqual([['div', null], ['#text(hello)', 0]]);
|
||||
expect(humanizeContentProjection(parse('<div>hello</div>', [
|
||||
createComp('div', ['*'])
|
||||
]))).toEqual([['div', null], ['#text(hello)', 0]]);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1222,9 +1251,10 @@ Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>
|
|||
});
|
||||
|
||||
it('should project children of components with ngNonBindable', () => {
|
||||
expect(humanizeContentProjection(parse('<div ngNonBindable>{{hello}}<span></span></div>', [
|
||||
createComp('div', ['*'])
|
||||
]))).toEqual([['div', null], ['#text({{hello}})', 0], ['span', 0]]);
|
||||
expect(
|
||||
humanizeContentProjection(parse(
|
||||
'<div ngNonBindable>{{hello}}<span></span></div>', [createComp('div', ['*'])])))
|
||||
.toEqual([['div', null], ['#text({{hello}})', 0], ['span', 0]]);
|
||||
});
|
||||
|
||||
it('should match the element when there is an inline template', () => {
|
||||
|
@ -1302,7 +1332,8 @@ Can't have multiple template bindings on one element. Use only one attribute nam
|
|||
});
|
||||
|
||||
it('should report invalid property names', () => {
|
||||
expect(() => parse('<div [invalidProp]></div>', [])).toThrowError(`Template parse errors:
|
||||
expect(() => parse('<div [invalidProp]></div>', []))
|
||||
.toThrowError(`Template parse errors:
|
||||
Can't bind to 'invalidProp' since it isn't a known property of 'div'. ("<div [ERROR ->][invalidProp]></div>"): TestComp@0:5`);
|
||||
});
|
||||
|
||||
|
@ -1430,7 +1461,8 @@ Property binding a not used by any directive on an embedded template. Make sure
|
|||
});
|
||||
|
||||
it('should keep nested children of elements with ngNonBindable', () => {
|
||||
expect(humanizeTplAst(parse('<div ngNonBindable><span>{{b}}</span></div>', []))).toEqual([
|
||||
expect(humanizeTplAst(parse('<div ngNonBindable><span>{{b}}</span></div>', [])))
|
||||
.toEqual([
|
||||
[ElementAst, 'div'], [AttrAst, 'ngNonBindable', ''], [ElementAst, 'span'],
|
||||
[TextAst, '{{b}}']
|
||||
]);
|
||||
|
@ -1454,10 +1486,11 @@ Property binding a not used by any directive on an embedded template. Make sure
|
|||
|
||||
it('should convert <ng-content> elements into regular elements inside of elements with ngNonBindable',
|
||||
() => {
|
||||
expect(humanizeTplAst(parse('<div ngNonBindable><ng-content></ng-content>a</div>', [])))
|
||||
expect(
|
||||
humanizeTplAst(parse('<div ngNonBindable><ng-content></ng-content>a</div>', [])))
|
||||
.toEqual([
|
||||
[ElementAst, 'div'], [AttrAst, 'ngNonBindable', ''], [ElementAst, 'ng-content'],
|
||||
[TextAst, 'a']
|
||||
[ElementAst, 'div'], [AttrAst, 'ngNonBindable', ''],
|
||||
[ElementAst, 'ng-content'], [TextAst, 'a']
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -1490,8 +1523,10 @@ Property binding a not used by any directive on an embedded template. Make sure
|
|||
});
|
||||
|
||||
it('should support variables', () => {
|
||||
expect(humanizeTplAstSourceSpans(parse('<template let-a="b"></template>', []))).toEqual([
|
||||
[EmbeddedTemplateAst, '<template let-a="b">'], [VariableAst, 'a', 'b', 'let-a="b"']
|
||||
expect(humanizeTplAstSourceSpans(parse('<template let-a="b"></template>', [])))
|
||||
.toEqual([
|
||||
[EmbeddedTemplateAst, '<template let-a="b">'],
|
||||
[VariableAst, 'a', 'b', 'let-a="b"']
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -1536,8 +1571,8 @@ Property binding a not used by any directive on an embedded template. Make sure
|
|||
template: new CompileTemplateMetadata({ngContentSelectors: []})
|
||||
});
|
||||
expect(humanizeTplAstSourceSpans(parse('<div a>', [dirA, comp]))).toEqual([
|
||||
[ElementAst, 'div', '<div a>'], [AttrAst, 'a', '', 'a'], [DirectiveAst, dirA, '<div a>'],
|
||||
[DirectiveAst, comp, '<div a>']
|
||||
[ElementAst, 'div', '<div a>'], [AttrAst, 'a', '', 'a'],
|
||||
[DirectiveAst, dirA, '<div a>'], [DirectiveAst, comp, '<div a>']
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -1573,7 +1608,8 @@ Property binding a not used by any directive on an embedded template. Make sure
|
|||
inputs: ['aProp']
|
||||
});
|
||||
expect(humanizeTplAstSourceSpans(parse('<div [aProp]="foo"></div>', [dirA]))).toEqual([
|
||||
[ElementAst, 'div', '<div [aProp]="foo">'], [DirectiveAst, dirA, '<div [aProp]="foo">'],
|
||||
[ElementAst, 'div', '<div [aProp]="foo">'],
|
||||
[DirectiveAst, dirA, '<div [aProp]="foo">'],
|
||||
[BoundDirectivePropertyAst, 'aProp', 'foo', '[aProp]="foo"']
|
||||
]);
|
||||
});
|
||||
|
@ -1605,8 +1641,8 @@ The pipe 'test' could not be found ("[ERROR ->]{{a | test}}"): TestComp@0:0`);
|
|||
'<template ngPluralCase="many">big</template>' +
|
||||
'</ng-container>';
|
||||
|
||||
expect(humanizeTplAst(parse(shortForm, []))).toEqual(humanizeTplAst(parse(expandedForm, [
|
||||
])));
|
||||
expect(humanizeTplAst(parse(shortForm, [
|
||||
]))).toEqual(humanizeTplAst(parse(expandedForm, [])));
|
||||
});
|
||||
|
||||
it('should expand other messages', () => {
|
||||
|
@ -1616,8 +1652,8 @@ The pipe 'test' could not be found ("[ERROR ->]{{a | test}}"): TestComp@0:0`);
|
|||
'<template ngSwitchCase="other">bar</template>' +
|
||||
'</ng-container>';
|
||||
|
||||
expect(humanizeTplAst(parse(shortForm, []))).toEqual(humanizeTplAst(parse(expandedForm, [
|
||||
])));
|
||||
expect(humanizeTplAst(parse(shortForm, [
|
||||
]))).toEqual(humanizeTplAst(parse(expandedForm, [])));
|
||||
});
|
||||
|
||||
it('should be possible to escape ICU messages', () => {
|
||||
|
|
|
@ -13,7 +13,8 @@ export class MockSchemaRegistry implements ElementSchemaRegistry {
|
|||
constructor(
|
||||
public existingProperties: {[key: string]: boolean},
|
||||
public attrPropMapping: {[key: string]: string},
|
||||
public existingElements: {[key: string]: boolean}) {}
|
||||
public existingElements: {[key: string]: boolean}, public invalidProperties: Array<string>,
|
||||
public invalidAttributes: Array<string>) {}
|
||||
|
||||
hasProperty(tagName: string, property: string, schemas: SchemaMetadata[]): boolean {
|
||||
const value = this.existingProperties[property];
|
||||
|
@ -32,4 +33,23 @@ export class MockSchemaRegistry implements ElementSchemaRegistry {
|
|||
getMappedPropName(attrName: string): string { return this.attrPropMapping[attrName] || attrName; }
|
||||
|
||||
getDefaultComponentElementName(): string { return 'ng-component'; }
|
||||
|
||||
validateProperty(name: string): {error: boolean, msg?: string} {
|
||||
if (this.invalidProperties.indexOf(name) > -1) {
|
||||
return {error: true, msg: `Binding to property '${name}' is disallowed for security reasons`};
|
||||
} else {
|
||||
return {error: false};
|
||||
}
|
||||
}
|
||||
|
||||
validateAttribute(name: string): {error: boolean, msg?: string} {
|
||||
if (this.invalidAttributes.indexOf(name) > -1) {
|
||||
return {
|
||||
error: true,
|
||||
msg: `Binding to attribute '${name}' is disallowed for security reasons`
|
||||
};
|
||||
} else {
|
||||
return {error: false};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ export function createUrlResolverWithoutPackagePrefix(): UrlResolver {
|
|||
// internal test packages.
|
||||
// TODO: get rid of it or move to a separate @angular/internal_testing package
|
||||
export var TEST_COMPILER_PROVIDERS: Provider[] = [
|
||||
{provide: ElementSchemaRegistry, useValue: new MockSchemaRegistry({}, {}, {})},
|
||||
{provide: ElementSchemaRegistry, useValue: new MockSchemaRegistry({}, {}, {}, [], [])},
|
||||
{provide: ResourceLoader, useClass: MockResourceLoader},
|
||||
{provide: UrlResolver, useFactory: createUrlResolverWithoutPackagePrefix}
|
||||
];
|
||||
|
|
|
@ -66,7 +66,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
|||
|
||||
expect(() => TestBed.createComponent(SecuredComponent))
|
||||
.toThrowError(
|
||||
/Binding to event attribute 'onclick' is disallowed for security reasons, please use \(click\)=.../);
|
||||
/Binding to event property 'onclick' is disallowed for security reasons, please use \(click\)=.../);
|
||||
});
|
||||
|
||||
it('should disallow binding to on* unless it is consumed by a directive', () => {
|
||||
|
|
Loading…
Reference in New Issue