def swallows_exceptions(java_dest: str, exclude: list = None) -> bool: """ Search for ``catch`` blocks that are empty or only have comments. See `REQ.161 <https://fluidattacks.com/web/rules/161/>`_. See `CWE-391 <https://cwe.mitre.org/data/definitions/391.html>`_. :param java_dest: Path to a Java source file or package. :param exclude: Paths that contains any string from this list are ignored. """ # Empty() grammar matches 'anything' # ~Empty() grammar matches 'not anything' or 'nothing' grammar = Suppress(Keyword('catch')) + nestedExpr(opener='(', closer=')') \ + nestedExpr(opener='{', closer='}', content=~Empty()) grammar.ignore(javaStyleComment) try: matches = lang.path_contains_grammar(grammar, java_dest, LANGUAGE_SPECS, exclude) except FileNotFoundError: show_unknown('File does not exist', details=dict(code_dest=java_dest)) else: if matches: show_open('Code has empty "catch" blocks', details=dict(matched=matches)) return True show_close('Code does not have empty "catch" blocks', details=dict(code_dest=java_dest)) return False
def has_switch_without_default(js_dest: str, exclude: list = None) -> bool: r""" Check if all ``switch``\ es have a ``default`` clause. See `REQ.161 <https://fluidattacks.com/web/rules/161/>`_. See `CWE-478 <https://cwe.mitre.org/data/definitions/478.html>`_. :param js_dest: Path to a JavaScript source file or package. :param exclude: Paths that contains any string from this list are ignored. """ switch = Keyword('switch') + nestedExpr(opener='(', closer=')') switch_block = Suppress(switch) + nestedExpr(opener='{', closer='}') switch_block.ignore(cppStyleComment) switch_block.ignore(L_CHAR) switch_block.ignore(L_STRING) switch_block.addCondition(lambda x: not RE_HAVES_DEFAULT.search(str(x))) try: matches = lang.path_contains_grammar(switch_block, js_dest, LANGUAGE_SPECS, exclude) except FileNotFoundError: show_unknown('File does not exist', details=dict(code_dest=js_dest)) return False if matches: show_open('Code does not have "switch" with "default" clause', details=dict(matched=matches)) return True show_close('Code has "switch" with "default" clause', details=dict(code_dest=js_dest)) return False
def _declares_catch_for_exceptions( java_dest: str, exceptions_list: list, open_msg: str, closed_msg: str, exclude: list = None) -> bool: """Search for the declaration of catch for the given exceptions.""" any_exception = L_VAR_CHAIN_NAME provided_exception = MatchFirst( [Keyword(exception) for exception in exceptions_list]) exception_group = delimitedList(expr=any_exception, delim='|') exception_group.addCondition( # Ensure that at least one exception in the group is the provided one lambda tokens: any(provided_exception.matches(tok) for tok in tokens)) grammar = Suppress(Keyword('catch')) + nestedExpr( opener='(', closer=')', content=( exception_group + Suppress(Optional(L_VAR_NAME)))) grammar.ignore(javaStyleComment) grammar.ignore(L_STRING) grammar.ignore(L_CHAR) try: matches = lang.path_contains_grammar(grammar, java_dest, LANGUAGE_SPECS, exclude) except FileNotFoundError: show_unknown('File does not exist', details=dict(code_dest=java_dest)) else: if matches: show_open(open_msg, details=dict(matched=matches)) return True show_close(closed_msg, details=dict(code_dest=java_dest)) return False
def uses_insecure_cipher(java_dest: str, algorithm: str, exclude: list = None) -> bool: """ Check if code uses an insecure cipher algorithm. See `REQ.148 <https://fluidattacks.com/web/rules/148/>`_. See `REQ.149 <https://fluidattacks.com/web/rules/149/>`_. :param java_dest: Path to a Java source file or package. :param algorithm: Insecure algorithm. :param exclude: Paths that contains any string from this list are ignored. """ method = 'Cipher.getInstance("{}")'.format(algorithm.upper()) op_mode = '/' + oneOf('CBC ECB', caseless=True) padding = '/' + oneOf('NoPadding PKCS5Padding', caseless=True) algorithm = '"' + CaselessKeyword(algorithm) + Optional( op_mode + Optional(padding)) + '"' grammar = Suppress(Keyword('Cipher') + '.' + Keyword('getInstance')) + \ nestedExpr() grammar.ignore(javaStyleComment) grammar.addCondition( # Ensure that at least one token is the provided algorithm lambda tokens: tokens.asList() and any( algorithm.matches(tok) for tok in tokens[0])) try: matches = lang.path_contains_grammar(grammar, java_dest, LANGUAGE_SPECS, exclude) except FileNotFoundError: show_unknown('File does not exist', details=dict(location=java_dest)) return False if not matches: show_close('Code does not use {} method'.format(method), details=dict(location=java_dest)) return False show_open('Code uses {} method'.format(method), details=dict(matches=matches)) return True
def has_if_without_else(java_dest: str, exclude: list = None) -> bool: r""" Check if all ``if``\ s have an ``else`` clause. See `REQ.161 <https://fluidattacks.com/web/rules/161/>`_. :param java_dest: Path to a Java source file or package. :param exclude: Paths that contains any string from this list are ignored. """ args = nestedExpr(opener='(', closer=')') if_ = Keyword('if') + args if_line = Optional('}') + if_ + Optional('{') try: conds = lang.check_grammar(if_line, java_dest, LANGUAGE_SPECS, exclude) except FileNotFoundError: show_unknown('File does not exist', details=dict(code_dest=java_dest)) return False else: if not conds: show_close('Code does not use "if" statements', details=dict(code_dest=java_dest)) return False block = nestedExpr(opener='{', closer='}') if_block = if_ + block else_if_block = Keyword('else') + Keyword('if') + args + block else_block = Keyword('else') + block cond_block = \ Suppress(if_block + ZeroOrMore(else_if_block)) + Optional(else_block) cond_block.ignore(javaStyleComment) cond_block.ignore(L_CHAR) cond_block.ignore(L_STRING) vulns = {} for code_file, val in conds.items(): vulns.update(lang.block_contains_empty_grammar(cond_block, code_file, val['lines'], _get_block)) if not vulns: show_close('Code has "if" with "else" clause', details=dict(file=java_dest, fingerprint=get_sha256(java_dest))) else: show_open('Code has "if" without "else" clause', details=dict(matched=vulns, total_vulns=len(vulns))) return True return False
def has_switch_without_default(csharp_dest: str, exclude: list = None) -> bool: r""" Check if all ``switch``\ es have a ``default`` clause. See `REQ.161 <https://fluidattacks.com/web/rules/161/>`_. See `CWE-478 <https://cwe.mitre.org/data/definitions/478.html>`_. :param csharp_dest: Path to a C# source file or package. :param exclude: Paths that contains any string from this list are ignored. """ switch = Keyword('switch') + nestedExpr(opener='(', closer=')') switch_line = Optional('}') + switch + Optional('{') result = False try: switches = lang.check_grammar(switch_line, csharp_dest, LANGUAGE_SPECS, exclude) except FileNotFoundError: show_unknown('File does not exist', details=dict(code_dest=csharp_dest)) return False else: if not switches: show_close('Code does not have switches', details=dict(code_dest=csharp_dest)) return False switch_block = Suppress(switch) + nestedExpr(opener='{', closer='}') switch_block.ignore(javaStyleComment) switch_block.ignore(L_CHAR) switch_block.ignore(L_STRING) vulns = {} for code_file, val in switches.items(): vulns.update( lang.block_contains_grammar(switch_block, code_file, val['lines'], _get_block, should_not_have=r'(?:default\s*:)')) if not vulns: show_close('Code has "switch" with "default" clause', details=dict(file=csharp_dest, fingerprint=get_sha256(csharp_dest))) else: show_open('Code does not have "switch" with "default" clause', details=dict(matched=vulns, total_vulns=len(vulns))) result = True return result
def __init__(self): name = Word(alphas, alphanums + '_' + '-') variable = Suppress('?') + name require_def = Suppress('(') + ':requirements' + \ OneOrMore(one_of(':strips :typing :negative-preconditions :disjunctive-preconditions :equality :existential-preconditions :universal-preconditions :quantified-preconditions :conditional-effects :fluents :numeric-fluents :adl :durative-actions :duration-inequalities :timed-initial-literals :action-costs')) \ + Suppress(')') types_def = Suppress('(') + ':types' + \ OneOrMore(Group(Group(OneOrMore(name)) + \ Optional(Suppress('-') + name))).setResultsName('types') \ + Suppress(')') constants_def = Suppress('(') + ':constants' + \ OneOrMore(Group(Group(OneOrMore(name)) + \ Optional(Suppress('-') + name))).setResultsName('constants') \ + Suppress(')') predicate = Suppress('(') + \ Group(name + Group(ZeroOrMore(Group(Group(OneOrMore(variable)) + \ Optional(Suppress('-') + name))))) \ + Suppress(')') predicates_def = Suppress('(') + ':predicates' + \ Group(OneOrMore(predicate)).setResultsName('predicates') \ + Suppress(')') functions_def = Suppress('(') + ':functions' + \ Group(OneOrMore(predicate)).setResultsName('functions') \ + Suppress(')') parameters = ZeroOrMore(Group(Group(OneOrMore(variable)) \ + Optional(Suppress('-') + name))).setResultsName('params') action_def = Group(Suppress('(') + ':action' + name.setResultsName('name') \ + ':parameters' + Suppress('(') + parameters + Suppress(')') \ + Optional(':precondition' + nestedExpr().setResultsName('pre')) \ + Optional(':effect' + nestedExpr().setResultsName('eff')) \ + Suppress(')')) dur_action_def = Group(Suppress('(') + ':durative-action' + name.setResultsName('name') \ + ':parameters' + Suppress('(') + parameters + Suppress(')') \ + ':duration' + nestedExpr().setResultsName('duration') \ + ':condition' + nestedExpr().setResultsName('cond') \ + ':effect' + nestedExpr().setResultsName('eff') \ + Suppress(')')) domain = Suppress('(') + 'define' \ + Suppress('(') + 'domain' + name.setResultsName('name') + Suppress(')') \ + Optional(require_def) + Optional(types_def) + Optional(constants_def) \ + Optional(predicates_def) + Optional(functions_def) \ + Group(ZeroOrMore(action_def | dur_action_def)).setResultsName('actions') + Suppress(')') objects = OneOrMore(Group(Group(OneOrMore(name)) \ + Optional(Suppress('-') + name))).setResultsName('objects') metric = (Keyword('minimize') | Keyword('maximize')).setResultsName('optimization') \ + (name | nestedExpr()).setResultsName('metric') problem = Suppress('(') + 'define' \ + Suppress('(') + 'problem' + name.setResultsName('name') + Suppress(')') \ + Suppress('(') + ':domain' + name + Suppress(')') + Optional(require_def) \ + Optional(Suppress('(') + ':objects' + objects + Suppress(')')) \ + Suppress('(') + ':init' + ZeroOrMore(nestedExpr()).setResultsName('init') + Suppress(')') \ + Suppress('(') + ':goal' + nestedExpr().setResultsName('goal') + Suppress(')') \ + Optional(Suppress('(') + ':metric' + metric + Suppress(')')) \ + Suppress(')') domain.ignore(';' + restOfLine) problem.ignore(';' + restOfLine) self._domain = domain self._problem = problem self._parameters = parameters