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) {
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)
module.exports.isBlankLine = function isBlankLine(line) {
// Call to String.replace follows best practices and is not a security check
// False-positive for js/incomplete-multi-character-sanitization
/**
* Returns true iff the input line is blank (contains nothing, whitespace, or
* comments (unclosed start/end comments allowed)).
*
* @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 ||
!line.trim() ||
!line
.replace(/<!--.*?-->/g, "")
.replace(/<!--.*$/g, "")
.replace(/^.*-->/g, "")
.replace(/>/g, "")
.trim());
};
!removeComments(line).replace(/>/g, "").trim());
}
module.exports.isBlankLine = isBlankLine;
/**
* 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);
};
// Returns true iff the input line is blank (no content)
// Example: Contains nothing, whitespace, or comment (unclosed start/end okay)
module.exports.isBlankLine = function isBlankLine(line) {
// Call to String.replace follows best practices and is not a security check
// False-positive for js/incomplete-multi-character-sanitization
/**
* Returns true iff the input line is blank (contains nothing, whitespace, or
* comments (unclosed start/end comments allowed)).
*
* @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 (
!line ||
!line.trim() ||
!line
.replace(/<!--.*?-->/g, "")
.replace(/<!--.*$/g, "")
.replace(/^.*-->/g, "")
.replace(/>/g, "")
.trim()
!removeComments(line).replace(/>/g, "").trim()
);
};
}
module.exports.isBlankLine = isBlankLine;
/**
* Compare function for Array.prototype.sort for ascending order of numbers.

View file

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