Static Analyzer for Solidity
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
slither/slither/detectors/abstract_detector.py

131 lines
4.5 KiB

import abc
import re
from slither.utils.colors import green, yellow, red
from collections import OrderedDict
class IncorrectDetectorInitialization(Exception):
pass
class DetectorClassification:
HIGH = 0
MEDIUM = 1
LOW = 2
INFORMATIONAL = 3
classification_colors = {
DetectorClassification.INFORMATIONAL: green,
DetectorClassification.LOW: green,
DetectorClassification.MEDIUM: yellow,
DetectorClassification.HIGH: red,
}
classification_txt = {
DetectorClassification.INFORMATIONAL: 'Informational',
DetectorClassification.LOW: 'Low',
DetectorClassification.MEDIUM: 'Medium',
DetectorClassification.HIGH: 'High',
}
class AbstractDetector(metaclass=abc.ABCMeta):
ARGUMENT = '' # run the detector with slither.py --ARGUMENT
HELP = '' # help information
IMPACT = None
CONFIDENCE = None
WIKI = ''
def __init__(self, slither, logger):
self.slither = slither
self.contracts = slither.contracts
self.filename = slither.filename
self.logger = logger
if not self.HELP:
raise IncorrectDetectorInitialization('HELP is not initialized {}'.format(self.__class__.__name__))
if not self.ARGUMENT:
raise IncorrectDetectorInitialization('ARGUMENT is not initialized {}'.format(self.__class__.__name__))
if re.match('^[a-zA-Z0-9_-]*$', self.ARGUMENT) is None:
raise IncorrectDetectorInitialization('ARGUMENT has illegal character {}'.format(self.__class__.__name__))
if self.IMPACT not in [DetectorClassification.LOW,
DetectorClassification.MEDIUM,
DetectorClassification.HIGH,
DetectorClassification.INFORMATIONAL]:
raise IncorrectDetectorInitialization('IMPACT is not initialized {}'.format(self.__class__.__name__))
if self.CONFIDENCE not in [DetectorClassification.LOW,
DetectorClassification.MEDIUM,
DetectorClassification.HIGH,
DetectorClassification.INFORMATIONAL]:
raise IncorrectDetectorInitialization('CONFIDENCE is not initialized {}'.format(self.__class__.__name__))
def log(self, info):
if self.logger:
info = "\n"+info
if self.WIKI != '':
info += 'Reference: {}'.format(self.WIKI)
self.logger.info(self.color(info))
@abc.abstractmethod
def detect(self):
"""TODO Documentation"""
return
@property
def color(self):
return classification_colors[self.IMPACT]
def generate_json_result(self, info):
d = OrderedDict()
d['check'] = self.ARGUMENT
d['impact'] = classification_txt[self.IMPACT]
d['confidence'] = classification_txt[self.CONFIDENCE]
d['description'] = info
d['elements'] = []
return d
@staticmethod
def add_variable_to_json(variable, d):
d['elements'].append({'type': 'variable',
'name': variable.name,
'source_mapping': variable.source_mapping})
@staticmethod
def add_variables_to_json(variables, d):
for variable in sorted(variables, key=lambda x:x.name):
AbstractDetector.add_variable_to_json(variable, d)
@staticmethod
def add_contract_to_json(contract, d):
d['elements'].append({'type': 'contract',
'name': contract.name,
'source_mapping': contract.source_mapping})
@staticmethod
def add_function_to_json(function, d):
contract = {'elements':[]}
AbstractDetector.add_contract_to_json(function.contract, contract)
d['elements'].append({'type': 'function',
'name': function.name,
'source_mapping': function.source_mapping,
'contract': contract['elements'][0]})
@staticmethod
def add_functions_to_json(functions, d):
for function in sorted(functions, key=lambda x: x.name):
AbstractDetector.add_function_to_json(function, d)
@staticmethod
def add_nodes_to_json(nodes, d):
for node in sorted(nodes, key=lambda x: x.node_id):
d['elements'].append({'type': 'expression',
'expression': str(node.expression),
'source_mapping': node.source_mapping})