mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-15 20:30:39 -07:00
fix: enforce root containment for renderFile/parseFile lookups (#870)
Made-with: Cursor
This commit is contained in:
@@ -30,5 +30,11 @@ describe('fs/loader', function () {
|
|||||||
const result = toValueSync(loader.lookup('./foo/bar', LookupType.Partials, true, '/root/current'))
|
const result = toValueSync(loader.lookup('./foo/bar', LookupType.Partials, true, '/root/current'))
|
||||||
expect(result).toBe(resolve('/root/foo/bar'))
|
expect(result).toBe(resolve('/root/foo/bar'))
|
||||||
})
|
})
|
||||||
|
it('should enforce containment for LookupType.Root', function () {
|
||||||
|
const mockFs = { ...fs, existsSync: () => true, exists: async () => true }
|
||||||
|
const loader = new Loader({ relativeReference: false, fs: mockFs, extname: '', root: ['/safe'] } as any)
|
||||||
|
expect(() => toValueSync(loader.lookup('/etc/hosts', LookupType.Root, true)))
|
||||||
|
.toThrow(/ENOENT/)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
+4
-7
@@ -43,15 +43,12 @@ export class Loader {
|
|||||||
|
|
||||||
public * lookup (file: string, type: LookupType, sync?: boolean, currentFile?: string): Generator<unknown, string, string> {
|
public * lookup (file: string, type: LookupType, sync?: boolean, currentFile?: string): Generator<unknown, string, string> {
|
||||||
const dirs = this.options[type]
|
const dirs = this.options[type]
|
||||||
const enforceRoot = type !== LookupType.Root
|
|
||||||
for (const filepath of this.candidates(file, dirs, currentFile)) {
|
for (const filepath of this.candidates(file, dirs, currentFile)) {
|
||||||
if (enforceRoot) {
|
let allowed = false
|
||||||
let allowed = false
|
for (const dir of dirs) {
|
||||||
for (const dir of dirs) {
|
if (yield this.contains(!!sync, dir, filepath)) { allowed = true; break }
|
||||||
if (yield this.contains(!!sync, dir, filepath)) { allowed = true; break }
|
|
||||||
}
|
|
||||||
if (!allowed) continue
|
|
||||||
}
|
}
|
||||||
|
if (!allowed) continue
|
||||||
if (yield this.exists(!!sync, filepath)) return filepath
|
if (yield this.exists(!!sync, filepath)) return filepath
|
||||||
}
|
}
|
||||||
throw this.lookupError(file, dirs)
|
throw this.lookupError(file, dirs)
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ describe('#renderFile()', function () {
|
|||||||
return expect(html).toContain('"name": "liquidjs"')
|
return expect(html).toContain('"name": "liquidjs"')
|
||||||
})
|
})
|
||||||
it('should render file with context', async function () {
|
it('should render file with context', async function () {
|
||||||
|
engine = new Liquid({ root: views, extname: '.html' })
|
||||||
const html = await engine.renderFile(resolve(views, 'name.html'), { name: 'harttle' })
|
const html = await engine.renderFile(resolve(views, 'name.html'), { name: 'harttle' })
|
||||||
return expect(html).toBe('My name is harttle.')
|
return expect(html).toBe('My name is harttle.')
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import { drainStream } from '../stub/stream'
|
|||||||
describe('.renderToNodeStream()', function () {
|
describe('.renderToNodeStream()', function () {
|
||||||
it('should render to stream in Node.js', done => {
|
it('should render to stream in Node.js', done => {
|
||||||
const cjs = require('../../dist/liquid.node')
|
const cjs = require('../../dist/liquid.node')
|
||||||
const engine = new cjs.Liquid()
|
const engine = new cjs.Liquid({ root: resolve(__dirname, '../stub/root/') })
|
||||||
const tpl = engine.parseFileSync(resolve(__dirname, '../stub/root/foo.html'))
|
const tpl = engine.parseFileSync('foo.html')
|
||||||
const stream = engine.renderToNodeStream(tpl)
|
const stream = engine.renderToNodeStream(tpl)
|
||||||
let html = ''
|
let html = ''
|
||||||
stream.on('data', (data: string) => { html += data })
|
stream.on('data', (data: string) => { html += data })
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ describe('Liquid', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
describe('#renderFile', function () {
|
describe('#renderFile', function () {
|
||||||
|
afterEach(restore)
|
||||||
it('should throw with lookup list when file not exist', function () {
|
it('should throw with lookup list when file not exist', function () {
|
||||||
const engine = new Liquid({
|
const engine = new Liquid({
|
||||||
root: ['/boo', '/root/'],
|
root: ['/boo', '/root/'],
|
||||||
@@ -116,6 +117,22 @@ describe('Liquid', function () {
|
|||||||
})
|
})
|
||||||
return expect(engine.renderFile('/not/exist.html')).rejects.toThrow(/Failed to lookup "\/not\/exist.html" in "\/boo,\/root\/"/)
|
return expect(engine.renderFile('/not/exist.html')).rejects.toThrow(/Failed to lookup "\/not\/exist.html" in "\/boo,\/root\/"/)
|
||||||
})
|
})
|
||||||
|
it('should reject absolute paths outside root', async function () {
|
||||||
|
mock({
|
||||||
|
'/safe/foo.html': 'safe',
|
||||||
|
'/etc/secret': 'SECRET'
|
||||||
|
})
|
||||||
|
const engine = new Liquid({ root: ['/safe'] })
|
||||||
|
await expect(engine.renderFile('/etc/secret')).rejects.toThrow(/Failed to lookup/)
|
||||||
|
})
|
||||||
|
it('should reject absolute paths outside root (sync)', function () {
|
||||||
|
mock({
|
||||||
|
'/safe/foo.html': 'safe',
|
||||||
|
'/etc/secret': 'SECRET'
|
||||||
|
})
|
||||||
|
const engine = new Liquid({ root: ['/safe'] })
|
||||||
|
expect(() => engine.renderFileSync('/etc/secret')).toThrow(/Failed to lookup/)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
describe('#parseFile', function () {
|
describe('#parseFile', function () {
|
||||||
it('should throw with lookup list when file not exist', function () {
|
it('should throw with lookup list when file not exist', function () {
|
||||||
@@ -127,7 +144,7 @@ describe('Liquid', function () {
|
|||||||
})
|
})
|
||||||
it('should fallback to require.resolve in Node.js', async function () {
|
it('should fallback to require.resolve in Node.js', async function () {
|
||||||
const engine = new Liquid({
|
const engine = new Liquid({
|
||||||
root: ['/root/'],
|
root: [process.cwd()],
|
||||||
extname: '.html'
|
extname: '.html'
|
||||||
})
|
})
|
||||||
const tpls = await engine.parseFileSync('jest')
|
const tpls = await engine.parseFileSync('jest')
|
||||||
|
|||||||
Reference in New Issue
Block a user