mirror of
https://github.com/aljazceru/CTFd.git
synced 2025-12-18 06:24:23 +01:00
Max attmpts (#227)
* Making max_attempts use the Challenge value instead of the Config value
This commit is contained in:
@@ -103,8 +103,6 @@ def admin_config():
|
|||||||
mg_base_url = set_config("mg_base_url", request.form.get('mg_base_url', None))
|
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))
|
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 = Config.query.filter_by(key='start').first()
|
||||||
db_start.value = start
|
db_start.value = start
|
||||||
|
|
||||||
@@ -124,7 +122,6 @@ def admin_config():
|
|||||||
cache.clear()
|
cache.clear()
|
||||||
ctf_name = get_config('ctf_name')
|
ctf_name = get_config('ctf_name')
|
||||||
ctf_theme = get_config('ctf_theme')
|
ctf_theme = get_config('ctf_theme')
|
||||||
max_tries = get_config('max_tries')
|
|
||||||
hide_scores = get_config('hide_scores')
|
hide_scores = get_config('hide_scores')
|
||||||
|
|
||||||
mail_server = get_config('mail_server')
|
mail_server = get_config('mail_server')
|
||||||
@@ -135,9 +132,6 @@ def admin_config():
|
|||||||
mailfrom_addr = get_config('mailfrom_addr')
|
mailfrom_addr = get_config('mailfrom_addr')
|
||||||
mg_api_key = get_config('mg_api_key')
|
mg_api_key = get_config('mg_api_key')
|
||||||
mg_base_url = get_config('mg_base_url')
|
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')
|
view_after_ctf = get_config('view_after_ctf')
|
||||||
start = get_config('start')
|
start = get_config('start')
|
||||||
@@ -164,7 +158,6 @@ def admin_config():
|
|||||||
start=start,
|
start=start,
|
||||||
end=end,
|
end=end,
|
||||||
hide_scores=hide_scores,
|
hide_scores=hide_scores,
|
||||||
max_tries=max_tries,
|
|
||||||
mail_server=mail_server,
|
mail_server=mail_server,
|
||||||
mail_port=mail_port,
|
mail_port=mail_port,
|
||||||
mail_username=mail_username,
|
mail_username=mail_username,
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ def admin_chal_types():
|
|||||||
@admins_only
|
@admins_only
|
||||||
def admin_chals():
|
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', 'max_attempts').order_by(Challenges.value).all()
|
||||||
|
|
||||||
teams_with_points = db.session.query(Solves.teamid).join(Teams).filter(
|
teams_with_points = db.session.query(Solves.teamid).join(Teams).filter(
|
||||||
Teams.banned == False).group_by(Solves.teamid).count()
|
Teams.banned == False).group_by(Solves.teamid).count()
|
||||||
@@ -45,6 +45,7 @@ def admin_chals():
|
|||||||
'description': x.description,
|
'description': x.description,
|
||||||
'category': x.category,
|
'category': x.category,
|
||||||
'hidden': x.hidden,
|
'hidden': x.hidden,
|
||||||
|
'max_attempts': x.max_attempts,
|
||||||
'percentage_solved': percentage
|
'percentage_solved': percentage
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -145,6 +146,11 @@ def admin_create_chal():
|
|||||||
chal.hidden = True
|
chal.hidden = True
|
||||||
else:
|
else:
|
||||||
chal.hidden = False
|
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.add(chal)
|
||||||
db.session.flush()
|
db.session.flush()
|
||||||
|
|
||||||
@@ -191,7 +197,8 @@ def admin_update_chal():
|
|||||||
challenge = Challenges.query.filter_by(id=request.form['id']).first_or_404()
|
challenge = Challenges.query.filter_by(id=request.form['id']).first_or_404()
|
||||||
challenge.name = request.form['name']
|
challenge.name = request.form['name']
|
||||||
challenge.description = request.form['desc']
|
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.category = request.form['category']
|
||||||
challenge.hidden = 'hidden' in request.form
|
challenge.hidden = 'hidden' in request.form
|
||||||
db.session.add(challenge)
|
db.session.add(challenge)
|
||||||
|
|||||||
@@ -205,8 +205,8 @@ def chal(chalid):
|
|||||||
saved_keys = Keys.query.filter_by(chal=chal.id).all()
|
saved_keys = Keys.query.filter_by(chal=chal.id).all()
|
||||||
|
|
||||||
# Hit max attempts
|
# Hit max attempts
|
||||||
max_tries = int(get_config("max_tries"))
|
max_tries = chal.max_attempts
|
||||||
if fails >= max_tries > 0:
|
if max_tries and fails >= max_tries > 0:
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'status': '0',
|
'status': '0',
|
||||||
'message': "You have 0 tries remaining"
|
'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))
|
logger.info("[{0}] {1} submitted {2} with kpm {3} [WRONG]".format(*data))
|
||||||
# return '0' # key was wrong
|
# return '0' # key was wrong
|
||||||
if max_tries:
|
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'
|
tries_str = 'tries'
|
||||||
if attempts_left == 1:
|
if attempts_left == 1:
|
||||||
tries_str = 'try'
|
tries_str = 'try'
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ class Challenges(db.Model):
|
|||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
name = db.Column(db.String(80))
|
name = db.Column(db.String(80))
|
||||||
description = db.Column(db.Text)
|
description = db.Column(db.Text)
|
||||||
|
max_attempts = db.Column(db.Integer, default=0)
|
||||||
value = db.Column(db.Integer)
|
value = db.Column(db.Integer)
|
||||||
category = db.Column(db.String(80))
|
category = db.Column(db.String(80))
|
||||||
type = db.Column(db.Integer)
|
type = db.Column(db.Integer)
|
||||||
|
|||||||
@@ -49,6 +49,11 @@ function loadchal(id, update) {
|
|||||||
$('.chal-name').val(obj.name);
|
$('.chal-name').val(obj.name);
|
||||||
$('.chal-desc').val(obj.description);
|
$('.chal-desc').val(obj.description);
|
||||||
$('.chal-value').val(obj.value);
|
$('.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-category').val(obj.category);
|
||||||
$('.chal-id').val(obj.id);
|
$('.chal-id').val(obj.id);
|
||||||
$('.chal-hidden').prop('checked', false);
|
$('.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
|
// Markdown Preview
|
||||||
$('#desc-edit').on('shown.bs.tab', function (event) {
|
$('#desc-edit').on('shown.bs.tab', function (event) {
|
||||||
|
|||||||
@@ -66,6 +66,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input name="hidden" type="checkbox" id="solve-attempts-checkbox">
|
||||||
|
Limit amount of solve attempts
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div id="solve-attempts-input" style="display: none;">
|
||||||
|
<label for="max_attempts">Maximum Attempts</label>
|
||||||
|
<input class="form-control" id='max_attempts' name='max_attempts' type='number' placeholder="0">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
|
|||||||
@@ -1,11 +1,19 @@
|
|||||||
// Markdown Preview
|
// Markdown Preview
|
||||||
$('#desc-edit').on('shown.bs.tab', function (event) {
|
$('#desc-edit').on('shown.bs.tab', function (event) {
|
||||||
if (event.target.hash == '#desc-preview'){
|
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) {
|
$('#new-desc-edit').on('shown.bs.tab', function (event) {
|
||||||
if (event.target.hash == '#new-desc-preview'){
|
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('');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -137,6 +137,18 @@
|
|||||||
<label for="value">Value</label>
|
<label for="value">Value</label>
|
||||||
<input type="number" class="form-control chal-value" name="value" placeholder="Enter value" required>
|
<input type="number" class="form-control chal-value" name="value" placeholder="Enter value" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input class="chal-attempts-checkbox" id="limit_max_attempts" name="limit_max_attempts" type="checkbox">
|
||||||
|
Limit challenge attempts
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" id="chal-attempts-group" style="display:none;">
|
||||||
|
<label for="value">Max Attempts</label>
|
||||||
|
<input type="number" class="form-control chal-attempts" id="chal-attempts-input" name="max_attempts" placeholder="Enter value">
|
||||||
|
</div>
|
||||||
<input class="chal-id" type='hidden' name='id' placeholder='ID'>
|
<input class="chal-id" type='hidden' name='id' placeholder='ID'>
|
||||||
|
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
|
|||||||
@@ -59,10 +59,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div role="tabpanel" class="tab-pane" id="accounts-section">
|
<div role="tabpanel" class="tab-pane" id="accounts-section">
|
||||||
<div class="form-group">
|
|
||||||
<label for="max_tries">Maximum Attempts Per Challenge (0 to disable):</label>
|
|
||||||
<input class="form-control" 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="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
<input id="verify_emails" name="verify_emails" type="checkbox" {% if verify_emails %}checked{% endif %}>
|
<input id="verify_emails" name="verify_emails" type="checkbox" {% if verify_emails %}checked{% endif %}>
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
"""Adding max_attempts to Challenges
|
||||||
|
|
||||||
|
Revision ID: d6514ec92738
|
||||||
|
Revises: a4e30c94c360
|
||||||
|
Create Date: 2017-03-09 01:20:31.423407
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'd6514ec92738'
|
||||||
|
down_revision = 'a4e30c94c360'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column('challenges', sa.Column('max_attempts', sa.Integer(), nullable=True, default=0))
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_column('challenges', 'max_attempts')
|
||||||
|
# ### end Alembic commands ###
|
||||||
Reference in New Issue
Block a user