Commits (303)
......@@ -4,16 +4,21 @@
burpui-dev.cfg*
burpui/RELEASE
devel.sh
clean.sh
*.egg*
.tox
.reports
.coverage
.coveragerc
.ropeproject
.pylintrc
.pytest_cache
.python-version
.pre-commit-config.yaml
dist
_build
.tags
celerybeat-schedule
Pipfile*
pkgs/burp-ui-sql/burpui_sql/VERSION
pkgs/burp-ui-extra/burpui_extra/VERSION
pkgs/burp-ui-agent/burpui_agent
pkgs/burp-ui-monitor/burpui_monitor
variables:
GIT_DEPTH: 1
GIT_SUBMODULE_STRATEGY: recursive
BURP_VERSION: 2.4.0
PG_VERSION: 10
SRC_DIR: burpui
image: docker:git
stages:
- test
- build
- deploy
test:lint:
test:format:
stage: test
image: python:2.7
image: python:3.8
script:
- pip install flake8 pylint
- make flake8
- pip install black
- black --check .
tags:
- lint
except:
- tags
- rc
- demo
test:py2.7:
test:lint:3.6:
stage: test
image: python:2.7
image: python:3.6
script:
- pip install tox
- tox -e py27
- tox -e pep8
tags:
- docker
- lint
except:
- tags
- rc
- demo
test:lint:3.7:
stage: test
image: python:3.7
script:
- pip install tox
- tox -e pep8
tags:
- lint
except:
- tags
- rc
- demo
test:lint:3.8:
stage: test
image: python:3.8
script:
- pip install tox
- tox -e pep8
tags:
- lint
except:
- tags
test:lint:3.9:
stage: test
image: python:3.9
script:
- pip install tox
- tox -e pep8
tags:
- lint
except:
- tags
- rc
- demo
test:py3.6:
test:lint:3.10:
stage: test
image: python:3.10
script:
- pip install tox
- tox -e pep8
tags:
- lint
except:
- tags
- rc
- demo
test:py:3.6:
stage: test
image: python:3.6
script:
- pip install tox
- mkdir .reports
- tox -e py36
tags:
- docker
except:
- tags
- rc
- demo
artifacts:
reports:
junit: .reports/burpui.junit.xml
build:py2:
stage: build
image: python:2.7
test:py:3.7:
stage: test
image: python:3.7
script:
- /bin/bash tests/run_build.sh
- pip install tox
- mkdir .reports
- tox -e py37
tags:
- build
only:
- master@ziirish/burp-ui
- demo@ziirish/burp-ui
- docker
except:
- tags
- rc
- demo
artifacts:
paths:
- dist/
- meta/
expire_in: 2 mos
reports:
junit: .reports/burpui.junit.xml
test:py:3.8:
stage: test
image: python:3.8
script:
- pip install tox
- mkdir .reports
- tox -e py38
tags:
- docker
except:
- tags
artifacts:
reports:
junit: .reports/burpui.junit.xml
test:py:3.9:
stage: test
image: python:3.9
script:
- pip install tox
- mkdir .reports
- tox -e py39
tags:
- docker
except:
- tags
- rc
- demo
artifacts:
reports:
junit: .reports/burpui.junit.xml
test:py:3.10:
stage: test
image: python:3.10
script:
- pip install tox
- mkdir .reports
- tox -e py310
tags:
- docker
except:
- tags
- rc
- demo
artifacts:
reports:
junit: .reports/burpui.junit.xml
build:py3:
stage: build
image: python:3.6
image: python:3.8
script:
- /bin/bash tests/run_build.sh
- tests/build.sh
tags:
- build
only:
- master@ziirish/burp-ui
- demo@ziirish/burp-ui
- stable@ziirish/burp-ui
artifacts:
paths:
- dist/
......@@ -72,10 +190,10 @@ build:py3:
build:doc:
stage: build
image: python:3.6
image: python:3.8
script:
- pip install -U -r docs/requirements.txt
- make doc
- pip install -U .[rtd]
- cd docs && make html
tags:
- build
only:
......@@ -90,12 +208,12 @@ build:docker:latest:
stage: build
script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
- docker build --pull -t $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:latest -f docker/Dockerfile .
- (cd docker/demo/docker-pg && docker build --pull -t $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/pgsql:10 .)
- (cd docker/components/docker-burp && docker build --pull -t $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/burp:2.0.54 .)
- docker build --cache-from $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:latest --pull -t $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:latest -f docker/Dockerfile .
- (cd docker/demo/docker-pg && docker build --cache-from $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/pgsql:$PG_VERSION --pull -t $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/pgsql:$PG_VERSION .)
- (cd docker/components/docker-burp && docker build --cache-from $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/burp:$BURP_VERSION --pull -t $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/burp:$BURP_VERSION .)
- docker push $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:latest
- docker push $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/pgsql:10
- docker push $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/burp:2.0.54
- docker push $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/pgsql:$PG_VERSION
- docker push $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/burp:$BURP_VERSION
tags:
- registry
only:
......@@ -105,12 +223,12 @@ build:docker:release:
stage: build
script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
- docker build --pull -t $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:$CI_COMMIT_TAG -f docker/Dockerfile .
- (cd docker/demo/docker-pg && docker build --pull -t $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/pgsql:10 .)
- (cd docker/components/docker-burp && docker build --pull -t $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/burp:2.0.54 .)
- docker build --cache-from $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:latest --pull -t $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:$CI_COMMIT_TAG -f docker/Dockerfile .
- (cd docker/demo/docker-pg && docker build --cache-from $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/pgsql:$PG_VERSION --pull -t $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/pgsql:$PG_VERSION .)
- (cd docker/components/docker-burp && docker build --cache-from $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/burp:$BURP_VERSION --pull -t $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/burp:$BURP_VERSION .)
- docker push $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:$CI_COMMIT_TAG
- docker push $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/pgsql:10
- docker push $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/burp:2.0.54
- docker push $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/pgsql:$PG_VERSION
- docker push $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/burp:$BURP_VERSION
only:
- tags
tags:
......@@ -120,12 +238,12 @@ build:docker:stable:
stage: build
script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
- docker build --pull -t $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:stable -f docker/Dockerfile .
- (cd docker/demo/docker-pg && docker build --pull -t $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/pgsql:10 .)
- (cd docker/components/docker-burp && docker build --pull -t $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/burp:2.0.54 .)
- docker build --cache-from $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:latest --pull -t $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:stable -f docker/Dockerfile .
- (cd docker/demo/docker-pg && docker build --cache-from $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/pgsql:$PG_VERSION --pull -t $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/pgsql:$PG_VERSION .)
- (cd docker/components/docker-burp && docker build --cache-from $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/burp:$BURP_VERSION --pull -t $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/burp:$BURP_VERSION .)
- docker push $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:stable
- docker push $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/pgsql:10
- docker push $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/burp:2.0.54
- docker push $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/pgsql:$PG_VERSION
- docker push $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/burp:$BURP_VERSION
only:
- stable@ziirish/burp-ui
tags:
......@@ -137,6 +255,7 @@ build:docker:demo:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
- docker build --pull -t $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:demo -f docker/Dockerfile .
- docker push $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:demo
- apk add --no-cache curl
- "curl $SENTRY_WEBHOOK -X POST -H 'Content-Type: application/json' -d '{\"version\": \"'$CI_COMMIT_REF_NAME'_'$CI_COMMIT_SHA'\"}'"
only:
- demo@ziirish/burp-ui
......@@ -148,12 +267,11 @@ deploy:demo:
script:
- find docker/demo/ -name "install" -o -name "init" | xargs sed -i "s/@build@/$CI_COMMIT_SHA/"
- cd docker/demo/ && find . -maxdepth 1 -type d -a ! -name dist -exec cp -r ../../dist "{}/" \; -exec cp -r ../../meta "{}/" \; && cd ../..
- find docker/demo/ -name "Dockerfile" | xargs sed -i "s,^.*@ARTIFACTS@.*$,COPY dist/*.tar.gz /tmp/burpui.dev.tar.gz,;s,^.*@BUIAGENT_ARTIFACTS@.*$,COPY meta/burp-ui-agent*.tar.gz /tmp/burp-ui-agent.dev.tar.gz,"
- find docker/demo/ -name "Dockerfile" | xargs sed -i "s,^.*@ARTIFACTS@.*$,COPY dist/*.tar.gz /tmp/burpui.dev.tar.gz,;s,^.*@BUIAGENT_ARTIFACTS@.*$,COPY meta/burp-ui-agent*.tar.gz /tmp/burp-ui-agent.dev.tar.gz,;s,^.*@BUIMONITOR_ARTIFACTS@.*$,COPY meta/burp-ui-monitor*.tar.gz /tmp/burp-ui-monitor.dev.tar.gz,"
- test -d /srv/demo/docker && rm -rf /srv/demo/docker
- cp -r docker/demo/ /srv/demo/docker
- cd /srv/demo/docker/
# old docker client, we need the "-e" flag
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN -e $DUMMY_EMAIL $CI_REGISTRY
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
- docker-compose build --pull
- docker-compose stop
- docker-compose rm -f
......@@ -165,3 +283,5 @@ deploy:demo:
environment:
name: demo
url: https://demo.burp-ui.org/
variables:
DOCKER_HOST: unix:///var/run/docker.sock
......@@ -47,8 +47,8 @@ burp-2.1.18
```
$ bui-manage sysinfo
Python version: 3.6.1
Burp-UI version: 0.5.0 (stable)
Python version: 3.6.5
Burp-UI version: 0.6.1 (stable)
Single mode: True
Backend version: 2
WebSocket embedded: False
......
# https://docs.readthedocs.io/en/latest/yaml-config.html
version: 2
build:
image: latest
python:
version: 3.7
install:
- method: pip
path: .
extra_requirements:
- rtd
Changelog
=========
Current
-------
- **BREAKING**: the *single* and *version* options within the ``[Global]`` section have been removed in favor of a new unified *backend* option
- **BREAKING**: a change introduced by `#284 <https://git.ziirish.me/ziirish/burp-ui/issues/284>`_ may return wrong timestamps for backups made with burp-server <= 2.1.10 if your current burp-server is >= 2.1.10
- **BREAKING**: the authentication backends section have been renamed with the ``:AUTH`` suffix
- **BREAKING**: the ``prefix`` option has been moved from the ``[Global]`` configuration section to the ``[Production]`` one
- Add: new `audit logging <https://git.ziirish.me/ziirish/burp-ui/issues/260>`_ system
- Add: new ``bui-monitor`` processes pool + ``async`` backend to parallelize some requests `#278 <https://git.ziirish.me/ziirish/burp-ui/issues/278>`_
- Add: new `listen` and `listen_status` options in burp-2.2.10 `#279 <https://git.ziirish.me/ziirish/burp-ui/issues/279>`_
- Add: new `order` keyword in ACL definitions in order to decide whether `rw` should be evaluated first or not `#305 <https://git.ziirish.me/ziirish/burp-ui/issues/305>`__
- Add: new `exclude` keyword in ACL definitions in order to exclude some clients from the rules `#305 <https://git.ziirish.me/ziirish/burp-ui/issues/305>`__
- Add: new *static templates* that allow you to create *onetime* (variables) templates `#280 <https://git.ziirish.me/ziirish/burp-ui/issues/280>`_
- Add: return last backup attempt `#309 <https://git.ziirish.me/ziirish/burp-ui/issues/309>`_
- Add: allow to hide selected clients/servers `#282 <https://git.ziirish.me/ziirish/burp-ui/issues/282>`_
- Add: allow to delete clients data upon removal `#232 <https://git.ziirish.me/ziirish/burp-ui/issues/232>`_
- Add: allow to create clients from templates in one call `#266 <https://git.ziirish.me/ziirish/burp-ui/issues/266>`_
- Add: allow to rename clients/templates `#274 <https://git.ziirish.me/ziirish/burp-ui/issues/274>`_
- Add: allow to set a custom timezone in which to display UI dates `#329 <https://git.ziirish.me/ziirish/burp-ui/issues/329>`_
- Fix: sync pkgs requirements with burp-ui's `#300 <https://git.ziirish.me/ziirish/burp-ui/issues/300>`__
- Fix: wrong command suggestion `#296 <https://git.ziirish.me/ziirish/burp-ui/issues/296>`__
- Fix: allow templates removal `#290 <https://git.ziirish.me/ziirish/burp-ui/issues/290>`__
- Fix: don't preload LDAP users `#270 <https://git.ziirish.me/ziirish/burp-ui/issues/270>`__
- Fix: don't screw up configuration files `#333 <https://git.ziirish.me/ziirish/burp-ui/issues/333>`__
- Fix: issue `#268 <https://git.ziirish.me/ziirish/burp-ui/issues/268>`_
- `Full changelog <https://git.ziirish.me/ziirish/burp-ui/compare/0.6.0...master>`__
0.6.6 (04/02/2019)
------------------
- Fix: python 3.7 compatibility `#304 <https://git.ziirish.me/ziirish/burp-ui/issues/304>`__
- Fix: agent cannot start `#302 <https://git.ziirish.me/ziirish/burp-ui/issues/302>`__
0.6.5 (03/27/2019)
------------------
- Fix: packaging issue
0.6.4 (03/26/2019)
------------------
- Fix: sync pkgs requirements with burp-ui's `#300 <https://git.ziirish.me/ziirish/burp-ui/issues/300>`__
0.6.3 (03/13/2019)
------------------
- Fix: don't preload LDAP users `#270 <https://git.ziirish.me/ziirish/burp-ui/issues/270>`__
0.6.2 (03/05/2019)
------------------
- Fix: wrong command suggestion `#296 <https://git.ziirish.me/ziirish/burp-ui/issues/296>`__
- Fix: allow templates removal `#290 <https://git.ziirish.me/ziirish/burp-ui/issues/290>`__
- Fix: support burp-2.2.16 `#291 <https://git.ziirish.me/ziirish/burp-ui/issues/291>`_
- Fix: issue `#268 <https://git.ziirish.me/ziirish/burp-ui/issues/268>`_
0.6.1 (05/17/2018)
------------------
- Improvement: Don't cache any data when there is a running backup
- Fix: cannot display bui-agent version
- Fix: live-monitor was broken do to a missing cache
- `Full changelog <https://git.ziirish.me/ziirish/burp-ui/compare/0.6.0...0.6.1>`__
0.6.0 (05/14/2018)
------------------
......
......@@ -12,5 +12,6 @@ Graham Keeling (main author of Burp)
larsen0815
Johannes Lerch
slarti5191
Lukas Schreiner
Robert Tichy
Benjamin `ziirish` SANS (main author)
......@@ -7,6 +7,7 @@ include burpui/VERSION
include burpui/RELEASE
include requirements.txt
include share/burpui/etc/burpui.sample.cfg
include share/burpui/etc/buimonitor.sample.cfg
include babel.cfg
graft contrib
graft burpui
......
.PHONY: all test clean_coverage doc doc_coverage clean pep8 pyflakes check
all:
@echo 'test run the unit tests'
@echo 'flake8 check pep8 compliance'
@echo 'check make sure you are ready to commit'
@echo 'clean cleanup the source tree'
doc_coverage:
@echo 'Running docstring coverage...'
@docstring-coverage burpui
test: clean_coverage
@echo 'Running all tests...'
@nosetests --with-coverage --cover-package=burpui test/test_burpui.py
doc:
@echo 'Generating documentation...'
@cd docs && make html
clean:
@find . -type d -name "__pycache__" -exec rm -rf "{}" \; || true
@find . -type f -name "*.pyc" -delete || true
@rm -rf build dist burp_ui.egg-info docs/_build || true
@cd docs && make clean
clean_coverage:
@rm -f .coverage
flake8:
@echo 'Checking pep8 compliance and errors...'
@flake8 --ignore=E501,E722 burpui
check: pep8 pyflakes doc_coverage test
Burp-UI
=======
.. image:: https://git.ziirish.me/ziirish/burp-ui/badges/stable/build.svg
.. image:: https://git.ziirish.me/ziirish/burp-ui/badges/master/pipeline.svg
:target: https://git.ziirish.me/ziirish/burp-ui/pipelines
:alt: Build Status
.. image:: https://git.ziirish.me/ziirish/burp-ui/badges/stable/coverage.svg
.. image:: https://git.ziirish.me/ziirish/burp-ui/badges/master/coverage.svg
:target: https://git.ziirish.me/ziirish/burp-ui/pipelines
:alt: Test coverage
.. image:: https://readthedocs.org/projects/burp-ui/badge/?version=stable
:target: https://readthedocs.org/projects/burp-ui/?badge=stable
.. image:: https://readthedocs.org/projects/burp-ui/badge/?version=latest
:target: https://readthedocs.org/projects/burp-ui/?badge=latest
:alt: Documentation Status
.. contents::
......@@ -21,8 +21,8 @@ Introduction
Screenshots
^^^^^^^^^^^
.. image:: https://git.ziirish.me/ziirish/burp-ui/raw/stable/docs/_static/burp-ui.gif
:target: https://git.ziirish.me/ziirish/burp-ui/blob/stable/docs/_static/burp-ui.gif
.. image:: https://git.ziirish.me/ziirish/burp-ui/raw/master/docs/_static/burp-ui.gif
:target: https://git.ziirish.me/ziirish/burp-ui/blob/master/docs/_static/burp-ui.gif
Demo
^^^^
......@@ -84,6 +84,8 @@ I have closed the *github tracker* to have a unique tracker system.
Also please, read the `Contributing`_ page before reporting any issue to make
sure we have all the informations to help you.
Bug report that don't comply with the rules will likely be **ignored** because
my spare time is quite limited.
See also
--------
......@@ -143,7 +145,7 @@ would not exist without `Burp`_.
.. _Flask: http://flask.pocoo.org/
.. _License: https://git.ziirish.me/ziirish/burp-ui/blob/master/LICENSE
.. _Burp: http://burp.grke.org/
.. _burpui.cfg: https://git.ziirish.me/ziirish/burp-ui/blob/stable/share/burpui/etc/burpui.sample.cfg
.. _burp-ui.readthedocs.io: https://burp-ui.readthedocs.io/en/stable/
.. _FAQ: https://burp-ui.readthedocs.io/en/stable/faq.html
.. _Contributing: https://burp-ui.readthedocs.io/en/stable/contributing.html
.. _burpui.cfg: https://git.ziirish.me/ziirish/burp-ui/blob/master/share/burpui/etc/burpui.sample.cfg
.. _burp-ui.readthedocs.io: https://burp-ui.readthedocs.io/en/latest/
.. _FAQ: https://burp-ui.readthedocs.io/en/latest/faq.html
.. _Contributing: https://burp-ui.readthedocs.io/en/latest/contributing.html
......@@ -9,17 +9,12 @@ jQuery/Bootstrap
.. moduleauthor:: Ziirish <hi+burpui@ziirish.me>
"""
import sys
import warnings
from .app import init
from .app import create_app
warnings.simplefilter('always', RuntimeWarning)
if sys.version_info < (3, 0): # pragma: no cover
reload(sys)
sys.setdefaultencoding('utf-8')
warnings.simplefilter("always", RuntimeWarning)
# backward compatibility
create_app = init
init = create_app
......@@ -17,34 +17,73 @@ from argparse import ArgumentParser, REMAINDER
ROOT = os.path.dirname(os.path.realpath(__file__))
# Try to load modules from our current env first
sys.path.insert(0, os.path.join(ROOT, '..'))
sys.path.insert(0, os.path.join(ROOT, ".."))
def parse_args(mode=True, name=None):
mname = name
if not name:
mname = 'burp-ui'
mname = "burp-ui"
parser = ArgumentParser(prog=mname)
parser.add_argument('-v', '--verbose', dest='log', help='increase output verbosity (e.g., -vv is more verbose than -v)', action='count')
parser.add_argument('-d', '--debug', dest='debug', help='enable debug mode', action='store_true')
parser.add_argument('-V', '--version', dest='version', help='print version and exit', action='store_true')
parser.add_argument('-c', '--config', dest='config', help='burp-ui configuration file', metavar='<CONFIG>')
parser.add_argument('-l', '--logfile', dest='logfile', help='output logs in defined file', metavar='<FILE>')
parser.add_argument('-i', '--migrations', dest='migrations', help='migrations directory', metavar='<MIGRATIONSDIR>')
parser.add_argument('remaining', nargs=REMAINDER)
parser.add_argument(
"-v",
"--verbose",
dest="log",
help="increase output verbosity (e.g., -vv is more verbose than -v)",
action="count",
)
parser.add_argument(
"-d", "--debug", dest="debug", help="enable debug mode", action="store_true"
)
parser.add_argument(
"-V",
"--version",
dest="version",
help="print version and exit",
action="store_true",
)
parser.add_argument(
"-c",
"--config",
dest="config",
help="burp-ui configuration file",
metavar="<CONFIG>",
)
parser.add_argument(
"-l",
"--logfile",
dest="logfile",
help="output logs in defined file",
metavar="<FILE>",
)
parser.add_argument(
"-i",
"--migrations",
dest="migrations",
help="migrations directory",
metavar="<MIGRATIONSDIR>",
)
parser.add_argument("remaining", nargs=REMAINDER)
if mode:
parser.add_argument('-m', '--mode', dest='mode', help='application mode', metavar='<agent|server|celery|manage|legacy>')
parser.add_argument(
"-m",
"--mode",
dest="mode",
help="application mode",
metavar="<agent|server|celery|manage|monitor|legacy>",
)
options, unknown = parser.parse_known_args()
if mode and options.mode and options.mode not in ['celery', 'manage', 'server']:
if mode and options.mode and options.mode not in ["celery", "manage", "server"]:
options = parser.parse_args()
unknown = []
if options.version:
from burpui.desc import __title__, __version__, __release__
ver = '{}: v{}'.format(mname or __title__, __version__)
ver = "{}: v{}".format(mname or __title__, __version__)
if options.log:
ver = '{} ({})'.format(ver, __release__)
ver = "{} ({})".format(ver, __release__)
print(ver)
sys.exit(0)
......@@ -57,18 +96,20 @@ def main():
"""
options, unknown = parse_args(mode=True)
if not options.mode or options.mode == 'server':
if not options.mode or options.mode == "server":
server(options, unknown)
elif options.mode == 'agent':
elif options.mode == "agent":
agent(options)
elif options.mode == 'celery':
elif options.mode == "celery":
celery()
elif options.mode == 'manage':
elif options.mode == "manage":
manage()
elif options.mode == 'legacy':
elif options.mode == "monitor":
monitor(options)
elif options.mode == "legacy":
legacy(options, unknown)
else:
print('Wrong mode!')
print("Wrong mode!")
sys.exit(1)
......@@ -84,66 +125,92 @@ def server(options=None, unknown=None):
if options.config:
conf = lookup_file(options.config, guess=False)
else:
if 'BUI_CONFIG' in env:
conf = env['BUI_CONFIG']
if "BUI_CONFIG" in env:
conf = env["BUI_CONFIG"]
else:
conf = lookup_file()
check_config(conf)
if os.path.isdir('burpui'):
env['FLASK_APP'] = 'burpui/cli.py'
if os.path.isdir("burpui"):
env["FLASK_APP"] = "burpui/cli.py"
else:
env['FLASK_APP'] = 'burpui.cli'
env['BUI_CONFIG'] = conf
env['BUI_VERBOSE'] = str(options.log)
env["FLASK_APP"] = "burpui.cli"
env["BUI_CONFIG"] = conf
env["BUI_VERBOSE"] = str(options.log)
if options.logfile:
env['BUI_LOGFILE'] = options.logfile
env["BUI_LOGFILE"] = options.logfile
if options.debug:
env['BUI_DEBUG'] = '1'
env['FLASK_DEBUG'] = '1'
env['BUI_MODE'] = 'server'
args = [
'flask',
'run'
]
env["BUI_DEBUG"] = "1"
env["FLASK_DEBUG"] = "1"
env["BUI_MODE"] = "server"
args = ["flask", "run"]
args += unknown
args += [x for x in options.remaining if x != '--']
args += [x for x in options.remaining if x != "--"]
os.execvpe(args[0], args, env)
def agent(options=None):
from gevent import monkey
from burpui.agent import BUIAgent as Agent
import trio
from burpui.engines.agent import BUIAgent as Agent
from burpui.utils import lookup_file
from burpui._compat import patch_json
monkey.patch_all()
patch_json()
if not options:
options, _ = parse_args(mode=False, name="bui-agent")
conf = ["buiagent.cfg", "buiagent.sample.cfg"]
if options.config:
conf = lookup_file(options.config, guess=False)
else:
conf = lookup_file(conf)
check_config(conf)
agent = Agent(conf, options.log, options.logfile)
trio.run(agent.run)
def monitor(options=None):
import trio
from burpui.engines.monitor import MonitorPool
from burpui.utils import lookup_file
if not options:
options, _ = parse_args(mode=False, name='bui-agent')
options, _ = parse_args(mode=False, name="bui-agent")
conf = ['buiagent.cfg', 'buiagent.sample.cfg']
conf = ["buimonitor.cfg", "buimonitor.sample.cfg"]
if options.config:
conf = lookup_file(options.config, guess=False)
else:
conf = lookup_file(conf)
check_config(conf)
agent = Agent(conf, options.log, options.logfile, options.debug)
agent.run()
monitor = MonitorPool(conf, options.log, options.logfile)
trio.run(monitor.run)
def celery():
from burpui.utils import lookup_file
parser = ArgumentParser('bui-celery')
parser.add_argument('-c', '--config', dest='config', help='burp-ui configuration file', metavar='<CONFIG>')
parser.add_argument('-t', '--type', dest='type', help='celery mode', metavar='<worker|beat|flower>')
parser.add_argument('-m', '--mode', dest='mode', help='application mode', metavar='<agent|server|worker|manage|legacy>')
parser.add_argument('remaining', nargs=REMAINDER)
parser = ArgumentParser("bui-celery")
parser.add_argument(
"-c",
"--config",
dest="config",
help="burp-ui configuration file",
metavar="<CONFIG>",
)
parser.add_argument(
"-t", "--type", dest="type", help="celery mode", metavar="<worker|beat|flower>"
)
parser.add_argument(
"-m",
"--mode",
dest="mode",
help="application mode",
metavar="<agent|server|worker|manage|legacy>",
)
parser.add_argument("remaining", nargs=REMAINDER)
options, unknown = parser.parse_known_args()
env = os.environ
......@@ -151,18 +218,18 @@ def celery():
if options.config:
conf = lookup_file(options.config, guess=False)
else:
if 'BUI_CONFIG' in env:
conf = env['BUI_CONFIG']
if "BUI_CONFIG" in env:
conf = env["BUI_CONFIG"]
else:
conf = lookup_file()
if options.type:
celery_mode = options.type
else:
celery_mode = 'worker'
celery_mode = "worker"
# make conf path absolute
if not conf.startswith('/'):
if not conf.startswith("/"):
curr = os.getcwd()
conf = os.path.join(curr, conf)
......@@ -170,17 +237,12 @@ def celery():
os.chdir(ROOT)
env['BUI_MODE'] = 'celery'
env['BUI_CONFIG'] = conf
env["BUI_MODE"] = "celery"
env["BUI_CONFIG"] = conf
args = [
'celery',
celery_mode,
'-A',
'worker.celery'
]
args = ["celery", "-A", "engines.worker.celery", celery_mode]
args += unknown
args += [x for x in options.remaining if x != '--']
args += [x for x in options.remaining if x != "--"]
os.execvpe(args[0], args, env)
......@@ -188,48 +250,78 @@ def celery():
def manage():
from burpui.utils import lookup_file
parser = ArgumentParser('bui-manage')
parser.add_argument('-v', '--verbose', dest='log', help='increase output verbosity (e.g., -vv is more verbose than -v)', action='count')
parser.add_argument('-c', '--config', dest='config', help='burp-ui configuration file', metavar='<CONFIG>')
parser.add_argument('-i', '--migrations', dest='migrations', help='migrations directory', metavar='<MIGRATIONSDIR>')
parser.add_argument('-m', '--mode', dest='mode', help='application mode', metavar='<agent|server|worker|manage|legacy>')
parser.add_argument('-l', '--logfile', dest='logfile', help='output logs in defined file', metavar='<FILE>')
parser.add_argument('remaining', nargs=REMAINDER)
parser = ArgumentParser("bui-manage")
parser.add_argument(
"-v",
"--verbose",
dest="log",
help="increase output verbosity (e.g., -vv is more verbose than -v)",
action="count",
)
parser.add_argument(
"-c",
"--config",
dest="config",
help="burp-ui configuration file",
metavar="<CONFIG>",
)
parser.add_argument(
"-i",
"--migrations",
dest="migrations",
help="migrations directory",
metavar="<MIGRATIONSDIR>",
)
parser.add_argument(
"-m",
"--mode",
dest="mode",
help="application mode",
metavar="<agent|server|worker|manage|legacy>",
)
parser.add_argument(
"-l",
"--logfile",
dest="logfile",
help="output logs in defined file",
metavar="<FILE>",
)
parser.add_argument("remaining", nargs=REMAINDER)
options, unknown = parser.parse_known_args()
env = os.environ
if options.logfile:
env['BUI_LOGFILE'] = options.logfile
env["BUI_LOGFILE"] = options.logfile
if options.config:
conf = lookup_file(options.config, guess=False)
else:
if 'BUI_CONFIG' in env:
conf = env['BUI_CONFIG']
if "BUI_CONFIG" in env:
conf = env["BUI_CONFIG"]
else:
conf = lookup_file()
check_config(conf)
if options.migrations:
migrations = lookup_file(options.migrations, guess=False, directory=True, check=False)
migrations = lookup_file(
options.migrations, guess=False, directory=True, check=False
)
else:
migrations = lookup_file('migrations', directory=True)
migrations = lookup_file("migrations", directory=True)
env['BUI_MODE'] = 'manage'
env['BUI_CONFIG'] = conf
env['BUI_VERBOSE'] = str(options.log)
env["BUI_MODE"] = "manage"
env["BUI_CONFIG"] = conf
env["BUI_VERBOSE"] = str(options.log)
if migrations:
env['BUI_MIGRATIONS'] = migrations
if os.path.isdir('burpui') and os.path.isfile('burpui/cli.py'):
env['FLASK_APP'] = 'burpui/cli.py'
env["BUI_MIGRATIONS"] = migrations
if os.path.isdir("burpui") and os.path.isfile("burpui/cli.py"):
env["FLASK_APP"] = "burpui/cli.py"
else:
env['FLASK_APP'] = 'burpui.cli'
env["FLASK_APP"] = "burpui.cli"
args = [
'flask'
]
args = ["flask"]
args += unknown
args += [x for x in options.remaining if x != '--']
args += [x for x in options.remaining if x != "--"]
os.execvpe(args[0], args, env)
......@@ -240,47 +332,44 @@ def legacy(options=None, unknown=None):
if unknown is None:
unknown = []
if not options:
options, unknown = parse_args(mode=False, name='burpui-legacy')
options, unknown = parse_args(mode=False, name="burpui-legacy")
env = os.environ
if options.config:
conf = lookup_file(options.config, guess=False)
else:
if 'BUI_CONFIG' in env:
conf = env['BUI_CONFIG']
if "BUI_CONFIG" in env:
conf = env["BUI_CONFIG"]
else:
conf = lookup_file()
check_config(conf)
env['BUI_MODE'] = 'legacy'
env['BUI_CONFIG'] = conf
if os.path.isdir('burpui'):
env['FLASK_APP'] = 'burpui/cli.py'
env["BUI_MODE"] = "legacy"
env["BUI_CONFIG"] = conf
if os.path.isdir("burpui"):
env["FLASK_APP"] = "burpui/cli.py"
else:
env['FLASK_APP'] = 'burpui.cli'
env['BUI_VERBOSE'] = str(options.log)
env["FLASK_APP"] = "burpui.cli"
env["BUI_VERBOSE"] = str(options.log)
if options.logfile:
env['BUI_LOGFILE'] = options.logfile
env["BUI_LOGFILE"] = options.logfile
if options.debug:
env['BUI_DEBUG'] = '1'
env['FLASK_DEBUG'] = '1'
env["BUI_DEBUG"] = "1"
env["FLASK_DEBUG"] = "1"
args = [
'flask',
'legacy'
]
args = ["flask", "legacy"]
args += unknown
args += [x for x in options.remaining if x != '--']
args += [x for x in options.remaining if x != "--"]
os.execvpe(args[0], args, env)
def check_config(conf):
if not conf:
raise IOError('No configuration file found')
raise IOError("No configuration file found")
if not os.path.isfile(conf):
raise IOError('File does not exist: \'{0}\''.format(conf))
raise IOError("File does not exist: '{0}'".format(conf))
if __name__ == '__main__':
if __name__ == "__main__":
main()
......@@ -7,72 +7,26 @@
.. moduleauthor:: Ziirish <hi+burpui@ziirish.me>
"""
import re
import sys
import pickle # noqa
try:
import cPickle as pickle # noqa
except ImportError:
import pickle # noqa
from urllib.parse import unquote, quote, urlparse, urljoin # noqa
if sys.version_info[0] >= 3:
PY3 = True
from urllib.parse import unquote, quote, urlparse, urljoin # noqa
text_type = str
string_types = (str,)
def iterkeys(d, *args, **kwargs):
return iter(d.keys(*args, **kwargs))
def itervalues(d, *args, **kwargs):
return iter(d.values(*args, **kwargs))
def iteritems(d, *args, **kwargs):
return iter(d.items(*args, **kwargs))
def iterlists(d, *args, **kwargs):
return iter(d.lists(*args, **kwargs))
def iterlistvalues(d, *args, **kwargs):
return iter(d.listvalues(*args, **kwargs))
else:
PY3 = False
from urllib import unquote, quote # noqa
from urlparse import urlparse, urljoin # noqa
text_type = unicode
string_types = (str, unicode)
def iterkeys(d, *args, **kwargs):
return d.iterkeys(*args, **kwargs)
def itervalues(d, *args, **kwargs):
return d.itervalues(*args, **kwargs)
def iteritems(d, *args, **kwargs):
return d.iteritems(*args, **kwargs)
def iterlists(d, *args, **kwargs):
return d.iterlists(*args, **kwargs)
def iterlistvalues(d, *args, **kwargs):
return d.iterlistvalues(*args, **kwargs)
text_type = str
string_types = (str,)
def to_bytes(text):
"""Transform string to bytes."""
if isinstance(text, text_type):
text = text.encode('utf-8')
return text or b''
text = text.encode("utf-8")
return text or b""
def to_unicode(input_bytes, encoding='utf-8'):
def to_unicode(input_bytes, encoding="utf-8"):
"""Decodes input_bytes to text if needed."""
if not isinstance(input_bytes, string_types):
input_bytes = input_bytes.decode(encoding)
elif re.match(r'\\u[0-9a-f]{4}', input_bytes):
input_bytes = input_bytes.decode('unicode-escape')
return input_bytes or u''
return input_bytes or ""
# maps module name -> attribute name -> original item
......@@ -86,24 +40,24 @@ def patch_item(module, attr, newitem, newmodule=None):
olditem = getattr(module, attr, NONE)
if olditem is not NONE:
saved.setdefault(module.__name__, {}).setdefault(attr, olditem)
if newmodule and not getattr(newmodule, 'ori_' + attr, None):
setattr(newmodule, 'ori_' + attr, olditem)
if not getattr(newmodule, 'ori_' + attr, None):
if newmodule and not getattr(newmodule, "ori_" + attr, None):
setattr(newmodule, "ori_" + attr, olditem)
if not getattr(newmodule, "ori_" + attr, None):
setattr(module, attr, newitem)
def patch_module(name, items=None):
toimport = items or []
mod = __name__
if '.' in mod:
mod = mod.split('.')[0]
replace_module = __import__('{}._{}'.format(mod, name), fromlist=toimport)
if "." in mod:
mod = mod.split(".")[0]
replace_module = __import__("{}._{}".format(mod, name), fromlist=toimport)
module_name = name
module = __import__(module_name)
if items is None:
items = getattr(replace_module, '__implements__', None)
items = getattr(replace_module, "__implements__", None)
if items is None:
raise AttributeError('%r does not have __implements__' % replace_module)
raise AttributeError("%r does not have __implements__" % replace_module)
for attr in items:
patch_item(module, attr, getattr(replace_module, attr), replace_module)
......@@ -114,4 +68,4 @@ def patch_json():
except ImportError:
# ujson is not available, we won't patch anything
return
patch_module('json', ['dumps', 'loads'])
patch_module("json", ["dumps", "loads"])
......@@ -8,20 +8,19 @@
"""
import ujson
from six import viewkeys
__implements__ = ['dumps', 'loads']
__implements__ = ["dumps", "loads"]
ori_dumps = None
ori_loads = None
IMPLEMENTED_DUMPS_KWARGS = [
'ensure_ascii',
'double_precision',
'encode_html_chars',
'sort_keys',
"ensure_ascii",
"double_precision",
"encode_html_chars",
"sort_keys",
]
IMPLEMENTED_LOADS_KWARGS = [
'precise_float',
"precise_float",
]
......@@ -30,7 +29,7 @@ IMPLEMENTED_LOADS_KWARGS = [
def dumps(*args, **kwargs):
keys = []
if kwargs:
keys = viewkeys(kwargs)
keys = kwargs.keys()
for key in keys:
if key not in IMPLEMENTED_DUMPS_KWARGS:
return ori_dumps(*args, **kwargs)
......@@ -43,7 +42,7 @@ def dumps(*args, **kwargs):
def loads(*args, **kwargs):
keys = []
if kwargs:
keys = viewkeys(kwargs)
keys = kwargs.keys()
for key in keys:
if key not in IMPLEMENTED_LOADS_KWARGS:
return ori_loads(*args, **kwargs)
......
......@@ -14,4 +14,4 @@ from . import create_app
# This is a lie we are not really unittesting, but we want to avoid the v2
# errors
app = create_app(conf='/dev/null', gunicorn=False, unittest=True)
app = create_app(conf="/dev/null", gunicorn=False, unittest=True)
# -*- coding: utf8 -*-
"""
.. module:: burpui.agent
:platform: Unix
:synopsis: Burp-UI agent module.
.. moduleauthor:: Ziirish <hi+burpui@ziirish.me>
"""
import os
import struct
import re
import time
import sys
import json
import logging
import traceback
from gevent.lock import RLock
from gevent.pool import Pool
from gevent.server import StreamServer
from logging.handlers import RotatingFileHandler
from .exceptions import BUIserverException
from .misc.backend.interface import BUIbackend
from ._compat import pickle, to_bytes, to_unicode
from .utils import BUIlogging
from .config import config
from .desc import __version__
try:
from sendfile import sendfile
USE_SENDFILE = True
except ImportError:
USE_SENDFILE = False
G_PORT = 10000
G_BIND = u'::'
G_SSL = False
G_VERSION = 2
G_SSLCERT = u''
G_SSLKEY = u''
G_PASSWORD = u'password'
DISCLOSURE = 5
lock = RLock()
class BurpHandler(BUIbackend):
# These functions MUST be implemented because we inherit an abstract class.
# The hack here is to get the list of the functions and let the interpreter
# think we don't have to implement them.
# Thanks to this list, we know what function are implemented by our backend.
foreign = BUIbackend.__abstractmethods__
BUIbackend.__abstractmethods__ = frozenset()
def __init__(self, vers=2, logger=None, conf=None):
self.vers = vers
self.logger = logger
top = __name__
if '.' in top:
top = top.split('.')[0]
module = '{0}.misc.backend.burp{1}'.format(top, self.vers)
try:
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
mod = __import__(module, fromlist=['Burp'])
Client = mod.Burp
self.backend = Client(conf=conf)
except Exception as e:
self.logger.error('{}\n\nFailed loading backend for Burp version {}: {}'.format(traceback.format_exc(), self.vers, str(e)))
sys.exit(2)
def __getattribute__(self, name):
# always return this value because we need it and if we don't do that
# we'll end up with an infinite loop
if name == 'foreign' or name == 'backend':
return object.__getattribute__(self, name)
# now we can retrieve the 'foreign' list and know if the object called
# is in the backend
if name in self.foreign:
return getattr(self.backend, name)
try:
return getattr(self.backend, name)
except AttributeError:
pass
return object.__getattribute__(self, name)
class BUIAgent(BUIbackend, BUIlogging):
BUIbackend.__abstractmethods__ = frozenset()
defaults = {
'Global': {
'port': G_PORT,
'bind': G_BIND,
'ssl': G_SSL,
'sslcert': G_SSLCERT,
'sslkey': G_SSLKEY,
'version': G_VERSION,
'password': G_PASSWORD,
},
}
def __init__(self, conf=None, level=0, logfile=None, debug=False):
self.debug = debug
self.padding = 1
level = level or 0
if level > logging.NOTSET:
logging.addLevelName(DISCLOSURE, 'DISCLOSURE')
levels = [
logging.CRITICAL,
logging.ERROR,
logging.WARNING,
logging.INFO,
logging.DEBUG,
DISCLOSURE
]
if level >= len(levels):
level = len(levels) - 1
lvl = levels[level]
self.logger.setLevel(lvl)
if lvl > logging.DEBUG:
LOG_FORMAT = '[%(asctime)s] %(levelname)s in %(module)s.%(funcName)s: %(message)s'
else:
LOG_FORMAT = (
'-' * 80 + '\n' +
'%(levelname)s in %(module)s.%(funcName)s [%(pathname)s:%(lineno)d]:\n' +
'%(message)s\n' +
'-' * 80
)
if logfile:
handler = RotatingFileHandler(logfile, maxBytes=1024 * 1024 * 100, backupCount=20)
else:
handler = logging.StreamHandler()
handler.setLevel(lvl)
handler.setFormatter(logging.Formatter(LOG_FORMAT))
self.logger.addHandler(handler)
self._logger('info', 'conf: ' + conf)
self._logger('info', 'level: ' + logging.getLevelName(lvl))
if not conf:
raise IOError('No configuration file found')
# Raise exception if errors are encountered during parsing
self.conf = config
self.conf.parse(conf, True, self.defaults)
self.conf.default_section('Global')
self.port = self.conf.safe_get('port', 'integer')
self.bind = self.conf.safe_get('bind')
self.vers = self.conf.safe_get('version', 'integer')
self.ssl = self.conf.safe_get('ssl', 'boolean')
self.sslcert = self.conf.safe_get('sslcert')
self.sslkey = self.conf.safe_get('sslkey')
self.password = self.conf.safe_get('password')
self.conf.setdefault('BUI_AGENT', True)
self.client = BurpHandler(self.vers, self.logger, self.conf)
pool = Pool(10000)
if not self.ssl:
self.server = StreamServer((self.bind, self.port), self.handle, spawn=pool)
else:
self.server = StreamServer((self.bind, self.port), self.handle, keyfile=self.sslkey, certfile=self.sslcert, spawn=pool)
def run(self):
try:
self.server.serve_forever()
except KeyboardInterrupt:
sys.exit(0)
def handle(self, request, address):
"""self.request is the client connection"""
with lock:
try:
self.request = request
err = None
res = ''
lengthbuf = self.request.recv(8)
if not lengthbuf:
return
length, = struct.unpack('!Q', lengthbuf)
data = self.recvall(length)
self._logger('info', 'recv: {}'.format(data))
txt = to_unicode(data)
self._logger('info', 'recv2: {}'.format(txt))
if txt == 'RE':
return
j = json.loads(txt)
if j['password'] != self.password:
self._logger('warning', '-----> Wrong Password <-----')
self.request.sendall(b'KO')
return
try:
if j['func'] == 'proxy_parser':
parser = self.client.get_parser()
if j['args']:
res = json.dumps(getattr(parser, j['method'])(**j['args']))
else:
res = json.dumps(getattr(parser, j['method'])())
elif j['func'] == 'agent_version':
res = json.dumps(__version__)
elif j['func'] == 'restore_files':
res, err = getattr(self.client, j['func'])(**j['args'])
if err:
self.request.sendall(b'ER')
self.request.sendall(struct.pack('!Q', len(err)))
self.request.sendall(to_bytes(err))
self._logger('error', 'Restoration failed')
return
elif j['func'] == 'get_file':
path = j['path']