Beispiel #1
0
 def _init_from_list(self, contract):
     self._parser = SlitherSolc("", self)
     for c in contract:
         if "absolutePath" in c:
             path = c["absolutePath"]
         else:
             path = c["attributes"]["absolutePath"]
         self._parser.parse_top_level_from_loaded_json(c, path)
Beispiel #2
0
    def _init_from_raw_json(self, filename):
        if not os.path.isfile(filename):
            raise SlitherError(
                "{} does not exist (are you in the correct directory?)".format(filename)
            )
        assert filename.endswith("json")
        with open(filename, encoding="utf8") as astFile:
            stdout = astFile.read()
            if not stdout:
                to_log = f"Empty AST file: {filename}"
                raise SlitherError(to_log)
        contracts_json = stdout.split("\n=")

        self._parser = SlitherSolc(filename, self)

        for c in contracts_json:
            self._parser.parse_top_level_from_json(c)
Beispiel #3
0
    def __init__(self, target, **kwargs):
        """
        Args:
            target (str | list(json) | CryticCompile)
        Keyword Args:
            solc (str): solc binary location (default 'solc')
            disable_solc_warnings (bool): True to disable solc warnings (default false)
            solc_arguments (str): solc arguments (default '')
            ast_format (str): ast format (default '--ast-compact-json')
            filter_paths (list(str)): list of path to filter (default [])
            triage_mode (bool): if true, switch to triage mode (default false)
            exclude_dependencies (bool): if true, exclude results that are only related to dependencies
            generate_patches (bool): if true, patches are generated (json output only)

            truffle_ignore (bool): ignore truffle.js presence (default false)
            truffle_build_directory (str): build truffle directory (default 'build/contracts')
            truffle_ignore_compile (bool): do not run truffle compile (default False)
            truffle_version (str): use a specific truffle version (default None)

            embark_ignore (bool): ignore embark.js presence (default false)
            embark_ignore_compile (bool): do not run embark build (default False)
            embark_overwrite_config (bool): overwrite original config file (default false)

        """
        super().__init__()
        self._parser: SlitherSolc  #  This could be another parser, like SlitherVyper, interface needs to be determined

        self._disallow_partial: bool = kwargs.get("disallow_partial", False)
        self._skip_assembly: bool = kwargs.get("skip_assembly", False)
        self._show_ignored_findings: bool = kwargs.get("show_ignored_findings", False)

        # list of files provided (see --splitted option)
        if isinstance(target, list):
            self._init_from_list(target)
        elif isinstance(target, str) and target.endswith(".json"):
            self._init_from_raw_json(target)
        else:
            self._parser = SlitherSolc("", self)
            try:
                if isinstance(target, CryticCompile):
                    crytic_compile = target
                else:
                    crytic_compile = CryticCompile(target, **kwargs)
                self._crytic_compile = crytic_compile
            except InvalidCompilation as e:
                # pylint: disable=raise-missing-from
                raise SlitherError(f"Invalid compilation: \n{str(e)}")
            for path, ast in crytic_compile.asts.items():
                self._parser.parse_top_level_from_loaded_json(ast, path)
                self.add_source_code(path)

        if kwargs.get("generate_patches", False):
            self.generate_patches = True

        self._markdown_root = kwargs.get("markdown_root", "")

        self._detectors = []
        self._printers = []

        filter_paths = kwargs.get("filter_paths", [])
        for p in filter_paths:
            self.add_path_to_filter(p)

        self._exclude_dependencies = kwargs.get("exclude_dependencies", False)

        triage_mode = kwargs.get("triage_mode", False)
        self._triage_mode = triage_mode

        self._parser.parse_contracts()

        # skip_analyze is only used for testing
        if not kwargs.get("skip_analyze", False):
            self._parser.analyze_contracts()
Beispiel #4
0
class Slither(SlitherCore):  # pylint: disable=too-many-instance-attributes
    def __init__(self, target, **kwargs):
        """
        Args:
            target (str | list(json) | CryticCompile)
        Keyword Args:
            solc (str): solc binary location (default 'solc')
            disable_solc_warnings (bool): True to disable solc warnings (default false)
            solc_arguments (str): solc arguments (default '')
            ast_format (str): ast format (default '--ast-compact-json')
            filter_paths (list(str)): list of path to filter (default [])
            triage_mode (bool): if true, switch to triage mode (default false)
            exclude_dependencies (bool): if true, exclude results that are only related to dependencies
            generate_patches (bool): if true, patches are generated (json output only)

            truffle_ignore (bool): ignore truffle.js presence (default false)
            truffle_build_directory (str): build truffle directory (default 'build/contracts')
            truffle_ignore_compile (bool): do not run truffle compile (default False)
            truffle_version (str): use a specific truffle version (default None)

            embark_ignore (bool): ignore embark.js presence (default false)
            embark_ignore_compile (bool): do not run embark build (default False)
            embark_overwrite_config (bool): overwrite original config file (default false)

        """
        super().__init__()
        self._parser: SlitherSolc  #  This could be another parser, like SlitherVyper, interface needs to be determined

        self._disallow_partial: bool = kwargs.get("disallow_partial", False)
        self._skip_assembly: bool = kwargs.get("skip_assembly", False)
        self._show_ignored_findings: bool = kwargs.get("show_ignored_findings", False)

        # list of files provided (see --splitted option)
        if isinstance(target, list):
            self._init_from_list(target)
        elif isinstance(target, str) and target.endswith(".json"):
            self._init_from_raw_json(target)
        else:
            self._parser = SlitherSolc("", self)
            try:
                if isinstance(target, CryticCompile):
                    crytic_compile = target
                else:
                    crytic_compile = CryticCompile(target, **kwargs)
                self._crytic_compile = crytic_compile
            except InvalidCompilation as e:
                # pylint: disable=raise-missing-from
                raise SlitherError(f"Invalid compilation: \n{str(e)}")
            for path, ast in crytic_compile.asts.items():
                self._parser.parse_top_level_from_loaded_json(ast, path)
                self.add_source_code(path)

        if kwargs.get("generate_patches", False):
            self.generate_patches = True

        self._markdown_root = kwargs.get("markdown_root", "")

        self._detectors = []
        self._printers = []

        filter_paths = kwargs.get("filter_paths", [])
        for p in filter_paths:
            self.add_path_to_filter(p)

        self._exclude_dependencies = kwargs.get("exclude_dependencies", False)

        triage_mode = kwargs.get("triage_mode", False)
        self._triage_mode = triage_mode

        self._parser.parse_contracts()

        # skip_analyze is only used for testing
        if not kwargs.get("skip_analyze", False):
            self._parser.analyze_contracts()

    def _init_from_raw_json(self, filename):
        if not os.path.isfile(filename):
            raise SlitherError(
                "{} does not exist (are you in the correct directory?)".format(filename)
            )
        assert filename.endswith("json")
        with open(filename, encoding="utf8") as astFile:
            stdout = astFile.read()
            if not stdout:
                to_log = f"Empty AST file: {filename}"
                raise SlitherError(to_log)
        contracts_json = stdout.split("\n=")

        self._parser = SlitherSolc(filename, self)

        for c in contracts_json:
            self._parser.parse_top_level_from_json(c)

    def _init_from_list(self, contract):
        self._parser = SlitherSolc("", self)
        for c in contract:
            if "absolutePath" in c:
                path = c["absolutePath"]
            else:
                path = c["attributes"]["absolutePath"]
            self._parser.parse_top_level_from_loaded_json(c, path)

    @property
    def detectors(self):
        return self._detectors

    @property
    def detectors_high(self):
        return [d for d in self.detectors if d.IMPACT == DetectorClassification.HIGH]

    @property
    def detectors_medium(self):
        return [d for d in self.detectors if d.IMPACT == DetectorClassification.MEDIUM]

    @property
    def detectors_low(self):
        return [d for d in self.detectors if d.IMPACT == DetectorClassification.LOW]

    @property
    def detectors_informational(self):
        return [d for d in self.detectors if d.IMPACT == DetectorClassification.INFORMATIONAL]

    @property
    def detectors_optimization(self):
        return [d for d in self.detectors if d.IMPACT == DetectorClassification.OPTIMIZATION]

    def register_detector(self, detector_class):
        """
        :param detector_class: Class inheriting from `AbstractDetector`.
        """
        _check_common_things("detector", detector_class, AbstractDetector, self._detectors)

        instance = detector_class(self, logger_detector)
        self._detectors.append(instance)

    def register_printer(self, printer_class):
        """
        :param printer_class: Class inheriting from `AbstractPrinter`.
        """
        _check_common_things("printer", printer_class, AbstractPrinter, self._printers)

        instance = printer_class(self, logger_printer)
        self._printers.append(instance)

    def run_detectors(self):
        """
        :return: List of registered detectors results.
        """

        self.load_previous_results()
        results = [d.detect() for d in self._detectors]
        self.write_results_to_hide()
        return results

    def run_printers(self):
        """
        :return: List of registered printers outputs.
        """

        return [p.output(self._crytic_compile.target).data for p in self._printers]

    @property
    def triage_mode(self):
        return self._triage_mode