-
Notifications
You must be signed in to change notification settings - Fork 996
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor Slither entry point: a Slither object will now detect by itself
if the directory is a truffle or embark one. The advantage is to simplify: - external scripts and utils (ex: possible-paths/check-upgradability support embark natively) - __main__.pyn Changes: - Remove is_truffle/is_embark flag - Move truffle compile to Sliter._init_from_truffle - Refactor help, there are two new option groups: truffle and embark - Rename --ignore-truffle-compile to truffle-ignore-compile
- Loading branch information
Showing
4 changed files
with
96 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,6 @@ | |
import json | ||
import logging | ||
import os | ||
import platform | ||
import subprocess | ||
import sys | ||
import traceback | ||
|
@@ -49,6 +48,10 @@ def process(filename, args, detector_classes, printer_classes): | |
disable_solc_warnings=args.disable_solc_warnings, | ||
solc_arguments=args.solc_args, | ||
ast_format=ast, | ||
truffle_build_directory=args.truffle_build_directory, | ||
truffle_ignore_compile=args.truffle_ignore_compile, | ||
truffle_version=args.truffle_version, | ||
embark_overwrite_config=args.embark_overwrite_config, | ||
filter_paths=parse_filter_paths(args), | ||
triage_mode=args.triage_mode) | ||
|
||
|
@@ -76,62 +79,6 @@ def _process(slither, detector_classes, printer_classes): | |
|
||
return results, analyzed_contracts_count | ||
|
||
def process_truffle(dirname, args, detector_classes, printer_classes): | ||
# Truffle on windows has naming conflicts where it will invoke truffle.js directly instead | ||
# of truffle.cmd (unless in powershell or git bash). The cleanest solution is to explicitly call | ||
# truffle.cmd. Reference: | ||
# https://truffleframework.com/docs/truffle/reference/configuration#resolving-naming-conflicts-on-windows | ||
if not args.ignore_truffle_compile: | ||
truffle_base_command = "truffle" if platform.system() != 'Windows' else "truffle.cmd" | ||
cmd = [truffle_base_command, 'compile'] | ||
if args.truffle_version: | ||
cmd = ['npx',args.truffle_version,'compile'] | ||
elif os.path.isfile('package.json'): | ||
with open('package.json') as f: | ||
package = json.load(f) | ||
if 'devDependencies' in package: | ||
if 'truffle' in package['devDependencies']: | ||
version = package['devDependencies']['truffle'] | ||
if version.startswith('^'): | ||
version = version[1:] | ||
truffle_version = 'truffle@{}'.format(version) | ||
cmd = ['npx', truffle_version,'compile'] | ||
logger.info("'{}' running (use --truffle-version [email protected] to use specific version)".format(' '.join(cmd))) | ||
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
||
stdout, stderr = process.communicate() | ||
stdout, stderr = stdout.decode(), stderr.decode() # convert bytestrings to unicode strings | ||
|
||
logger.info(stdout) | ||
|
||
if stderr: | ||
logger.error(stderr) | ||
|
||
slither = Slither(dirname, | ||
solc=args.solc, | ||
disable_solc_warnings=args.disable_solc_warnings, | ||
solc_arguments=args.solc_args, | ||
is_truffle=True, | ||
truffle_build_directory=args.truffle_build_directory, | ||
filter_paths=parse_filter_paths(args), | ||
triage_mode=args.triage_mode) | ||
|
||
return _process(slither, detector_classes, printer_classes) | ||
|
||
def process_embark(dirname, args, detector_classes, printer_classes): | ||
|
||
slither = Slither(dirname, | ||
solc=args.solc, | ||
disable_solc_warnings=args.disable_solc_warnings, | ||
solc_arguments=args.solc_args, | ||
is_truffle=False, | ||
is_embark=True, | ||
embark_overwrite_config=args.embark_overwrite_config, | ||
filter_paths=parse_filter_paths(args), | ||
triage_mode=args.triage_mode) | ||
|
||
return _process(slither, detector_classes, printer_classes) | ||
|
||
|
||
def process_files(filenames, args, detector_classes, printer_classes): | ||
all_contracts = [] | ||
|
@@ -299,14 +246,14 @@ def parse_filter_paths(args): | |
'truffle_version': None, | ||
'disable_color': False, | ||
'filter_paths': None, | ||
'ignore_truffle_compile': False, | ||
'truffle_ignore_compile': False, | ||
'truffle_build_directory': 'build/contracts', | ||
'embark_overwrite_config': False, | ||
'legacy_ast': False | ||
} | ||
|
||
def parse_args(detector_classes, printer_classes): | ||
parser = argparse.ArgumentParser(description='Slither', | ||
parser = argparse.ArgumentParser(description='Slither. For usage information, see https://github.com/crytic/slither/wiki/Usage', | ||
usage="slither.py contract.sol [flag]") | ||
|
||
parser.add_argument('filename', | ||
|
@@ -320,6 +267,8 @@ def parse_args(detector_classes, printer_classes): | |
group_detector = parser.add_argument_group('Detectors') | ||
group_printer = parser.add_argument_group('Printers') | ||
group_solc = parser.add_argument_group('Solc options') | ||
group_truffle = parser.add_argument_group('Truffle options') | ||
group_embark = parser.add_argument_group('Embark options') | ||
group_misc = parser.add_argument_group('Additional option') | ||
|
||
group_detector.add_argument('--detect', | ||
|
@@ -396,14 +345,33 @@ def parse_args(detector_classes, printer_classes): | |
action='store_true', | ||
default=False) | ||
|
||
group_truffle.add_argument('--truffle-ignore-compile', | ||
help='Do not run truffle compile', | ||
action='store_true', | ||
dest='truffle_ignore_compile', | ||
default=defaults_flag_in_config['truffle_ignore_compile']) | ||
|
||
group_truffle.add_argument('--truffle-build-directory', | ||
help='Do not run truffle compile', | ||
action='store', | ||
dest='truffle_build_directory', | ||
default=defaults_flag_in_config['truffle_build_directory']) | ||
|
||
group_truffle.add_argument('--truffle-version', | ||
help='Use a local Truffle version (with npx)', | ||
action='store', | ||
default=defaults_flag_in_config['truffle_version']) | ||
|
||
group_embark.add_argument('--embark-overwrite-config', | ||
help='Install @trailofbits/embark-contract-export and add it to embark.json', | ||
action='store_true', | ||
default=defaults_flag_in_config['embark_overwrite_config']) | ||
|
||
group_misc.add_argument('--json', | ||
help='Export results as JSON', | ||
action='store', | ||
default=defaults_flag_in_config['json']) | ||
group_misc.add_argument('--truffle-version', | ||
help='Use a local Truffle version (with npx)', | ||
action='store', | ||
default=defaults_flag_in_config['truffle_version']) | ||
|
||
|
||
group_misc.add_argument('--disable-color', | ||
help='Disable output colorization', | ||
|
@@ -416,18 +384,6 @@ def parse_args(detector_classes, printer_classes): | |
dest='filter_paths', | ||
default=defaults_flag_in_config['filter_paths']) | ||
|
||
group_misc.add_argument('--ignore-truffle-compile', | ||
help='Do not run truffle compile', | ||
action='store_true', | ||
dest='ignore_truffle_compile', | ||
default=defaults_flag_in_config['ignore_truffle_compile']) | ||
|
||
group_misc.add_argument('--truffle-build-directory', | ||
help='Do not run truffle compile', | ||
action='store', | ||
dest='truffle_build_directory', | ||
default=defaults_flag_in_config['truffle_build_directory']) | ||
|
||
group_misc.add_argument('--triage-mode', | ||
help='Run triage mode (save results in slither.db.json)', | ||
action='store_true', | ||
|
@@ -457,11 +413,6 @@ def parse_args(detector_classes, printer_classes): | |
action='store_true', | ||
default=False) | ||
|
||
group_misc.add_argument('--embark-overwrite-config', | ||
help=argparse.SUPPRESS, | ||
action='store_true', | ||
default=defaults_flag_in_config['embark_overwrite_config']) | ||
|
||
parser.add_argument('--wiki-detectors', | ||
help=argparse.SUPPRESS, | ||
action=OutputWiki, | ||
|
@@ -588,15 +539,12 @@ def main_impl(all_detector_classes, all_printer_classes): | |
|
||
globbed_filenames = glob.glob(filename, recursive=True) | ||
|
||
if os.path.isfile(filename): | ||
if os.path.isfile(filename) or\ | ||
os.path.isfile(os.path.join(filename, 'truffle.js')) or\ | ||
os.path.isfile(os.path.join(filename, 'truffle-config.js')) or\ | ||
os.path.isfile(os.path.join(filename, 'embark.json')): | ||
(results, number_contracts) = process(filename, args, detector_classes, printer_classes) | ||
|
||
elif os.path.isfile(os.path.join(filename, 'truffle.js')) or os.path.isfile(os.path.join(filename, 'truffle-config.js')): | ||
(results, number_contracts) = process_truffle(filename, args, detector_classes, printer_classes) | ||
|
||
elif os.path.isfile(os.path.join(filename, 'embark.json')): | ||
(results, number_contracts) = process_embark(filename, args, detector_classes, printer_classes) | ||
|
||
elif os.path.isdir(filename) or len(globbed_filenames) > 0: | ||
extension = "*.sol" if not args.solc_ast else "*.json" | ||
filenames = glob.glob(os.path.join(filename, extension)) | ||
|
@@ -612,7 +560,6 @@ def main_impl(all_detector_classes, all_printer_classes): | |
number_contracts += number_contracts_tmp | ||
results += results_tmp | ||
|
||
|
||
else: | ||
raise Exception("Unrecognised file/dir path: '#{filename}'".format(filename=filename)) | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ | |
import sys | ||
import glob | ||
import json | ||
import platform | ||
|
||
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification | ||
from slither.printers.abstract_printer import AbstractPrinter | ||
|
@@ -28,28 +29,36 @@ def __init__(self, contract, **kwargs): | |
disable_solc_warnings (bool): True to disable solc warnings (default false) | ||
solc_argeuments (str): solc arguments (default '') | ||
ast_format (str): ast format (default '--ast-compact-json') | ||
is_truffle (bool): is a truffle directory (default false) | ||
truffle_build_directory (str): build truffle directory (default 'build/contracts') | ||
is_embark (bool): is an embark directory (default false) | ||
embark_overwrite_config (bool): overwrite original config file (default false) | ||
filter_paths (list(str)): list of path to filter (default []) | ||
triage_mode (bool): if true, switch to triage mode (default false) | ||
''' | ||
is_truffle = kwargs.get('is_truffle', False) | ||
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) | ||
is_embark = kwargs.get('is_embark', False) | ||
embark_overwrite_config = kwargs.get('embark_overwrite_config', False) | ||
embark_ignore (bool): ignore embark.js presence (default false) | ||
embark_overwrite_config (bool): overwrite original config file (default false) | ||
''' | ||
|
||
truffle_ignore = kwargs.get('truffle_ignore', False) | ||
embark_ignore = kwargs.get('embark_ignore', False) | ||
|
||
# truffle directory | ||
if is_truffle: | ||
self._init_from_truffle(contract, kwargs.get('truffle_build_directory', 'build/contracts')) | ||
# embark directory | ||
elif is_embark: | ||
self._init_from_embark(contract, embark_overwrite_config) | ||
# list of files provided (see --splitted option) | ||
elif isinstance(contract, list): | ||
if isinstance(contract, list): | ||
self._init_from_list(contract) | ||
# truffle directory | ||
elif not truffle_ignore and (os.path.isfile(os.path.join(contract, 'truffle.js')) or | ||
os.path.isfile(os.path.join(contract, 'truffle-config.js'))): | ||
self._init_from_truffle(contract, | ||
kwargs.get('truffle_build_directory', 'build/contracts'), | ||
kwargs.get('truffle_ignore_compile', False), | ||
kwargs.get('truffle_version', None)) | ||
# embark directory | ||
elif not embark_ignore and os.path.isfile(os.path.join(contract, 'embark.json')): | ||
self._init_from_embark(contract, | ||
kwargs.get('embark_overwrite_config', False)) | ||
# .json or .sol provided | ||
else: | ||
self._init_from_solc(contract, **kwargs) | ||
|
@@ -85,7 +94,7 @@ def _init_from_embark(self, contract, embark_overwrite_config): | |
with open('embark.json', 'w') as outfile: | ||
json.dump(embark_json, outfile, indent=2) | ||
else: | ||
if (not 'plugins' in embark_json) or (not 'embark-contract-info' in embark_json['plugins']): | ||
if (not 'plugins' in embark_json) or (not plugin_name in embark_json['plugins']): | ||
logger.error(red('embark-contract-info plugin was found in embark.json. Please install the plugin (see https://github.com/crytic/slither/wiki/Usage#embark), or use --embark-overwrite-config.')) | ||
sys.exit(-1) | ||
|
||
|
@@ -96,17 +105,46 @@ def _init_from_embark(self, contract, embark_overwrite_config): | |
# Embark might return information to stderr, but compile without issue | ||
logger.error("%s"%stderr.decode()) | ||
infile = os.path.join(contract, 'crytic-export', 'contracts.json') | ||
print(infile) | ||
if not os.path.isfile(infile): | ||
logger.error(red('Embark did not generate the AST file. Is Embark installed (npm install -g embark)? Is embark-contract-info installed? (npm install -g embark).')) | ||
sys.exit(-1) | ||
with open(infile, 'r') as f: | ||
contracts_loaded = json.load(f) | ||
contracts_loaded = contracts_loaded['asts'] | ||
for contract_loaded in contracts_loaded: | ||
self._parse_contracts_from_loaded_json(contract_loaded, contract_loaded['absolutePath']) | ||
self._parse_contracts_from_loaded_json(contract_loaded, | ||
contract_loaded['absolutePath']) | ||
|
||
def _init_from_truffle(self, contract, build_directory, truffle_ignore_compile, truffle_version): | ||
# Truffle on windows has naming conflicts where it will invoke truffle.js directly instead | ||
# of truffle.cmd (unless in powershell or git bash). The cleanest solution is to explicitly call | ||
# truffle.cmd. Reference: | ||
# https://truffleframework.com/docs/truffle/reference/configuration#resolving-naming-conflicts-on-windows | ||
if not truffle_ignore_compile: | ||
truffle_base_command = "truffle" if platform.system() != 'Windows' else "truffle.cmd" | ||
cmd = [truffle_base_command, 'compile'] | ||
if truffle_version: | ||
cmd = ['npx', truffle_version, 'compile'] | ||
elif os.path.isfile('package.json'): | ||
with open('package.json') as f: | ||
package = json.load(f) | ||
if 'devDependencies' in package: | ||
if 'truffle' in package['devDependencies']: | ||
version = package['devDependencies']['truffle'] | ||
if version.startswith('^'): | ||
version = version[1:] | ||
truffle_version = 'truffle@{}'.format(version) | ||
cmd = ['npx', truffle_version, 'compile'] | ||
logger.info("'{}' running (use --truffle-version [email protected] to use specific version)".format(' '.join(cmd))) | ||
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
||
stdout, stderr = process.communicate() | ||
stdout, stderr = stdout.decode(), stderr.decode()# convert bytestrings to unicode strings | ||
|
||
logger.info(stdout) | ||
|
||
def _init_from_truffle(self, contract, build_directory): | ||
if stderr: | ||
logger.error(stderr) | ||
if not os.path.isdir(os.path.join(contract, build_directory)): | ||
logger.info(red('No truffle build directory found, did you run `truffle compile`?')) | ||
sys.exit(-1) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters