Fix dynamic challenges to work in user mode and team mode (#760)

* Fix dynamic challenges to work in user mode and team mode (Closes #759)
* Add test for solving dynamic challenges and challenge de-valuation
* Add missing oauth_login link to team_enrollment.html
selenium-screenshot-testing
Kevin Chung 2018-11-27 03:04:51 -05:00 committed by GitHub
parent 2bd310b5d9
commit e79f32a5c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 66 additions and 6 deletions

View File

@ -7,6 +7,7 @@ from CTFd import utils
from CTFd.utils.migrations import upgrade
from CTFd.utils.user import get_ip
from CTFd.utils.uploads import upload_file, delete_file
from CTFd.utils.modes import get_model
from flask import Blueprint
import math
@ -92,9 +93,11 @@ class DynamicValueChallenge(BaseChallenge):
for attr, value in data.items():
setattr(challenge, attr, value)
Model = get_model()
solve_count = Solves.query \
.join(Teams, Solves.team_id == Teams.id) \
.filter(Solves.challenge_id == challenge.id, Teams.banned == False) \
.join(Model, Solves.account_id == Model.id) \
.filter(Solves.challenge_id == challenge.id, Model.hidden == False, Model.banned == False) \
.count()
# It is important that this calculation takes into account floats.
@ -165,9 +168,11 @@ class DynamicValueChallenge(BaseChallenge):
data = request.form or request.get_json()
submission = data['submission'].strip()
solve_count = Solves.query\
.join(Teams, Solves.team_id == Teams.id)\
.filter(Solves.challenge_id == chal.id, Teams.banned == False)\
Model = get_model()
solve_count = Solves.query \
.join(Model, Solves.account_id == Model.id) \
.filter(Solves.challenge_id == challenge.id, Model.hidden == False, Model.banned == False) \
.count()
# It is important that this calculation takes into account floats.

View File

@ -20,7 +20,7 @@
</div>
<div class="row">
<div class="col-md-6 offset-md-3 text-center">
<a class="btn btn-primary w-100" href="">Play with Official Team</a>
<a class="btn btn-primary w-100" href="{{ url_for('auth.oauth_login') }}">Play with Official Team</a>
</div>
</div>
<div class="row pt-3">

View File

@ -114,3 +114,58 @@ def test_can_delete_dynamic_challenge():
challenges = DynamicChallenge.query.all()
assert len(challenges) == 0
destroy_ctfd(app)
def test_dynamic_challenge_loses_value_properly():
app = create_ctfd(enable_plugins=True)
with app.app_context():
register_user(app)
client = login_as_user(app, name="admin", password="password")
challenge_data = {
"name": "name",
"category": "category",
"description": "description",
"value": 100,
"decay": 20,
"minimum": 1,
"state": "visible",
"type": "dynamic"
}
r = client.post('/api/v1/challenges', json=challenge_data)
assert r.get_json().get('data')['id'] == 1
flag = gen_flag(app.db, challenge_id=1, content='flag')
for i, team_id in enumerate(range(2, 26)):
name = "user{}".format(team_id)
email = "user{}@ctfd.io".format(team_id)
# We need to bypass rate-limiting so gen_user instead of register_user
gen_user(app.db, name=name, email=email)
with app.test_client() as client:
# We need to bypass rate-limiting so creating a fake user instead of logging in
with client.session_transaction() as sess:
sess['id'] = team_id
sess['name'] = name
sess['type'] = 'user'
sess['email'] = email
sess['nonce'] = 'fake-nonce'
data = {
"submission": 'flag',
"challenge_id": 1
}
r = client.post('/api/v1/challenges/attempt', json=data)
resp = r.get_json()['data']
assert resp['status'] == 'correct'
chal = DynamicChallenge.query.filter_by(id=1).first()
if i >= 20:
assert chal.value == chal.minimum
else:
assert chal.initial >= chal.value
assert chal.value > chal.minimum
destroy_ctfd(app)