Allow CTFd to run with script_root != '/' and PostgreSQL (#125)

Also, Add WSGI config example
This commit is contained in:
Robert Blair Mason Jr
2016-06-22 00:18:09 -04:00
committed by Kevin Chung
parent a9b79770f8
commit 6b2257236f
37 changed files with 291 additions and 264 deletions

View File

@@ -4,6 +4,7 @@ from CTFd.models import db, Teams, Solves, Awards, Containers, Challenges, Wrong
from itsdangerous import TimedSerializer, BadTimeSignature from itsdangerous import TimedSerializer, BadTimeSignature
from sqlalchemy.sql import and_, or_, not_ from sqlalchemy.sql import and_, or_, not_
from sqlalchemy.sql.expression import union_all from sqlalchemy.sql.expression import union_all
from sqlalchemy.sql.functions import coalesce
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
from socket import inet_aton, inet_ntoa from socket import inet_aton, inet_ntoa
from passlib.hash import bcrypt_sha256 from passlib.hash import bcrypt_sha256
@@ -18,6 +19,8 @@ import json
import datetime import datetime
import calendar import calendar
from scoreboard import get_standings
admin = Blueprint('admin', __name__) admin = Blueprint('admin', __name__)
@@ -276,12 +279,12 @@ def delete_container(container_id):
def new_container(): def new_container():
name = request.form.get('name') name = request.form.get('name')
if set(name) <= set('abcdefghijklmnopqrstuvwxyz0123456789-_'): if set(name) <= set('abcdefghijklmnopqrstuvwxyz0123456789-_'):
return redirect('/admin/containers') return redirect(url_for('admin.list_container'))
buildfile = request.form.get('buildfile') buildfile = request.form.get('buildfile')
files = request.files.getlist('files[]') files = request.files.getlist('files[]')
create_image(name=name, buildfile=buildfile, files=files) create_image(name=name, buildfile=buildfile, files=files)
run_image(name) run_image(name)
return redirect('/admin/containers') return redirect(url_for('admin.list_container'))
@@ -291,7 +294,7 @@ def admin_chals():
if request.method == 'POST': if request.method == 'POST':
chals = Challenges.query.add_columns('id', 'name', 'value', 'description', 'category', 'hidden').order_by(Challenges.value).all() chals = Challenges.query.add_columns('id', 'name', 'value', 'description', 'category', 'hidden').order_by(Challenges.value).all()
teams_with_points = db.session.query(Solves.teamid, Teams.name).join(Teams).filter( teams_with_points = db.session.query(Solves.teamid).join(Teams).filter(
Teams.banned == False).group_by( Teams.banned == False).group_by(
Solves.teamid).count() Solves.teamid).count()
@@ -427,7 +430,7 @@ def admin_teams(page):
page_start = results_per_page * ( page - 1 ) page_start = results_per_page * ( page - 1 )
page_end = results_per_page * ( page - 1 ) + results_per_page page_end = results_per_page * ( page - 1 ) + results_per_page
teams = Teams.query.slice(page_start, page_end).all() teams = Teams.query.order_by(Teams.id.asc()).slice(page_start, page_end).all()
count = db.session.query(db.func.count(Teams.id)).first()[0] count = db.session.query(db.func.count(Teams.id)).first()[0]
pages = int(count / results_per_page) + (count % results_per_page > 0) pages = int(count / results_per_page) + (count % results_per_page > 0)
return render_template('admin/teams.html', teams=teams, pages=pages, curr_page=page) return render_template('admin/teams.html', teams=teams, pages=pages, curr_page=page)
@@ -442,7 +445,9 @@ def admin_team(teamid):
solves = Solves.query.filter_by(teamid=teamid).all() solves = Solves.query.filter_by(teamid=teamid).all()
solve_ids = [s.chalid for s in solves] solve_ids = [s.chalid for s in solves]
missing = Challenges.query.filter( not_(Challenges.id.in_(solve_ids) ) ).all() missing = Challenges.query.filter( not_(Challenges.id.in_(solve_ids) ) ).all()
addrs = Tracking.query.filter_by(team=teamid).order_by(Tracking.date.desc()).group_by(Tracking.ip).all() addrs = db.session.query(Tracking.ip, db.func.max(Tracking.date)) \
.filter_by(team=teamid) \
.group_by(Tracking.ip).all()
wrong_keys = WrongKeys.query.filter_by(teamid=teamid).order_by(WrongKeys.date.asc()).all() wrong_keys = WrongKeys.query.filter_by(teamid=teamid).order_by(WrongKeys.date.asc()).all()
awards = Awards.query.filter_by(teamid=teamid).order_by(Awards.date.asc()).all() awards = Awards.query.filter_by(teamid=teamid).order_by(Awards.date.asc()).all()
score = user.score() score = user.score()
@@ -452,10 +457,12 @@ def admin_team(teamid):
elif request.method == 'POST': elif request.method == 'POST':
admin_user = request.form.get('admin', None) admin_user = request.form.get('admin', None)
if admin_user: if admin_user:
admin_user = 1 if admin_user == "true" else 0 admin_user = True if admin_user == 'true' else False
user.admin = admin_user user.admin = admin_user
# Set user.banned to hide admins from scoreboard
user.banned = admin_user user.banned = admin_user
db.session.commit() db.session.commit()
db.session.close()
return jsonify({'data': ['success']}) return jsonify({'data': ['success']})
name = request.form.get('name', None) name = request.form.get('name', None)
@@ -545,35 +552,21 @@ def admin_graph(graph_type):
json_data['categories'].append({'category':category, 'count':count}) json_data['categories'].append({'category':category, 'count':count})
return jsonify(json_data) return jsonify(json_data)
elif graph_type == "solves": elif graph_type == "solves":
solves = Solves.query.join(Teams).filter(Teams.banned == False).add_columns(db.func.count(Solves.chalid)).group_by(Solves.chalid).all() solves_sub = db.session.query(Solves.chalid, db.func.count(Solves.chalid).label('solves_cnt')) \
.join(Teams, Solves.teamid == Teams.id).filter(Teams.banned == False) \
.group_by(Solves.chalid).subquery()
solves = db.session.query(solves_sub.columns.chalid, solves_sub.columns.solves_cnt, Challenges.name) \
.join(Challenges, solves_sub.columns.chalid == Challenges.id).all()
json_data = {} json_data = {}
for chal, count in solves: for chal, count, name in solves:
json_data[chal.chal.name] = count json_data[name] = count
return jsonify(json_data) return jsonify(json_data)
@admin.route('/admin/scoreboard') @admin.route('/admin/scoreboard')
@admins_only @admins_only
def admin_scoreboard(): def admin_scoreboard():
score = db.func.sum(Challenges.value).label('score') standings = get_standings(admin=True)
scores = db.session.query(Solves.teamid.label('teamid'), Teams.name.label('name'), Teams.banned.label('banned'), score, Solves.date.label('date')) \
.join(Teams) \
.join(Challenges) \
.group_by(Solves.teamid)
awards = db.session.query(Teams.id.label('teamid'), Teams.name.label('name'), Teams.banned.label('banned'),
db.func.sum(Awards.value).label('score'), Awards.date.label('date')) \
.filter(Teams.id == Awards.teamid) \
.group_by(Teams.id)
results = union_all(scores, awards).alias('results')
standings = db.session.query(results.columns.teamid, results.columns.name, results.columns.banned,
db.func.sum(results.columns.score).label('score')) \
.group_by(results.columns.teamid) \
.order_by(db.func.sum(results.columns.score).desc(), db.func.max(results.columns.date)) \
.all()
db.session.close()
return render_template('admin/scoreboard.html', teams=standings) return render_template('admin/scoreboard.html', teams=standings)
@@ -711,8 +704,17 @@ def admin_stats():
wrong_count = db.session.query(db.func.count(WrongKeys.id)).first()[0] wrong_count = db.session.query(db.func.count(WrongKeys.id)).first()[0]
solve_count = db.session.query(db.func.count(Solves.id)).first()[0] solve_count = db.session.query(db.func.count(Solves.id)).first()[0]
challenge_count = db.session.query(db.func.count(Challenges.id)).first()[0] challenge_count = db.session.query(db.func.count(Challenges.id)).first()[0]
most_solved_chal = Solves.query.add_columns(db.func.count(Solves.chalid).label('solves')).group_by(Solves.chalid).order_by('solves DESC').first()
least_solved_chal = Challenges.query.add_columns(db.func.count(Solves.chalid).label('solves')).outerjoin(Solves).group_by(Challenges.id).order_by('solves ASC').first() solves_raw = db.func.count(Solves.chalid).label('solves_raw')
solves_sub = db.session.query(Solves.chalid, solves_raw) \
.group_by(Solves.chalid).subquery()
solves_cnt = coalesce(solves_sub.columns.solves_raw, 0).label('solves_cnt')
most_solved_chal = Challenges.query.add_columns(solves_cnt) \
.outerjoin(solves_sub, solves_sub.columns.chalid == Challenges.id) \
.order_by(solves_cnt.desc()).first()
least_solved_chal = Challenges.query.add_columns(solves_cnt) \
.outerjoin(solves_sub, solves_sub.columns.chalid == Challenges.id) \
.order_by(solves_cnt.asc()).first()
db.session.close() db.session.close()

View File

@@ -172,4 +172,4 @@ def login():
def logout(): def logout():
if authed(): if authed():
session.clear() session.clear()
return redirect('/') return redirect(url_for('views.static_html'))

View File

@@ -20,7 +20,7 @@ def challenges_view():
if view_after_ctf(): if view_after_ctf():
pass pass
else: else:
return redirect('/') return redirect(url_for('views.static_html'))
if get_config('verify_emails') and not is_verified(): if get_config('verify_emails') and not is_verified():
return redirect(url_for('auth.confirm_user')) return redirect(url_for('auth.confirm_user'))
if can_view_challenges(): if can_view_challenges():
@@ -36,7 +36,7 @@ def chals():
if view_after_ctf(): if view_after_ctf():
pass pass
else: else:
return redirect('/') return redirect(url_for('views.static_html'))
if can_view_challenges(): if can_view_challenges():
chals = Challenges.query.filter(or_(Challenges.hidden != True, Challenges.hidden == None)).add_columns('id', 'name', 'value', 'description', 'category').order_by(Challenges.value).all() chals = Challenges.query.filter(or_(Challenges.hidden != True, Challenges.hidden == None)).add_columns('id', 'name', 'value', 'description', 'category').order_by(Challenges.value).all()
@@ -56,10 +56,13 @@ def chals():
@challenges.route('/chals/solves') @challenges.route('/chals/solves')
def chals_per_solves(): def chals_per_solves():
if can_view_challenges(): if can_view_challenges():
solves = Solves.query.join(Teams, Solves.teamid == Teams.id).filter(Teams.banned == False).add_columns(db.func.count(Solves.chalid)).group_by(Solves.chalid).all() solves_sub = db.session.query(Solves.chalid, db.func.count(Solves.chalid).label('solves')).join(Teams, Solves.teamid == Teams.id).filter(Teams.banned == False).group_by(Solves.chalid).subquery()
solves = db.session.query(solves_sub.columns.chalid, solves_sub.columns.solves, Challenges.name) \
.join(Challenges, solves_sub.columns.chalid == Challenges.id).all()
json = {} json = {}
for chal, count in solves: for chal, count, name in solves:
json[chal.chal.name] = count json[name] = count
db.session.close()
return jsonify(json) return jsonify(json)
return redirect(url_for('auth.login', next='chals/solves')) return redirect(url_for('auth.login', next='chals/solves'))

View File

@@ -180,7 +180,7 @@ class Solves(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
chalid = db.Column(db.Integer, db.ForeignKey('challenges.id')) chalid = db.Column(db.Integer, db.ForeignKey('challenges.id'))
teamid = db.Column(db.Integer, db.ForeignKey('teams.id')) teamid = db.Column(db.Integer, db.ForeignKey('teams.id'))
ip = db.Column(db.Integer) ip = db.Column(db.BigInteger)
flag = db.Column(db.Text) flag = db.Column(db.Text)
date = db.Column(db.DateTime, default=datetime.datetime.utcnow) date = db.Column(db.DateTime, default=datetime.datetime.utcnow)
team = db.relationship('Teams', foreign_keys="Solves.teamid", lazy='joined') team = db.relationship('Teams', foreign_keys="Solves.teamid", lazy='joined')

View File

@@ -5,31 +5,37 @@ from sqlalchemy.sql.expression import union_all
scoreboard = Blueprint('scoreboard', __name__) scoreboard = Blueprint('scoreboard', __name__)
def get_standings(admin=False, count=None):
score = db.func.sum(Challenges.value).label('score')
date = db.func.max(Solves.date).label('date')
scores = db.session.query(Solves.teamid.label('teamid'), score, date).join(Challenges).group_by(Solves.teamid)
awards = db.session.query(Awards.teamid.label('teamid'), db.func.sum(Awards.value).label('score'), db.func.max(Awards.date).label('date')) \
.group_by(Awards.teamid)
results = union_all(scores, awards).alias('results')
sumscores = db.session.query(results.columns.teamid, db.func.sum(results.columns.score).label('score'), db.func.max(results.columns.date).label('date')) \
.group_by(results.columns.teamid).subquery()
if admin:
standings_query = db.session.query(Teams.id.label('teamid'), Teams.name.label('name'), Teams.banned, sumscores.columns.score) \
.join(sumscores, Teams.id == sumscores.columns.teamid) \
.order_by(sumscores.columns.score.desc(), sumscores.columns.date)
else:
standings_query = db.session.query(Teams.id.label('teamid'), Teams.name.label('name'), sumscores.columns.score) \
.join(sumscores, Teams.id == sumscores.columns.teamid) \
.filter(Teams.banned == False) \
.order_by(sumscores.columns.score.desc(), sumscores.columns.date)
if count is not None:
standings = standings_query.all()
else:
standings = standings_query.limit(count).all()
db.session.close()
return standings
@scoreboard.route('/scoreboard') @scoreboard.route('/scoreboard')
def scoreboard_view(): def scoreboard_view():
if get_config('view_scoreboard_if_authed') and not authed(): if get_config('view_scoreboard_if_authed') and not authed():
return redirect(url_for('auth.login', next=request.path)) return redirect(url_for('auth.login', next=request.path))
score = db.func.sum(Challenges.value).label('score') standings = get_standings()
scores = db.session.query(Solves.teamid.label('teamid'), Teams.name.label('name'), score, Solves.date.label('date')) \
.join(Teams) \
.join(Challenges) \
.filter(Teams.banned == False) \
.group_by(Solves.teamid)
awards = db.session.query(Teams.id.label('teamid'), Teams.name.label('name'),
db.func.sum(Awards.value).label('score'), Awards.date.label('date')) \
.filter(Teams.id == Awards.teamid) \
.group_by(Teams.id)
results = union_all(scores, awards).alias('results')
standings = db.session.query(results.columns.teamid, results.columns.name,
db.func.sum(results.columns.score).label('score')) \
.group_by(results.columns.teamid) \
.order_by(db.func.sum(results.columns.score).desc(), db.func.max(results.columns.date)) \
.all()
db.session.close()
return render_template('scoreboard.html', teams=standings) return render_template('scoreboard.html', teams=standings)
@@ -37,25 +43,7 @@ def scoreboard_view():
def scores(): def scores():
if get_config('view_scoreboard_if_authed') and not authed(): if get_config('view_scoreboard_if_authed') and not authed():
return redirect(url_for('auth.login', next=request.path)) return redirect(url_for('auth.login', next=request.path))
score = db.func.sum(Challenges.value).label('score') standings = get_standings()
scores = db.session.query(Solves.teamid.label('teamid'), Teams.name.label('name'), score, Solves.date.label('date')) \
.join(Teams) \
.join(Challenges) \
.filter(Teams.banned == False) \
.group_by(Solves.teamid)
awards = db.session.query(Teams.id.label('teamid'), Teams.name.label('name'), db.func.sum(Awards.value).label('score'), Awards.date.label('date'))\
.filter(Teams.id==Awards.teamid)\
.group_by(Teams.id)
results = union_all(scores, awards).alias('results')
standings = db.session.query(results.columns.teamid, results.columns.name, db.func.sum(results.columns.score).label('score'))\
.group_by(results.columns.teamid)\
.order_by(db.func.sum(results.columns.score).desc(), db.func.max(results.columns.date))\
.all()
db.session.close()
json = {'standings':[]} json = {'standings':[]}
for i, x in enumerate(standings): for i, x in enumerate(standings):
json['standings'].append({'pos':i+1, 'id':x.teamid, 'team':x.name,'score':int(x.score)}) json['standings'].append({'pos':i+1, 'id':x.teamid, 'team':x.name,'score':int(x.score)})
@@ -74,26 +62,7 @@ def topteams(count):
count = 10 count = 10
json = {'scores':{}} json = {'scores':{}}
standings = get_standings(count=count)
score = db.func.sum(Challenges.value).label('score')
scores = db.session.query(Solves.teamid.label('teamid'), Teams.name.label('name'), score, Solves.date.label('date')) \
.join(Teams) \
.join(Challenges) \
.filter(Teams.banned == False) \
.group_by(Solves.teamid)
awards = db.session.query(Teams.id.label('teamid'), Teams.name.label('name'),
db.func.sum(Awards.value).label('score'), Awards.date.label('date')) \
.filter(Teams.id == Awards.teamid) \
.group_by(Teams.id)
results = union_all(scores, awards).alias('results')
standings = db.session.query(results.columns.teamid, results.columns.name,
db.func.sum(results.columns.score).label('score')) \
.group_by(results.columns.teamid) \
.order_by(db.func.sum(results.columns.score).desc(), db.func.max(results.columns.date)) \
.limit(count).all()
for team in standings: for team in standings:
solves = Solves.query.filter_by(teamid=team.teamid).all() solves = Solves.query.filter_by(teamid=team.teamid).all()

View File

@@ -46,7 +46,7 @@ function loadchal(id, update) {
} }
function submitkey(chal, key) { function submitkey(chal, key) {
$.post("/admin/chal/" + chal, { $.post(script_root + "/admin/chal/" + chal, {
key: key, key: key,
nonce: $('#nonce').val() nonce: $('#nonce').val()
}, function (data) { }, function (data) {
@@ -55,7 +55,7 @@ function submitkey(chal, key) {
} }
function loadkeys(chal){ function loadkeys(chal){
$.get('/admin/keys/' + chal, function(data){ $.get(script_root + '/admin/keys/' + chal, function(data){
$('#keys-chal').val(chal); $('#keys-chal').val(chal);
keys = $.parseJSON(JSON.stringify(data)); keys = $.parseJSON(JSON.stringify(data));
keys = keys['keys']; keys = keys['keys'];
@@ -84,7 +84,7 @@ function updatekeys(){
$('#current-keys input[name*="key_type"]:checked').each(function(){ $('#current-keys input[name*="key_type"]:checked').each(function(){
vals.push($(this).val()); vals.push($(this).val());
}) })
$.post('/admin/keys/'+chal, {'keys':keys, 'vals':vals, 'nonce': $('#nonce').val()}) $.post(script_root + '/admin/keys/'+chal, {'keys':keys, 'vals':vals, 'nonce': $('#nonce').val()})
loadchal(chal, true) loadchal(chal, true)
$('#update-keys').modal('hide'); $('#update-keys').modal('hide');
} }
@@ -93,7 +93,7 @@ function loadtags(chal){
$('#tags-chal').val(chal) $('#tags-chal').val(chal)
$('#current-tags').empty() $('#current-tags').empty()
$('#chal-tags').empty() $('#chal-tags').empty()
$.get('/admin/tags/'+chal, function(data){ $.get(script_root + '/admin/tags/'+chal, function(data){
tags = $.parseJSON(JSON.stringify(data)) tags = $.parseJSON(JSON.stringify(data))
tags = tags['tags'] tags = tags['tags']
for (var i = 0; i < tags.length; i++) { for (var i = 0; i < tags.length; i++) {
@@ -108,11 +108,11 @@ function loadtags(chal){
} }
function deletetag(tagid){ function deletetag(tagid){
$.post('/admin/tags/'+tagid+'/delete', {'nonce': $('#nonce').val()}); $.post(script_root + '/admin/tags/'+tagid+'/delete', {'nonce': $('#nonce').val()});
} }
function deletechal(chalid){ function deletechal(chalid){
$.post('/admin/chal/delete', {'nonce':$('#nonce').val(), 'id':chalid}); $.post(script_root + '/admin/chal/delete', {'nonce':$('#nonce').val(), 'id':chalid});
} }
function updatetags(){ function updatetags(){
@@ -121,13 +121,13 @@ function updatetags(){
$('#chal-tags > span > span').each(function(i, e){ $('#chal-tags > span > span').each(function(i, e){
tags.push($(e).text()) tags.push($(e).text())
}); });
$.post('/admin/tags/'+chal, {'tags':tags, 'nonce': $('#nonce').val()}) $.post(script_root + '/admin/tags/'+chal, {'tags':tags, 'nonce': $('#nonce').val()})
loadchal(chal) loadchal(chal)
} }
function loadfiles(chal){ function loadfiles(chal){
$('#update-files form').attr('action', '/admin/files/'+chal) $('#update-files form').attr('action', script_root+'/admin/files/'+chal)
$.get('/admin/files/' + chal, function(data){ $.get(script_root + '/admin/files/' + chal, function(data){
$('#files-chal').val(chal) $('#files-chal').val(chal)
files = $.parseJSON(JSON.stringify(data)); files = $.parseJSON(JSON.stringify(data));
files = files['files'] files = files['files']
@@ -141,7 +141,7 @@ function loadfiles(chal){
} }
function deletefile(chal, file, elem){ function deletefile(chal, file, elem){
$.post('/admin/files/' + chal,{ $.post(script_root + '/admin/files/' + chal,{
'nonce': $('#nonce').val(), 'nonce': $('#nonce').val(),
'method': 'delete', 'method': 'delete',
'file': file 'file': file
@@ -155,7 +155,7 @@ function deletefile(chal, file, elem){
function loadchals(){ function loadchals(){
$('#challenges').empty(); $('#challenges').empty();
$.post("/admin/chals", { $.post(script_root + "/admin/chals", {
'nonce': $('#nonce').val() 'nonce': $('#nonce').val()
}, function (data) { }, function (data) {
categories = []; categories = [];
@@ -207,7 +207,7 @@ $('#submit-tags').click(function (e) {
$('#delete-chal form').submit(function(e){ $('#delete-chal form').submit(function(e){
e.preventDefault(); e.preventDefault();
$.post('/admin/chal/delete', $(this).serialize(), function(data){ $.post(script_root + '/admin/chal/delete', $(this).serialize(), function(data){
console.log(data) console.log(data)
if (data){ if (data){
loadchals(); loadchals();

View File

@@ -16,7 +16,7 @@ function scoregraph () {
var times = [] var times = []
var scores = [] var scores = []
var teamname = $('#team-id').text() var teamname = $('#team-id').text()
$.get('/admin/solves/'+teamid(), function( data ) { $.get(script_root + '/admin/solves/'+teamid(), function( data ) {
var solves = $.parseJSON(JSON.stringify(data)); var solves = $.parseJSON(JSON.stringify(data));
solves = solves['solves']; solves = solves['solves'];
@@ -48,7 +48,7 @@ function scoregraph () {
function keys_percentage_graph(){ function keys_percentage_graph(){
// Solves and Fails pie chart // Solves and Fails pie chart
$.get('/admin/fails/'+teamid(), function(data){ $.get(script_root + '/admin/fails/'+teamid(), function(data){
var res = $.parseJSON(JSON.stringify(data)); var res = $.parseJSON(JSON.stringify(data));
var solves = res['solves']; var solves = res['solves'];
var fails = res['fails']; var fails = res['fails'];
@@ -75,7 +75,7 @@ function keys_percentage_graph(){
} }
function category_breakdown_graph(){ function category_breakdown_graph(){
$.get('/admin/solves/'+teamid(), function(data){ $.get(script_root + '/admin/solves/'+teamid(), function(data){
var solves = $.parseJSON(JSON.stringify(data)); var solves = $.parseJSON(JSON.stringify(data));
solves = solves['solves']; solves = solves['solves'];

View File

@@ -58,7 +58,7 @@ $("#answer-input").keyup(function(event){
function submitkey(chal, key, nonce) { function submitkey(chal, key, nonce) {
$('#submit-key').addClass("disabled-button"); $('#submit-key').addClass("disabled-button");
$('#submit-key').prop('disabled', true); $('#submit-key').prop('disabled', true);
$.post("/chal/" + chal, { $.post(script_root + "/chal/" + chal, {
key: key, key: key,
nonce: nonce nonce: nonce
}, function (data) { }, function (data) {
@@ -103,7 +103,7 @@ function submitkey(chal, key, nonce) {
} }
function marksolves() { function marksolves() {
$.get('/solves', function (data) { $.get(script_root + '/solves', function (data) {
solves = $.parseJSON(JSON.stringify(data)); solves = $.parseJSON(JSON.stringify(data));
for (var i = solves['solves'].length - 1; i >= 0; i--) { for (var i = solves['solves'].length - 1; i >= 0; i--) {
id = solves['solves'][i].chalid; id = solves['solves'][i].chalid;
@@ -118,7 +118,7 @@ function marksolves() {
} }
function updatesolves(){ function updatesolves(){
$.get('/chals/solves', function (data) { $.get(script_root + '/chals/solves', function (data) {
solves = $.parseJSON(JSON.stringify(data)); solves = $.parseJSON(JSON.stringify(data));
chals = Object.keys(solves); chals = Object.keys(solves);
@@ -133,7 +133,7 @@ function updatesolves(){
} }
function getsolves(id){ function getsolves(id){
$.get('/chal/'+id+'/solves', function (data) { $.get(script_root + '/chal/'+id+'/solves', function (data) {
var teams = data['teams']; var teams = data['teams'];
var box = $('#chal-solves-names'); var box = $('#chal-solves-names');
box.empty(); box.empty();
@@ -147,8 +147,7 @@ function getsolves(id){
} }
function loadchals() { function loadchals() {
$.get(script_root + "/chals", function (data) {
$.get("/chals", function (data) {
var categories = []; var categories = [];
challenges = $.parseJSON(JSON.stringify(data)); challenges = $.parseJSON(JSON.stringify(data));

View File

@@ -1,5 +1,5 @@
function updatescores () { function updatescores () {
$.get('/scores', function( data ) { $.get(script_root + '/scores', function( data ) {
teams = $.parseJSON(JSON.stringify(data)); teams = $.parseJSON(JSON.stringify(data));
$('#scoreboard > tbody').empty() $('#scoreboard > tbody').empty()
for (var i = 0; i < teams['standings'].length; i++) { for (var i = 0; i < teams['standings'].length; i++) {
@@ -23,7 +23,7 @@ function UTCtoDate(utc){
return d; return d;
} }
function scoregraph () { function scoregraph () {
$.get('/top/10', function( data ) { $.get(script_root + '/top/10', function( data ) {
var scores = $.parseJSON(JSON.stringify(data)); var scores = $.parseJSON(JSON.stringify(data));
scores = scores['scores']; scores = scores['scores'];
if (Object.keys(scores).length == 0 ){ if (Object.keys(scores).length == 0 ){

View File

@@ -25,7 +25,7 @@ function scoregraph() {
var times = [] var times = []
var scores = [] var scores = []
var teamname = $('#team-id').text() var teamname = $('#team-id').text()
$.get('/solves/' + teamid(), function (data) { $.get(script_root + '/solves/' + teamid(), function (data) {
var solves = $.parseJSON(JSON.stringify(data)); var solves = $.parseJSON(JSON.stringify(data));
solves = solves['solves']; solves = solves['solves'];
@@ -57,7 +57,7 @@ function scoregraph() {
function keys_percentage_graph() { function keys_percentage_graph() {
// Solves and Fails pie chart // Solves and Fails pie chart
$.get('/fails/' + teamid(), function (data) { $.get(script_root + '/fails/' + teamid(), function (data) {
var res = $.parseJSON(JSON.stringify(data)); var res = $.parseJSON(JSON.stringify(data));
var solves = res['solves']; var solves = res['solves'];
var fails = res['fails']; var fails = res['fails'];
@@ -85,7 +85,7 @@ function keys_percentage_graph() {
} }
function category_breakdown_graph() { function category_breakdown_graph() {
$.get('/solves/' + teamid(), function (data) { $.get(script_root + '/solves/' + teamid(), function (data) {
var solves = $.parseJSON(JSON.stringify(data)); var solves = $.parseJSON(JSON.stringify(data));
solves = solves['solves']; solves = solves['solves'];

View File

@@ -5,15 +5,18 @@
<title>Admin Panel</title> <title>Admin Panel</title>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="/static/img/favicon.ico" type="image/x-icon"> <link rel="shortcut icon" href="{{ request.script_root }}/static/img/favicon.ico" type="image/x-icon">
<link rel="icon" href="/static/img/favicon.ico" type="image/x-icon"> <link rel="icon" href="{{ request.script_root }}/static/img/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="/static/css/vendor/bootstrap.min.css"> <link rel="stylesheet" href="{{ request.script_root }}/static/css/vendor/bootstrap.min.css">
<link rel="stylesheet" href="/static/css/vendor/font-awesome/css/font-awesome.min.css" /> <link rel="stylesheet" href="{{ request.script_root }}/static/css/vendor/font-awesome/css/font-awesome.min.css" />
<link rel="stylesheet" href="/static/css/style.css"> <link rel="stylesheet" href="{{ request.script_root }}/static/css/style.css">
<link href='/static/css/vendor/lato.css' rel='stylesheet' type='text/css'> <link href='{{ request.script_root }}/static/css/vendor/lato.css' rel='stylesheet' type='text/css'>
<link href='/static/css/vendor/raleway.css' rel='stylesheet' type='text/css'> <link href='{{ request.script_root }}/static/css/vendor/raleway.css' rel='stylesheet' type='text/css'>
<link rel="stylesheet" type="text/css" href="/static/admin/css/style.css"> <link rel="stylesheet" type="text/css" href="{{ request.script_root }}/static/admin/css/style.css">
<script src="/static/js/vendor/moment.min.js"></script> <script src="{{ request.script_root }}/static/js/vendor/moment.min.js"></script>
<script type="text/javascript">
var script_root = "{{ request.script_root }}";
</script>
{% block stylesheets %} {% endblock %} {% block stylesheets %} {% endblock %}
</head> </head>
@@ -27,20 +30,20 @@
<span class="icon-bar"></span> <span class="icon-bar"></span>
<span class="icon-bar"></span> <span class="icon-bar"></span>
</button> </button>
<a href="/" class="navbar-brand">CTFd</a> <a href="{{ request.script_root }}/" class="navbar-brand">CTFd</a>
</div> </div>
<div class="navbar-collapse collapse" aria-expanded="false" style="height: 0px"> <div class="navbar-collapse collapse" aria-expanded="false" style="height: 0px">
<ul class="nav navbar-nav navbar-nav-right"> <ul class="nav navbar-nav navbar-nav-right">
<li><a href="/admin/graphs">Graphs</a></li> <li><a href="{{ request.script_root }}/admin/graphs">Graphs</a></li>
<li><a href="/admin/pages">Pages</a></li> <li><a href="{{ request.script_root }}/admin/pages">Pages</a></li>
<li><a href="/admin/teams">Teams</a></li> <li><a href="{{ request.script_root }}/admin/teams">Teams</a></li>
<li><a href="/admin/scoreboard">Scoreboard</a></li> <li><a href="{{ request.script_root }}/admin/scoreboard">Scoreboard</a></li>
{% if can_create_container() %} {% if can_create_container() %}
<li><a href="/admin/containers">Containers</a></li> <li><a href="{{ request.script_root }}/admin/containers">Containers</a></li>
{% endif %} {% endif %}
<li><a href="/admin/chals">Challenges</a></li> <li><a href="{{ request.script_root }}/admin/chals">Challenges</a></li>
<li><a href="/admin/statistics">Statistics</a></li> <li><a href="{{ request.script_root }}/admin/statistics">Statistics</a></li>
<li><a href="/admin/config">Config</a></li> <li><a href="{{ request.script_root }}/admin/config">Config</a></li>
</ul> </ul>
</div> </div>
</div> </div>
@@ -50,9 +53,9 @@
{% block content %} {% endblock %} {% block content %} {% endblock %}
</div> </div>
</div> </div>
<script src="/static/js/vendor/jquery.min.js"></script> <script src="{{ request.script_root }}/static/js/vendor/jquery.min.js"></script>
<script src="/static/js/vendor/marked.min.js"></script> <script src="{{ request.script_root }}/static/js/vendor/marked.min.js"></script>
<script src="/static/js/vendor/bootstrap.min.js"></script> <script src="{{ request.script_root }}/static/js/vendor/bootstrap.min.js"></script>
{% block scripts %} {% endblock %} {% block scripts %} {% endblock %}
</body> </body>

View File

@@ -31,7 +31,7 @@
<h3>New Challenge</h3> <h3>New Challenge</h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form method="POST" action="/admin/chal/new" enctype="multipart/form-data"> <form method="POST" action="{{ request.script_root }}/admin/chal/new" enctype="multipart/form-data">
<div class="form-group"> <div class="form-group">
<label for="name">Name</label> <label for="name">Name</label>
<input type="text" class="form-control" name="name" placeholder="Enter challenge name"> <input type="text" class="form-control" name="name" placeholder="Enter challenge name">
@@ -105,7 +105,7 @@
<h3 class="chal-title text-center"></h3> <h3 class="chal-title text-center"></h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form method="POST" action="/admin/chal/update"> <form method="POST" action="{{ request.script_root }}/admin/chal/update">
<input name='nonce' type='hidden' value="{{ nonce }}"> <input name='nonce' type='hidden' value="{{ nonce }}">
<div class="form-group"> <div class="form-group">
@@ -168,7 +168,7 @@
<h3>Delete Challenge</h3> <h3>Delete Challenge</h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form method="POST" action="/admin/chal/delete"> <form method="POST" action="{{ request.script_root }}/admin/chal/delete">
<input type="hidden" name="nonce" value="{{ nonce }}"> <input type="hidden" name="nonce" value="{{ nonce }}">
<input type="hidden" name="id" class="chal-id"> <input type="hidden" name="id" class="chal-id">
<div class="small-6 small-centered text-center columns"> <div class="small-6 small-centered text-center columns">
@@ -190,7 +190,7 @@
<h3>Keys</h3> <h3>Keys</h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form method="POST" action="/admin/keys" style="text-align:center"> <form method="POST" action="{{ request.script_root }}/admin/keys" style="text-align:center">
<a href="#" id="create-key" class="btn btn-primary" style="margin-bottom:15px;">New Key</a> <a href="#" id="create-key" class="btn btn-primary" style="margin-bottom:15px;">New Key</a>
<input name='nonce' type='hidden' value="{{ nonce }}"> <input name='nonce' type='hidden' value="{{ nonce }}">
<input id="keys-chal" name='chal' type='hidden'> <input id="keys-chal" name='chal' type='hidden'>
@@ -212,7 +212,7 @@
<h3>Files</h3> <h3>Files</h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form method="POST" action="/admin/files/" enctype="multipart/form-data"> <form method="POST" action="{{ request.script_root }}/admin/files/" enctype="multipart/form-data">
<input name='nonce' type='hidden' value="{{ nonce }}"> <input name='nonce' type='hidden' value="{{ nonce }}">
<input id="files-chal" name='chal' type='hidden'> <input id="files-chal" name='chal' type='hidden'>
<input name='method' type='hidden' value='upload'> <input name='method' type='hidden' value='upload'>
@@ -298,7 +298,7 @@
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
<script src="/static/js/utils.js"></script> <script src="{{ request.script_root }}/static/js/utils.js"></script>
<script src="/static/admin/js/multi-modal.js"></script> <script src="{{ request.script_root }}/static/admin/js/multi-modal.js"></script>
<script src="/static/admin/js/chalboard.js"></script> <script src="{{ request.script_root }}/static/admin/js/chalboard.js"></script>
{% endblock %} {% endblock %}

View File

@@ -9,7 +9,7 @@
aria-hidden="true">&times;</span></button> aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="container-modal-label">Create Container</h4> <h4 class="modal-title" id="container-modal-label">Create Container</h4>
</div> </div>
<form method="POST" action="/admin/containers/new" enctype="multipart/form-data"> <form method="POST" action="{{ request.script_root }}/admin/containers/new" enctype="multipart/form-data">
<div class="modal-body"> <div class="modal-body">
<div class="form-group"> <div class="form-group">
<label for="name">Name</label> <label for="name">Name</label>

View File

@@ -49,7 +49,7 @@
<tbody> <tbody>
{% for solve in solves %} {% for solve in solves %}
<tr> <tr>
<td class="text-center team" id="{{ solve.teamid }}"><a href="/admin/team/{{ solve.teamid }}">{{ solve.team_name }}</a> <td class="text-center team" id="{{ solve.teamid }}"><a href="{{ request.script_root }}/admin/team/{{ solve.teamid }}">{{ solve.team_name }}</a>
<td class="text-center chal" id="{{ solve.chalid }}">{{ solve.chal_name }}</td> <td class="text-center chal" id="{{ solve.chalid }}">{{ solve.chal_name }}</td>
<td class="text-center solve-time"><script>document.write( moment({{ solve.date|unix_time_millis }}).local().format('MMMM Do, h:mm:ss A'))</script></td> <td class="text-center solve-time"><script>document.write( moment({{ solve.date|unix_time_millis }}).local().format('MMMM Do, h:mm:ss A'))</script></td>
<td class="text-center">{{ solve.flag }}</td> <td class="text-center">{{ solve.flag }}</td>
@@ -61,24 +61,24 @@
{% if pages > 1 %} {% if pages > 1 %}
<div class="text-center">Page <div class="text-center">Page
<br> <br>
{% if curr_page != 1 %}<a href="/admin/correct_keys/{{ curr_page-1 }}">&lt;&lt;&lt;</a>{% endif %} {% if curr_page != 1 %}<a href="{{ request.script_root }}/admin/correct_keys/{{ curr_page-1 }}">&lt;&lt;&lt;</a>{% endif %}
{% for page in range(1, pages + 1) %} {% for page in range(1, pages + 1) %}
{% if curr_page != page %} {% if curr_page != page %}
<a href="/admin/correct_keys/{{ page }}">{{ page }}</a> <a href="{{ request.script_root }}/admin/correct_keys/{{ page }}">{{ page }}</a>
{% else %} {% else %}
<b>{{ page }}</b> <b>{{ page }}</b>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% if curr_page != pages %}<a href="/admin/correct_keys/{{ curr_page+1 }}">&gt;&gt;&gt;</a>{% endif %} {% if curr_page != pages %}<a href="{{ request.script_root }}/admin/correct_keys/{{ curr_page+1 }}">&gt;&gt;&gt;</a>{% endif %}
<a href=""> <a href="{{ request.script_root }}">
</div> </div>
{% endif %} {% endif %}
</div> </div>
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
<script src="/static/js/utils.js"></script> <script src="{{ request.script_root }}/static/js/utils.js"></script>
<script src="/static/admin/js/team.js"></script> <script src="{{ request.script_root }}/static/admin/js/team.js"></script>
<script> <script>
$('#delete-solve').click(function(e){ $('#delete-solve').click(function(e){
e.preventDefault(); e.preventDefault();
@@ -95,7 +95,7 @@
var modal = $('#confirm') var modal = $('#confirm')
modal.find('#confirm-team-name').text(team_name) modal.find('#confirm-team-name').text(team_name)
modal.find('#confirm-chal-name').text(chal_name) modal.find('#confirm-chal-name').text(chal_name)
$('#confirm form').attr('action', '/admin/solves/'+team+'/'+chal+'/delete'); $('#confirm form').attr('action', '{{ request.script_root }}/admin/solves/'+team+'/'+chal+'/delete');
$('#confirm').modal('show'); $('#confirm').modal('show');
} }

View File

@@ -1,7 +1,7 @@
{% extends "admin/base.html" %} {% extends "admin/base.html" %}
{% block stylesheets %} {% block stylesheets %}
<link rel="stylesheet" type="text/css" href="/static/css/vendor/codemirror.min.css"> <link rel="stylesheet" type="text/css" href="{{ request.script_root }}/static/css/vendor/codemirror.min.css">
<style> <style>
.row-fluid { margin: 25px; padding-bottom: 25px; } .row-fluid { margin: 25px; padding-bottom: 25px; }
</style> </style>
@@ -38,7 +38,7 @@
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
<script src="/static/js/vendor/codemirror.min.js"></script> <script src="{{ request.script_root }}/static/js/vendor/codemirror.min.js"></script>
<script> <script>
var editor = CodeMirror.fromTextArea(document.getElementById("admin-pages-editor"), { var editor = CodeMirror.fromTextArea(document.getElementById("admin-pages-editor"), {
lineNumbers: true, lineNumbers: true,
@@ -49,7 +49,7 @@
}); });
$('#page-edit').submit(function (e){ $('#page-edit').submit(function (e){
$(this).attr('action', '/admin/pages/'+$('#route').val()); $(this).attr('action', '{{ request.script_root }}/admin/pages/'+$('#route').val());
}); });
</script> </script>
{% endblock %} {% endblock %}

View File

@@ -29,7 +29,7 @@
display: block; display: block;
} }
</style> </style>
<script src="/static/js/vendor/plotly.min.js"></script> <script src="{{ request.script_root }}/static/js/vendor/plotly.min.js"></script>
<script type="text/javascript"> <script type="text/javascript">
// $.distint(array) // $.distint(array)
// Unique elements in array // Unique elements in array
@@ -59,7 +59,7 @@
} }
function solves_graph() { function solves_graph() {
$.get('/admin/graphs/solves', function(data){ $.get('{{ request.script_root }}/admin/graphs/solves', function(data){
var solves = $.parseJSON(JSON.stringify(data)); var solves = $.parseJSON(JSON.stringify(data));
var chals = []; var chals = [];
var counts = []; var counts = [];
@@ -89,7 +89,7 @@
function keys_percentage_graph(){ function keys_percentage_graph(){
// Solves and Fails pie chart // Solves and Fails pie chart
$.get('/admin/fails/all', function(data){ $.get('{{ request.script_root }}/admin/fails/all', function(data){
var res = $.parseJSON(JSON.stringify(data)); var res = $.parseJSON(JSON.stringify(data));
var solves = res['solves']; var solves = res['solves'];
var fails = res['fails']; var fails = res['fails'];
@@ -116,7 +116,7 @@
} }
function category_breakdown_graph(){ function category_breakdown_graph(){
$.get('/admin/graphs/categories', function(data){ $.get('{{ request.script_root }}/admin/graphs/categories', function(data){
res = $.parseJSON(JSON.stringify(data)); res = $.parseJSON(JSON.stringify(data));
res = res['categories'] res = res['categories']

View File

@@ -1,7 +1,7 @@
{% extends "admin/base.html" %} {% extends "admin/base.html" %}
{% block stylesheets %} {% block stylesheets %}
<link rel="stylesheet" type="text/css" href="/static/css/vendor/codemirror.min.css"> <link rel="stylesheet" type="text/css" href="{{ request.script_root }}/static/css/vendor/codemirror.min.css">
{% endblock %} {% endblock %}
{% block content %} {% block content %}
@@ -38,7 +38,7 @@
</div> </div>
<div class="col-md-3"> <div class="col-md-3">
<h3>HTML Pages <a href="/admin/pages?mode=create"><i class="fa fa-plus"></i></a></h3> <h3>HTML Pages <a href="{{ request.script_root }}/admin/pages?mode=create"><i class="fa fa-plus"></i></a></h3>
<table id="pages" class="table table-striped"> <table id="pages" class="table table-striped">
<thead> <thead>
<tr> <tr>
@@ -49,7 +49,7 @@
<tbody> <tbody>
{% for route in routes %} {% for route in routes %}
<tr name="{{ route.route }}"> <tr name="{{ route.route }}">
<td class="route-name"><a href="/admin/pages/{{ route.route }}">{{ route.route }}</a></td> <td class="route-name"><a href="{{ request.script_root }}/admin/pages/{{ route.route }}">{{ route.route }}</a></td>
<td class="text-center"><i class="fa fa-times"></i></td> <td class="text-center"><i class="fa fa-times"></i></td>
</tr> </tr>
{% endfor %} {% endfor %}
@@ -60,7 +60,7 @@
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
<script src="/static/js/vendor/codemirror.min.js"></script> <script src="{{ request.script_root }}/static/js/vendor/codemirror.min.js"></script>
<script> <script>
var editor = CodeMirror.fromTextArea(document.getElementById("pages-editor"), { var editor = CodeMirror.fromTextArea(document.getElementById("pages-editor"), {
lineNumbers: true, lineNumbers: true,
@@ -85,7 +85,7 @@ function load_confirm_modal(route){
var modal = $('#confirm') var modal = $('#confirm')
modal.find('input[name=route]').val(route) modal.find('input[name=route]').val(route)
modal.find('#confirm-route-name').text(route) modal.find('#confirm-route-name').text(route)
$('#confirm form').attr('action', '/admin/page/'+route+'/delete'); $('#confirm form').attr('action', '{{ request.script_root }}/admin/page/'+route+'/delete');
$('#confirm').modal(); $('#confirm').modal();
} }

View File

@@ -17,16 +17,16 @@
{% for team in teams %} {% for team in teams %}
<tr> <tr>
<td>{{ loop.index }}</td> <td>{{ loop.index }}</td>
<td><a href="/admin/team/{{ team.teamid }}">{{ team.name }}</a></td> <td><a href="{{ request.script_root }}/admin/team/{{ team.teamid }}">{{ team.name }}</a></td>
<td>{{ team.score }}</td> <td>{{ team.score }}</td>
<td> <td>
{% if not team.banned %} {% if not team.banned %}
<form method="POST" style="margin:0;" action="/admin/team/{{ team.teamid }}/ban"> <form method="POST" style="margin:0;" action="{{ request.script_root }}/admin/team/{{ team.teamid }}/ban">
<a onclick="$(this).parent().submit()">Ban</a> <a onclick="$(this).parent().submit()">Ban</a>
<input type="hidden" value="{{ nonce }}" name="nonce"> <input type="hidden" value="{{ nonce }}" name="nonce">
</form> </form>
{%else %} {%else %}
<form method="POST" style="margin:0;" action="/admin/team/{{ team.teamid }}/unban"> <form method="POST" style="margin:0;" action="{{ request.script_root }}/admin/team/{{ team.teamid }}/unban">
<a onclick="$(this).parent().submit()">Unban</a> <a onclick="$(this).parent().submit()">Unban</a>
<input type="hidden" value="{{ nonce }}" name="nonce"> <input type="hidden" value="{{ nonce }}" name="nonce">
</form> </form>

View File

@@ -7,11 +7,11 @@
<h1>Statistics</h1> <h1>Statistics</h1>
<h3><b>{{ team_count }}</b> teams registered</h3> <h3><b>{{ team_count }}</b> teams registered</h3>
<h3><b>{{ wrong_count }}</b> <a href="wrong_keys/1">wrong keys</a> submitted</h3> <h3><b>{{ wrong_count }}</b> <a href="{{ request.script_root }}/admin/wrong_keys/1">wrong keys</a> submitted</h3>
<h3><b>{{ solve_count }}</b> <a href="correct_keys/1">right keys</a> submitted</h3> <h3><b>{{ solve_count }}</b> <a href="{{ request.script_root }}/admin/correct_keys/1">right keys</a> submitted</h3>
<h3><b>{{ challenge_count }}</b> challenges</h3> <h3><b>{{ challenge_count }}</b> challenges</h3>
{% if most_solved %} {% if most_solved %}
<h3>Most solved: <b>{{ most_solved[0].chal.name }}</b> with {{ most_solved[1] }}</b> solves</h3> <h3>Most solved: <b>{{ most_solved[0].name }}</b> with {{ most_solved[1] }}</b> solves</h3>
{% endif %} {% endif %}
{% if least_solved %} {% if least_solved %}
<h3>Least solved: <b>{{ least_solved[0].name }}</b> with {{ least_solved[1] }}</b> solves</h3> <h3>Least solved: <b>{{ least_solved[0].name }}</b> with {{ least_solved[1] }}</b> solves</h3>

View File

@@ -22,7 +22,7 @@
<h4 class="modal-title" id="create-award-label">Create Award</h4> <h4 class="modal-title" id="create-award-label">Create Award</h4>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form id="award-create-form" method="POST" action="/admin/awards/add"> <form id="award-create-form" method="POST" action="{{ request.script_root }}/admin/awards/add">
<div class="form-group"> <div class="form-group">
<label for="award-name-input">Name</label> <label for="award-name-input">Name</label>
<input type="text" class="form-control" id="award-name-input" name="name" placeholder="Enter award name"> <input type="text" class="form-control" id="award-name-input" name="name" placeholder="Enter award name">
@@ -62,7 +62,7 @@
<h3 id="confirm-title">Delete Key</h3> <h3 id="confirm-title">Delete Key</h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form method="POST" action="/admin/chal/delete"> <form method="POST" action="{{ request.script_root }}/admin/chal/delete">
<input id="nonce" type="hidden" name="nonce" value="{{ nonce }}"> <input id="nonce" type="hidden" name="nonce" value="{{ nonce }}">
<div class="small-6 small-centered text-center columns"> <div class="small-6 small-centered text-center columns">
<p id="confirm-description"></p> <p id="confirm-description"></p>
@@ -104,8 +104,8 @@
<tbody> <tbody>
{% for addr in addrs %} {% for addr in addrs %}
<tr> <tr>
<td class="text-center">{{ addr.ip|long2ip }}</td> <td class="text-center">{{ addr[0]|long2ip }}</td>
<td class="text-center solve-time"><script>document.write( moment({{ addr.date|unix_time_millis }}).local().format('MMMM Do, h:mm:ss A'))</script></td> <td class="text-center solve-time"><script>document.write( moment({{ addr[1]|unix_time_millis }}).local().format('MMMM Do, h:mm:ss A'))</script></td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
@@ -221,10 +221,10 @@
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
<script src="/static/js/vendor/moment.min.js"></script> <script src="{{ request.script_root }}/static/js/vendor/moment.min.js"></script>
<script src="/static/js/vendor/plotly.min.js"></script> <script src="{{ request.script_root }}/static/js/vendor/plotly.min.js"></script>
<script src="/static/js/utils.js"></script> <script src="{{ request.script_root }}/static/js/utils.js"></script>
<script src="/static/admin/js/team.js"></script> <script src="{{ request.script_root }}/static/admin/js/team.js"></script>
<script> <script>
$('#delete-solve').click(function (e) { $('#delete-solve').click(function (e) {
e.preventDefault(); e.preventDefault();
@@ -270,7 +270,7 @@
description.find('#confirm-chal-name').text(chal_name); description.find('#confirm-chal-name').text(chal_name);
description = description.html() description = description.html()
var action = '/admin/solves/' + team + '/' + chal + '/delete'; var action = '{{ request.script_root }}/admin/solves/' + team + '/' + chal + '/delete';
} else if (type == 'chal-wrong') { } else if (type == 'chal-wrong') {
var title = 'Delete Wrong Key'; var title = 'Delete Wrong Key';
var description = "<span>Are you sure you want to delete " + var description = "<span>Are you sure you want to delete " +
@@ -285,12 +285,12 @@
description.find('#confirm-chal-name').text(chal_name); description.find('#confirm-chal-name').text(chal_name);
description = description.html() description = description.html()
var action = '/admin/wrong_keys/' + team + '/' + chal + '/delete'; var action = '{{ request.script_root }}/admin/wrong_keys/' + team + '/' + chal + '/delete';
} else if (type == 'award-row') { } else if (type == 'award-row') {
var title = 'Delete Award'; var title = 'Delete Award';
var description = "<span>Are you sure you want to delete the " + var description = "<span>Are you sure you want to delete the " +
"<strong>{0}</strong> award?</span>".format(chal_name); "<strong>{0}</strong> award?</span>".format(chal_name);
var action = '/admin/awards/{0}/delete'.format(chal); var action = '{{ request.script_root }}/admin/awards/{0}/delete'.format(chal);
} }
var msg = { var msg = {
@@ -323,7 +323,7 @@
description.find('#confirm-chal-name').text(chal_name); description.find('#confirm-chal-name').text(chal_name);
description = description.html() description = description.html()
var action = '/admin/solves/' + team + '/' + chal + '/solve'; var action = '{{request.script_root }}/admin/solves/' + team + '/' + chal + '/solve';
var msg = { var msg = {
title : title, title : title,

View File

@@ -62,7 +62,7 @@ input[type="checkbox"] { margin: 0px !important; position: relative; top: 5px; }
<h2 class="text-center">Edit User</h2> <h2 class="text-center">Edit User</h2>
</div> </div>
<div class="modal-body" style="padding:20px; height:525px;"> <div class="modal-body" style="padding:20px; height:525px;">
<form method="POST" action="/admin/teams/"> <form method="POST" action="{{ request.script_root }}/admin/teams/">
<input type="hidden" name="nonce" value="{{ nonce }}"> <input type="hidden" name="nonce" value="{{ nonce }}">
<input type="hidden" name="id"> <input type="hidden" name="id">
<div class="form-group"> <div class="form-group">
@@ -123,7 +123,7 @@ input[type="checkbox"] { margin: 0px !important; position: relative; top: 5px; }
{% for team in teams %} {% for team in teams %}
<tr name="{{ team.id }}"> <tr name="{{ team.id }}">
<td class="team-id">{{ team.id }}</td> <td class="team-id">{{ team.id }}</td>
<td class="team-name"><a href="/admin/team/{{ team.id }}">{{ team.name | truncate(32) }}</a> <td class="team-name"><a href="{{ request.script_root }}/admin/team/{{ team.id }}">{{ team.name | truncate(32) }}</a>
</td> </td>
<td class="team-email">{{ team.email | truncate(32) }}</td> <td class="team-email">{{ team.email | truncate(32) }}</td>
<td class="team-website">{% if team.website and team.website.startswith('http') %}<a href="{{ team.website }}">{{ team.website | truncate(32) }}</a>{% endif %} <td class="team-website">{% if team.website and team.website.startswith('http') %}<a href="{{ team.website }}">{{ team.website | truncate(32) }}</a>{% endif %}
@@ -150,15 +150,15 @@ input[type="checkbox"] { margin: 0px !important; position: relative; top: 5px; }
{% if pages > 1 %} {% if pages > 1 %}
<div class="text-center">Page <div class="text-center">Page
<br> <br>
{% if curr_page != 1 %}<a href="/admin/teams/{{ curr_page-1 }}">&lt;&lt;&lt;</a>{% endif %} {% if curr_page != 1 %}<a href="{{ request.script_root }}/admin/teams/{{ curr_page-1 }}">&lt;&lt;&lt;</a>{% endif %}
{% for page in range(1, pages + 1) %} {% for page in range(1, pages + 1) %}
{% if curr_page != page %} {% if curr_page != page %}
<a href="/admin/teams/{{ page }}">{{ page }}</a> <a href="{{ request.script_root }}/admin/teams/{{ page }}">{{ page }}</a>
{% else %} {% else %}
<b>{{ page }}</b> <b>{{ page }}</b>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% if curr_page != pages %}<a href="/admin/teams/{{ curr_page+1 }}">&gt;&gt;&gt;</a>{% endif %} {% if curr_page != pages %}<a href="{{ request.script_root }}/admin/teams/{{ curr_page+1 }}">&gt;&gt;&gt;</a>{% endif %}
</div> </div>
{% endif %} {% endif %}
</div> </div>
@@ -175,7 +175,7 @@ function load_update_modal(id, name, email, website, affiliation, country){
modal_form.find('input[name=website]').val(website) modal_form.find('input[name=website]').val(website)
modal_form.find('input[name=affiliation]').val(affiliation) modal_form.find('input[name=affiliation]').val(affiliation)
modal_form.find('input[name=country]').val(country) modal_form.find('input[name=country]').val(country)
$('#user form').attr('action', '/admin/team/'+id) $('#user form').attr('action', '{{ request.script_root }}/admin/team/'+id)
$('#user').modal("show"); $('#user').modal("show");
} }
@@ -215,7 +215,7 @@ $('.team-admin input').on('change', function(){
var nonce = $('#nonce').val() var nonce = $('#nonce').val()
console.log(admin) console.log(admin)
$.post('/admin/team/'+id, {'admin':admin, 'nonce':nonce}); $.post('{{ request.script_root }}/admin/team/'+id, {'admin':admin, 'nonce':nonce});
}) })
$('#send-user-email').click(function(e){ $('#send-user-email').click(function(e){
@@ -260,7 +260,7 @@ function load_confirm_modal(id, name){
var modal = $('#confirm') var modal = $('#confirm')
modal.find('input[name=id]').val(id) modal.find('input[name=id]').val(id)
modal.find('#confirm-team-name').text(name) modal.find('#confirm-team-name').text(name)
$('#confirm form').attr('action', '/admin/team/'+id+'/delete'); $('#confirm form').attr('action', '{{ request.script_root }}/admin/team/'+id+'/delete');
$('#confirm').modal(); $('#confirm').modal();
} }
@@ -276,7 +276,7 @@ function load_email_modal(id){
modal.find('textarea').val("") modal.find('textarea').val("")
modal.find('input[name=id]').val(id) modal.find('input[name=id]').val(id)
$('#email-user-errors').empty() $('#email-user-errors').empty()
$('#email-user form').attr('action', '/admin/team/'+id+'/mail'); $('#email-user form').attr('action', '{{ request.script_root }}/admin/team/'+id+'/mail');
$('#email-user').modal(); $('#email-user').modal();
} }

View File

@@ -56,7 +56,7 @@
<tbody> <tbody>
{% for wrong_key in wrong_keys %} {% for wrong_key in wrong_keys %}
<tr> <tr>
<td class="text-center team" id="{{ wrong_key.team }}"><a href="/admin/team/{{ wrong_key.team }}">{{ wrong_key.team_name }}</a> <td class="text-center team" id="{{ wrong_key.team }}"><a href="{{ request.script_root }}/admin/team/{{ wrong_key.team }}">{{ wrong_key.team_name }}</a>
<td class="text-center chal" id="{{ wrong_key.chalid }}">{{ wrong_key.chal_name }}</td> <td class="text-center chal" id="{{ wrong_key.chalid }}">{{ wrong_key.chal_name }}</td>
<td class="text-center solve-time"><script>document.write( moment({{ wrong_key.date|unix_time_millis }}).local().format('MMMM Do, h:mm:ss A'))</script></td> <td class="text-center solve-time"><script>document.write( moment({{ wrong_key.date|unix_time_millis }}).local().format('MMMM Do, h:mm:ss A'))</script></td>
<td class="text-center">{{ wrong_key.flag }}</td> <td class="text-center">{{ wrong_key.flag }}</td>
@@ -68,24 +68,24 @@
{% if pages > 1 %} {% if pages > 1 %}
<div class="text-center">Page <div class="text-center">Page
<br> <br>
{% if curr_page != 1 %}<a href="/admin/wrong_keys/{{ curr_page-1 }}">&lt;&lt;&lt;</a>{% endif %} {% if curr_page != 1 %}<a href="{{ request.script_root }}/admin/wrong_keys/{{ curr_page-1 }}">&lt;&lt;&lt;</a>{% endif %}
{% for page in range(1, pages + 1) %} {% for page in range(1, pages + 1) %}
{% if curr_page != page %} {% if curr_page != page %}
<a href="/admin/wrong_keys/{{ page }}">{{ page }}</a> <a href="{{ request.script_root }}/admin/wrong_keys/{{ page }}">{{ page }}</a>
{% else %} {% else %}
<b>{{ page }}</b> <b>{{ page }}</b>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% if curr_page != pages %}<a href="/admin/wrong_keys/{{ curr_page+1 }}">&gt;&gt;&gt;</a>{% endif %} {% if curr_page != pages %}<a href="{{ request.script_root }}/admin/wrong_keys/{{ curr_page+1 }}">&gt;&gt;&gt;</a>{% endif %}
<a href=""> <a href="{{ request.script_root }}">
</div> </div>
{% endif %} {% endif %}
</div> </div>
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
<script src="/static/js/utils.js"></script> <script src="{{ request.script_root }}/static/js/utils.js"></script>
<script src="/static/admin/js/team.js"></script> <script src="{{ request.script_root }}/static/admin/js/team.js"></script>
<script> <script>
$('#delete-solve').click(function (e) { $('#delete-solve').click(function (e) {
e.preventDefault(); e.preventDefault();
@@ -102,7 +102,7 @@
var modal = $('#confirm') var modal = $('#confirm')
modal.find('#confirm-team-name').text(team_name); modal.find('#confirm-team-name').text(team_name);
modal.find('#confirm-chal-name').text(chal_name); modal.find('#confirm-chal-name').text(chal_name);
$('#confirm form').attr('action', '/admin/wrong_keys/' + team + '/' + chal + '/delete'); $('#confirm form').attr('action', '{{ request.script_root }}/admin/wrong_keys/' + team + '/' + chal + '/delete');
$('#confirm').modal('show'); $('#confirm').modal('show');
} }

View File

@@ -4,16 +4,19 @@
<title>{{ ctf_name() }}</title> <title>{{ ctf_name() }}</title>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="/static/img/favicon.ico" type="image/x-icon"> <link rel="shortcut icon" href="{{ request.script_root }}/static/img/favicon.ico" type="image/x-icon">
<link rel="icon" href="/static/img/favicon.ico" type="image/x-icon"> <link rel="icon" href="{{ request.script_root }}/static/img/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="/static/css/vendor/bootstrap.min.css"> <link rel="stylesheet" href="{{ request.script_root }}/static/css/vendor/bootstrap.min.css">
<link rel="stylesheet" href="/static/css/vendor/font-awesome/css/font-awesome.min.css" /> <link rel="stylesheet" href="{{ request.script_root }}/static/css/vendor/font-awesome/css/font-awesome.min.css" />
<link href='/static/css/vendor/lato.css' rel='stylesheet' type='text/css'> <link href='{{ request.script_root }}/static/css/vendor/lato.css' rel='stylesheet' type='text/css'>
<link href='/static/css/vendor/raleway.css' rel='stylesheet' type='text/css'> <link href='{{ request.script_root }}/static/css/vendor/raleway.css' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="/static/css/style.css"> <link rel="stylesheet" href="{{ request.script_root }}/static/css/style.css">
<link rel="stylesheet" type="text/css" href="/static/user.css"> <link rel="stylesheet" type="text/css" href="{{ request.script_root }}/static/user.css">
{% block stylesheets %}{% endblock %} {% block stylesheets %}{% endblock %}
<script src="/static/js/vendor/moment.min.js"></script> <script src="{{ request.script_root }}/static/js/vendor/moment.min.js"></script>
<script type="text/javascript">
var script_root = "{{ request.script_root }}";
</script>
</head> </head>
<body> <body>
<div class="body-container"> <div class="body-container">
@@ -25,31 +28,31 @@
<span class="icon-bar"></span> <span class="icon-bar"></span>
<span class="icon-bar"></span> <span class="icon-bar"></span>
</button> </button>
<a href="/" class="navbar-brand">{{ ctf_name() }}</a> <a href="{{ request.script_root }}/" class="navbar-brand">{{ ctf_name() }}</a>
</div> </div>
<div class="navbar-collapse collapse" aria-expanded="false" style="height: 0px"> <div class="navbar-collapse collapse" aria-expanded="false" style="height: 0px">
<ul class="nav navbar-nav"> <ul class="nav navbar-nav">
{% for page in pages() %} {% for page in pages() %}
<li><a href="/{{ page.route }}">{{ page.route|title }}</a></li> <li><a href="{{ request.script_root }}/{{ page.route }}">{{ page.route|title }}</a></li>
{% endfor %} {% endfor %}
<li><a href="/teams">Teams</a></li> <li><a href="{{ request.script_root }}/teams">Teams</a></li>
<li><a href="/scoreboard">Scoreboard</a></li> <li><a href="{{ request.script_root }}/scoreboard">Scoreboard</a></li>
<li><a href="/challenges">Challenges</a></li> <li><a href="{{ request.script_root }}/challenges">Challenges</a></li>
</ul> </ul>
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
{% if username is defined %} {% if username is defined %}
{% if admin %} {% if admin %}
<li><a href="/admin">Admin</a></li> <li><a href="{{ request.script_root }}/admin">Admin</a></li>
{% endif %} {% endif %}
<li><a href="/team/{{ id }}">Team</a></li> <li><a href="{{ request.script_root }}/team/{{ id }}">Team</a></li>
<li><a href="/profile">Profile</a></li> <li><a href="{{ request.script_root }}/profile">Profile</a></li>
<li><a href="/logout">Logout</a></li> <li><a href="{{ request.script_root }}/logout">Logout</a></li>
{% else %} {% else %}
{% if can_register() %} {% if can_register() %}
<li><a href="/register">Register</a></li> <li><a href="{{ request.script_root }}/register">Register</a></li>
<li><a style="padding-left:0px;padding-right:0px;">|</a></li> <li><a style="padding-left:0px;padding-right:0px;">|</a></li>
{% endif %} {% endif %}
<li><a href="/login">Login</a></li> <li><a href="{{ request.script_root }}/login">Login</a></li>
{% endif %} {% endif %}
</ul> </ul>
</div> </div>
@@ -60,9 +63,9 @@
{% endblock %} {% endblock %}
</div> </div>
<script src="/static/js/vendor/jquery.min.js"></script> <script src="{{ request.script_root }}/static/js/vendor/jquery.min.js"></script>
<script src="/static/js/vendor/marked.min.js"></script> <script src="{{ request.script_root }}/static/js/vendor/marked.min.js"></script>
<script src="/static/js/vendor/bootstrap.min.js"></script> <script src="{{ request.script_root }}/static/js/vendor/bootstrap.min.js"></script>
{% block scripts %} {% block scripts %}
{% endblock %} {% endblock %}
</body> </body>

View File

@@ -154,7 +154,7 @@
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
<script src="/static/js/utils.js"></script> <script src="{{ request.script_root }}/static/js/utils.js"></script>
<script src="/static/js/chalboard.js"></script> <script src="{{ request.script_root }}/static/js/chalboard.js"></script>
<script src="/static/js/style.js"></script> <script src="{{ request.script_root }}/static/js/style.js"></script>
{% endblock %} {% endblock %}

View File

@@ -44,6 +44,6 @@
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
<script src="/static/js/style.js"></script> <script src="{{ request.script_root }}/static/js/style.js"></script>
{% endblock %} {% endblock %}

View File

@@ -53,7 +53,7 @@
</div> </div>
<div class="done-row row"> <div class="done-row row">
<div class="col-md-6" style="padding-left:0px"> <div class="col-md-6" style="padding-left:0px">
<a class="pull-left align-text-to-button" href="/reset_password">Forgot your password?</a> <a class="pull-left align-text-to-button" href="{{ request.script_root }}/reset_password">Forgot your password?</a>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<button type="submit" id="submit" tabindex="5" class="btn btn-md btn-theme btn-outlined pull-right">Submit</button> <button type="submit" id="submit" tabindex="5" class="btn btn-md btn-theme btn-outlined pull-right">Submit</button>
@@ -67,6 +67,6 @@
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
<script src="/static/js/style.js"></script> <script src="{{ request.script_root }}/static/js/style.js"></script>
{% endblock %} {% endblock %}

View File

@@ -132,5 +132,5 @@
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
<script src="/static/js/style.js"></script> <script src="{{ request.script_root }}/static/js/style.js"></script>
{% endblock %} {% endblock %}

View File

@@ -63,7 +63,7 @@
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
<script src="/static/js/style.js"></script> <script src="{{ request.script_root }}/static/js/style.js"></script>
<script> <script>
if (window.location.hash == "#frame"){ if (window.location.hash == "#frame"){
$('.top-bar').hide() $('.top-bar').hide()

View File

@@ -55,5 +55,5 @@
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
<script src="/static/js/style.js"></script> <script src="{{ request.script_root }}/static/js/style.js"></script>
{% endblock %} {% endblock %}

View File

@@ -23,7 +23,7 @@
</thead> </thead>
<tbody> <tbody>
{% for team in teams %} {% for team in teams %}
<tr><td>{{ loop.index }}</td><td><a href="/team/{{ team.teamid }}">{{ team.name }}</a></td><td>{{ team.score }}</td></tr> <tr><td>{{ loop.index }}</td><td><a href="{{ request.script_root }}/team/{{ team.teamid }}">{{ team.name }}</a></td><td>{{ team.score }}</td></tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
@@ -31,7 +31,7 @@
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
<script src="/static/js/vendor/plotly.min.js"></script> <script src="{{ request.script_root }}/static/js/vendor/plotly.min.js"></script>
<script src="/static/js/utils.js"></script> <script src="{{ request.script_root }}/static/js/utils.js"></script>
<script src="/static/js/scoreboard.js"></script> <script src="{{ request.script_root }}/static/js/scoreboard.js"></script>
{% endblock %} {% endblock %}

View File

@@ -63,5 +63,5 @@
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
<script src="/static/js/style.js"></script> <script src="{{ request.script_root }}/static/js/style.js"></script>
{% endblock %} {% endblock %}

View File

@@ -69,7 +69,7 @@
<tbody> <tbody>
{% for solve in solves %} {% for solve in solves %}
<tr> <tr>
<td><a href="/challenges#{{ solve.chal.name }}">{{ solve.chal.name }}</a></td> <td><a href="{{ request.script_root }}/challenges#{{ solve.chal.name }}">{{ solve.chal.name }}</a></td>
<td class="hidden-xs">{{ solve.chal.category }}</td><td>{{ solve.chal.value }}</td> <td class="hidden-xs">{{ solve.chal.category }}</td><td>{{ solve.chal.value }}</td>
<td class="solve-time"><script>document.write( moment({{ solve.date|unix_time_millis }}).local().format('MMMM Do, h:mm:ss A'))</script></td> <td class="solve-time"><script>document.write( moment({{ solve.date|unix_time_millis }}).local().format('MMMM Do, h:mm:ss A'))</script></td>
</tr> </tr>
@@ -81,7 +81,7 @@
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
<script src="/static/js/vendor/plotly.min.js"></script> <script src="{{ request.script_root }}/static/js/vendor/plotly.min.js"></script>
<script src="/static/js/utils.js"></script> <script src="{{ request.script_root }}/static/js/utils.js"></script>
<script src="/static/js/team.js"></script> <script src="{{ request.script_root }}/static/js/team.js"></script>
{% endblock %} {% endblock %}

View File

@@ -22,7 +22,7 @@
<tbody> <tbody>
{% for team in teams %} {% for team in teams %}
<tr> <tr>
<td><a href="/team/{{ team.id }}">{{ team.name }}</a></td> <td><a href="{{ request.script_root }}/team/{{ team.id }}">{{ team.name }}</a></td>
<td>{% if team.website and team.website.startswith('http://') %}<a href="{{ team.website }}">{{ team.website }}</a>{% endif %}</td> <td>{% if team.website and team.website.startswith('http://') %}<a href="{{ team.website }}">{{ team.website }}</a>{% endif %}</td>
<td><span>{% if team.affiliation %}{{ team.affiliation }}{% endif %}</span></td> <td><span>{% if team.affiliation %}{{ team.affiliation }}{% endif %}</span></td>
<td class="hidden-xs"><span>{% if team.country %}{{ team.country }}{% endif %}</span></td> <td class="hidden-xs"><span>{% if team.country %}{{ team.country }}{% endif %}</span></td>
@@ -33,16 +33,16 @@
{% if team_pages > 1 %} {% if team_pages > 1 %}
<div class="text-center">Page <div class="text-center">Page
<br> <br>
{% if curr_page != 1 %}<a href="/teams/{{ curr_page-1 }}">&lt;&lt;&lt;</a>{% endif %} {% if curr_page != 1 %}<a href="{{ request.script_root }}/teams/{{ curr_page-1 }}">&lt;&lt;&lt;</a>{% endif %}
{% for page in range(1, team_pages + 1) %} {% for page in range(1, team_pages + 1) %}
{% if curr_page != page %} {% if curr_page != page %}
<a href="/teams/{{ page }}">{{ page }}</a> <a href="{{ request.script_root }}/teams/{{ page }}">{{ page }}</a>
{% else %} {% else %}
<b>{{page}}</b> <b>{{page}}</b>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% if curr_page != team_pages %}<a href="/teams/{{ curr_page+1 }}">&gt;&gt;&gt;</a>{% endif %} {% if curr_page != team_pages %}<a href="{{ request.script_root }}/teams/{{ curr_page+1 }}">&gt;&gt;&gt;</a>{% endif %}
<a href=""> <a href="{{ request.script_root }}">
</div> </div>
{% endif %} {% endif %}
</div> </div>

View File

@@ -19,7 +19,7 @@ views = Blueprint('views', __name__)
@views.before_request @views.before_request
def redirect_setup(): def redirect_setup():
if request.path == "/static/css/style.css": if request.path.startswith("/static"):
return return
if not is_setup() and request.path != "/setup": if not is_setup() and request.path != "/setup":
return redirect(url_for('views.setup')) return redirect(url_for('views.setup'))
@@ -50,15 +50,15 @@ def setup():
## Index page ## Index page
page = Pages('index', """<div class="container main-container"> page = Pages('index', """<div class="container main-container">
<img class="logo" src="/static/img/logo.png" /> <img class="logo" src="{0}/static/img/logo.png" />
<h3 class="text-center"> <h3 class="text-center">
Welcome to a cool CTF framework written by <a href="https://github.com/ColdHeat">Kevin Chung</a> of <a href="https://github.com/isislab">@isislab</a> Welcome to a cool CTF framework written by <a href="https://github.com/ColdHeat">Kevin Chung</a> of <a href="https://github.com/isislab">@isislab</a>
</h3> </h3>
<h4 class="text-center"> <h4 class="text-center">
<a href="/admin">Click here</a> to login and setup your CTF <a href="{0}/admin">Click here</a> to login and setup your CTF
</h4> </h4>
</div>""") </div>""".format(request.script_root))
#max attempts per challenge #max attempts per challenge
max_tries = set_config("max_tries",0) max_tries = set_config("max_tries",0)
@@ -89,9 +89,9 @@ def setup():
db.session.add(admin) db.session.add(admin)
db.session.commit() db.session.commit()
app.setup = False app.setup = False
return redirect('/') return redirect(url_for('views.static_html'))
return render_template('setup.html', nonce=session.get('nonce')) return render_template('setup.html', nonce=session.get('nonce'))
return redirect('/') return redirect(url_for('views.static_html'))
# Custom CSS handler # Custom CSS handler

46
ctfd.ini Normal file
View File

@@ -0,0 +1,46 @@
# UWSGI Configuration File
# Install uwsgi (sudo apt-get install uwsgi), copy this file to
# /etc/uwsgi/apps-available and then link it in /etc/uwsgi/apps-enabled
# Only two lines below (commented) need to be changed for your config.
# Then, you can use something like the following in your nginx config:
#
# # SERVER_ROOT is not / (e.g. /ctf)
# location = /ctf { rewrite ^ /ctf/; }
# location /ctf {
# include uwsgi_params;
# uwsgi_pass unix:/run/uwsgi/app/ctfd/socket;
# }
#
# # SERVER_ROOT is /
# location / {
# include uwsgi_params;
# wsgi_pass unix:/run/uwsgi/app/ctfd/socket;
# }
[uwsgi]
# Where you've put CTFD
chdir = /var/www/ctfd/
# If SCRIPT_ROOT is not /
#mount = /ctf=wsgi.py
# SCRIPT_ROOT is /
mount = /=wsgi.py
# You shouldn't need to change anything past here
plugin = python
module = wsgi
master = true
processes = 1
threads = 1
vacuum = true
manage-script-name = true
wsgi-file = wsgi.py
callable = app
die-on-term = true
# If you're not on debian/ubuntu, replace with uid/gid of web user
uid = www-data
gid = www-data

2
wsgi.py Normal file
View File

@@ -0,0 +1,2 @@
from CTFd import create_app
app = create_app()