slither.utils.command_line
1import argparse 2import enum 3import json 4import os 5import re 6import logging 7from collections import defaultdict 8from typing import Dict, List, Type, Union 9 10from crytic_compile.cryticparser.defaults import ( 11 DEFAULTS_FLAG_IN_CONFIG as DEFAULTS_FLAG_IN_CONFIG_CRYTIC_COMPILE, 12) 13 14from slither.detectors.abstract_detector import classification_txt, AbstractDetector 15from slither.printers.abstract_printer import AbstractPrinter 16from slither.utils.colors import yellow, red 17from slither.utils.myprettytable import MyPrettyTable 18 19logger = logging.getLogger("Slither") 20 21DEFAULT_JSON_OUTPUT_TYPES = ["detectors", "printers"] 22JSON_OUTPUT_TYPES = [ 23 "compilations", 24 "console", 25 "detectors", 26 "printers", 27 "list-detectors", 28 "list-printers", 29] 30 31 32class FailOnLevel(enum.Enum): 33 PEDANTIC = "pedantic" 34 LOW = "low" 35 MEDIUM = "medium" 36 HIGH = "high" 37 NONE = "none" 38 39 40# Those are the flags shared by the command line and the config file 41defaults_flag_in_config = { 42 "codex": False, 43 "codex_contracts": "all", 44 "codex_model": "text-davinci-003", 45 "codex_temperature": 0, 46 "codex_max_tokens": 300, 47 "codex_log": False, 48 "detectors_to_run": "all", 49 "printers_to_run": None, 50 "detectors_to_exclude": None, 51 "exclude_dependencies": False, 52 "exclude_informational": False, 53 "exclude_optimization": False, 54 "exclude_low": False, 55 "exclude_medium": False, 56 "exclude_high": False, 57 "fail_on": FailOnLevel.PEDANTIC, 58 "json": None, 59 "sarif": None, 60 "json-types": ",".join(DEFAULT_JSON_OUTPUT_TYPES), 61 "disable_color": False, 62 "filter_paths": None, 63 "include_paths": None, 64 "generate_patches": False, 65 # debug command 66 "skip_assembly": False, 67 "legacy_ast": False, 68 "zip": None, 69 "zip_type": "lzma", 70 "show_ignored_findings": False, 71 "no_fail": False, 72 "sarif_input": "export.sarif", 73 "sarif_triage": "export.sarif.sarifexplorer", 74 "triage_database": "slither.db.json", 75 **DEFAULTS_FLAG_IN_CONFIG_CRYTIC_COMPILE, 76} 77 78deprecated_flags = { 79 "fail_pedantic": True, 80 "fail_low": False, 81 "fail_medium": False, 82 "fail_high": False, 83} 84 85 86def read_config_file(args: argparse.Namespace) -> None: 87 # No config file was provided as an argument 88 if args.config_file is None: 89 # Check wether the default config file is present 90 if os.path.exists("slither.config.json"): 91 # The default file exists, use it 92 args.config_file = "slither.config.json" 93 else: 94 return 95 96 if os.path.isfile(args.config_file): 97 try: 98 with open(args.config_file, encoding="utf8") as f: 99 config = json.load(f) 100 for key, elem in config.items(): 101 if key in deprecated_flags: 102 logger.info( 103 yellow(f"{args.config_file} has a deprecated key: {key} : {elem}") 104 ) 105 migrate_config_options(args, key, elem) 106 continue 107 if key not in defaults_flag_in_config: 108 logger.info( 109 yellow(f"{args.config_file} has an unknown key: {key} : {elem}") 110 ) 111 continue 112 if getattr(args, key) == defaults_flag_in_config[key]: 113 setattr(args, key, elem) 114 except json.decoder.JSONDecodeError as e: 115 logger.error(red(f"Impossible to read {args.config_file}, please check the file {e}")) 116 else: 117 logger.error(red(f"File {args.config_file} is not a file or does not exist")) 118 logger.error(yellow("Falling back to the default settings...")) 119 120 121def migrate_config_options(args: argparse.Namespace, key: str, elem): 122 if key.startswith("fail_") and getattr(args, "fail_on") == defaults_flag_in_config["fail_on"]: 123 if key == "fail_pedantic": 124 pedantic_setting = elem 125 fail_on = FailOnLevel.PEDANTIC if pedantic_setting else FailOnLevel.NONE 126 setattr(args, "fail_on", fail_on) 127 logger.info(f"Migrating fail_pedantic: {pedantic_setting} as fail_on: {fail_on.value}") 128 elif key == "fail_low" and elem is True: 129 logger.info("Migrating fail_low: true -> fail_on: low") 130 setattr(args, "fail_on", FailOnLevel.LOW) 131 132 elif key == "fail_medium" and elem is True: 133 logger.info("Migrating fail_medium: true -> fail_on: medium") 134 setattr(args, "fail_on", FailOnLevel.MEDIUM) 135 136 elif key == "fail_high" and elem is True: 137 logger.info("Migrating fail_high: true -> fail_on: high") 138 setattr(args, "fail_on", FailOnLevel.HIGH) 139 else: 140 logger.warning(yellow(f"Key {key} was deprecated but no migration was provided")) 141 142 143def output_to_markdown( 144 detector_classes: List[Type[AbstractDetector]], 145 printer_classes: List[Type[AbstractPrinter]], 146 filter_wiki: str, 147) -> None: 148 def extract_help(cls: Union[Type[AbstractDetector], Type[AbstractPrinter]]) -> str: 149 if cls.WIKI == "": 150 return cls.HELP 151 return f"[{cls.HELP}]({cls.WIKI})" 152 153 detectors_list = [] 154 print(filter_wiki) 155 for detector in detector_classes: 156 argument = detector.ARGUMENT 157 # dont show the backdoor example 158 if argument == "backdoor": 159 continue 160 if not filter_wiki in detector.WIKI: 161 continue 162 help_info = extract_help(detector) 163 impact = detector.IMPACT 164 confidence = classification_txt[detector.CONFIDENCE] 165 detectors_list.append((argument, help_info, impact, confidence)) 166 167 # Sort by impact, confidence, and name 168 detectors_list = sorted( 169 detectors_list, key=lambda element: (element[2], element[3], element[0]) 170 ) 171 idx = 1 172 for (argument, help_info, impact, confidence) in detectors_list: 173 print(f"{idx} | `{argument}` | {help_info} | {classification_txt[impact]} | {confidence}") 174 idx = idx + 1 175 176 print() 177 printers_list = [] 178 for printer in printer_classes: 179 argument = printer.ARGUMENT 180 help_info = extract_help(printer) 181 printers_list.append((argument, help_info)) 182 183 # Sort by impact, confidence, and name 184 printers_list = sorted(printers_list, key=lambda element: (element[0])) 185 idx = 1 186 for (argument, help_info) in printers_list: 187 print(f"{idx} | `{argument}` | {help_info}") 188 idx = idx + 1 189 190 191def get_level(l: str) -> int: 192 tab = l.count("\t") + 1 193 if l.replace("\t", "").startswith(" -"): 194 tab = tab + 1 195 if l.replace("\t", "").startswith("-"): 196 tab = tab + 1 197 return tab 198 199 200def convert_result_to_markdown(txt: str) -> str: 201 # -1 to remove the last \n 202 lines = txt[0:-1].split("\n") 203 ret = [] 204 level = 0 205 for l in lines: 206 next_level = get_level(l) 207 prefix = "<li>" 208 if next_level < level: 209 prefix = "</ul>" * (level - next_level) + prefix 210 if next_level > level: 211 prefix = "<ul>" * (next_level - level) + prefix 212 level = next_level 213 ret.append(prefix + l) 214 215 return "".join(ret) 216 217 218def output_results_to_markdown( 219 all_results: List[Dict], checklistlimit: str, show_ignored_findings: bool 220) -> None: 221 checks = defaultdict(list) 222 info: Dict = defaultdict(dict) 223 for results_ in all_results: 224 checks[results_["check"]].append(results_) 225 info[results_["check"]] = { 226 "impact": results_["impact"], 227 "confidence": results_["confidence"], 228 } 229 230 if not show_ignored_findings: 231 print( 232 "**THIS CHECKLIST IS NOT COMPLETE**. Use `--show-ignored-findings` to show all the results." 233 ) 234 235 print("Summary") 236 for check_ in checks: 237 print( 238 f" - [{check_}](#{check_}) ({len(checks[check_])} results) ({info[check_]['impact']})" 239 ) 240 241 counter = 0 242 for (check, results) in checks.items(): 243 print(f"## {check}") 244 print(f'Impact: {info[check]["impact"]}') 245 print(f'Confidence: {info[check]["confidence"]}') 246 additional = False 247 if checklistlimit and len(results) > 5: 248 results = results[0:5] 249 additional = True 250 for result in results: 251 print(" - [ ] ID-" + f"{counter}") 252 counter = counter + 1 253 print(result["markdown"]) 254 if result["first_markdown_element"]: 255 print(result["first_markdown_element"]) 256 print("\n") 257 if additional: 258 print(f"**More results were found, check [{checklistlimit}]({checklistlimit})**") 259 260 261def output_wiki(detector_classes: List[Type[AbstractDetector]], filter_wiki: str) -> None: 262 263 # Sort by impact, confidence, and name 264 detectors_list = sorted( 265 detector_classes, 266 key=lambda element: (element.IMPACT, element.CONFIDENCE, element.ARGUMENT), 267 ) 268 269 for detector in detectors_list: 270 argument = detector.ARGUMENT 271 # dont show the backdoor example 272 if argument == "backdoor": 273 continue 274 if not filter_wiki in detector.WIKI: 275 continue 276 check = detector.ARGUMENT 277 impact = classification_txt[detector.IMPACT] 278 confidence = classification_txt[detector.CONFIDENCE] 279 title = detector.WIKI_TITLE 280 description = detector.WIKI_DESCRIPTION 281 exploit_scenario = detector.WIKI_EXPLOIT_SCENARIO 282 recommendation = detector.WIKI_RECOMMENDATION 283 284 print(f"\n## {title}") 285 print("### Configuration") 286 print(f"* Check: `{check}`") 287 print(f"* Severity: `{impact}`") 288 print(f"* Confidence: `{confidence}`") 289 print("\n### Description") 290 print(description) 291 if exploit_scenario: 292 print("\n### Exploit Scenario:") 293 print(exploit_scenario) 294 print("\n### Recommendation") 295 print(recommendation) 296 297 298def output_detectors(detector_classes: List[Type[AbstractDetector]]) -> None: 299 detectors_list = [] 300 for detector in detector_classes: 301 argument = detector.ARGUMENT 302 # dont show the backdoor example 303 if argument == "backdoor": 304 continue 305 help_info = detector.HELP 306 impact = detector.IMPACT 307 confidence = classification_txt[detector.CONFIDENCE] 308 detectors_list.append((argument, help_info, impact, confidence)) 309 table = MyPrettyTable(["Num", "Check", "What it Detects", "Impact", "Confidence"]) 310 311 # Sort by impact, confidence, and name 312 detectors_list = sorted( 313 detectors_list, key=lambda element: (element[2], element[3], element[0]) 314 ) 315 idx = 1 316 for (argument, help_info, impact, confidence) in detectors_list: 317 table.add_row([str(idx), argument, help_info, classification_txt[impact], confidence]) 318 idx = idx + 1 319 print(table) 320 321 322# pylint: disable=too-many-locals 323def output_detectors_json( 324 detector_classes: List[Type[AbstractDetector]], 325) -> List[Dict]: 326 detectors_list = [] 327 for detector in detector_classes: 328 argument = detector.ARGUMENT 329 # dont show the backdoor example 330 if argument == "backdoor": 331 continue 332 help_info = detector.HELP 333 impact = detector.IMPACT 334 confidence = classification_txt[detector.CONFIDENCE] 335 wiki_url = detector.WIKI 336 wiki_description = detector.WIKI_DESCRIPTION 337 wiki_exploit_scenario = detector.WIKI_EXPLOIT_SCENARIO 338 wiki_recommendation = detector.WIKI_RECOMMENDATION 339 detectors_list.append( 340 ( 341 argument, 342 help_info, 343 impact, 344 confidence, 345 wiki_url, 346 wiki_description, 347 wiki_exploit_scenario, 348 wiki_recommendation, 349 ) 350 ) 351 352 # Sort by impact, confidence, and name 353 detectors_list = sorted( 354 detectors_list, key=lambda element: (element[2], element[3], element[0]) 355 ) 356 idx = 1 357 table = [] 358 for ( 359 argument, 360 help_info, 361 impact, 362 confidence, 363 wiki_url, 364 description, 365 exploit, 366 recommendation, 367 ) in detectors_list: 368 table.append( 369 { 370 "index": idx, 371 "check": argument, 372 "title": help_info, 373 "impact": classification_txt[impact], 374 "confidence": confidence, 375 "wiki_url": wiki_url, 376 "description": description, 377 "exploit_scenario": exploit, 378 "recommendation": recommendation, 379 } 380 ) 381 idx = idx + 1 382 return table 383 384 385def output_printers(printer_classes: List[Type[AbstractPrinter]]) -> None: 386 printers_list = [] 387 for printer in printer_classes: 388 argument = printer.ARGUMENT 389 help_info = printer.HELP 390 printers_list.append((argument, help_info)) 391 table = MyPrettyTable(["Num", "Printer", "What it Does"]) 392 393 # Sort by impact, confidence, and name 394 printers_list = sorted(printers_list, key=lambda element: (element[0])) 395 idx = 1 396 for (argument, help_info) in printers_list: 397 table.add_row([str(idx), argument, help_info]) 398 idx = idx + 1 399 print(table) 400 401 402def output_printers_json(printer_classes: List[Type[AbstractPrinter]]) -> List[Dict]: 403 printers_list = [] 404 for printer in printer_classes: 405 argument = printer.ARGUMENT 406 help_info = printer.HELP 407 408 printers_list.append((argument, help_info)) 409 410 # Sort by name 411 printers_list = sorted(printers_list, key=lambda element: (element[0])) 412 idx = 1 413 table = [] 414 for (argument, help_info) in printers_list: 415 table.append({"index": idx, "check": argument, "title": help_info}) 416 idx = idx + 1 417 return table 418 419 420def check_and_sanitize_markdown_root(markdown_root: str) -> str: 421 # Regex to check whether the markdown_root is a GitHub URL 422 match = re.search( 423 r"(https://)github.com/([a-zA-Z-]+)([:/][A-Za-z0-9_.-]+[:/]?)([A-Za-z0-9_.-]*)(.*)", 424 markdown_root, 425 ) 426 if match: 427 if markdown_root[-1] != "/": 428 logger.warning("Appending '/' in markdown_root url for better code referencing") 429 markdown_root = markdown_root + "/" 430 431 if not match.group(4): 432 logger.warning( 433 "Appending 'master/tree/' in markdown_root url for better code referencing" 434 ) 435 markdown_root = markdown_root + "master/tree/" 436 elif match.group(4) == "tree": 437 logger.warning( 438 "Replacing 'tree' with 'blob' in markdown_root url for better code referencing" 439 ) 440 positions = match.span(4) 441 markdown_root = f"{markdown_root[:positions[0]]}blob{markdown_root[positions[1]:]}" 442 443 return markdown_root
logger =
<Logger Slither (WARNING)>
DEFAULT_JSON_OUTPUT_TYPES =
['detectors', 'printers']
JSON_OUTPUT_TYPES =
['compilations', 'console', 'detectors', 'printers', 'list-detectors', 'list-printers']
class
FailOnLevel(enum.Enum):
33class FailOnLevel(enum.Enum): 34 PEDANTIC = "pedantic" 35 LOW = "low" 36 MEDIUM = "medium" 37 HIGH = "high" 38 NONE = "none"
An enumeration.
PEDANTIC =
<FailOnLevel.PEDANTIC: 'pedantic'>
LOW =
<FailOnLevel.LOW: 'low'>
MEDIUM =
<FailOnLevel.MEDIUM: 'medium'>
HIGH =
<FailOnLevel.HIGH: 'high'>
NONE =
<FailOnLevel.NONE: 'none'>
Inherited Members
- enum.Enum
- name
- value
defaults_flag_in_config =
{'codex': False, 'codex_contracts': 'all', 'codex_model': 'text-davinci-003', 'codex_temperature': 0, 'codex_max_tokens': 300, 'codex_log': False, 'detectors_to_run': 'all', 'printers_to_run': None, 'detectors_to_exclude': None, 'exclude_dependencies': False, 'exclude_informational': False, 'exclude_optimization': False, 'exclude_low': False, 'exclude_medium': False, 'exclude_high': False, 'fail_on': <FailOnLevel.PEDANTIC: 'pedantic'>, 'json': None, 'sarif': None, 'json-types': 'detectors,printers', 'disable_color': False, 'filter_paths': None, 'include_paths': None, 'generate_patches': False, 'skip_assembly': False, 'legacy_ast': False, 'zip': None, 'zip_type': 'lzma', 'show_ignored_findings': False, 'no_fail': False, 'sarif_input': 'export.sarif', 'sarif_triage': 'export.sarif.sarifexplorer', 'triage_database': 'slither.db.json', 'compile_force_framework': None, 'compile_remove_metadata': False, 'compile_custom_build': None, 'solc': 'solc', 'solc_remaps': None, 'solc_args': None, 'solc_disable_warnings': False, 'solc_working_dir': None, 'solc_solcs_select': None, 'solc_solcs_bin': None, 'solc_standard_json': False, 'solc_force_legacy_json': False, 'truffle_version': None, 'truffle_ignore_compile': False, 'truffle_build_directory': 'build/contracts', 'truffle_overwrite_config': False, 'truffle_overwrite_version': None, 'embark_ignore_compile': False, 'embark_overwrite_config': False, 'brownie_ignore_compile': False, 'dapp_ignore_compile': False, 'etherlime_ignore_compile': False, 'etherlime_compile_arguments': None, 'etherscan_only_source_code': False, 'etherscan_only_bytecode': False, 'etherscan_api_key': None, 'etherscan_export_directory': 'etherscan-contracts', 'waffle_ignore_compile': False, 'waffle_config_file': None, 'npx_disable': False, 'ignore_compile': False, 'skip_clean': False, 'buidler_ignore_compile': False, 'buidler_cache_directory': 'cache', 'buidler_skip_directory_name_fix': False, 'hardhat_ignore_compile': False, 'hardhat_cache_directory': None, 'hardhat_artifacts_directory': None, 'foundry_ignore_compile': False, 'foundry_out_directory': 'out', 'foundry_compile_all': False, 'export_dir': 'crytic-export', 'compile_libraries': None}
deprecated_flags =
{'fail_pedantic': True, 'fail_low': False, 'fail_medium': False, 'fail_high': False}
def
read_config_file(args: argparse.Namespace) -> None:
87def read_config_file(args: argparse.Namespace) -> None: 88 # No config file was provided as an argument 89 if args.config_file is None: 90 # Check wether the default config file is present 91 if os.path.exists("slither.config.json"): 92 # The default file exists, use it 93 args.config_file = "slither.config.json" 94 else: 95 return 96 97 if os.path.isfile(args.config_file): 98 try: 99 with open(args.config_file, encoding="utf8") as f: 100 config = json.load(f) 101 for key, elem in config.items(): 102 if key in deprecated_flags: 103 logger.info( 104 yellow(f"{args.config_file} has a deprecated key: {key} : {elem}") 105 ) 106 migrate_config_options(args, key, elem) 107 continue 108 if key not in defaults_flag_in_config: 109 logger.info( 110 yellow(f"{args.config_file} has an unknown key: {key} : {elem}") 111 ) 112 continue 113 if getattr(args, key) == defaults_flag_in_config[key]: 114 setattr(args, key, elem) 115 except json.decoder.JSONDecodeError as e: 116 logger.error(red(f"Impossible to read {args.config_file}, please check the file {e}")) 117 else: 118 logger.error(red(f"File {args.config_file} is not a file or does not exist")) 119 logger.error(yellow("Falling back to the default settings..."))
def
migrate_config_options(args: argparse.Namespace, key: str, elem):
122def migrate_config_options(args: argparse.Namespace, key: str, elem): 123 if key.startswith("fail_") and getattr(args, "fail_on") == defaults_flag_in_config["fail_on"]: 124 if key == "fail_pedantic": 125 pedantic_setting = elem 126 fail_on = FailOnLevel.PEDANTIC if pedantic_setting else FailOnLevel.NONE 127 setattr(args, "fail_on", fail_on) 128 logger.info(f"Migrating fail_pedantic: {pedantic_setting} as fail_on: {fail_on.value}") 129 elif key == "fail_low" and elem is True: 130 logger.info("Migrating fail_low: true -> fail_on: low") 131 setattr(args, "fail_on", FailOnLevel.LOW) 132 133 elif key == "fail_medium" and elem is True: 134 logger.info("Migrating fail_medium: true -> fail_on: medium") 135 setattr(args, "fail_on", FailOnLevel.MEDIUM) 136 137 elif key == "fail_high" and elem is True: 138 logger.info("Migrating fail_high: true -> fail_on: high") 139 setattr(args, "fail_on", FailOnLevel.HIGH) 140 else: 141 logger.warning(yellow(f"Key {key} was deprecated but no migration was provided"))
def
output_to_markdown( detector_classes: List[Type[slither.detectors.abstract_detector.AbstractDetector]], printer_classes: List[Type[slither.printers.abstract_printer.AbstractPrinter]], filter_wiki: str) -> None:
144def output_to_markdown( 145 detector_classes: List[Type[AbstractDetector]], 146 printer_classes: List[Type[AbstractPrinter]], 147 filter_wiki: str, 148) -> None: 149 def extract_help(cls: Union[Type[AbstractDetector], Type[AbstractPrinter]]) -> str: 150 if cls.WIKI == "": 151 return cls.HELP 152 return f"[{cls.HELP}]({cls.WIKI})" 153 154 detectors_list = [] 155 print(filter_wiki) 156 for detector in detector_classes: 157 argument = detector.ARGUMENT 158 # dont show the backdoor example 159 if argument == "backdoor": 160 continue 161 if not filter_wiki in detector.WIKI: 162 continue 163 help_info = extract_help(detector) 164 impact = detector.IMPACT 165 confidence = classification_txt[detector.CONFIDENCE] 166 detectors_list.append((argument, help_info, impact, confidence)) 167 168 # Sort by impact, confidence, and name 169 detectors_list = sorted( 170 detectors_list, key=lambda element: (element[2], element[3], element[0]) 171 ) 172 idx = 1 173 for (argument, help_info, impact, confidence) in detectors_list: 174 print(f"{idx} | `{argument}` | {help_info} | {classification_txt[impact]} | {confidence}") 175 idx = idx + 1 176 177 print() 178 printers_list = [] 179 for printer in printer_classes: 180 argument = printer.ARGUMENT 181 help_info = extract_help(printer) 182 printers_list.append((argument, help_info)) 183 184 # Sort by impact, confidence, and name 185 printers_list = sorted(printers_list, key=lambda element: (element[0])) 186 idx = 1 187 for (argument, help_info) in printers_list: 188 print(f"{idx} | `{argument}` | {help_info}") 189 idx = idx + 1
def
get_level(l: str) -> int:
def
convert_result_to_markdown(txt: str) -> str:
201def convert_result_to_markdown(txt: str) -> str: 202 # -1 to remove the last \n 203 lines = txt[0:-1].split("\n") 204 ret = [] 205 level = 0 206 for l in lines: 207 next_level = get_level(l) 208 prefix = "<li>" 209 if next_level < level: 210 prefix = "</ul>" * (level - next_level) + prefix 211 if next_level > level: 212 prefix = "<ul>" * (next_level - level) + prefix 213 level = next_level 214 ret.append(prefix + l) 215 216 return "".join(ret)
def
output_results_to_markdown( all_results: List[Dict], checklistlimit: str, show_ignored_findings: bool) -> None:
219def output_results_to_markdown( 220 all_results: List[Dict], checklistlimit: str, show_ignored_findings: bool 221) -> None: 222 checks = defaultdict(list) 223 info: Dict = defaultdict(dict) 224 for results_ in all_results: 225 checks[results_["check"]].append(results_) 226 info[results_["check"]] = { 227 "impact": results_["impact"], 228 "confidence": results_["confidence"], 229 } 230 231 if not show_ignored_findings: 232 print( 233 "**THIS CHECKLIST IS NOT COMPLETE**. Use `--show-ignored-findings` to show all the results." 234 ) 235 236 print("Summary") 237 for check_ in checks: 238 print( 239 f" - [{check_}](#{check_}) ({len(checks[check_])} results) ({info[check_]['impact']})" 240 ) 241 242 counter = 0 243 for (check, results) in checks.items(): 244 print(f"## {check}") 245 print(f'Impact: {info[check]["impact"]}') 246 print(f'Confidence: {info[check]["confidence"]}') 247 additional = False 248 if checklistlimit and len(results) > 5: 249 results = results[0:5] 250 additional = True 251 for result in results: 252 print(" - [ ] ID-" + f"{counter}") 253 counter = counter + 1 254 print(result["markdown"]) 255 if result["first_markdown_element"]: 256 print(result["first_markdown_element"]) 257 print("\n") 258 if additional: 259 print(f"**More results were found, check [{checklistlimit}]({checklistlimit})**")
def
output_wiki( detector_classes: List[Type[slither.detectors.abstract_detector.AbstractDetector]], filter_wiki: str) -> None:
262def output_wiki(detector_classes: List[Type[AbstractDetector]], filter_wiki: str) -> None: 263 264 # Sort by impact, confidence, and name 265 detectors_list = sorted( 266 detector_classes, 267 key=lambda element: (element.IMPACT, element.CONFIDENCE, element.ARGUMENT), 268 ) 269 270 for detector in detectors_list: 271 argument = detector.ARGUMENT 272 # dont show the backdoor example 273 if argument == "backdoor": 274 continue 275 if not filter_wiki in detector.WIKI: 276 continue 277 check = detector.ARGUMENT 278 impact = classification_txt[detector.IMPACT] 279 confidence = classification_txt[detector.CONFIDENCE] 280 title = detector.WIKI_TITLE 281 description = detector.WIKI_DESCRIPTION 282 exploit_scenario = detector.WIKI_EXPLOIT_SCENARIO 283 recommendation = detector.WIKI_RECOMMENDATION 284 285 print(f"\n## {title}") 286 print("### Configuration") 287 print(f"* Check: `{check}`") 288 print(f"* Severity: `{impact}`") 289 print(f"* Confidence: `{confidence}`") 290 print("\n### Description") 291 print(description) 292 if exploit_scenario: 293 print("\n### Exploit Scenario:") 294 print(exploit_scenario) 295 print("\n### Recommendation") 296 print(recommendation)
def
output_detectors( detector_classes: List[Type[slither.detectors.abstract_detector.AbstractDetector]]) -> None:
299def output_detectors(detector_classes: List[Type[AbstractDetector]]) -> None: 300 detectors_list = [] 301 for detector in detector_classes: 302 argument = detector.ARGUMENT 303 # dont show the backdoor example 304 if argument == "backdoor": 305 continue 306 help_info = detector.HELP 307 impact = detector.IMPACT 308 confidence = classification_txt[detector.CONFIDENCE] 309 detectors_list.append((argument, help_info, impact, confidence)) 310 table = MyPrettyTable(["Num", "Check", "What it Detects", "Impact", "Confidence"]) 311 312 # Sort by impact, confidence, and name 313 detectors_list = sorted( 314 detectors_list, key=lambda element: (element[2], element[3], element[0]) 315 ) 316 idx = 1 317 for (argument, help_info, impact, confidence) in detectors_list: 318 table.add_row([str(idx), argument, help_info, classification_txt[impact], confidence]) 319 idx = idx + 1 320 print(table)
def
output_detectors_json( detector_classes: List[Type[slither.detectors.abstract_detector.AbstractDetector]]) -> List[Dict]:
324def output_detectors_json( 325 detector_classes: List[Type[AbstractDetector]], 326) -> List[Dict]: 327 detectors_list = [] 328 for detector in detector_classes: 329 argument = detector.ARGUMENT 330 # dont show the backdoor example 331 if argument == "backdoor": 332 continue 333 help_info = detector.HELP 334 impact = detector.IMPACT 335 confidence = classification_txt[detector.CONFIDENCE] 336 wiki_url = detector.WIKI 337 wiki_description = detector.WIKI_DESCRIPTION 338 wiki_exploit_scenario = detector.WIKI_EXPLOIT_SCENARIO 339 wiki_recommendation = detector.WIKI_RECOMMENDATION 340 detectors_list.append( 341 ( 342 argument, 343 help_info, 344 impact, 345 confidence, 346 wiki_url, 347 wiki_description, 348 wiki_exploit_scenario, 349 wiki_recommendation, 350 ) 351 ) 352 353 # Sort by impact, confidence, and name 354 detectors_list = sorted( 355 detectors_list, key=lambda element: (element[2], element[3], element[0]) 356 ) 357 idx = 1 358 table = [] 359 for ( 360 argument, 361 help_info, 362 impact, 363 confidence, 364 wiki_url, 365 description, 366 exploit, 367 recommendation, 368 ) in detectors_list: 369 table.append( 370 { 371 "index": idx, 372 "check": argument, 373 "title": help_info, 374 "impact": classification_txt[impact], 375 "confidence": confidence, 376 "wiki_url": wiki_url, 377 "description": description, 378 "exploit_scenario": exploit, 379 "recommendation": recommendation, 380 } 381 ) 382 idx = idx + 1 383 return table
def
output_printers( printer_classes: List[Type[slither.printers.abstract_printer.AbstractPrinter]]) -> None:
386def output_printers(printer_classes: List[Type[AbstractPrinter]]) -> None: 387 printers_list = [] 388 for printer in printer_classes: 389 argument = printer.ARGUMENT 390 help_info = printer.HELP 391 printers_list.append((argument, help_info)) 392 table = MyPrettyTable(["Num", "Printer", "What it Does"]) 393 394 # Sort by impact, confidence, and name 395 printers_list = sorted(printers_list, key=lambda element: (element[0])) 396 idx = 1 397 for (argument, help_info) in printers_list: 398 table.add_row([str(idx), argument, help_info]) 399 idx = idx + 1 400 print(table)
def
output_printers_json( printer_classes: List[Type[slither.printers.abstract_printer.AbstractPrinter]]) -> List[Dict]:
403def output_printers_json(printer_classes: List[Type[AbstractPrinter]]) -> List[Dict]: 404 printers_list = [] 405 for printer in printer_classes: 406 argument = printer.ARGUMENT 407 help_info = printer.HELP 408 409 printers_list.append((argument, help_info)) 410 411 # Sort by name 412 printers_list = sorted(printers_list, key=lambda element: (element[0])) 413 idx = 1 414 table = [] 415 for (argument, help_info) in printers_list: 416 table.append({"index": idx, "check": argument, "title": help_info}) 417 idx = idx + 1 418 return table
def
check_and_sanitize_markdown_root(markdown_root: str) -> str:
421def check_and_sanitize_markdown_root(markdown_root: str) -> str: 422 # Regex to check whether the markdown_root is a GitHub URL 423 match = re.search( 424 r"(https://)github.com/([a-zA-Z-]+)([:/][A-Za-z0-9_.-]+[:/]?)([A-Za-z0-9_.-]*)(.*)", 425 markdown_root, 426 ) 427 if match: 428 if markdown_root[-1] != "/": 429 logger.warning("Appending '/' in markdown_root url for better code referencing") 430 markdown_root = markdown_root + "/" 431 432 if not match.group(4): 433 logger.warning( 434 "Appending 'master/tree/' in markdown_root url for better code referencing" 435 ) 436 markdown_root = markdown_root + "master/tree/" 437 elif match.group(4) == "tree": 438 logger.warning( 439 "Replacing 'tree' with 'blob' in markdown_root url for better code referencing" 440 ) 441 positions = match.span(4) 442 markdown_root = f"{markdown_root[:positions[0]]}blob{markdown_root[positions[1]:]}" 443 444 return markdown_root