Changelog: https://roxy-wi.org/changelog#7.0.0
pull/364/head
Aidaho 2023-10-01 00:38:22 +03:00
parent 9ec2cd3c8f
commit 9f022fb614
14 changed files with 224 additions and 220 deletions

View File

@ -1,19 +1,16 @@
import uuid
import distro
from datetime import datetime, timedelta
from flask import render_template, request, redirect, url_for, flash, make_response
from flask_login import login_user, login_required, logout_user, current_user
from flask_login import login_required, logout_user, current_user
from app import app, login_manager, cache
import app.modules.db.sql as sql
import app.modules.server.server as server_mod
import app.modules.roxywi.common as roxywi_common
import app.modules.roxywi.auth as roxywi_auth
import app.modules.roxywi.roxy as roxy
import app.modules.roxy_wi_tools as roxy_wi_tools
@app.before_request
@cache.memoize(2)
def check_login():
if request.endpoint not in ('login_page', 'static', 'main.show_roxywi_version'):
try:
@ -21,13 +18,13 @@ def check_login():
except Exception:
return redirect(url_for('login_page'))
if user_params is None:
make_response(redirect(url_for('login_page')))
if not sql.is_user_active(user_params['user_id']):
return redirect(url_for('login_page'))
try:
roxywi_auth.check_login(user_params['user_uuid'], user_params['token'])
except Exception:
make_response(redirect(url_for('login_page')))
return redirect(url_for('login_page'))
@login_manager.user_loader
@ -53,6 +50,7 @@ def redirect_to_login(response):
@app.route('/login', methods=['GET', 'POST'])
def login_page():
roxy.update_plan()
next_url = request.args.get('next') or request.form.get('next')
login = request.form.get('login')
password = request.form.get('pass')
@ -62,89 +60,31 @@ def login_page():
if next_url is None:
next_url = ''
try:
groups = sql.select_groups(id=user_groups)
for g in groups:
if g[0] == int(user_groups):
user_group = g[1]
except Exception:
user_group = ''
try:
if distro.id() == 'ubuntu':
if os.path.exists('/etc/apt/auth.conf.d/roxy-wi.conf'):
cmd = "grep login /etc/apt/auth.conf.d/roxy-wi.conf |awk '{print $2}'"
get_user_name, stderr = server_mod.subprocess_execute(cmd)
user_name = get_user_name[0]
else:
user_name = 'git'
else:
if os.path.exists('/etc/yum.repos.d/roxy-wi.repo'):
cmd = "grep base /etc/yum.repos.d/roxy-wi.repo |awk -F\":\" '{print $2}'|awk -F\"/\" '{print $3}'"
get_user_name, stderr = server_mod.subprocess_execute(cmd)
user_name = get_user_name[0]
else:
user_name = 'git'
if sql.select_user_name():
sql.update_user_name(user_name)
else:
sql.insert_user_name(user_name)
except Exception as e:
roxywi_common.logging('Cannot update subscription: ', str(e), roxywi=1)
try:
session_ttl = int(sql.get_setting('session_ttl'))
except Exception:
session_ttl = 5
expires = datetime.utcnow() + timedelta(days=session_ttl)
if login and password:
users = sql.select_users(user=login)
for user in users:
if user.activeuser == 0:
flash('Your login is disabled', 'alert alert-danger wrong-login')
return 'Your login is disabled', 200
if user.ldap_user == 1:
if login in user.username:
print(str(user.groups))
if roxywi_auth.check_in_ldap(login, password):
login_user(user)
resp = make_response(next_url or url_for('overview.index'))
resp.set_cookie('uuid', user_uuid, secure=True, expires=expires.strftime("%a, %d %b %Y %H:%M:%S GMT"))
resp.set_cookie('group', str(user.groups), secure=True, expires=expires.strftime("%a, %d %b %Y %H:%M:%S GMT"))
role = int(user.role)
user1 = user.username
user_uuid, user_token = roxywi_auth.create_uuid_and_token(login)
return roxywi_auth.do_login(user_uuid, str(user.groups), user, next_url)
else:
passwordHashed = roxy_wi_tools.Tools.get_hash(password)
if login in user.username and passwordHashed == user.password:
user_uuid = str(uuid.uuid4())
user_token = str(uuid.uuid4())
sql.write_user_uuid(login, user_uuid)
sql.write_user_token(login, user_token)
hashed_password = roxy_wi_tools.Tools.get_hash(password)
if login in user.username and hashed_password == user.password:
role = int(user.role)
user1 = user.username
login_user(user)
resp = make_response(next_url or url_for('overview.index'))
try:
resp.set_cookie('uuid', user_uuid, secure=True, expires=expires.strftime("%a, %d %b %Y %H:%M:%S GMT"))
resp.set_cookie('group', str(user.groups), secure=True, expires=expires.strftime("%a, %d %b %Y %H:%M:%S GMT"))
except Exception as e:
print(e)
try:
user_name = sql.get_user_name_by_uuid(user_uuid)
roxywi_common.logging('Roxy-WI server', f' user: {user_name}, group: {user_group} login', roxywi=1)
except Exception:
pass
return resp
user_uuid, user_token = roxywi_auth.create_uuid_and_token(login)
return roxywi_auth.do_login(user_uuid, str(user.groups), user, next_url)
else:
flash('Login or password is not correct', 'alert alert-danger wrong-login')
return 'Login or password is not correct'
else:
return 'ban', 200
else:
flash('Login or password is not correct', 'alert alert-danger wrong-login')
try:
lang = roxywi_common.get_user_lang_for_flask()

View File

@ -382,6 +382,15 @@ def select_users(**kwargs):
return query_res
def is_user_active(user_id: int) -> int:
try:
query = User.get(User.user_id == user_id).activeuser
except Exception as e:
out_error(e)
else:
return int(query)
def select_user_groups(user_id, **kwargs):
if kwargs.get("limit") is not None:
query = UserGroups.select().where(UserGroups.user_id == user_id).limit(1)

View File

@ -1,97 +1,138 @@
from flask import request, abort
import uuid
from flask import request, abort, make_response, url_for
from flask_login import login_user
from datetime import datetime, timedelta
import modules.db.sql as sql
import app.modules.roxywi.common as roxywi_common
def check_login(user_uuid, token, **kwargs) -> str:
if user_uuid is None:
return 'login_page'
if user_uuid is None:
return 'login_page'
try:
sql.delete_old_uuid()
except Exception as e:
raise Exception(f'error: cannot connect to DB {e}')
try:
sql.delete_old_uuid()
except Exception as e:
raise Exception(f'error: cannot connect to DB {e}')
if user_uuid is not None:
if sql.get_user_name_by_uuid(user_uuid) is None:
return 'login_page'
if kwargs.get('service'):
required_service = str(kwargs.get('service'))
user_id = sql.get_user_id_by_uuid(user_uuid)
user_services = sql.select_user_services(user_id)
if required_service in user_services:
return 'ok'
else:
return 'index'
if user_uuid is not None:
if sql.get_user_name_by_uuid(user_uuid) is None:
return 'login_page'
if kwargs.get('service'):
required_service = str(kwargs.get('service'))
user_id = sql.get_user_id_by_uuid(user_uuid)
user_services = sql.select_user_services(user_id)
if required_service in user_services:
return 'ok'
else:
return 'overview.index'
try:
ip = request.remote_addr
except Exception:
ip = ''
try:
ip = request.remote_addr
except Exception:
ip = ''
sql.update_last_act_user(user_uuid, token, ip)
sql.update_last_act_user(user_uuid, token, ip)
return 'login_page'
return 'login_page'
def is_admin(level=1, **kwargs):
if kwargs.get('role_id'):
role = kwargs.get('role_id')
else:
user_id = request.cookies.get('uuid')
group_id = request.cookies.get('group')
if kwargs.get('role_id'):
role = kwargs.get('role_id')
else:
user_id = request.cookies.get('uuid')
group_id = request.cookies.get('group')
try:
role = sql.get_user_role_by_uuid(user_id, group_id)
except Exception:
role = 4
pass
try:
return True if int(role) <= int(level) else False
except Exception:
return False
try:
role = sql.get_user_role_by_uuid(user_id, group_id)
except Exception:
role = 4
pass
try:
return True if int(role) <= int(level) else False
except Exception:
return False
def page_for_admin(level=1) -> None:
if not is_admin(level=level):
return abort(400, 'bad permission')
if not is_admin(level=level):
return abort(400, 'bad permission')
def check_in_ldap(user, password):
import ldap
import ldap
server = sql.get_setting('ldap_server')
port = sql.get_setting('ldap_port')
ldap_class_search = sql.get_setting('ldap_class_search')
root_user = sql.get_setting('ldap_user')
root_password = sql.get_setting('ldap_password')
ldap_base = sql.get_setting('ldap_base')
ldap_search_field = sql.get_setting('ldap_search_field')
ldap_user_attribute = sql.get_setting('ldap_user_attribute')
ldap_type = sql.get_setting('ldap_type')
server = sql.get_setting('ldap_server')
port = sql.get_setting('ldap_port')
ldap_class_search = sql.get_setting('ldap_class_search')
root_user = sql.get_setting('ldap_user')
root_password = sql.get_setting('ldap_password')
ldap_base = sql.get_setting('ldap_base')
ldap_search_field = sql.get_setting('ldap_search_field')
ldap_user_attribute = sql.get_setting('ldap_user_attribute')
ldap_type = sql.get_setting('ldap_type')
ldap_proto = 'ldap' if ldap_type == "0" else 'ldaps'
ldap_proto = 'ldap' if ldap_type == "0" else 'ldaps'
ldap_bind = ldap.initialize('{}://{}:{}/'.format(ldap_proto, server, port))
try:
ldap_bind.protocol_version = ldap.VERSION3
ldap_bind.set_option(ldap.OPT_REFERRALS, 0)
ldap_bind = ldap.initialize('{}://{}:{}/'.format(ldap_proto, server, port))
try:
ldap_bind.protocol_version = ldap.VERSION3
ldap_bind.set_option(ldap.OPT_REFERRALS, 0)
bind = ldap_bind.simple_bind_s(root_user, root_password)
bind = ldap_bind.simple_bind_s(root_user, root_password)
criteria = "(&(objectClass=" + ldap_class_search + ")(" + ldap_user_attribute + "=" + user + "))"
attributes = [ldap_search_field]
result = ldap_bind.search_s(ldap_base, ldap.SCOPE_SUBTREE, criteria, attributes)
criteria = "(&(objectClass=" + ldap_class_search + ")(" + ldap_user_attribute + "=" + user + "))"
attributes = [ldap_search_field]
result = ldap_bind.search_s(ldap_base, ldap.SCOPE_SUBTREE, criteria, attributes)
bind = ldap_bind.simple_bind_s(result[0][0], password)
except ldap.INVALID_CREDENTIALS:
return False
except ldap.SERVER_DOWN:
raise Exception('error: LDAP server is down')
except ldap.LDAPError as e:
if type(e.message) == dict and 'desc' in e.message:
raise Exception(f'error: {e.message["desc"]}')
else:
raise Exception (f'error: {e}')
else:
return True
bind = ldap_bind.simple_bind_s(result[0][0], password)
except ldap.INVALID_CREDENTIALS:
return False
except ldap.SERVER_DOWN:
raise Exception('error: LDAP server is down')
except ldap.LDAPError as e:
if type(e.message) == dict and 'desc' in e.message:
raise Exception(f'error: {e.message["desc"]}')
else:
raise Exception (f'error: {e}')
else:
return True
def create_uuid_and_token(login: str):
user_uuid = str(uuid.uuid4())
user_token = str(uuid.uuid4())
sql.write_user_uuid(login, user_uuid)
sql.write_user_token(login, user_token)
return user_uuid, user_token
def do_login(user_uuid: str, user_group: str, user: str, next_url: str):
try:
session_ttl = int(sql.get_setting('session_ttl'))
except Exception:
session_ttl = 5
expires = datetime.utcnow() + timedelta(days=session_ttl)
login_user(user)
resp = make_response(next_url or url_for('overview.index'))
resp.set_cookie('uuid', user_uuid, secure=True, expires=expires.strftime("%a, %d %b %Y %H:%M:%S GMT"))
resp.set_cookie('group', str(user_group), secure=True, expires=expires.strftime("%a, %d %b %Y %H:%M:%S GMT"))
try:
user_group_name = sql.get_group_name_by_id(user_group)
except Exception:
user_group_name = ''
try:
user_name = sql.get_user_name_by_uuid(user_uuid)
roxywi_common.logging('Roxy-WI server', f' user: {user_name}, group: {user_group_name} login', roxywi=1)
except Exception as e:
print(f'error: {e}')
return resp

View File

@ -1,9 +1,8 @@
import os
import cgi
import glob
import distro
from flask import request, redirect, make_response, url_for
from flask import request
import modules.db.sql as sql
import modules.roxy_wi_tools as roxy_wi_tools
@ -120,7 +119,7 @@ def logging(server_ip: str, action: str, **kwargs) -> None:
user_group = ''
try:
ip = cgi.escape(os.environ["REMOTE_ADDR"])
ip = request.remote_addr
except Exception:
ip = ''
@ -220,27 +219,24 @@ def get_users_params(**kwargs):
user_uuid = request.cookies.get('uuid')
user = sql.get_user_name_by_uuid(user_uuid)
except Exception:
make_response(redirect(url_for('login_page')))
return
raise Exception('error: Cannot get user UUID')
try:
group_id = int(request.cookies.get('group'))
except Exception:
make_response(redirect(url_for('login_page')))
return
raise Exception('error: Cannot get user group')
try:
role = sql.get_user_role_by_uuid(user_uuid, group_id)
except Exception:
make_response(redirect(url_for('login_page')))
return
raise Exception('error: Cannot get user role')
try:
user_id = sql.get_user_id_by_uuid(user_uuid)
user_services = sql.select_user_services(user_id)
token = sql.get_token(user_uuid)
except Exception:
make_response(redirect(url_for('login_page')))
return
raise Exception('error: Cannot get user token')
if kwargs.get('virt') and kwargs.get('haproxy'):
servers = get_dick_permit(virt=1, haproxy=1)
@ -264,7 +260,8 @@ def get_users_params(**kwargs):
'token': token,
'servers': servers,
'user_services': user_services,
'lang': user_lang
'lang': user_lang,
'user_id': user_id
}
return user_params

View File

@ -1,12 +1,14 @@
import os
import re
import distro
import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
import modules.db.sql as sql
import modules.roxywi.common as roxywi_common
import app.modules.server.server as server_mod
def is_docker() -> bool:
@ -34,7 +36,7 @@ def versions():
current_ver_without_dots += '0'
current_ver_without_dots = int(current_ver_without_dots)
except Exception:
current_ver = "Sorry cannot get current version"
current_ver = "Cannot get current version"
current_ver_without_dots = 0
try:
@ -100,3 +102,25 @@ def action_service(action: str, service: str) -> str:
os.system(cmd)
roxywi_common.logging('Roxy-WI server', f' The service {service} has been {action}ed', roxywi=1, login=1)
return 'ok'
def update_plan():
try:
if distro.id() == 'ubuntu':
path_to_repo = '/etc/apt/auth.conf.d/roxy-wi.conf'
cmd = "grep login /etc/apt/auth.conf.d/roxy-wi.conf |awk '{print $2}'"
else:
path_to_repo = '/etc/yum.repos.d/roxy-wi.repo'
cmd = "grep base /etc/yum.repos.d/roxy-wi.repo |awk -F\":\" '{print $2}'|awk -F\"/\" '{print $3}'"
if os.path.exists(path_to_repo):
get_user_name, stderr = server_mod.subprocess_execute(cmd)
user_name = get_user_name[0]
else:
user_name = 'git'
if sql.select_user_name():
sql.update_user_name(user_name)
else:
sql.insert_user_name(user_name)
except Exception as e:
roxywi_common.logging('Cannot update subscription: ', str(e), roxywi=1)

View File

@ -291,8 +291,7 @@ def show_version(service, server_ip, configver, save):
stderr = config_mod.master_slave_upload_and_restart(server_ip, configver, save_action, service)
return render_template(
'configver.html',
h2=1, role=user_params['role'], user=user, select_id="serv", serv=server_ip, aftersave=aftersave,
'configver.html', role=user_params['role'], user=user, select_id="serv", serv=server_ip, aftersave=aftersave,
selects=servers, stderr=stderr, save=save, configver=configver, service=service,
user_services=user_params['user_services'], token=user_params['token'], lang=user_params['lang']
)

View File

@ -1,5 +1,6 @@
import os
import datetime
from flask import render_template, request, redirect, url_for
from flask_login import login_required
@ -39,7 +40,6 @@ def logs_internal():
time_storage = sql.get_setting('log_time_storage')
log_path = get_config.get_config_var('main', 'log_path')
selects = roxywi_common.get_files(log_path, file_format="log")
try:
time_storage_hours = time_storage * 24
@ -49,8 +49,10 @@ def logs_internal():
file_modified = datetime.datetime.fromtimestamp(os.path.getmtime(curpath))
if datetime.datetime.now() - file_modified > datetime.timedelta(hours=time_storage_hours):
os.remove(curpath)
except Exception:
pass
except Exception as e:
print(f'error: cannot delete old log files: {e}')
selects = roxywi_common.get_files(log_path, file_format="log")
if log_type is None:
selects.append(['fail2ban.log', 'fail2ban.log'])
@ -58,7 +60,7 @@ def logs_internal():
selects.append(['roxy-wi.access.log', 'access.log'])
return render_template(
'logs_internal.html', h2=1, autorefresh=1, role=user_params['role'], user=user,
'logs_internal.html', autorefresh=1, role=user_params['role'], user=user,
user_services=user_params['user_services'], token=user_params['token'], lang=user_params['lang'],
selects=selects, serv='viewlogs'
)

View File

@ -60,7 +60,7 @@ def stats(service, serv):
return redirect(url_for('overview.index'))
return render_template(
'statsview.html', h2=1, autorefresh=1, role=user_params['role'], user=user, selects=servers, serv=serv,
'statsview.html', autorefresh=1, role=user_params['role'], user=user, selects=servers, serv=serv,
service=service, user_services=user_params['user_services'], token=user_params['token'],
select_id="serv", lang=user_params['lang'], service_desc=service_desc
)

View File

@ -27,9 +27,9 @@ def index():
groups = sql.select_groups()
return render_template(
'ovw.html', h2=1, autorefresh=1, role=user_params['role'], user=user, groups=groups,
roles=sql.select_roles(), servers=user_params['servers'], user_services=user_params['user_services'],
roxy_wi_log=roxy_logs.roxy_wi_log(), token=user_params['token'], guide_me=1, lang=user_params['lang']
'ovw.html', autorefresh=1, role=user_params['role'], user=user, groups=groups, roles=sql.select_roles(),
servers=user_params['servers'], user_services=user_params['user_services'], roxy_wi_log=roxy_logs.roxy_wi_log(),
token=user_params['token'], guide_me=1, lang=user_params['lang']
)

View File

@ -41,7 +41,7 @@ def portscanner():
user_subscription = roxywi_common.return_user_subscription()
return render_template(
'portscanner.html', h2=1, autorefresh=0, role=user_params['role'], user=user, servers=user_params['servers'],
'portscanner.html', autorefresh=0, role=user_params['role'], user=user, servers=user_params['servers'],
port_scanner_settings=port_scanner_settings, count_ports=count_ports, port_scanner=''.join(port_scanner),
port_scanner_stderr=port_scanner_stderr, user_services=user_params['user_services'], user_status=user_subscription['user_status'],
user_plan=user_subscription['user_plan'], token=user_params['token'], lang=user_params['lang']

View File

@ -15,7 +15,7 @@ def before_request():
pass
@bp.route('/')
@bp.route('')
def runtimeapi():
try:
user_params = roxywi_common.get_users_params(haproxy=1)

View File

@ -103,9 +103,9 @@ def smon_history():
return redirect(url_for('login_page'))
return render_template(
'smon/history.html', h2=1, autorefresh=0, role=user_params['role'], user=user, smon=smon,
lang=user_params['lang'], user_status=user_subscription['user_status'], user_plan=user_subscription['user_plan'],
token=user_params['token'], smon_status=smon_status, smon_error=stderr, user_services=user_params['user_services']
'smon/history.html', autorefresh=0, role=user_params['role'], user=user, smon=smon, lang=user_params['lang'],
user_status=user_subscription['user_status'], user_plan=user_subscription['user_plan'], token=user_params['token'],
smon_status=smon_status, smon_error=stderr, user_services=user_params['user_services']
)
@ -126,7 +126,7 @@ def smon_host_history(server_ip):
return redirect(url_for('login_page'))
return render_template(
'smon/history.html', h2=1, autorefresh=0, role=user_params['role'], user=user, smon=smon,
'smon/history.html', autorefresh=0, role=user_params['role'], user=user, smon=smon,
lang=user_params['lang'], user_status=user_subscription['user_status'], user_plan=user_subscription['user_plan'],
token=user_params['token'], smon_status=smon_status, smon_error=stderr, user_services=user_params['user_services']
)
@ -169,7 +169,7 @@ def smon_admin():
return redirect(url_for('login_page'))
return render_template(
'smon/add.html', h2=1, autorefresh=0, role=user_params['role'], user=user, smon=smon, lang=user_params['lang'],
'smon/add.html', autorefresh=0, role=user_params['role'], user=user, smon=smon, lang=user_params['lang'],
user_status=user_subscription['user_status'], user_plan=user_subscription['user_plan'], token=user_params['token'],
smon_status=smon_status, smon_error=stderr, user_services=user_params['user_services'], telegrams=telegrams,
slacks=slacks, pds=pds, smon_ping=smon_ping, smon_tcp=smon_tcp, smon_http=smon_http, smon_dns=smon_dns

View File

@ -50,12 +50,11 @@ def waf(service):
autorefresh = 1
return render_template(
'waf.html',
h2=1, title=title, autorefresh=autorefresh, role=user_params['role'], user=user_params['user'], serv=serv,
servers=servers_waf,
servers_all=servers, manage_rules=manage_rules, rules=rules, user_services=user_params['user_services'],
waf_rule_file=waf_rule_file, waf_rule_id=waf_rule_id, config=config_read, cfg=cfg, token=user_params['token'],
config_file_name=config_file_name, service=service, lang=user_params['lang']
'waf.html', title=title, autorefresh=autorefresh, role=user_params['role'], user=user_params['user'], serv=serv,
servers=servers_waf, servers_all=servers, manage_rules=manage_rules, rules=rules,
user_services=user_params['user_services'], waf_rule_file=waf_rule_file, waf_rule_id=waf_rule_id,
config=config_read, cfg=cfg, token=user_params['token'], config_file_name=config_file_name, service=service,
lang=user_params['lang']
)
@ -82,12 +81,11 @@ def waf_rules(service, server_ip):
roxywi_auth.check_login(user_params['user_uuid'], user_params['token'], service=1)
return render_template(
'waf.html',
h2=1, title=title, autorefresh=0, role=user_params['role'], user=user_params['user'], serv=server_ip,
servers=servers_waf,
servers_all=servers, manage_rules=manage_rules, rules=rules, user_services=user_params['user_services'],
waf_rule_file=waf_rule_file, waf_rule_id=waf_rule_id, config=config_read, cfg=cfg, token=user_params['token'],
config_file_name=config_file_name, service=service, lang=user_params['lang']
'waf.html', title=title, autorefresh=0, role=user_params['role'], user=user_params['user'], serv=server_ip,
servers=servers_waf, servers_all=servers, manage_rules=manage_rules, rules=rules,
user_services=user_params['user_services'], waf_rule_file=waf_rule_file, waf_rule_id=waf_rule_id,
config=config_read, cfg=cfg, token=user_params['token'], config_file_name=config_file_name, service=service,
lang=user_params['lang']
)
@ -125,12 +123,10 @@ def waf_rule_edit(service, server_ip, rule_id):
print('Cannot read imported config file')
return render_template(
'waf.html',
h2=1, title=title, autorefresh=0, role=user_params['role'], user=user_params['user'], serv=server_ip,
servers=servers_waf,
servers_all=servers, manage_rules=manage_rules, rules=rules, user_services=user_params['user_services'],
waf_rule_file=waf_rule_file, waf_rule_id=rule_id, config=config_read, cfg=cfg, token=user_params['token'],
config_file_name=config_file_name, service=service, lang=user_params['lang']
'waf.html', title=title, autorefresh=0, role=user_params['role'], user=user_params['user'], serv=server_ip,
servers=servers_waf, servers_all=servers, manage_rules=manage_rules, rules=rules,
user_services=user_params['user_services'], waf_rule_file=waf_rule_file, waf_rule_id=rule_id, config=config_read,
cfg=cfg, token=user_params['token'], config_file_name=config_file_name, service=service, lang=user_params['lang']
)

View File

@ -206,26 +206,24 @@
</div>
</div>
<div class="container">
{% if h2 %}
<h2>
{% block h2 %}{% endblock %}
{% include 'include/login.html' %}
{% if autorefresh %}
<span class="auto-refresh">
<a onclick="pauseAutoRefresh()" class="auto-refresh-pause" style="display: none; margin-top: 3px; position: absolute;"></a>
<a onclick="pauseAutoResume()" class="auto-refresh-resume" style="display: none; margin-top: 4px; position: absolute;"></a>
<span id="0" class="auto-refresh-span">
<span class="auto-refresh-reload auto-refresh-reload-icon"></span>
{{lang.words.auto|title()}}-{{lang.words.refresh}}
</span>
<span id="1" style="display: none;" class="auto-refresh-span">
<span class="auto-refresh-reload auto-refresh-reload-icon"></span>
{{lang.words.auto|title()}}-{{lang.words.refresh}}
</span>
</span>
{% endif %}
</h2>
{% endif %}
<h2>
{% block h2 %}{% endblock %}
{% include 'include/login.html' %}
{% if autorefresh %}
<span class="auto-refresh">
<a onclick="pauseAutoRefresh()" class="auto-refresh-pause" style="display: none; margin-top: 3px; position: absolute;"></a>
<a onclick="pauseAutoResume()" class="auto-refresh-resume" style="display: none; margin-top: 4px; position: absolute;"></a>
<span id="0" class="auto-refresh-span">
<span class="auto-refresh-reload auto-refresh-reload-icon"></span>
{{lang.words.auto|title()}}-{{lang.words.refresh}}
</span>
<span id="1" style="display: none;" class="auto-refresh-span">
<span class="auto-refresh-reload auto-refresh-reload-icon"></span>
{{lang.words.auto|title()}}-{{lang.words.refresh}}
</span>
</span>
{% endif %}
</h2>
{% if autorefresh %}
<div class="auto-refresh-div">
<div class="auto-refresh-head">
@ -266,9 +264,7 @@
</div>
</div>
{% endif %}
{% if h2 %}
<ul id='browse_histroy'></ul>
{% endif %}
<ul id='browse_histroy'></ul>
{% if role %}
{% if role <= 2 %}
<div id="apply" style="display: none;">