refactor(strftime): rely on memoryLimit for width control

Remove MAX_STRFTIME_PAD hard capping and rely on memoryLimit enforcement before padding allocation. Update strftime/date tests and security-model docs to match the new boundary and renderLimit caveats.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Yang Jun
2026-05-10 13:34:37 +08:00
co-authored by Cursor
parent b2d68fba5f
commit b405733cdb
5 changed files with 9 additions and 19 deletions
-9
View File
@@ -31,10 +31,6 @@ describe('util/strftime', function () {
expect(t(date, '%j')).toBe('061')
})
})
it('should cap excessive numeric pad width for day-of-month', function () {
expect(t(now, '%5d')).toBe('00004')
expect(t(now, '%2000d').length).toBe(1024)
})
it('should format %q as date suffix', function () {
const first = new TestDate('2016-03-01 03:05:03')
const second = new TestDate('2016-03-02 03:05:03')
@@ -91,11 +87,6 @@ describe('util/strftime', function () {
expect(t(time, '%10N')).toBe('1290000000')
expect(t(time, '%0N')).toBe('129000000')
})
it('should cap excessive numeric pad width for %N', function () {
const time = new TestDate('2019-12-15 01:21:00.129')
expect(t(time, '%2000N').length).toBe(1024)
expect(t(time, '%50000N').length).toBe(1024)
})
it('should format %p as upper cased am/pm', function () {
expect(t(now, '%p')).toBe('PM')
expect(t(then, '%p')).toBe('AM')
+1 -5
View File
@@ -2,9 +2,6 @@ import { changeCase, padStart, padEnd } from './underscore'
import { LiquidDate } from './liquid-date'
import type { Limiter } from './limiter'
/** Upper bound for numeric strftime widths (%N, %15d, …) — avoids unbounded pad / CPU / memory. */
export const MAX_STRFTIME_PAD = 1024
const rFormat = /%([-_0^#:]+)?(\d+)?([EO])?(.)/
interface FormatOptions {
flags: Record<string, boolean>;
@@ -98,7 +95,7 @@ const formatCodes: Record<string, (d: LiquidDate, opts: FormatOptions) => unknow
m: (d: LiquidDate) => d.getMonth() + 1,
M: (d: LiquidDate) => d.getMinutes(),
N: (d: LiquidDate, opts: FormatOptions) => {
const width = Math.min(Number(opts.width) || 9, MAX_STRFTIME_PAD)
const width = Number(opts.width) || 9
const str = String(d.getMilliseconds()).slice(0, width)
opts.memoryLimit?.use(width - str.length)
return padEnd(str, width, '0')
@@ -151,7 +148,6 @@ function format (d: LiquidDate, match: RegExpExecArray, memoryLimit?: Pick<Limit
if (flags['_']) padChar = ' '
else if (flags['0']) padChar = '0'
if (flags['-']) padWidth = 0
else if (padWidth > MAX_STRFTIME_PAD) padWidth = MAX_STRFTIME_PAD
memoryLimit?.use(Math.max(0, padWidth - ret.length))
return padStart(ret, padWidth, padChar)