@memberjunction/templates 6.2.0-edge.3 → 6.2.0-edge.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -1
- package/dist/InheritedMemberNames.d.ts +12 -0
- package/dist/InheritedMemberNames.d.ts.map +1 -0
- package/dist/InheritedMemberNames.js +19 -0
- package/dist/InheritedMemberNames.js.map +1 -0
- package/dist/NunjucksCompileGuard.d.ts +17 -0
- package/dist/NunjucksCompileGuard.d.ts.map +1 -0
- package/dist/NunjucksCompileGuard.js +273 -0
- package/dist/NunjucksCompileGuard.js.map +1 -0
- package/dist/NunjucksSandbox.d.ts +26 -0
- package/dist/NunjucksSandbox.d.ts.map +1 -0
- package/dist/NunjucksSandbox.js +317 -0
- package/dist/NunjucksSandbox.js.map +1 -0
- package/dist/TemplateEngine.d.ts +41 -9
- package/dist/TemplateEngine.d.ts.map +1 -1
- package/dist/TemplateEngine.js +123 -23
- package/dist/TemplateEngine.js.map +1 -1
- package/dist/TemplateSandboxError.d.ts +9 -0
- package/dist/TemplateSandboxError.d.ts.map +1 -0
- package/dist/TemplateSandboxError.js +12 -0
- package/dist/TemplateSandboxError.js.map +1 -0
- package/dist/TemplateVariableAnalysis.d.ts +27 -0
- package/dist/TemplateVariableAnalysis.d.ts.map +1 -0
- package/dist/TemplateVariableAnalysis.js +140 -0
- package/dist/TemplateVariableAnalysis.js.map +1 -0
- package/dist/extensions/TemplateEmbed.extension.d.ts +13 -1
- package/dist/extensions/TemplateEmbed.extension.d.ts.map +1 -1
- package/dist/extensions/TemplateEmbed.extension.js +16 -8
- package/dist/extensions/TemplateEmbed.extension.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/operations/TemplateRunAuthorization.d.ts +20 -0
- package/dist/operations/TemplateRunAuthorization.d.ts.map +1 -0
- package/dist/operations/TemplateRunAuthorization.js +37 -0
- package/dist/operations/TemplateRunAuthorization.js.map +1 -0
- package/dist/operations/TemplateRunOperation.d.ts +6 -0
- package/dist/operations/TemplateRunOperation.d.ts.map +1 -1
- package/dist/operations/TemplateRunOperation.js +10 -1
- package/dist/operations/TemplateRunOperation.js.map +1 -1
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -85,6 +85,10 @@ if (result.Success) {
|
|
|
85
85
|
}
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
+
Stored templates are HTML-escaped by default. For plain text a model reads (AI prompt templates), pass
|
|
89
|
+
`{ autoescape: false }` as the sixth argument: `Affineur & Owner` then stays `Affineur & Owner`. The raw render keeps
|
|
90
|
+
the registered extensions, and a `{% template %}` embed inside it renders raw too.
|
|
91
|
+
|
|
88
92
|
### Simple Template Rendering
|
|
89
93
|
|
|
90
94
|
For ad-hoc templates not stored in the database:
|
|
@@ -109,6 +113,23 @@ const subject = await engine.RenderTemplateSimple(
|
|
|
109
113
|
// subject.Output: "Acme & Co — your invite" (no entity encoding)
|
|
110
114
|
```
|
|
111
115
|
|
|
116
|
+
### Variables a Template Reads
|
|
117
|
+
|
|
118
|
+
`GetReferencedVariables()` parses a template's text and returns the top-level variable names it reads:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
const result = engine.GetReferencedVariables('{% for r in rows %}{{ r.name }}{% endfor %}{{ user.email }}');
|
|
122
|
+
// result.Names: rows, r, user
|
|
123
|
+
// result.Complete: true
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
- `Names` holds top-level names only: `{{ user.email }}` gives `user`. It also holds loop, `set`, filter and keyword-argument names, so treat it as a superset of the data keys the template reads.
|
|
127
|
+
- The analysis follows stored templates named by a string literal in `{% include %}`, `{% import %}`, `{% from %}`, `{% extends %}` and `{% template %}`, and reads every content of each one. It does not follow a template named by an expression.
|
|
128
|
+
- Of the custom tags, the analysis follows `{% template %}` and reads the arguments and body of `{% AIPrompt %}`. A tag from any other extension makes the result incomplete, because the extension's code can read data that the template text does not show.
|
|
129
|
+
- `Complete: false` means "unknown", not "none". `Reason` tells why: a template is named by an expression, a named template does not exist or cannot be loaded, the text does not parse, or a tag comes from an extension the analysis does not know. A caller that keeps only the referenced data must keep all of it when the result is incomplete.
|
|
130
|
+
- The engine returns the same frozen result for the same template text until `ClearTemplateCache()`. It does not cache a result with `ParseFailed: true` (the text, or a template it pulls in, does not parse).
|
|
131
|
+
- The method sets up the Nunjucks environment and the registered extensions first, so it gives the same answer before and after the first `Config()`.
|
|
132
|
+
|
|
112
133
|
### Custom Nunjucks Filters
|
|
113
134
|
|
|
114
135
|
The engine provides built-in filters for JSON operations:
|
|
@@ -124,6 +145,68 @@ The engine provides built-in filters for JSON operations:
|
|
|
124
145
|
{% set parsed = jsonString | jsonparse %}
|
|
125
146
|
```
|
|
126
147
|
|
|
148
|
+
### Template Sandbox
|
|
149
|
+
|
|
150
|
+
Users can edit stored templates, so the engine guards nunjucks when this package loads
|
|
151
|
+
(`HardenNunjucksRuntime()`). The guard is process-wide: it also covers nunjucks environments that
|
|
152
|
+
other packages create, and templates loaded through `include` and `import`. It checks templates at
|
|
153
|
+
two points.
|
|
154
|
+
|
|
155
|
+
**Before a template compiles.** The nunjucks compiler copies names from the template into the code it
|
|
156
|
+
generates, so `AssertTemplateTreeIsSafe()` checks every parsed template first:
|
|
157
|
+
|
|
158
|
+
- Variable, filter, loop, `set`, macro, import and block names must be plain names: letters,
|
|
159
|
+
combining marks, digits, connector characters such as `_`, and `$`. A filter name can also contain
|
|
160
|
+
dots.
|
|
161
|
+
- A test name (`is defined`, `is none`) and an extension's registered name and method must not
|
|
162
|
+
contain a quote, a backslash or a line break.
|
|
163
|
+
- A name that every object inherits (a member of `Object.prototype`, such as `toString`,
|
|
164
|
+
`hasOwnProperty` or `constructor`), or `prototype`, must not be used as a dictionary key, a keyword
|
|
165
|
+
argument, a macro or call-block argument, a `set`, loop, import, macro or block name, or a filter or
|
|
166
|
+
test name. The code generator also refuses such a name as a dictionary key or keyword argument. Bare
|
|
167
|
+
names and member reads are not in this rule: `{{ constructor }}` reads only an own key of the render
|
|
168
|
+
data, and a member read such as `obj.constructor` or `value.toLocaleString()` goes through the
|
|
169
|
+
render-time member check (see below).
|
|
170
|
+
- The name of a called member, such as `obj["key"]()`, must not contain a backslash or a line break.
|
|
171
|
+
- A loop variable must not reuse an identifier that the generated loop code uses, such as `context`,
|
|
172
|
+
`frame`, `runtime`, `env`, `cb`, `next`, `tasks` or `undefined`. A unit test compiles every kind of
|
|
173
|
+
loop body with nunjucks 3.2.4, including loops inside macros and blocks, and checks this list against
|
|
174
|
+
the generated code, so a nunjucks upgrade that adds an identifier fails the test.
|
|
175
|
+
- The parse tree may hold only nunjucks nodes, plain values and regular expression literals. This
|
|
176
|
+
matters only for extensions, which build their own nodes.
|
|
177
|
+
|
|
178
|
+
**While a template renders.**
|
|
179
|
+
|
|
180
|
+
- A filter, test or global resolves only to a name that the environment registered itself, never to a
|
|
181
|
+
member that every object inherits. This also covers the test names that the `select` and `reject`
|
|
182
|
+
filters receive while the template renders. Such a name must be text, a number or another simple
|
|
183
|
+
value such as `none`; an object, a function or a symbol is refused.
|
|
184
|
+
- The member names `constructor`, `prototype` and the `__define/lookup Getter/Setter__` accessors read
|
|
185
|
+
as empty unless they hold an object's own data that is not a function. `__proto__` always reads as
|
|
186
|
+
empty. This applies to a literal member name (`obj.name`, `obj["name"]`) and to one computed while
|
|
187
|
+
the template renders (`obj[key]`) alike.
|
|
188
|
+
- A bare name such as `{{ user }}` resolves only to a template variable, an own key of the render data,
|
|
189
|
+
or an own environment global. It never resolves to a property that the data or the globals inherit,
|
|
190
|
+
such as `valueOf`.
|
|
191
|
+
- A macro or call-block argument that a call leaves out is filled only from a keyword argument of the
|
|
192
|
+
same name that the call itself passes, never from a member that the keyword arguments inherit, so
|
|
193
|
+
otherwise it reads as empty. Keyword arguments written at a call site must be a plain object literal
|
|
194
|
+
with ordinary names; keyword arguments passed as a value (from render data, for example) are read
|
|
195
|
+
through a copy of their own keys.
|
|
196
|
+
- A template must not read a member of the render context, an environment, a loader, a frame, a
|
|
197
|
+
template or a nunjucks module. A lookup or call that would return one of them fails.
|
|
198
|
+
- A template must not reach `Function` (or its async and generator variants), `eval`, `Object`,
|
|
199
|
+
`Reflect`, `globalThis` or `process`.
|
|
200
|
+
|
|
201
|
+
A template that breaks one of these rules fails with a `TemplateSandboxError`.
|
|
202
|
+
|
|
203
|
+
The guard blocks reflection and code injection, not ordinary methods. Pass templates plain data, not
|
|
204
|
+
objects whose methods reach the database or the file system (for example `BaseEntity` instances).
|
|
205
|
+
|
|
206
|
+
The `RunTemplate` mutation and the `Template.Run` remote operation also apply
|
|
207
|
+
`GetTemplateRunRefusal()` before they load anything: they refuse scope-limited sessions and callers
|
|
208
|
+
without read permission on `MJ: Templates` and `MJ: Template Contents`.
|
|
209
|
+
|
|
127
210
|
### Template Extensions
|
|
128
211
|
|
|
129
212
|
Extensions are registered via the MJ class factory:
|
|
@@ -153,9 +236,10 @@ graph LR
|
|
|
153
236
|
| `Config()` | method | Load metadata and initialize Nunjucks environment |
|
|
154
237
|
| `RenderTemplate()` | method | Render a stored template with validation |
|
|
155
238
|
| `RenderTemplateSimple()` | method | Render an ad-hoc template string |
|
|
239
|
+
| `GetReferencedVariables()` | method | List the top-level variables a template's text reads |
|
|
156
240
|
| `AddTemplate()` | method | Add a template to the Nunjucks loader |
|
|
157
241
|
| `SetupNunjucks()` | method | Re-initialize the Nunjucks environment |
|
|
158
|
-
| `ClearTemplateCache()` | method | Clear cached compiled templates |
|
|
242
|
+
| `ClearTemplateCache()` | method | Clear cached compiled templates and variable analysis results |
|
|
159
243
|
|
|
160
244
|
### Rendering Process
|
|
161
245
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview The one list of names that the template sandbox refuses wherever a template names something.
|
|
3
|
+
* @module @memberjunction/templates
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* True for a name that a template may not use as a dictionary key, a keyword argument, a macro or call-block
|
|
7
|
+
* argument, a variable, macro or block name, or a filter or test name. nunjucks reads and writes such names
|
|
8
|
+
* on plain objects, where they reach inherited members or the object's prototype.
|
|
9
|
+
* @param name the name as nunjucks uses it
|
|
10
|
+
*/
|
|
11
|
+
export declare function IsInheritedMemberName(name: string): boolean;
|
|
12
|
+
//# sourceMappingURL=InheritedMemberNames.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InheritedMemberNames.d.ts","sourceRoot":"","sources":["../src/InheritedMemberNames.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE3D"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview The one list of names that the template sandbox refuses wherever a template names something.
|
|
3
|
+
* @module @memberjunction/templates
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* The members of `Object.prototype`, which every plain object inherits (such as `constructor`, `toString`
|
|
7
|
+
* and `__proto__`), and `prototype`, which leads from a constructor to what its instances inherit.
|
|
8
|
+
*/
|
|
9
|
+
const INHERITED_MEMBER_NAMES = new Set([...Object.getOwnPropertyNames(Object.prototype), 'prototype']);
|
|
10
|
+
/**
|
|
11
|
+
* True for a name that a template may not use as a dictionary key, a keyword argument, a macro or call-block
|
|
12
|
+
* argument, a variable, macro or block name, or a filter or test name. nunjucks reads and writes such names
|
|
13
|
+
* on plain objects, where they reach inherited members or the object's prototype.
|
|
14
|
+
* @param name the name as nunjucks uses it
|
|
15
|
+
*/
|
|
16
|
+
export function IsInheritedMemberName(name) {
|
|
17
|
+
return INHERITED_MEMBER_NAMES.has(name);
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=InheritedMemberNames.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InheritedMemberNames.js","sourceRoot":"","sources":["../src/InheritedMemberNames.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,MAAM,sBAAsB,GAAwB,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC;AAE5H;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAC9C,OAAO,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks a parsed nunjucks template, and throws a {@link TemplateSandboxError} if a name in it could
|
|
3
|
+
* change the code the compiler generates:
|
|
4
|
+
* - every variable, filter, loop, `set`, macro, import and block name must be a plain name (letters,
|
|
5
|
+
* combining marks, digits, connector punctuation such as `_`, and `$`); a filter name can also contain dots
|
|
6
|
+
* - a test name, and an extension's registered name and method, must not contain a quote, a backslash or a line break
|
|
7
|
+
* - a name that every object inherits (`toString`, `hasOwnProperty`, ...), or `prototype`, must not be a
|
|
8
|
+
* dictionary key, a keyword argument, a macro or call-block argument, a `set`, loop, import, macro or
|
|
9
|
+
* block name, or a filter or test name
|
|
10
|
+
* - the name of a called member must not contain a backslash or a line break
|
|
11
|
+
* - a loop variable must not reuse an identifier that the generated loop code uses (`context`, `frame`,
|
|
12
|
+
* `runtime`, `tasks`, `undefined`, ...)
|
|
13
|
+
* - the tree must hold only nunjucks nodes, plain values and regular expression literals
|
|
14
|
+
* @param tree the root node the nunjucks parser returns
|
|
15
|
+
*/
|
|
16
|
+
export declare function AssertTemplateTreeIsSafe(tree: unknown): void;
|
|
17
|
+
//# sourceMappingURL=NunjucksCompileGuard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NunjucksCompileGuard.d.ts","sourceRoot":"","sources":["../src/NunjucksCompileGuard.ts"],"names":[],"mappings":"AA6DA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAE5D"}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Refuses nunjucks templates whose names could change the code nunjucks compiles.
|
|
3
|
+
*
|
|
4
|
+
* The nunjucks 3.2.4 compiler copies template-controlled names into the JavaScript it generates
|
|
5
|
+
* without escaping them. That covers variable, filter, test and loop names; the names that `set`,
|
|
6
|
+
* `macro`, `import` and `from` bind; and the name of a called member. The generated code runs when
|
|
7
|
+
* the template renders, so the runtime guard in `NunjucksSandbox.ts` never sees it. nunjucks also
|
|
8
|
+
* reads and writes template names as keys of plain objects, so a name that every object inherits is
|
|
9
|
+
* refused as a key, an argument or a binding. Bare names and member reads are left to the runtime guard.
|
|
10
|
+
* {@link AssertTemplateTreeIsSafe} checks a parsed template before it compiles.
|
|
11
|
+
* @module @memberjunction/templates
|
|
12
|
+
*/
|
|
13
|
+
import nunjucks from 'nunjucks';
|
|
14
|
+
import { IsInheritedMemberName } from './InheritedMemberNames.js';
|
|
15
|
+
import { TemplateSandboxError } from './TemplateSandboxError.js';
|
|
16
|
+
const NUNJUCKS = nunjucks;
|
|
17
|
+
/**
|
|
18
|
+
* Letters, combining marks, decimal digits, connector punctuation (such as `_`) and `$`. Each one is safe
|
|
19
|
+
* inside a JavaScript string. In a raw identifier, a character that cannot start it (a digit, a mark, or
|
|
20
|
+
* connector punctuation other than `_`) or cannot appear in it at all (U+2E2F) only makes the generated
|
|
21
|
+
* code fail with a SyntaxError.
|
|
22
|
+
*/
|
|
23
|
+
const PLAIN_NAME = /^[\p{L}\p{Mn}\p{Mc}\p{Nd}\p{Pc}$]+$/u;
|
|
24
|
+
/** A filter name can also contain dots (`{{ x | ns.filter }}`). */
|
|
25
|
+
const PLAIN_FILTER_NAME = /^[\p{L}\p{Mn}\p{Mc}\p{Nd}\p{Pc}$]+(?:\.[\p{L}\p{Mn}\p{Mc}\p{Nd}\p{Pc}$]+)*$/u;
|
|
26
|
+
/** Characters that end a double-quoted JavaScript string, or escape out of it. */
|
|
27
|
+
const UNSAFE_STRING_CHARACTERS = /["\\\r\n\u2028\u2029]/;
|
|
28
|
+
/** The compiler escapes `"` in a called member's name, so only these characters can end that string. */
|
|
29
|
+
const UNSAFE_CALL_NAME_CHARACTERS = /[\\\r\n\u2028\u2029]/;
|
|
30
|
+
/**
|
|
31
|
+
* Identifiers that the generated code of a loop body uses (nunjucks 3.2.4). An async loop binds its loop
|
|
32
|
+
* variables as raw function parameters, so a loop variable with one of these names shadows them.
|
|
33
|
+
* `NunjucksCompileGuard.test.ts` compiles every kind of loop body and checks this list against the
|
|
34
|
+
* generated code.
|
|
35
|
+
*/
|
|
36
|
+
const RESERVED_LOOP_NAMES = new Set([
|
|
37
|
+
'env', 'context', 'frame', 'runtime', 'cb', 'next', 'lineno', 'colno', 'output', 'tasks',
|
|
38
|
+
'parentTemplate', 'callerFrame', 'kwargs', 'Object', 'Math', 'Error', 'undefined', 'Infinity',
|
|
39
|
+
]);
|
|
40
|
+
/** Prefixes of generated identifiers: temporaries (`t_3`, `macro_t_3`, `hole_0`), blocks (`b_`), macro arguments (`l_`). */
|
|
41
|
+
const RESERVED_LOOP_NAME_PREFIX = /^(?:t|macro_t|hole|b|l)_/;
|
|
42
|
+
/**
|
|
43
|
+
* Checks a parsed nunjucks template, and throws a {@link TemplateSandboxError} if a name in it could
|
|
44
|
+
* change the code the compiler generates:
|
|
45
|
+
* - every variable, filter, loop, `set`, macro, import and block name must be a plain name (letters,
|
|
46
|
+
* combining marks, digits, connector punctuation such as `_`, and `$`); a filter name can also contain dots
|
|
47
|
+
* - a test name, and an extension's registered name and method, must not contain a quote, a backslash or a line break
|
|
48
|
+
* - a name that every object inherits (`toString`, `hasOwnProperty`, ...), or `prototype`, must not be a
|
|
49
|
+
* dictionary key, a keyword argument, a macro or call-block argument, a `set`, loop, import, macro or
|
|
50
|
+
* block name, or a filter or test name
|
|
51
|
+
* - the name of a called member must not contain a backslash or a line break
|
|
52
|
+
* - a loop variable must not reuse an identifier that the generated loop code uses (`context`, `frame`,
|
|
53
|
+
* `runtime`, `tasks`, `undefined`, ...)
|
|
54
|
+
* - the tree must hold only nunjucks nodes, plain values and regular expression literals
|
|
55
|
+
* @param tree the root node the nunjucks parser returns
|
|
56
|
+
*/
|
|
57
|
+
export function AssertTemplateTreeIsSafe(tree) {
|
|
58
|
+
new TemplateTreeCheck().Visit(tree);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* One pass over a parse tree. It visits every own property of every node, not only the fields
|
|
62
|
+
* nunjucks lists, because the parser stores some compiled parts outside them (the body of a `set` block).
|
|
63
|
+
*/
|
|
64
|
+
class TemplateTreeCheck {
|
|
65
|
+
constructor() {
|
|
66
|
+
this.visited = new WeakSet();
|
|
67
|
+
this.filterNames = new WeakSet();
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Checks a value of the tree and everything under it.
|
|
71
|
+
* @param owner the node whose field holds the value
|
|
72
|
+
* @param field the name of that field
|
|
73
|
+
*/
|
|
74
|
+
Visit(value, owner, field) {
|
|
75
|
+
if (Array.isArray(value)) {
|
|
76
|
+
asArray(value).forEach((item) => this.Visit(item, owner, field));
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (!isNode(value)) {
|
|
80
|
+
if (!isPlainValue(value) && !isPatternLiteral(value, owner, field)) {
|
|
81
|
+
throw refusal('Template parse trees may only hold nunjucks nodes, plain values and regular expressions', owner);
|
|
82
|
+
}
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (this.visited.has(value)) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
this.visited.add(value);
|
|
89
|
+
this.checkNode(value);
|
|
90
|
+
for (const key of Object.keys(value)) {
|
|
91
|
+
this.Visit(property(value, key), value, key);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
checkNode(node) {
|
|
95
|
+
switch (node.typename) {
|
|
96
|
+
case 'Symbol':
|
|
97
|
+
return this.checkName(node, node, this.filterNames.has(node) ? PLAIN_FILTER_NAME : PLAIN_NAME);
|
|
98
|
+
case 'Pair':
|
|
99
|
+
return this.refuseInheritedName(nameValue(property(node, 'key')), node, 'a dictionary key or keyword argument');
|
|
100
|
+
case 'Filter':
|
|
101
|
+
case 'FilterAsync':
|
|
102
|
+
return this.checkFilterName(node);
|
|
103
|
+
case 'Is':
|
|
104
|
+
return this.checkTestName(node);
|
|
105
|
+
case 'FunCall':
|
|
106
|
+
return this.checkCallName(node);
|
|
107
|
+
case 'Set':
|
|
108
|
+
return asArray(property(node, 'targets')).forEach((target) => this.checkBindingName(target, node));
|
|
109
|
+
case 'For':
|
|
110
|
+
case 'AsyncEach':
|
|
111
|
+
case 'AsyncAll':
|
|
112
|
+
return this.checkLoopNames(node);
|
|
113
|
+
case 'Macro':
|
|
114
|
+
case 'Caller':
|
|
115
|
+
return this.checkMacroNames(node);
|
|
116
|
+
case 'Import':
|
|
117
|
+
return this.checkBindingName(property(node, 'target'), node);
|
|
118
|
+
case 'FromImport':
|
|
119
|
+
return this.checkImportedNames(node);
|
|
120
|
+
case 'Block':
|
|
121
|
+
return this.checkBindingName(property(node, 'name'), node);
|
|
122
|
+
case 'Super':
|
|
123
|
+
return this.checkName(property(node, 'blockName'), node);
|
|
124
|
+
case 'CallExtension':
|
|
125
|
+
case 'CallExtensionAsync':
|
|
126
|
+
return this.checkExtensionCall(node);
|
|
127
|
+
default:
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/** A name the compiler copies as written: a symbol or a quoted string that is a plain name. */
|
|
132
|
+
checkName(nameNode, owner, pattern = PLAIN_NAME) {
|
|
133
|
+
const name = nameValue(nameNode);
|
|
134
|
+
if (name === undefined || !pattern.test(name)) {
|
|
135
|
+
throw refusal('Templates may only use plain names (letters, marks, digits, _ and $)', owner);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/** The one rule for every position that names something: a name that `IsInheritedMemberName` matches is refused. */
|
|
139
|
+
refuseInheritedName(name, owner, position) {
|
|
140
|
+
if (name !== undefined && IsInheritedMemberName(name)) {
|
|
141
|
+
throw refusal(`Templates may not use "${name}" as ${position}`, owner);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/** A name that `set`, a loop, `import`, `from` or `macro` binds as a variable, or a block name. */
|
|
145
|
+
checkBindingName(nameNode, owner) {
|
|
146
|
+
this.checkName(nameNode, owner);
|
|
147
|
+
this.refuseInheritedName(nameValue(nameNode), owner, 'a variable, macro or block name');
|
|
148
|
+
}
|
|
149
|
+
/** nunjucks finds a filter in a plain object, so a name it inherits would resolve to the inherited member. */
|
|
150
|
+
checkFilterName(node) {
|
|
151
|
+
const name = property(node, 'name');
|
|
152
|
+
if (isNode(name)) {
|
|
153
|
+
this.filterNames.add(name);
|
|
154
|
+
}
|
|
155
|
+
this.checkName(name, node, PLAIN_FILTER_NAME);
|
|
156
|
+
this.refuseInheritedName(nameValue(name), node, 'a filter or test name');
|
|
157
|
+
}
|
|
158
|
+
/** The compiler writes the test name into a double-quoted string, as text and without escaping it. */
|
|
159
|
+
checkTestName(node) {
|
|
160
|
+
const name = testName(node);
|
|
161
|
+
if (UNSAFE_STRING_CHARACTERS.test(name)) {
|
|
162
|
+
throw refusal('Templates may not use a test name that contains a quote, a backslash or a line break', node);
|
|
163
|
+
}
|
|
164
|
+
this.refuseInheritedName(name, node, 'a filter or test name');
|
|
165
|
+
}
|
|
166
|
+
/** The compiler writes the called expression's name, built by its own `_getNodeName`, into a string. */
|
|
167
|
+
checkCallName(node) {
|
|
168
|
+
let name;
|
|
169
|
+
try {
|
|
170
|
+
const compiler = NUNJUCKS.compiler.Compiler.prototype;
|
|
171
|
+
name = compiler._getNodeName.call(compiler, property(node, 'name'));
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
name = undefined;
|
|
175
|
+
}
|
|
176
|
+
if (typeof name !== 'string' || UNSAFE_CALL_NAME_CHARACTERS.test(name)) {
|
|
177
|
+
throw refusal('Templates may not call a member whose name contains a backslash or a line break', node);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
checkLoopNames(node) {
|
|
181
|
+
const name = property(node, 'name');
|
|
182
|
+
const loopNames = isNode(name) && name.typename === 'Array' ? asArray(property(name, 'children')) : [name];
|
|
183
|
+
for (const loopName of loopNames) {
|
|
184
|
+
this.checkBindingName(loopName, node);
|
|
185
|
+
const value = nameValue(loopName) ?? '';
|
|
186
|
+
if (RESERVED_LOOP_NAMES.has(value) || RESERVED_LOOP_NAME_PREFIX.test(value)) {
|
|
187
|
+
throw refusal(`Templates may not use "${value}" as a loop variable`, node);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/** Positional arguments, and the keys of a trailing keyword-argument dictionary, become names. */
|
|
192
|
+
checkMacroNames(node) {
|
|
193
|
+
this.checkBindingName(property(node, 'name'), node);
|
|
194
|
+
const args = asArray(property(property(node, 'args'), 'children'));
|
|
195
|
+
args.forEach((arg, index) => {
|
|
196
|
+
const isKeywordArguments = index === args.length - 1 && isNode(arg) && (arg.typename === 'Dict' || arg.typename === 'KeywordArgs');
|
|
197
|
+
if (!isKeywordArguments) {
|
|
198
|
+
this.checkArgumentName(arg, node);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
asArray(property(arg, 'children')).forEach((pair) => this.checkArgumentName(property(pair, 'key'), node));
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* A macro or call-block argument. When a call leaves out a positional argument, nunjucks fills it from the
|
|
206
|
+
* call's keyword arguments, so an argument named after a member every object inherits would read that member.
|
|
207
|
+
*/
|
|
208
|
+
checkArgumentName(nameNode, owner) {
|
|
209
|
+
this.checkName(nameNode, owner);
|
|
210
|
+
this.refuseInheritedName(nameValue(nameNode), owner, 'a macro or call-block argument');
|
|
211
|
+
}
|
|
212
|
+
/** The names `from ... import` reads from the imported template, and the names it binds. */
|
|
213
|
+
checkImportedNames(node) {
|
|
214
|
+
for (const entry of asArray(property(property(node, 'names'), 'children'))) {
|
|
215
|
+
if (isNode(entry) && entry.typename === 'Pair') {
|
|
216
|
+
this.checkBindingName(property(entry, 'key'), node);
|
|
217
|
+
this.checkBindingName(property(entry, 'value'), node);
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
this.checkBindingName(entry, node);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/** The compiler writes an extension tag's registered name and method into double-quoted strings. */
|
|
225
|
+
checkExtensionCall(node) {
|
|
226
|
+
for (const value of [property(node, 'extName'), property(node, 'prop')]) {
|
|
227
|
+
if (typeof value !== 'string' || UNSAFE_STRING_CHARACTERS.test(value)) {
|
|
228
|
+
throw refusal('Template extensions must have names without a quote, a backslash or a line break', node);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* The test name as the compiler writes it: the text of the called name's value for `is test(...)`,
|
|
235
|
+
* else the text of the test's own value. `is none` gives `"null"`.
|
|
236
|
+
*/
|
|
237
|
+
function testName(node) {
|
|
238
|
+
const test = property(node, 'right');
|
|
239
|
+
const calledName = property(test, 'name');
|
|
240
|
+
return String(calledName ? property(calledName, 'value') : property(test, 'value'));
|
|
241
|
+
}
|
|
242
|
+
function isNode(value) {
|
|
243
|
+
return value instanceof NUNJUCKS.nodes.Node;
|
|
244
|
+
}
|
|
245
|
+
/** `undefined`, `null`, a string, a number or a boolean. */
|
|
246
|
+
function isPlainValue(value) {
|
|
247
|
+
return value === undefined || value === null || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';
|
|
248
|
+
}
|
|
249
|
+
/** A regular expression literal (`r/.../`), which the parser stores as the value of a Literal node. */
|
|
250
|
+
function isPatternLiteral(value, owner, field) {
|
|
251
|
+
return value instanceof RegExp && owner?.typename === 'Literal' && field === 'value';
|
|
252
|
+
}
|
|
253
|
+
/** A node's field, or `undefined` when the value is not a node. */
|
|
254
|
+
function property(node, key) {
|
|
255
|
+
return isNode(node) ? node[key] : undefined;
|
|
256
|
+
}
|
|
257
|
+
function asArray(value) {
|
|
258
|
+
return Array.isArray(value) ? value : [];
|
|
259
|
+
}
|
|
260
|
+
/** The text of a symbol or of a quoted string, or `undefined` for any other node. */
|
|
261
|
+
function nameValue(node) {
|
|
262
|
+
if (!isNode(node) || (node.typename !== 'Symbol' && node.typename !== 'Literal')) {
|
|
263
|
+
return undefined;
|
|
264
|
+
}
|
|
265
|
+
const value = property(node, 'value');
|
|
266
|
+
return typeof value === 'string' ? value : undefined;
|
|
267
|
+
}
|
|
268
|
+
/** The error for a refused template, with the node's position when the node has one. */
|
|
269
|
+
function refusal(reason, node) {
|
|
270
|
+
const hasPosition = node !== undefined && Number.isInteger(node.lineno) && Number.isInteger(node.colno);
|
|
271
|
+
return new TemplateSandboxError(hasPosition ? `${reason} (line ${node.lineno + 1}, column ${node.colno + 1})` : reason);
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=NunjucksCompileGuard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NunjucksCompileGuard.js","sourceRoot":"","sources":["../src/NunjucksCompileGuard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guards the nunjucks parser, code generator and runtime used by every nunjucks environment in this process. After this call:
|
|
3
|
+
* - a template whose names could change the compiled code fails to compile (see `AssertTemplateTreeIsSafe`)
|
|
4
|
+
* - a macro or call-block argument that a call leaves out is filled only from a keyword argument that the
|
|
5
|
+
* call itself passes under that name, never from a member the keyword arguments inherit, so otherwise it
|
|
6
|
+
* reads as empty
|
|
7
|
+
* - keyword arguments written at a call site must be an ordinary object literal: ones that inherit from anything
|
|
8
|
+
* but `Object.prototype`, or that use a name that every object inherits (or `prototype`), throw, and the code
|
|
9
|
+
* generator refuses such a name as a dictionary key or keyword argument too; keyword arguments passed as a
|
|
10
|
+
* value (from render data, for example) are read through a copy of their own keys
|
|
11
|
+
* - a filter, test or global resolves only to a name the environment registered itself, never to a member
|
|
12
|
+
* that every object inherits (such as `hasOwnProperty`); an object, a function or a symbol is refused as the name
|
|
13
|
+
* - a member named `constructor`, `prototype`, `__proto__` or one of the `__define/lookup Getter/Setter__`
|
|
14
|
+
* accessors, written literally or computed while rendering, reads as `undefined`, unless it is an object's
|
|
15
|
+
* own data that is not a function; `__proto__` always reads as `undefined`
|
|
16
|
+
* - a bare name resolves only to a template variable, an own key of the render data, or an own environment
|
|
17
|
+
* global, never to a property that the render data or the globals inherit
|
|
18
|
+
* - a template may not read a member of the render context, an environment, a loader, a frame, a
|
|
19
|
+
* template or a nunjucks module, and a lookup or call that would return one of them throws
|
|
20
|
+
* - a lookup or call that would produce or use `Function` (or its async and generator variants), `eval`,
|
|
21
|
+
* `Object`, `Reflect`, `globalThis` or `process` throws a {@link TemplateSandboxError}
|
|
22
|
+
*
|
|
23
|
+
* Safe to call any number of times: a hook that already carries the guard is left as it is.
|
|
24
|
+
*/
|
|
25
|
+
export declare function HardenNunjucksRuntime(): void;
|
|
26
|
+
//# sourceMappingURL=NunjucksSandbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NunjucksSandbox.d.ts","sourceRoot":"","sources":["../src/NunjucksSandbox.ts"],"names":[],"mappings":"AAiIA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAY5C"}
|