def main(): parser = argparse.ArgumentParser( description="Submit analysis to MythX API") create_parser(parser) args = parser.parse_args() config["endpoints"]["production"] = args.api_url handler = APIHandler(middlewares=[ ClientToolNameMiddleware(name="ApiTests"), AnalysisCacheMiddleware(no_cache=args.no_cache), ]) logging.info(f"Running MythX API tests without cache: {args.no_cache}") c = Client(eth_address=ETH_ADDRESS, password=PASSWORD, handler=handler) logging.info(f"Submit analysis to API: {args.api_url}") resp = c.analyze(**API_PAYLOAD) logging.info(resp.to_dict()) while not c.analysis_ready(resp.uuid): logging.info("Checking analysis status") time.sleep(1) issues = c.report(resp.uuid) detected_issues = issues.to_dict() logging.info(json.dumps(detected_issues, indent=2)) return detected_issues
def cli(ctx, **kwargs): """Your CLI for interacting with https://mythx.io/ \f :param ctx: Click context holding group-level parameters :param debug: Boolean to enable the `logging` debug mode :param api_key: User JWT access token from the MythX dashboard :param username: The MythX account ETH address/username :param password: The account password from the MythX dashboard :param fmt: The formatter to use for the subcommand output :param ci: Boolean to return exit code 1 on medium/high-sev issues :param output: Output file to write the results into """ ctx.obj = dict(kwargs) ctx.obj["retval"] = 0 toolname_mw = ClientToolNameMiddleware( name="mythx-cli-{}".format(__version__)) if kwargs["api_key"] is not None: ctx.obj["client"] = Client(access_token=kwargs["api_key"], middlewares=[toolname_mw]) elif kwargs["username"] and kwargs["password"]: ctx.obj["client"] = Client(eth_address=kwargs["username"], password=kwargs["password"], middlewares=[toolname_mw]) else: raise click.UsageError(( "The trial user has been deprecated. You can still use the MythX CLI for free " "by signing up for a free account at https://mythx.io/ and entering your access " "credentials.")) if kwargs["debug"]: for name in logging.root.manager.loggerDict: logging.getLogger(name).setLevel(logging.DEBUG)
def get_client() -> Client: eth_address = environ.get("PYTHX_USERNAME") or click.prompt( "Please enter your Ethereum address", type=click.STRING, default="0x0000000000000000000000000000000000000000", ) password = environ.get("PYTHX_PASSWORD") or click.prompt( "Please enter your MythX password", type=click.STRING, hide_input=True, default="trial", ) c = Client(eth_address=eth_address, password=password, staging=False) c.login() return c
def get_mythx_client() -> Client: """Generate a MythX client instance. This method will look for an API key passed as a parameter, and if none is found, look for a key in the environment variable :code:`MYTHX_API_KEY`. If a key is detected, a PythX client instance is returned, otherwise a :code:`ValidationError` is raised. :raises: ValidationError if no valid API key is provided :return: A PythX client instance """ if CONFIG.argv["api-key"]: auth_args = {"api_key": CONFIG.argv["api-key"]} elif environ.get("MYTHX_API_KEY"): auth_args = {"api_key": environ.get("MYTHX_API_KEY")} else: raise ValidationError( "You must provide a MythX API key via environment variable or the command line" ) return Client(**auth_args, middlewares=[ ClientToolNameMiddleware( name=f"brownie-{__version__}") ])
def cli(ctx, **kwargs): """Your CLI for interacting with https://mythx.io/ \f :param ctx: Click context holding group-level parameters :param debug: Boolean to enable the `logging` debug mode :param access_token: User JWT access token from the MythX dashboard :param eth_address: The MythX account ETH address/username :param password: The account password from the MythX dashboard :param staging: Boolean to redirect requests to MythX staging :param fmt: The formatter to use for the subcommand output """ ctx.obj = dict(kwargs) toolname_mw = ClientToolNameMiddleware( name="mythx-cli-{}".format(__version__)) if kwargs["access_token"] is not None: ctx.obj["client"] = Client( access_token=kwargs["access_token"], staging=kwargs["staging"], middlewares=[toolname_mw], ) elif kwargs["eth_address"] and kwargs["password"]: ctx.obj["client"] = Client( eth_address=kwargs["eth_address"], password=kwargs["password"], staging=kwargs["staging"], middlewares=[toolname_mw], ) else: # default to trial user client ctx.obj["client"] = Client( eth_address="0x0000000000000000000000000000000000000000", password="******", staging=kwargs["staging"], middlewares=[toolname_mw], ) if kwargs["debug"]: for name in logging.root.manager.loggerDict: logging.getLogger(name).setLevel(logging.DEBUG) return 0
def get_mythx_client(): # if both eth address and username are None, if ARGV["access-token"]: authenticated = True auth_args = {"access_token": ARGV["access-token"]} elif ARGV["eth-address"] and ARGV["password"]: authenticated = True auth_args = { "eth_address": ARGV["eth-address"], "password": ARGV["password"] } elif environ.get("MYTHX_ACCESS_TOKEN"): authenticated = True auth_args = {"access_token": environ.get("MYTHX_ACCESS_TOKEN")} elif environ.get("MYTHX_ETH_ADDRESS") and environ.get("MYTHX_PASSWORD"): authenticated = True auth_args = { "eth_address": environ.get("MYTHX_ETH_ADDRESS"), "password": environ.get("MYTHX_PASSWORD"), } else: authenticated = False auth_args = { "eth_address": "0x0000000000000000000000000000000000000000", "password": "******", } return ( Client( **auth_args, middlewares=[ ClientToolNameMiddleware(name="brownie-{}".format(__version__)) ], ), authenticated, )
def analyze(contracts: List[SolidityContract], analysis_mode: str = "quick") -> Report: """ Analyze contracts via the MythX API. :param contracts: List of solidity contracts to analyze :param analysis_mode: The mode to submit the analysis request with. "quick" or "full" (default: "quick") :return: Report with analyzed contracts """ assert analysis_mode in ("quick", "full"), "analysis_mode must be 'quick' or 'full'" c = Client( eth_address=os.environ.get("MYTHX_ETH_ADDRESS", TRIAL_ETH_ADDRESS), password=os.environ.get("MYTHX_PASSWORD", TRIAL_PASSWORD), ) if c.eth_address == TRIAL_ETH_ADDRESS: print( "You are currently running MythX in Trial mode. This mode reports only a partial analysis of your smart contracts, limited to three vulnerabilities. To get a more complete analysis, sign up for a free account at https://mythx.io." ) issues = [] # type: List[Issue] # TODO: Analyze multiple contracts asynchronously. for contract in contracts: source_codes = {} source_list = [] sources = {} # type: Dict[str, Any] main_source = None try: main_source = contract.input_file for solidity_file in contract.solidity_files: source_codes[solidity_file.filename] = solidity_file.data for filename in contract.solc_json["sources"].keys(): sources[filename] = {} if source_codes[filename]: sources[filename]["source"] = source_codes[filename] sources[filename]["ast"] = contract.solc_json["sources"][ filename]["ast"] source_list.append(filename) source_list.sort( key=lambda fname: contract.solc_json["sources"][fname]["id"]) except AttributeError: # No solidity file pass assert contract.creation_code, "Creation bytecode must exist." try: resp = c.analyze( contract_name=contract.name, analysis_mode=analysis_mode, bytecode=contract.creation_code or None, deployed_bytecode=contract.code or None, sources=sources or None, main_source=main_source, source_list=source_list or None, ) except MythXAPIError as e: log.critical(e) while not c.analysis_ready(resp.uuid): log.info(c.status(resp.uuid).analysis) time.sleep(5) for issue in c.report(resp.uuid): issue = Issue( contract=contract.name, function_name=None, address=issue.locations[0].source_map.components[0].offset if issue.locations else -1, swc_id=issue.swc_id[4:] or "None", # remove 'SWC-' prefix title=issue.swc_title, bytecode=contract.creation_code, severity=issue.severity.capitalize(), description_head=issue.description_short, description_tail=issue.description_long, ) issue.add_code_info(contract) issues.append(issue) report = Report(contracts=contracts) for issue in issues: report.append_issue(issue) return report
def cli( ctx, debug: bool, api_key: str, username: str, password: str, fmt: str, ci: bool, output: str, yes: bool, config: str, stdout: bool, ) -> None: """Your CLI for interacting with https://mythx.io/ \f :param ctx: Click context holding group-level parameters :param debug: Boolean to enable the `logging` debug mode :param api_key: User JWT api token from the MythX dashboard :param username: The MythX account ETH address/username :param password: The account password from the MythX dashboard :param fmt: The formatter to use for the subcommand output :param ci: Boolean to return exit code 1 on medium/high-sev issues :param output: Output file to write the results into :param config: YAML config file to read default parameters from :param stdout: Force printing to stdout and ignore output files """ # set loggers to debug mode if debug: for name in logging.root.manager.loggerDict: logging.getLogger(name).setLevel(logging.DEBUG) ctx.obj = { "debug": debug, "api_key": api_key, "username": username, "password": password, "fmt": fmt, "ci": ci, "output": output, "yes": yes, "config": config, } LOGGER.debug("Initializing configuration context") config_file = config or ".mythx.yml" if Path(config_file).is_file(): LOGGER.debug(f"Parsing config at {config_file}") with open(config_file) as config_f: parsed_config = yaml.safe_load(config_f.read()) else: parsed_config = {"analyze": {}} # The analyze context is updated separately in the command # implementation ctx.obj["analyze"] = parsed_config.get("analyze", {}) # overwrite context with top-level YAML config keys if necessary update_context(ctx.obj, "ci", parsed_config, "ci", False) if stdout: # if forced stdout, don't set output file ctx.obj["output"] = None else: update_context(ctx.obj, "output", parsed_config, "output", None) update_context(ctx.obj, "fmt", parsed_config, "format", "table") update_context(ctx.obj, "yes", parsed_config, "confirm", False) # set return value - used for CI failures ctx.obj["retval"] = 0 LOGGER.debug(f"Initializing tool name middleware with {__version__}") toolname_mw = ClientToolNameMiddleware( name="mythx-cli-{}".format(__version__)) if api_key is not None: LOGGER.debug("Initializing client with API key") ctx.obj["client"] = Client(api_key=api_key, middlewares=[toolname_mw]) elif username and password: LOGGER.debug("Initializing client with username and password") ctx.obj["client"] = Client(username=username, password=password, middlewares=[toolname_mw]) else: raise click.UsageError(( "The trial user has been deprecated. You can still use the MythX CLI for free " "by signing up for a free account at https://mythx.io/ and entering your access " "credentials."))
try: os.mkdir(OUTPUT_DIR) except: traceback.print_exc() # Script Set up try: environment = utils.grabEnvFile() binaries = os.listdir("./outputs/compiled_bin") except: raise Exception("Init Script Environment") # Init Mythx Client c = Client(api_key=environment.get("MYTHX_API_KEY")) log_string = "" for byte_file in binaries: print("Analyzing: %s" % byte_file) byte: str = "" try: byte = str( open(os.path.join(ROOT_BINARIES_DIR, byte_file), "r").read()) assert len(byte) > 0 except: print("Data Error in: %s ... Skipping" % byte_file) continue