mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-15 20:30:39 -07:00
fix(filters): support Buffer input in base64_encode to prevent binary data corruption (#881)
* fix: support Buffer input in base64_encode filter
When binary data (e.g. images, PDFs) is passed through the template
context as a Node.js Buffer, the base64_encode filter would call
stringify() on it first, which internally does String(value). This
triggers Buffer.toString() with the default 'utf-8' encoding, which
is a lossy conversion for non-UTF-8 byte sequences — invalid bytes
get replaced with U+FFFD, permanently destroying the original data.
The fix checks for Buffer.isBuffer() before stringify, and calls
buffer.toString('base64') directly, bypassing the lossy UTF-8
intermediate step. String inputs continue through the existing path
unchanged.
Made-with: Cursor
* fix: handle Buffer in filter layer to fix browser build
Move Buffer handling from base64-impl.ts (which gets swapped for the
browser impl at build time) into base64.ts (the filter layer). This
avoids a type error during the browser rollup build where the browser
impl only accepts string.
Also guard Buffer.isBuffer() with typeof Buffer !== 'undefined' for
safety in browser environments.
Made-with: Cursor
This commit is contained in:
@@ -8,7 +8,11 @@ import { FilterImpl } from '../template'
|
|||||||
import { stringify } from '../util'
|
import { stringify } from '../util'
|
||||||
import { base64Encode, base64Decode } from './base64-impl'
|
import { base64Encode, base64Decode } from './base64-impl'
|
||||||
|
|
||||||
export function base64_encode (this: FilterImpl, value: string): string {
|
export function base64_encode (this: FilterImpl, value: string | Buffer): string {
|
||||||
|
if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {
|
||||||
|
this.context.memoryLimit.use(value.byteLength)
|
||||||
|
return value.toString('base64')
|
||||||
|
}
|
||||||
const str = stringify(value)
|
const str = stringify(value)
|
||||||
this.context.memoryLimit.use(str.length)
|
this.context.memoryLimit.use(str.length)
|
||||||
return base64Encode(str)
|
return base64Encode(str)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { test } from '../../stub/render'
|
import { test, liquid } from '../../stub/render'
|
||||||
|
|
||||||
describe('filters/base64', function () {
|
describe('filters/base64', function () {
|
||||||
describe('base64_encode', function () {
|
describe('base64_encode', function () {
|
||||||
@@ -65,6 +65,33 @@ describe('filters/base64', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('base64_encode with Buffer input', function () {
|
||||||
|
it('should encode a Buffer to base64 without data corruption', async () => {
|
||||||
|
const buf = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0xff, 0xfe])
|
||||||
|
const result = await liquid.parseAndRender('{{ data | base64_encode }}', { data: buf })
|
||||||
|
expect(result).toBe(buf.toString('base64'))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should preserve bytes that are invalid UTF-8', async () => {
|
||||||
|
const buf = Buffer.from([0x80, 0xff, 0xfe, 0x00, 0x01])
|
||||||
|
const result = await liquid.parseAndRender('{{ data | base64_encode }}', { data: buf })
|
||||||
|
const decoded = Buffer.from(result, 'base64')
|
||||||
|
expect(decoded).toEqual(buf)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle an empty Buffer', async () => {
|
||||||
|
const buf = Buffer.alloc(0)
|
||||||
|
const result = await liquid.parseAndRender('{{ data | base64_encode }}', { data: buf })
|
||||||
|
expect(result).toBe('')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle a Buffer containing valid UTF-8 text', async () => {
|
||||||
|
const buf = Buffer.from('Hello World', 'utf8')
|
||||||
|
const result = await liquid.parseAndRender('{{ data | base64_encode }}', { data: buf })
|
||||||
|
expect(result).toBe(Buffer.from('Hello World').toString('base64'))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('base64 round-trip', function () {
|
describe('base64 round-trip', function () {
|
||||||
it('should encode and decode back to original', () => {
|
it('should encode and decode back to original', () => {
|
||||||
return test('{{ "Hello, World!" | base64_encode | base64_decode }}', 'Hello, World!')
|
return test('{{ "Hello, World!" | base64_encode | base64_decode }}', 'Hello, World!')
|
||||||
|
|||||||
Reference in New Issue
Block a user