From 6b6113b236d136c412251c2c6f147c9321b2acfe Mon Sep 17 00:00:00 2001 From: ziirish Date: Mon, 19 Oct 2015 21:13:13 +0200 Subject: [PATCH] rework installer and remove external scripts --- bui-agent | 48 +----------------- burp-ui | 32 +----------- burpui/__init__.py | 118 ++++++++++++++++++++++++++------------------- burpui/__main__.py | 96 ++++++++++++++++++++++++++++++++++++ burpui/routes.py | 9 ++-- burpui/server.py | 17 ++++--- setup.py | 18 ++++--- 7 files changed, 192 insertions(+), 146 deletions(-) create mode 100644 burpui/__main__.py diff --git a/bui-agent b/bui-agent index 4097e41e..69f0bf80 100755 --- a/bui-agent +++ b/bui-agent @@ -1,47 +1,3 @@ -#!/usr/bin/env python -# -*- coding: utf8 -*- -import sys -import os -import logging -from optparse import OptionParser +#!/bin/bash -sys.path.append('{0}/..'.format(os.path.join(os.path.dirname(os.path.realpath(__file__))))) - -from burpui.agent import BUIAgent as Agent - -if __name__ == '__main__': - """ - Main function - """ - parser = OptionParser() - parser.add_option('-v', '--verbose', dest='log', help='increase output verbosity (e.g., -vv is more than -v)', action='count') - parser.add_option('-l', '--logfile', dest='logfile', help='where to store logs', metavar='LOGFILE') - parser.add_option('-c', '--config', dest='config', help='configuration file', metavar='CONFIG') - - (options, args) = parser.parse_args() - - if options.config: - if os.path.isfile(options.config): - conf = options.config - else: - raise IOError('File not found: \'{0}\''.format(options.config)) - else: - root = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - '..', - 'share', - 'burpui', - 'etc' - ) - conf_files = [ - '/etc/burp/buiagent.cfg', - os.path.join(root, 'buiagent.cfg'), - os.path.join(root, 'buiagent.sample.cfg') - ] - for p in conf_files: - if os.path.isfile(p): - conf = p - break - - agent = Agent(conf, options.log, options.logfile) - agent.run() +python ./burpui -m agent $@ diff --git a/burp-ui b/burp-ui index 17f3273c..c845549f 100755 --- a/burp-ui +++ b/burp-ui @@ -1,31 +1,3 @@ -#!/usr/bin/env python -# -*- coding: utf8 -*- -import sys -import os -from optparse import OptionParser +#!/bin/bash -sys.path.append('{0}/..'.format(os.path.join(os.path.dirname(os.path.realpath(__file__))))) - -from burpui import bui, init, __title__, __version__ - -if __name__ == '__main__': - """ - Main function - """ - parser = OptionParser() - parser.add_option('-v', '--verbose', dest='log', help='verbose output', action='store_true') - parser.add_option('-d', '--debug', dest='log', help='verbose output (alias)', action='store_true') # alias for -v - parser.add_option('-V', '--version', dest='version', help='print version and exit', action='store_true') - parser.add_option('-c', '--config', dest='config', help='configuration file', metavar='CONFIG') - parser.add_option('-l', '--logfile', dest='logfile', help='output logs in defined file', metavar='FILE') - - (options, args) = parser.parse_args() - d = options.log - - if options.version: - print ('{}: v{}'.format(__title__, __version__)) - sys.exit(0) - - init(options.config, d, options.logfile, False) - - bui.run(d) +python ./burpui $@ diff --git a/burpui/__init__.py b/burpui/__init__.py index ab89cffa..99449c98 100644 --- a/burpui/__init__.py +++ b/burpui/__init__.py @@ -17,9 +17,9 @@ import logging from flask import Flask from flask.ext.login import LoginManager from flask.ext.bower import Bower -from burpui.server import BUIServer as BurpUI -from burpui.routes import view -from burpui.api import api +from .server import BUIServer as BurpUI +from .routes import view +from .api import api if sys.version_info < (3, 0): reload(sys) @@ -51,7 +51,7 @@ app.register_blueprint(view) # We initialize the API api.app = app -api.bui = bui +api.init_bui(bui) api.init_app(app) # And the login_manager @@ -74,57 +74,17 @@ def load_user(userid): return None # pragma: no cover -def init(conf=None, debug=False, logfile=None, gunicorn=True): - """Initialize the whole application. - - :param conf: Configuration file to use - :type conf: str - - :param debug: Enable verbose output - :type debug: bool - - :param logfile: Store the logs in the given file - :type logfile: str - - :param gunicorn: Enable gunicorn engine instead of flask's default - :type gunicorn: bool - - :returns: A :class:`Flask` object - """ - if debug and not gunicorn: # pragma: no cover - app.config['DEBUG'] = debug - app.config['TESTING'] = True - - if logfile: - from logging import Formatter - from logging.handlers import RotatingFileHandler - file_handler = RotatingFileHandler(logfile, maxBytes=1024 * 1024 * 100, backupCount=20) - if debug: - LOG_FORMAT = ( - '-' * 80 + '\n' + - '%(levelname)s in %(module)s [%(pathname)s:%(lineno)d]:\n' + - '%(message)s\n' + - '-' * 80 - ) - file_handler.setLevel(logging.DEBUG) - else: - LOG_FORMAT = '[%(asctime)s] %(levelname)s in %(module)s: %(message)s' - file_handler.setLevel(logging.INFO) - file_handler.setFormatter(Formatter(LOG_FORMAT)) - app.logger.addHandler(file_handler) - +def lookup_config(conf=None): + ret = None if conf: if os.path.isfile(conf): + ret = conf app.config['CFG'] = conf else: raise IOError('File not found: \'{0}\''.format(conf)) else: root = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - '..', - '..', - '..', - '..', + sys.prefix, 'share', 'burpui', 'etc' @@ -135,12 +95,70 @@ def init(conf=None, debug=False, logfile=None, gunicorn=True): os.path.join(root, 'burpui.sample.cfg') ] for p in conf_files: - app.logger.debug('Trying file \'%s\'', p) + app.logger.debug('Trying file \'{}\''.format(p)) if os.path.isfile(p): app.config['CFG'] = p - app.logger.debug('Using file \'%s\'', p) + ret = p + app.logger.debug('Using file \'{}\''.format(p)) break + return ret + + +def init(conf=None, debug=0, logfile=None, gunicorn=True): + """Initialize the whole application. + + :param conf: Configuration file to use + :type conf: str + + :param debug: Enable verbose output + :type debug: int + + :param logfile: Store the logs in the given file + :type logfile: str + + :param gunicorn: Enable gunicorn engine instead of flask's default + :type gunicorn: bool + + :returns: A :class:`Flask` object + """ + # The debug argument used to be a boolean so we keep supporting this format + if isinstance(debug, bool): + debug = logging.DEBUG + else: + levels = [logging.NOTSET, logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG] + if debug >= len(levels): + debug = len(levels) - 1 + if not debug: + debug = 0 + debug = levels[debug] + + if debug != logging.NOTSET and not gunicorn: # pragma: no cover + app.config['DEBUG'] = True + app.config['TESTING'] = True + + if logfile: + from logging import Formatter + from logging.handlers import RotatingFileHandler + file_handler = RotatingFileHandler(logfile, maxBytes=1024 * 1024 * 100, backupCount=20) + if debug > logging.INFO: + LOG_FORMAT = ( + '-' * 80 + '\n' + + '%(levelname)s in %(module)s [%(pathname)s:%(lineno)d]:\n' + + '%(message)s\n' + + '-' * 80 + ) + file_handler.setLevel(debug) + else: + LOG_FORMAT = '[%(asctime)s] %(levelname)s in %(module)s: %(message)s' + file_handler.setLevel(debug) + file_handler.setFormatter(Formatter(LOG_FORMAT)) + app.logger.addHandler(file_handler) + + # Still need to test conf file here because the init function can be called + # by gunicorn directly + lookup_config(conf) + bui.setup(app.config['CFG']) if gunicorn: # pragma: no cover diff --git a/burpui/__main__.py b/burpui/__main__.py new file mode 100644 index 00000000..a4f1e13c --- /dev/null +++ b/burpui/__main__.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python +# -*- coding: utf8 -*- +import sys +import os +from argparse import ArgumentParser + +sys.path.append('{0}/..'.format(os.path.join(os.path.dirname(os.path.realpath(__file__))))) + + +def parse_args(mode=True, name=None): + if not name: + name = 'burp-ui' + parser = ArgumentParser(prog=name) + parser.add_argument('-v', '--verbose', dest='log', help='increase output verbosity (e.g., -vv is more than -v)', action='count') + parser.add_argument('-d', '--debug', dest='log', help='alias for -v', action='count') # alias for -v + parser.add_argument('-V', '--version', dest='version', help='print version and exit', action='store_true') + parser.add_argument('-c', '--config', dest='config', help='configuration file', metavar='CONFIG') + parser.add_argument('-l', '--logfile', dest='logfile', help='output logs in defined file', metavar='FILE') + if mode: + parser.add_argument('-m', '--mode', dest='mode', help='application mode (server or agent)', metavar='MODE') + + options = parser.parse_args() + + if options.version: + from burpui import __title__, __version__ + print ('{}: v{}'.format(__title__, __version__)) + sys.exit(0) + + return options + + +def main(): + """ + Main function + """ + options = parse_args(mode=True) + + if not options.mode or options.mode == 'server': + server(options) + else: + agent(options) + + +def server(options=None): + from burpui import bui as server, init, lookup_config + + if not options: + options = parse_args(mode=False) + + conf = lookup_config() + check_config(conf) + + init(conf, options.log, options.logfile, False) + + server.run() + + +def agent(options=None): + from burpui.agent import BUIAgent as Agent + + if not options: + options = parse_args(mode=False, name='bui-agent') + + conf = None + if options.config: + conf = options.config + else: + root = os.path.join( + sys.prefix, + 'share', + 'burpui', + 'etc' + ) + conf_files = [ + '/etc/burp/buiagent.cfg', + os.path.join(root, 'buiagent.cfg'), + os.path.join(root, 'buiagent.sample.cfg') + ] + for p in conf_files: + if os.path.isfile(p): + conf = p + break + + check_config(conf) + + agent = Agent(conf, options.log, options.logfile) + agent.run() + + +def check_config(conf): + if not conf or not os.path.isfile(conf): + raise IOError('File not found: \'{0}\''.format(conf)) + + +if __name__ == '__main__': + main() diff --git a/burpui/routes.py b/burpui/routes.py index a296a140..19fd06bf 100644 --- a/burpui/routes.py +++ b/burpui/routes.py @@ -5,12 +5,9 @@ import sys from flask import request, render_template, jsonify, redirect, url_for, abort, flash, Blueprint from flask.ext.login import login_user, login_required, logout_user, current_user -from burpui.forms import LoginForm -from burpui.misc.utils import human_readable as _hr -from burpui.misc.backend.interface import BUIserverException - -import burpui.api -from burpui.api.servers import ServersStats, Live +from .forms import LoginForm +from .misc.utils import human_readable as _hr +from .misc.backend.interface import BUIserverException if sys.version_info >= (3, 0): from urllib.parse import quote diff --git a/burpui/server.py b/burpui/server.py index 7be5be4e..9e3eda80 100644 --- a/burpui/server.py +++ b/burpui/server.py @@ -14,7 +14,7 @@ except ImportError: import traceback import sys -from burpui.misc.backend.burp1 import Burp as BurpGeneric +from .misc.backend.burp1 import Burp as BurpGeneric g_port = '5000' g_bind = '::' @@ -79,6 +79,8 @@ class BUIServer: self.auth = self._safe_config_get(config.get, 'auth') if self.auth and self.auth.lower() != 'none': try: + import os + sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) mod = __import__( 'burpui.misc.auth.{0}'.format(self.auth.lower()), fromlist=['UserHandler'] @@ -98,6 +100,8 @@ class BUIServer: if self.acl_engine and self.acl_engine.lower() != 'none': try: + import os + sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) mod = __import__( 'burpui.misc.acl.{0}'.format(self.acl_engine.lower()), fromlist=['ACLloader'] @@ -141,6 +145,8 @@ class BUIServer: # This instanciation is used for development purpose only self.cli = BurpGeneric(dummy=True) try: + import os + sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) mod = __import__(module, fromlist=['Burp']) Client = mod.Burp self.cli = Client(self, conf=conf) @@ -184,12 +190,9 @@ class BUIServer: return self.defaults[key] return None - def run(self, debug=False): + def run(self): """The :func:`burpui.server.BUIServer.run` functions is used to actually launch the ``Burp-UI`` server. - - :param debug: Enable debug mode - :type conf: bool """ if not self.init: self.setup() @@ -199,6 +202,6 @@ class BUIServer: if self.sslcontext: self.app.config['SSL'] = True - self.app.run(host=self.bind, port=self.port, debug=debug, ssl_context=self.sslcontext) + self.app.run(host=self.bind, port=self.port, debug=self.app.config['DEBUG'], ssl_context=self.sslcontext) else: - self.app.run(host=self.bind, port=self.port, debug=debug) + self.app.run(host=self.bind, port=self.port, debug=self.app.config['DEBUG']) diff --git a/setup.py b/setup.py index 548a2e8f..6f5a417e 100755 --- a/setup.py +++ b/setup.py @@ -41,8 +41,7 @@ class BuildStatic(Command): def run(self): log.info("running [bower install]") try: - path = check_output(['which', 'bower']) - check_output([path, 'install'], cwd=ROOT) + check_output(['bower', 'install'], cwd=ROOT) except Exception as e: log.warn(str(e)) @@ -105,15 +104,20 @@ setup( package_data={ 'static': 'burpui/static/*', 'templates': 'burpui/templates/*', - 'VERSION': 'burpui/VERSION' + 'VERSION': 'burpui/VERSION', + }, + entry_points={ + 'console_scripts': [ + 'burp-ui=burpui.__main__:server', + 'bui-agent=burpui.__main__:agent', + ], }, - scripts=['bin/burp-ui', 'bin/bui-agent'], data_files=[ (datadir, [os.path.join(datadir, 'burpui.sample.cfg')]), (datadir, [os.path.join(datadir, 'buiagent.sample.cfg')]), (os.path.join(contrib, 'centos'), ['contrib/centos/init.sh']), (os.path.join(contrib, 'debian'), ['contrib/debian/init.sh']), - (os.path.join(contrib, 'gunicorn.d'), ['contrib/gunicorn.d/burp-ui']) + (os.path.join(contrib, 'gunicorn.d'), ['contrib/gunicorn.d/burp-ui']), ], install_requires=requires, extras_require={ @@ -129,12 +133,12 @@ setup( 'Programming Language :: Python', 'Programming Language :: Python :: 2.7', 'Topic :: System :: Archiving :: Backup', - 'Topic :: System :: Monitoring' + 'Topic :: System :: Monitoring', ], cmdclass={ 'build_static': BuildStatic, 'develop': DevelopWithBuildStatic, 'sdist': SdistWithBuildStatic, - 'install': CustomInstall + 'install': CustomInstall, } )