mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(animations): detect object trigger values with Object.hasOwn
StateValue and AnimationTransitionNamespace.trigger detect the {value,
params} object form of a trigger binding by calling hasOwnProperty on the
bound value. When that value is an object from untrusted data (for example
a parsed JSON payload) carrying an own hasOwnProperty key, the shadowed
property is called as a method and throws, breaking the animation flush.
Use Object.hasOwn for the check so a shadowing key no longer matters.
This commit is contained in:
committed by
Jessica Janiuk
parent
1a006a8f97
commit
c73a001fbf
@@ -112,7 +112,7 @@ class StateValue {
|
||||
input: any,
|
||||
public namespaceId: string = '',
|
||||
) {
|
||||
const isObj = input && input.hasOwnProperty('value');
|
||||
const isObj = input && Object.hasOwn(input, 'value');
|
||||
const value = isObj ? input['value'] : input;
|
||||
this.value = normalizeTriggerValue(value);
|
||||
if (isObj) {
|
||||
@@ -246,7 +246,7 @@ class AnimationTransitionNamespace {
|
||||
|
||||
let fromState = triggersWithStates.get(triggerName);
|
||||
const toState = new StateValue(value, this.id);
|
||||
const isObj = value && value.hasOwnProperty('value');
|
||||
const isObj = value && Object.hasOwn(value, 'value');
|
||||
if (!isObj && fromState) {
|
||||
toState.absorbOptions(fromState.options);
|
||||
}
|
||||
|
||||
@@ -118,6 +118,25 @@ const DEFAULT_NAMESPACE_ID = 'id';
|
||||
expect(engine.players.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should read the value from a trigger object whose own key shadows hasOwnProperty', () => {
|
||||
const engine = makeEngine();
|
||||
|
||||
const trig = trigger('myTrigger', [
|
||||
transition('* => *', [style({height: '0px'}), animate(1000, style({height: '100px'}))]),
|
||||
]);
|
||||
|
||||
registerTrigger(element, engine, trig);
|
||||
|
||||
// A bound trigger value in the `{value, params}` object form can come from
|
||||
// untrusted data (e.g. a parsed JSON payload) and carry an own `hasOwnProperty`
|
||||
// key that shadows the method. Detecting the object form must not depend on it.
|
||||
const value = JSON.parse('{"value": "matched", "hasOwnProperty": "x"}');
|
||||
expect(() => setProperty(element, engine, 'myTrigger', value)).not.toThrow();
|
||||
|
||||
engine.flush();
|
||||
expect(engine.players.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should throw an error if an animation property without a matching trigger is changed', () => {
|
||||
const engine = makeEngine();
|
||||
expect(() => {
|
||||
|
||||
Reference in New Issue
Block a user