From 76735410f8260f8f3655ddc420ae12ec1c8760be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Thu, 4 Feb 2021 08:46:02 +0100 Subject: [PATCH] [FIX] qweb: prevent issue with builtin object properties The QWeb expression parser use an object as a mapping between some strings and the desired output in the compiled template. However, as we should all know, objects are not Maps, they have some additional properties, such as "constructor" or "hasOwnProperty". The simple solution is to make sure the mapping object does not have anything in its prototype chain to pollute its purpose. closes #835 --- src/qweb/expression_parser.ts | 8 ++++---- tests/qweb/qweb_expressions.test.ts | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/qweb/expression_parser.ts b/src/qweb/expression_parser.ts index 95da771e..3d11294b 100644 --- a/src/qweb/expression_parser.ts +++ b/src/qweb/expression_parser.ts @@ -29,14 +29,14 @@ const RESERVED_WORDS = "true,false,NaN,null,undefined,debugger,console,window,in "," ); -const WORD_REPLACEMENT = { +const WORD_REPLACEMENT = Object.assign(Object.create(null), { and: "&&", or: "||", gt: ">", gte: ">=", lt: "<", lte: "<=", -}; +}); export interface QWebVar { id: string; // foo @@ -69,7 +69,7 @@ interface Token { varName?: string; } -const STATIC_TOKEN_MAP: { [key: string]: TKind } = { +const STATIC_TOKEN_MAP: { [key: string]: TKind } = Object.assign(Object.create(null), { "{": "LEFT_BRACE", "}": "RIGHT_BRACE", "[": "LEFT_BRACKET", @@ -78,7 +78,7 @@ const STATIC_TOKEN_MAP: { [key: string]: TKind } = { ",": "COMMA", "(": "LEFT_PAREN", ")": "RIGHT_PAREN", -}; +}); // note that the space after typeof is relevant. It makes sure that the formatted // expression has a space after typeof diff --git a/tests/qweb/qweb_expressions.test.ts b/tests/qweb/qweb_expressions.test.ts index de4f383d..226c9b76 100644 --- a/tests/qweb/qweb_expressions.test.ts +++ b/tests/qweb/qweb_expressions.test.ts @@ -196,4 +196,8 @@ describe("expression evaluation", () => { expect(compileExpr("f(...state.list)", {})).toBe("scope['f'](...scope['state'].list)"); expect(compileExpr("f([...list])", {})).toBe("scope['f']([...scope['list']])"); }); + + test("works with builtin properties", () => { + expect(compileExpr("state.constructor.name", {})).toBe("scope['state'].constructor.name"); + }); });