diff --git a/__tests__/csv-escape.test.ts b/__tests__/csv-escape.test.ts index f6dc6df..5a4ece1 100644 --- a/__tests__/csv-escape.test.ts +++ b/__tests__/csv-escape.test.ts @@ -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"') + }) }) diff --git a/__tests__/shell-escape.test.ts b/__tests__/shell-escape.test.ts index ece4c37..f7c6a7c 100644 --- a/__tests__/shell-escape.test.ts +++ b/__tests__/shell-escape.test.ts @@ -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'") + }) }) diff --git a/dist/index.js b/dist/index.js index 10c9fda..d2fea6c 100644 --- a/dist/index.js +++ b/dist/index.js @@ -501,7 +501,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 @@ -533,12 +533,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 diff --git a/src/list-format/csv-escape.ts b/src/list-format/csv-escape.ts index 262cf2d..04092cd 100644 --- a/src/list-format/csv-escape.ts +++ b/src/list-format/csv-escape.ts @@ -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 } diff --git a/src/list-format/shell-escape.ts b/src/list-format/shell-escape.ts index 1a3e3c9..9f1d96f 100644 --- a/src/list-format/shell-escape.ts +++ b/src/list-format/shell-escape.ts @@ -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}"` }