From b2eb60c9b8f6072cd66a3d9c085e15ec4ff77315 Mon Sep 17 00:00:00 2001 From: ziirish Date: Wed, 18 Nov 2015 22:46:59 +0100 Subject: [PATCH] move utilities functions --- burpui/misc/parser/burp1.py | 2 +- burpui/misc/parser/interface.py | 2 +- burpui/utils.py | 169 ++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 burpui/utils.py diff --git a/burpui/misc/parser/burp1.py b/burpui/misc/parser/burp1.py index 84f91e25..6c734d4c 100644 --- a/burpui/misc/parser/burp1.py +++ b/burpui/misc/parser/burp1.py @@ -7,8 +7,8 @@ import codecs from glob import glob -from ..utils import BUIserverException from .interface import BUIparser +from ...exceptions import BUIserverException class Parser(BUIparser): diff --git a/burpui/misc/parser/interface.py b/burpui/misc/parser/interface.py index c42de7a6..e405e491 100644 --- a/burpui/misc/parser/interface.py +++ b/burpui/misc/parser/interface.py @@ -7,7 +7,7 @@ .. moduleauthor:: Ziirish """ -from ..utils import BUIlogging +from ...utils import BUIlogging class BUIparser(BUIlogging): diff --git a/burpui/utils.py b/burpui/utils.py new file mode 100644 index 00000000..7357f586 --- /dev/null +++ b/burpui/utils.py @@ -0,0 +1,169 @@ +# -*- coding: utf8 -*- +""" +.. module:: burpui.utils + :platform: Unix + :synopsis: Burp-UI utils module. + +.. moduleauthor:: Ziirish + +""" +import math +import string +import sys +import zipfile +import tarfile +import logging + +from inspect import currentframe, getouterframes + +if sys.version_info >= (3, 0): + long = int # pragma: no cover + + +class human_readable(long): + """define a human_readable class to allow custom formatting + format specifiers supported : + em : formats the size as bits in IEC format i.e. 1024 bits (128 bytes) = 1Kib + eM : formats the size as Bytes in IEC format i.e. 1024 bytes = 1KiB + sm : formats the size as bits in SI format i.e. 1000 bits = 1kb + sM : formats the size as bytes in SI format i.e. 1000 bytes = 1KB + cm : format the size as bit in the common format i.e. 1024 bits (128 bytes) = 1Kb + cM : format the size as bytes in the common format i.e. 1024 bytes = 1KB + + code from: http://code.activestate.com/recipes/578323-human-readable-filememory-sizes-v2/ + """ + def __format__(self, fmt): # pragma: no cover + # is it an empty format or not a special format for the size class + if fmt == "" or fmt[-2:].lower() not in ["em", "sm", "cm"]: + if fmt[-1].lower() in ['b', 'c', 'd', 'o', 'x', 'n', 'e', 'f', 'g', '%']: + # Numeric format. + return long(self).__format__(fmt) + else: + return str(self).__format__(fmt) + + if sys.version_info >= (3, 0): + chars = string.ascii_lowercase + else: + chars = string.lowercase + # work out the scale, suffix and base + factor, suffix = (8, "b") if fmt[-1] in chars else (1, "B") + base = 1024 if fmt[-2] in ["e", "c"] else 1000 + + # Add the i for the IEC format + suffix = "i" + suffix if fmt[-2] == "e" else suffix + + mult = ["", "K", "M", "G", "T", "P"] + + val = float(self) * factor + i = 0 if val < 1 else int(math.log(val, base)) + 1 + v = val / math.pow(base, i) + v, i = (v, i) if v > 0.5 else (v * base, i - 1) + + # Identify if there is a width and extract it + width = "" if fmt.find(".") == -1 else fmt[:fmt.index(".")] + precis = fmt[:-2] if width == "" else fmt[fmt.index("."):-2] + + # do the precision bit first, so width/alignment works with the suffix + if float(self) == 0: + return "{0:{1}f}".format(v, precis) + t = ("{0:{1}f}" + mult[i] + suffix).format(v, precis) + + return "{0:{1}}".format(t, width) if width != "" else t + + +if sys.version_info >= (3, 0): # pragma: no cover + class BUIlogger(logging.Logger): + padding = 0 + """Logger class for more convenience""" + def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None, sinfo=None): + """ + Try to guess where was call the function + """ + cf = currentframe() + caller = getouterframes(cf) + cpt = 0 + size = len(caller) + me = __file__ + if me.endswith('.pyc'): + me = me[:-1] + # It's easy to get the _logger parent function because it's the + # following frame + while cpt < size - 1: + (_, filename, _, function_name, _, _) = caller[cpt] + if function_name == '_logger' and filename == me: + cpt += 1 + break + cpt += 1 + cpt += self.padding + (frame, filename, line_number, function_name, lines, index) = caller[cpt] + return super(BUIlogger, self).makeRecord(name, level, filename, line_number, msg, args, exc_info, func=function_name, extra=extra, sinfo=sinfo) +else: + class BUIlogger(logging.Logger): + padding = 0 + """Logger class for more convenience""" + def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None): + """Try to guess where was call the function""" + cf = currentframe() + caller = getouterframes(cf) + cpt = 0 + size = len(caller) + me = __file__ + if me.endswith('.pyc'): + me = me[:-1] + # It's easy to get the _logger parent function because it's the + # following frame + while cpt < size - 1: + (_, filename, _, function_name, _, _) = caller[cpt] + if function_name == '_logger' and filename == me: + cpt += 1 + break + cpt += 1 + cpt += self.padding + (frame, filename, line_number, function_name, lines, index) = caller[cpt] + return super(BUIlogger, self).makeRecord(name, level, filename, line_number, msg, args, exc_info, func=function_name, extra=extra) + + +class BUIlogging(object): + logger = None + monkey = None + padding = 0 + """Provides a generic logging method for all modules""" + def _logger(self, level, msg, *args): + """generic logging method so that the logging is backend-independent""" + if self.logger and self.logger.getEffectiveLevel() <= logging.getLevelName(level.upper()): + sav = None + if not self.monkey: + self.monkey = BUIlogger(__name__) + # bui-agent overrides the _logger function so we add a padding offset + self.monkey.padding = self.padding + # dynamically monkey-patch the makeRecord function + sav = self.logger.makeRecord + self.logger.makeRecord = self.monkey.makeRecord + self.logger.log(logging.getLevelName(level.upper()), msg, *args) + self.logger.makeRecord = sav + + +class BUIcompress(): + """Provides a context to generate any kind of archive supported by burp-ui""" + def __init__(self, name, archive): # pragma: no cover + self.name = name + self.archive = archive + + def __enter__(self): + self.arch = None + if self.archive == 'zip': + self.arch = zipfile.ZipFile(self.name, mode='w', compression=zipfile.ZIP_DEFLATED) + elif self.archive == 'tar.gz': + self.arch = tarfile.open(self.name, 'w:gz') + elif self.archive == 'tar.bz2': + self.arch = tarfile.open(self.name, 'w:bz2') + return self + + def __exit__(self, type, value, traceback): + self.arch.close() + + def append(self, path, arcname): + if self.archive == 'zip': + self.arch.write(path, arcname) + elif self.archive in ['tar.gz', 'tar.bz2']: + self.arch.add(path, arcname=arcname, recursive=False)