def patch(self): team = get_current_team() if team.captain_id != session["id"]: return ( { "success": False, "errors": { "": ["Only team captains can edit team information"] }, }, 403, ) data = request.get_json() response = TeamSchema(view="self", instance=team, partial=True).load(data) if response.errors: return {"success": False, "errors": response.errors}, 400 db.session.commit() clear_team_session(team_id=team.id) response = TeamSchema("self").dump(response.data) db.session.close() return {"success": True, "data": response.data}
def delete(self): team_disbanding = get_config("team_disbanding", default="inactive_only") if team_disbanding == "disabled": return ( { "success": False, "errors": {"": ["Team disbanding is currently disabled"]}, }, 403, ) team = get_current_team() if team.captain_id != session["id"]: return ( { "success": False, "errors": {"": ["Only team captains can disband their team"]}, }, 403, ) # The team must not have performed any actions in the CTF performed_actions = any( [ team.solves != [], team.fails != [], team.awards != [], Submissions.query.filter_by(team_id=team.id).all() != [], Unlocks.query.filter_by(team_id=team.id).all() != [], ] ) if performed_actions: return ( { "success": False, "errors": { "": [ "You cannot disband your team as it has participated in the event. " "Please contact an admin to disband your team or remove a member." ] }, }, 403, ) for member in team.members: member.team_id = None clear_user_session(user_id=member.id) db.session.delete(team) db.session.commit() clear_team_session(team_id=team.id) clear_standings() db.session.close() return {"success": True}
def join(): infos = get_infos() errors = get_errors() user = get_current_user_attrs() if user.team_id: errors.append("You are already in a team. You cannot join another.") if request.method == "GET": team_size_limit = get_config("team_size", default=0) if team_size_limit: plural = "" if team_size_limit == 1 else "s" infos.append("Teams are limited to {limit} member{plural}".format( limit=team_size_limit, plural=plural)) return render_template("teams/join_team.html", infos=infos, errors=errors) if request.method == "POST": teamname = request.form.get("name") passphrase = request.form.get("password", "").strip() team = Teams.query.filter_by(name=teamname).first() if errors: return ( render_template("teams/join_team.html", infos=infos, errors=errors), 403, ) if team and verify_password(passphrase, team.password): team_size_limit = get_config("team_size", default=0) if team_size_limit and len(team.members) >= team_size_limit: errors.append( "{name} has already reached the team size limit of {limit}" .format(name=team.name, limit=team_size_limit)) return render_template("teams/join_team.html", infos=infos, errors=errors) user = get_current_user() user.team_id = team.id db.session.commit() if len(team.members) == 1: team.captain_id = user.id db.session.commit() clear_user_session(user_id=user.id) clear_team_session(team_id=team.id) return redirect(url_for("challenges.listing")) else: errors.append("That information is incorrect") return render_template("teams/join_team.html", infos=infos, errors=errors)
def join(): infos = get_infos() errors = get_errors() if request.method == "GET": team_size_limit = get_config("team_size", default=0) if team_size_limit: plural = "" if team_size_limit == 1 else "s" infos.append( "Команды могут содержать не больше {limit} участников".format( limit=team_size_limit, plural=plural)) return render_template("teams/join_team.html", infos=infos, errors=errors) if request.method == "POST": teamname = request.form.get("name") passphrase = request.form.get("password", "").strip() team = Teams.query.filter_by(name=teamname).first() if team and verify_password(passphrase, team.password): team_size_limit = get_config("team_size", default=0) if team_size_limit and len(team.members) >= team_size_limit: errors.append( "Команда {name} уже достигла лимит в {limit} участников". format(name=team.name, limit=team_size_limit)) return render_template("teams/join_team.html", infos=infos, errors=errors) user = get_current_user() user.team_id = team.id db.session.commit() if len(team.members) == 1: team.captain_id = user.id db.session.commit() clear_user_session(user_id=user.id) clear_team_session(team_id=team.id) return redirect(url_for("challenges.listing")) else: errors.append("Такая информация некорректна") return render_template("teams/join_team.html", infos=infos, errors=errors)
def delete(self, team_id): team = Teams.query.filter_by(id=team_id).first_or_404() team_id = team.id for member in team.members: member.team_id = None clear_user_session(user_id=member.id) db.session.delete(team) db.session.commit() clear_team_session(team_id=team_id) clear_standings() db.session.close() return {"success": True}
def new(): infos = get_infos() errors = get_errors() if request.method == "GET": team_size_limit = get_config("team_size", default=0) if team_size_limit: plural = "" if team_size_limit == 1 else "s" infos.append( "Teams are limited to {limit} member{plural}".format( limit=team_size_limit, plural=plural ) ) return render_template("teams/new_team.html", infos=infos, errors=errors) elif request.method == "POST": teamname = request.form.get("name", "").strip() passphrase = request.form.get("password", "").strip() errors = get_errors() user = get_current_user() existing_team = Teams.query.filter_by(name=teamname).first() if existing_team: errors.append("That team name is already taken") if not teamname: errors.append("That team name is invalid") if errors: return render_template("teams/new_team.html", errors=errors) team = Teams(name=teamname, password=passphrase, captain_id=user.id) db.session.add(team) db.session.commit() user.team_id = team.id db.session.commit() clear_user_session(user_id=user.id) clear_team_session(team_id=team.id) return redirect(url_for("challenges.listing"))
def patch(self, team_id): team = Teams.query.filter_by(id=team_id).first_or_404() data = request.get_json() data["id"] = team_id schema = TeamSchema(view="admin", instance=team, partial=True) response = schema.load(data) if response.errors: return {"success": False, "errors": response.errors}, 400 response = schema.dump(response.data) db.session.commit() clear_team_session(team_id=team.id) clear_standings() db.session.close() return {"success": True, "data": response.data}
def invite(): infos = get_infos() errors = get_errors() code = request.args.get("code") if code is None: abort(404) user = get_current_user_attrs() if user.team_id: errors.append("You are already in a team. You cannot join another.") try: team = Teams.load_invite_code(code) except TeamTokenExpiredException: abort(403, description="This invite URL has expired") except TeamTokenInvalidException: abort(403, description="This invite URL is invalid") team_size_limit = get_config("team_size", default=0) if request.method == "GET": if team_size_limit: infos.append( "Teams are limited to {limit} member{plural}".format( limit=team_size_limit, plural=pluralize(number=team_size_limit) ) ) return render_template( "teams/invite.html", team=team, infos=infos, errors=errors ) if request.method == "POST": if errors: return ( render_template( "teams/invite.html", team=team, infos=infos, errors=errors ), 403, ) if team_size_limit and len(team.members) >= team_size_limit: errors.append( "{name} has already reached the team size limit of {limit}".format( name=team.name, limit=team_size_limit ) ) return ( render_template( "teams/invite.html", team=team, infos=infos, errors=errors ), 403, ) user = get_current_user() user.team_id = team.id db.session.commit() clear_user_session(user_id=user.id) clear_team_session(team_id=team.id) return redirect(url_for("challenges.listing"))
def new(): infos = get_infos() errors = get_errors() if bool(get_config("team_creation", default=True)) is False: abort( 403, description="Team creation is currently disabled. Please join an existing team.", ) num_teams_limit = int(get_config("num_teams", default=0)) num_teams = Teams.query.filter_by(banned=False, hidden=False).count() if num_teams_limit and num_teams >= num_teams_limit: abort( 403, description=f"Reached the maximum number of teams ({num_teams_limit}). Please join an existing team.", ) user = get_current_user_attrs() if user.team_id: errors.append("You are already in a team. You cannot join another.") if request.method == "GET": team_size_limit = get_config("team_size", default=0) if team_size_limit: plural = "" if team_size_limit == 1 else "s" infos.append( "Teams are limited to {limit} member{plural}".format( limit=team_size_limit, plural=plural ) ) return render_template("teams/new_team.html", infos=infos, errors=errors) elif request.method == "POST": teamname = request.form.get("name", "").strip() passphrase = request.form.get("password", "").strip() website = request.form.get("website") affiliation = request.form.get("affiliation") user = get_current_user() existing_team = Teams.query.filter_by(name=teamname).first() if existing_team: errors.append("That team name is already taken") if not teamname: errors.append("That team name is invalid") # Process additional user fields fields = {} for field in TeamFields.query.all(): fields[field.id] = field entries = {} for field_id, field in fields.items(): value = request.form.get(f"fields[{field_id}]", "").strip() if field.required is True and (value is None or value == ""): errors.append("Please provide all required fields") break # Handle special casing of existing profile fields if field.name.lower() == "affiliation": affiliation = value break elif field.name.lower() == "website": website = value break if field.field_type == "boolean": entries[field_id] = bool(value) else: entries[field_id] = value if website: valid_website = validators.validate_url(website) else: valid_website = True if affiliation: valid_affiliation = len(affiliation) < 128 else: valid_affiliation = True if valid_website is False: errors.append("Websites must be a proper URL starting with http or https") if valid_affiliation is False: errors.append("Please provide a shorter affiliation") if errors: return render_template("teams/new_team.html", errors=errors), 403 team = Teams(name=teamname, password=passphrase, captain_id=user.id) if website: team.website = website if affiliation: team.affiliation = affiliation db.session.add(team) db.session.commit() for field_id, value in entries.items(): entry = TeamFieldEntries(field_id=field_id, value=value, team_id=team.id) db.session.add(entry) db.session.commit() user.team_id = team.id db.session.commit() clear_user_session(user_id=user.id) clear_team_session(team_id=team.id) return redirect(url_for("challenges.listing"))
def oauth_redirect(): oauth_code = request.args.get("code") state = request.args.get("state") if session["nonce"] != state: log("logins", "[{date}] {ip} - OAuth State validation mismatch") error_for(endpoint="auth.login", message="OAuth State validation mismatch.") return redirect(url_for("auth.login")) if oauth_code: url = (get_app_config("OAUTH_TOKEN_ENDPOINT") or get_config("oauth_token_endpoint") or "https://auth.majorleaguecyber.org/oauth/token") client_id = get_app_config("OAUTH_CLIENT_ID") or get_config( "oauth_client_id") client_secret = get_app_config("OAUTH_CLIENT_SECRET") or get_config( "oauth_client_secret") headers = {"content-type": "application/x-www-form-urlencoded"} data = { "code": oauth_code, "client_id": client_id, "client_secret": client_secret, "grant_type": "authorization_code", } token_request = requests.post(url, data=data, headers=headers) if token_request.status_code == requests.codes.ok: token = token_request.json()["access_token"] user_url = (get_app_config("OAUTH_API_ENDPOINT") or get_config("oauth_api_endpoint") or "https://api.majorleaguecyber.org/user") headers = { "Authorization": "Bearer " + str(token), "Content-type": "application/json", } api_data = requests.get(url=user_url, headers=headers).json() user_id = api_data["id"] user_name = api_data["name"] user_email = api_data["email"] user = Users.query.filter_by(email=user_email).first() if user is None: # Check if we are allowing registration before creating users if registration_visible() or mlc_registration(): user = Users( name=user_name, email=user_email, oauth_id=user_id, verified=True, ) db.session.add(user) db.session.commit() else: log("logins", "[{date}] {ip} - Public registration via MLC blocked") error_for( endpoint="auth.login", message= "Public registration is disabled. Please try again later.", ) return redirect(url_for("auth.login")) if get_config("user_mode") == TEAMS_MODE: team_id = api_data["team"]["id"] team_name = api_data["team"]["name"] team = Teams.query.filter_by(oauth_id=team_id).first() if team is None: team = Teams(name=team_name, oauth_id=team_id, captain_id=user.id) db.session.add(team) db.session.commit() clear_team_session(team_id=team.id) team_size_limit = get_config("team_size", default=0) if team_size_limit and len(team.members) >= team_size_limit: plural = "" if team_size_limit == 1 else "s" size_error = "Teams are limited to {limit} member{plural}.".format( limit=team_size_limit, plural=plural) error_for(endpoint="auth.login", message=size_error) return redirect(url_for("auth.login")) team.members.append(user) db.session.commit() if user.oauth_id is None: user.oauth_id = user_id user.verified = True db.session.commit() clear_user_session(user_id=user.id) login_user(user) return redirect(url_for("challenges.listing")) else: log("logins", "[{date}] {ip} - OAuth token retrieval failure") error_for(endpoint="auth.login", message="OAuth token retrieval failure.") return redirect(url_for("auth.login")) else: log("logins", "[{date}] {ip} - Received redirect without OAuth code") error_for(endpoint="auth.login", message="Received redirect without OAuth code.") return redirect(url_for("auth.login"))
def new(): infos = get_infos() errors = get_errors() if request.method == "GET": team_size_limit = get_config("team_size", default=0) if team_size_limit: plural = "" if team_size_limit == 1 else "s" infos.append("Teams are limited to {limit} member{plural}".format( limit=team_size_limit, plural=plural)) return render_template("teams/new_team.html", infos=infos, errors=errors) elif request.method == "POST": teamname = request.form.get("name", "").strip() passphrase = request.form.get("password", "").strip() errors = get_errors() website = request.form.get("website") affiliation = request.form.get("affiliation") user = get_current_user() existing_team = Teams.query.filter_by(name=teamname).first() if existing_team: errors.append("Такое имя команды уже занято") if not teamname: errors.append("Имя команды неправильное") # Process additional user fields fields = {} for field in TeamFields.query.all(): fields[field.id] = field entries = {} for field_id, field in fields.items(): value = request.form.get(f"fields[{field_id}]", "").strip() if field.required is True and (value is None or value == ""): errors.append("Пожалуйста, укажите все обязательные поля") break # Handle special casing of existing profile fields if field.name.lower() == "affiliation": affiliation = value break elif field.name.lower() == "website": website = value break if field.field_type == "boolean": entries[field_id] = bool(value) else: entries[field_id] = value if website: valid_website = validators.validate_url(website) else: valid_website = True if affiliation: valid_affiliation = len(affiliation) < 128 else: valid_affiliation = True if valid_website is False: errors.append( "Вебсайт должен быть правильной ссылкой, начинающейся с http или https" ) if valid_affiliation is False: errors.append("Пожалуйста, укажите учреждение покороче") if errors: return render_template("teams/new_team.html", errors=errors) team = Teams(name=teamname, password=passphrase, captain_id=user.id) if website: team.website = website if affiliation: team.affiliation = affiliation db.session.add(team) db.session.commit() for field_id, value in entries.items(): entry = TeamFieldEntries(field_id=field_id, value=value, team_id=team.id) db.session.add(entry) db.session.commit() user.team_id = team.id db.session.commit() clear_user_session(user_id=user.id) clear_team_session(team_id=team.id) return redirect(url_for("challenges.listing"))