diff --git a/CTFd/admin/__init__.py b/CTFd/admin/__init__.py index 06f822a1..8a58ff76 100644 --- a/CTFd/admin/__init__.py +++ b/CTFd/admin/__init__.py @@ -103,8 +103,6 @@ def admin_config(): mg_base_url = set_config("mg_base_url", request.form.get('mg_base_url', None)) mg_api_key = set_config("mg_api_key", request.form.get('mg_api_key', None)) - max_tries = set_config("max_tries", request.form.get('max_tries', None)) - db_start = Config.query.filter_by(key='start').first() db_start.value = start @@ -124,7 +122,6 @@ def admin_config(): cache.clear() ctf_name = get_config('ctf_name') ctf_theme = get_config('ctf_theme') - max_tries = get_config('max_tries') hide_scores = get_config('hide_scores') mail_server = get_config('mail_server') @@ -135,9 +132,6 @@ def admin_config(): mailfrom_addr = get_config('mailfrom_addr') mg_api_key = get_config('mg_api_key') mg_base_url = get_config('mg_base_url') - if not max_tries: - set_config('max_tries', 0) - max_tries = 0 view_after_ctf = get_config('view_after_ctf') start = get_config('start') @@ -164,7 +158,6 @@ def admin_config(): start=start, end=end, hide_scores=hide_scores, - max_tries=max_tries, mail_server=mail_server, mail_port=mail_port, mail_username=mail_username, diff --git a/CTFd/admin/challenges.py b/CTFd/admin/challenges.py index a61bd048..98dc0abc 100644 --- a/CTFd/admin/challenges.py +++ b/CTFd/admin/challenges.py @@ -24,7 +24,7 @@ def admin_chal_types(): @admins_only def admin_chals(): 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', '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() @@ -45,6 +45,7 @@ def admin_chals(): 'description': x.description, 'category': x.category, 'hidden': x.hidden, + 'max_attempts': x.max_attempts, 'percentage_solved': percentage }) @@ -145,6 +146,11 @@ def admin_create_chal(): 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() @@ -191,7 +197,8 @@ 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 = request.form['value'] + 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) diff --git a/CTFd/challenges.py b/CTFd/challenges.py index 06fc08e4..8394b1a3 100644 --- a/CTFd/challenges.py +++ b/CTFd/challenges.py @@ -205,8 +205,8 @@ def chal(chalid): saved_keys = Keys.query.filter_by(chal=chal.id).all() # Hit max attempts - max_tries = int(get_config("max_tries")) - if fails >= max_tries > 0: + max_tries = chal.max_attempts + if max_tries and fails >= max_tries > 0: return jsonify({ 'status': '0', 'message': "You have 0 tries remaining" @@ -230,7 +230,7 @@ def chal(chalid): logger.info("[{0}] {1} submitted {2} with kpm {3} [WRONG]".format(*data)) # return '0' # key was wrong if max_tries: - attempts_left = max_tries - fails + attempts_left = max_tries - fails - 1 ## Off by one since fails has changed since it was gotten tries_str = 'tries' if attempts_left == 1: tries_str = 'try' diff --git a/CTFd/models.py b/CTFd/models.py index 7248c065..1aaae96e 100644 --- a/CTFd/models.py +++ b/CTFd/models.py @@ -58,6 +58,7 @@ class Challenges(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(80)) description = db.Column(db.Text) + max_attempts = db.Column(db.Integer, default=0) value = db.Column(db.Integer) category = db.Column(db.String(80)) type = db.Column(db.Integer) diff --git a/CTFd/static/admin/js/chalboard.js b/CTFd/static/admin/js/chalboard.js index 11907727..b4de1fca 100644 --- a/CTFd/static/admin/js/chalboard.js +++ b/CTFd/static/admin/js/chalboard.js @@ -49,6 +49,11 @@ function loadchal(id, update) { $('.chal-name').val(obj.name); $('.chal-desc').val(obj.description); $('.chal-value').val(obj.value); + if (parseInt(obj.max_attempts) > 0){ + $('.chal-attempts').val(obj.max_attempts); + $('#limit_max_attempts').prop('checked', true); + $('#chal-attempts-group').show(); + } $('.chal-category').val(obj.category); $('.chal-id').val(obj.id); $('.chal-hidden').prop('checked', false); @@ -309,7 +314,14 @@ $(".tag-insert").keyup(function (e) { } }); - +$('#limit_max_attempts').change(function() { + if(this.checked) { + $('#chal-attempts-group').show(); + } else { + $('#chal-attempts-group').hide(); + $('#chal-attempts-input').val(''); + } +}); // Markdown Preview $('#desc-edit').on('shown.bs.tab', function (event) { diff --git a/CTFd/static/admin/js/templates/challenges/standard/standard-challenge-create.hbs b/CTFd/static/admin/js/templates/challenges/standard/standard-challenge-create.hbs index 5f222ebc..73aa5228 100644 --- a/CTFd/static/admin/js/templates/challenges/standard/standard-challenge-create.hbs +++ b/CTFd/static/admin/js/templates/challenges/standard/standard-challenge-create.hbs @@ -66,6 +66,19 @@ +
+
+ +
+ +
+
diff --git a/CTFd/static/admin/js/templates/challenges/standard/standard-challenge-create.js b/CTFd/static/admin/js/templates/challenges/standard/standard-challenge-create.js index 6a51e888..dbd575c5 100644 --- a/CTFd/static/admin/js/templates/challenges/standard/standard-challenge-create.js +++ b/CTFd/static/admin/js/templates/challenges/standard/standard-challenge-create.js @@ -1,11 +1,19 @@ // Markdown Preview $('#desc-edit').on('shown.bs.tab', function (event) { if (event.target.hash == '#desc-preview'){ - $(event.target.hash).html(marked($('#desc-editor').val(), {'gfm':true, 'breaks':true})) + $(event.target.hash).html(marked($('#desc-editor').val(), {'gfm':true, 'breaks':true})); } }); $('#new-desc-edit').on('shown.bs.tab', function (event) { if (event.target.hash == '#new-desc-preview'){ - $(event.target.hash).html(marked($('#new-desc-editor').val(), {'gfm':true, 'breaks':true})) + $(event.target.hash).html(marked($('#new-desc-editor').val(), {'gfm':true, 'breaks':true})); + } +}); +$("#solve-attempts-checkbox").change(function() { + if(this.checked) { + $('#solve-attempts-input').show(); + } else { + $('#solve-attempts-input').hide(); + $('#max_attempts').val(''); } }); \ No newline at end of file diff --git a/CTFd/templates/admin/chals.html b/CTFd/templates/admin/chals.html index 66273ee5..e84f44e3 100644 --- a/CTFd/templates/admin/chals.html +++ b/CTFd/templates/admin/chals.html @@ -137,6 +137,18 @@
+ +
+ +
+ +
diff --git a/CTFd/templates/admin/config.html b/CTFd/templates/admin/config.html index 88b14bff..829e8f86 100644 --- a/CTFd/templates/admin/config.html +++ b/CTFd/templates/admin/config.html @@ -59,10 +59,6 @@
-
- - -