refactoring + documentation

This commit is contained in:
ziirish 2016-05-27 16:57:19 +02:00
parent 4db03d82d9
commit b5f7873875
6 changed files with 247 additions and 138 deletions

View file

@ -249,7 +249,7 @@ def init(conf=None, verbose=0, logfile=None, gunicorn=True, unittest=False, debu
red = Redis(host=host, port=port)
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = red
app.config['SESSION_USE_SIGNER'] = app.secret_key != None
app.config['SESSION_USE_SIGNER'] = app.secret_key is not None
app.config['SESSION_PERMANENT'] = False
ses = Session()
ses.init_app(app)

View file

@ -12,13 +12,14 @@ import os
import sys
from flask import Blueprint, Response, request
from flask_restplus import Api
from flask_restplus import Api as ApiPlus
from flask_login import current_user
from flask_cache import Cache
from importlib import import_module
from functools import wraps
from .._compat import IS_GUNICORN, PY3
from ..exceptions import BUIserverException
if PY3: # pragma: no cover
basestring = str
@ -125,7 +126,7 @@ def api_login_required(func):
return decorated_view
class ApiWrapper(Api):
class Api(ApiPlus):
"""Wrapper class around :class:`flask_restplus.Api`"""
cache = Cache(config={'CACHE_TYPE': 'null', 'CACHE_NO_NULL_WARNING': True})
loaded = False
@ -157,4 +158,14 @@ class ApiWrapper(Api):
apibp = Blueprint('api', __name__, url_prefix='/api')
api = ApiWrapper(apibp, title='Burp-UI API', description='Burp-UI API to interact with burp', doc='/doc', decorators=[api_login_required])
api = Api(apibp, title='Burp-UI API', description='Burp-UI API to interact with burp', doc='/doc', decorators=[api_login_required])
@api.errorhandler(BUIserverException)
def handle_bui_server_exception(error):
"""Forward a BUIserverException to the final user
:param error: Custom exception
:type error: :class:`burpui.exceptions.BUIserverException`
"""
return {'message': error.description}, error.code

View file

@ -143,11 +143,7 @@ class ServerBackup(Resource):
(not api.bui.acl.is_client_allowed(self.username,
name,
server) and not
self.is_admin and
(to and not
api.bui.acl.is_client_allowed(self.username,
to,
server)))):
self.is_admin)):
self.abort(
403,
'You are not allowed to schedule a backup for this client'

View file

@ -41,12 +41,12 @@ class Restore(Resource):
- ``pass``: password to use for encrypted backups
"""
parser = api.parser()
parser.add_argument('pass', help='Password to use for encrypted backups', location=('form', 'json'), nullable=True)
parser.add_argument('format', required=False, help='Returning archive format', location=('form', 'json'), choices=('zip', 'tar.gz', 'tar.bz2'), default='zip', nullable=True)
parser.add_argument('strip', type=int, help='Number of elements to strip in the path', default=0, location=('form', 'json'), nullable=True)
parser.add_argument('list', required=True, help='List of files/directories to restore', location=('form', 'json'), nullable=False)
parser.add_argument('pass', help='Password to use for encrypted backups', nullable=True)
parser.add_argument('format', required=False, help='Returning archive format', choices=('zip', 'tar.gz', 'tar.bz2'), default='zip', nullable=True)
parser.add_argument('strip', type=int, help='Number of elements to strip in the path', default=0, nullable=True)
parser.add_argument('list', required=True, help='List of files/directories to restore', nullable=False)
# FIXME: the example json seems interpreted during the raise of the exception
# parser.add_argument('list', required=True, help='List of files/directories to restore (example: \'{"restore":[{"folder":true,"key":"/etc"}]}\')', location=('form', 'json'), nullable=False)
# parser.add_argument('list', required=True, help='List of files/directories to restore (example: \'{"restore":[{"folder":true,"key":"/etc"}]}\')', nullable=False)
@ns.expect(parser, validate=True)
@ns.doc(
@ -230,11 +230,11 @@ class ServerRestore(Resource):
- ``restoreto-sc``: restore files on an other client
"""
parser = api.parser()
parser.add_argument('list-sc', required=True, help='List of files/directories to restore', location='form', nullable=False)
parser.add_argument('strip-sc', type=int, help='Number of elements to strip in the path', default=0, location='form', nullable=True)
parser.add_argument('prefix-sc', help='Prefix to the restore path', location='form', nullable=True)
parser.add_argument('force-sc', type=boolean, help='Whether to overwrite existing files', default=False, location='form', nullable=True)
parser.add_argument('restoreto-sc', help='Restore files on an other client', location='form', nullable=True)
parser.add_argument('list-sc', required=True, help='List of files/directories to restore', nullable=False)
parser.add_argument('strip-sc', type=int, help='Number of elements to strip in the path', default=0, nullable=True)
parser.add_argument('prefix-sc', help='Prefix to the restore path', nullable=True)
parser.add_argument('force-sc', type=boolean, help='Whether to overwrite existing files', default=False, nullable=True)
parser.add_argument('restoreto-sc', help='Restore files on an other client', nullable=True)
list_fields = api.model('ListRestoreFiles', {
'key': fields.String(

View file

@ -5,11 +5,11 @@ from . import api, cache_key, parallel_loop
from .custom import fields, Resource
from ..exceptions import BUIserverException
ns = api.namespace('servers', 'Servers methods')
if not api.bui.standalone:
ns = api.namespace('servers', 'Servers methods')
@ns.route('/stats', endpoint='servers_stats')
class ServersStats(Resource):
@ns.route('/stats', endpoint='servers_stats')
class ServersStats(Resource):
"""The :class:`burpui.api.servers.ServersStats` resource allows you to
retrieve statistics about servers/agents.
@ -54,7 +54,6 @@ class ServersStats(Resource):
"""
r = []
if hasattr(api.bui.cli, 'servers'):
restrict = []
check = False
if api.bui.acl and not self.is_admin:
@ -85,9 +84,8 @@ class ServersStats(Resource):
return r
@ns.route('/report', endpoint='servers_report')
class ServersReport(Resource):
@ns.route('/report', endpoint='servers_report')
class ServersReport(Resource):
"""The :class:`burpui.api.servers.ServersReport` resource allows you to
retrieve a report about servers/agents.
@ -156,7 +154,6 @@ class ServersReport(Resource):
:returns: The *JSON* described above.
"""
r = {}
if hasattr(api.bui.cli, 'servers'):
restrict = []
check = False
if api.bui.acl and not self.is_admin:

View file

@ -9,6 +9,7 @@
"""
from . import api
from .custom import Resource
from .custom.inputs import boolean
from .._compat import unquote
from flask import jsonify, request, url_for
from werkzeug.datastructures import ImmutableMultiDict
@ -28,6 +29,17 @@ class ServerSettings(Resource):
This resource is part of the :mod:`burpui.api.settings` module.
"""
@ns.doc(
params={
'conf': 'Path of the configuration file',
'server': 'Which server to collect data from when in multi-agent mode',
},
responses={
200: 'Success',
403: 'Insufficient permissions',
500: 'Internal failure',
}
)
def post(self, conf=None, server=None):
"""Saves the server configuration"""
# Only the admin can edit the configuration
@ -37,6 +49,17 @@ class ServerSettings(Resource):
noti = api.bui.cli.store_conf_srv(request.form, conf, server)
return {'notif': noti}, 200
@ns.doc(
params={
'conf': 'Path of the configuration file',
'server': 'Which server to collect data from when in multi-agent mode',
},
responses={
200: 'Success',
403: 'Insufficient permissions',
500: 'Internal failure',
}
)
def get(self, conf=None, server=None):
"""Reads the server configuration
@ -193,6 +216,16 @@ class ServerSettings(Resource):
endpoint='clients_list')
class ClientsList(Resource):
@ns.doc(
params={
'server': 'Which server to collect data from when in multi-agent mode',
},
responses={
200: 'Success',
403: 'Insufficient permissions',
500: 'Internal failure',
}
)
def get(self, server=None):
"""Returns a list of clients"""
# Only the admin can edit the configuration
@ -217,6 +250,21 @@ class ClientSettings(Resource):
parser = api.parser()
parser.add_argument('newclient', required=True, help="No 'newclient' provided")
parser_delete = api.parser()
parser_delete.add_argument('revoke', type=boolean, help='Whether to revoke the certificate or not', default=False, nullable=True)
parser_delete.add_argument('delcert', type=boolean, help='Whether to delete the certificate or not', default=False, nullable=True)
@ns.doc(
params={
'server': 'Which server to collect data from when in multi-agent mode',
},
responses={
200: 'Success',
400: 'Missing parameter',
403: 'Insufficient permissions',
500: 'Internal failure',
}
)
def put(self, server=None):
"""Creates a new client"""
# Only the admin can edit the configuration
@ -243,6 +291,18 @@ class ClientSettings(Resource):
api.cache.clear()
return {'notif': noti}, 201
@ns.doc(
params={
'server': 'Which server to collect data from when in multi-agent mode',
'client': 'Client name',
'conf': 'Path of the configuration file',
},
responses={
200: 'Success',
403: 'Insufficient permissions',
500: 'Internal failure',
}
)
def post(self, server=None, client=None, conf=None):
"""Saves a given client configuration"""
# Only the admin can edit the configuration
@ -252,6 +312,18 @@ class ClientSettings(Resource):
noti = api.bui.cli.store_conf_cli(request.form, client, conf, server)
return {'notif': noti}
@ns.doc(
params={
'server': 'Which server to collect data from when in multi-agent mode',
'client': 'Client name',
'conf': 'Path of the configuration file',
},
responses={
200: 'Success',
403: 'Insufficient permissions',
500: 'Internal failure',
}
)
def get(self, server=None, client=None, conf=None):
"""Reads a given client configuration"""
# Only the admin can edit the configuration
@ -275,7 +347,19 @@ class ClientSettings(Resource):
'defaults': api.bui.cli.get_parser_attr('defaults', server)
}
@ns.doc(
params={
'server': 'Which server to collect data from when in multi-agent mode',
'client': 'Client name',
},
responses={
200: 'Success',
403: 'Insufficient permissions',
500: 'Internal failure',
}
)
def delete(self, server=None, client=None):
"""Deletes a given client"""
# Only the admin can edit the configuration
if api.bui.acl and not self.is_admin:
self.abort(403, 'Sorry, you don\'t have rights to access the setting panel')
@ -295,6 +379,17 @@ class PathExpander(Resource):
parser = api.parser()
parser.add_argument('path', required=True, help="No 'path' provided")
@ns.doc(
params={
'server': 'Which server to collect data from when in multi-agent mode',
'client': 'Client name',
},
responses={
200: 'Success',
403: 'Insufficient permissions',
500: 'Internal failure',
}
)
def get(self, server=None, client=None):
"""Expends a given path
@ -313,10 +408,20 @@ class PathExpander(Resource):
@ns.route('/options',
'<server>/options',
'/<server>/options',
endpoint='setting_options')
class SettingOptions(Resource):
@ns.doc(
params={
'server': 'Which server to collect data from when in multi-agent mode',
},
responses={
200: 'Success',
403: 'Insufficient permissions',
500: 'Internal failure',
}
)
def get(self, server=None):
"""Returns various setting options"""
if api.bui.acl and not self.is_admin: