195 lines
5.8 KiB
Python
195 lines
5.8 KiB
Python
|
|
import logging
|
||
|
|
from .colors import *
|
||
|
|
|
||
|
|
__all__ = ['setup_logger', 'console_log_level', 'file_log_level', 'log_file']
|
||
|
|
|
||
|
|
console_log_level = 'INFO'
|
||
|
|
file_log_level = None
|
||
|
|
log_file = 'xsstrike.log'
|
||
|
|
|
||
|
|
"""
|
||
|
|
Default Logging Levels
|
||
|
|
CRITICAL = 50
|
||
|
|
ERROR = 40
|
||
|
|
WARNING = 30
|
||
|
|
INFO = 20
|
||
|
|
DEBUG = 10
|
||
|
|
"""
|
||
|
|
|
||
|
|
VULN_LEVEL_NUM = 60
|
||
|
|
RUN_LEVEL_NUM = 22
|
||
|
|
GOOD_LEVEL_NUM = 25
|
||
|
|
|
||
|
|
|
||
|
|
logging.addLevelName(VULN_LEVEL_NUM, 'VULN')
|
||
|
|
logging.addLevelName(RUN_LEVEL_NUM, 'RUN')
|
||
|
|
logging.addLevelName(GOOD_LEVEL_NUM, 'GOOD')
|
||
|
|
|
||
|
|
|
||
|
|
def _vuln(self, msg, *args, **kwargs):
|
||
|
|
if self.isEnabledFor(VULN_LEVEL_NUM):
|
||
|
|
self._log(VULN_LEVEL_NUM, msg, args, **kwargs)
|
||
|
|
|
||
|
|
|
||
|
|
def _run(self, msg, *args, **kwargs):
|
||
|
|
if self.isEnabledFor(RUN_LEVEL_NUM):
|
||
|
|
self._log(RUN_LEVEL_NUM, msg, args, **kwargs)
|
||
|
|
|
||
|
|
|
||
|
|
def _good(self, msg, *args, **kwargs):
|
||
|
|
if self.isEnabledFor(GOOD_LEVEL_NUM):
|
||
|
|
self._log(GOOD_LEVEL_NUM, msg, args, **kwargs)
|
||
|
|
|
||
|
|
|
||
|
|
logging.Logger.vuln = _vuln
|
||
|
|
logging.Logger.run = _run
|
||
|
|
logging.Logger.good = _good
|
||
|
|
|
||
|
|
|
||
|
|
log_config = {
|
||
|
|
'DEBUG': {
|
||
|
|
'value': logging.DEBUG,
|
||
|
|
'prefix': '{}[*]{}'.format(yellow, end),
|
||
|
|
},
|
||
|
|
'INFO': {
|
||
|
|
'value': logging.INFO,
|
||
|
|
'prefix': info,
|
||
|
|
},
|
||
|
|
'RUN': {
|
||
|
|
'value': RUN_LEVEL_NUM,
|
||
|
|
'prefix': run,
|
||
|
|
},
|
||
|
|
'GOOD': {
|
||
|
|
'value': GOOD_LEVEL_NUM,
|
||
|
|
'prefix': good,
|
||
|
|
},
|
||
|
|
'WARNING': {
|
||
|
|
'value': logging.WARNING,
|
||
|
|
'prefix': '[!!]'.format(yellow, end),
|
||
|
|
},
|
||
|
|
'ERROR': {
|
||
|
|
'value': logging.ERROR,
|
||
|
|
'prefix': bad,
|
||
|
|
},
|
||
|
|
'CRITICAL': {
|
||
|
|
'value': logging.CRITICAL,
|
||
|
|
'prefix': '{}[--]{}'.format(red, end),
|
||
|
|
},
|
||
|
|
'VULN': {
|
||
|
|
'value': VULN_LEVEL_NUM,
|
||
|
|
'prefix': '{}[++]{}'.format(green, red),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
class CustomFormatter(logging.Formatter):
|
||
|
|
def format(self, record):
|
||
|
|
msg = super().format(record)
|
||
|
|
if record.levelname in log_config.keys():
|
||
|
|
msg = '%s %s %s' % (log_config[record.levelname]['prefix'], msg, end)
|
||
|
|
return msg
|
||
|
|
|
||
|
|
|
||
|
|
class CustomStreamHandler(logging.StreamHandler):
|
||
|
|
default_terminator = '\n'
|
||
|
|
|
||
|
|
def emit(self, record):
|
||
|
|
"""
|
||
|
|
Overrides emit method to temporally update terminator character in case last log record character is '\r'
|
||
|
|
:param record:
|
||
|
|
:return:
|
||
|
|
"""
|
||
|
|
if record.msg.endswith('\r'):
|
||
|
|
self.terminator = '\r'
|
||
|
|
super().emit(record)
|
||
|
|
self.terminator = self.default_terminator
|
||
|
|
else:
|
||
|
|
super().emit(record)
|
||
|
|
|
||
|
|
|
||
|
|
def _switch_to_no_format_loggers(self):
|
||
|
|
self.removeHandler(self.console_handler)
|
||
|
|
self.addHandler(self.no_format_console_handler)
|
||
|
|
if hasattr(self, 'file_handler') and hasattr(self, 'no_format_file_handler'):
|
||
|
|
self.removeHandler(self.file_handler)
|
||
|
|
self.addHandler(self.no_format_file_handler)
|
||
|
|
|
||
|
|
|
||
|
|
def _switch_to_default_loggers(self):
|
||
|
|
self.removeHandler(self.no_format_console_handler)
|
||
|
|
self.addHandler(self.console_handler)
|
||
|
|
if hasattr(self, 'file_handler') and hasattr(self, 'no_format_file_handler'):
|
||
|
|
self.removeHandler(self.no_format_file_handler)
|
||
|
|
self.addHandler(self.file_handler)
|
||
|
|
|
||
|
|
|
||
|
|
def _get_level_and_log(self, msg, level):
|
||
|
|
if level.upper() in log_config.keys():
|
||
|
|
log_method = getattr(self, level.lower())
|
||
|
|
log_method(msg)
|
||
|
|
else:
|
||
|
|
self.info(msg)
|
||
|
|
|
||
|
|
|
||
|
|
def log_red_line(self, amount=60, level='INFO'):
|
||
|
|
_switch_to_no_format_loggers(self)
|
||
|
|
_get_level_and_log(self, red + ('-' * amount) + end, level)
|
||
|
|
_switch_to_default_loggers(self)
|
||
|
|
|
||
|
|
|
||
|
|
def log_no_format(self, msg='', level='INFO'):
|
||
|
|
_switch_to_no_format_loggers(self)
|
||
|
|
_get_level_and_log(self, msg, level)
|
||
|
|
_switch_to_default_loggers(self)
|
||
|
|
|
||
|
|
|
||
|
|
def log_debug_json(self, msg='', data={}):
|
||
|
|
if self.isEnabledFor(logging.DEBUG):
|
||
|
|
if isinstance(data, dict):
|
||
|
|
import json
|
||
|
|
try:
|
||
|
|
self.debug('{} {}'.format(msg, json.dumps(data, indent=2)))
|
||
|
|
except TypeError:
|
||
|
|
self.debug('{} {}'.format(msg, data))
|
||
|
|
else:
|
||
|
|
self.debug('{} {}'.format(msg, data))
|
||
|
|
|
||
|
|
|
||
|
|
def setup_logger(name='xsstrike'):
|
||
|
|
from types import MethodType
|
||
|
|
logger = logging.getLogger(name)
|
||
|
|
logger.setLevel(logging.DEBUG)
|
||
|
|
console_handler = CustomStreamHandler(sys.stdout)
|
||
|
|
console_handler.setLevel(log_config[console_log_level]['value'])
|
||
|
|
console_handler.setFormatter(CustomFormatter('%(message)s'))
|
||
|
|
logger.addHandler(console_handler)
|
||
|
|
# Setup blank handler to temporally use to log without format
|
||
|
|
no_format_console_handler = CustomStreamHandler(sys.stdout)
|
||
|
|
no_format_console_handler.setLevel((log_config[console_log_level]['value']))
|
||
|
|
no_format_console_handler.setFormatter(logging.Formatter(fmt=''))
|
||
|
|
# Store current handlers
|
||
|
|
logger.console_handler = console_handler
|
||
|
|
logger.no_format_console_handler = no_format_console_handler
|
||
|
|
|
||
|
|
if file_log_level:
|
||
|
|
detailed_formatter = logging.Formatter('%(asctime)s %(name)s - %(levelname)s - %(message)s')
|
||
|
|
file_handler = logging.FileHandler(log_file)
|
||
|
|
file_handler.setLevel(log_config[file_log_level]['value'])
|
||
|
|
file_handler.setFormatter(detailed_formatter)
|
||
|
|
logger.addHandler(file_handler)
|
||
|
|
# Setup blank handler to temporally use to log without format
|
||
|
|
no_format_file_handler = logging.FileHandler(log_file)
|
||
|
|
no_format_file_handler.setLevel(log_config[file_log_level]['value'])
|
||
|
|
no_format_file_handler.setFormatter(logging.Formatter(fmt=''))
|
||
|
|
# Store file handlers
|
||
|
|
logger.file_handler = file_handler
|
||
|
|
logger.no_format_file_handler = no_format_file_handler
|
||
|
|
|
||
|
|
# Create logger method to only log a red line
|
||
|
|
logger.red_line = MethodType(log_red_line, logger)
|
||
|
|
# Create logger method to log without format
|
||
|
|
logger.no_format = MethodType(log_no_format, logger)
|
||
|
|
# Create logger method to convert data to json and log with debug level
|
||
|
|
logger.debug_json = MethodType(log_debug_json, logger)
|
||
|
|
return logger
|