diff --git a/app.py b/app.py index 15293ad..df63994 100644 --- a/app.py +++ b/app.py @@ -208,7 +208,7 @@ def run_instance(): challenge_name = request.form.get("challenge_name", None) # Disable captcha on debug mode - if not current_app.config["ENABLE_RECAPTCHA"] and not recaptcha.verify(): + if not current_app.config["DEBUG"] and current_app.config["ENABLE_RECAPTCHA"] and not recaptcha.verify(): flash("Captcha failed.", "red") return redirect(url_for('index')) @@ -222,8 +222,8 @@ def run_instance(): flash("The challenge name is not valid.", "red") return redirect(url_for('index')) - if get_challenge_count_per_team(session["team_id"]) >= MAX_CHALLENGES_PER_TEAM: - flash(f"Your team has reached the maximum number of concurrent running instances ({MAX_CHALLENGES_PER_TEAM}).", "red") + if get_challenge_count_per_team(session["team_id"]) >= MAX_INSTANCE_PER_TEAM: + flash(f"Your team has reached the maximum number of concurrent running instances ({MAX_INSTANCE_PER_TEAM}).", "red") return redirect(url_for('index')) remove_user_running_instance(session["user_id"]) diff --git a/app/app.py b/app/app.py index 9003780..770274f 100644 --- a/app/app.py +++ b/app/app.py @@ -16,7 +16,7 @@ def create_app(): app.config["SQLALCHEMY_DATABASE_URI"] = getenv("DATABASE_URI") app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False - app.config["ENABLE_RECAPTCHA"] = getenv("ENABLE_RECAPTCHA", False) + app.config["ENABLE_RECAPTCHA"] = getenv("ENABLE_RECAPTCHA", False) in ["1", "True", "TRUE"] app.config["RECAPTCHA_SITE_KEY"] = getenv("RECAPTCHA_SITE_KEY", "") app.config["RECAPTCHA_SECRET_KEY"] = getenv("RECAPTCHA_SECRET_KEY", "") diff --git a/app/utils.py b/app/utils.py index 959eda1..b5c619f 100644 --- a/app/utils.py +++ b/app/utils.py @@ -190,6 +190,25 @@ def check_challenge_name(challenge_name): return True return False +def check_mode(key): + """ + Returns the mode of the CTFd instance (teams or user) + """ + base_url = CTFD_URL.strip('/') + try: + req = requests.get(f"{base_url}/api/v1/teams", + headers={"Authorization":f"Token {key}", "Content-Type": "application/json"}) + # If /api/v1/teams endpoint is accessible, then CTF mode is teams, otherwise if 404 it's user. Dirty but works. + if req.status_code == 200: + return "teams" + elif req.status_code == 404: + return "user" + else: + return False + except Exception as err: + current_app.logger.error(f"Error checking mode: {err}") + current_app.logger.error("Error: %s", err) + return False def check_access_key(key): """ @@ -202,7 +221,7 @@ def check_access_key(key): "team_name": None, "is_admin": False } - + pattern = r'^ctfd_[a-zA-Z0-9]+$' if not re.match(pattern, key): return False, "Invalid access key, wrong format!", user @@ -215,18 +234,30 @@ def check_access_key(key): success = resp_json.get("success", False) user["user_id"] = resp_json.get("data", {}).get("id", "") user["username"] = resp_json.get("data", {}).get("name", "") - user["team_id"] = resp_json.get("data", {}).get("team_id", False) - # User is not in a team - if not success or not user["team_id"]: - return False, "User not in a team or invalid token.", user + mode = check_mode(key) + current_app.logger.error(mode) + + if mode == "teams": + user["team_id"] = resp_json.get("data", {}).get("team_id", False) - resp_json = requests.get(f"{base_url}/api/v1/teams/{user['team_id']}", - headers={"Authorization":f"Token {key}", "Content-Type":"application/json"}).json() - user["team_name"] = resp_json.get("data", {}).get("name", "") + # User is not in a team + if not success or not user["team_id"]: + return False, "User not in a team or invalid token.", user + + resp_json = requests.get(f"{base_url}/api/v1/teams/{user['team_id']}", + headers={"Authorization":f"Token {key}", "Content-Type":"application/json"}).json() + user["team_name"] = resp_json.get("data", {}).get("name", "") + # Easy workaround to keep the app working even in solo mode is to emulate a fake team based on user id and username :) + elif mode == "user": + user["team_id"] = resp_json.get("data", {}).get("id", "") + user["team_name"] = resp_json.get("data", {}).get("name", "") + else: + return False, "An error occurred while checking the CTF mode" resp_json = requests.get(f"{base_url}/api/v1/configs", headers={"Authorization":f"Token {key}", "Content-Type":"application/json"}).json() user["is_admin"] = resp_json.get("success", False) + return True, "", user except Exception as err: current_app.logger.error("Unable to reach CTFd with access key: %s", key)