diff --git a/CTFd/api/v1/unlocks.py b/CTFd/api/v1/unlocks.py index 33aae35..61403b5 100644 --- a/CTFd/api/v1/unlocks.py +++ b/CTFd/api/v1/unlocks.py @@ -59,6 +59,16 @@ class UnlockList(Resource): if response.errors: return {"success": False, "errors": response.errors}, 400 + existing = Unlocks.query.filter_by(**req).first() + if existing: + return ( + { + "success": False, + "errors": {"target": "You've already unlocked this this target"}, + }, + 400, + ) + db.session.add(response.data) award_schema = AwardSchema() diff --git a/tests/api/v1/user/test_hints.py b/tests/api/v1/user/test_hints.py index b35a009..ff51bd0 100644 --- a/tests/api/v1/user/test_hints.py +++ b/tests/api/v1/user/test_hints.py @@ -95,6 +95,27 @@ def test_api_hint_unlocked(): 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_api_hints_admin_access(): """Can the users access /api/v1/hints if not admin""" app = create_ctfd()