mirror of
https://github.com/aljazceru/CTFd.git
synced 2025-12-17 14:04:20 +01:00
Merge branch 'master' of https://github.com/isislab/CTFd into view_challs_after
Conflicts: CTFd/admin.py CTFd/challenges.py
This commit is contained in:
@@ -74,6 +74,7 @@ def init_admin(app):
|
||||
ctf_name = set_config("ctf_name", request.form.get('ctf_name', None))
|
||||
mg_api_key = set_config("mg_api_key", request.form.get('mg_api_key', None))
|
||||
do_api_key = set_config("do_api_key", request.form.get('do_api_key', None))
|
||||
max_tries = set_config("max_tries", request.form.get('max_tries', None))
|
||||
|
||||
|
||||
db_start = Config.query.filter_by(key='start').first()
|
||||
@@ -100,6 +101,11 @@ def init_admin(app):
|
||||
if not do_api_key:
|
||||
set_config('do_api_key', None)
|
||||
|
||||
max_tries = get_config('max_tries')
|
||||
if not max_tries:
|
||||
set_config('max_tries', 0)
|
||||
max_tries = 0
|
||||
|
||||
view_after_ctf = get_config('view_after_ctf') == '1'
|
||||
if not view_after_ctf:
|
||||
set_config('view_after_ctf', 0)
|
||||
@@ -129,6 +135,7 @@ def init_admin(app):
|
||||
db.session.close()
|
||||
|
||||
return render_template('admin/config.html', ctf_name=ctf_name, start=start, end=end,
|
||||
max_tries=max_tries,
|
||||
view_challenges_unregistered=view_challenges_unregistered,
|
||||
prevent_registration=prevent_registration, do_api_key=do_api_key, mg_api_key=mg_api_key,
|
||||
prevent_name_change=prevent_name_change,
|
||||
@@ -165,6 +172,13 @@ def init_admin(app):
|
||||
pages = Pages.query.all()
|
||||
return render_template('admin/pages.html', routes=pages)
|
||||
|
||||
@app.route('/admin/page/<pageroute>/delete', methods=['POST'])
|
||||
@admins_only
|
||||
def delete_page(pageroute):
|
||||
page = Pages.query.filter_by(route=pageroute).first()
|
||||
db.session.delete(page)
|
||||
db.session.commit()
|
||||
return '1'
|
||||
|
||||
@app.route('/admin/hosts', methods=['GET'])
|
||||
@admins_only
|
||||
@@ -448,7 +462,7 @@ def init_admin(app):
|
||||
solve_count = db.session.query(db.func.count(Solves.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 = Solves.query.add_columns(db.func.count(Solves.chalid).label('solves')).group_by(Solves.chalid).order_by('solves ASC').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()
|
||||
|
||||
db.session.close()
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from flask import current_app as app, render_template, request, redirect, abort, jsonify, json as json_mod, url_for, session
|
||||
|
||||
from CTFd.utils import ctftime, view_after_ctf, authed, unix_time, get_kpm, can_view_challenges, is_admin
|
||||
from CTFd.utils import ctftime, view_after_ctf, authed, unix_time, get_kpm, can_view_challenges, is_admin, get_config
|
||||
from CTFd.models import db, Challenges, Files, Solves, WrongKeys, Keys
|
||||
|
||||
import time
|
||||
@@ -58,7 +58,17 @@ def init_challenges(app):
|
||||
db.session.close()
|
||||
json = {'solves':[]}
|
||||
for x in solves:
|
||||
json['solves'].append({'id':x.id, 'chal':x.chal.name, 'chalid':x.chalid,'team':x.teamid, 'value': x.chal.value, 'category':x.chal.category, 'time':unix_time(x.date)})
|
||||
json['solves'].append({ 'chal':x.chal.name, 'chalid':x.chalid,'team':x.teamid, 'value': x.chal.value, 'category':x.chal.category, 'time':unix_time(x.date)})
|
||||
return jsonify(json)
|
||||
|
||||
@app.route('/maxattempts')
|
||||
def attempts():
|
||||
chals = Challenges.query.add_columns('id').all()
|
||||
json = {'maxattempts':[]}
|
||||
for chal, chalid in chals:
|
||||
fails = WrongKeys.query.filter_by(team=session['id'], chal=chalid).count()
|
||||
if fails >= int(get_config("max_tries")) and int(get_config("max_tries")) > 0:
|
||||
json['maxattempts'].append({'chalid':chalid})
|
||||
return jsonify(json)
|
||||
|
||||
@app.route('/fails/<teamid>', methods=['GET'])
|
||||
@@ -82,9 +92,12 @@ def init_challenges(app):
|
||||
if not ctftime():
|
||||
return redirect('/challenges')
|
||||
if authed():
|
||||
fails = WrongKeys.query.filter_by(team=session['id'],chal=chalid).count()
|
||||
logger = logging.getLogger('keys')
|
||||
data = (time.strftime("%m/%d/%Y %X"), session['username'].encode('utf-8'), request.form['key'].encode('utf-8'), get_kpm(session['id']))
|
||||
print "[{0}] {1} submitted {2} with kpm {3}".format(*data)
|
||||
if fails >= int(get_config("max_tries")) and int(get_config("max_tries")) > 0:
|
||||
return "4" #too many tries on this challenge
|
||||
if get_kpm(session['id']) > 10:
|
||||
wrong = WrongKeys(session['id'], chalid, request.form['key'])
|
||||
db.session.add(wrong)
|
||||
|
||||
@@ -62,6 +62,10 @@ def init_views(app):
|
||||
html = request.form['html']
|
||||
page = Pages('index', html)
|
||||
|
||||
#max attempts per challenge
|
||||
max_tries = Config("max_tries",0)
|
||||
|
||||
|
||||
## Start time
|
||||
start = Config('start', None)
|
||||
end = Config('end', None)
|
||||
@@ -77,6 +81,7 @@ def init_views(app):
|
||||
db.session.add(ctf_name)
|
||||
db.session.add(admin)
|
||||
db.session.add(page)
|
||||
db.session.add(max_tries)
|
||||
db.session.add(start)
|
||||
db.session.add(end)
|
||||
db.session.add(view_challenges_unregistered)
|
||||
|
||||
@@ -105,6 +105,12 @@ function submitkey(chal, key, nonce) {
|
||||
$('#submit-key').css('background-color', '#e18728')
|
||||
$('#submit-key').prop('disabled', true)
|
||||
}
|
||||
else if (data == 4){ // too many incorrect solves
|
||||
$('#submit-key').text('Too many attempts.')
|
||||
$('#submit-key').css('background-color', 'red')
|
||||
$('#submit-key').prop('disabled', true)
|
||||
}
|
||||
marktoomanyattempts()
|
||||
marksolves()
|
||||
updatesolves()
|
||||
setTimeout(function(){
|
||||
@@ -129,6 +135,20 @@ function marksolves() {
|
||||
});
|
||||
}
|
||||
|
||||
function marktoomanyattempts() {
|
||||
$.get('/maxattempts', function (data) {
|
||||
maxattempts = $.parseJSON(JSON.stringify(data));
|
||||
for (var i = maxattempts['maxattempts'].length - 1; i >= 0; i--) {
|
||||
id = maxattempts['maxattempts'][i].chalid
|
||||
$('#challenges button[value="' + id + '"]').addClass('secondary')
|
||||
$('#challenges button[value="' + id + '"]').css('background-color', '#FF9999')
|
||||
};
|
||||
if (window.location.hash.length > 0){
|
||||
loadchalbyname(window.location.hash.substring(1))
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updatesolves(){
|
||||
$.get('/chals/solves', function (data) {
|
||||
solves = $.parseJSON(JSON.stringify(data));
|
||||
@@ -177,6 +197,7 @@ function loadchals() {
|
||||
$('#' + challenges['game'][i].category.replace(/ /g,"-")).append($('<button value="' + challenges['game'][i].id + '">' + challenges['game'][i].value + '</button>'));
|
||||
};
|
||||
updatesolves()
|
||||
marktoomanyattempts()
|
||||
marksolves()
|
||||
|
||||
$('#challenges button').click(function (e) {
|
||||
|
||||
@@ -12,6 +12,11 @@
|
||||
<input id='ctf_name' name='ctf_name' type='text' placeholder="CTF Name" {% if ctf_name is defined and ctf_name != None %}value="{{ ctf_name }}"{% endif %}>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<label for="max_tries">Maximum Attempts Per Challenge (0 to disable):</label>
|
||||
<input id='max_tries' name='max_tries' type='text' placeholder="0" {% if max_tries is defined and max_tries != None %}value="{{ max_tries }}"{% endif %}>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<label for="start">Mailgun API Key:</label>
|
||||
<input id='mg_api_key' name='mg_api_key' type='text' placeholder="Mailgun API Key" {% if mg_api_key is defined and mg_api_key != None %}value="{{ mg_api_key }}"{% endif %}>
|
||||
|
||||
@@ -3,16 +3,31 @@
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<br>
|
||||
<div id="confirm" class="reveal-modal" data-reveal>
|
||||
<h2 class="text-center">Delete Page</h2>
|
||||
<form method="POST">
|
||||
<input type="hidden" name="route">
|
||||
<input id="nonce" type="hidden" name="nonce" value="{{ nonce }}">
|
||||
<div class="small-6 small-centered text-center columns">
|
||||
<p>Are you sure you want to delete <strong id="confirm-route-name"></strong>?</p>
|
||||
<button type="button" class="button alert radius" onclick="$('#confirm').foundation('reveal', 'close');">No</button>
|
||||
<button type="button" id="delete-route" class="button success radius">Yes</button>
|
||||
</div>
|
||||
</form>
|
||||
<a class="close-reveal-modal">×</a>
|
||||
</div>
|
||||
<table id="pages">
|
||||
<thead>
|
||||
<tr>
|
||||
<td><b>Route</b></td>
|
||||
<td class="text-center" style="width: 150px;"><b>Settings</b></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for route in routes %}
|
||||
<tr>
|
||||
<td><a href="/admin/pages/{{ route.route }}">{{ route.route }}</a></td>
|
||||
<tr name="{{ route.route }}">
|
||||
<td class="route-name"><a href="/admin/pages/{{ route.route }}">{{ route.route }}</a></td>
|
||||
<td class="text-center"><i class="fa fa-times"></i></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
@@ -25,4 +40,30 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
$('#delete-route').click(function(e){
|
||||
e.preventDefault();
|
||||
var route = $('#confirm input[name="route"]').val()
|
||||
$.post($('#confirm form').attr('action'), $('#confirm form').serialize(), function(data){
|
||||
var data = $.parseJSON(JSON.stringify(data))
|
||||
if (data == "1"){
|
||||
location.reload()
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
function load_confirm_modal(route){
|
||||
var modal = $('#confirm')
|
||||
modal.find('input[name=route]').val(route)
|
||||
modal.find('#confirm-route-name').text(route)
|
||||
$('#confirm form').attr('action', '/admin/page/'+route+'/delete');
|
||||
$('#confirm').foundation('reveal', 'open');
|
||||
}
|
||||
|
||||
$('.fa-times').click(function(){
|
||||
var elem = $(this).parent().parent();
|
||||
var name = elem.find('.route-name').text().trim();
|
||||
load_confirm_modal(name)
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<h3>Most solved: <b>{{ most_solved[0].chal.name }}</b> with {{ most_solved[1] }}</b> solves</h3>
|
||||
{% endif %}
|
||||
{% if least_solved %}
|
||||
<h3>Least solved: <b>{{ least_solved[0].chal.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>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user