mirror of
https://github.com/ziirish/burp-ui.git
synced 2026-05-21 06:45:24 -06:00
new backend 'multi' for #14
This commit is contained in:
parent
bfdf3d7efd
commit
268b2fa756
23 changed files with 534 additions and 119 deletions
|
|
@ -20,6 +20,8 @@ if __name__ == '__main__':
|
|||
(options, args) = parser.parse_args()
|
||||
d = options.log
|
||||
app.config['DEBUG'] = d
|
||||
if d:
|
||||
app.config['TESTING'] = True
|
||||
|
||||
if options.config:
|
||||
if os.path.isfile(options.config):
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ __license__ = 'BSD 3-clause'
|
|||
|
||||
from flask import Flask
|
||||
from flask.ext.login import LoginManager
|
||||
from burpui.server import Server as BurpUI
|
||||
from burpui.server import BUIServer as BurpUI
|
||||
|
||||
# First, we setup the app
|
||||
app = Flask(__name__)
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@ class LdapLoader:
|
|||
query = 'uid={0}'.format(uid)
|
||||
self.app.logger.info('query: %s | base: %s', query, self.base)
|
||||
r = self.ldap.search(query, base_dn=self.base)
|
||||
except:
|
||||
self.app.logger.info('Ooops, LDAP lookup failed')
|
||||
except Exception, e:
|
||||
self.app.logger.error('Ooops, LDAP lookup failed: %s', str(e))
|
||||
return None
|
||||
|
||||
return r[0]['uid'][0]
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ class Burp(BUIbackend):
|
|||
Utilities functions
|
||||
"""
|
||||
|
||||
def status(self, query='\n'):
|
||||
def status(self, query='\n', agent=None):
|
||||
"""
|
||||
status connects to the burp status port, ask the given 'question' and
|
||||
parses the output in an array
|
||||
|
|
@ -178,7 +178,7 @@ class Burp(BUIbackend):
|
|||
self.logger('error', 'Cannot contact burp server at %s:%s', self.host, self.port)
|
||||
raise BUIserverException('Cannot contact burp server at {0}:{1}'.format(self.host, self.port))
|
||||
|
||||
def parse_backup_log(self, f, n, c=None):
|
||||
def parse_backup_log(self, f, n, c=None, agent=None):
|
||||
"""
|
||||
parse_backup_log parses the log.gz of a given backup and returns a dict
|
||||
containing different stats used to render the charts in the reporting view
|
||||
|
|
@ -269,7 +269,7 @@ class Burp(BUIbackend):
|
|||
break
|
||||
return backup
|
||||
|
||||
def get_counters(self, name=None):
|
||||
def get_counters(self, name=None, agent=None):
|
||||
"""
|
||||
get_counters parses the stats of the live status for a given client and
|
||||
returns a dict
|
||||
|
|
@ -310,7 +310,7 @@ class Burp(BUIbackend):
|
|||
r['timeleft'] = -1
|
||||
return r
|
||||
|
||||
def is_backup_running(self, name=None):
|
||||
def is_backup_running(self, name=None, agent=None):
|
||||
"""
|
||||
is_backup_running returns True if the given client is currently running a
|
||||
backup
|
||||
|
|
@ -327,7 +327,7 @@ class Burp(BUIbackend):
|
|||
return True
|
||||
return False
|
||||
|
||||
def is_one_backup_running(self):
|
||||
def is_one_backup_running(self, agent=None):
|
||||
"""
|
||||
is_one_backup_running returns a list of clients name that are currently
|
||||
running a backup
|
||||
|
|
@ -343,7 +343,7 @@ class Burp(BUIbackend):
|
|||
self.running = r
|
||||
return r
|
||||
|
||||
def get_all_clients(self):
|
||||
def get_all_clients(self, agent=None):
|
||||
"""
|
||||
get_all_clients returns a list of dict representing each clients with their
|
||||
name, state and last backup date
|
||||
|
|
@ -370,7 +370,7 @@ class Burp(BUIbackend):
|
|||
j.append(c)
|
||||
return j
|
||||
|
||||
def get_client(self, name=None):
|
||||
def get_client(self, name=None, agent=None):
|
||||
"""
|
||||
get_client returns a list of dict representing the backups (with its number
|
||||
and date) of a given client
|
||||
|
|
@ -399,7 +399,7 @@ class Burp(BUIbackend):
|
|||
r.reverse()
|
||||
return r
|
||||
|
||||
def get_tree(self, name=None, backup=None, root=None):
|
||||
def get_tree(self, name=None, backup=None, root=None, agent=None):
|
||||
"""
|
||||
get_tree returns a list of dict representing files/dir (with their attr)
|
||||
within a given path
|
||||
|
|
@ -442,7 +442,7 @@ class Burp(BUIbackend):
|
|||
r.append(t)
|
||||
return r
|
||||
|
||||
def restore_files(self, name=None, backup=None, files=None):
|
||||
def restore_files(self, name=None, backup=None, files=None, agent=None):
|
||||
if not name or not backup or not files:
|
||||
return None
|
||||
flist = json.loads(files)
|
||||
|
|
|
|||
|
|
@ -6,28 +6,28 @@ class BUIbackend:
|
|||
self.host = host
|
||||
self.port = port
|
||||
|
||||
def status(self, query='\n'):
|
||||
def status(self, query='\n', agent=None):
|
||||
raise NotImplementedError("Sorry, the current Backend does not implement this method!")
|
||||
|
||||
def parse_backup_log(self, f, n, c=None):
|
||||
def parse_backup_log(self, f, n, c=None, agent=None):
|
||||
raise NotImplementedError("Sorry, the current Backend does not implement this method!")
|
||||
|
||||
def get_counters(self, name=None):
|
||||
def get_counters(self, name=None, agent=None):
|
||||
raise NotImplementedError("Sorry, the current Backend does not implement this method!")
|
||||
|
||||
def is_backup_running(self, name=None):
|
||||
def is_backup_running(self, name=None, agent=None):
|
||||
raise NotImplementedError("Sorry, the current Backend does not implement this method!")
|
||||
|
||||
def is_one_backup_running(self):
|
||||
def is_one_backup_running(self, agent=None):
|
||||
raise NotImplementedError("Sorry, the current Backend does not implement this method!")
|
||||
|
||||
def get_all_clients(self):
|
||||
def get_all_clients(self, agent=None):
|
||||
raise NotImplementedError("Sorry, the current Backend does not implement this method!")
|
||||
|
||||
def get_client(self, name=None):
|
||||
def get_client(self, name=None, agent=None):
|
||||
raise NotImplementedError("Sorry, the current Backend does not implement this method!")
|
||||
|
||||
def get_tree(self, name=None, backup=None, root=None):
|
||||
def get_tree(self, name=None, backup=None, root=None, agent=None):
|
||||
raise NotImplementedError("Sorry, the current Backend does not implement this method!")
|
||||
|
||||
class BUIserverException(Exception):
|
||||
|
|
|
|||
249
burpui/misc/backend/multi.py
Normal file
249
burpui/misc/backend/multi.py
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
# -*- coding: utf8 -*-
|
||||
import re
|
||||
|
||||
import socket
|
||||
import sys
|
||||
import json
|
||||
import struct
|
||||
import ConfigParser
|
||||
|
||||
from burpui.misc.backend.interface import BUIbackend, BUIserverException
|
||||
|
||||
class Burp(BUIbackend):
|
||||
|
||||
def __init__(self, app=None, conf=None):
|
||||
self.app = app
|
||||
self.servers = {}
|
||||
self.servers_status = {}
|
||||
if conf:
|
||||
config = ConfigParser.ConfigParser()
|
||||
with open(conf) as fp:
|
||||
config.readfp(fp)
|
||||
for sec in config.sections():
|
||||
r = re.match('^Agent:(.+)$', sec)
|
||||
if r:
|
||||
try:
|
||||
host = config.get(sec, 'host')
|
||||
port = config.getint(sec, 'port')
|
||||
password = config.get(sec, 'password')
|
||||
ssl = config.getboolean(sec, 'ssl')
|
||||
except Exception, e:
|
||||
self.app.logger.error(str(e))
|
||||
self.servers[r.group(1)] = NClient(app, host, port, password, ssl)
|
||||
|
||||
self.app.logger.debug(self.servers)
|
||||
for key, serv in self.servers.iteritems():
|
||||
self.servers_status[key] = {'clients': [], 'alive': serv.connected}
|
||||
if not serv.connected:
|
||||
continue
|
||||
for c in serv.get_all_clients(key):
|
||||
self.servers_status[key]['clients'].append(c['name'])
|
||||
|
||||
"""
|
||||
Utilities functions
|
||||
"""
|
||||
|
||||
def status(self, query='\n', agent=None):
|
||||
"""
|
||||
status connects to the burp status port, ask the given 'question' and
|
||||
parses the output in an array
|
||||
"""
|
||||
return self.servers[agent].status(query)
|
||||
|
||||
def parse_backup_log(self, f, n, c=None, agent=None):
|
||||
"""
|
||||
parse_backup_log parses the log.gz of a given backup and returns a dict
|
||||
containing different stats used to render the charts in the reporting view
|
||||
"""
|
||||
return self.servers[agent].parse_backup_log(f, n, c)
|
||||
|
||||
def get_counters(self, name=None, agent=None):
|
||||
"""
|
||||
get_counters parses the stats of the live status for a given client and
|
||||
returns a dict
|
||||
"""
|
||||
return self.servers[agent].get_counters(name)
|
||||
|
||||
def is_backup_running(self, name=None, agent=None):
|
||||
"""
|
||||
is_backup_running returns True if the given client is currently running a
|
||||
backup
|
||||
"""
|
||||
return self.servers[agent].is_backup_running(name)
|
||||
|
||||
def is_one_backup_running(self, agent=None):
|
||||
"""
|
||||
is_one_backup_running returns a list of clients name that are currently
|
||||
running a backup
|
||||
"""
|
||||
return self.servers[agent].is_one_backup_running()
|
||||
|
||||
def get_all_clients(self, agent=None):
|
||||
"""
|
||||
get_all_clients returns a list of dict representing each clients with their
|
||||
name, state and last backup date
|
||||
"""
|
||||
return self.servers[agent].get_all_clients()
|
||||
|
||||
def get_client(self, name=None, agent=None):
|
||||
"""
|
||||
get_client returns a list of dict representing the backups (with its number
|
||||
and date) of a given client
|
||||
"""
|
||||
return self.servers[agent].get_client(name)
|
||||
|
||||
def get_tree(self, name=None, backup=None, root=None, agent=None):
|
||||
"""
|
||||
get_tree returns a list of dict representing files/dir (with their attr)
|
||||
within a given path
|
||||
"""
|
||||
return self.servers[agent].get_tree(name, backup, root)
|
||||
|
||||
def restore_files(self, name=None, backup=None, files=None, agent=None):
|
||||
pass
|
||||
|
||||
class NClient(BUIbackend):
|
||||
|
||||
def __init__(self, app=None, host=None, port=None, password=None, ssl=None):
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.password = password
|
||||
self.ssl = ssl
|
||||
self.nok = False
|
||||
self.connected = False
|
||||
self.app = app
|
||||
self.conn()
|
||||
|
||||
def conn(self):
|
||||
try:
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.sock.connect((self.host, self.port))
|
||||
self.connected = True
|
||||
self.app.logger.debug('OK, connected to agent %s:%s', self.host, self.port)
|
||||
except Exception, e:
|
||||
self.connected = False
|
||||
self.app.logger.error('Could not connect to %s:%s => %s', self.host, self.port, str(e))
|
||||
|
||||
def send_command(self, data=None):
|
||||
if not data:
|
||||
return
|
||||
old_data = data
|
||||
try:
|
||||
data['password'] = self.password
|
||||
raw = json.dumps(data)
|
||||
length = len(raw)
|
||||
self.sock.sendall(struct.pack('!Q', length))
|
||||
self.sock.sendall(raw)
|
||||
self.app.logger.debug("Sending: %s", raw)
|
||||
res = self.sock.recv(10)
|
||||
self.app.logger.debug("recv: '%s'", res)
|
||||
if 'OK Result:' != res:
|
||||
self.app.logger.debug('Ooops, unsuccessful!')
|
||||
self.nok = True
|
||||
return
|
||||
self.app.logger.debug("Data sent successfully")
|
||||
self.nok = False
|
||||
except Exception, e:
|
||||
self.app.logger.error(str(e))
|
||||
self.conn()
|
||||
self.nok = True
|
||||
self.send_command(old_data)
|
||||
|
||||
def get_result(self):
|
||||
if self.nok:
|
||||
return None
|
||||
self.app.logger.debug('What now?')
|
||||
lengthbuf = self.sock.recv(8)
|
||||
length, = struct.unpack('!Q', lengthbuf)
|
||||
return self.recvall(length)
|
||||
|
||||
def recvall(self, length):
|
||||
buf = b''
|
||||
bsize = 1024
|
||||
while length:
|
||||
newbuf = self.sock.recv(1024)
|
||||
if not newbuf: return None
|
||||
buf += newbuf
|
||||
length -= len(newbuf)
|
||||
self.app.logger.debug('result: %s', buf)
|
||||
return buf
|
||||
|
||||
"""
|
||||
Utilities functions
|
||||
"""
|
||||
|
||||
def status(self, query='\n', agent=None):
|
||||
"""
|
||||
status connects to the burp status port, ask the given 'question' and
|
||||
parses the output in an array
|
||||
"""
|
||||
data = {'func': 'status', 'args': {'query': query}}
|
||||
self.send_command(data)
|
||||
return json.loads(self.get_result())
|
||||
|
||||
def parse_backup_log(self, f, n, c=None, agent=None):
|
||||
"""
|
||||
parse_backup_log parses the log.gz of a given backup and returns a dict
|
||||
containing different stats used to render the charts in the reporting view
|
||||
"""
|
||||
data = {'func': 'parse_backup_log', 'args': {'f': f, 'n': n, 'c': c}}
|
||||
self.send_command(data)
|
||||
return json.loads(self.get_result())
|
||||
|
||||
def get_counters(self, name=None, agent=None):
|
||||
"""
|
||||
get_counters parses the stats of the live status for a given client and
|
||||
returns a dict
|
||||
"""
|
||||
data = {'func': 'get_counters', 'args': {'name': name}}
|
||||
self.send_command(data)
|
||||
return json.loads(self.get_result())
|
||||
|
||||
def is_backup_running(self, name=None, agent=None):
|
||||
"""
|
||||
is_backup_running returns True if the given client is currently running a
|
||||
backup
|
||||
"""
|
||||
data = {'func': 'is_backup_running', 'args': {'name': name}}
|
||||
self.send_command(data)
|
||||
return json.loads(self.get_result())
|
||||
|
||||
def is_one_backup_running(self, agent=None):
|
||||
"""
|
||||
is_one_backup_running returns a list of clients name that are currently
|
||||
running a backup
|
||||
"""
|
||||
data = {'func': 'is_one_backup_running', 'args': None}
|
||||
self.send_command(data)
|
||||
return json.loads(self.get_result())
|
||||
|
||||
def get_all_clients(self, agent=None):
|
||||
"""
|
||||
get_all_clients returns a list of dict representing each clients with their
|
||||
name, state and last backup date
|
||||
"""
|
||||
data = {'func': 'get_all_clients', 'args': None}
|
||||
self.send_command(data)
|
||||
return json.loads(self.get_result())
|
||||
|
||||
def get_client(self, name=None, agent=None):
|
||||
"""
|
||||
get_client returns a list of dict representing the backups (with its number
|
||||
and date) of a given clientm
|
||||
"""
|
||||
data = {'func': 'get_client', 'args': {'name': name}}
|
||||
self.send_command(data)
|
||||
return json.loads(self.get_result())
|
||||
|
||||
def get_tree(self, name=None, backup=None, root=None, agent=None):
|
||||
"""
|
||||
get_tree returns a list of dict representing files/dir (with their attr)
|
||||
within a given path
|
||||
"""
|
||||
data = {'func': 'get_tree', 'args': {'name': name, 'backup': backup, 'root': root}}
|
||||
self.send_command(data)
|
||||
return json.loads(self.get_result())
|
||||
|
||||
def restore_files(self, name=None, backup=None, files=None, agent=None):
|
||||
return None
|
||||
|
||||
180
burpui/routes.py
180
burpui/routes.py
|
|
@ -15,15 +15,6 @@ def load_user(userid):
|
|||
return bui.uhandler.user(userid)
|
||||
return None
|
||||
|
||||
@app.route('/test/download')
|
||||
def test_download():
|
||||
try:
|
||||
resp = send_file('/tmp/monfichierr', as_attachment=True)
|
||||
resp.set_cookie('fileDownload', 'true')
|
||||
return resp
|
||||
except Exception, e:
|
||||
abort(500)
|
||||
|
||||
@app.route('/api/restore/<name>/<int:backup>', methods=['POST'])
|
||||
@login_required
|
||||
def restore(name=None, backup=None):
|
||||
|
|
@ -47,25 +38,32 @@ The whole API returns JSON-formated data
|
|||
"""
|
||||
|
||||
@app.route('/api/running-clients.json')
|
||||
@app.route('/api/<server>/running-clients.json')
|
||||
@login_required
|
||||
def running_clients():
|
||||
def running_clients(server=None):
|
||||
"""
|
||||
API: running_clients
|
||||
:returns: a list of running clients
|
||||
"""
|
||||
r = bui.cli.is_one_backup_running()
|
||||
if not server:
|
||||
server = request.args.get('server')
|
||||
r = bui.cli.is_one_backup_running(agent=server)
|
||||
return jsonify(results=r)
|
||||
|
||||
@app.route('/api/render-live-template', methods=['GET'])
|
||||
@app.route('/api/<server>/render-live-template', methods=['GET'])
|
||||
@app.route('/api/render-live-template/<name>')
|
||||
@app.route('/api/<server>/render-live-template/<name>')
|
||||
@login_required
|
||||
def render_live_tpl(name=None):
|
||||
def render_live_tpl(server=None, name=None):
|
||||
"""
|
||||
API: render_live_tpl
|
||||
:param name: the client name if any. You can also use the GET parameter
|
||||
'name' to achieve the same thing
|
||||
:returns: HTML that should be included directly into the page
|
||||
"""
|
||||
if not server:
|
||||
server = request.args.get('server')
|
||||
c = request.args.get('name')
|
||||
if not name and not c:
|
||||
abort(500)
|
||||
|
|
@ -74,136 +72,166 @@ def render_live_tpl(name=None):
|
|||
if name not in bui.cli.running:
|
||||
abort(404)
|
||||
try:
|
||||
counters = bui.cli.get_counters(name)
|
||||
counters = bui.cli.get_counters(name, agent=server)
|
||||
except BUIserverException:
|
||||
counters = []
|
||||
return render_template('live-monitor-template.html', cname=name, counters=counters)
|
||||
return render_template('live-monitor-template.html', cname=name, counters=counters, server=server)
|
||||
|
||||
@app.route('/api/servers.json')
|
||||
@login_required
|
||||
def servers_json():
|
||||
r = []
|
||||
for serv in bui.cli.servers_status:
|
||||
r.append({'name': serv, 'clients': len(bui.cli.servers_status[serv]['clients']), 'connected': bui.cli.servers_status[serv]['alive']})
|
||||
return jsonify(results=r)
|
||||
|
||||
@app.route('/api/live.json')
|
||||
@app.route('/api/<server>/live.json')
|
||||
@login_required
|
||||
def live():
|
||||
def live(server=None):
|
||||
"""
|
||||
API: live
|
||||
:returns: the live status of the server
|
||||
"""
|
||||
if not server:
|
||||
server = request.args.get('server')
|
||||
r = []
|
||||
for c in bui.cli.is_one_backup_running():
|
||||
for c in bui.cli.is_one_backup_running(agent=server):
|
||||
s = {}
|
||||
s['client'] = c
|
||||
try:
|
||||
s['status'] = bui.cli.get_counters(c)
|
||||
s['status'] = bui.cli.get_counters(c, agent=server)
|
||||
except BUIserverException:
|
||||
s['status'] = []
|
||||
r.append(s)
|
||||
return jsonify(results=r)
|
||||
|
||||
@app.route('/api/running.json')
|
||||
@app.route('/api/<server>/running.json')
|
||||
@login_required
|
||||
def backup_running():
|
||||
def backup_running(server=None):
|
||||
"""
|
||||
API: backup_running
|
||||
:returns: true if at least one backup is running
|
||||
"""
|
||||
j = bui.cli.is_one_backup_running()
|
||||
if not server:
|
||||
server = request.args.get('server')
|
||||
j = bui.cli.is_one_backup_running(agent=server)
|
||||
r = len(j) > 0
|
||||
return jsonify(results=r)
|
||||
|
||||
@app.route('/api/client-tree.json/<name>/<int:backup>', methods=['GET'])
|
||||
@app.route('/api/<server>/client-tree.json/<name>/<int:backup>', methods=['GET'])
|
||||
@login_required
|
||||
def client_tree(name=None, backup=None):
|
||||
def client_tree(server=None, name=None, backup=None):
|
||||
"""
|
||||
WebService: return a specific client files tree
|
||||
:param name: the client name (mandatory)
|
||||
:param backup: the backup number (mandatory)
|
||||
|
||||
"""
|
||||
if not server:
|
||||
server = request.args.get('server')
|
||||
j = []
|
||||
if not name or not backup:
|
||||
return jsonify(results=j)
|
||||
root = request.args.get('root')
|
||||
try:
|
||||
j = bui.cli.get_tree(name, backup, root)
|
||||
j = bui.cli.get_tree(name, backup, root, agent=server)
|
||||
except BUIserverException, e:
|
||||
err = [[2, str(e)]]
|
||||
return jsonify(notif=err)
|
||||
return jsonify(results=j)
|
||||
|
||||
@app.route('/api/clients-report.json')
|
||||
@app.route('/api/<server>/clients-report.json')
|
||||
@login_required
|
||||
def clients_report_json():
|
||||
def clients_report_json(server=None):
|
||||
"""
|
||||
WebService: return a JSON with global stats
|
||||
"""
|
||||
if not server:
|
||||
server = request.args.get('server')
|
||||
j = []
|
||||
try:
|
||||
clients = bui.cli.get_all_clients()
|
||||
clients = bui.cli.get_all_clients(agent=server)
|
||||
except BUIserverException, e:
|
||||
err = [[2, str(e)]]
|
||||
return jsonify(notif=err)
|
||||
cl = []
|
||||
ba = []
|
||||
for c in clients:
|
||||
client = bui.cli.get_client(c['name'])
|
||||
client = bui.cli.get_client(c['name'], agent=server)
|
||||
if not client:
|
||||
continue
|
||||
f = bui.cli.status('c:{0}:b:{1}:f:log.gz\n'.format(c['name'], client[-1]['number']))
|
||||
cl.append( { 'name': c['name'], 'stats': bui.cli.parse_backup_log(f, client[-1]['number']) } )
|
||||
f = bui.cli.status('c:{0}:b:{1}:f:log.gz\n'.format(c['name'], client[-1]['number']), agent=server)
|
||||
cl.append( { 'name': c['name'], 'stats': bui.cli.parse_backup_log(f, client[-1]['number'], agent=server) } )
|
||||
for b in client:
|
||||
f = bui.cli.status('c:{0}:b:{1}:f:log.gz\n'.format(c['name'], b['number']))
|
||||
ba.append(bui.cli.parse_backup_log(f, b['number'], c['name']))
|
||||
f = bui.cli.status('c:{0}:b:{1}:f:log.gz\n'.format(c['name'], b['number']), agent=server)
|
||||
ba.append(bui.cli.parse_backup_log(f, b['number'], c['name']), agent=server)
|
||||
j.append( { 'clients': cl, 'backups': sorted(ba, key=lambda k: k['end']) } )
|
||||
return jsonify(results=j)
|
||||
|
||||
@app.route('/api/client-stat.json/<name>')
|
||||
@app.route('/api/<server>/client-stat.json/<name>')
|
||||
@app.route('/api/client-stat.json/<name>/<int:backup>')
|
||||
@app.route('/api/<server>/client-stat.json/<name>/<int:backup>')
|
||||
@login_required
|
||||
def client_stat_json(name=None, backup=None):
|
||||
def client_stat_json(server=None, name=None, backup=None):
|
||||
"""
|
||||
WebService: return a specific client detailed report
|
||||
"""
|
||||
if not server:
|
||||
server = request.args.get('server')
|
||||
j = []
|
||||
if not name:
|
||||
err = [[1, 'No client defined']]
|
||||
return jsonify(notif=err)
|
||||
if backup:
|
||||
try:
|
||||
f = bui.cli.status('c:{0}:b:{1}:f:log.gz\n'.format(name, backup))
|
||||
f = bui.cli.status('c:{0}:b:{1}:f:log.gz\n'.format(name, backup), agent=server)
|
||||
except BUIserverException, e:
|
||||
err = [[2, str(e)]]
|
||||
return jsonify(notif=err)
|
||||
j = bui.cli.parse_backup_log(f, backup)
|
||||
j = bui.cli.parse_backup_log(f, backup, agent=server)
|
||||
else:
|
||||
try:
|
||||
cl = bui.cli.get_client(name)
|
||||
cl = bui.cli.get_client(name, agent=server)
|
||||
except BUIserverException, e:
|
||||
err = [[2, str(e)]]
|
||||
return jsonify(notif=err)
|
||||
for c in cl:
|
||||
f = bui.cli.status('c:{0}:b:{1}:f:log.gz\n'.format(name, c['number']))
|
||||
j.append(bui.cli.parse_backup_log(f, c['number']))
|
||||
f = bui.cli.status('c:{0}:b:{1}:f:log.gz\n'.format(name, c['number']), agent=server)
|
||||
j.append(bui.cli.parse_backup_log(f, c['number']), agent=server)
|
||||
return jsonify(results=j)
|
||||
|
||||
@app.route('/api/client.json/<name>')
|
||||
@app.route('/api/<server>/client.json/<name>')
|
||||
@login_required
|
||||
def client_json(name=None):
|
||||
def client_json(server=None, name=None):
|
||||
"""
|
||||
WebService: return a specific client backups overview
|
||||
"""
|
||||
if not server:
|
||||
server = request.args.get('server')
|
||||
try:
|
||||
j = bui.cli.get_client(name)
|
||||
j = bui.cli.get_client(name, agent=server)
|
||||
except BUIserverException, e:
|
||||
err = [[2, str(e)]]
|
||||
return jsonify(notif=err)
|
||||
return jsonify(results=j)
|
||||
|
||||
@app.route('/api/clients.json')
|
||||
@app.route('/api/<server>/clients.json')
|
||||
@login_required
|
||||
def clients():
|
||||
def clients_json(server=None):
|
||||
"""
|
||||
WebService: return a JSON listing all clients
|
||||
"""
|
||||
if not server:
|
||||
server = request.args.get('server')
|
||||
try:
|
||||
j = bui.cli.get_all_clients()
|
||||
j = bui.cli.get_all_clients(agent=server)
|
||||
except BUIserverException, e:
|
||||
err = [[2, str(e)]]
|
||||
return jsonify(notif=err)
|
||||
|
|
@ -240,63 +268,83 @@ And here is the main site
|
|||
"""
|
||||
|
||||
@app.route('/live-monitor')
|
||||
@app.route('/<server>/live-monitor')
|
||||
@app.route('/live-monitor/<name>')
|
||||
@app.route('/<server>/live-monitor/<name>')
|
||||
@login_required
|
||||
def live_monitor(name=None):
|
||||
def live_monitor(server=None, name=None):
|
||||
"""
|
||||
Live status monitor view
|
||||
"""
|
||||
if not server:
|
||||
server = request.get.args('server')
|
||||
if not bui.cli.running:
|
||||
flash('Sorry, there are no running backups', 'warning')
|
||||
return redirect(url_for('home'))
|
||||
return render_template('live-monitor.html', live=True, cname=name)
|
||||
return render_template('live-monitor.html', live=True, cname=name, server=server)
|
||||
|
||||
@app.route('/client-browse/<name>', methods=['GET'])
|
||||
@app.route('/<server>/client-browse/<name>', methods=['GET'])
|
||||
@app.route('/client-browse/<name>/<int:backup>')
|
||||
@app.route('/<server>/client-browse/<name>/<int:backup>')
|
||||
@login_required
|
||||
def client_browse(name=None, backup=None):
|
||||
def client_browse(server=None, name=None, backup=None):
|
||||
"""
|
||||
Browse a specific backup of a specific client
|
||||
"""
|
||||
if not server:
|
||||
server = request.args.get('server')
|
||||
bkp = request.args.get('backup')
|
||||
if bkp and not backup:
|
||||
return redirect(url_for('client_browse', name=name, backup=bkp))
|
||||
return render_template('client-browse.html', tree=True, backup=True, overview=True, cname=name, nbackup=backup)
|
||||
return redirect(url_for('client_browse', name=name, backup=bkp, server=server))
|
||||
return render_template('client-browse.html', tree=True, backup=True, overview=True, cname=name, nbackup=backup, server=server)
|
||||
|
||||
@app.route('/client-report/<name>')
|
||||
@app.route('/<server>/client-report/<name>')
|
||||
@login_required
|
||||
def client_report(name=None):
|
||||
def client_report(server=None, name=None):
|
||||
"""
|
||||
Specific client report
|
||||
"""
|
||||
l = bui.cli.get_client(name)
|
||||
if not server:
|
||||
server = request.args.get('server')
|
||||
l = bui.cli.get_client(name, agent=server)
|
||||
if len(l) == 1:
|
||||
return redirect(url_for('backup_report', name=name, backup=l[0]['number']))
|
||||
return render_template('client-report.html', client=True, report=True, cname=name)
|
||||
return redirect(url_for('backup_report', name=name, backup=l[0]['number']), server=server)
|
||||
return render_template('client-report.html', client=True, report=True, cname=name, server=server)
|
||||
|
||||
@app.route('/clients-report')
|
||||
@app.route('/<server>/clients-report')
|
||||
@login_required
|
||||
def clients_report():
|
||||
def clients_report(server=None):
|
||||
"""
|
||||
Global report
|
||||
"""
|
||||
return render_template('clients-report.html', clients=True, report=True)
|
||||
if not server:
|
||||
server = request.args.get('server')
|
||||
return render_template('clients-report.html', clients=True, report=True, server=server)
|
||||
|
||||
@app.route('/backup-report/<name>', methods=['GET'])
|
||||
@app.route('/<server>/backup-report/<name>', methods=['GET'])
|
||||
@app.route('/backup-report/<name>/<int:backup>', methods=['GET'])
|
||||
@app.route('/<server>/backup-report/<name>/<int:backup>', methods=['GET'])
|
||||
@login_required
|
||||
def backup_report(name=None, backup=None):
|
||||
def backup_report(server=None, name=None, backup=None):
|
||||
"""
|
||||
Backup specific report
|
||||
"""
|
||||
if not backup:
|
||||
backup = request.args.get('backup')
|
||||
return render_template('backup-report.html', client=True, backup=True, report=True, cname=name, nbackup=backup)
|
||||
if not server:
|
||||
server = request.args.get('server')
|
||||
return render_template('backup-report.html', client=True, backup=True, report=True, cname=name, nbackup=backup, server=server)
|
||||
|
||||
@app.route('/client', methods=['GET'])
|
||||
@app.route('/<server>/client', methods=['GET'])
|
||||
@app.route('/client/<name>')
|
||||
@app.route('/<server>/client/<name>')
|
||||
@login_required
|
||||
def client(name=None):
|
||||
def client(server=None, name=None):
|
||||
"""
|
||||
Specific client overview
|
||||
"""
|
||||
|
|
@ -304,9 +352,24 @@ def client(name=None):
|
|||
c = name
|
||||
else:
|
||||
c = request.args.get('name')
|
||||
if bui.cli.is_backup_running(c):
|
||||
return redirect(url_for('live_monitor', name=name))
|
||||
return render_template('client.html', client=True, overview=True, cname=c)
|
||||
if not server:
|
||||
server = request.args.get('server')
|
||||
if bui.cli.is_backup_running(c, agent=server):
|
||||
return redirect(url_for('live_monitor', name=name, server=server))
|
||||
return render_template('client.html', client=True, overview=True, cname=c, server=server)
|
||||
|
||||
@app.route('/clients', methods=['GET'])
|
||||
@app.route('/<server>/clients', methods=['GET'])
|
||||
@login_required
|
||||
def clients(server=None):
|
||||
if not server:
|
||||
server = request.args.get('server')
|
||||
return render_template('clients.html', clients=True, overview=True, server=server)
|
||||
|
||||
@app.route('/servers', methods=['GET'])
|
||||
@login_required
|
||||
def servers():
|
||||
return render_template('servers.html', servers=True, overview=True)
|
||||
|
||||
@app.route('/login', methods=['POST', 'GET'])
|
||||
def login():
|
||||
|
|
@ -317,6 +380,8 @@ def login():
|
|||
login_user(user, remember=form.remember.data)
|
||||
flash('Logged in successfully', 'success')
|
||||
return redirect(request.args.get("next") or url_for('home'))
|
||||
else:
|
||||
flash('Wrong username or password', 'danger')
|
||||
return render_template('login.html', form=form, login=True)
|
||||
|
||||
@app.route('/logout')
|
||||
|
|
@ -331,4 +396,7 @@ def home():
|
|||
"""
|
||||
Home page
|
||||
"""
|
||||
return render_template('clients.html', clients=True, overview=True)
|
||||
if bui.standalone:
|
||||
return redirect(url_for('clients'))
|
||||
else:
|
||||
return redirect(url_for('servers'))
|
||||
|
|
|
|||
|
|
@ -6,18 +6,19 @@ g_port = 5000
|
|||
g_bind = '::'
|
||||
g_refresh = 15
|
||||
g_ssl = False
|
||||
g_standalone = True
|
||||
g_sslcert = ''
|
||||
g_sslkey = ''
|
||||
g_version = 1
|
||||
g_auth = 'basic'
|
||||
|
||||
class Server:
|
||||
class BUIServer:
|
||||
def __init__(self, app=None):
|
||||
self.init = False
|
||||
self.app = app
|
||||
|
||||
def setup(self, conf=None):
|
||||
global g_refresh, g_port, g_bind, g_ssl, g_sslcert, g_sslkey, g_version, g_auth
|
||||
global g_refresh, g_port, g_bind, g_ssl, g_sslcert, g_sslkey, g_version, g_auth, g_standalone
|
||||
self.sslcontext = None
|
||||
if not conf:
|
||||
conf = self.app.config['CFG']
|
||||
|
|
@ -27,7 +28,8 @@ class Server:
|
|||
|
||||
config = ConfigParser.ConfigParser({'port': g_port,'bind': g_bind,
|
||||
'refresh': g_refresh, 'ssl': g_ssl, 'sslcert': g_sslcert,
|
||||
'sslkey': g_sslkey, 'version': g_version, 'auth': g_auth})
|
||||
'sslkey': g_sslkey, 'version': g_version, 'auth': g_auth,
|
||||
'standalone': g_standalone})
|
||||
with open(conf) as fp:
|
||||
config.readfp(fp)
|
||||
try:
|
||||
|
|
@ -39,6 +41,11 @@ class Server:
|
|||
except ValueError:
|
||||
self.app.logger.error("Wrong value for 'ssl' key! Assuming 'false'")
|
||||
self.ssl = False
|
||||
try:
|
||||
self.standalone = config.getboolean('Global', 'standalone')
|
||||
except ValueError:
|
||||
self.app.logger.error("Wrong value for 'standalone' key! Assuming 'True'")
|
||||
self.standalone = True
|
||||
self.sslcert = config.get('Global', 'sslcert')
|
||||
self.sslkey = config.get('Global', 'sslkey')
|
||||
self.auth = config.get('Global', 'auth')
|
||||
|
|
@ -53,21 +60,28 @@ class Server:
|
|||
else:
|
||||
# I know that's ugly, but hey, I need it!
|
||||
self.app.login_manager._login_disabled = True
|
||||
except ConfigParser.NoOptionError:
|
||||
self.app.logger.error("Missing option")
|
||||
except ConfigParser.NoOptionError, e:
|
||||
self.app.logger.error(str(e))
|
||||
|
||||
self.app.config['REFRESH'] = config.getint('UI', 'refresh')
|
||||
|
||||
self.app.config['STANDALONE'] = self.standalone
|
||||
|
||||
self.app.logger.info('burp version: %d', self.vers)
|
||||
self.app.logger.info('listen port: %d', self.port)
|
||||
self.app.logger.info('bind addr: %s', self.bind)
|
||||
self.app.logger.info('use ssl: %s', self.ssl)
|
||||
self.app.logger.info('standalone: %s', self.standalone)
|
||||
self.app.logger.info('sslcert: %s', self.sslcert)
|
||||
self.app.logger.info('sslkey: %s', self.sslkey)
|
||||
self.app.logger.info('refresh: %d', self.app.config['REFRESH'])
|
||||
|
||||
if self.standalone:
|
||||
module = 'burpui.misc.backend.burp{0}'.format(self.vers)
|
||||
else:
|
||||
module = 'burpui.misc.backend.multi'
|
||||
try:
|
||||
mod = __import__('burpui.misc.backend.burp{0}'.format(self.vers), fromlist=['Burp'])
|
||||
mod = __import__(module, fromlist=['Burp'])
|
||||
Client = mod.Burp
|
||||
self.cli = Client(self.app, conf=conf)
|
||||
except Exception, e:
|
||||
|
|
@ -87,6 +101,7 @@ class Server:
|
|||
self.sslcontext.use_certificate_file(self.sslcert)
|
||||
|
||||
if self.sslcontext:
|
||||
self.app.config['SSL'] = True
|
||||
self.app.run(host=self.bind, port=self.port, debug=debug, ssl_context=self.sslcontext)
|
||||
else:
|
||||
self.app.run(host=self.bind, port=self.port, debug=debug)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
{% include "small_topbar.html" %}
|
||||
<ul class="breadcrumb" style="margin-bottom: 5px;">
|
||||
<li><a href="{{ url_for('home') }}">Home</a></li>
|
||||
<li><a href="{{ url_for('client', name=cname) }}">{{ cname }} overview</a></li>
|
||||
<li><a href="{{ url_for('client', name=cname, server=server) }}">{{ cname }} overview</a></li>
|
||||
<li class="active">Backup n°{{ nbackup|mypad }} overview</li>
|
||||
</ul>
|
||||
<br />
|
||||
|
|
|
|||
|
|
@ -34,8 +34,9 @@ var notif = function(type, message) {
|
|||
};
|
||||
|
||||
{% if not login -%}
|
||||
{% if not (servers and overview) -%}
|
||||
var _check_running = function() {
|
||||
url = '{{ url_for("backup_running") }}';
|
||||
url = '{{ url_for("backup_running", server=server) }}';
|
||||
$.getJSON(url, function(data) {
|
||||
if (data.results) {
|
||||
$('#toblink').addClass('blink');
|
||||
|
|
@ -44,6 +45,11 @@ var _check_running = function() {
|
|||
}
|
||||
});
|
||||
};
|
||||
{% else -%}
|
||||
var _check_running = function() {
|
||||
return false;
|
||||
};
|
||||
{% endif -%}
|
||||
{% endif -%}
|
||||
|
||||
/***
|
||||
|
|
@ -54,7 +60,7 @@ var _clients_bh = new Bloodhound({
|
|||
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
||||
limit: 10,
|
||||
prefetch: {
|
||||
url: '{{ url_for("clients") }}',
|
||||
url: '{{ url_for("clients_json", server=server) }}',
|
||||
filter: function(list) {
|
||||
if (list.results) {
|
||||
return list.results;
|
||||
|
|
@ -75,9 +81,12 @@ $('#input-client').typeahead(null, {
|
|||
source: _clients_bh.ttAdapter()
|
||||
});
|
||||
|
||||
{% if servers and overview -%}
|
||||
{% include "js/servers.js" %}
|
||||
{% endif -%}
|
||||
|
||||
{% if clients and overview -%}
|
||||
{% include "js/home.js" %}
|
||||
{% include "js/clients.js" %}
|
||||
{% endif -%}
|
||||
|
||||
{% if clients and report -%}
|
||||
|
|
@ -148,6 +157,9 @@ $(function() {
|
|||
{% if not login -%}
|
||||
_check_running();
|
||||
{% endif -%}
|
||||
{% if servers and overview -%}
|
||||
_servers();
|
||||
{% endif -%}
|
||||
});
|
||||
|
||||
/***
|
||||
|
|
@ -156,7 +168,7 @@ $(function() {
|
|||
var search = $('input[id="input-client"]');
|
||||
search.keypress(function(e) {
|
||||
if (e.which == 13) {
|
||||
window.location = '{{ url_for("client") }}?name='+search.val();
|
||||
window.location = '{{ url_for("client", server=server) }}?name='+search.val();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -182,6 +194,9 @@ $(function() {
|
|||
{% if live -%}
|
||||
_live();
|
||||
{% endif -%}
|
||||
{% if servers and overview -%}
|
||||
_servers();
|
||||
{% endif -%}
|
||||
|
||||
{% if not report and not login -%}
|
||||
/***
|
||||
|
|
@ -197,6 +212,9 @@ $(function() {
|
|||
{% if live -%}
|
||||
_live();
|
||||
{% endif -%}
|
||||
{% if servers and overview -%}
|
||||
_servers();
|
||||
{% endif -%}
|
||||
return;
|
||||
}, {{ config.REFRESH * 1000 }});
|
||||
{% endif -%}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ var _client = function() {
|
|||
|
||||
chart_unified.yAxis.tickFormat(d3.format(',.0f'));
|
||||
}
|
||||
url = '{{ url_for("client_stat_json", name=cname, backup=nbackup) }}';
|
||||
url = '{{ url_for("client_stat_json", name=cname, backup=nbackup, server=server) }}';
|
||||
$.getJSON(url, function(d) {
|
||||
var _fields = [ 'dir', 'files', 'hardlink', 'softlink' ];
|
||||
j = d.results;
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@
|
|||
},
|
||||
source: function() {
|
||||
r = [];
|
||||
$.getJSON('{{ url_for("client_tree", name=cname, backup=nbackup) }}', function(data) {
|
||||
$.getJSON('{{ url_for("client_tree", name=cname, backup=nbackup, server=server) }}', function(data) {
|
||||
if (!data.results) {
|
||||
if (data.notif) {
|
||||
$.each(data.notif, function(i, n) {
|
||||
|
|
@ -84,7 +84,7 @@
|
|||
r = [];
|
||||
p = node.key;
|
||||
if (p !== "/") p += '/';
|
||||
$.getJSON('{{ url_for("client_tree", name=cname, backup=nbackup) }}?root='+p, function(data) {
|
||||
$.getJSON('{{ url_for("client_tree", name=cname, backup=nbackup, server=server) }}?root='+p, function(data) {
|
||||
if (!data.results) {
|
||||
if (data.notif) {
|
||||
$.each(data.notif, function(i, n) {
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ var _client = function() {
|
|||
|
||||
_chart_stats.bars.forceY([0]);
|
||||
}
|
||||
url = '{{ url_for("client_stat_json", name=cname) }}';
|
||||
url = '{{ url_for("client_stat_json", name=cname, server=server) }}';
|
||||
$.getJSON(url, function(d) {
|
||||
var _fields = [ 'dir', 'files', 'hardlink', 'softlink', 'files_enc', 'meta', 'meta_enc', 'special', 'efs', 'vssheader', 'vssheader_enc', 'vssfooter', 'vssfooter_enc' ];
|
||||
var stats = true;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
* The JSON is then parsed into a table
|
||||
*/
|
||||
var _client = function() {
|
||||
url = '{{ url_for("client_json", name=cname) }}';
|
||||
url = '{{ url_for("client_json", name=cname, server=server) }}';
|
||||
$.getJSON(url, function(data) {
|
||||
$('#table-client >tbody:last').empty();
|
||||
$('#client-alert').hide();
|
||||
|
|
@ -41,7 +41,7 @@ var _client = function() {
|
|||
$('#client-alert').show();
|
||||
} else {
|
||||
$.each(data.results.reverse(), function(j, c) {
|
||||
$('#table-client> tbody:last').append('<tr class="clickable" style="cursor: pointer;"><td><a href="{{ url_for("client_browse", name=cname) }}?backup='+c.number+'" style="color: inherit; text-decoration: inherit;">'+pad(c.number, 7)+'</a></td><td>'+c.date+'</td></tr>');
|
||||
$('#table-client> tbody:last').append('<tr class="clickable" style="cursor: pointer;"><td><a href="{{ url_for("client_browse", name=cname, server=server) }}?backup='+c.number+'" style="color: inherit; text-decoration: inherit;">'+pad(c.number, 7)+'</a></td><td>'+c.date+'</td></tr>');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ var _clients = function() {
|
|||
_charts_obj.push({ 'key': 'chart_'+j, 'obj': tmp, 'data': [] });
|
||||
});
|
||||
}
|
||||
url = '{{ url_for("clients_report_json") }}';
|
||||
url = '{{ url_for("clients_report_json", server=server) }}';
|
||||
$.getJSON(url, function(d) {
|
||||
rep = [];
|
||||
size = [];
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ var __status = {
|
|||
* The JSON is then parsed into a table
|
||||
*/
|
||||
var _clients = function() {
|
||||
url = '{{ url_for("clients") }}';
|
||||
url = '{{ url_for("clients_json", server=server) }}';
|
||||
$.getJSON(url, function(data) {
|
||||
$('#table-clients > tbody:last').empty();
|
||||
if (!data.results) {
|
||||
|
|
@ -49,7 +49,7 @@ var _clients = function() {
|
|||
if (__status[c.state] != undefined) {
|
||||
clas = ' '+__status[c.state];
|
||||
}
|
||||
$('#table-clients > tbody:last').append('<tr class="clickable'+clas+'" style="cursor: pointer;"><td><a href="{{ url_for("client") }}?name='+c.name+'" style="color: inherit; text-decoration: inherit;">'+c.name+'</a></td><td>'+c.state+'</td><td>'+c.last+'</td></tr>');
|
||||
$('#table-clients > tbody:last').append('<tr class="clickable'+clas+'" style="cursor: pointer;"><td><a href="{{ url_for("client", server=server) }}?name='+c.name+'" style="color: inherit; text-decoration: inherit;">'+c.name+'</a></td><td>'+c.state+'</td><td>'+c.last+'</td></tr>');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
|
||||
_live = function() {
|
||||
url = '{{ url_for("running_clients") }}';
|
||||
url = '{{ url_for("running_clients", server=server) }}';
|
||||
html = ''
|
||||
$.getJSON(url, function(data) {
|
||||
if (!data.results || data.results.length === 0) {
|
||||
document.location = '{{ url_for("home") }}';
|
||||
document.location = '{{ url_for("home", server=server) }}';
|
||||
}
|
||||
$.each(data.results, function(i, c) {
|
||||
u = '{{ url_for("render_live_tpl") }}?name='+c;
|
||||
u = '{{ url_for("render_live_tpl", server=server) }}?name='+c;
|
||||
$.get(u, function(d) {
|
||||
html += d;
|
||||
});
|
||||
|
|
|
|||
33
burpui/templates/js/servers.js
Normal file
33
burpui/templates/js/servers.js
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
|
||||
/***
|
||||
* Here is the 'servers' part
|
||||
* It is available on the global clients view
|
||||
*/
|
||||
|
||||
/***
|
||||
* _servers: function that retrieve up-to-date informations from the burp server
|
||||
* The JSON is then parsed into a table
|
||||
*/
|
||||
var _servers = function() {
|
||||
url = '{{ url_for("servers_json") }}';
|
||||
$.getJSON(url, function(data) {
|
||||
$('#table-servers > tbody:last').empty();
|
||||
if (!data.results) {
|
||||
if (data.notif) {
|
||||
$.each(data.notif, function(i, n) {
|
||||
notif(n[0], n[1]);
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
$.each(data.results, function(j, c) {
|
||||
cl = '';
|
||||
glyph = 'glyphicon-ok';
|
||||
if (!c.connected) {
|
||||
cl = ' danger';
|
||||
glyph = 'glyphicon-remove';
|
||||
}
|
||||
$('#table-servers > tbody:last').append('<tr class="clickable'+cl+'" style="cursor: pointer;"><td><a href="{{ url_for("clients") }}?server='+c.name+'" style="color: inherit; text-decoration: inherit;">'+c.name+'</a></td><td>'+c.clients+'</td><td><span class="glyphicon '+glyph+'"></span></td></tr>');
|
||||
});
|
||||
});
|
||||
};
|
||||
26
burpui/templates/servers.html
Normal file
26
burpui/templates/servers.html
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
{% extends "layout.html" %}
|
||||
{% block body %}
|
||||
{% include "notifications.html" %}
|
||||
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
|
||||
{% include "small_topbar.html" %}
|
||||
<ul class="breadcrumb" style="margin-bottom: 5px;">
|
||||
<li class="active">Home</li>
|
||||
</ul>
|
||||
<br />
|
||||
<h1 class="page-header">Servers</h1>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover" id="table-servers">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Clients</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -2,9 +2,9 @@
|
|||
<ul class="nav nav-sidebar">
|
||||
<li {% if overview %}class="active"{% endif %}>
|
||||
{% if backup %}
|
||||
<a href="{{ url_for('client_browse', name=cname) }}?backup={{ nbackup }}"><span class="glyphicon glyphicon-th"></span> Overview</a>
|
||||
<a href="{{ url_for('client_browse', name=cname, server=server) }}?backup={{ nbackup }}"><span class="glyphicon glyphicon-th"></span> Overview</a>
|
||||
{% elif client %}
|
||||
<a href="{{ url_for('client', name=cname) }}"><span class="glyphicon glyphicon-th"></span> Overview</a>
|
||||
<a href="{{ url_for('client', name=cname, server=server) }}"><span class="glyphicon glyphicon-th"></span> Overview</a>
|
||||
{% elif clients %}
|
||||
<a href="{{ url_for('home') }}"><span class="glyphicon glyphicon-th"></span> Overview</a>
|
||||
{% else %}
|
||||
|
|
@ -13,11 +13,11 @@
|
|||
</li>
|
||||
<li {% if report %}class="active"{% endif %}>
|
||||
{% if client and not backup %}
|
||||
<a href="{{ url_for('client_report', name=cname) }}"><span class="glyphicon glyphicon-stats"></span> Reports</a>
|
||||
<a href="{{ url_for('client_report', name=cname, server=server) }}"><span class="glyphicon glyphicon-stats"></span> Reports</a>
|
||||
{% elif clients %}
|
||||
<a href="{{ url_for('clients_report') }}"><span class="glyphicon glyphicon-stats"></span> Reports</a>
|
||||
<a href="{{ url_for('clients_report', server=server) }}"><span class="glyphicon glyphicon-stats"></span> Reports</a>
|
||||
{% elif backup %}
|
||||
<a href="{{ url_for('backup_report', name=cname, backup=nbackup) }}"><span class="glyphicon glyphicon-stats"></span> Reports</a>
|
||||
<a href="{{ url_for('backup_report', name=cname, backup=nbackup, server=server) }}"><span class="glyphicon glyphicon-stats"></span> Reports</a>
|
||||
{% else %}
|
||||
<a href="#"><span class="glyphicon glyphicon-stats"></span> Reports</a>
|
||||
{% endif %}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
<div class="btn-group btn-group-justified hidden-md hidden-lg">
|
||||
{% if backup %}
|
||||
<a class="btn btn-default {% if overview %}active{% endif %}" href="{{ url_for('client_browse', name=cname) }}?backup={{ nbackup }}"><span class="glyphicon glyphicon-th"></span> Overview</a>
|
||||
<a class="btn btn-default {% if overview %}active{% endif %}" href="{{ url_for('client_browse', name=cname, server=server) }}?backup={{ nbackup }}"><span class="glyphicon glyphicon-th"></span> Overview</a>
|
||||
{% elif client %}
|
||||
<a class="btn btn-default {% if overview %}active{% endif %}" href="{{ url_for('client', name=cname) }}"><span class="glyphicon glyphicon-th"></span> Overview</a>
|
||||
<a class="btn btn-default {% if overview %}active{% endif %}" href="{{ url_for('client', name=cname, server=server) }}"><span class="glyphicon glyphicon-th"></span> Overview</a>
|
||||
{% elif clients %}
|
||||
<a class="btn btn-default {% if overview %}active{% endif %}" href="{{ url_for('home') }}"><span class="glyphicon glyphicon-th"></span> Overview</a>
|
||||
{% else %}
|
||||
<a class="btn btn-default {% if overview %}active{% endif %}" href="#"><span class="glyphicon glyphicon-th"></span> Overview</a>
|
||||
{% endif %}
|
||||
{% if client and not backup %}
|
||||
<a class="btn btn-default {% if report %}active{% endif %}" href="{{ url_for('client_report', name=cname) }}"><span class="glyphicon glyphicon-stats"></span> Reports</a>
|
||||
<a class="btn btn-default {% if report %}active{% endif %}" href="{{ url_for('client_report', name=cname, server=server) }}"><span class="glyphicon glyphicon-stats"></span> Reports</a>
|
||||
{% elif clients %}
|
||||
<a class="btn btn-default {% if report %}active{% endif %}" href="{{ url_for('clients_report') }}"><span class="glyphicon glyphicon-stats"></span> Reports</a>
|
||||
<a class="btn btn-default {% if report %}active{% endif %}" href="{{ url_for('clients_report', server=server) }}"><span class="glyphicon glyphicon-stats"></span> Reports</a>
|
||||
{% elif backup %}
|
||||
<a class="btn btn-default {% if report %}active{% endif %}" href="{{ url_for('backup_report', name=cname, backup=nbackup) }}"><span class="glyphicon glyphicon-stats"></span> Reports</a>
|
||||
<a class="btn btn-default {% if report %}active{% endif %}" href="{{ url_for('backup_report', name=cname, backup=nbackup, server=server) }}"><span class="glyphicon glyphicon-stats"></span> Reports</a>
|
||||
{% else %}
|
||||
<a class="btn btn-default {% if report %}active{% endif %}" href="#"><span class="glyphicon glyphicon-stats"></span> Reports</a>
|
||||
{% endif %}
|
||||
|
|
|
|||
|
|
@ -10,13 +10,16 @@
|
|||
<a class="navbar-brand" href="{{ url_for('home') }}">Burp Server Dashboard</a>
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li class="detail{% if clients %} active{% endif %}"><a href="{{ url_for('home') }}"><span class="glyphicon glyphicon-home"></span><span class="dtl hidden-md hidden-lg"> Clients</span></a></li>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
{% if not config.STANDALONE -%}
|
||||
<li class="detail"><a href="{{ url_for('home') }}"><span class="glyphicon glyphicon-hdd"></span><span class="dtl hidden-md hidden-lg"> Servers</span></a></li>
|
||||
{% endif -%}
|
||||
<li class="detail{% if clients %} active{% endif %}"><a href="{{ url_for('home') }}"><span class="glyphicon glyphicon-tasks"></span><span class="dtl hidden-md hidden-lg"> Clients</span></a></li>
|
||||
<li class="detail disabled"><a href="#"><span class="glyphicon glyphicon-wrench"></span><span class="dtl hidden-md hidden-lg"> Settings</span></a></li>
|
||||
<li class="detail{% if live %} active{% endif %}"><a href="{{ url_for('live_monitor') }}"><span id="toblink" class="glyphicon glyphicon-screenshot"></span><span class="dtl hidden-md hidden-lg"> Live monitor</span></a></li>
|
||||
{% if current_user and current_user.is_authenticated() %}
|
||||
<li class="detail{% if live %} active{% endif %}"><a href="{{ url_for('live_monitor', server=server) }}"><span id="toblink" class="glyphicon glyphicon-screenshot"></span><span class="dtl hidden-md hidden-lg"> Live monitor</span></a></li>
|
||||
{% if current_user and current_user.is_authenticated() -%}
|
||||
<li class="detail"><a href="{{ url_for('logout') }}"><span class="glyphicon glyphicon-log-out"></span><span class="dtl hidden-md hidden-lg"> Logout<small>({{ current_user.name }})</small></span></a></li>
|
||||
{% endif %}
|
||||
{% endif -%}
|
||||
<li><a id="refresh" href="#"><span class="glyphicon glyphicon-refresh"></span><span class="hidden-md hidden-lg"> Refresh</span></a></li>
|
||||
</ul>
|
||||
<form class="navbar-form navbar-right" id="search">
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ sslkey: /etc/burp/ssl_cert-server.key
|
|||
# burp server version (currently only burp 1.x is implemented)
|
||||
version: 1
|
||||
# Handle multiple bui-servers or not
|
||||
# /!\ Do not set it to false now as it is experimental /!\
|
||||
standalone: true
|
||||
# authentication plugin (mandatory)
|
||||
# list the misc/auth directory to see the available backends
|
||||
|
|
@ -56,13 +57,13 @@ refresh: 15
|
|||
#admin: password
|
||||
#user1: otherpassword
|
||||
|
||||
## If you set standalone to false, add one section like this one per bui-server
|
||||
#[Server:serv1]
|
||||
## bui-server address
|
||||
## If you set standalone to false, add one section like this one per bui-agent
|
||||
#[Agent:agent1]
|
||||
## bui-agent address
|
||||
#host: 192.168.1.1
|
||||
## bui-server port
|
||||
## bui-agent port
|
||||
#port: 10000
|
||||
## bui-server password
|
||||
## bui-agent password
|
||||
#password: azerty
|
||||
## enable SSL
|
||||
#ssl: true
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue