Browse Source

Add more cases to escapeFormulae, allow to pass RegExp

pull/904/head
caub 3 years ago
parent
commit
c312bfc7fb
  1. 2
      docs/docs.html
  2. 8
      papaparse.js
  3. 20
      tests/test-cases.js

2
docs/docs.html

@ -343,7 +343,7 @@
<code>escapeFormulae</code> <code>escapeFormulae</code>
</td> </td>
<td> <td>
If <code>true</code>, field values that begin with <code>=</code>, <code>+</code>, <code>-</code>, or <code>@</code>, will be prepended with a <code>'</code> to defend against <a href="https://www.contextis.com/en/blog/comma-separated-vulnerabilities" target="_blank" rel="noopener">injection attacks</a>, because Excel and LibreOffice will automatically parse such cells as formulae. If <code>true</code>, field values that begin with <code>=</code>, <code>+</code>, <code>-</code>, <code>@</code>, <code>\t</code>, or <code>\r</code>, will be prepended with a <code>'</code> to defend against <a href="https://owasp.org/www-community/attacks/CSV_Injection" target="_blank" rel="noopener">injection attacks</a>, because Excel and LibreOffice will automatically parse such cells as formulae. You can override those values by setting this option to a regular expression
</td> </td>
</tr> </tr>
</table> </table>

8
papaparse.js

@ -367,10 +367,10 @@ License: MIT
_escapedQuote = _config.escapeChar + _quoteChar; _escapedQuote = _config.escapeChar + _quoteChar;
} }
if (typeof _config.escapeFormulae === 'boolean') if (typeof _config.escapeFormulae === 'boolean' || _config.escapeFormulae instanceof RegExp) {
_escapeFormulae = _config.escapeFormulae; _escapeFormulae = _config.escapeFormulae instanceof RegExp ? _config.escapeFormulae : /^[=+\-@\t\r].*$/;
}
} }
/** The double for loop that iterates the data and writes out a CSV string including header row */ /** The double for loop that iterates the data and writes out a CSV string including header row */
function serialize(fields, data, skipEmptyLines) function serialize(fields, data, skipEmptyLines)
@ -444,7 +444,7 @@ License: MIT
if (str.constructor === Date) if (str.constructor === Date)
return JSON.stringify(str).slice(1, 25); return JSON.stringify(str).slice(1, 25);
if (_escapeFormulae === true && typeof str === "string" && (str.match(/^[=+\-@].*$/) !== null)) { if (_escapeFormulae && typeof str === "string" && _escapeFormulae.test(str)) {
str = "'" + str; str = "'" + str;
} }

20
tests/test-cases.js

@ -1879,32 +1879,32 @@ var UNPARSE_TESTS = [
}, },
{ {
description: "Escape formulae", description: "Escape formulae",
input: [{ "Col1": "=danger", "Col2": "@danger", "Col3": "safe" }, { "Col1": "safe=safe", "Col2": "+danger", "Col3": "-danger, danger" }, { "Col1": "'+safe", "Col2": "'@safe", "Col3": "safe, safe" }], input: [{ "Col1": "=danger", "Col2": "@danger", "Col3": "safe" }, { "Col1": "safe=safe", "Col2": "+danger", "Col3": "-danger, danger" }, { "Col1": "'+safe", "Col2": "'@safe", "Col3": "safe, safe" }, { "Col1": "\tdanger", "Col2": "\rdanger,", "Col3": "safe\t\r" }],
config: { escapeFormulae: true }, config: { escapeFormulae: true },
expected: 'Col1,Col2,Col3\r\n\'=danger,\'@danger,safe\r\nsafe=safe,\'+danger,"\'-danger, danger"\r\n\'+safe,\'@safe,"safe, safe"' expected: 'Col1,Col2,Col3\r\n\'=danger,\'@danger,safe\r\nsafe=safe,\'+danger,"\'-danger, danger"\r\n\'+safe,\'@safe,"safe, safe"\r\n\'\tdanger,"\'\rdanger,","safe\t\r"'
}, },
{ {
description: "Don't escape formulae by default", description: "Don't escape formulae by default",
input: [{ "Col1": "=danger", "Col2": "@danger", "Col3": "safe" }, { "Col1": "safe=safe", "Col2": "+danger", "Col3": "-danger, danger" }, { "Col1": "'+safe", "Col2": "'@safe", "Col3": "safe, safe" }], input: [{ "Col1": "=danger", "Col2": "@danger", "Col3": "safe" }, { "Col1": "safe=safe", "Col2": "+danger", "Col3": "-danger, danger" }, { "Col1": "'+safe", "Col2": "'@safe", "Col3": "safe, safe" }, { "Col1": " danger", "Col2": "\rdanger,", "Col3": "safe\t\r" }],
expected: 'Col1,Col2,Col3\r\n=danger,@danger,safe\r\nsafe=safe,+danger,"-danger, danger"\r\n\'+safe,\'@safe,"safe, safe"' expected: 'Col1,Col2,Col3\r\n=danger,@danger,safe\r\nsafe=safe,+danger,"-danger, danger"\r\n\'+safe,\'@safe,"safe, safe"\r\n\tdanger,"\rdanger,","safe\t\r"'
}, },
{ {
description: "Escape formulae with forced quotes", description: "Escape formulae with forced quotes",
input: [{ "Col1": "=danger", "Col2": "@danger", "Col3": "safe" }, { "Col1": "safe=safe", "Col2": "+danger", "Col3": "-danger, danger" }, { "Col1": "'+safe", "Col2": "'@safe", "Col3": "safe, safe" }], input: [{ "Col1": "=danger", "Col2": "@danger", "Col3": "safe" }, { "Col1": "safe=safe", "Col2": "+danger", "Col3": "-danger, danger" }, { "Col1": "'+safe", "Col2": "'@safe", "Col3": "safe, safe" }, { "Col1": " danger", "Col2": "\rdanger,", "Col3": "safe\t\r" }],
config: { escapeFormulae: true, quotes: true }, config: { escapeFormulae: true, quotes: true },
expected: '"Col1","Col2","Col3"\r\n"\'=danger","\'@danger","safe"\r\n"safe=safe","\'+danger","\'-danger, danger"\r\n"\'+safe","\'@safe","safe, safe"' expected: '"Col1","Col2","Col3"\r\n"\'=danger","\'@danger","safe"\r\n"safe=safe","\'+danger","\'-danger, danger"\r\n"\'+safe","\'@safe","safe, safe"\r\n"\'\tdanger","\'\rdanger,","safe\t\r"'
}, },
{ {
description: "Escape formulae with single-quote quoteChar and escapeChar", description: "Escape formulae with single-quote quoteChar and escapeChar",
input: [{ "Col1": "=danger", "Col2": "@danger", "Col3": "safe" }, { "Col1": "safe=safe", "Col2": "+danger", "Col3": "-danger, danger" }, { "Col1": "'+safe", "Col2": "'@safe", "Col3": "safe, safe" }], input: [{ "Col1": "=danger", "Col2": "@danger", "Col3": "safe" }, { "Col1": "safe=safe", "Col2": "+danger", "Col3": "-danger, danger" }, { "Col1": "'+safe", "Col2": "'@safe", "Col3": "safe, safe" }, { "Col1": " danger", "Col2": "\rdanger,", "Col3": "safe, \t\r" }],
config: { escapeFormulae: true, quoteChar: "'", escapeChar: "'" }, config: { escapeFormulae: true, quoteChar: "'", escapeChar: "'" },
expected: 'Col1,Col2,Col3\r\n\'\'=danger,\'\'@danger,safe\r\nsafe=safe,\'\'+danger,\'\'\'-danger, danger\'\r\n\'\'+safe,\'\'@safe,\'safe, safe\'' expected: 'Col1,Col2,Col3\r\n\'\'=danger,\'\'@danger,safe\r\nsafe=safe,\'\'+danger,\'\'\'-danger, danger\'\r\n\'\'+safe,\'\'@safe,\'safe, safe\'\r\n\'\'\tdanger,\'\'\'\rdanger,\',\'safe, \t\r\''
}, },
{ {
description: "Escape formulae with single-quote quoteChar and escapeChar and forced quotes", description: "Escape formulae with single-quote quoteChar and escapeChar and forced quotes",
input: [{ "Col1": "=danger", "Col2": "@danger", "Col3": "safe" }, { "Col1": "safe=safe", "Col2": "+danger", "Col3": "-danger, danger" }, { "Col1": "'+safe", "Col2": "'@safe", "Col3": "safe, safe" }], input: [{ "Col1": "=danger", "Col2": "@danger", "Col3": "safe" }, { "Col1": "safe=safe", "Col2": "+danger", "Col3": "-danger, danger" }, { "Col1": "'+safe", "Col2": "'@safe", "Col3": "safe, safe" }, { "Col1": " danger", "Col2": "\rdanger,", "Col3": "safe, \t\r" }],
config: { escapeFormulae: true, quotes: true, quoteChar: "'", escapeChar: "'" }, config: { escapeFormulae: true, quotes: true, quoteChar: "'", escapeChar: "'" },
expected: '\'Col1\',\'Col2\',\'Col3\'\r\n\'\'\'=danger\',\'\'\'@danger\',\'safe\'\r\n\'safe=safe\',\'\'\'+danger\',\'\'\'-danger, danger\'\r\n\'\'\'+safe\',\'\'\'@safe\',\'safe, safe\'' expected: '\'Col1\',\'Col2\',\'Col3\'\r\n\'\'\'=danger\',\'\'\'@danger\',\'safe\'\r\n\'safe=safe\',\'\'\'+danger\',\'\'\'-danger, danger\'\r\n\'\'\'+safe\',\'\'\'@safe\',\'safe, safe\'\r\n\'\'\'\tdanger\',\'\'\'\rdanger,\',\'safe, \t\r\''
}, },
]; ];

Loading…
Cancel
Save