Files
CTFd/CTFd/admin/challenges.py
Kevin Chung 613ede5738 Max attmpts (#227)
* Making max_attempts use the Challenge value instead of the Config value
2017-03-09 23:47:08 -05:00

207 lines
7.7 KiB
Python

from flask import current_app as app, render_template, request, redirect, jsonify, url_for, Blueprint
from CTFd.utils import admins_only, is_admin, unix_time, get_config, \
set_config, sendmail, rmdir, create_image, delete_image, run_image, container_status, container_ports, \
container_stop, container_start, get_themes, cache, upload_file
from CTFd.models import db, Teams, Solves, Awards, Containers, Challenges, WrongKeys, Keys, Tags, Files, Tracking, Pages, Config, DatabaseError
from CTFd.plugins.keys import get_key_class, KEY_CLASSES
from CTFd.plugins.challenges import get_chal_class, CHALLENGE_CLASSES
import os
admin_challenges = Blueprint('admin_challenges', __name__)
@admin_challenges.route('/admin/chal_types', methods=['GET'])
@admins_only
def admin_chal_types():
data = {}
for class_id in CHALLENGE_CLASSES:
data[class_id] = CHALLENGE_CLASSES.get(class_id).name
return jsonify(data)
@admin_challenges.route('/admin/chals', methods=['POST', 'GET'])
@admins_only
def admin_chals():
if request.method == 'POST':
chals = Challenges.query.add_columns('id', 'name', 'value', 'description', 'category', 'hidden', 'max_attempts').order_by(Challenges.value).all()
teams_with_points = db.session.query(Solves.teamid).join(Teams).filter(
Teams.banned == False).group_by(Solves.teamid).count()
json_data = {'game': []}
for x in chals:
solve_count = Solves.query.join(Teams, Solves.teamid == Teams.id).filter(
Solves.chalid == x[1], Teams.banned == False).count()
if teams_with_points > 0:
percentage = (float(solve_count) / float(teams_with_points))
else:
percentage = 0.0
json_data['game'].append({
'id': x.id,
'name': x.name,
'value': x.value,
'description': x.description,
'category': x.category,
'hidden': x.hidden,
'max_attempts': x.max_attempts,
'percentage_solved': percentage
})
db.session.close()
return jsonify(json_data)
else:
return render_template('admin/chals.html')
@admin_challenges.route('/admin/tags/<int:chalid>', methods=['GET', 'POST'])
@admins_only
def admin_tags(chalid):
if request.method == 'GET':
tags = Tags.query.filter_by(chal=chalid).all()
json_data = {'tags': []}
for x in tags:
json_data['tags'].append({'id': x.id, 'chal': x.chal, 'tag': x.tag})
return jsonify(json_data)
elif request.method == 'POST':
newtags = request.form.getlist('tags[]')
for x in newtags:
tag = Tags(chalid, x)
db.session.add(tag)
db.session.commit()
db.session.close()
return '1'
@admin_challenges.route('/admin/tags/<int:tagid>/delete', methods=['POST'])
@admins_only
def admin_delete_tags(tagid):
if request.method == 'POST':
tag = Tags.query.filter_by(id=tagid).first_or_404()
db.session.delete(tag)
db.session.commit()
db.session.close()
return '1'
@admin_challenges.route('/admin/files/<int:chalid>', methods=['GET', 'POST'])
@admins_only
def admin_files(chalid):
if request.method == 'GET':
files = Files.query.filter_by(chal=chalid).all()
json_data = {'files': []}
for x in files:
json_data['files'].append({'id': x.id, 'file': x.location})
return jsonify(json_data)
if request.method == 'POST':
if request.form['method'] == "delete":
f = Files.query.filter_by(id=request.form['file']).first_or_404()
upload_folder = os.path.join(app.root_path, app.config['UPLOAD_FOLDER'])
if os.path.exists(os.path.join(upload_folder, f.location)): # Some kind of os.path.isfile issue on Windows...
os.unlink(os.path.join(upload_folder, f.location))
db.session.delete(f)
db.session.commit()
db.session.close()
return '1'
elif request.form['method'] == "upload":
files = request.files.getlist('files[]')
for f in files:
upload_file(file=f, chalid=chalid)
db.session.commit()
db.session.close()
return '1'
@admin_challenges.route('/admin/chal/<int:chalid>/<prop>', methods=['GET'])
@admins_only
def admin_get_values(chalid, prop):
challenge = Challenges.query.filter_by(id=chalid).first_or_404()
if prop == 'keys':
chal_keys = Keys.query.filter_by(chal=challenge.id).all()
json_data = {'keys': []}
for x in chal_keys:
json_data['keys'].append({'id': x.id, 'key': x.flag, 'type': x.key_type, 'type_name': get_key_class(x.key_type).name})
return jsonify(json_data)
elif prop == 'tags':
tags = Tags.query.filter_by(chal=chalid).all()
json_data = {'tags': []}
for x in tags:
json_data['tags'].append({'id': x.id, 'chal': x.chal, 'tag': x.tag})
return jsonify(json_data)
@admin_challenges.route('/admin/chal/new', methods=['GET', 'POST'])
@admins_only
def admin_create_chal():
if request.method == 'POST':
files = request.files.getlist('files[]')
# Create challenge
chal = Challenges(request.form['name'], request.form['desc'], request.form['value'], request.form['category'], int(request.form['chaltype']))
if 'hidden' in request.form:
chal.hidden = True
else:
chal.hidden = False
max_attempts = request.form.get('max_attempts')
if max_attempts and max_attempts.isdigit():
chal.max_attempts = int(max_attempts)
db.session.add(chal)
db.session.flush()
flag = Keys(chal.id, request.form['key'], int(request.form['key_type[0]']))
if request.form.get('keydata'):
flag.data = request.form.get('keydata')
db.session.add(flag)
db.session.commit()
for f in files:
upload_file(file=f, chalid=chal.id)
db.session.commit()
db.session.close()
return redirect(url_for('admin_challenges.admin_chals'))
else:
return render_template('admin/chals/create.html')
@admin_challenges.route('/admin/chal/delete', methods=['POST'])
@admins_only
def admin_delete_chal():
challenge = Challenges.query.filter_by(id=request.form['id']).first_or_404()
WrongKeys.query.filter_by(chalid=challenge.id).delete()
Solves.query.filter_by(chalid=challenge.id).delete()
Keys.query.filter_by(chal=challenge.id).delete()
files = Files.query.filter_by(chal=challenge.id).all()
Files.query.filter_by(chal=challenge.id).delete()
for file in files:
upload_folder = app.config['UPLOAD_FOLDER']
folder = os.path.dirname(os.path.join(os.path.normpath(app.root_path), upload_folder, file.location))
rmdir(folder)
Tags.query.filter_by(chal=challenge.id).delete()
Challenges.query.filter_by(id=challenge.id).delete()
db.session.commit()
db.session.close()
return '1'
@admin_challenges.route('/admin/chal/update', methods=['POST'])
@admins_only
def admin_update_chal():
challenge = Challenges.query.filter_by(id=request.form['id']).first_or_404()
challenge.name = request.form['name']
challenge.description = request.form['desc']
challenge.value = int(request.form.get('value', 0)) if request.form.get('value', 0) else 0
challenge.max_attempts = int(request.form.get('max_attempts', 0)) if request.form.get('max_attempts', 0) else 0
challenge.category = request.form['category']
challenge.hidden = 'hidden' in request.form
db.session.add(challenge)
db.session.commit()
db.session.close()
return redirect(url_for('admin_challenges.admin_chals'))