Compare commits

...

1 Commits
v4 ... v3.0.4

Author SHA1 Message Date
Michal Dorner
0e4a8c6eff Merge commit from fork
fix: escape multi-line filenames in list-files shell and csv output
2026-08-05 12:20:52 +02:00
5 changed files with 26 additions and 6 deletions

View File

@@ -20,4 +20,12 @@ describe('csvEscape() backslash escapes every character except subset of definit
test('Double quote should be escaped by another double quote', () => {
expect(csvEscape('file " with double quote')).toBe('"file "" with double quote"')
})
test('filename with LF should be quoted per RFC 4180', () => {
expect(csvEscape('a\nb')).toBe('"a\nb"')
})
test('filename with CRLF should be quoted per RFC 4180', () => {
expect(csvEscape('a\r\nb')).toBe('"a\r\nb"')
})
})

View File

@@ -54,4 +54,16 @@ describe('shellEscape() returns human readable filenames with as few escaping ap
test('filename with single quote and special characters is split and quoted/escaped as needed', () => {
expect(shellEscape("file'with $quote")).toBe("file\\''with $quote'")
})
test('filename with LF should be single-quoted', () => {
expect(shellEscape('x\ntouch pwned.md')).toBe("'x\ntouch pwned.md'")
})
test('filename with CRLF should be single-quoted', () => {
expect(shellEscape('x\r\ntouch pwned.md')).toBe("'x\r\ntouch pwned.md'")
})
test('filename with CR should be single-quoted', () => {
expect(shellEscape('a\rb')).toBe("'a\rb'")
})
})

6
dist/index.js vendored
View File

@@ -473,7 +473,7 @@ function csvEscape(value) {
if (value === '')
return value;
// Only safe characters
if (/^[a-zA-Z0-9._+:@%/-]+$/m.test(value)) {
if (/^[a-zA-Z0-9._+:@%/-]+$/.test(value)) {
return value;
}
// https://tools.ietf.org/html/rfc4180
@@ -505,12 +505,12 @@ function shellEscape(value) {
if (value === '')
return value;
// Only safe characters
if (/^[a-zA-Z0-9,._+:@%/-]+$/m.test(value)) {
if (/^[a-zA-Z0-9,._+:@%/-]+$/.test(value)) {
return value;
}
if (value.includes("'")) {
// Only safe characters, single quotes and white-spaces
if (/^[a-zA-Z0-9,._+:@%/'\s-]+$/m.test(value)) {
if (/^[a-zA-Z0-9,._+:@%/'\s-]+$/.test(value)) {
return `"${value}"`;
}
// Split by single quote and apply escaping recursively

View File

@@ -4,7 +4,7 @@ export function csvEscape(value: string): string {
if (value === '') return value
// Only safe characters
if (/^[a-zA-Z0-9._+:@%/-]+$/m.test(value)) {
if (/^[a-zA-Z0-9._+:@%/-]+$/.test(value)) {
return value
}

View File

@@ -9,13 +9,13 @@ export function shellEscape(value: string): string {
if (value === '') return value
// Only safe characters
if (/^[a-zA-Z0-9,._+:@%/-]+$/m.test(value)) {
if (/^[a-zA-Z0-9,._+:@%/-]+$/.test(value)) {
return value
}
if (value.includes("'")) {
// Only safe characters, single quotes and white-spaces
if (/^[a-zA-Z0-9,._+:@%/'\s-]+$/m.test(value)) {
if (/^[a-zA-Z0-9,._+:@%/'\s-]+$/.test(value)) {
return `"${value}"`
}