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") 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_ctfd(app)
def listing(): standings = get_standings() return render_template( "scoreboard.html", standings=standings, score_frozen=config.is_scoreboard_frozen(), )
def test_challenge_team_submit(): """Is a user's solved challenge reflected by 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) gen_challenge(app.db) gen_flag(app.db, 1) app.db.session.commit() with login_as_user(app, name="user_name") as client: flag = {"challenge_id": 1, "submission": "flag"} client.post('/api/v1/challenges/attempt', json=flag) with login_as_user(app) as second_client: flag = {"challenge_id": 1, "submission": "flag"} r = second_client.post('/api/v1/challenges/attempt', json=flag) assert r.json['data']['status'] == 'already_solved' standings = get_standings() assert standings[0][2] == "team_name" assert standings[0][3] == 100 destroy_ctfd(app)
def get(self): challenge_count = Challenges.query.count() or 1 total_points = (Challenges.query.with_entities( db.func.sum(Challenges.value).label("sum")).filter_by( state="visible").first().sum) or 0 # Convert Decimal() to int in some database backends for Python 2 total_points = int(total_points) # Divide score by challenges to get brackets with explicit floor division bracket_size = total_points // challenge_count # Get standings standings = get_standings(admin=True) # Iterate over standings and increment the count for each bracket for each standing within that bracket bottom, top = 0, bracket_size count = 1 brackets = defaultdict(lambda: 0) for t in reversed(standings): if ((t.score >= bottom) and (t.score <= top)) or t.score <= 0: brackets[top] += 1 else: count += 1 bottom, top = (bracket_size, (bracket_size * count)) brackets[top] += 1 return {"success": True, "data": {"brackets": brackets}}
def multi_scoreboard(sb=None): if sb == None: sb = 'Global' infos = get_infos() if config.is_scoreboard_frozen(): infos.append("Scoreboard has been frozen") if is_admin() is True and scores_visible() is False: infos.append("Scores are not currently visible to users") standings = get_standings() teams = [] scoreboards = ["Global"] for t in Teams.query.all(): if sb == "Global" and (t.name not in teams): teams.append(t.name) for f in t.fields: if f.name not in scoreboards: scoreboards.append(f.name) if f.name == sb and (t.name not in teams): teams.append(t.name) if sb not in scoreboards: abort(404) filtered_standings = [st for st in standings if st[2] in teams] return render_template("multi_scoreboard.html", standings=filtered_standings, infos=infos, scoreboards=scoreboards, scoreboard=sb)
def get(self): standings = get_standings() response = [] mode = get_config("user_mode") if mode == TEAMS_MODE: team_ids = [] for team in standings: team_ids.append(team.account_id) teams = Teams.query.filter(Teams.id.in_(team_ids)).all() teams = [next(t for t in teams if t.id == id) for id in team_ids] for i, x in enumerate(standings): entry = { "pos": i + 1, "account_id": x.account_id, "oauth_id": x.oauth_id, "name": x.name, "score": int(x.score), } if mode == TEAMS_MODE: members = [] for member in teams[i].members: members.append({ "id": member.id, "oauth_id": member.oauth_id, "name": member.name, "score": int(member.score), }) entry["members"] = members response.append(entry) return {"success": True, "data": response}
def get(self): standings = get_standings() response = [] mode = get_config('user_mode') if mode == TEAMS_MODE: team_ids = [] for team in standings: team_ids.append(team.account_id) teams = Teams.query.filter(Teams.id.in_(team_ids)).all() teams = [next(t for t in teams if t.id == id) for id in team_ids] for i, x in enumerate(standings): entry = { 'pos': i + 1, 'account_id': x.account_id, 'oauth_id': x.oauth_id, 'name': x.name, 'score': int(x.score) } if mode == TEAMS_MODE: members = [] for member in teams[i].members: members.append({ 'id': member.id, 'oauth_id': member.oauth_id, 'name': member.name, 'score': int(member.score) }) entry['members'] = members response.append(entry) return {'success': True, 'data': response}
def listing(): infos = get_infos() if config.is_scoreboard_frozen(): infos.append("Scoreboard has been frozen") standings = get_standings() return render_template("scoreboard.html", standings=standings, infos=infos)
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_admin_standings(): app = create_ctfd(user_mode="teams") with app.app_context(): setup_app(app) standings = get_standings(admin=True) assert standings[0].name == "team1" assert standings[0].score == 100
def listing(): infos = get_infos() if config.is_scoreboard_frozen(): infos.append("Результаты заморожены") if is_admin() is True and scores_visible() is False: infos.append("Результаты сейчас не отображаются для участников") standings = get_standings() return render_template("scoreboard.html", standings=standings, infos=infos)
def listing(): infos = get_infos() if config.is_scoreboard_frozen(): infos.append("Scoreboard has been frozen") if is_admin() is True and scores_visible() is False: infos.append("Scores are not currently visible to users") standings = get_standings() return render_template("scoreboard.html", standings=standings, infos=infos)
def test_standings(): app = create_ctfd(user_mode="teams") with app.app_context(): setup_app(app) standings = get_standings() assert standings[0].name == "team2" assert standings[0].score == 100 destroy_ctfd(app)
def get(self, count): response = {} standings = get_standings(count=count) team_ids = [team.account_id for team in standings] solves = Solves.query.filter(Solves.account_id.in_(team_ids)) awards = Awards.query.filter(Awards.account_id.in_(team_ids)) freeze = get_config('freeze') if freeze: solves = solves.filter(Solves.date < unix_time_to_utc(freeze)) awards = awards.filter(Awards.date < unix_time_to_utc(freeze)) solves = solves.all() awards = awards.all() for i, team in enumerate(team_ids): response[i + 1] = { 'id': standings[i].account_id, 'name': standings[i].name, 'solves': [] } for solve in solves: if solve.account_id == team: response[i + 1]['solves'].append({ 'challenge_id': solve.challenge_id, 'account_id': solve.account_id, 'team_id': solve.team_id, 'user_id': solve.user_id, 'value': solve.challenge.value, 'date': isoformat(solve.date) }) for award in awards: if award.account_id == team: response[i + 1]['solves'].append({ 'challenge_id': None, 'account_id': award.account_id, 'team_id': award.team_id, 'user_id': award.user_id, 'value': award.value, 'date': isoformat(award.date) }) response[i + 1]['solves'] = sorted(response[i + 1]['solves'], key=lambda k: k['date']) return { 'success': True, 'data': response }
def get(self): standings = get_standings() response = [] mode = get_config("user_mode") account_type = get_mode_as_word() if mode == TEAMS_MODE: r = db.session.execute( select([ Users.id, Users.name, Users.oauth_id, Users.team_id, Users.hidden, Users.banned, ]).where(Users.team_id.isnot(None))) users = r.fetchall() membership = defaultdict(dict) for u in users: if u.hidden is False and u.banned is False: membership[u.team_id][u.id] = { "id": u.id, "oauth_id": u.oauth_id, "name": u.name, "score": 0, } # Get user_standings as a dict so that we can more quickly get member scores user_standings = get_user_standings() for u in user_standings: membership[u.team_id][u.user_id]["score"] = int(u.score) for i, x in enumerate(standings): entry = { "pos": i + 1, "account_id": x.account_id, "account_url": generate_account_url(account_id=x.account_id), "account_type": account_type, "oauth_id": x.oauth_id, "name": x.name, "score": int(x.score), } if mode == TEAMS_MODE: entry["members"] = list(membership[x.account_id].values()) response.append(entry) return {"success": True, "data": response}
def listing(): infos = get_infos() if config.is_scoreboard_frozen(): infos.append("Scoreboard has been frozen") if is_admin() is True and scores_visible() is False: infos.append("Scores are not currently visible to users") standings = get_standings() standings_interne = [s for s in standings if s.fields != True] standings_externe = [s for s in standings if s.fields == True] return render_template("scoreboard.html", standings_interne=standings_interne, standings_externe=standings_externe, infos=infos)
def get(self): response = {'tasks': [], 'standings': []} mode = get_config("user_mode") freeze = get_config("freeze") # Get Challenges challenges = Challenges.query.filter( and_(Challenges.state != 'hidden', Challenges.state != 'locked')).order_by( Challenges.value).all() challenges_ids = {} for i, x in enumerate(challenges): response['tasks'].append(unicode_safe(x.name) + " " + str(x.value)) challenges_ids[x.id] = unicode_safe(x.name) + " " + str(x.value) # Get Standings if mode == TEAMS_MODE: standings = get_standings() team_ids = [team.account_id for team in standings] else: abort(501, "CTFTime only accepts team scores.") solves = Solves.query.filter(Solves.account_id.in_(team_ids)) if freeze: solves = solves.filter(Solves.date < unix_time_to_utc(freeze)) for i, team in enumerate(team_ids): team_standing = { 'pos': i + 1, 'team': unicode_safe(standings[i].name), 'score': float(standings[i].score), 'taskStats': {} } team_solves = solves.filter( Solves.account_id == standings[i].account_id) for solve in team_solves: chall_name = challenges_ids[solve.challenge_id] team_standing["taskStats"][chall_name] = { "points": solve.challenge.value, "time": unix_time(solve.date), } response['standings'].append(team_standing) return response
def test_scoreboard_team_score(): """Is a user's submitted flag reflected on the team's score on /scoreboard""" app = create_ctfd(user_mode="teams") with app.app_context(): user = gen_user(app.db, name="user") team = gen_team(app.db) user.team_id = team.id team.members.append(user) gen_challenge(app.db) gen_flag(app.db, 1) app.db.session.commit() with login_as_user(app) as client: flag = {"challenge_id": 1, "submission": "flag"} client.post("/api/v1/challenges/attempt", json=flag) standings = get_standings() assert standings[0][2] == "team_name" assert standings[0][3] == 100 destroy_ctfd(app)
def static_html(route): """ Route in charge of routing users to Pages. :param route: :return: """ page = get_page(route) if page is None: abort(404) else: if route == 'index': try: highscore = str(get_standings()[0][3]).rjust(6, '0') except: highscore = '000000' return render_template('index.html', highscore=highscore) elif page.auth_required and authed() is False: return redirect(url_for('auth.login', next=request.full_path)) return render_template("page.html", content=markdown(page.content))
def scoreboard_listing(): infos = get_infos() if config.is_scoreboard_frozen(): infos.append("Scoreboard has been frozen") if is_admin() is True and scores_visible() is False: infos.append("Scores are not currently visible to users") Model = get_model() standings = get_standings(fields=[Model.email]) category_standings = get_category_standings() return render_template( "scoreboard.html", standings=standings, category_standings=category_standings, infos=infos, email_group_asset=email_group_asset, )
def view_single_rank(): # override templates dir_path = os.path.dirname(os.path.realpath(__file__)) template_path = os.path.join(dir_path, 'assets') template_path = os.path.join(template_path, 'scoreboard.html') override_template("scoreboard.html", open(template_path).read()) # get categories categories = get_all_categories() # load scores standings = get_standings() ranks = [] for index1, category in enumerate(categories): ranks.append([]) for standing in standings: account_id = standing.account_id name = standing.name oauth_id = standing.oauth_id score = get_user_scores_for_each_category( standing.account_id, categories)[index1] ranks[index1].append([account_id, name, oauth_id, score]) ranks[index1] = sorted(ranks[index1], key=(lambda x: x[3]), reverse=True) # rank[0] account_id # rank[1] name # rank[2] oauth_id # rank[3] score return render_template("scoreboard.html", categories=categories, enumerate=enumerate, ranks=ranks, standings=standings, score_frozen=config.is_scoreboard_frozen())
def scoreboard_listing(): standings = get_standings(admin=True) user_standings = get_user_standings(admin=True) if is_teams_mode() else None return render_template( "admin/scoreboard.html", standings=standings, user_standings=user_standings )
def get(self, count): response = {} standings = get_standings(count=count) team_ids = [team.account_id for team in standings] solves = Solves.query.filter(Solves.account_id.in_(team_ids)) awards = Awards.query.filter(Awards.account_id.in_(team_ids)) freeze = get_config("freeze") if freeze: solves = solves.filter(Solves.date < unix_time_to_utc(freeze)) awards = awards.filter(Awards.date < unix_time_to_utc(freeze)) solves = solves.all() awards = awards.all() for i, team in enumerate(team_ids): response[i + 1] = { "id": standings[i].account_id, "name": standings[i].name, "solves": [], } for solve in solves: if solve.account_id == team: response[i + 1]["solves"].append({ "challenge_id": solve.challenge_id, "account_id": solve.account_id, "team_id": solve.team_id, "user_id": solve.user_id, "value": solve.challenge.value, "date": isoformat(solve.date), }) for award in awards: if award.account_id == team: response[i + 1]["solves"].append({ "challenge_id": None, "account_id": award.account_id, "team_id": award.team_id, "user_id": award.user_id, "value": award.value, "date": isoformat(award.date), }) response[i + 1]["solves"] = sorted(response[i + 1]["solves"], key=lambda k: k["date"]) return {"success": True, "data": response}
def get(self): standings = get_standings() response = [] mode = get_config("user_mode") account_type = get_mode_as_word() if mode == TEAMS_MODE: team_ids = [] for team in standings: team_ids.append(team.account_id) # Get team objects with members explicitly loaded in teams = (Teams.query.options(joinedload(Teams.members)).filter( Teams.id.in_(team_ids)).all()) # Sort according to team_ids order teams = [next(t for t in teams if t.id == id) for id in team_ids] # Get user_standings as a dict so that we can more quickly get member scores user_standings = get_user_standings() users = {} for u in user_standings: users[u.user_id] = u for i, x in enumerate(standings): entry = { "pos": i + 1, "account_id": x.account_id, "account_url": generate_account_url(account_id=x.account_id), "account_type": account_type, "oauth_id": x.oauth_id, "name": x.name, "score": int(x.score), } if mode == TEAMS_MODE: members = [] # This code looks like it would be slow # but it is faster than accessing each member's score individually for member in teams[i].members: user = users.get(member.id) if user: members.append({ "id": user.user_id, "oauth_id": user.oauth_id, "name": user.name, "score": int(user.score), }) else: if member.hidden is False and member.banned is False: members.append({ "id": member.id, "oauth_id": member.oauth_id, "name": member.name, "score": 0, }) entry["members"] = members response.append(entry) return {"success": True, "data": response}
def get(self, count): response = {} standings = get_standings(count=count) team_ids = [team.account_id for team in standings] solves = Solves.query.filter(Solves.account_id.in_(team_ids)) awards = Awards.query.filter(Awards.account_id.in_(team_ids)) hints_name_list = db.session.query( db.func.concat("Hint ", Hints.id).label("hints_name")).count() if hints_name_list > 0: hints_name = db.func.concat("Hint ", Hints.id).label("hints_name") awards = db.session.query( Awards.account_id.label('account_id'), Awards.team_id.label('team_id'), Awards.user_id.label('user_id'), Awards.value.label('value'), Awards.date.label('date'), ) \ .join(Hints, Awards.name == hints_name) \ .join(Solves, (Awards.account_id == Solves.account_id) & (Hints.challenge_id == Solves.challenge_id)) \ .filter(Awards.value != 0) \ .filter(Awards.account_id.in_(team_ids)) awards_by_admin = db.session.query( Awards.account_id.label('account_id'), Awards.team_id.label('team_id'), Awards.user_id.label('user_id'), Awards.value.label('value'), Awards.date.label('date'), ) \ .filter(Awards.account_id.in_(team_ids)) \ .filter(Awards.value > 0) awards = awards.union(awards_by_admin) freeze = get_config('freeze') if freeze: solves = solves.filter(Solves.date < unix_time_to_utc(freeze)) awards = awards.filter(Awards.date < unix_time_to_utc(freeze)) solves = solves.all() awards = awards.all() for i, team in enumerate(team_ids): response[i + 1] = { 'id': standings[i].account_id, 'name': standings[i].name, 'solves': [] } for solve in solves: if solve.account_id == team: response[i + 1]['solves'].append({ 'challenge_id': solve.challenge_id, 'account_id': solve.account_id, 'team_id': solve.team_id, 'user_id': solve.user_id, 'value': solve.challenge.value, 'date': isoformat(solve.date) }) for award in awards: if award.account_id == team: response[i + 1]['solves'].append({ 'challenge_id': None, 'account_id': award.account_id, 'team_id': award.team_id, 'user_id': award.user_id, 'value': award.value, 'date': isoformat(award.date) }) response[i + 1]['solves'] = sorted(response[i + 1]['solves'], key=lambda k: k['date']) return {'success': True, 'data': response}
def get(self, count): response = {} standings = get_standings(count=count) team_ids = [team.account_id for team in standings] solves = Solves.query.filter(Solves.account_id.in_(team_ids)) awards = Awards.query.filter(Awards.account_id.in_(team_ids)) freeze = get_config("freeze") if freeze: solves = solves.filter(Solves.date < unix_time_to_utc(freeze)) awards = awards.filter(Awards.date < unix_time_to_utc(freeze)) solves = solves.all() awards = awards.all() # Build a mapping of accounts to their solves and awards solves_mapper = defaultdict(list) for solve in solves: solves_mapper[solve.account_id].append({ "challenge_id": solve.challenge_id, "account_id": solve.account_id, "team_id": solve.team_id, "user_id": solve.user_id, "value": solve.challenge.value, "date": isoformat(solve.date), }) for award in awards: solves_mapper[award.account_id].append({ "challenge_id": None, "account_id": award.account_id, "team_id": award.team_id, "user_id": award.user_id, "value": award.value, "date": isoformat(award.date), }) # Sort all solves by date for team_id in solves_mapper: solves_mapper[team_id] = sorted(solves_mapper[team_id], key=lambda k: k["date"]) for i, team in enumerate(team_ids): response[i + 1] = { "id": standings[i].account_id, "name": standings[i].name, "solves": solves_mapper.get(standings[i].account_id, []), } return {"success": True, "data": response}
def dump_scoreboard_csv(): # TODO: Add fields to scoreboard data temp = StringIO() writer = csv.writer(temp) standings = get_standings() # Get all user fields in a specific order user_fields = UserFields.query.all() user_field_ids = [f.id for f in user_fields] user_field_names = [f.name for f in user_fields] if is_teams_mode(): team_fields = TeamFields.query.all() team_field_ids = [f.id for f in team_fields] team_field_names = [f.name for f in team_fields] header = ([ "place", "team", "team id", "score", "member name", "member id", "member email", "member score", ] + user_field_names + team_field_names) writer.writerow(header) for i, standing in enumerate(standings): team = Teams.query.filter_by(id=standing.account_id).first() # Build field entries using the order of the field values team_field_entries = { f.field_id: f.value for f in team.field_entries } team_field_values = [ team_field_entries.get(f_id, "") for f_id in team_field_ids ] team_row = [ i + 1, team.name, team.id, standing.score, "", "", ] + team_field_values writer.writerow(team_row) for member in team.members: user_field_entries = { f.field_id: f.value for f in member.field_entries } user_field_values = [ user_field_entries.get(f_id, "") for f_id in user_field_ids ] user_row = [ "", "", "", "", member.name, member.id, member.email, member.score, ] + user_field_values writer.writerow(user_row) elif is_users_mode(): header = ["place", "user", "score"] + user_field_names writer.writerow(header) for i, standing in enumerate(standings): user = Users.query.filter_by(id=standing.account_id).first() # Build field entries using the order of the field values user_field_entries = { f.field_id: f.value for f in user.field_entries } user_field_values = [ user_field_entries.get(f_id, "") for f_id in user_field_ids ] user_row = [i + 1, user.name, standing.score] + user_field_values writer.writerow(user_row) # In Python 3 send_file requires bytes output = BytesIO() output.write(temp.getvalue().encode("utf-8")) output.seek(0) temp.close() return output