feat: remove memoryLimit; add templateLimit, outputLengthLimit, maxDepth (#937)

* feat: remove memoryLimit option (#910)

Co-authored-by: Cursor <[email protected]>

* feat: add templateLimit, outputLengthLimit, and maxDepth DoS limits

Enforce v11 resource guards in render and tags, fix for offset/else behavior, and update tutorials for Tag-class registration.

Co-authored-by: Cursor <[email protected]>

* docs: revert unnecessary tutorial churn from memoryLimit PR

Restore the two-example register-filters-tags structure (Value + Hash)
and undo unrelated constructor/emitter doc edits not required for DoS limits.

Co-authored-by: Cursor <[email protected]>

* docs: trim security-model prose and update render-tag-content

Remove diary-style engine comparisons from security-model.md.
Update render-tag-content tutorial to Tag class examples with tpls class field.

Co-authored-by: Cursor <[email protected]>

* docs: note maxDepth stack overflow applies to renderSync only

Explain why async render does not need maxDepth for stack protection based on generator/toPromise driving.

Co-authored-by: Cursor <[email protected]>

* refactor: track maxDepth via depthLimit Limiter on Context

Replace increaseDepth/decreaseDepth with a shared Limiter that supports
paired use/release, matching templateLimit and outputLengthLimit patterns.

Co-authored-by: Cursor <[email protected]>

* fix: remove spurious diff noise in filter files

Restore misc.ts from origin/next with LF line endings and re-apply only
memoryLimit removal, avoiding CRLF and blank-line churn in the export block.

Co-authored-by: Cursor <[email protected]>

* refactor: minimize PR diff noise

Co-authored-by: Cursor <[email protected]>

* feat: cap strftime pad width at 1M

docs: restructure security model with production guidance
Co-authored-by: Cursor <[email protected]>

* refactor: simplify depthLimit in partial tags and tighten security docs

Drop try/finally around depthLimit in include, layout, and render; release at generator end. Consolidate production guidance in security-model.md. Fix padded-blocks lint in dos.spec.ts.

Co-authored-by: Cursor <[email protected]>

---------

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Yang Jun
2026-07-15 22:58:13 +08:00
committed by GitHub
co-authored by Cursor
parent f0b6cd375c
commit 61ed163821
29 changed files with 305 additions and 312 deletions
+10 -8
View File
@@ -1,4 +1,3 @@
import { getPerformance } from '../util/performance'
import { Drop } from '../drop/drop'
import { __assign } from 'tslib'
import { NormalizedFullOptions, defaultOptions, RenderOptions } from '../liquid-options'
@@ -36,17 +35,19 @@ export class Context {
*/
public strictVariables: boolean;
public ownPropertyOnly: boolean;
public memoryLimit: Limiter;
public renderLimit: Limiter;
public constructor (env: object = {}, opts: NormalizedFullOptions = defaultOptions, renderOptions: RenderOptions = {}, { memoryLimit, renderLimit }: { [key: string]: Limiter } = {}) {
public templateLimit: Limiter;
public outputLengthLimit: Limiter;
public depthLimit: Limiter;
public constructor (env: object = {}, opts: NormalizedFullOptions = defaultOptions, renderOptions: RenderOptions = {}, { templateLimit, outputLengthLimit, depthLimit }: { templateLimit?: Limiter, outputLengthLimit?: Limiter, depthLimit?: Limiter } = {}) {
this.sync = !!renderOptions.sync
this.opts = opts
this.globals = renderOptions.globals ?? opts.globals
this.environments = isObject(env) ? env : Object(env)
this.strictVariables = renderOptions.strictVariables ?? this.opts.strictVariables
this.ownPropertyOnly = renderOptions.ownPropertyOnly ?? opts.ownPropertyOnly
this.memoryLimit = memoryLimit ?? new Limiter('memory alloc', renderOptions.memoryLimit ?? opts.memoryLimit)
this.renderLimit = renderLimit ?? new Limiter('template render', getPerformance().now() + (renderOptions.renderLimit ?? opts.renderLimit))
this.templateLimit = templateLimit ?? new Limiter('template', renderOptions.templateLimit ?? opts.templateLimit)
this.outputLengthLimit = outputLengthLimit ?? new Limiter('output length', renderOptions.outputLengthLimit ?? opts.outputLengthLimit)
this.depthLimit = depthLimit ?? new Limiter('template depth', opts.maxDepth)
}
public getRegister<T> (key: string, defaultValue: T = undefined as T): T {
return (this.registers[key] = this.registers[key] || defaultValue)
@@ -109,8 +110,9 @@ export class Context {
strictVariables: this.strictVariables,
ownPropertyOnly: this.ownPropertyOnly
}, {
renderLimit: this.renderLimit,
memoryLimit: this.memoryLimit
templateLimit: this.templateLimit,
outputLengthLimit: this.outputLengthLimit,
depthLimit: this.depthLimit
})
}
private findScope (key: string | number) {