diff --git a/src/main/java/com/cflint/plugins/core/QueryParamChecker.java b/src/main/java/com/cflint/plugins/core/QueryParamChecker.java index 75f956f8..9fcf92d8 100644 --- a/src/main/java/com/cflint/plugins/core/QueryParamChecker.java +++ b/src/main/java/com/cflint/plugins/core/QueryParamChecker.java @@ -4,6 +4,8 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.io.StringReader; +import java.io.BufferedReader; import com.cflint.BugList; import com.cflint.CF; @@ -36,18 +38,33 @@ public void element(final Element element, final Context context, final BugList if ( element.getName().equalsIgnoreCase(CF.CFQUERY) && !CF.QUERY.equalsIgnoreCase(element.getAttributeValue(CF.DBTYPE))) { String content = element.getContent().toString(); + final String allowVariableExpression = context.getConfiguration().getParameter(this,"allowVariableExpression"); + Pattern allowVariableExpressionPattern = null; + if ( !"".equals(allowVariableExpression) ) { + allowVariableExpressionPattern = Pattern.compile(allowVariableExpression,Pattern.DOTALL); + } + final String allowLineExpression = context.getConfiguration().getParameter(this,"allowLineExpression"); //Todo : cfparser/Jericho does not support parsing out the cfqueryparam very well. // the following code will not work when there is a > sign in the expression content = content.replaceAll("<[cC][fF][qQ][uU][eE][rR][yY][pP][aA][rR][aA][mM][^>]*>", ""); if (content.indexOf('#') >= 0) { - final List ignoreLines = determineIgnoreLines(element); + final List ignoreLines = determineIgnoreLines(content, context.startLine()); final Matcher matcher = Pattern.compile("#(?:##)?([^#]+)(?:##)?#($|[^#])",Pattern.DOTALL).matcher(content); while (matcher.find()) { if (matcher.groupCount() >= 1) { int currentline = context.startLine() + countNewLinesUpTo(content, matcher.start()); + String linecontent = content.split("\\R")[currentline-context.startLine()]; int currentOffset = element.getStartTag().getEnd() + 1 + matcher.start(); - final String variableName = matcher.group(1); - if (!ignoreLines.contains(currentline)) { + String variableName = matcher.group(1); + Pattern allowLineExpressionPattern = null; + if ( !"".equals(allowLineExpression) ) { + //System.out.println(allowLineExpression.replaceAll("\\$\\{variable\\}","\\\\Q" + Matcher.quoteReplacement(variableName) + "\\\\E")); + allowLineExpressionPattern = Pattern.compile(allowLineExpression.replaceAll("\\$\\{variable\\}","\\\\Q" + Matcher.quoteReplacement(variableName) + "\\\\E"),Pattern.DOTALL); + } + if ( !ignoreLines.contains(currentline) + && (allowVariableExpressionPattern == null || !allowVariableExpressionPattern.matcher(variableName).find()) + && (allowLineExpressionPattern == null || !allowLineExpressionPattern.matcher(linecontent).find())) { + //System.out.println("linecontent:" + linecontent); context.addMessage("CFQUERYPARAM_REQ", variableName, currentline, currentOffset); } } @@ -63,18 +80,59 @@ public void element(final Element element, final Context context, final BugList * @param element the element object * @return the line numbers of any @@CFLintIgnore annotations. */ - private List determineIgnoreLines(final Element element) { + private List determineIgnoreLines(final String textContent, final int start ) { + final List ignoreLines = new ArrayList<>(); - for (Element comment : element.getChildElements()) { - if ("!---".equals(comment.getName()) && comment.toString().contains("@CFLintIgnore") && comment.toString().contains("CFQUERYPARAM_REQ")) { - int ignoreLine = comment.getSource().getRow(comment.getEnd()); - ignoreLines.add(ignoreLine); - ignoreLines.add(ignoreLine + 1); - ignoreLines.add(comment.getSource().getRow(comment.getBegin())); - } else { - ignoreLines.addAll(determineIgnoreLines(comment)); + int currentline = start; + String line = null; + List tmpIgnoreLines = new ArrayList<>(); + int match = 0; + + BufferedReader bufReader = new BufferedReader(new StringReader(textContent)); + + try { + while( (line=bufReader.readLine()) != null ) + { + if ( line.contains("!---") ) { + if (!tmpIgnoreLines.contains(currentline)) { + tmpIgnoreLines.add(currentline); + } + match = 1; + } + + if ( line.contains("@CFLintIgnore") && match > 0 ) { + if (!tmpIgnoreLines.contains(currentline)) { + tmpIgnoreLines.add(currentline); + } + match = 2; + } + + if ( line.contains("CFQUERYPARAM_REQ") && match > 1 ) { + if (!tmpIgnoreLines.contains(currentline)) { + tmpIgnoreLines.add(currentline); + } + match = 3; + } + + if ( line.contains("--->") && match > 2 ) { + if (!tmpIgnoreLines.contains(currentline)) { + tmpIgnoreLines.add(currentline); + } + if (!tmpIgnoreLines.contains(currentline+1)) { + tmpIgnoreLines.add(currentline+1); + } + ignoreLines.addAll(tmpIgnoreLines); + tmpIgnoreLines.clear(); + match = 0; + } + + currentline++; + } + } catch(Exception e) { + e.printStackTrace(); } + return ignoreLines; } diff --git a/src/main/resources/cflint.definition.json b/src/main/resources/cflint.definition.json index 26978612..87c25076 100644 --- a/src/main/resources/cflint.definition.json +++ b/src/main/resources/cflint.definition.json @@ -85,7 +85,16 @@ "severity": "WARNING" } ], - "parameter": [] + "parameter": [ + { + "name": "allowVariableExpression", + "value": "" + }, + { + "name": "allowLineExpression", + "value": "" + } + ] }, { "name": "TypedQueryNew", diff --git a/src/test/java/com/cflint/TestCFBugs_QueryParams.java b/src/test/java/com/cflint/TestCFBugs_QueryParams.java index db1d6424..75736204 100644 --- a/src/test/java/com/cflint/TestCFBugs_QueryParams.java +++ b/src/test/java/com/cflint/TestCFBugs_QueryParams.java @@ -138,6 +138,9 @@ public void testCFScript_QueryParams_ignore_offset() throws CFLintScanException " ON C.aID = A.aID\n" + " AND C.bar = #magicVal# \n" + + " \n" + + " #delim# C.bar = \n" + " WHERE \n" + "