/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.lang.apex.rule.security; import java.util.List; import net.sourceforge.pmd.lang.apex.ast.ASTLiteralExpression; import net.sourceforge.pmd.lang.apex.ast.ASTMethodCallExpression; import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; import net.sourceforge.pmd.lang.apex.ast.ASTVariableExpression; import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; /** * Finds all .addError method calls that are not HTML escaped on purpose * * @author sergey.gorbaty * */ public class ApexXSSFromEscapeFalseRule extends AbstractApexRule { private static final String ADD_ERROR = "addError"; public ApexXSSFromEscapeFalseRule() { setProperty(CODECLIMATE_CATEGORIES, new String[] { "Security" }); setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 100); setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); } @Override public Object visit(ASTUserClass node, Object data) { if (Helper.isTestMethodOrClass(node) || Helper.isSystemLevelClass(node)) { return data; // stops all the rules } List<ASTMethodCallExpression> methodCalls = node.findDescendantsOfType(ASTMethodCallExpression.class); for (ASTMethodCallExpression methodCall : methodCalls) { if (Helper.isMethodName(methodCall, ADD_ERROR)) { validateBooleanParameter(methodCall, data); } } return data; } private void validateBooleanParameter(ASTMethodCallExpression methodCall, Object data) { int numberOfChildren = methodCall.jjtGetNumChildren(); if (numberOfChildren == 3) { // addError('',false) Object potentialLiteral = methodCall.jjtGetChild(2); if (potentialLiteral instanceof ASTLiteralExpression) { ASTLiteralExpression parameter = (ASTLiteralExpression) potentialLiteral; Object o = parameter.getNode().getLiteral(); if (o instanceof Boolean) { Boolean paramValue = (Boolean) o; if (paramValue.equals(Boolean.FALSE)) { validateLiteralPresence(methodCall, data); } } } } } private void validateLiteralPresence(ASTMethodCallExpression methodCall, Object data) { List<ASTVariableExpression> variables = methodCall.findDescendantsOfType(ASTVariableExpression.class); for (ASTVariableExpression v : variables) { addViolation(data, v); } } }