mirror of https://github.com/JohnHammond/CTFd.git
Fix challenge requirement visibility; add challenge requirements test; mark solves after loading chals (#755)
* Fix challenge requirement visibility * Add challenge requirements test * Mark solves after loading chalsselenium-screenshot-testing
parent
ae90537a59
commit
821c5552c1
|
@ -160,6 +160,40 @@ class Challenge(Resource):
|
||||||
|
|
||||||
chal_class = get_chal_class(chal.type)
|
chal_class = get_chal_class(chal.type)
|
||||||
|
|
||||||
|
requirements = chal.requirements
|
||||||
|
if requirements:
|
||||||
|
if current_user.authed():
|
||||||
|
user = get_current_user()
|
||||||
|
solve_ids = Solves.query \
|
||||||
|
.with_entities(Solves.challenge_id) \
|
||||||
|
.filter_by(account_id=user.account_id) \
|
||||||
|
.order_by(Solves.challenge_id.asc()) \
|
||||||
|
.all()
|
||||||
|
solve_ids = set([value for value, in solve_ids])
|
||||||
|
|
||||||
|
prereqs = set(requirements.get('prerequisites', []))
|
||||||
|
anonymize = requirements.get('anonymize')
|
||||||
|
if solve_ids >= prereqs:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if anonymize:
|
||||||
|
return {
|
||||||
|
'success': True,
|
||||||
|
'data': {
|
||||||
|
'id': chal.id,
|
||||||
|
'type': 'hidden',
|
||||||
|
'name': '???',
|
||||||
|
'value': 0,
|
||||||
|
'category': '???',
|
||||||
|
'tags': [],
|
||||||
|
'template': '',
|
||||||
|
'script': ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
abort(403)
|
||||||
|
else:
|
||||||
|
abort(403)
|
||||||
|
|
||||||
tags = [
|
tags = [
|
||||||
tag['value'] for tag in TagSchema(
|
tag['value'] for tag in TagSchema(
|
||||||
"user", many=True).dump(
|
"user", many=True).dump(
|
||||||
|
@ -286,6 +320,7 @@ class ChallengeAttempt(Resource):
|
||||||
.filter_by(account_id=user.account_id) \
|
.filter_by(account_id=user.account_id) \
|
||||||
.order_by(Solves.challenge_id.asc()) \
|
.order_by(Solves.challenge_id.asc()) \
|
||||||
.all()
|
.all()
|
||||||
|
solve_ids = set([solve_id for solve_id, in solve_ids])
|
||||||
|
|
||||||
prereqs = set(requirements.get('prerequisites', []))
|
prereqs = set(requirements.get('prerequisites', []))
|
||||||
if solve_ids >= prereqs:
|
if solve_ids >= prereqs:
|
||||||
|
|
|
@ -69,7 +69,9 @@ function updateChalWindow(obj) {
|
||||||
$('#submit-key').prop('disabled', true);
|
$('#submit-key').prop('disabled', true);
|
||||||
window.challenge.submit(function (data) {
|
window.challenge.submit(function (data) {
|
||||||
renderSubmissionResponse(data);
|
renderSubmissionResponse(data);
|
||||||
loadchals();
|
loadchals(function () {
|
||||||
|
marksolves();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -161,8 +163,6 @@ function renderSubmissionResponse(response, cb) {
|
||||||
answer_input.removeClass("too-fast");
|
answer_input.removeClass("too-fast");
|
||||||
}, 3000);
|
}, 3000);
|
||||||
}
|
}
|
||||||
marksolves();
|
|
||||||
// updatesolves();
|
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
$('.alert').slideUp();
|
$('.alert').slideUp();
|
||||||
$('#submit-key').removeClass("disabled-button");
|
$('#submit-key').removeClass("disabled-button");
|
||||||
|
|
|
@ -297,52 +297,6 @@ def test_challenge_kpm_limit():
|
||||||
destroy_ctfd(app)
|
destroy_ctfd(app)
|
||||||
|
|
||||||
|
|
||||||
# def test_submitting_flags_with_large_ips():
|
|
||||||
# """Test that users with high octect IP addresses can submit flags"""
|
|
||||||
# app = create_ctfd()
|
|
||||||
# with app.app_context():
|
|
||||||
# register_user(app)
|
|
||||||
# client = login_as_user(app)
|
|
||||||
#
|
|
||||||
# # SQLite doesn't support BigInteger well so we can't test it properly
|
|
||||||
# ip_addresses = ['172.18.0.1', '255.255.255.255', '2001:0db8:85a3:0000:0000:8a2e:0370:7334']
|
|
||||||
# for ip_address in ip_addresses:
|
|
||||||
# # Monkeypatch get_ip
|
|
||||||
# def get_ip_fake(req=None):
|
|
||||||
# return ip_address
|
|
||||||
# utils.get_ip = get_ip_fake
|
|
||||||
#
|
|
||||||
# # Generate challenge and flag
|
|
||||||
# chal = gen_challenge(app.db)
|
|
||||||
# chal_id = chal.id
|
|
||||||
# flag = gen_flag(app.db, chal=chal.id, flag=u'correct_key')
|
|
||||||
#
|
|
||||||
# # Submit wrong_key
|
|
||||||
# with client.session_transaction() as sess:
|
|
||||||
# data = {
|
|
||||||
# "key": 'wrong_key',
|
|
||||||
# "nonce": sess.get('nonce')
|
|
||||||
# }
|
|
||||||
# r = client.post('/api/v1/challenges/attempt'.format(chal_id), json=data)
|
|
||||||
# assert r.status_code == 200
|
|
||||||
# resp = json.loads(r.data.decode('utf8'))
|
|
||||||
# assert resp.get('status') == 0 and resp.get('message') == "Incorrect"
|
|
||||||
# assert Fails.query.filter_by(ip=ip_address).first()
|
|
||||||
#
|
|
||||||
# # Submit correct key
|
|
||||||
# with client.session_transaction() as sess:
|
|
||||||
# data = {
|
|
||||||
# "key": 'correct_key',
|
|
||||||
# "nonce": sess.get('nonce')
|
|
||||||
# }
|
|
||||||
# r = client.post('/api/v1/challenges/attempt'.format(chal_id), json=data)
|
|
||||||
# assert r.status_code == 200
|
|
||||||
# resp = json.loads(r.data.decode('utf8'))
|
|
||||||
# assert resp.get('status') == 1 and resp.get('message') == "Correct"
|
|
||||||
# assert Solves.query.filter_by(ip=ip_address).first()
|
|
||||||
# destroy_ctfd(app)
|
|
||||||
|
|
||||||
|
|
||||||
def test_that_view_challenges_unregistered_works():
|
def test_that_view_challenges_unregistered_works():
|
||||||
'''Test that view_challenges_unregistered works'''
|
'''Test that view_challenges_unregistered works'''
|
||||||
app = create_ctfd()
|
app = create_ctfd()
|
||||||
|
@ -449,6 +403,71 @@ def test_hidden_challenge_is_unsolveable():
|
||||||
destroy_ctfd(app)
|
destroy_ctfd(app)
|
||||||
|
|
||||||
|
|
||||||
|
def test_challenge_with_requirements_is_unsolveable():
|
||||||
|
"""Test that a challenge with a requirement is unsolveable without first solving the requirement"""
|
||||||
|
app = create_ctfd()
|
||||||
|
with app.app_context():
|
||||||
|
register_user(app)
|
||||||
|
client = login_as_user(app)
|
||||||
|
chal1 = gen_challenge(app.db)
|
||||||
|
flag1 = gen_flag(app.db, challenge_id=chal1.id, content='flag')
|
||||||
|
|
||||||
|
requirements = {
|
||||||
|
'prerequisites': [1]
|
||||||
|
}
|
||||||
|
chal2 = gen_challenge(app.db, requirements=requirements)
|
||||||
|
app.db.session.commit()
|
||||||
|
|
||||||
|
flag2 = gen_flag(app.db, challenge_id=chal2.id, content='flag')
|
||||||
|
|
||||||
|
r = client.get('/api/v1/challenges')
|
||||||
|
challenges = r.get_json()['data']
|
||||||
|
assert len(challenges) == 1
|
||||||
|
assert challenges[0]['id'] == 1
|
||||||
|
|
||||||
|
r = client.get('/api/v1/challenges/2')
|
||||||
|
assert r.status_code == 403
|
||||||
|
assert r.get_json().get('data') is None
|
||||||
|
|
||||||
|
# Attempt to solve hidden Challenge 2
|
||||||
|
data = {
|
||||||
|
"submission": 'flag',
|
||||||
|
"challenge_id": 2
|
||||||
|
}
|
||||||
|
r = client.post('/api/v1/challenges/attempt', json=data)
|
||||||
|
assert r.status_code == 403
|
||||||
|
assert r.get_json().get('data') is None
|
||||||
|
|
||||||
|
# Solve Challenge 1
|
||||||
|
data = {
|
||||||
|
"submission": 'flag',
|
||||||
|
"challenge_id": 1
|
||||||
|
}
|
||||||
|
r = client.post('/api/v1/challenges/attempt', json=data)
|
||||||
|
resp = r.get_json()['data']
|
||||||
|
assert resp['status'] == 'correct'
|
||||||
|
|
||||||
|
# Challenge 2 should now be visible
|
||||||
|
r = client.get('/api/v1/challenges')
|
||||||
|
challenges = r.get_json()['data']
|
||||||
|
assert len(challenges) == 2
|
||||||
|
|
||||||
|
r = client.get('/api/v1/challenges/2')
|
||||||
|
assert r.status_code == 200
|
||||||
|
assert r.get_json().get('data')['id'] == 2
|
||||||
|
|
||||||
|
# Attempt to solve the now-visible Challenge 2
|
||||||
|
data = {
|
||||||
|
"submission": 'flag',
|
||||||
|
"challenge_id": 2
|
||||||
|
}
|
||||||
|
r = client.post('/api/v1/challenges/attempt', json=data)
|
||||||
|
assert r.status_code == 200
|
||||||
|
assert resp['status'] == 'correct'
|
||||||
|
|
||||||
|
destroy_ctfd(app)
|
||||||
|
|
||||||
|
|
||||||
def test_challenges_cannot_be_solved_while_paused():
|
def test_challenges_cannot_be_solved_while_paused():
|
||||||
"""Test that challenges cannot be solved when the CTF is paused"""
|
"""Test that challenges cannot be solved when the CTF is paused"""
|
||||||
app = create_ctfd()
|
app = create_ctfd()
|
||||||
|
@ -488,55 +507,3 @@ def test_challenges_cannot_be_solved_while_paused():
|
||||||
wrong_keys = Fails.query.count()
|
wrong_keys = Fails.query.count()
|
||||||
assert wrong_keys == 0
|
assert wrong_keys == 0
|
||||||
destroy_ctfd(app)
|
destroy_ctfd(app)
|
||||||
|
|
||||||
|
|
||||||
# def test_challenge_solves_can_be_seen():
|
|
||||||
# """Test that the /solves endpoint works properly for users"""
|
|
||||||
# app = create_ctfd()
|
|
||||||
# with app.app_context():
|
|
||||||
# register_user(app)
|
|
||||||
#
|
|
||||||
# with app.test_client() as client:
|
|
||||||
# r = client.get('/solves')
|
|
||||||
# assert r.location.startswith("http://localhost/login?next=")
|
|
||||||
# assert r.status_code == 302
|
|
||||||
#
|
|
||||||
# client = login_as_user(app)
|
|
||||||
#
|
|
||||||
# r = client.get('/solves')
|
|
||||||
# data = r.get_data(as_text=True)
|
|
||||||
# data = json.loads(data)
|
|
||||||
#
|
|
||||||
# assert len(data['solves']) == 0
|
|
||||||
#
|
|
||||||
# chal = gen_challenge(app.db)
|
|
||||||
# chal_id = chal.id
|
|
||||||
# flag = gen_flag(app.db, chal=chal_id, flag='flag')
|
|
||||||
# with client.session_transaction() as sess:
|
|
||||||
# data = {
|
|
||||||
# "key": 'flag',
|
|
||||||
# "nonce": sess.get('nonce')
|
|
||||||
# }
|
|
||||||
# r = client.post('/api/v1/challenges/attempt'.format(chal_id), json=data)
|
|
||||||
#
|
|
||||||
# data = r.get_data(as_text=True)
|
|
||||||
# data = json.loads(data)
|
|
||||||
#
|
|
||||||
# r = client.get('/solves')
|
|
||||||
# data = r.get_data(as_text=True)
|
|
||||||
# data = json.loads(data)
|
|
||||||
#
|
|
||||||
# assert len(data['solves']) > 0
|
|
||||||
#
|
|
||||||
# team = Teams.query.filter_by(id=2).first()
|
|
||||||
# team.banned = True
|
|
||||||
# db.session.commit()
|
|
||||||
#
|
|
||||||
# r = client.get('/solves')
|
|
||||||
# data = r.get_data(as_text=True)
|
|
||||||
# data = json.loads(data)
|
|
||||||
#
|
|
||||||
# team = Teams.query.filter_by(id=2).first()
|
|
||||||
# assert team.banned
|
|
||||||
# assert len(data['solves']) > 0
|
|
||||||
# destroy_ctfd(app)
|
|
||||||
|
|
Loading…
Reference in New Issue