huge MVC refactoring

This commit is contained in:
ziirish 2015-07-28 17:26:06 +02:00
parent 97e8b302ab
commit 6201eea94b
26 changed files with 273 additions and 257 deletions

View file

@ -11,6 +11,8 @@ import logging
from flask import Flask
from flask.ext.login import LoginManager
from burpui.server import BUIServer as BurpUI
from burpui.routes import view
from burpui.api import api
reload(sys)
sys.setdefaultencoding('utf-8')
@ -30,19 +32,32 @@ app.config['CFG'] = None
app.secret_key = 'VpgOXNXAgcO81xFPyWj07ppN6kExNZeCDRShseNzFKV7ZCgmW2/eLn6xSlt7pYAVBj12zx2Vv9Kw3Q3jd1266A=='
app.jinja_env.globals.update(isinstance=isinstance, list=list)
app.jinja_env.globals.update(api=api)
# We initialize the core
bui = BurpUI(app)
# Then we load our routes
view.bui = bui
app.register_blueprint(view)
# We initialize the API
api.app = app
api.bui = bui
api.init_app(app)
# And the login_manager
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
login_manager.login_view = 'view.login'
login_manager.login_message_category = 'info'
# Then we load our routes
# This import cannot take place earlier because the modules relies on app that must be initialized first
import burpui.routes
@login_manager.user_loader
def load_user(userid):
if bui.auth != 'none':
return bui.uhandler.user(userid)
return None
def init(conf=None, debug=False, logfile=None, gunicorn=True):

View file

@ -11,12 +11,10 @@
import os
import re
from burpui import app
from flask.ext.restful import Api
api = Api(app)
app.jinja_env.globals.update(api=api)
api = Api()
api.bui = None
# hack to automatically import api modules
for f in os.listdir(__path__[0]):

View file

@ -9,7 +9,6 @@
"""
import json
from burpui import app, bui
from burpui.api import api
from burpui.misc.backend.interface import BUIserverException
from flask.ext.restful import reqparse, Resource
@ -84,13 +83,13 @@ class ClientTree(Resource):
return jsonify(results=j)
root = self.parser.parse_args()['root']
try:
if (bui.acl and
(not bui.acl.is_admin(current_user.name) and not
bui.acl.is_client_allowed(current_user.name,
name,
server))):
if (api.bui.acl and
(not api.bui.acl.is_admin(current_user.name) and not
api.bui.acl.is_client_allowed(current_user.name,
name,
server))):
raise BUIserverException('Sorry, you are not allowed to view this client')
j = bui.cli.get_tree(name, backup, root, agent=server)
j = api.bui.cli.get_tree(name, backup, root, agent=server)
except BUIserverException, e:
err = [[2, str(e)]]
return jsonify(notif=err)
@ -271,28 +270,28 @@ class ClientStats(Resource):
if not name:
err = [[1, 'No client defined']]
return jsonify(notif=err)
if (bui.acl and not
bui.acl.is_client_allowed(current_user.name,
name,
server)):
if (api.bui.acl and not
api.bui.acl.is_client_allowed(current_user.name,
name,
server)):
err = [[2, 'You don\'t have rights to view this client stats']]
return jsonify(notif=err)
if backup:
try:
j = bui.cli.get_backup_logs(backup, name, agent=server)
j = api.bui.cli.get_backup_logs(backup, name, agent=server)
except BUIserverException, e:
err = [[2, str(e)]]
return jsonify(notif=err)
else:
try:
cl = bui.cli.get_client(name, agent=server)
cl = api.bui.cli.get_client(name, agent=server)
except BUIserverException, e:
err = [[2, str(e)]]
return jsonify(notif=err)
err = []
for c in cl:
try:
j.append(bui.cli.get_backup_logs(c['number'], name, agent=server))
j.append(api.bui.cli.get_backup_logs(c['number'], name, agent=server))
except BUIserverException, e:
temp = [2, str(e)]
if temp not in err:
@ -353,13 +352,13 @@ class ClientReport(Resource):
if not server:
server = self.parser.parse_args()['server']
try:
if (bui.acl and (
not bui.acl.is_admin(current_user.name) and
not bui.acl.is_client_allowed(current_user.name,
name,
server))):
if (api.bui.acl and (
not api.bui.acl.is_admin(current_user.name) and
not api.bui.acl.is_client_allowed(current_user.name,
name,
server))):
raise BUIserverException('Sorry, you cannot access this client')
j = bui.cli.get_client(name, agent=server)
j = api.bui.cli.get_client(name, agent=server)
except BUIserverException, e:
err = [[2, str(e)]]
return jsonify(notif=err)

View file

@ -9,7 +9,6 @@
"""
import json
from burpui import app, bui
from burpui.api import api
from burpui.misc.backend.interface import BUIserverException
from flask.ext.restful import reqparse, Resource
@ -64,32 +63,32 @@ class RunningClients(Resource):
if not server:
server = self.parser.parse_args()['server']
if client:
if bui.acl:
if (not bui.acl.is_admin(current_user.name) and not
bui.acl.is_client_allowed(current_user.name,
client,
server)):
if api.bui.acl:
if (not api.bui.acl.is_admin(current_user.name) and not
api.bui.acl.is_client_allowed(current_user.name,
client,
server)):
r = []
return jsonify(results=r)
if bui.cli.is_backup_running(client, server):
r = [bui.cli.get_client(client, server)]
if api.bui.cli.is_backup_running(client, server):
r = [api.bui.cli.get_client(client, server)]
return jsonify(results=r)
else:
r = []
return jsonify(results=r)
r = bui.cli.is_one_backup_running(server)
r = api.bui.cli.is_one_backup_running(server)
# Manage ACL
if (bui.acl and not
bui.acl.is_admin(current_user.name)):
if (api.bui.acl and not
api.bui.acl.is_admin(current_user.name)):
if isinstance(r, dict):
new = {}
for serv in bui.acl.servers(current_user.name):
allowed = bui.acl.clients(current_user.name, serv)
for serv in api.bui.acl.servers(current_user.name):
allowed = api.bui.acl.clients(current_user.name, serv)
new[serv] = [x for x in r[serv] if x in allowed]
r = new
else:
allowed = bui.acl.clients(current_user.name, server)
allowed = api.bui.acl.clients(current_user.name, server)
r = [x for x in r if x in allowed]
return jsonify(results=r)
@ -127,18 +126,18 @@ class RunningBackup(Resource):
:returns: The *JSON* described above.
"""
j = bui.cli.is_one_backup_running(server)
j = api.bui.cli.is_one_backup_running(server)
# Manage ACL
if (bui.acl and not
bui.acl.is_admin(current_user.name)):
if (api.bui.acl and not
api.bui.acl.is_admin(current_user.name)):
if isinstance(j, dict):
new = {}
for serv in bui.acl.servers(current_user.name):
allowed = bui.acl.clients(current_user.name, serv)
for serv in api.bui.acl.servers(current_user.name):
allowed = api.bui.acl.clients(current_user.name, serv)
new[serv] = [x for x in j[serv] if x in allowed]
j = new
else:
allowed = bui.acl.clients(current_user.name, server)
allowed = api.bui.acl.clients(current_user.name, server)
j = [x for x in j if x in allowed]
r = False
if isinstance(j, dict):
@ -227,12 +226,12 @@ class ClientsReport(Resource):
j = []
try:
# Manage ACL
if (not bui.standalone and bui.acl and
(not bui.acl.is_admin(current_user.name) and
if (not api.bui.standalone and api.bui.acl and
(not api.bui.acl.is_admin(current_user.name) and
server not in
bui.acl.servers(current_user.name))):
api.bui.acl.servers(current_user.name))):
raise BUIserverException('Sorry, you don\'t have rights on this server')
clients = bui.cli.get_all_clients(agent=server)
clients = api.bui.cli.get_all_clients(agent=server)
except BUIserverException, e:
err = [[2, str(e)]]
return jsonify(notif=err)
@ -241,16 +240,16 @@ class ClientsReport(Resource):
# Filter only allowed clients
allowed = []
check = False
if (bui.acl and not
bui.acl.is_admin(current_user.name)):
if (api.bui.acl and not
api.bui.acl.is_admin(current_user.name)):
check = True
allowed = bui.acl.clients(current_user.name, server)
allowed = api.bui.acl.clients(current_user.name, server)
aclients = []
for c in clients:
if check and c['name'] not in allowed:
continue
aclients.append(c)
j = bui.cli.get_clients_report(aclients, server)
j = api.bui.cli.get_clients_report(aclients, server)
return jsonify(results=j)
@ -308,16 +307,16 @@ class ClientsStats(Resource):
if not server:
server = self.parser.parse_args()['server']
try:
if (not bui.standalone and
bui.acl and
(not bui.acl.is_admin(current_user.name) and
if (not api.bui.standalone and
api.bui.acl and
(not api.bui.acl.is_admin(current_user.name) and
server not in
bui.acl.servers(current_user.name))):
api.bui.acl.servers(current_user.name))):
raise BUIserverException('Sorry, you don\'t have any rights on this server')
j = bui.cli.get_all_clients(agent=server)
if (bui.acl and not
bui.acl.is_admin(current_user.name)):
j = [x for x in j if x['name'] in bui.acl.clients(current_user.name, server)]
j = api.bui.cli.get_all_clients(agent=server)
if (api.bui.acl and not
api.bui.acl.is_admin(current_user.name)):
j = [x for x in j if x['name'] in api.bui.acl.clients(current_user.name, server)]
except BUIserverException, e:
err = [[2, str(e)]]
return jsonify(notif=err)

View file

@ -10,7 +10,6 @@
from zlib import adler32
from time import gmtime, strftime, time
from burpui import app, bui, login_manager
from burpui.api import api
from flask.ext.restful import reqparse, Resource, abort
from flask.ext.login import current_user, login_required
@ -70,11 +69,11 @@ class Restore(Resource):
if not l or not name or not backup:
abort(500)
# Manage ACL
if (bui.acl and
(not bui.acl.is_client_allowed(current_user.name,
name,
server) and not
bui.acl.is_admin(current_user.name))):
if (api.bui.acl and
(not api.bui.acl.is_client_allowed(current_user.name,
name,
server) and not
api.bui.acl.is_admin(current_user.name))):
abort(403)
if server:
filename = 'restoration_%d_%s_on_%s_at_%s.%s' % (
@ -91,7 +90,7 @@ class Restore(Resource):
f)
if not server:
# Standalone mode, we can just return the file unless there were errors
archive, err = bui.cli.restore_files(name, backup, l, s, f, p)
archive, err = api.bui.cli.restore_files(name, backup, l, s, f, p)
if not archive:
if err:
return make_response(err, 500)
@ -116,23 +115,23 @@ class Restore(Resource):
mimetype='application/zip')
resp.set_cookie('fileDownload', 'true')
except Exception, e:
app.logger.error(str(e))
api.app.logger.error(str(e))
abort(500)
else:
# Multi-agent mode
socket = None
try:
socket, length, err = bui.cli.restore_files(name,
backup,
l,
s,
f,
p,
server)
app.logger.debug('Need to get %d Bytes : %s', length, socket)
socket, length, err = api.bui.cli.restore_files(name,
backup,
l,
s,
f,
p,
server)
api.app.logger.debug('Need to get %d Bytes : %s', length, socket)
if err:
app.logger.debug('Something went wrong: %s', err)
api.app.logger.debug('Something went wrong: %s', err)
socket.close()
return make_response(err, 500)
@ -152,7 +151,7 @@ class Restore(Resource):
if not buf:
continue
received += len(buf)
app.logger.debug('%d/%d', received, l)
api.app.logger.debug('%d/%d', received, l)
yield buf
sock.close()
@ -174,6 +173,6 @@ class Restore(Resource):
except HTTPException, e:
raise e
except Exception, e:
app.logger.error(str(e))
api.app.logger.error(str(e))
abort(500)
return resp

View file

@ -1,6 +1,5 @@
# -*- coding: utf8 -*-
from burpui import bui
from burpui.api import api
from burpui.misc.backend.interface import BUIserverException
from flask.ext.restful import reqparse, Resource
@ -8,30 +7,36 @@ from flask.ext.login import current_user, login_required
from flask import jsonify
@api.resource('/api/servers.json')
@api.resource('/api/servers.json', endpoint='api.servers_stats')
class ServersStats(Resource):
"""
The :class:`burpui.api.servers.ServersStats` resource allows you to
retrieve statistics about servers/agents.
This resource is part of the :mod:`burpui.api.servers` module.
"""
@login_required
def get(self):
r = []
if hasattr(bui.cli, 'servers'):
if hasattr(api.bui.cli, 'servers'):
check = False
allowed = []
if (bui.acl and not
bui.acl.is_admin(current_user.name)):
if (api.bui.acl and not
api.bui.acl.is_admin(current_user.name)):
check = True
allowed = bui.acl.servers(current_user.name)
for serv in bui.cli.servers:
allowed = api.bui.acl.servers(current_user.name)
for serv in api.bui.cli.servers:
try:
if check:
if serv in allowed:
r.append({'name': serv,
'clients': len(bui.cli.servers[serv].get_all_clients(serv)),
'alive': bui.cli.servers[serv].ping()})
'clients': len(api.bui.cli.servers[serv].get_all_clients(serv)),
'alive': api.bui.cli.servers[serv].ping()})
else:
r.append({'name': serv,
'clients': len(bui.cli.servers[serv].get_all_clients(serv)),
'alive': bui.cli.servers[serv].ping()})
'clients': len(api.bui.cli.servers[serv].get_all_clients(serv)),
'alive': api.bui.cli.servers[serv].ping()})
except BUIserverException, e:
err = [[2, str(e)]]
return jsonify(notif=err)
@ -39,8 +44,18 @@ class ServersStats(Resource):
@api.resource('/api/live.json',
'/api/<server>/live.json')
'/api/<server>/live.json',
endpoint='api.live')
class Live(Resource):
"""
The :class:`burpui.api.servers.Live` resource allows you to
retrieve a list of servers that are currently *alive*.
This resource is part of the :mod:`burpui.api.servers` module.
An optional ``GET`` parameter called ``server`` is supported when running
in multi-agent mode.
"""
def __init__(self):
self.parser = reqparse.RequestParser()
@ -56,9 +71,9 @@ class Live(Resource):
server = self.parser.parse_args()['server']
r = []
if server:
l = (bui.cli.is_one_backup_running(server))[server]
l = (api.bui.cli.is_one_backup_running(server))[server]
else:
l = bui.cli.is_one_backup_running()
l = api.bui.cli.is_one_backup_running()
if isinstance(l, dict):
for k, a in l.iteritems():
for c in a:
@ -66,7 +81,7 @@ class Live(Resource):
s['client'] = c
s['agent'] = k
try:
s['status'] = bui.cli.get_counters(c, agent=k)
s['status'] = api.bui.cli.get_counters(c, agent=k)
except BUIserverException:
s['status'] = []
r.append(s)
@ -75,7 +90,7 @@ class Live(Resource):
s = {}
s['client'] = c
try:
s['status'] = bui.cli.get_counters(c, agent=server)
s['status'] = api.bui.cli.get_counters(c, agent=server)
except BUIserverException:
s['status'] = []
r.append(s)

View file

@ -8,7 +8,6 @@
"""
from burpui import app, bui, login_manager
from burpui.api import api
from flask.ext.restful import reqparse, abort, Resource
from flask.ext.login import current_user, login_required
@ -158,19 +157,19 @@ class ServerSettings(Resource):
:returns: The *JSON* described above.
"""
# Only the admin can edit the configuration
if (bui.acl and not
bui.acl.is_admin(current_user.name)):
if (api.bui.acl and not
api.bui.acl.is_admin(current_user.name)):
abort(403, message='Sorry, you don\'t have rights to access the setting panel')
r = bui.cli.read_conf_srv(server)
r = api.bui.cli.read_conf_srv(server)
return jsonify(results=r,
boolean=bui.cli.get_parser_attr('boolean_srv', server),
string=bui.cli.get_parser_attr('string_srv', server),
integer=bui.cli.get_parser_attr('integer_srv', server),
multi=bui.cli.get_parser_attr('multi_srv', server),
server_doc=bui.cli.get_parser_attr('doc', server),
suggest=bui.cli.get_parser_attr('values', server),
placeholders=bui.cli.get_parser_attr('placeholders', server),
defaults=bui.cli.get_parser_attr('defaults', server))
boolean=api.bui.cli.get_parser_attr('boolean_srv', server),
string=api.bui.cli.get_parser_attr('string_srv', server),
integer=api.bui.cli.get_parser_attr('integer_srv', server),
multi=api.bui.cli.get_parser_attr('multi_srv', server),
server_doc=api.bui.cli.get_parser_attr('doc', server),
suggest=api.bui.cli.get_parser_attr('values', server),
placeholders=api.bui.cli.get_parser_attr('placeholders', server),
defaults=api.bui.cli.get_parser_attr('defaults', server))
@api.resource('/api/client-config/<client>',
@ -180,8 +179,8 @@ class ClientSettings(Resource):
@login_required
def get(self, server=None, client=None):
# Only the admin can edit the configuration
if (bui.acl and not
bui.acl.is_admin(current_user.name)):
if (api.bui.acl and not
api.bui.acl.is_admin(current_user.name)):
abort(403, message='Sorry, you don\'t have rights to access the setting panel')
r = bui.cli.read_conf_cli(client, server)
r = api.bui.cli.read_conf_cli(client, server)
return jsonify(results=r)

View file

@ -3,12 +3,11 @@ import math
import select
import json
from flask import Flask, Response, request, render_template, jsonify, redirect, url_for, abort, flash
from flask import Flask, Response, request, render_template, jsonify, redirect, url_for, abort, flash, Blueprint
from flask.ext.login import login_user, login_required, logout_user, current_user
from werkzeug.datastructures import Headers
from werkzeug.exceptions import HTTPException
from burpui import app, bui, login_manager
from burpui.forms import LoginForm
from burpui.misc.utils import human_readable as _hr
from burpui.misc.backend.interface import BUIserverException
@ -16,30 +15,26 @@ from burpui.misc.backend.interface import BUIserverException
import burpui.api
from burpui.api.servers import ServersStats, Live
@login_manager.user_loader
def load_user(userid):
if bui.auth != 'none':
return bui.uhandler.user(userid)
return None
view = Blueprint('view', __name__, template_folder='templates')
view.bui = None
@app.route('/settings', methods=['GET', 'POST'])
@app.route('/<server>/settings', methods=['GET', 'POST'])
@app.route('/settings/<client>', methods=['GET', 'POST'])
@app.route('/<server>/settings/<client>', methods=['GET', 'POST'])
@view.route('/settings', methods=['GET', 'POST'])
@view.route('/<server>/settings', methods=['GET', 'POST'])
@view.route('/settings/<client>', methods=['GET', 'POST'])
@view.route('/<server>/settings/<client>', methods=['GET', 'POST'])
@login_required
def settings(server=None, client=None):
# Only the admin can edit the configuration
if bui.acl and not bui.acl.is_admin(current_user.name):
if view.bui.acl and not view.bui.acl.is_admin(current_user.name):
abort(403)
if not client:
client = request.args.get('client')
if request.method == 'POST':
if not client:
noti = bui.cli.store_conf_srv(request.form, server)
noti = view.bui.cli.store_conf_srv(request.form, server)
else:
noti = bui.cli.store_conf_cli(request.form, server)
noti = view.bui.cli.store_conf_cli(request.form, server)
return jsonify(notif=noti)
return render_template('settings.html', settings=True, server=server, client=client)
@ -52,14 +47,11 @@ The whole API returns JSON-formated data
The API has been split-out into several files and now uses Flask-Restful
"""
app.jinja_env.globals.update(ServersStats=ServersStats)
app.jinja_env.globals.update(Live=Live)
@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>')
@view.route('/api/render-live-template', methods=['GET'])
@view.route('/api/<server>/render-live-template', methods=['GET'])
@view.route('/api/render-live-template/<name>')
@view.route('/api/<server>/render-live-template/<name>')
@login_required
def render_live_tpl(server=None, name=None):
"""
@ -76,24 +68,24 @@ def render_live_tpl(server=None, name=None):
if not name:
abort(500)
# Manage ACL
if (bui.acl and
(not bui.acl.is_client_allowed(current_user.name, name, server) or
not bui.acl.is_admin(current_user.name))):
if (view.bui.acl and
(not view.bui.acl.is_client_allowed(current_user.name, name, server) or
not view.bui.acl.is_admin(current_user.name))):
abort(403)
if isinstance(bui.cli.running, dict):
if server and name not in bui.cli.running[server]:
if isinstance(view.bui.cli.running, dict):
if server and name not in view.bui.cli.running[server]:
abort(404)
else:
found = False
for k, a in bui.cli.running.iteritems():
for k, a in view.bui.cli.running.iteritems():
found = found or (name in a)
if not found:
abort(404)
else:
if name not in bui.cli.running:
if name not in view.bui.cli.running:
abort(404)
try:
counters = bui.cli.get_counters(name, agent=server)
counters = view.bui.cli.get_counters(name, agent=server)
except BUIserverException:
counters = []
return render_template('live-monitor-template.html', cname=name, counters=counters, server=server)
@ -103,7 +95,7 @@ Here are some custom filters
"""
@app.template_filter()
@view.app_template_filter()
def mypad(s):
"""
Filter: used to pad 0's to backup numbers as in the burp's status monitor
@ -113,7 +105,7 @@ def mypad(s):
return '{0:07d}'.format(int(s))
@app.template_filter()
@view.app_template_filter()
def time_human(d):
s = ''
seconds = (((d % 31536000) % 86400) % 3600) % 60
@ -124,7 +116,7 @@ def time_human(d):
return '%s %02dm %02ds' % (s, minutes, seconds)
@app.template_filter()
@view.app_template_filter()
def bytes_human(b):
return '{0:.1eM}'.format(_hr(b))
@ -133,10 +125,10 @@ 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>')
@view.route('/live-monitor')
@view.route('/<server>/live-monitor')
@view.route('/live-monitor/<name>')
@view.route('/<server>/live-monitor/<name>')
@login_required
def live_monitor(server=None, name=None):
"""
@ -144,27 +136,27 @@ def live_monitor(server=None, name=None):
"""
if not server:
server = request.args.get('server')
if bui.standalone:
if not bui.cli.running:
if view.bui.standalone:
if not view.bui.cli.running:
flash('Sorry, there are no running backups', 'warning')
return redirect(url_for('home'))
return redirect(url_for('.home'))
else:
run = False
for a in bui.cli.servers:
run = run or (a in bui.cli.running and bui.cli.running[a])
for a in view.bui.cli.servers:
run = run or (a in view.bui.cli.running and view.bui.cli.running[a])
if not run:
flash('Sorry, there are no running backups', 'warning')
return redirect(url_for('home'))
return redirect(url_for('.home'))
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>')
@app.route('/client-browse/<name>/<int:backup>/<int:encrypted>')
@app.route('/<server>/client-browse/<name>/<int:backup>/<int:encrypted>')
@view.route('/client-browse/<name>', methods=['GET'])
@view.route('/<server>/client-browse/<name>', methods=['GET'])
@view.route('/client-browse/<name>/<int:backup>')
@view.route('/<server>/client-browse/<name>/<int:backup>')
@view.route('/client-browse/<name>/<int:backup>/<int:encrypted>')
@view.route('/<server>/client-browse/<name>/<int:backup>/<int:encrypted>')
@login_required
def client_browse(server=None, name=None, backup=None, encrypted=None):
"""
@ -176,12 +168,12 @@ def client_browse(server=None, name=None, backup=None, encrypted=None):
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, encrypted=encrypted, server=server))
return redirect(url_for('.client_browse', name=name, backup=bkp, encrypted=encrypted, server=server))
return render_template('client-browse.html', tree=True, backup=True, overview=True, cname=name, nbackup=backup, encrypted=encrypted, server=server)
@app.route('/client-report/<name>')
@app.route('/<server>/client-report/<name>')
@view.route('/client-report/<name>')
@view.route('/<server>/client-report/<name>')
@login_required
def client_report(server=None, name=None):
"""
@ -190,16 +182,16 @@ def client_report(server=None, name=None):
if not server:
server = request.args.get('server')
try:
l = bui.cli.get_client(name, agent=server)
l = view.bui.cli.get_client(name, agent=server)
except BUIserverException:
l = []
if len(l) == 1:
return redirect(url_for('backup_report', name=name, backup=l[0]['number'], server=server))
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')
@view.route('/clients-report')
@view.route('/<server>/clients-report')
@login_required
def clients_report(server=None):
"""
@ -210,10 +202,10 @@ def clients_report(server=None):
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'])
@view.route('/backup-report/<name>', methods=['GET'])
@view.route('/<server>/backup-report/<name>', methods=['GET'])
@view.route('/backup-report/<name>/<int:backup>', methods=['GET'])
@view.route('/<server>/backup-report/<name>/<int:backup>', methods=['GET'])
@login_required
def backup_report(server=None, name=None, backup=None):
"""
@ -226,10 +218,10 @@ def backup_report(server=None, name=None, backup=None):
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>')
@view.route('/client', methods=['GET'])
@view.route('/<server>/client', methods=['GET'])
@view.route('/client/<name>')
@view.route('/<server>/client/<name>')
@login_required
def client(server=None, name=None):
"""
@ -241,13 +233,13 @@ def client(server=None, name=None):
c = request.args.get('name')
if not server:
server = request.args.get('server')
if bui.cli.is_backup_running(c, agent=server):
return redirect(url_for('live_monitor', name=c, server=server))
if view.bui.cli.is_backup_running(c, agent=server):
return redirect(url_for('.live_monitor', name=c, 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'])
@view.route('/clients', methods=['GET'])
@view.route('/<server>/clients', methods=['GET'])
@login_required
def clients(server=None):
if not server:
@ -255,40 +247,40 @@ def clients(server=None):
return render_template('clients.html', clients=True, overview=True, server=server)
@app.route('/servers', methods=['GET'])
@view.route('/servers', methods=['GET'])
@login_required
def servers():
return render_template('servers.html', servers=True, overview=True)
@app.route('/login', methods=['POST', 'GET'])
@view.route('/login', methods=['POST', 'GET'])
def login():
form = LoginForm(request.form)
if form.validate_on_submit():
user = bui.uhandler.user(form.username.data)
user = view.bui.uhandler.user(form.username.data)
if user.active and user.login(form.username.data, passwd=form.password.data):
login_user(user, remember=form.remember.data)
flash('Logged in successfully', 'success')
return redirect(request.args.get("next") or url_for('home'))
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')
@view.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('home'))
return redirect(url_for('.home'))
@app.route('/')
@view.route('/')
@login_required
def home():
"""
Home page
"""
if bui.standalone:
return redirect(url_for('clients'))
if view.bui.standalone:
return redirect(url_for('.clients'))
else:
return redirect(url_for('servers'))
return redirect(url_for('.servers'))

View file

@ -5,13 +5,13 @@
{% include "small_topbar.html" %}
<ul class="breadcrumb" style="margin-bottom: 5px;">
{% if server -%}
<li><a href="{{ url_for('home') }}">Home</a></li>
<li><a href="{{ url_for('clients', server=server) }}">{{ server }} clients</a></li>
<li><a href="{{ url_for('client', name=cname, server=server) }}">{{ cname }} overview</a></li>
<li><a href="{{ url_for('view.home') }}">Home</a></li>
<li><a href="{{ url_for('view.clients', server=server) }}">{{ server }} clients</a></li>
<li><a href="{{ url_for('view.client', name=cname, server=server) }}">{{ cname }} overview</a></li>
<li class="active">Backup n°{{ nbackup|mypad }} overview</li>
{% else -%}
<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('view.home') }}">Home</a></li>
<li><a href="{{ url_for('view.client', name=cname) }}">{{ cname }} overview</a></li>
<li class="active">Backup n°{{ nbackup|mypad }} overview</li>
{% endif -%}
</ul>

View file

@ -3,15 +3,15 @@
{% 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;">
<ul class="breadcrumb" style="margin-bottom: 5px;">
{% if server -%}
<li><a href="{{ url_for('home') }}">Home</a></li>
<li><a href="{{ url_for('clients', server=server) }}">{{ server }} clients</a></li>
<li><a href="{{ url_for('client', name=cname, server=server) }}">{{ cname }} overview</a></li>
<li><a href="{{ url_for('view.home') }}">Home</a></li>
<li><a href="{{ url_for('view.clients', server=server) }}">{{ server }} clients</a></li>
<li><a href="{{ url_for('view.client', name=cname, server=server) }}">{{ cname }} overview</a></li>
<li class="active">Backup n°{{ nbackup|mypad }} overview</li>
{% else -%}
<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('view.home') }}">Home</a></li>
<li><a href="{{ url_for('view.client', name=cname) }}">{{ cname }} overview</a></li>
<li class="active">Backup n°{{ nbackup|mypad }} overview</li>
{% endif -%}
</ul>
@ -24,7 +24,7 @@
<input type="text" class="form-control" placeholder="filter..." name="search-tree" autocomplete="off">
<div class="input-group-btn">
<button class="btn btn-default dropdown-toggle" data-toggle="dropdown" type="button">
<span class="glyphicon glyphicon-cog"></span> options
<span class="glyphicon glyphicon-cog"></span> options
<span class="caret"></span>
</button>
<ul class="dropdown-menu browse">

View file

@ -5,11 +5,11 @@
{% include "small_topbar.html" %}
<ul class="breadcrumb" style="margin-bottom: 5px;">
{% if server -%}
<li><a href="{{ url_for('home') }}">Home</a></li>
<li><a href="{{ url_for('clients', server=server) }}">{{ server }} clients</a></li>
<li><a href="{{ url_for('view.home') }}">Home</a></li>
<li><a href="{{ url_for('view.clients', server=server) }}">{{ server }} clients</a></li>
<li class="active">{{ cname }} overview</li>
{% else -%}
<li><a href="{{ url_for('home') }}">Home</a></li>
<li><a href="{{ url_for('view.home') }}">Home</a></li>
<li class="active">{{ cname }} overview</li>
{% endif -%}
</ul>

View file

@ -5,11 +5,11 @@
{% include "small_topbar.html" %}
<ul class="breadcrumb" style="margin-bottom: 5px;">
{% if server -%}
<li><a href="{{ url_for('home') }}">Home</a></li>
<li><a href="{{ url_for('clients', server=server) }}">{{ server }} clients</a></li>
<li><a href="{{ url_for('view.home') }}">Home</a></li>
<li><a href="{{ url_for('view.clients', server=server) }}">{{ server }} clients</a></li>
<li class="active">{{ cname }} overview</li>
{% else -%}
<li><a href="{{ url_for('home') }}">Home</a></li>
<li><a href="{{ url_for('view.home') }}">Home</a></li>
<li class="active">{{ cname }} overview</li>
{% endif -%}
</ul>

View file

@ -5,7 +5,7 @@
{% include "small_topbar.html" %}
<ul class="breadcrumb" style="margin-bottom: 5px;">
{% if server -%}
<li><a href="{{ url_for('home') }}">Home</a></li>
<li><a href="{{ url_for('view.home') }}">Home</a></li>
<li class="active">{{ server }} clients</li>
{% else -%}
<li class="active">Home</li>

View file

@ -5,7 +5,7 @@
{% include "small_topbar.html" %}
<ul class="breadcrumb" style="margin-bottom: 5px;">
{% if server -%}
<li><a href="{{ url_for('home') }}">Home</a></li>
<li><a href="{{ url_for('view.home') }}">Home</a></li>
<li class="active">{{ server }} clients</li>
{% else -%}
<li class="active">Home</li>

View file

@ -64,7 +64,7 @@ var _check_running = function() {
/***
* _clients_bh: Bloodhound object used for the autocompletion of the input field
*/
var _clients_bh = new Bloodhound({
var _clients_bh = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
limit: 10,
@ -135,7 +135,7 @@ $('#input-client').typeahead({
{% endif -%}
{% endfor -%}
).on('typeahead:selected', function(obj, datum, name) {
window.location = '{{ url_for("client") }}?name='+datum.name+'&server='+name;
window.location = '{{ url_for("view.client") }}?name='+datum.name+'&server='+name;
});
{% endif -%}
{% endif -%}
@ -245,7 +245,7 @@ $(function() {
var search = $('input[id="input-client"]');
search.keypress(function(e) {
if (e.which == 13) {
window.location = '{{ url_for("client", server=server) }}?name='+search.val();
window.location = '{{ url_for("view.client", server=server) }}?name='+search.val();
}
});
{% endif -%}

View file

@ -52,7 +52,7 @@ var _client_table = $('#table-client').dataTable( {
},
columns: [
{ data: null, render: function ( data, type, row ) {
return '<a href="{{ url_for("client_browse", name=cname, server=server) }}?backup='+data.number+(data.encrypted?'&encrypted=1':'')+'" style="color: inherit; text-decoration: inherit;">'+pad(data.number, 7)+'</a>';
return '<a href="{{ url_for("view.client_browse", name=cname, server=server) }}?backup='+data.number+(data.encrypted?'&encrypted=1':'')+'" style="color: inherit; text-decoration: inherit;">'+pad(data.number, 7)+'</a>';
}
},
{ data: 'date' },

View file

@ -69,7 +69,7 @@ var _clients_table = $('#table-clients').dataTable( {
},
columns: [
{ data: null, render: function ( data, type, row ) {
return '<a href="{{ url_for("client", server=server) }}?name='+data.name+'" style="color: inherit; text-decoration: inherit;">'+data.name+'</a>';
return '<a href="{{ url_for("view.client", server=server) }}?name='+data.name+'" style="color: inherit; text-decoration: inherit;">'+data.name+'</a>';
}
},
{ data: 'state' },

View file

@ -7,12 +7,12 @@ _parse_live_result = function(data, serv) {
$.each(data.results, function(i, c) {
if (c instanceof String || typeof c == 'string') {
{% if server -%}
u = '{{ url_for("render_live_tpl", server=server) }}?name='+c;
u = '{{ url_for("view.render_live_tpl", server=server) }}?name='+c;
{% else -%}
if (serv) {
u = '{{ url_for("render_live_tpl") }}?name='+c+'&server='+serv;
u = '{{ url_for("view.render_live_tpl") }}?name='+c+'&server='+serv;
} else {
u = '{{ url_for("render_live_tpl") }}?name='+c;
u = '{{ url_for("view.render_live_tpl") }}?name='+c;
}
{% endif -%}
$.get(u, function(d) {
@ -24,12 +24,12 @@ _parse_live_result = function(data, serv) {
$.each(c, function(j, a) {
$.each(a, function(k, cl) {
{% if server -%}
u = '{{ url_for("render_live_tpl", server=server) }}?name='+cl;
u = '{{ url_for("view.render_live_tpl", server=server) }}?name='+cl;
{% else -%}
if (serv) {
u = '{{ url_for("render_live_tpl") }}?name='+cl+'&server='+serv;
u = '{{ url_for("view.render_live_tpl") }}?name='+cl+'&server='+serv;
} else {
u = '{{ url_for("render_live_tpl") }}?name='+cl;
u = '{{ url_for("view.render_live_tpl") }}?name='+cl;
}
{% endif -%}
$.get(u, function(d) {
@ -57,9 +57,9 @@ _live = function() {
});
});
{% if server -%}
redirect = '{{ url_for("home", server=server) }}';
redirect = '{{ url_for("view.home", server=server) }}';
{% else -%}
redirect = '{{ url_for("home") }}';
redirect = '{{ url_for("view.home") }}';
{% endif -%}
if (!html) {
document.location = redirect;
@ -78,9 +78,9 @@ _live = function() {
html += _parse_live_result(data);
});
{% if server -%}
redirect = '{{ url_for("home", server=server) }}';
redirect = '{{ url_for("view.home", server=server) }}';
{% else -%}
redirect = '{{ url_for("home") }}';
redirect = '{{ url_for("view.home") }}';
{% endif -%}
if (!html) {
document.location = redirect;

View file

@ -11,7 +11,7 @@
var _servers_table = $('#table-servers').dataTable( {
responsive: true,
ajax: {
url: '{{ api.url_for(ServersStats) }}',
url: '{{ url_for("api.servers_stats") }}',
dataSrc: function (data) {
if (!data.results) {
if (data.notif) {
@ -33,7 +33,7 @@ var _servers_table = $('#table-servers').dataTable( {
},
columns: [
{ data: null, render: function ( data, type, row ) {
href = '{{ url_for("clients") }}?server='+data.name;
href = '{{ url_for("view.clients") }}?server='+data.name;
if (!data.alive) {
href = '#';
}

View file

@ -300,7 +300,7 @@ app.controller('ConfigCtrl', function($scope, $http) {
/* A client has been selected, we redirect to the client config page */
$scope.selectClient = function(selected, select) {
select.search = undefined;
document.location = '{{ url_for("settings", server=server) }}?client='+selected.name;
document.location = '{{ url_for("view.settings", server=server) }}?client='+selected.name;
};
$scope.undoAdd = function(type) {
$scope.add[type] = false;

View file

@ -2,7 +2,7 @@
{% block body %}
<div class="main">
<ul class="breadcrumb" style="margin-bottom: 5px;">
<li><a href="{{ url_for('home') }}">Home</a></li>
<li><a href="{{ url_for('view.home') }}">Home</a></li>
<li class="active">Live monitor</li>
</ul>
<div class="row" id="live-container">

View file

@ -63,7 +63,7 @@
{# Renders WTForm in bootstrap way. There are two ways to call function:
- as macros: it will render all field forms using cycle to iterate over them
- as call: it will insert form fields as you specify:
e.g. {% call macros.render_form(form, action_url=url_for('login_view'), action_text='Login',
e.g. {% call macros.render_form(form, action_url=url_for('view.login_view'), action_text='Login',
class_='login-form') %}
{{ macros.render_field(form.email, placeholder='Input email', type='email') }}
{{ macros.render_field(form.password, placeholder='Input password', type='password') }}

View file

@ -5,7 +5,7 @@
{% include "small_topbar.html" %}
<ul class="breadcrumb" style="margin-bottom: 5px;">
{% if server -%}
<li><a href="{{ url_for('home') }}">Home</a></li>
<li><a href="{{ url_for('view.home') }}">Home</a></li>
<li class="active">{{ server }} Burp Configuration</li>
{% else -%}
<li class="active">Burp Configuration</li>
@ -22,7 +22,7 @@
</div>
<div id="settings-panel" class="form-container" style="display:none;">
<form class="form-horizontal" action="{{ url_for('settings', server=server) }}" method="POST" ng-submit="submit($event)" name="setSettings" onbeforeunload>
<form class="form-horizontal" action="{{ url_for('view.settings', server=server) }}" method="POST" ng-submit="submit($event)" name="setSettings" onbeforeunload>
{# From here, the jinja syntax is escaped because we use the angularjs syntax #}
{% raw %}
<fieldset>

View file

@ -5,26 +5,26 @@
<ul class="nav nav-sidebar">
<li {% if overview %}class="active"{% endif %}>
{% if backup %}
<a href="{{ url_for('client_browse', name=cname, server=server) }}?backup={{ nbackup }}"><span class="glyphicon glyphicon-th"></span>&nbsp;Overview</a>
<a href="{{ url_for('view.client_browse', name=cname, server=server) }}?backup={{ nbackup }}"><span class="glyphicon glyphicon-th"></span>&nbsp;Overview</a>
{% elif client %}
<a href="{{ url_for('client', name=cname, server=server) }}"><span class="glyphicon glyphicon-th"></span>&nbsp;Overview</a>
<a href="{{ url_for('view.client', name=cname, server=server) }}"><span class="glyphicon glyphicon-th"></span>&nbsp;Overview</a>
{% elif clients %}
<a href="{{ url_for('clients', server=server) }}"><span class="glyphicon glyphicon-th"></span>&nbsp;Overview</a>
<a href="{{ url_for('view.clients', server=server) }}"><span class="glyphicon glyphicon-th"></span>&nbsp;Overview</a>
{% elif servers %}
<a href="{{ url_for('servers') }}"><span class="glyphicon glyphicon-th"></span>&nbsp;Overview</a>
<a href="{{ url_for('view.servers') }}"><span class="glyphicon glyphicon-th"></span>&nbsp;Overview</a>
{% else %}
<a href="#"><span class="glyphicon glyphicon-th"></span>&nbsp;Overview</a>
{% endif %}
</li>
<li {% if report %}class="active"{% endif %}>
{% if client and not backup %}
<a href="{{ url_for('client_report', name=cname, server=server) }}"><span class="glyphicon glyphicon-stats"></span>&nbsp;Reports</a>
<a href="{{ url_for('view.client_report', name=cname, server=server) }}"><span class="glyphicon glyphicon-stats"></span>&nbsp;Reports</a>
{% elif clients %}
<a href="{{ url_for('clients_report', server=server) }}"><span class="glyphicon glyphicon-stats"></span>&nbsp;Reports</a>
<a href="{{ url_for('view.clients_report', server=server) }}"><span class="glyphicon glyphicon-stats"></span>&nbsp;Reports</a>
{% elif backup %}
<a href="{{ url_for('backup_report', name=cname, backup=nbackup, server=server) }}"><span class="glyphicon glyphicon-stats"></span>&nbsp;Reports</a>
<a href="{{ url_for('view.backup_report', name=cname, backup=nbackup, server=server) }}"><span class="glyphicon glyphicon-stats"></span>&nbsp;Reports</a>
{% elif servers %}
<a href="{{ url_for('servers') }}"><span class="glyphicon glyphicon-stats"></span>&nbsp;Reports</a>
<a href="{{ url_for('view.servers') }}"><span class="glyphicon glyphicon-stats"></span>&nbsp;Reports</a>
{% else %}
<a href="#"><span class="glyphicon glyphicon-stats"></span>&nbsp;Reports</a>
{% endif %}

View file

@ -1,24 +1,24 @@
{% if not settings -%}
<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, server=server) }}?backup={{ nbackup }}"><span class="glyphicon glyphicon-th"></span>&nbsp;Overview</a>
<a class="btn btn-default {% if overview %}active{% endif %}" href="{{ url_for('view.client_browse', name=cname, server=server) }}?backup={{ nbackup }}"><span class="glyphicon glyphicon-th"></span>&nbsp;Overview</a>
{% elif client -%}
<a class="btn btn-default {% if overview %}active{% endif %}" href="{{ url_for('client', name=cname, server=server) }}"><span class="glyphicon glyphicon-th"></span>&nbsp;Overview</a>
<a class="btn btn-default {% if overview %}active{% endif %}" href="{{ url_for('view.client', name=cname, server=server) }}"><span class="glyphicon glyphicon-th"></span>&nbsp;Overview</a>
{% elif clients -%}
<a class="btn btn-default {% if overview %}active{% endif %}" href="{{ url_for('clients', server=server) }}"><span class="glyphicon glyphicon-th"></span>&nbsp;Overview</a>
<a class="btn btn-default {% if overview %}active{% endif %}" href="{{ url_for('view.clients', server=server) }}"><span class="glyphicon glyphicon-th"></span>&nbsp;Overview</a>
{% elif servers -%}
<a class="btn btn-default {% if overview %}active{% endif %}" href="{{ url_for('servers') }}"><span class="glyphicon glyphicon-th"></span>&nbsp;Overview</a>
<a class="btn btn-default {% if overview %}active{% endif %}" href="{{ url_for('view.servers') }}"><span class="glyphicon glyphicon-th"></span>&nbsp;Overview</a>
{% else -%}
<a class="btn btn-default {% if overview %}active{% endif %}" href="#"><span class="glyphicon glyphicon-th"></span>&nbsp;Overview</a>
{% endif -%}
{% if client and not backup -%}
<a class="btn btn-default {% if report %}active{% endif %}" href="{{ url_for('client_report', name=cname, server=server) }}"><span class="glyphicon glyphicon-stats"></span>&nbsp;Reports</a>
<a class="btn btn-default {% if report %}active{% endif %}" href="{{ url_for('view.client_report', name=cname, server=server) }}"><span class="glyphicon glyphicon-stats"></span>&nbsp;Reports</a>
{% elif clients -%}
<a class="btn btn-default {% if report %}active{% endif %}" href="{{ url_for('clients_report', server=server) }}"><span class="glyphicon glyphicon-stats"></span>&nbsp;Reports</a>
<a class="btn btn-default {% if report %}active{% endif %}" href="{{ url_for('view.clients_report', server=server) }}"><span class="glyphicon glyphicon-stats"></span>&nbsp;Reports</a>
{% elif servers -%}
<a class="btn btn-default {% if report %}active{% endif %}" href="{{ url_for('servers') }}"><span class="glyphicon glyphicon-stats"></span>&nbsp;Reports</a>
<a class="btn btn-default {% if report %}active{% endif %}" href="{{ url_for('view.servers') }}"><span class="glyphicon glyphicon-stats"></span>&nbsp;Reports</a>
{% elif backup -%}
<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>&nbsp;Reports</a>
<a class="btn btn-default {% if report %}active{% endif %}" href="{{ url_for('view.backup_report', name=cname, backup=nbackup, server=server) }}"><span class="glyphicon glyphicon-stats"></span>&nbsp;Reports</a>
{% else -%}
<a class="btn btn-default {% if report %}active{% endif %}" href="#"><span class="glyphicon glyphicon-stats"></span>&nbsp;Reports</a>
{% endif -%}

View file

@ -7,25 +7,25 @@
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{{ url_for('home') }}">Burp Server Dashboard</a>
<a class="navbar-brand" href="{{ url_for('view.home') }}">Burp Server Dashboard</a>
</div>
{% if not login -%}
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
{% if not config.STANDALONE -%}
<li class="detail {% if not server %}active{% endif %}"><a href="{{ url_for('home') }}"><span class="glyphicon glyphicon-hdd"></span><span class="dtl">&nbsp;Servers</span></a></li>
<li class="detail {% if not server %}active{% endif %}"><a href="{{ url_for('view.home') }}"><span class="glyphicon glyphicon-hdd"></span><span class="dtl">&nbsp;Servers</span></a></li>
{% if server -%}
<li class="detail{% if clients %} active{% endif %}"><a href="{{ url_for('clients', server=server) }}"><span class="glyphicon glyphicon-tasks"></span><span class="dtl">&nbsp;Clients</span></a></li>
<li class="detail{% if clients %} active{% endif %}"><a href="{{ url_for('view.clients', server=server) }}"><span class="glyphicon glyphicon-tasks"></span><span class="dtl">&nbsp;Clients</span></a></li>
{% endif -%}
{% else -%}
<li class="detail{% if clients %} active{% endif %}"><a href="{{ url_for('home') }}"><span class="glyphicon glyphicon-tasks"></span><span class="dtl">&nbsp;Clients</span></a></li>
<li class="detail{% if clients %} active{% endif %}"><a href="{{ url_for('view.home') }}"><span class="glyphicon glyphicon-tasks"></span><span class="dtl">&nbsp;Clients</span></a></li>
{% endif -%}
{% if config.STANDALONE or server -%}
<li class="detail{% if settings %} active{% endif %}"><a href="{{ url_for('settings', server=server) }}"><span class="glyphicon glyphicon-wrench"></span><span class="dtl">&nbsp;Settings</span></a></li>
<li class="detail{% if settings %} active{% endif %}"><a href="{{ url_for('view.settings', server=server) }}"><span class="glyphicon glyphicon-wrench"></span><span class="dtl">&nbsp;Settings</span></a></li>
{% endif -%}
<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">&nbsp;Live monitor</span></a></li>
<li class="detail{% if live %} active{% endif %}"><a href="{{ url_for('view.live_monitor', server=server) }}"><span id="toblink" class="glyphicon glyphicon-screenshot"></span><span class="dtl">&nbsp;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">&nbsp;Logout<small>({{ current_user.name }})</small></span></a></li>
<li class="detail"><a href="{{ url_for('view.logout') }}"><span class="glyphicon glyphicon-log-out"></span><span class="dtl">&nbsp;Logout<small>({{ current_user.name }})</small></span></a></li>
{% endif -%}
<li><a id="refresh" href="#"><span class="glyphicon glyphicon-refresh"></span><span class="hidden-md hidden-lg">&nbsp;Refresh</span></a></li>
</ul>