CoolFace
Apppublic

vishalbhat07/ctfd

sourceHugging Faceupdated 6mo agoView on Hugging Face
0likes
test_dynamic.py403 linesDownload Raw Back to challenges
1#!/usr/bin/env python2# -*- coding: utf-8 -*-3 4from CTFd.models import Challenges5from CTFd.plugins.dynamic_challenges import DynamicChallenge, DynamicValueChallenge6from CTFd.utils.security.signing import hmac7from tests.helpers import (8    FakeRequest,9    create_ctfd,10    destroy_ctfd,11    gen_flag,12    gen_user,13    login_as_user,14    register_user,15)16 17 18def test_can_create_dynamic_challenge():19    """Test that dynamic challenges can be made from the API/admin panel"""20    app = create_ctfd(enable_plugins=True)21    with app.app_context():22        register_user(app)23        client = login_as_user(app, name="admin", password="password")24 25        challenge_data = {26            "name": "name",27            "category": "category",28            "description": "description",29            "initial": 100,30            "decay": 20,31            "minimum": 1,32            "state": "hidden",33            "type": "dynamic",34        }35 36        r = client.post("/api/v1/challenges", json=challenge_data)37        assert r.get_json().get("data")["id"] == 138 39        challenges = DynamicChallenge.query.all()40        assert len(challenges) == 141 42        challenge = challenges[0]43        assert challenge.value == 10044        assert challenge.initial == 10045        assert challenge.decay == 2046        assert challenge.minimum == 147    destroy_ctfd(app)48 49 50def test_can_update_dynamic_challenge():51    app = create_ctfd(enable_plugins=True)52    with app.app_context():53        challenge_data = {54            "name": "name",55            "category": "category",56            "description": "description",57            "initial": 100,58            "decay": 20,59            "minimum": 1,60            "state": "hidden",61            "type": "dynamic",62        }63        req = FakeRequest(form=challenge_data)64        challenge = DynamicValueChallenge.create(req)65 66        assert challenge.value == 10067        assert challenge.initial == 10068        assert challenge.decay == 2069        assert challenge.minimum == 170 71        challenge_data = {72            "name": "new_name",73            "category": "category",74            "description": "new_description",75            "value": "200",76            "initial": "200",77            "decay": "40",78            "minimum": "5",79            "max_attempts": "0",80            "state": "visible",81        }82 83        req = FakeRequest(form=challenge_data)84        challenge = DynamicValueChallenge.update(challenge, req)85 86        assert challenge.name == "new_name"87        assert challenge.description == "new_description"88        assert challenge.value == 20089        assert challenge.initial == 20090        assert challenge.decay == 4091        assert challenge.minimum == 592        assert challenge.state == "visible"93 94    destroy_ctfd(app)95 96 97def test_can_add_requirement_dynamic_challenge():98    """Test that requirements can be added to dynamic challenges"""99    app = create_ctfd(enable_plugins=True)100    with app.app_context():101        challenge_data = {102            "name": "name",103            "category": "category",104            "description": "description",105            "initial": 100,106            "decay": 20,107            "minimum": 1,108            "state": "hidden",109            "type": "dynamic",110        }111        req = FakeRequest(form=challenge_data)112        challenge = DynamicValueChallenge.create(req)113 114        assert challenge.value == 100115        assert challenge.initial == 100116        assert challenge.decay == 20117        assert challenge.minimum == 1118 119        challenge_data = {120            "name": "second_name",121            "category": "category",122            "description": "new_description",123            "value": "200",124            "initial": "200",125            "decay": "40",126            "minimum": "5",127            "max_attempts": "0",128            "state": "visible",129        }130 131        req = FakeRequest(form=challenge_data)132        challenge = DynamicValueChallenge.create(req)133 134        assert challenge.name == "second_name"135        assert challenge.description == "new_description"136        assert challenge.value == 200137        assert challenge.initial == 200138        assert challenge.decay == 40139        assert challenge.minimum == 5140        assert challenge.state == "visible"141 142        challenge_data = {"requirements": [1]}143 144        req = FakeRequest(form=challenge_data)145        challenge = DynamicValueChallenge.update(challenge, req)146 147        assert challenge.requirements == [1]148 149    destroy_ctfd(app)150 151 152def test_can_delete_dynamic_challenge():153    """Test that dynamic challenges can be deleted"""154    app = create_ctfd(enable_plugins=True)155    with app.app_context():156        register_user(app)157        client = login_as_user(app, name="admin", password="password")158 159        challenge_data = {160            "name": "name",161            "category": "category",162            "description": "description",163            "initial": 100,164            "decay": 20,165            "minimum": 1,166            "state": "hidden",167            "type": "dynamic",168        }169 170        r = client.post("/api/v1/challenges", json=challenge_data)171        assert r.get_json().get("data")["id"] == 1172 173        challenges = DynamicChallenge.query.all()174        assert len(challenges) == 1175 176        challenge = challenges[0]177        DynamicValueChallenge.delete(challenge)178 179        challenges = DynamicChallenge.query.all()180        assert len(challenges) == 0181    destroy_ctfd(app)182 183 184def test_dynamic_challenge_loses_value_properly():185    app = create_ctfd(enable_plugins=True)186    with app.app_context():187        register_user(app)188        client = login_as_user(app, name="admin", password="password")189 190        challenge_data = {191            "name": "name",192            "category": "category",193            "description": "description",194            "initial": 100,195            "decay": 20,196            "minimum": 1,197            "state": "visible",198            "type": "dynamic",199        }200 201        r = client.post("/api/v1/challenges", json=challenge_data)202        assert r.get_json().get("data")["id"] == 1203 204        gen_flag(app.db, challenge_id=1, content="flag")205 206        for i, team_id in enumerate(range(2, 26)):207            name = "user{}".format(team_id)208            email = "user{}@examplectf.com".format(team_id)209            # We need to bypass rate-limiting so gen_user instead of register_user210            user = gen_user(app.db, name=name, email=email)211            user_id = user.id212 213            with app.test_client() as client:214                # We need to bypass rate-limiting so creating a fake user instead of logging in215                with client.session_transaction() as sess:216                    sess["id"] = user_id217                    sess["nonce"] = "fake-nonce"218                    sess["hash"] = hmac(user.password)219 220                data = {"submission": "flag", "challenge_id": 1}221 222                r = client.post("/api/v1/challenges/attempt", json=data)223                resp = r.get_json()["data"]224                assert resp["status"] == "correct"225 226                chal = DynamicChallenge.query.filter_by(id=1).first()227                if i >= 20:228                    assert chal.value == chal.minimum229                else:230                    assert chal.initial >= chal.value231                    assert chal.value > chal.minimum232    destroy_ctfd(app)233 234 235def test_dynamic_challenge_doesnt_lose_value_on_update():236    """Dynamic challenge updates without changing any values or solves shouldn't change the current value. See #1043"""237    app = create_ctfd(enable_plugins=True)238    with app.app_context():239        challenge_data = {240            "name": "name",241            "category": "category",242            "description": "description",243            "initial": 10000,244            "decay": 4,245            "minimum": 10,246            "state": "visible",247            "type": "dynamic",248        }249        req = FakeRequest(form=challenge_data)250        challenge = DynamicValueChallenge.create(req)251        challenge_id = challenge.id252        gen_flag(app.db, challenge_id=challenge.id, content="flag")253        register_user(app)254        with login_as_user(app) as client:255            data = {"submission": "flag", "challenge_id": challenge_id}256            r = client.post("/api/v1/challenges/attempt", json=data)257            assert r.status_code == 200258            assert r.get_json()["data"]["status"] == "correct"259        chal = Challenges.query.filter_by(id=challenge_id).first()260        prev_chal_value = chal.value261        chal = DynamicValueChallenge.update(chal, req)262        assert prev_chal_value == chal.value263    destroy_ctfd(app)264 265 266def test_dynamic_challenge_value_isnt_affected_by_hidden_users():267    app = create_ctfd(enable_plugins=True)268    with app.app_context():269        register_user(app)270        client = login_as_user(app, name="admin", password="password")271 272        challenge_data = {273            "name": "name",274            "category": "category",275            "description": "description",276            "initial": 100,277            "decay": 20,278            "minimum": 1,279            "state": "visible",280            "type": "dynamic",281        }282 283        r = client.post("/api/v1/challenges", json=challenge_data)284        assert r.get_json().get("data")["id"] == 1285 286        gen_flag(app.db, challenge_id=1, content="flag")287 288        # Make a solve as a regular user. This should not affect the value.289        data = {"submission": "flag", "challenge_id": 1}290 291        r = client.post("/api/v1/challenges/attempt", json=data)292        resp = r.get_json()["data"]293        assert resp["status"] == "correct"294 295        # Make solves as hidden users. Also should not affect value296        for _, team_id in enumerate(range(2, 26)):297            name = "user{}".format(team_id)298            email = "user{}@examplectf.com".format(team_id)299            # We need to bypass rate-limiting so gen_user instead of register_user300            user = gen_user(app.db, name=name, email=email)301            user.hidden = True302            app.db.session.commit()303            user_id = user.id304 305            with app.test_client() as client:306                # We need to bypass rate-limiting so creating a fake user instead of logging in307                with client.session_transaction() as sess:308                    sess["id"] = user_id309                    sess["nonce"] = "fake-nonce"310                    sess["hash"] = hmac(user.password)311 312                data = {"submission": "flag", "challenge_id": 1}313 314                r = client.post("/api/v1/challenges/attempt", json=data)315                assert r.status_code == 200316                resp = r.get_json()["data"]317                assert resp["status"] == "correct"318 319                chal = DynamicChallenge.query.filter_by(id=1).first()320                assert chal.value == chal.initial321    destroy_ctfd(app)322 323 324def test_dynamic_challenges_reset():325    app = create_ctfd(enable_plugins=True)326    with app.app_context():327        client = login_as_user(app, name="admin", password="password")328 329        challenge_data = {330            "name": "name",331            "category": "category",332            "description": "description",333            "initial": 100,334            "decay": 20,335            "minimum": 1,336            "state": "hidden",337            "type": "dynamic",338        }339 340        r = client.post("/api/v1/challenges", json=challenge_data)341        assert Challenges.query.count() == 1342        assert DynamicChallenge.query.count() == 1343 344        with client.session_transaction() as sess:345            data = {"nonce": sess.get("nonce"), "challenges": "on"}346            r = client.post("/admin/reset", data=data)347            assert r.location.endswith("/admin/statistics")348        assert Challenges.query.count() == 0349        assert DynamicChallenge.query.count() == 0350 351    destroy_ctfd(app)352 353 354def test_dynamic_challenge_linear_loses_value_properly():355    app = create_ctfd(enable_plugins=True)356    with app.app_context():357        register_user(app)358        client = login_as_user(app, name="admin", password="password")359 360        challenge_data = {361            "name": "name",362            "category": "category",363            "description": "description",364            "function": "linear",365            "initial": 100,366            "decay": 5,367            "minimum": 1,368            "state": "visible",369            "type": "dynamic",370        }371 372        r = client.post("/api/v1/challenges", json=challenge_data)373        assert r.get_json().get("data")["id"] == 1374 375        gen_flag(app.db, challenge_id=1, content="flag")376 377        for i, team_id in enumerate(range(2, 26)):378            name = "user{}".format(team_id)379            email = "user{}@examplectf.com".format(team_id)380            # We need to bypass rate-limiting so gen_user instead of register_user381            user = gen_user(app.db, name=name, email=email)382            user_id = user.id383 384            with app.test_client() as client:385                # We need to bypass rate-limiting so creating a fake user instead of logging in386                with client.session_transaction() as sess:387                    sess["id"] = user_id388                    sess["nonce"] = "fake-nonce"389                    sess["hash"] = hmac(user.password)390 391                data = {"submission": "flag", "challenge_id": 1}392                r = client.post("/api/v1/challenges/attempt", json=data)393                resp = r.get_json()["data"]394                assert resp["status"] == "correct"395 396                chal = DynamicChallenge.query.filter_by(id=1).first()397 398                if i >= 20:399                    assert chal.value == chal.minimum400                else:401                    assert chal.value == (chal.initial - (i * 5))402    destroy_ctfd(app)403