fix(ivy): validate props and attrs with "on" prefix at runtime (#28054)
Prior to this change we performed prop and attr name validation at compile time, which failed in case a given prop/attr is an input to a Directive (thus should not be a subject to this check). Since Directive matching in Ivy happens at runtime, the corresponding checks are now moved to runtime as well. PR Close #28054
This commit is contained in:
@ -10,6 +10,7 @@ import {InjectFlags, InjectionToken, Injector} from '../di';
|
||||
import {resolveForwardRef} from '../di/forward_ref';
|
||||
import {Type} from '../interface/type';
|
||||
import {QueryList} from '../linker';
|
||||
import {validateAttribute, validateProperty} from '../sanitization/sanitization';
|
||||
import {Sanitizer} from '../sanitization/security';
|
||||
import {StyleSanitizeFn} from '../sanitization/style_sanitizer';
|
||||
import {assertDataInRange, assertDefined, assertEqual, assertLessThan, assertNotEqual} from '../util/assert';
|
||||
@ -973,6 +974,7 @@ export function elementEnd(): void {
|
||||
export function elementAttribute(
|
||||
index: number, name: string, value: any, sanitizer?: SanitizerFn | null): void {
|
||||
if (value !== NO_CHANGE) {
|
||||
ngDevMode && validateAttribute(name);
|
||||
const lView = getLView();
|
||||
const renderer = lView[RENDERER];
|
||||
const element = getNativeByIndex(index, lView);
|
||||
@ -1064,11 +1066,14 @@ function elementPropertyInternal<T>(
|
||||
}
|
||||
}
|
||||
} else if (tNode.type === TNodeType.Element) {
|
||||
if (ngDevMode) {
|
||||
validateProperty(propName);
|
||||
ngDevMode.rendererSetProperty++;
|
||||
}
|
||||
const renderer = loadRendererFn ? loadRendererFn(tNode, lView) : lView[RENDERER];
|
||||
// It is assumed that the sanitizer is only added when the compiler determines that the property
|
||||
// is risky, so sanitization can be done without further checks.
|
||||
value = sanitizer != null ? (sanitizer(value, tNode.tagName || '', propName) as any) : value;
|
||||
ngDevMode && ngDevMode.rendererSetProperty++;
|
||||
if (isProceduralRenderer(renderer)) {
|
||||
renderer.setProperty(element as RElement, propName, value);
|
||||
} else if (!isAnimationProp(propName)) {
|
||||
|
@ -179,6 +179,24 @@ export const defaultStyleSanitizer = (function(prop: string, value?: string): st
|
||||
return sanitizeStyle(value);
|
||||
} as StyleSanitizeFn);
|
||||
|
||||
export function validateProperty(name: 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.`;
|
||||
throw new Error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
export function validateAttribute(name: string) {
|
||||
if (name.toLowerCase().startsWith('on')) {
|
||||
const msg = `Binding to event attribute '${name}' is disallowed for security reasons, ` +
|
||||
`please use (${name.slice(2)})=...`;
|
||||
throw new Error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
function getSanitizer(): Sanitizer|null {
|
||||
const lView = getLView();
|
||||
return lView && lView[SANITIZER];
|
||||
|
Reference in New Issue
Block a user