def attempts(): if not utils.user_can_view_challenges(): return redirect(url_for('auth.login', next=request.path)) chals = Challenges.query.add_columns('id').all() json = {'maxattempts': []} for chal, chalid in chals: fails = WrongKeys.query.filter_by(teamid=session['id'], chalid=chalid).count() if fails >= int(utils.get_config("max_tries")) and int( utils.get_config("max_tries")) > 0: json['maxattempts'].append({'chalid': chalid}) return jsonify(json)
def topteams(count): json = {'scores': {}} if utils.get_config('view_scoreboard_if_authed') and not utils.authed(): return redirect(url_for('auth.login', next=request.path)) if utils.hide_scores(): return jsonify(json) if count > 20 or count < 0: count = 10 standings = get_standings(count=count) for team in standings: solves = Solves.query.filter_by(teamid=team.teamid) awards = Awards.query.filter_by(teamid=team.teamid) freeze = utils.get_config('freeze') if freeze: solves = solves.filter( Solves.date < utils.unix_time_to_utc(freeze)) awards = awards.filter( Awards.date < utils.unix_time_to_utc(freeze)) solves = solves.all() awards = awards.all() json['scores'][team.name] = [] for x in solves: json['scores'][team.name].append({ 'chal': x.chalid, 'team': x.teamid, 'value': x.chal.value, 'time': utils.unix_time(x.date) }) for award in awards: json['scores'][team.name].append({ 'chal': None, 'team': award.teamid, 'value': award.value, 'time': utils.unix_time(award.date) }) json['scores'][team.name] = sorted(json['scores'][team.name], key=lambda k: k['time']) return jsonify(json)
def admin_pages_view(route): if request.method == 'GET' and request.args.get('mode') == 'create': return render_template('admin/editor.html') if route and request.method == 'GET': page = Pages.query.filter_by(route=route).first() return render_template('admin/editor.html', page=page) if route and request.method == 'POST': page = Pages.query.filter_by(route=route).first() errors = [] html = request.form['html'] route = request.form['route'] if not route: errors.append('Missing URL route') if errors: page = Pages(html, '') return render_template('/admin/editor.html', page=page) if page: page.route = route page.html = html db.session.commit() db.session.close() return redirect(url_for('admin_pages.admin_pages_view')) page = Pages(route, html) db.session.add(page) db.session.commit() db.session.close() return redirect(url_for('admin_pages.admin_pages_view')) pages = Pages.query.all() return render_template('admin/pages.html', routes=pages, css=utils.get_config('css'))
def scoreboard_view(): if utils.get_config('view_scoreboard_if_authed') and not utils.authed(): return redirect(url_for('auth.login', next=request.path)) if utils.hide_scores(): return render_template('scoreboard.html', errors=['Scores are currently hidden']) standings = get_standings() return render_template('scoreboard.html', teams=standings, score_frozen=utils.is_scoreboard_frozen())
def profile(): if utils.authed(): if request.method == "POST": errors = [] name = request.form.get('name') email = request.form.get('email') user = Teams.query.filter_by(id=session['id']).first() if not utils.get_config('prevent_name_change'): names = Teams.query.filter_by(name=name).first() name_len = len(request.form['name']) == 0 emails = Teams.query.filter_by(email=email).first() valid_email = re.match(r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)", email) if ('password' in request.form.keys() and not len(request.form['password']) == 0) and \ (not bcrypt_sha256.verify(request.form.get('confirm').strip(), user.password)): errors.append("Your old password doesn't match what we have.") if not valid_email: errors.append("That email doesn't look right") if not utils.get_config('prevent_name_change') and names and name != session['username']: errors.append('That team name is already taken') if emails and emails.id != session['id']: errors.append('That email has already been used') if not utils.get_config('prevent_name_change') and name_len: errors.append('Pick a longer team name') if len(errors) > 0: return render_template('profile.html', name=name, email=email, errors=errors) else: team = Teams.query.filter_by(id=session['id']).first() if not utils.get_config('prevent_name_change'): team.name = name if team.email != email.lower(): team.email = email.lower() if utils.get_config('verify_emails'): team.verified = False session['username'] = team.name if 'password' in request.form.keys() and not len(request.form['password']) == 0: team.password = bcrypt_sha256.encrypt(request.form.get('password')) db.session.commit() db.session.close() return redirect(url_for('views.profile')) else: user = Teams.query.filter_by(id=session['id']).first() name = user.name email = user.email prevent_name_change = utils.get_config('prevent_name_change') confirm_email = utils.get_config('verify_emails') and not user.verified return render_template('profile.html', name=name, email=email, prevent_name_change=prevent_name_change, confirm_email=confirm_email) else: return redirect(url_for('auth.login'))
def solves(teamid=None): solves = None awards = None if teamid is None: if utils.is_admin(): solves = Solves.query.filter_by(teamid=session['id']).all() elif utils.user_can_view_challenges(): if utils.authed(): solves = Solves.query.join(Teams, Solves.teamid == Teams.id).filter( Solves.teamid == session['id'], Teams.banned == False).all() else: return jsonify({'solves': []}) else: return redirect(url_for('auth.login', next='solves')) else: solves = Solves.query.filter_by(teamid=teamid) awards = Awards.query.filter_by(teamid=teamid) freeze = utils.get_config('freeze') if freeze: freeze = utils.unix_time_to_utc(freeze) if teamid != session.get('id'): solves = solves.filter(Solves.date < freeze) awards = awards.filter(Awards.date < freeze) solves = solves.all() awards = awards.all() db.session.close() json = {'solves': []} for solve in solves: json['solves'].append({ 'chal': solve.chal.name, 'chalid': solve.chalid, 'team': solve.teamid, 'value': solve.chal.value, 'category': solve.chal.category, 'time': utils.unix_time(solve.date) }) if awards: for award in awards: json['solves'].append({ 'chal': award.name, 'chalid': None, 'team': award.teamid, 'value': award.value, 'category': award.category or "Award", 'time': utils.unix_time(award.date) }) json['solves'].sort(key=lambda k: k['time']) return jsonify(json)
def teams(page): page = abs(int(page)) results_per_page = 50 page_start = results_per_page * (page - 1) page_end = results_per_page * (page - 1) + results_per_page if utils.get_config('verify_emails'): count = Teams.query.filter_by(verified=True, banned=False).count() teams = Teams.query.filter_by(verified=True, banned=False).slice(page_start, page_end).all() else: count = Teams.query.filter_by(banned=False).count() teams = Teams.query.filter_by(banned=False).slice(page_start, page_end).all() pages = int(count / results_per_page) + (count % results_per_page > 0) return render_template('teams.html', teams=teams, team_pages=pages, curr_page=page)
def get_standings(admin=False, count=None): scores = db.session.query( Solves.teamid.label('teamid'), db.func.sum(Challenges.value).label('score'), db.func.max(Solves.date).label('date')).join(Challenges).group_by( Solves.teamid) awards = db.session.query(Awards.teamid.label('teamid'), db.func.sum(Awards.value).label('score'), db.func.max(Awards.date).label('date')).group_by( Awards.teamid) freeze = utils.get_config('freeze') if not admin and freeze: scores = scores.filter(Solves.date < utils.unix_time_to_utc(freeze)) awards = awards.filter(Awards.date < utils.unix_time_to_utc(freeze)) results = union_all(scores, awards).alias('results') sumscores = db.session.query( results.columns.teamid, db.func.sum(results.columns.score).label('score'), db.func.max(results.columns.date).label('date')).group_by( results.columns.teamid).subquery() if admin: standings_query = db.session.query( Teams.id.label('teamid'), Teams.name.label('name'), Teams.banned, sumscores.columns.score )\ .join(sumscores, Teams.id == sumscores.columns.teamid) \ .order_by(sumscores.columns.score.desc(), sumscores.columns.date) else: standings_query = db.session.query( Teams.id.label('teamid'), Teams.name.label('name'), sumscores.columns.score )\ .join(sumscores, Teams.id == sumscores.columns.teamid) \ .filter(Teams.banned == False) \ .order_by(sumscores.columns.score.desc(), sumscores.columns.date) if count is None: standings = standings_query.all() else: standings = standings_query.limit(count).all() db.session.close() return standings
def team(teamid): if utils.get_config('view_scoreboard_if_utils.authed') and not utils.authed(): return redirect(url_for('auth.login', next=request.path)) errors = [] freeze = utils.get_config('freeze') user = Teams.query.filter_by(id=teamid).first_or_404() solves = Solves.query.filter_by(teamid=teamid) awards = Awards.query.filter_by(teamid=teamid) place = user.place() score = user.score() if freeze: freeze = utils.unix_time_to_utc(freeze) if teamid != session.get('id'): solves = solves.filter(Solves.date < freeze) awards = awards.filter(Awards.date < freeze) solves = solves.all() awards = awards.all() db.session.close() if utils.hide_scores() and teamid != session.get('id'): errors.append('Scores are currently hidden') if errors: return render_template('team.html', team=user, errors=errors) if request.method == 'GET': return render_template('team.html', solves=solves, awards=awards, team=user, score=score, place=place, score_frozen=utils.is_scoreboard_frozen()) elif request.method == 'POST': json = {'solves': []} for x in solves: json['solves'].append({'id': x.id, 'chal': x.chalid, 'team': x.teamid}) return jsonify(json)
def scores(): json = {'standings': []} if utils.get_config('view_scoreboard_if_authed') and not utils.authed(): return redirect(url_for('auth.login', next=request.path)) if utils.hide_scores(): return jsonify(json) standings = get_standings() for i, x in enumerate(standings): json['standings'].append({ 'pos': i + 1, 'id': x.teamid, 'team': x.name, 'score': int(x.score) }) return jsonify(json)
def challenges_view(): errors = [] start = utils.get_config('start') or 0 end = utils.get_config('end') or 0 if not utils.is_admin(): # User is not an admin if not utils.ctftime(): # It is not CTF time if utils.view_after_ctf( ): # But we are allowed to view after the CTF ends pass else: # We are NOT allowed to view after the CTF ends if utils.get_config('start') and not utils.ctf_started(): errors.append('{} has not started yet'.format( utils.ctf_name())) if (utils.get_config('end') and utils.ctf_ended()) and not utils.view_after_ctf(): errors.append('{} has ended'.format(utils.ctf_name())) return render_template('chals.html', errors=errors, start=int(start), end=int(end)) if utils.get_config('verify_emails') and not utils.is_verified( ): # User is not confirmed return redirect(url_for('auth.confirm_user')) if utils.user_can_view_challenges(): # Do we allow unauthenticated users? if utils.get_config('start') and not utils.ctf_started(): errors.append('{} has not started yet'.format(utils.ctf_name())) if (utils.get_config('end') and utils.ctf_ended()) and not utils.view_after_ctf(): errors.append('{} has ended'.format(utils.ctf_name())) return render_template('chals.html', errors=errors, start=int(start), end=int(end)) else: return redirect(url_for('auth.login', next='challenges'))
def custom_css(): return Response(utils.get_config('css'), mimetype='text/css')
def create_app(config='unit6.config.Config'): app = Flask(__name__) with app.app_context(): app.config.from_object(config) app.jinja_loader = ThemeLoader(os.path.join(app.root_path, app.template_folder), followlinks=True) from unit6.models import db, Teams, Solves, Challenges, WrongKeys, Keys, Tags, Files, Tracking url = make_url(app.config['SQLALCHEMY_DATABASE_URI']) if url.drivername == 'postgres': url.drivername = 'postgresql' ## Creates database if the database database does not exist if not database_exists(url): create_database(url) ## Register database db.init_app(app) ## This creates tables instead of db.create_all() ## Allows migrations to happen properly ## Alembic sqlite support is lacking so we should just create_all anyway if url.drivername.startswith('sqlite'): db.create_all() app.db = db cache.init_app(app) app.cache = cache version = utils.get_config('ctf_version') if not version: ## Upgrading from an unversioned unit6 utils.set_config('ctf_version', __version__) if version and (StrictVersion(version) < StrictVersion(__version__) ): ## Upgrading from an older version of unit6 print("/*\\ unit6 has updated and must update the database! /*\\") print("/*\\ Please backup your database before proceeding! /*\\") print( "/*\\ unit6 maintainers are not responsible for any data loss! /*\\" ) if input('Run database migrations (Y/N)').lower().strip() == 'y': migrate_stamp() migrate_upgrade() utils.set_config('ctf_version', __version__) else: print('/*\\ Ignored database migrations... /*\\') exit() if not utils.get_config('ctf_theme'): utils.set_config('ctf_theme', 'original') from unit6.views import views from unit6.challenges import challenges from unit6.scoreboard import scoreboard from unit6.auth import auth from unit6.admin import admin, admin_statistics, admin_challenges, admin_pages, admin_scoreboard, admin_containers, admin_keys, admin_teams from unit6.utils import init_utils, init_errors, init_logs init_utils(app) init_errors(app) init_logs(app) app.register_blueprint(views) app.register_blueprint(challenges) app.register_blueprint(scoreboard) app.register_blueprint(auth) app.register_blueprint(admin) app.register_blueprint(admin_statistics) app.register_blueprint(admin_challenges) app.register_blueprint(admin_teams) app.register_blueprint(admin_scoreboard) app.register_blueprint(admin_keys) app.register_blueprint(admin_containers) app.register_blueprint(admin_pages) from unit6.plugins import init_plugins init_plugins(app) return app
def get_source(self, environment, template): if template.startswith('admin/'): return super(ThemeLoader, self).get_source(environment, template) theme = utils.get_config('ctf_theme') template = "/".join([theme, template]) return super(ThemeLoader, self).get_source(environment, template)
def admin_config(): if request.method == "POST": start = None end = None freeze = None if request.form.get('start'): start = int(request.form['start']) if request.form.get('end'): end = int(request.form['end']) if request.form.get('freeze'): freeze = int(request.form['freeze']) try: view_challenges_unregistered = bool(request.form.get('view_challenges_unregistered', None)) view_scoreboard_if_authed = bool(request.form.get('view_scoreboard_if_authed', None)) hide_scores = bool(request.form.get('hide_scores', None)) prevent_registration = bool(request.form.get('prevent_registration', None)) prevent_name_change = bool(request.form.get('prevent_name_change', None)) view_after_ctf = bool(request.form.get('view_after_ctf', None)) verify_emails = bool(request.form.get('verify_emails', None)) mail_tls = bool(request.form.get('mail_tls', None)) mail_ssl = bool(request.form.get('mail_ssl', None)) except (ValueError, TypeError): view_challenges_unregistered = None view_scoreboard_if_authed = None hide_scores = None prevent_registration = None prevent_name_change = None view_after_ctf = None verify_emails = None mail_tls = None mail_ssl = None finally: view_challenges_unregistered = utils.set_config('view_challenges_unregistered', view_challenges_unregistered) view_scoreboard_if_authed = utils.set_config('view_scoreboard_if_authed', view_scoreboard_if_authed) hide_scores = utils.set_config('hide_scores', hide_scores) prevent_registration = utils.set_config('prevent_registration', prevent_registration) prevent_name_change = utils.set_config('prevent_name_change', prevent_name_change) view_after_ctf = utils.set_config('view_after_ctf', view_after_ctf) verify_emails = utils.set_config('verify_emails', verify_emails) mail_tls = utils.set_config('mail_tls', mail_tls) mail_ssl = utils.set_config('mail_ssl', mail_ssl) mail_server = utils.set_config("mail_server", request.form.get('mail_server', None)) mail_port = utils.set_config("mail_port", request.form.get('mail_port', None)) mail_username = utils.set_config("mail_username", request.form.get('mail_username', None)) mail_password = utils.set_config("mail_password", request.form.get('mail_password', None)) ctf_name = utils.set_config("ctf_name", request.form.get('ctf_name', None)) ctf_theme = utils.set_config("ctf_theme", request.form.get('ctf_theme', None)) mailfrom_addr = utils.set_config("mailfrom_addr", request.form.get('mailfrom_addr', None)) mg_base_url = utils.set_config("mg_base_url", request.form.get('mg_base_url', None)) mg_api_key = utils.set_config("mg_api_key", request.form.get('mg_api_key', None)) db_freeze = utils.set_config("freeze", freeze) db_start = Config.query.filter_by(key='start').first() db_start.value = start db_end = Config.query.filter_by(key='end').first() db_end.value = end db.session.add(db_start) db.session.add(db_end) db.session.commit() db.session.close() with app.app_context(): cache.clear() return redirect(url_for('admin.admin_config')) with app.app_context(): cache.clear() ctf_name = utils.get_config('ctf_name') ctf_theme = utils.get_config('ctf_theme') hide_scores = utils.get_config('hide_scores') mail_server = utils.get_config('mail_server') mail_port = utils.get_config('mail_port') mail_username = utils.get_config('mail_username') mail_password = utils.get_config('mail_password') mailfrom_addr = utils.get_config('mailfrom_addr') mg_api_key = utils.get_config('mg_api_key') mg_base_url = utils.get_config('mg_base_url') view_after_ctf = utils.get_config('view_after_ctf') start = utils.get_config('start') end = utils.get_config('end') freeze = utils.get_config('freeze') mail_tls = utils.get_config('mail_tls') mail_ssl = utils.get_config('mail_ssl') view_challenges_unregistered = utils.get_config('view_challenges_unregistered') view_scoreboard_if_authed = utils.get_config('view_scoreboard_if_authed') prevent_registration = utils.get_config('prevent_registration') prevent_name_change = utils.get_config('prevent_name_change') verify_emails = utils.get_config('verify_emails') db.session.commit() db.session.close() themes = utils.get_themes() themes.remove(ctf_theme) return render_template('admin/config.html', ctf_name=ctf_name, ctf_theme_config=ctf_theme, start=start, end=end, freeze=freeze, hide_scores=hide_scores, mail_server=mail_server, mail_port=mail_port, mail_username=mail_username, mail_password=mail_password, mail_tls=mail_tls, mail_ssl=mail_ssl, view_challenges_unregistered=view_challenges_unregistered, view_scoreboard_if_authed=view_scoreboard_if_authed, prevent_registration=prevent_registration, mailfrom_addr=mailfrom_addr, mg_base_url=mg_base_url, mg_api_key=mg_api_key, prevent_name_change=prevent_name_change, verify_emails=verify_emails, view_after_ctf=view_after_ctf, themes=themes)