Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ csv({

##### Parameters

**header** _String_ The current column header.<br/>
**header** _String | Buffer_ The current column header (a `Buffer` when the `raw` option is `true`).<br/>
**index** _Number_ The current column index.

#### mapValues
Expand Down Expand Up @@ -217,7 +217,7 @@ Specifies a single-character string to denote a quoted string.

Type: `Boolean`<br>

If `true`, instructs the parser not to decode UTF-8 strings.
If `true`, instructs the parser not to decode UTF-8 strings. This also affects headers: each header (and the `header` passed to `mapHeaders`) is a `Buffer` rather than a `String`. Row keys are still plain strings (JavaScript coerces object keys), but row values remain `Buffer`s.

#### separator

Expand Down
2 changes: 1 addition & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Bugs Bunny,22
* mapHeaders: ({ header, index }) => header.toLowerCase()
* });
*/
readonly mapHeaders?: (args: { header: string; index: number }) => string | null;
readonly mapHeaders?: (args: { header: string | Buffer; index: number }) => string | Buffer | null;

/**
* A function that can be used to modify the value of each column value.
Expand Down
10 changes: 7 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,16 @@ const defaults = {

const DANGEROUS_KEYS = new Set(['__proto__', 'constructor', 'prototype'])

function sanitizeHeader(header) {
if (typeof header !== 'string') {
function sanitizeHeader (header) {
let key = header

if (Buffer.isBuffer(header)) {
key = header.toString('utf-8')
} else if (typeof header !== 'string') {
return null
}

if (DANGEROUS_KEYS.has(header)) {
if (DANGEROUS_KEYS.has(key)) {
return null
}

Expand Down
14 changes: 12 additions & 2 deletions index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,23 @@ expectType<csvParser.CsvParser>(csvParser({ headers: false }));
expectType<csvParser.CsvParser>(
csvParser({
mapHeaders: ({ header, index }) => {
expectType<string>(header);
expectType<string | Buffer>(header);
expectType<number>(index);
return header.toLowerCase();
return typeof header === 'string' ? header.toLowerCase() : header;
},
})
);
expectType<csvParser.CsvParser>(csvParser({ mapHeaders: ({ header, index }) => null }));
expectType<csvParser.CsvParser>(
csvParser({
raw: true,
mapHeaders: ({ header, index }) => {
expectType<string | Buffer>(header);
expectType<number>(index);
return header;
},
})
);
expectType<csvParser.CsvParser>(
csvParser({
mapValues: ({ header, index, value }) => {
Expand Down
2 changes: 2 additions & 0 deletions test/fixtures/prototype-pollution.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
a,__proto__,constructor,prototype,b
1,2,3,4,5
3 changes: 3 additions & 0 deletions test/fixtures/raw-headers.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
a,b
1,2
3,4
41 changes: 41 additions & 0 deletions test/issues.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,44 @@ test.cb('strict + skipLines (#136)', (t) => {

collect('strict+skipLines', { strict: true, skipLines: 1 }, verify)
})

test.cb('raw headers and rows are preserved (#251)', (t) => {
const verify = (err, lines) => {
t.false(err, 'no err')
t.is(lines.length, 2, '2 rows')
t.true(Buffer.isBuffer(lines[0].a), 'header a is a Buffer')
t.true(Buffer.isBuffer(lines[0].b), 'header b is a Buffer')
t.is(lines[0].a.toString(), '1')
t.is(lines[0].b.toString(), '2')
t.is(lines[1].a.toString(), '3')
t.is(lines[1].b.toString(), '4')
t.end()
}

collect('raw-headers', { raw: true }, verify)
})
Comment on lines +27 to +41

test.cb('prototype pollution keys are stripped from headers (#250)', (t) => {
const verify = (err, lines) => {
t.false(err, 'no err')
t.deepEqual(lines[0], { a: '1', b: '5' }, 'dangerous keys stripped')
t.false(Object.prototype.hasOwnProperty.call(lines[0], '__proto__'), 'no __proto__ own-property')
t.false(Object.prototype.hasOwnProperty.call(lines[0], 'constructor'), 'no constructor own-property')
t.false(Object.prototype.hasOwnProperty.call(lines[0], 'prototype'), 'no prototype own-property')
t.end()
}

collect('prototype-pollution', verify)
})

test.cb('prototype pollution keys are stripped from raw Buffer headers (#250 + #251)', (t) => {
const verify = (err, lines) => {
t.false(err, 'no err')
t.is(Object.keys(lines[0]).length, 2, 'only safe headers survive')
t.true(Buffer.isBuffer(lines[0].a), 'header a is a Buffer')
t.true(Buffer.isBuffer(lines[0].b), 'header b is a Buffer')
t.end()
}

collect('prototype-pollution', { raw: true }, verify)
})
Comment on lines +56 to +66