Reimplement helpers.isBlankLine to fix an instance of "Polynomial regular expression used on uncontrolled data".

This commit is contained in:
David Anson 2022-02-11 21:54:43 -08:00
parent b9474e84a3
commit 1c89dd5776
3 changed files with 76 additions and 27 deletions

View file

@ -78,20 +78,44 @@ module.exports.isEmptyString = function isEmptyString(str) {
module.exports.isObject = function isObject(obj) { module.exports.isObject = function isObject(obj) {
return (obj !== null) && (typeof obj === "object") && !Array.isArray(obj); return (obj !== null) && (typeof obj === "object") && !Array.isArray(obj);
}; };
// Returns true iff the input line is blank (no content) /**
// Example: Contains nothing, whitespace, or comment (unclosed start/end okay) * Returns true iff the input line is blank (contains nothing, whitespace, or
module.exports.isBlankLine = function isBlankLine(line) { * comments (unclosed start/end comments allowed)).
// Call to String.replace follows best practices and is not a security check *
// False-positive for js/incomplete-multi-character-sanitization * @param {string} line Input line.
* @returns {boolean} True iff line is blank.
*/
function isBlankLine(line) {
var startComment = "<!--";
var endComment = "-->";
var removeComments = function (s) {
// eslint-disable-next-line no-constant-condition
while (true) {
var start = s.indexOf(startComment);
var end = s.indexOf(endComment);
if ((end !== -1) && ((start === -1) || (end < start))) {
// Unmatched end comment is first
s = s.slice(end + endComment.length);
}
else if ((start !== -1) && (end !== -1)) {
// Start comment is before end comment
s = s.slice(0, start) + s.slice(end + endComment.length);
}
else if ((start !== -1) && (end === -1)) {
// Unmatched start comment is last
s = s.slice(0, start);
}
else {
// No more comments to remove
return s;
}
}
};
return (!line || return (!line ||
!line.trim() || !line.trim() ||
!line !removeComments(line).replace(/>/g, "").trim());
.replace(/<!--.*?-->/g, "") }
.replace(/<!--.*$/g, "") module.exports.isBlankLine = isBlankLine;
.replace(/^.*-->/g, "")
.replace(/>/g, "")
.trim());
};
/** /**
* Compare function for Array.prototype.sort for ascending order of numbers. * Compare function for Array.prototype.sort for ascending order of numbers.
* *

View file

@ -65,22 +65,43 @@ module.exports.isObject = function isObject(obj) {
return (obj !== null) && (typeof obj === "object") && !Array.isArray(obj); return (obj !== null) && (typeof obj === "object") && !Array.isArray(obj);
}; };
// Returns true iff the input line is blank (no content) /**
// Example: Contains nothing, whitespace, or comment (unclosed start/end okay) * Returns true iff the input line is blank (contains nothing, whitespace, or
module.exports.isBlankLine = function isBlankLine(line) { * comments (unclosed start/end comments allowed)).
// Call to String.replace follows best practices and is not a security check *
// False-positive for js/incomplete-multi-character-sanitization * @param {string} line Input line.
* @returns {boolean} True iff line is blank.
*/
function isBlankLine(line) {
const startComment = "<!--";
const endComment = "-->";
const removeComments = (s) => {
// eslint-disable-next-line no-constant-condition
while (true) {
const start = s.indexOf(startComment);
const end = s.indexOf(endComment);
if ((end !== -1) && ((start === -1) || (end < start))) {
// Unmatched end comment is first
s = s.slice(end + endComment.length);
} else if ((start !== -1) && (end !== -1)) {
// Start comment is before end comment
s = s.slice(0, start) + s.slice(end + endComment.length);
} else if ((start !== -1) && (end === -1)) {
// Unmatched start comment is last
s = s.slice(0, start);
} else {
// No more comments to remove
return s;
}
}
};
return ( return (
!line || !line ||
!line.trim() || !line.trim() ||
!line !removeComments(line).replace(/>/g, "").trim()
.replace(/<!--.*?-->/g, "")
.replace(/<!--.*$/g, "")
.replace(/^.*-->/g, "")
.replace(/>/g, "")
.trim()
); );
}; }
module.exports.isBlankLine = isBlankLine;
/** /**
* Compare function for Array.prototype.sort for ascending order of numbers. * Compare function for Array.prototype.sort for ascending order of numbers.

View file

@ -226,7 +226,7 @@ bar`
}); });
test("isBlankLine", (t) => { test("isBlankLine", (t) => {
t.plan(29); t.plan(33);
const blankLines = [ const blankLines = [
null, null,
"", "",
@ -248,7 +248,9 @@ test("isBlankLine", (t) => {
"<!--", "<!--",
" <!-- text", " <!-- text",
"text --> ", "text --> ",
"-->" "-->",
"text --> <!--text--> <!--text--> <!-- text",
"text --> --> <!--text--> <!--text--> <!-- <!-- text"
]; ];
blankLines.forEach((line) => t.true(helpers.isBlankLine(line), line || "")); blankLines.forEach((line) => t.true(helpers.isBlankLine(line), line || ""));
const nonBlankLines = [ const nonBlankLines = [
@ -259,7 +261,9 @@ test("isBlankLine", (t) => {
"<!--text--> text", "<!--text--> text",
"text <!--text-->", "text <!--text-->",
"text <!--", "text <!--",
"--> text" "--> text",
"text --> <!--text--> text <!--text--> <!-- text",
"text --> --> <!--text--> text <!--text--> <!-- <!-- text"
]; ];
nonBlankLines.forEach((line) => t.true(!helpers.isBlankLine(line), line)); nonBlankLines.forEach((line) => t.true(!helpers.isBlankLine(line), line));
}); });