fix(core): don't consider inherited NG_ELEMENT_ID during DI (#37574)

Special DI tokens like `ChangeDetectorRef` and `ElementRef` can provide a factory via `NG_ELEMENT_ID`. The problem is that we were reading it off the token as `token[NG_ELEMENT_ID]` which will go up the prototype chain if it couldn't be found on the current token, resulting in the private `ViewRef` API being exposed, because it extends `ChangeDetectorRef`.

These changes fix the issue by guarding the property access with `hasOwnProperty`.

Fixes #36235.

PR Close #37574
This commit is contained in:
crisbeto
2020-06-14 11:23:12 +02:00
committed by Andrew Kushnir
parent 7c0b25f5a6
commit 64b0ae93f7
2 changed files with 30 additions and 12 deletions

View File

@ -99,8 +99,12 @@ let nextNgElementId = 0;
export function bloomAdd(
injectorIndex: number, tView: TView, type: Type<any>|InjectionToken<any>|string): void {
ngDevMode && assertEqual(tView.firstCreatePass, true, 'expected firstCreatePass to be true');
let id: number|undefined =
typeof type !== 'string' ? (type as any)[NG_ELEMENT_ID] : type.charCodeAt(0) || 0;
let id: number|undefined;
if (typeof type === 'string') {
id = type.charCodeAt(0) || 0;
} else if (type.hasOwnProperty(NG_ELEMENT_ID)) {
id = (type as any)[NG_ELEMENT_ID];
}
// Set a unique ID on the directive type, so if something tries to inject the directive,
// we can easily retrieve the ID and hash it into the bloom bit that should be checked.
@ -584,7 +588,9 @@ export function bloomHashBitOrFactory(token: Type<any>|InjectionToken<any>|strin
if (typeof token === 'string') {
return token.charCodeAt(0) || 0;
}
const tokenId: number|undefined = (token as any)[NG_ELEMENT_ID];
const tokenId: number|undefined =
// First check with `hasOwnProperty` so we don't get an inherited ID.
token.hasOwnProperty(NG_ELEMENT_ID) ? (token as any)[NG_ELEMENT_ID] : undefined;
// Negative token IDs are used for special objects such as `Injector`
return (typeof tokenId === 'number' && tokenId > 0) ? tokenId & BLOOM_MASK : tokenId;
}