#!/usr/bin/env python # -*- coding: utf-8 -*- from CTFd.models import db, Unlocks, Users from CTFd.utils import set_config, text_type from tests.helpers import (create_ctfd, destroy_ctfd, register_user, login_as_user, gen_challenge, gen_award, gen_flag, gen_hint) from freezegun import freeze_time def test_user_cannot_unlock_hint(): """Test that a user can't unlock a hint if they don't have enough points""" app = create_ctfd() with app.app_context(): with app.test_client(): register_user(app, name="user1", email="user1@ctfd.io") chal = gen_challenge(app.db, value=100) chal_id = chal.id gen_flag(app.db, challenge_id=chal.id, content='flag') hint = gen_hint(db, chal_id, cost=10) hint_id = hint.id client = login_as_user(app, name="user1", password="password") with client.session_transaction(): r = client.get('/api/v1/hints/{}'.format(hint_id)) resp = r.get_json() assert resp['data'].get('content') is None assert resp['data'].get('cost') == 10 destroy_ctfd(app) def test_user_can_unlock_hint(): """Test that a user can unlock a hint if they have enough points""" app = create_ctfd() with app.app_context(): with app.test_client(): register_user(app, name="user1", email="user1@ctfd.io") chal = gen_challenge(app.db, value=100) chal_id = chal.id gen_flag(app.db, challenge_id=chal.id, content='flag') hint = gen_hint(app.db, chal_id, cost=10) hint_id = hint.id gen_award(app.db, user_id=2, value=15) client = login_as_user(app, name="user1", password="password") user = Users.query.filter_by(name="user1").first() assert user.score == 15 with client.session_transaction(): r = client.get('/api/v1/hints/{}'.format(hint_id)) resp = r.get_json() assert resp['data'].get('content') is None params = { "target": hint_id, "type": "hints" } r = client.post('/api/v1/unlocks', json=params) resp = r.get_json() assert resp['success'] is True r = client.get('/api/v1/hints/{}'.format(hint_id)) resp = r.get_json() assert resp['data'].get('content') == "This is a hint" user = Users.query.filter_by(name="user1").first() assert user.score == 5 destroy_ctfd(app) def test_unlocking_hints_with_no_cost(): """Test that hints with no cost can be unlocked""" app = create_ctfd() with app.app_context(): register_user(app) chal = gen_challenge(app.db) chal_id = chal.id gen_hint(app.db, chal_id) client = login_as_user(app) r = client.get('/api/v1/hints/1') resp = r.get_json()['data'] assert resp.get('content') == 'This is a hint' destroy_ctfd(app) def test_unlocking_hints_with_cost_during_ctf_with_points(): """Test that hints with a cost are unlocked if you have the points""" app = create_ctfd() with app.app_context(): register_user(app) chal = gen_challenge(app.db) chal_id = chal.id gen_hint(app.db, chal_id, cost=10) gen_award(app.db, user_id=2) client = login_as_user(app) r = client.get('/api/v1/hints/1') assert r.get_json()['data'].get('content') is None client.post('/api/v1/unlocks', json={ 'target': 1, 'type': 'hints' }) r = client.get('/api/v1/hints/1') assert r.get_json()['data'].get('content') == 'This is a hint' user = Users.query.filter_by(id=2).first() assert user.score == 90 destroy_ctfd(app) def test_unlocking_hints_with_cost_during_ctf_without_points(): """Test that hints with a cost are not unlocked if you don't have the points""" app = create_ctfd() with app.app_context(): register_user(app) chal = gen_challenge(app.db) chal_id = chal.id gen_hint(app.db, chal_id, cost=10) client = login_as_user(app) r = client.get('/api/v1/hints/1') assert r.get_json()['data'].get('content') is None r = client.post('/api/v1/unlocks', json={ 'target': 1, 'type': 'hints' }) assert r.get_json()['errors']['score'] == 'You do not have enough points to unlock this hint' r = client.get('/api/v1/hints/1') assert r.get_json()['data'].get('content') is None user = Users.query.filter_by(id=2).first() assert user.score == 0 destroy_ctfd(app) def test_unlocking_hints_with_cost_before_ctf(): """Test that hints are not unlocked if the CTF hasn't begun""" app = create_ctfd() with app.app_context(): register_user(app) chal = gen_challenge(app.db) chal_id = chal.id gen_hint(app.db, chal_id) gen_award(app.db, user_id=2) set_config('start', '1507089600') # Wednesday, October 4, 2017 12:00:00 AM GMT-04:00 DST set_config('end', '1507262400') # Friday, October 6, 2017 12:00:00 AM GMT-04:00 DST with freeze_time("2017-10-1"): client = login_as_user(app) r = client.get('/api/v1/hints/1') assert r.status_code == 403 assert r.get_json().get('data') is None r = client.post('/api/v1/unlocks', json={ 'target': 1, 'type': 'hints' }) assert r.status_code == 403 assert r.get_json().get('data') is None r = client.get('/api/v1/hints/1') assert r.get_json().get('data') is None assert r.status_code == 403 user = Users.query.filter_by(id=2).first() assert user.score == 100 assert Unlocks.query.count() == 0 destroy_ctfd(app) def test_unlocking_hints_with_cost_during_ended_ctf(): """Test that hints with a cost are not unlocked if the CTF has ended""" app = create_ctfd() with app.app_context(): register_user(app) chal = gen_challenge(app.db) chal_id = chal.id gen_hint(app.db, chal_id, cost=10) gen_award(app.db, user_id=2) set_config('start', '1507089600') # Wednesday, October 4, 2017 12:00:00 AM GMT-04:00 DST set_config('end', '1507262400') # Friday, October 6, 2017 12:00:00 AM GMT-04:00 DST with freeze_time("2017-11-4"): client = login_as_user(app) r = client.get('/api/v1/hints/1') assert r.get_json().get('data') is None assert r.status_code == 403 r = client.post('/api/v1/unlocks', json={ 'target': 1, 'type': 'hints' }) assert r.status_code == 403 assert r.get_json() r = client.get('/api/v1/hints/1') assert r.status_code == 403 user = Users.query.filter_by(id=2).first() assert user.score == 100 assert Unlocks.query.count() == 0 destroy_ctfd(app) def test_unlocking_hints_with_cost_during_frozen_ctf(): """Test that hints with a cost are unlocked if the CTF is frozen.""" app = create_ctfd() with app.app_context(): set_config('freeze', '1507262400') # Friday, October 6, 2017 12:00:00 AM GMT-04:00 DST with freeze_time("2017-10-4"): register_user(app) chal = gen_challenge(app.db) chal_id = chal.id gen_hint(app.db, chal_id, cost=10) gen_award(app.db, user_id=2) with freeze_time("2017-10-8"): client = login_as_user(app) client.get('/api/v1/hints/1') client.post('/api/v1/unlocks', json={ 'target': 1, 'type': 'hints' }) r = client.get('/api/v1/hints/1') resp = r.get_json()['data'] assert resp.get('content') == 'This is a hint' user = Users.query.filter_by(id=2).first() assert user.score == 100 destroy_ctfd(app) def test_unlocking_hint_for_unicode_challenge(): """Test that hints for challenges with unicode names can be unlocked""" app = create_ctfd() with app.app_context(): register_user(app) chal = gen_challenge(app.db, name=text_type('🐺')) chal_id = chal.id gen_hint(app.db, chal_id) client = login_as_user(app) r = client.get('/api/v1/hints/1') assert r.status_code == 200 resp = r.get_json()['data'] assert resp.get('content') == 'This is a hint' destroy_ctfd(app)