@woocommerce/csv-export
Advanced tools
Comparing version
@@ -8,3 +8,3 @@ /** | ||
function escapeCSVValue(value) { | ||
var stringValue = value.toString(); // Prevent CSV injection. | ||
let stringValue = value.toString(); // Prevent CSV injection. | ||
// See: http://www.contextis.com/resources/blog/comma-separated-vulnerabilities/ | ||
@@ -14,3 +14,3 @@ // See: WC_CSV_Exporter::escape_data() | ||
if (['=', '+', '-', '@'].includes(stringValue.charAt(0))) { | ||
stringValue = "'" + stringValue; | ||
stringValue = '"\t' + stringValue + '"'; | ||
} else if (stringValue.match(/[,"\s]/)) { | ||
@@ -24,17 +24,13 @@ stringValue = '"' + stringValue.replace(/"/g, '""') + '"'; | ||
function getCSVHeaders(headers) { | ||
return Array.isArray(headers) ? headers.map(function (header) { | ||
return escapeCSVValue(header.label); | ||
}).join(',') : []; | ||
return Array.isArray(headers) ? headers.map(header => escapeCSVValue(header.label)).join(',') : []; | ||
} | ||
function getCSVRows(rows) { | ||
return Array.isArray(rows) ? rows.map(function (row) { | ||
return row.map(function (rowItem) { | ||
if (undefined === rowItem.value || rowItem.value === null) { | ||
return ''; | ||
} | ||
return Array.isArray(rows) ? rows.map(row => row.map(rowItem => { | ||
if (undefined === rowItem.value || rowItem.value === null) { | ||
return ''; | ||
} | ||
return escapeCSVValue(rowItem.value); | ||
}).join(','); | ||
}).join('\n') : []; | ||
return escapeCSVValue(rowItem.value); | ||
}).join(',')).join('\n') : []; | ||
} | ||
@@ -51,5 +47,3 @@ /** | ||
export function generateCSVDataFromTable(headers, rows) { | ||
return [getCSVHeaders(headers), getCSVRows(rows)].filter(function (text) { | ||
return text.length; | ||
}).join('\n'); | ||
return [getCSVHeaders(headers), getCSVRows(rows)].filter(text => text.length).join('\n'); | ||
} | ||
@@ -65,10 +59,4 @@ /** | ||
export function generateCSVFileName() { | ||
var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; | ||
var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
var fileNameSections = [name.toLowerCase().replace(/[^a-z0-9]/g, '-'), moment().format('YYYY-MM-DD'), Object.keys(params).map(function (key) { | ||
return key.toLowerCase().replace(/[^a-z0-9]/g, '-') + '-' + decodeURIComponent(params[key]).toLowerCase().replace(/[^a-z0-9]/g, '-'); | ||
}).join('_')].filter(function (text) { | ||
return text.length; | ||
}); | ||
export function generateCSVFileName(name = '', params = {}) { | ||
const fileNameSections = [name.toLowerCase().replace(/[^a-z0-9]/g, '-'), moment().format('YYYY-MM-DD'), Object.keys(params).map(key => key.toLowerCase().replace(/[^a-z0-9]/g, '-') + '-' + decodeURIComponent(params[key]).toLowerCase().replace(/[^a-z0-9]/g, '-')).join('_')].filter(text => text.length); | ||
return fileNameSections.join('_') + '.csv'; | ||
@@ -85,3 +73,3 @@ } | ||
// eslint-disable-next-line no-undef | ||
var blob = new Blob([content], { | ||
const blob = new Blob([content], { | ||
type: 'text/csv;charset=utf-8' | ||
@@ -88,0 +76,0 @@ }); |
@@ -8,3 +8,3 @@ /** | ||
function escapeCSVValue(value) { | ||
var stringValue = value.toString(); // Prevent CSV injection. | ||
let stringValue = value.toString(); // Prevent CSV injection. | ||
// See: http://www.contextis.com/resources/blog/comma-separated-vulnerabilities/ | ||
@@ -14,3 +14,3 @@ // See: WC_CSV_Exporter::escape_data() | ||
if (['=', '+', '-', '@'].includes(stringValue.charAt(0))) { | ||
stringValue = "'" + stringValue; | ||
stringValue = '"\t' + stringValue + '"'; | ||
} else if (stringValue.match(/[,"\s]/)) { | ||
@@ -24,17 +24,13 @@ stringValue = '"' + stringValue.replace(/"/g, '""') + '"'; | ||
function getCSVHeaders(headers) { | ||
return Array.isArray(headers) ? headers.map(function (header) { | ||
return escapeCSVValue(header.label); | ||
}).join(',') : []; | ||
return Array.isArray(headers) ? headers.map(header => escapeCSVValue(header.label)).join(',') : []; | ||
} | ||
function getCSVRows(rows) { | ||
return Array.isArray(rows) ? rows.map(function (row) { | ||
return row.map(function (rowItem) { | ||
if (undefined === rowItem.value || rowItem.value === null) { | ||
return ''; | ||
} | ||
return Array.isArray(rows) ? rows.map(row => row.map(rowItem => { | ||
if (undefined === rowItem.value || rowItem.value === null) { | ||
return ''; | ||
} | ||
return escapeCSVValue(rowItem.value); | ||
}).join(','); | ||
}).join('\n') : []; | ||
return escapeCSVValue(rowItem.value); | ||
}).join(',')).join('\n') : []; | ||
} | ||
@@ -51,5 +47,3 @@ /** | ||
export function generateCSVDataFromTable(headers, rows) { | ||
return [getCSVHeaders(headers), getCSVRows(rows)].filter(function (text) { | ||
return text.length; | ||
}).join('\n'); | ||
return [getCSVHeaders(headers), getCSVRows(rows)].filter(text => text.length).join('\n'); | ||
} | ||
@@ -65,10 +59,4 @@ /** | ||
export function generateCSVFileName() { | ||
var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; | ||
var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
var fileNameSections = [name.toLowerCase().replace(/[^a-z0-9]/g, '-'), moment().format('YYYY-MM-DD'), Object.keys(params).map(function (key) { | ||
return key.toLowerCase().replace(/[^a-z0-9]/g, '-') + '-' + decodeURIComponent(params[key]).toLowerCase().replace(/[^a-z0-9]/g, '-'); | ||
}).join('_')].filter(function (text) { | ||
return text.length; | ||
}); | ||
export function generateCSVFileName(name = '', params = {}) { | ||
const fileNameSections = [name.toLowerCase().replace(/[^a-z0-9]/g, '-'), moment().format('YYYY-MM-DD'), Object.keys(params).map(key => key.toLowerCase().replace(/[^a-z0-9]/g, '-') + '-' + decodeURIComponent(params[key]).toLowerCase().replace(/[^a-z0-9]/g, '-')).join('_')].filter(text => text.length); | ||
return fileNameSections.join('_') + '.csv'; | ||
@@ -85,3 +73,3 @@ } | ||
// eslint-disable-next-line no-undef | ||
var blob = new Blob([content], { | ||
const blob = new Blob([content], { | ||
type: 'text/csv;charset=utf-8' | ||
@@ -88,0 +76,0 @@ }); |
@@ -0,1 +1,5 @@ | ||
# 1.3.2 | ||
- Use tab char for the CSV injection prevention. | ||
# 1.3.1 | ||
@@ -2,0 +6,0 @@ |
{ | ||
"name": "@woocommerce/csv-export", | ||
"version": "1.3.1", | ||
"version": "1.3.2", | ||
"description": "WooCommerce utility library to convert data to CSV files.", | ||
@@ -30,3 +30,3 @@ "author": "Automattic", | ||
}, | ||
"gitHead": "d7b72dde1c74b4a83e036856a78306616a520182" | ||
"gitHead": "2a2a046171c31009f7db02cae68b5c23ae9f6a3e" | ||
} |
export default `Date,Orders,Description,"Total Sales",Refunds,Coupons,Taxes,Shipping,"Net Sales","Negative Number" | ||
2018-04-29T00:00:00,30,"Lorem, ""ipsum""",200,19,19,100,19,200,'-123`; | ||
2018-04-29T00:00:00,30,"Lorem, ""ipsum""",200,19,19,100,19,200,"\t-123"`; |
@@ -14,3 +14,3 @@ /** | ||
if ( [ '=', '+', '-', '@' ].includes( stringValue.charAt( 0 ) ) ) { | ||
stringValue = "'" + stringValue; | ||
stringValue = '"\t' + stringValue + '"'; | ||
} else if ( stringValue.match( /[,"\s]/ ) ) { | ||
@@ -17,0 +17,0 @@ stringValue = '"' + stringValue.replace( /"/g, '""' ) + '"'; |
@@ -34,2 +34,25 @@ /* eslint-disable jest/no-mocks-import */ | ||
} ); | ||
it( 'should prefix tab character when the cell value starts with one of =, +, -, and @', () => { | ||
[ '=', '+', '-', '@' ].forEach( ( val ) => { | ||
const expected = 'value\n"\t' + val + 'test"'; | ||
const result = generateCSVDataFromTable( | ||
[ | ||
{ | ||
label: 'value', | ||
key: 'value', | ||
}, | ||
], | ||
[ | ||
[ | ||
{ | ||
display: 'value', | ||
value: val + 'test', | ||
}, | ||
], | ||
] | ||
); | ||
expect( result ).toBe( expected ); | ||
} ); | ||
} ); | ||
} ); | ||
@@ -36,0 +59,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
90219
41.05%29
123.08%671
68.17%1
Infinity%