def test_hint_team_unlock(): """Is a user's unlocked hint reflected on other team members""" app = create_kmactf(user_mode="teams") with app.app_context(): user = gen_user(app.db) second_user = gen_user(app.db, name="user", email="*****@*****.**") team = gen_team(app.db) user.team_id = team.id second_user.team_id = team.id team.members.append(user) team.members.append(second_user) chal = gen_challenge(app.db) gen_hint(app.db, chal.id, content="hint", cost=1, type="standard") gen_award(app.db, 2, team.id) app.db.session.commit() with login_as_user(app, name="user_name") as client: client.get("/api/v1/hints/1") client.post("/api/v1/unlocks", json={"target": 1, "type": "hints"}) client.get("/api/v1/hints/1") with login_as_user(app) as second_client: second_client.get("/api/v1/hints/1") second_client.post("/api/v1/unlocks", json={ "target": 1, "type": "hints" }) r = second_client.get("/api/v1/hints/1") assert r.json["data"]["content"] == "hint" standings = get_standings() assert standings[0][2] == "team_name" assert standings[0][3] == 99 destroy_kmactf(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_kmactf() 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_kmactf(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_kmactf() 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_kmactf(app)
def test_hint_team_unlocking_without_points(): """Test that teams cannot enter negative point valuations from unlocking hints""" app = create_ctfd(user_mode="teams") with app.app_context(): user = gen_user(app.db) second_user = gen_user(app.db, name="user", email="*****@*****.**") team = gen_team(app.db) user.team_id = team.id second_user.team_id = team.id team.members.append(user) team.members.append(second_user) chal = gen_challenge(app.db) gen_hint(app.db, chal.id, content="hint", cost=1, type="standard") app.db.session.commit() with login_as_user(app, name="user_name") as client: # Assert that we don't see a hint r = client.get("/api/v1/hints/1") assert r.get_json()["data"].get("content") is None # Attempt to unlock the hint r = client.post("/api/v1/unlocks", json={ "target": 1, "type": "hints" }) assert r.status_code == 400 assert (r.get_json()["errors"]["score"] == "You do not have enough points to unlock this hint") 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_kmactf() 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_kmactf(app)
def test_that_view_challenges_unregistered_works(): '''Test that view_challenges_unregistered works''' app = create_ctfd() with app.app_context(): chal = gen_challenge(app.db, name=text_type('ЁЯР║')) chal_id = chal.id gen_hint(app.db, chal_id) client = app.test_client() r = client.get('/api/v1/challenges', json='') assert r.status_code == 403 r = client.get('/api/v1/challenges') assert r.status_code == 302 set_config('challenge_visibility', 'public') client = app.test_client() r = client.get('/api/v1/challenges') assert r.get_json()['data'] r = client.get('/api/v1/challenges/1/solves') assert r.get_json().get('data') is not None data = { "submission": 'not_flag', "challenge_id": chal_id } r = client.post('/api/v1/challenges/attempt'.format(chal_id), json=data) assert r.status_code == 403 assert r.get_json().get('data').get('status') == "authentication_required" assert r.get_json().get('data').get('message') is None destroy_ctfd(app)
def test_export_ctf(): """Test that CTFd can export the database""" app = create_ctfd() if not app.config.get("SQLALCHEMY_DATABASE_URI").startswith("sqlite"): with app.app_context(): register_user(app) chal1 = gen_challenge(app.db, name=text_type("🐺")) gen_challenge(app.db, name=text_type("🐺"), requirements={"prerequisites": [1]}) chal_id = chal1.id gen_hint(app.db, chal_id) client = login_as_user(app) with client.session_transaction(): data = {"target": 1, "type": "hints"} r = client.post("/api/v1/unlocks", json=data) output = r.get_data(as_text=True) json.loads(output) app.db.session.commit() backup = export_ctf() with open("export.test_export_ctf.zip", "wb") as f: f.write(backup.read()) export = zipfile.ZipFile("export.test_export_ctf.zip", "r") data = json.loads(export.read("db/challenges.json")) assert data["results"][1]["requirements"] == {"prerequisites": [1]} os.remove("export.test_export_ctf.zip") 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_that_view_challenges_unregistered_works(): """Test that view_challenges_unregistered works""" app = create_ctfd() with app.app_context(): chal = gen_challenge(app.db, name=text_type("ЁЯР║")) chal_id = chal.id gen_hint(app.db, chal_id) client = app.test_client() r = client.get("/api/v1/challenges", json="") assert r.status_code == 403 r = client.get("/api/v1/challenges") assert r.status_code == 302 set_config("challenge_visibility", "public") client = app.test_client() r = client.get("/api/v1/challenges") assert r.get_json()["data"] r = client.get("/api/v1/challenges/1/solves") assert r.get_json().get("data") is not None data = {"submission": "not_flag", "challenge_id": chal_id} r = client.post("/api/v1/challenges/attempt", json=data) assert r.status_code == 403 assert r.get_json().get("data").get( "status") == "authentication_required" assert r.get_json().get("data").get("message") is None destroy_ctfd(app)
def test_hint_team_unlock(): """Is a user's unlocked hint reflected on other team members""" app = create_ctfd(user_mode="teams") with app.app_context(): user = gen_user(app.db) second_user = gen_user(app.db, name="user", email="*****@*****.**") team = gen_team(app.db) user.team_id = team.id second_user.team_id = team.id team.members.append(user) team.members.append(second_user) chal = gen_challenge(app.db) gen_hint(app.db, chal.id, content="hint", cost=1, type="standard") # Give the points to the user that doesn't unlock # Users that unlock hints should be able to unlock but cost their team points gen_award(app.db, user_id=3, team_id=team.id) app.db.session.commit() with login_as_user(app, name="user_name") as client: # Assert that we don't see a hint r = client.get("/api/v1/hints/1") assert r.get_json()["data"].get("content") is None # Unlock the hint client.post("/api/v1/unlocks", json={"target": 1, "type": "hints"}) # Assert that we see a hint r = client.get("/api/v1/hints/1") assert r.get_json()["data"].get("content") with login_as_user(app) as second_client: # Assert that we see a hint r = second_client.get("/api/v1/hints/1") assert r.get_json()["data"].get("content") # Assert that we can't double unlock r = second_client.post("/api/v1/unlocks", json={ "target": 1, "type": "hints" }) assert r.status_code == 400 assert (r.get_json()["errors"]["target"] == "You've already unlocked this this target") # Assert that we see a hint r = second_client.get("/api/v1/hints/1") assert r.json["data"]["content"] == "hint" # Verify standings # We start with 100 points from the award. # We lose a point because we unlock successfully once standings = get_standings() assert standings[0][2] == "team_name" assert standings[0][3] == 99 destroy_ctfd(app)
def test_api_hint_locked(): """Can the users unlock /api/v1/hints/<hint_id> if they don't have enough points""" app = create_ctfd() with app.app_context(): chal = gen_challenge(app.db) gen_hint(app.db, chal.id, content="This is a hint", cost=1, type="standard") register_user(app) client = login_as_user(app) r = client.get("/api/v1/hints/1") assert r.status_code == 200 r = client.post("/api/v1/unlocks", json={"target": 1, "type": "hints"}) assert r.status_code == 400 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_no_cost(): """Test that hints with no cost can be unlocked""" app = create_kmactf() 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_kmactf(app)
def test_api_hint_visibility(): """Can the users load /api/v1/hints/<hint_id> if logged in/out""" app = create_ctfd() with app.app_context(): chal = gen_challenge(app.db) gen_hint(app.db, chal.id) with app.test_client() as non_logged_in_user: r = non_logged_in_user.get("/api/v1/hints/1") assert r.status_code == 302 register_user(app) client = login_as_user(app) r = client.get("/api/v1/hints/1") assert r.status_code == 200 destroy_ctfd(app)
def test_teams_dont_prevent_other_teams_from_unlocking_hints(): """Unlocks from one user don't affect other users""" app = create_ctfd(user_mode="teams") with app.app_context(): chal = gen_challenge(app.db) gen_hint(app.db, chal.id, content="This is a hint", cost=1, type="standard") team1 = gen_team(app.db, name="team1", email="*****@*****.**") team2 = gen_team(app.db, name="team2", email="*****@*****.**") # Give users points with an award gen_award(app.db, user_id=team1.captain_id) gen_award(app.db, user_id=team2.captain_id) captain1 = team1.captain.name captain2 = team2.captain.name app.db.session.commit() # First team unlocks hint with login_as_user(app, name=captain1) as client: r = client.get("/api/v1/hints/1") assert r.status_code == 200 r = client.post("/api/v1/unlocks", json={ "target": 1, "type": "hints" }) assert r.status_code == 200 r = client.get("/api/v1/hints/1") assert r.status_code == 200 # Second team unlocks hint with login_as_user(app, name=captain2) as client: r = client.get("/api/v1/hints/1") assert r.status_code == 200 r = client.post("/api/v1/unlocks", json={ "target": 1, "type": "hints" }) assert r.status_code == 200 r = client.get("/api/v1/hints/1") assert r.status_code == 200 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)
def test_unlocking_hint_for_unicode_challenge(): """Test that hints for challenges with unicode names can be unlocked""" app = create_kmactf() 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_kmactf(app)
def test_api_hint_visibility_ctftime(): """Can the users load /api/v1/hints/<hint_id> if not ctftime""" app = create_ctfd() with app.app_context(), freeze_time("2017-10-7"): 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 chal = gen_challenge(app.db) gen_hint(app.db, chal.id) register_user(app) client = login_as_user(app) r = client.get("/api/v1/hints/1") assert r.status_code == 403 destroy_ctfd(app)
def test_admins_can_preview_hints(): """Test that admins are able to bypass restrictions and preview hints with ?preview=true""" app = create_ctfd() with app.app_context(): gen_challenge(app.db) gen_hint(app.db, challenge_id=1, cost=100) client = login_as_user(app, name="admin", password="******") r = client.get('/api/v1/hints/1') assert r.status_code == 200 hint = r.get_json() assert hint.get('content') is None r = client.get('/api/v1/hints/1?preview=true') assert r.status_code == 200 hint = r.get_json() assert hint['data']['content'] == "This is a hint" destroy_ctfd(app)
def test_users_cannot_preview_hints(): """Test that users aren't able to preview hints""" app = create_ctfd() with app.app_context(): gen_challenge(app.db) gen_hint(app.db, challenge_id=1, cost=100) register_user(app) client = login_as_user(app) r = client.get('/api/v1/hints/1') assert r.status_code == 200 hint = r.get_json() assert hint.get('content') is None r = client.get('/api/v1/hints/1?preview=true') assert r.status_code == 200 hint = r.get_json() assert hint['data'].get('content') is None destroy_ctfd(app)
def test_api_hint_admin_access(): """Can the users patch/delete /api/v1/hint/<hint_id> if not admin""" app = create_ctfd() with app.app_context(): chal = gen_challenge(app.db) gen_hint(app.db, chal.id, content="This is a hint", cost=1, type="standard") admin = login_as_user(app, "admin") register_user(app) client = login_as_user(app) r = client.patch("/api/v1/hints/1", json="") assert r.status_code == 403 r = client.delete("/api/v1/hints/1", json="") assert r.status_code == 403 r_admin = admin.patch("/api/v1/hints/1", json={"cost": 2}) assert r_admin.status_code == 200 r_admin = admin.delete("/api/v1/hints/1", json="") assert r_admin.status_code == 200 destroy_ctfd(app)
def test_users_dont_prevent_other_users_from_unlocking_hints(): """Unlocks from one user don't affect other users""" app = create_ctfd() with app.app_context(): chal = gen_challenge(app.db) gen_hint(app.db, chal.id, content="This is a hint", cost=1, type="standard") register_user(app) register_user(app, name="user2", email="*****@*****.**") # Give users points with an award gen_award(app.db, user_id=2) gen_award(app.db, user_id=3) # First user unlocks hints with login_as_user(app) as client: r = client.get("/api/v1/hints/1") assert r.status_code == 200 r = client.post("/api/v1/unlocks", json={ "target": 1, "type": "hints" }) assert r.status_code == 200 r = client.get("/api/v1/hints/1") assert r.status_code == 200 # Second user unlocks hints with login_as_user(app, name="user2") as client: r = client.get("/api/v1/hints/1") assert r.status_code == 200 r = client.post("/api/v1/unlocks", json={ "target": 1, "type": "hints" }) assert r.status_code == 200 r = client.get("/api/v1/hints/1") assert r.status_code == 200 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_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_with_points(): """Test that hints with a cost are unlocked if you have the points""" app = create_kmactf() 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_kmactf(app)
def test_export_ctf(): """Test that CTFd can export the database""" app = create_ctfd() if not app.config.get('SQLALCHEMY_DATABASE_URI').startswith('sqlite'): 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) with client.session_transaction(): data = {"target": 1, "type": "hints"} r = client.post('/api/v1/unlocks', json=data) output = r.get_data(as_text=True) json.loads(output) app.db.session.commit() backup = export_ctf() with open('export.zip', 'wb') as f: f.write(backup.read()) os.remove('export.zip') destroy_ctfd(app)
def test_api_hint_double_unlock(): """Can a target hint be unlocked twice""" app = create_ctfd() with app.app_context(): chal = gen_challenge(app.db) gen_hint(app.db, chal.id, content="This is a hint", cost=1, type="standard") register_user(app) # Give user points with an award gen_award(app.db, 2) client = login_as_user(app) r = client.get("/api/v1/hints/1") assert r.status_code == 200 r = client.post("/api/v1/unlocks", json={"target": 1, "type": "hints"}) assert r.status_code == 200 r = client.get("/api/v1/hints/1") assert r.status_code == 200 r = client.post("/api/v1/unlocks", json={"target": 1, "type": "hints"}) assert r.status_code == 400 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_api_challenge_with_properties_delete_admin(): """Can a user delete /api/v1/challenges/<challenge_id> if the challenge has other properties""" app = create_ctfd() with app.app_context(): challenge = gen_challenge(app.db) gen_hint(app.db, challenge_id=challenge.id) gen_tag(app.db, challenge_id=challenge.id) gen_flag(app.db, challenge_id=challenge.id) challenge = Challenges.query.filter_by(id=1).first() assert len(challenge.hints) == 1 assert len(challenge.tags) == 1 assert len(challenge.flags) == 1 with login_as_user(app, "admin") as client: r = client.delete("/api/v1/challenges/1", json="") assert r.status_code == 200 assert r.get_json().get("data") is None assert Tags.query.count() == 0 assert Hints.query.count() == 0 assert Flags.query.count() == 0 destroy_ctfd(app)
def test_user_can_unlock_hint(): """Test that a user can unlock a hint if they have enough points""" app = create_kmactf() with app.app_context(): with app.test_client(): register_user(app, name="user1", email="*****@*****.**") 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="******") 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_kmactf(app)