mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-19 22:40:48 -07:00
fix: unify blocked-key checks in findScope
Use shouldBlockScopeKeyRead in findScope hasKey so inherited constructor/__proto__/prototype do not falsely match environments. Remove redundant globals hasKey check; globals remains the fallback scope. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { Drop } from '../drop/drop'
|
import { Drop } from '../drop/drop'
|
||||||
import { __assign } from 'tslib'
|
import { __assign } from 'tslib'
|
||||||
import { NormalizedFullOptions, defaultOptions, RenderOptions } from '../liquid-options'
|
import { NormalizedFullOptions, defaultOptions, RenderOptions } from '../liquid-options'
|
||||||
import { createScope, isBlockedScopeKey, Scope, shouldBlockScopeKeyRead } from './scope'
|
import { createScope, Scope, shouldBlockScopeKeyRead } from './scope'
|
||||||
import { hasOwnProperty, isArray, isNil, isUndefined, isString, isFunction, isNumber, toLiquid, InternalUndefinedVariableError, toValueSync, isObject, Limiter, toValue, readArrayElement } from '../util'
|
import { hasOwnProperty, isArray, isNil, isUndefined, isString, isFunction, isNumber, toLiquid, InternalUndefinedVariableError, toValueSync, isObject, Limiter, toValue, readArrayElement } from '../util'
|
||||||
|
|
||||||
type PropertyKey = string | number;
|
type PropertyKey = string | number;
|
||||||
@@ -116,9 +116,9 @@ export class Context {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
private findScope (key: string | number) {
|
private findScope (key: string | number) {
|
||||||
if (isBlockedScopeKey(key) && this.ownPropertyOnly) return createScope()
|
|
||||||
const hasKey = (obj: Scope) => {
|
const hasKey = (obj: Scope) => {
|
||||||
if (obj == null) return false
|
if (obj == null) return false
|
||||||
|
if (shouldBlockScopeKeyRead(obj, key, this.ownPropertyOnly)) return false
|
||||||
return this.ownPropertyOnly
|
return this.ownPropertyOnly
|
||||||
? hasOwnProperty.call(obj, key)
|
? hasOwnProperty.call(obj, key)
|
||||||
: key in obj
|
: key in obj
|
||||||
@@ -128,7 +128,6 @@ export class Context {
|
|||||||
if (hasKey(candidate)) return candidate
|
if (hasKey(candidate)) return candidate
|
||||||
}
|
}
|
||||||
if (hasKey(this.environments)) return this.environments
|
if (hasKey(this.environments)) return this.environments
|
||||||
if (hasKey(this.globals)) return this.globals
|
|
||||||
return this.globals
|
return this.globals
|
||||||
}
|
}
|
||||||
readProperty (obj: Scope, key: (PropertyKey | Drop)) {
|
readProperty (obj: Scope, key: (PropertyKey | Drop)) {
|
||||||
|
|||||||
@@ -72,6 +72,10 @@ describe('scope security', function () {
|
|||||||
await expect(liquid.parseAndRender('{{ foo.constructor.name }}', scope, { ownPropertyOnly: false })).resolves.toBe('')
|
await expect(liquid.parseAndRender('{{ foo.constructor.name }}', scope, { ownPropertyOnly: false })).resolves.toBe('')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should not resolve top-level inherited constructor when ownPropertyOnly=false', async function () {
|
||||||
|
await expect(liquid.parseAndRender('{{ constructor.name }}', { name: 'Alice' }, { ownPropertyOnly: false })).resolves.toBe('')
|
||||||
|
})
|
||||||
|
|
||||||
it('should not write increment to __proto__ on user scope', async function () {
|
it('should not write increment to __proto__ on user scope', async function () {
|
||||||
const scope = Object.create(null) as Record<string, unknown>
|
const scope = Object.create(null) as Record<string, unknown>
|
||||||
await expect(liquid.parseAndRender('{% increment __proto__ %}', scope)).resolves.toBe('')
|
await expect(liquid.parseAndRender('{% increment __proto__ %}', scope)).resolves.toBe('')
|
||||||
|
|||||||
Reference in New Issue
Block a user